【六】Android MediaPlayer整体架构源码分析 -【start请求播放处理流程】【Part 6】【01】
2021/5/14 22:26:57
本文主要是介绍【六】Android MediaPlayer整体架构源码分析 -【start请求播放处理流程】【Part 6】【01】,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
承接上一章节分析:【六】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】
这篇关于【六】Android MediaPlayer整体架构源码分析 -【start请求播放处理流程】【Part 6】【01】的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-01-18android.permission.read_media_video
- 2024-01-18android_getaddrinfo failed eai_nodata
- 2024-01-18androidmo
- 2024-01-15Android下三种离屏渲染技术
- 2024-01-09Android 蓝牙使用
- 2024-01-06Android对接华为AI - 文本识别
- 2023-11-15代码安全之代码混淆及加固(Android)
- 2023-11-10简述Android语音播报TTS
- 2023-11-06Android WiFi工具类
- 2023-07-22Android开发未来的出路