承接上一章节分析:【六】Android MediaPlayer整体架构源码分析 -【start请求播放处理流程】【Part 5】
本系列文章分析的安卓源码版本:【Android 10.0 版本】
【此章节小节编号就接着上一章节排列】
3、setPortMode(kPortIndexOutput, IOMX::kPortModeDynamicANWBuffer)实现分析:
设置输出缓冲区buffer端口模式为 kPortModeDynamicANWBuffer 即会使用动态ANativeWindowBuffer来传递已解码输出数据。
// [frameworks/av/media/libstagefright/ACodec.cpp]
status_t ACodec::setPortMode(int32_t portIndex, IOMX::PortMode mode) {
// 调用底层具体实现者OMXNodeInstance对象的该方式
// 见下面的分析
status_t err = mOMXNode->setPortMode(portIndex, mode);
if (err != OK) {
ALOGE("[%s] setPortMode on %s to %s failed w/ err %d",
mComponentName.c_str(),
portIndex == kPortIndexInput ? "input" : "output",
asString(mode),
err);
return err;
}
// 缓存对应索引缓冲区buffer端口模式
mPortMode[portIndex] = mode;
return OK;
}
mOMXNode->setPortMode(portIndex, mode)实现分析:
调用底层具体实现者OMXNodeInstance对象的该方式
// [frameworks/av/media/libstagefright/omx/OMXNodeInstance.cpp]
status_t OMXNodeInstance::setPortMode(OMX_U32 portIndex, IOMX::PortMode mode) {
Mutex::Autolock autoLock(mLock);
if (mHandle == NULL) {
return DEAD_OBJECT;
}
// 检查输入输出buffer端口模式索引不能大于当前支持的模式索引最大值
// NELEM:宏定义计算数组大小
// #define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
if (portIndex >= NELEM(mPortMode)) {
ALOGE("b/31385713, portIndex(%u)", portIndex);
android_errorWriteLog(0x534e4554, "31385713");
return BAD_VALUE;
}
// mSailed:配置已设置(没有更多的元模式更改),即表示正在改变组件状态中时为true
// mNumPortBuffers[portIndex]:表示当前端口模式的buffer数量
// 若为true并且buffer已分配则返回失败
if (mSailed || mNumPortBuffers[portIndex] > 0) {
android_errorWriteLog(0x534e4554, "29422020");
return INVALID_OPERATION;
}
CLOG_CONFIG(setPortMode, "%s(%d), port %d", asString(mode), mode, portIndex);
status_t err = OK;
switch (mode) {
// 该模式IOMX::PortMode枚举声明
// 见3.1小节分析
case IOMX::kPortModeDynamicANWBuffer:
{
if (portIndex == kPortIndexOutput) {
// 输出buffer端口索引时
// 该标识根据此前相关章节分析可知,该值默认为false,是个实验性功能开关,打开则直接返回不支持状态码
if (mLegacyAdaptiveExperiment) {
CLOG_INTERNAL(setPortMode, "Legacy adaptive experiment: "
"not setting port mode to %s(%d) on output",
asString(mode), mode);
err = StatusFromOMXError(OMX_ErrorUnsupportedIndex);
break;
}
// 启用native buffer
// 见3.2小节分析
err = enableNativeBuffers_l(
portIndex, OMX_TRUE /*graphic*/, OMX_TRUE);
if (err != OK) {
// 如3.2分析可知,若是SoftAVCDec组件实现的话,那么将会执行此处,即不支持该buffer类型的输出数据
break;
}
}
// 此处将再次执行3.2小节流程,只是参数不同,最后两个都为false,
// 其实际预期处理结果:mSecureBufferType[portIndex] 为 kSecureBufferTypeOpaque 即 不透明安全buffer类型
(void)enableNativeBuffers_l(portIndex, OMX_FALSE /*graphic*/, OMX_FALSE);
// 存储元数据buffer类型模式设置
// 见3.3小节分析
err = storeMetaDataInBuffers_l(portIndex, OMX_TRUE, NULL);
break;
}
case IOMX::kPortModeDynamicNativeHandle:
{
if (portIndex != kPortIndexInput) {
CLOG_ERROR(setPortMode, BAD_VALUE,
"%s(%d) mode is only supported on input port", asString(mode), mode);
err = BAD_VALUE;
break;
}
(void)enableNativeBuffers_l(portIndex, OMX_TRUE /*graphic*/, OMX_FALSE);
(void)enableNativeBuffers_l(portIndex, OMX_FALSE /*graphic*/, OMX_FALSE);
MetadataBufferType metaType = kMetadataBufferTypeNativeHandleSource;
err = storeMetaDataInBuffers_l(portIndex, OMX_TRUE, &metaType);
break;
}
case IOMX::kPortModePresetSecureBuffer:
{
// Allow on both input and output.
(void)storeMetaDataInBuffers_l(portIndex, OMX_FALSE, NULL);
(void)enableNativeBuffers_l(portIndex, OMX_TRUE /*graphic*/, OMX_FALSE);
err = enableNativeBuffers_l(portIndex, OMX_FALSE /*graphic*/, OMX_TRUE);
break;
}
case IOMX::kPortModePresetANWBuffer:
{
if (portIndex != kPortIndexOutput) {
CLOG_ERROR(setPortMode, BAD_VALUE,
"%s(%d) mode is only supported on output port", asString(mode), mode);
err = BAD_VALUE;
break;
}
// Check if we're simulating legacy mode with metadata mode,
// if so, enable metadata mode.
if (mLegacyAdaptiveExperiment) {
if (storeMetaDataInBuffers_l(portIndex, OMX_TRUE, NULL) == OK) {
CLOG_INTERNAL(setPortMode, "Legacy adaptive experiment: "
"metdata mode enabled successfully");
break;
}
CLOG_INTERNAL(setPortMode, "Legacy adaptive experiment: "
"unable to enable metadata mode on output");
mLegacyAdaptiveExperiment = false;
}
// Disable secure buffer and enable graphic buffer
(void)enableNativeBuffers_l(portIndex, OMX_FALSE /*graphic*/, OMX_FALSE);
err = enableNativeBuffers_l(portIndex, OMX_TRUE /*graphic*/, OMX_TRUE);
if (err != OK) {
break;
}
// Not running experiment, or metadata is not supported.
// Disable metadata mode and use legacy mode.
(void)storeMetaDataInBuffers_l(portIndex, OMX_FALSE, NULL);
break;
}
// 输入输出buffer预设模式为字节buffer时
case IOMX::kPortModePresetByteBuffer:
{
// 由前面的分析,此处处理最终大致功能为:禁止使用这三种buffer数据类型模式
// Disable secure buffer, native buffer and metadata.
(void)enableNativeBuffers_l(portIndex, OMX_TRUE /*graphic*/, OMX_FALSE);
(void)enableNativeBuffers_l(portIndex, OMX_FALSE /*graphic*/, OMX_FALSE);
(void)storeMetaDataInBuffers_l(portIndex, OMX_FALSE, NULL);
// 注意:此处执行完毕之后 err 状态默认为OK,因此会执行下面的缓存对应索引buffer端口模式
break;
}
default:
CLOG_ERROR(setPortMode, BAD_VALUE, "invalid port mode %d", mode);
err = BAD_VALUE;
break;
}
if (err == OK) {
// 缓存对应索引buffer端口模式
mPortMode[portIndex] = mode;
}
return err;
}
3.1、该模式IOMX::PortMode枚举声明
也就是定了几种不同缓冲区buffer端口模式,将会采用不同的buffer来承载传递编解码数据
// [frameworks/av/media/libmedia/include/media/IOMX.h]
class IOMX : public RefBase {
enum PortMode {
kPortModePresetStart = 0,
kPortModePresetByteBuffer,
kPortModePresetANWBuffer,
kPortModePresetSecureBuffer,
kPortModePresetEnd,
kPortModeDynamicStart = 100,
kPortModeDynamicANWBuffer, // uses metadata mode kMetadataBufferTypeANWBuffer
// or kMetadataBufferTypeGrallocSource
kPortModeDynamicNativeHandle, // uses metadata mode kMetadataBufferTypeNativeHandleSource
kPortModeDynamicEnd,
};
}
3.2、enableNativeBuffers_l(portIndex, OMX_TRUE /graphic/, OMX_TRUE)实现分析:
启用native buffer
// [frameworks/av/media/libstagefright/omx/OMXNodeInstance.cpp]
status_t OMXNodeInstance::enableNativeBuffers_l(
OMX_U32 portIndex, OMX_BOOL graphic, OMX_BOOL enable) {
// 安全buffer类型枚举,见3.2.1小节声明
// 判断不能大于该buffer类型数组最大索引值
if (portIndex >= NELEM(mSecureBufferType)) {
ALOGE("b/31385713, portIndex(%u)", portIndex);
android_errorWriteLog(0x534e4554, "31385713");
return BAD_VALUE;
}
// 由参数可知,graphic和enable这两个值为true
CLOG_CONFIG(enableNativeBuffers, "%s:%u%s, %d", portString(portIndex), portIndex,
graphic ? ", graphic" : "", enable);
// graphic为true时启用android native buffer传递解码数据,否则为分配native句柄访问
// 此处为强转为OMX框架层的扩展参数数据类型
// 备注:举例SotfAVCDec即安卓原生h264解码器对这两个buffer参数类型(扩展参数类型)支持情况,都不支持。
OMX_STRING name = const_cast<OMX_STRING>(
graphic ? "OMX.google.android.index.enableAndroidNativeBuffers"
: "OMX.google.android.index.allocateNativeHandle");
// 获取该扩展参数类型索引,该方法见前面已有分析
OMX_INDEXTYPE index;
// 备注:举例SoftAVCDec都不支持,因此都会返回不支持错误码。然后进入失败流程走默认的buffer参数类型模式
// 也就是说:在SoftAVCDec中,graphic为true时返回错误,graphic为false时将会采用 mSecureBufferType[portIndex] = kSecureBufferTypeOpaque
OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);
if (err == OMX_ErrorNone) {
// 若支持该buffer分配数据模式时
// 创建OMX该参数
// 见3.2.2小节声明
EnableAndroidNativeBuffersParams params;
// 初始化该参数对象,见前面的分析
InitOMXParams(¶ms);
// 赋值
params.nPortIndex = portIndex;
params.enable = enable;
// 设置参数,此为宏定义即如前面流程分析的将会执行具体组件的实现方法
// 目前只举例简单阐述SoftAVCDec解码器其大致处理原理:
// TODO 待分析
err = OMX_SetParameter(mHandle, index, ¶ms);
CLOG_IF_ERROR(setParameter, err, "%s(%#x): %s:%u en=%d", name, index,
portString(portIndex), portIndex, enable);
if (!graphic) {
// 图形标记为false时
if (err == OMX_ErrorNone) {
// 底层处理成功时,根据enable来选择对应安全buffer类型类传递解码数据
mSecureBufferType[portIndex] =
enable ? kSecureBufferTypeNativeHandle : kSecureBufferTypeOpaque;
} else if (mSecureBufferType[portIndex] == kSecureBufferTypeUnknown) {
// 失败时,默认采用不透明数据模式
mSecureBufferType[portIndex] = kSecureBufferTypeOpaque;
}
} else {
// 图形标记为true时,表示根据enable来判断启用图形buffer类型
if (err == OMX_ErrorNone) {
// 底层处理成功时,赋值
mGraphicBufferEnabled[portIndex] = enable;
} else if (enable) {
// 若要求启用图形buffer但又失败了即底层不支持,则直接该为false不启用该类型。
mGraphicBufferEnabled[portIndex] = false;
}
}
} else {
// 若上面获取要求的扩展参数类型索引失败时即底层不支持该buffer参数类型时
CLOG_ERROR_IF(enable, getExtensionIndex, err, "%s", name);
if (!graphic) {
// graphic为false即不采用图形buffer时
// 如注释:底层解码器不支持该buffer扩展参数类型时,因此将检查是否有设置系统属性来手动覆盖,
// 这只是个临时应变方案,直到底层实现组件支持这个OMX扩展数据类型。该属性默认未设置
// Extension not supported, check for manual override with system property
// This is a temporary workaround until partners support the OMX extension
if (property_get_bool("media.mediadrmservice.enable", false)) {
CLOG_CONFIG(enableNativeBuffers, "system property override: using native-handles");
// 若设置为true即将会使用native buffer句柄访问
mSecureBufferType[portIndex] = kSecureBufferTypeNativeHandle;
} else if (mSecureBufferType[portIndex] == kSecureBufferTypeUnknown) {
// 若未设置,则默认采用不透明数据模式
mSecureBufferType[portIndex] = kSecureBufferTypeOpaque;
}
// 修正为成功
err = OMX_ErrorNone;
}
}
// OMX状态类型转换为native状态类型
// 见3.2.3小节分析
return StatusFromOMXError(err);
}
3.2.1、mSecureBufferType数据类型即SecureBufferType安全buffer类型枚举声明:
// [frameworks/av/media/libstagefright/omx/include/media/stagefright/omx/OMXNodeInstance.h]
enum SecureBufferType {
kSecureBufferTypeUnknown,
// 不透明的安全数据类型
kSecureBufferTypeOpaque,
// native句柄的安全数据类型
kSecureBufferTypeNativeHandle,
};
// 枚举数组
SecureBufferType mSecureBufferType[2];
3.2.2、EnableAndroidNativeBuffersParams该OMX该参数声明:
【英文注释太多,因此去掉了,可以自行在android源码在线官网查看说明】
其实就是个简单的结构声明,有几个参数
// [frameworks/native/headers/media_plugin/media/hardware/HardwareAPI.h]
struct EnableAndroidNativeBuffersParams {
// 该结构的数据大小
OMX_U32 nSize;
// 版本
OMX_VERSIONTYPE nVersion;
// 端口模式索引
OMX_U32 nPortIndex;
// 是否启用
OMX_BOOL enable;
};
3.2.3、StatusFromOMXError(err)实现分析:
OMX状态类型转换为native状态类型
// [frameworks/av/media/libstagefright/omx/OMXUtils.cpp]
status_t StatusFromOMXError(OMX_ERRORTYPE err) {
switch (err) {
// 成功
case OMX_ErrorNone:
return OK;
// 数据不足
case OMX_ErrorNoMore:
return NOT_ENOUGH_DATA;
// 不支持
case OMX_ErrorUnsupportedSetting:
case OMX_ErrorUnsupportedIndex:
return ERROR_UNSUPPORTED; // this is a media specific error
// 参数有误
case OMX_ErrorBadParameter:
return BAD_VALUE;
// 资源不足即内存不足
case OMX_ErrorInsufficientResources:
return NO_MEMORY;
// 无效组件名或组件未找到,转换为组件名未找到
case OMX_ErrorInvalidComponentName:
case OMX_ErrorComponentNotFound:
return NAME_NOT_FOUND;
// 未知错误
default:
return UNKNOWN_ERROR;
}
}
3.3、storeMetaDataInBuffers_l(portIndex, OMX_TRUE, NULL)实现分析:
存储元数据buffer类型模式设置
// [frameworks/av/media/libstagefright/omx/OMXNodeInstance.cpp]
status_t OMXNodeInstance::storeMetaDataInBuffers_l(
OMX_U32 portIndex, OMX_BOOL enable, MetadataBufferType *type) {
if (mSailed) {
android_errorWriteLog(0x534e4554, "29422020");
return INVALID_OPERATION;
}
if (portIndex != kPortIndexInput && portIndex != kPortIndexOutput) {
android_errorWriteLog(0x534e4554, "26324358");
if (type != NULL) {
*type = kMetadataBufferTypeInvalid;
}
return BAD_VALUE;
}
// 通过举例SoftAVCDec模块实现可知,该组件不支持这两种buffer模式。
OMX_INDEXTYPE index;
OMX_STRING name = const_cast<OMX_STRING>(
"OMX.google.android.index.storeMetaDataInBuffers");
OMX_STRING nativeBufferName = const_cast<OMX_STRING>(
"OMX.google.android.index.storeANWBufferInMetadata");
MetadataBufferType negotiatedType;
MetadataBufferType requestedType = type != NULL ? *type : kMetadataBufferTypeANWBuffer;
StoreMetaDataInBuffersParams params;
InitOMXParams(¶ms);
params.nPortIndex = portIndex;
params.bStoreMetaData = enable;
OMX_ERRORTYPE err =
requestedType == kMetadataBufferTypeANWBuffer
? OMX_GetExtensionIndex(mHandle, nativeBufferName, &index)
: OMX_ErrorUnsupportedIndex;
OMX_ERRORTYPE xerr = err;
if (err == OMX_ErrorNone) {
err = OMX_SetParameter(mHandle, index, ¶ms);
if (err == OMX_ErrorNone) {
name = nativeBufferName; // set name for debugging
negotiatedType = requestedType;
}
}
if (err != OMX_ErrorNone) {
// 因此对于SoftAVCDec组件将执行此处,但也不支持
err = OMX_GetExtensionIndex(mHandle, name, &index);
xerr = err;
if (err == OMX_ErrorNone) {
negotiatedType =
requestedType == kMetadataBufferTypeANWBuffer
? kMetadataBufferTypeGrallocSource : requestedType;
err = OMX_SetParameter(mHandle, index, ¶ms);
}
if (err == OMX_ErrorBadParameter) {
// 因此对于SoftAVCDec组件将执行此处
err = OMX_ErrorUnsupportedIndex;
}
}
// don't log loud error if component does not support metadata mode on the output
if (err != OMX_ErrorNone) {
if (err == OMX_ErrorUnsupportedIndex && portIndex == kPortIndexOutput) {
// 若底层不支持,则上层会采用回退方式处理
CLOGW("component does not support metadata mode; using fallback");
} else if (xerr != OMX_ErrorNone) {
CLOG_ERROR(getExtensionIndex, xerr, "%s", name);
} else {
CLOG_ERROR(setParameter, err, "%s(%#x): %s:%u en=%d type=%d", name, index,
portString(portIndex), portIndex, enable, negotiatedType);
}
negotiatedType = mMetadataType[portIndex];
} else {
if (!enable) {
negotiatedType = kMetadataBufferTypeInvalid;
}
mMetadataType[portIndex] = negotiatedType;
}
CLOG_CONFIG(storeMetaDataInBuffers, "%s:%u %srequested %s:%d negotiated %s:%d",
portString(portIndex), portIndex, enable ? "" : "UN",
asString(requestedType), requestedType, asString(negotiatedType), negotiatedType);
if (type != NULL) {
*type = negotiatedType;
}
// 注意:上面处理可能对于不同编/解码器会不支持而失败,但是看到这些错误log时其实也不会影响功能正常编解码
return StatusFromOMXError(err);
}
4、mOMXNode->prepareForAdaptivePlayback(kPortIndexOutput, OMX_TRUE, maxWidth, maxHeight)实现分析:
自适应播放准备请求
// [frameworks/av/media/libstagefright/omx/OMXNodeInstance.cpp]
status_t OMXNodeInstance::prepareForAdaptivePlayback(
OMX_U32 portIndex, OMX_BOOL enable, OMX_U32 maxFrameWidth,
OMX_U32 maxFrameHeight) {
Mutex::Autolock autolock(mLock);
if (mHandle == NULL) {
return DEAD_OBJECT;
}
if (mSailed) {
android_errorWriteLog(0x534e4554, "29422020");
return INVALID_OPERATION;
}
CLOG_CONFIG(prepareForAdaptivePlayback, "%s:%u en=%d max=%ux%u",
portString(portIndex), portIndex, enable, maxFrameWidth, maxFrameHeight);
if (mLegacyAdaptiveExperiment) {
CLOG_INTERNAL(prepareForAdaptivePlayback,
"Legacy adaptive experiment: reporting success");
return OK;
}
// 前面三个判断见此前相关分析
OMX_INDEXTYPE index;
// 备注:该buffer扩展OMX参数类型在SoftAVCDec组件中支持
OMX_STRING name = const_cast<OMX_STRING>(
"OMX.google.android.index.prepareForAdaptivePlayback");
// 备注:SoftAVCDec组件中支持返回成功,并返回index = kPrepareForAdaptivePlaybackIndex;
OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);
if (err != OMX_ErrorNone) {
CLOG_ERROR_IF(enable, getExtensionIndex, err, "%s", name);
return StatusFromOMXError(err);
}
// 创建该参数对象,其声明见下面的分析
PrepareForAdaptivePlaybackParams params;
// 初始化,见此前流程中分析
InitOMXParams(¶ms);
// 赋值
params.nPortIndex = portIndex;
params.bEnable = enable;
params.nMaxFrameWidth = maxFrameWidth;
params.nMaxFrameHeight = maxFrameHeight;
// 再次请求具体实现组件的设置参数方法
// 备注:按照此前国际惯例具体组件暂不分析,只简单阐述其大致工作:
// 注意此时的index = kPrepareForAdaptivePlaybackIndex,
// 解析参数,并记录支持自适应播放模式,缓存视频最大宽高及其默认宽高值。
// 并更新输入输出buffer端口配置信息(最初在构造函数中初始化的)例如帧宽高、步幅、色彩空间模式、buffer大小等
err = OMX_SetParameter(mHandle, index, ¶ms);
CLOG_IF_ERROR(setParameter, err, "%s(%#x): %s:%u en=%d max=%ux%u", name, index,
portString(portIndex), portIndex, enable, maxFrameWidth, maxFrameHeight);
// 最后正常情况下返回成功状态。
return StatusFromOMXError(err);
}
PrepareForAdaptivePlaybackParams 结构声明:
// [frameworks/native/headers/media_plugin/media/hardware/HardwareAPI.h]
struct PrepareForAdaptivePlaybackParams {
OMX_U32 nSize;
OMX_VERSIONTYPE nVersion;
OMX_U32 nPortIndex;
OMX_BOOL bEnable;
OMX_U32 nMaxFrameWidth;
OMX_U32 nMaxFrameHeight;
};
5、setupVideoDecoder(mime, msg, haveNativeWindow, usingSwRenderer, outputFormat)实现分析:
视频解码器初始化
备注:通过前面分析可知,在安卓原生SoftAVCDec软解码器组件时,haveNativeWindow值为false,usingSwRenderer为true。
// [frameworks/av/media/libstagefright/ACodec.cpp]
status_t ACodec::setupVideoDecoder(
const char *mime, const sp<AMessage> &msg, bool haveNativeWindow,
bool usingSwRenderer, sp<AMessage> &outputFormat) {
int32_t width, height;
// 获取原始输入格式的宽高
if (!msg->findInt32("width", &width)
|| !msg->findInt32("height", &height)) {
return INVALID_OPERATION;
}
// 根据mime格式获取对应的OMX支持的视频编码类型枚举
OMX_VIDEO_CODINGTYPE compressionFormat;
// 见5.1小节分析
status_t err = GetVideoCodingTypeFromMime(mime, &compressionFormat);
if (err != OK) {
return err;
}
if (compressionFormat == OMX_VIDEO_CodingHEVC) {
// 判断压缩格式即视频编码格式为HEVC即H265时
int32_t profile;
// 获取编码档次级别,并且判断该档次级别是否被当前解码器组件支持,不支持则直接fail
// 备注:目前只举例分析AVC即h264解码器处理原理,因此暂不展开此处理分析
if (msg->findInt32("profile", &profile)) {
// verify if Main10 profile is supported at all, and fail
// immediately if it's not supported.
if (profile == OMX_VIDEO_HEVCProfileMain10 ||
profile == OMX_VIDEO_HEVCProfileMain10HDR10) {
err = verifySupportForProfileAndLevel(
kPortIndexInput, profile, 0);
if (err != OK) {
return err;
}
}
}
}
// 备注:目前只举例分析AVC即h264解码器处理原理,因此暂不展开此处理分析
if (compressionFormat == OMX_VIDEO_CodingVP9) {
OMX_VIDEO_PARAM_PROFILELEVELTYPE params;
InitOMXParams(¶ms);
params.nPortIndex = kPortIndexInput;
// Check if VP9 decoder advertises supported profiles.
params.nProfileIndex = 0;
status_t err = mOMXNode->getParameter(
OMX_IndexParamVideoProfileLevelQuerySupported,
¶ms, sizeof(params));
mIsLegacyVP9Decoder = err != OK;
}
// 设置视频输入buffer端口格式类型信息
// 见5.2小节分析
err = setVideoPortFormatType(
kPortIndexInput, compressionFormat, OMX_COLOR_FormatUnused);
if (err != OK) {
return err;
}
int32_t tmp;
// 获取色彩空间类型
if (msg->findInt32("color-format", &tmp)) {
OMX_COLOR_FORMATTYPE colorFormat =
static_cast<OMX_COLOR_FORMATTYPE>(tmp);
// 再次执行该方法不同参数,如上该方法处理分析可知,举例SoftAVCDec组件时此处将会返回失败
err = setVideoPortFormatType(
kPortIndexOutput, OMX_VIDEO_CodingUnused, colorFormat, haveNativeWindow);
if (err != OK) {
// 是否设置了缩略图模式
int32_t thumbnailMode = 0;
if (msg->findInt32("thumbnail-mode", &thumbnailMode) &&
thumbnailMode) {
// 如上该方法处理分析可知,举例SoftAVCDec组件时此处将会返回失败
err = setVideoPortFormatType(
kPortIndexOutput, OMX_VIDEO_CodingUnused,
OMX_COLOR_FormatYUV420Planar, haveNativeWindow);
}
if (err != OK) {
// 此处将会在log中打印该不支持的色彩空间格式,但没关系,下面马上来处理默认加载可替代灵活格式
ALOGW("[%s] does not support color format %d",
mComponentName.c_str(), colorFormat);
// 可替代灵活格式处理流程
// 见5.3小节分析
// 备注:如下分析可知,举例SoftAVCDec时将会返回true
err = setSupportedOutputFormat(!haveNativeWindow /* getLegacyFlexibleFormat */);
}
}
} else {
// 可替代灵活格式处理流程
// 见5.3小节分析
err = setSupportedOutputFormat(!haveNativeWindow /* getLegacyFlexibleFormat */);
}
if (err != OK) {
return err;
}
// Set the component input buffer number to be |tmp|. If succeed,
// component will set input port buffer number to be |tmp|. If fail,
// component will keep the same buffer number as before.
// 根据注释:此处为设置组件输入缓冲区buffer数量(大小),未设置该字段时则为默认输入端口buffer数量
// 备注:也就是说我们可以(修改)指定底层缓冲区对应的缓冲区大小。
// 一般情况下不需要设置,使用默认值即可,因此暂不分析。【举例SoftAVCDec组件支持该设置】
if (msg->findInt32("android._num-input-buffers", &tmp)) {
err = setPortBufferNum(kPortIndexInput, tmp);
if (err != OK)
return err;
}
// Set the component output buffer number to be |tmp|. If succeed,
// component will set output port buffer number to be |tmp|. If fail,
// component will keep the same buffer number as before.
// 同上,此处设置输出buffer缓冲区大小
if (msg->findInt32("android._num-output-buffers", &tmp)) {
err = setPortBufferNum(kPortIndexOutput, tmp);
if (err != OK)
return err;
}
// 获取原始输入格式的帧率信息【此处通过获取两种不同类型数据来兼容处理】,未设置则为-1,正常情况都已设置
int32_t frameRateInt;
float frameRateFloat;
if (!msg->findFloat("frame-rate", &frameRateFloat)) {
if (!msg->findInt32("frame-rate", &frameRateInt)) {
frameRateInt = -1;
}
frameRateFloat = (float)frameRateInt;
}
// 设置缓冲区(输入)端口buffer视频格式
// 见5.4小节分析
err = setVideoFormatOnPort(
kPortIndexInput, width, height, compressionFormat, frameRateFloat);
if (err != OK) {
return err;
}
// 同上,设置缓冲区(输出)端口buffer视频格式
// 见5.4小节分析
err = setVideoFormatOnPort(
kPortIndexOutput, width, height, OMX_VIDEO_CodingUnused);
if (err != OK) {
return err;
}
// 设置色彩空间配置信息如色彩矩阵转换系数类型等
// 见5.5小节分析
err = setColorAspectsForVideoDecoder(
width, height, haveNativeWindow | usingSwRenderer, msg, outputFormat);
// 该支持情况是可选的,因此不支持时处理为正确
if (err == ERROR_UNSUPPORTED) { // support is optional
err = OK;
}
if (err != OK) {
return err;
}
// 百度百科信息:
// 高动态范围图像(High-Dynamic Range,简称HDR),相比普通的图像,可以提供更多的动态范围和图像细节,
// 根据不同的曝光时间的LDR(Low-Dynamic Range,低动态范围图像),并利用每个曝光时间相对应最佳细节的LDR图像来合成最终HDR图像。
// 它能够更好地反映出真实环境中的视觉效果。
// 向底层组件设置HDR静态信息
// 见5.6小节分析
err = setHDRStaticInfoForVideoCodec(kPortIndexOutput, msg, outputFormat);
// 由5.6分析可知,举例SoftAVCDec组件不支持该属性,但该属性为可选,因此允许修改为OK
if (err == ERROR_UNSUPPORTED) { // support is optional
err = OK;
}
return err;
}
5.1、GetVideoCodingTypeFromMime(mime, &compressionFormat)实现分析:
根据mime格式获取对应的OMX支持的视频编码类型枚举
由于本章节接下来内容篇幅过长,因此必须放入另一章节分析,请查看:
TODO 【六】Android MediaPlayer整体架构源码分析 -【start请求播放处理流程】【Part 6】【02】