MediaCodec_Analyze-3-start

article/2025/10/6 19:09:56

MediaCodec Analyse – start

Refrence: https://source.android.google.cn/devices/media

Android 媒体架构

一 APK调用的核心API

Android APK使用 MediaCodec API 播放音视频的简易流程:

MediaCodec codec = MediaCodec.createDecoderByType("video/avc");
MediaFormat format = MediaFormat.createVideoFormat("video/avc", 320, 480);
codec.configure(format, surface, null, 0);
codec.start();

上一章节,codec.configure(format, surface, null, 0);配置完了。调用codec.start();就可以使开始播放了。

补充

在开始分析codec.start();之前,要先分析一下ACodec中的mCodec->mOMXNode变量。因为之后有很多类似status_t err = mCodec->mOMXNode->sendCommand(OMX_CommandStateSet, OMX_StateIdle);的语句。

在执行APK中MediaCodec codec = MediaCodec.createDecoderByType("video/avc");语句时,会调用到ACodec::UninitializedState::onAllocateComponent(...)函数,在其中,通过HIDL架构得到sp<IOMX> omx;实例,然后会执行err = omx->allocateNode(componentName.c_str(), observer, &omxNode);

frameworks\av\media\libstagefright\ACodec.cpp

bool ACodec::UninitializedState::onAllocateComponent(const sp<AMessage> &msg) {ALOGV("onAllocateComponent");...... //sp<CodecObserver> observer = new CodecObserver(notify);sp<IOMX> omx;sp<IOMXNode> omxNode;status_t err = NAME_NOT_FOUND;OMXClient client;if (client.connect(owner.c_str()) != OK) {mCodec->signalError(OMX_ErrorUndefined, NO_INIT);return false;}omx = client.interface();pid_t tid = gettid();int prevPriority = androidGetThreadPriority(tid);androidSetThreadPriority(tid, ANDROID_PRIORITY_FOREGROUND);err = omx->allocateNode(componentName.c_str(), observer, &omxNode);androidSetThreadPriority(tid, prevPriority);...... //mCodec->mOMX = omx;mCodec->mOMXNode = omxNode;mCodec->mCallback->onComponentAllocated(mCodec->mComponentName.c_str());mCodec->changeState(mCodec->mLoadedState);return true;
}

Omx::allocateNode(...)函数中,主要有2个操作:

  • 通过mMaster->makeComponentInstance(...)创建component实例,并通过instance->setHandle(handle);保存
  • 创建TWOmxNode实例,并回调返回给ACodec

frameworks\av\media\libstagefright\omx\1.0\Omx.cpp

Return<void> Omx::allocateNode(const hidl_string& name, const sp<IOmxObserver>& observer, allocateNode_cb _hidl_cb) {using ::android::IOMXNode;using ::android::IOMXObserver;sp<OMXNodeInstance> instance;{Mutex::Autolock autoLock(mLock);if (mLiveNodes.size() == kMaxNodeInstances) {_hidl_cb(toStatus(NO_MEMORY), nullptr);return Void();}instance = new OMXNodeInstance(this, new LWOmxObserver(observer), name.c_str());// 保存component实例OMX_COMPONENTTYPE *handle;// 通过mMaster创建component实例OMX_ERRORTYPE err = mMaster->makeComponentInstance(name.c_str(), &OMXNodeInstance::kCallbacks, instance.get(), &handle);if (err != OMX_ErrorNone) {LOG(ERROR) << "Failed to allocate omx component '" << name.c_str() << "'  err=" << asString(err) << "(0x" << std::hex << unsigned(err) << ")";_hidl_cb(toStatus(StatusFromOMXError(err)), nullptr);return Void();}// 将创建好的component实例保存到OMXNodeInstance实例中instance->setHandle(handle);......}observer->linkToDeath(this, 0);// 创建TWOmxNode实例_hidl_cb(toStatus(OK), new TWOmxNode(instance));return Void();
}

mHandle的处理

由上文可知,通过OMX_ERRORTYPE err = mMaster->makeComponentInstance(name.c_str(), &OMXNodeInstance::kCallbacks, instance.get(), &handle);语句即可创建ComponentInstance实例,然后将其保存到handle变量中,最后调用instance->setHandle(handle);,使其保存到OMXNodeInstance实例的mHandle变量中。

makeComponentInstance函数传入的name,可能是OMX.realtek.video.decoderOMX_ERRORTYPE err = plugin->makeComponentInstance(name, callbacks, appData, component);语句会调用具体的实现,可能是softplugin,也可能是vendorplugin(即SOC厂商实现的OMXPlugin)。

frameworks\av\media\libstagefright\omx\OMXMaster.cpp

OMX_ERRORTYPE OMXMaster::makeComponentInstance(const char *name,const OMX_CALLBACKTYPE *callbacks,OMX_PTR appData,OMX_COMPONENTTYPE **component) {ALOGI("makeComponentInstance(%s) in %s process", name, mProcessName);Mutex::Autolock autoLock(mLock);*component = NULL;ssize_t index = mPluginByComponentName.indexOfKey(String8(name));if (index < 0) {return OMX_ErrorInvalidComponentName;}OMXPluginBase *plugin = mPluginByComponentName.valueAt(index);OMX_ERRORTYPE err = plugin->makeComponentInstance(name, callbacks, appData, component);if (err != OMX_ErrorNone) {return err;}mPluginByInstance.add(*component, plugin);return err;
}

framework\av\media\libstagefright\omx\OMXNodeInstance.cpp

void OMXNodeInstance::setHandle(OMX_HANDLETYPE handle) {CLOG_LIFE(allocateNode, "handle=%p", handle);CHECK(mHandle == NULL);mHandle = handle;if (handle != NULL) {mDispatcher = new CallbackDispatcher(this);}
}

TWOmxNode实例的处理

结合上下文,WOmxNode中的mBase变量保存的是OMXNodeInstance实例。

frameworks\av\media\libstagefright\omx\1.0\WOmxNode.cpp

TWOmxNode::TWOmxNode(sp<IOMXNode> const& base) : mBase(base) { }

因此,ACodec中的err = omx->allocateNode(componentName.c_str(), observer, &omxNode);中的omxNode实际是WOmxNode实例,即mCodec->mOMXNode = omxNode;保存的是WOmxNode实例。

codec.start();

frameworks\base\media\java\android\media\MediaCodec.java

    public final void start() {native_start();synchronized(mBufferLock) {cacheBuffers(true /* input */);cacheBuffers(false /* input */);}}private native final void native_start();

frameworks\base\media\jni\android_media_MediaCodec.cpp

static void android_media_MediaCodec_start(JNIEnv *env, jobject thiz) {ALOGV("android_media_MediaCodec_start");sp<JMediaCodec> codec = getMediaCodec(env, thiz);if (codec == NULL || codec->initCheck() != OK) {throwExceptionAsNecessary(env, INVALID_OPERATION);return;}status_t err = codec->start();throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, "start failed");
}status_t JMediaCodec::start() {return mCodec->start();
}

frameworks\av\media\libstagefright\MediaCodec.cpp

status_t MediaCodec::start() {sp<AMessage> msg = new AMessage(kWhatStart, this);status_t err;std::vector<MediaResourceParcel> resources;resources.push_back(MediaResource::CodecResource(mFlags & kFlagIsSecure, mIsVideo));// Don't know the buffer size at this point, but it's fine to use 1 because// the reclaimResource call doesn't consider the requester's buffer size for now.resources.push_back(MediaResource::GraphicMemoryResource(1));for (int i = 0; i <= kMaxRetry; ++i) {if (i > 0) {...... //MediaResource的处理}sp<AMessage> response;err = PostAndAwaitResponse(msg, &response);if (!isResourceError(err)) {break;}}return err;
}void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {switch (msg->what()) {......        case kWhatStart:{sp<AReplyToken> replyID;CHECK(msg->senderAwaitsResponse(&replyID));if (mState == FLUSHED) {setState(STARTED);if (mHavePendingInputBuffers) {onInputBufferAvailable();mHavePendingInputBuffers = false;}mCodec->signalResume();PostReplyWithError(replyID, OK);break;} else if (mState != CONFIGURED) {PostReplyWithError(replyID, INVALID_OPERATION);break;}mReplyID = replyID;setState(STARTING);mCodec->initiateStart();break;}......}
}

frameworks\av\media\libstagefright\ACodec.cpp

void ACodec::initiateStart() {(new AMessage(kWhatStart, this))->post();
}bool ACodec::LoadedState::onMessageReceived(const sp<AMessage> &msg) {bool handled = false;switch (msg->what()) {......case ACodec::kWhatStart:{onStart();handled = true;break;}......}return handled;
}void ACodec::LoadedState::onStart() {ALOGV("onStart");status_t err = mCodec->mOMXNode->sendCommand(OMX_CommandStateSet, OMX_StateIdle);if (err != OK) {mCodec->signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err));} else {mCodec->changeState(mCodec->mLoadedToIdleState);}
}

frameworks\av\media\libstagefright\omx\1.0\WOmxNode.cpp

Return<Status> TWOmxNode::sendCommand(uint32_t cmd, int32_t param) {return toStatus(mBase->sendCommand(toEnumCommandType(cmd), param));
}

frameworks\av\media\libstagefright\omx\OMXNodeInstance.cpp

status_t OMXNodeInstance::sendCommand(OMX_COMMANDTYPE cmd, OMX_S32 param) {const sp<IOMXBufferSource> bufferSource(getBufferSource());if (bufferSource != NULL && cmd == OMX_CommandStateSet) {if (param == OMX_StateIdle) {// Initiating transition from Executing -> Idle// ACodec is waiting for all buffers to be returned, do NOT// submit any more buffers to the codec.bufferSource->onOmxIdle();} else if (param == OMX_StateLoaded) {// Initiating transition from Idle/Executing -> Loaded// Buffers are about to be freed.bufferSource->onOmxLoaded();setBufferSource(NULL);}// fall through}Mutex::Autolock autoLock(mLock);if (mHandle == NULL) {return DEAD_OBJECT;}if (cmd == OMX_CommandStateSet) {// There are no configurations past first StateSet command.mSailed = true;}// bump internal-state debug level for 2 input and output frames past a command{Mutex::Autolock _l(mDebugLock);bumpDebugLevel_l(2 /* numInputBuffers */, 2 /* numOutputBuffers */);}const char *paramString = cmd == OMX_CommandStateSet ? asString((OMX_STATETYPE)param) : portString(param);CLOG_STATE(sendCommand, "%s(%d), %s(%d)", asString(cmd), cmd, paramString, param);OMX_ERRORTYPE err = OMX_SendCommand(mHandle, cmd, param, NULL);CLOG_IF_ERROR(sendCommand, err, "%s(%d), %s(%d)", asString(cmd), cmd, paramString, param);return StatusFromOMXError(err);
}

这是SOC厂商实现的内容,一般在libOMX_Core.so中。

frameworks/native/headers/media_plugin/media/openmax/OMX_Core.h

#define OMX_SendCommand(                                    \hComponent,                                        \Cmd,                                               \nParam,                                            \pCmdData)                                          \((OMX_COMPONENTTYPE*)(hComponent))->SendCommand(       \hComponent,                                        \Cmd,                                               \nParam,                                            \pCmdData)                          /* Macro End */

由文章开头的“补充”内容可知,OMX_ERRORTYPE err = OMX_SendCommand(mHandle, cmd, param, NULL);语句中的mHandle变量保存的是通过mMaster->makeComponentInstance(...)创建component实例。

所以((OMX_COMPONENTTYPE*)(hComponent))->SendCommand(hComponent, Cmd, nParam, pCmdData)函数,就是调用通过mMaster->makeComponentInstance(...)创建的component实例的SendCommand函数。


http://chatgpt.dhexx.cn/article/7EXjhVRJ.shtml

相关文章

mediacodec api

mediacodec api 官网&#xff1a; https://developer.android.com/reference/android/media/MediaCodec 中文&#xff1a; https://www.apiref.com/android-zh/android/media/MediaCodec.html 学习mediacodec api的使用说明&#xff0c;在android源码查看&#xff1a; andro…

MediaCodec硬解流程

一 MediaCodec概述 MediaCodec 是Android 4.1(api 16)版本引入的低层编解码接口&#xff0c;同时支持音视频的编码和解码。通常与MediaExtractor、MediaMuxer、AudioTrack结合使用&#xff0c;能够编解码诸如H.264、H.265、AAC、3gp等常见的音视频格式。MediaCodec在编解码的过…

MediaCodec_Analyze-1-create

MediaCodec Analyse – create Refrence: https://source.android.google.cn/devices/media 一 APK调用的核心API Android APK使用 MediaCodec API 播放音视频的简易流程&#xff1a; MediaCodec codec MediaCodec.createDecoderByType("video/avc"); MediaFormat…

mediacodec

MedaiCodec简介 MediaCodec是Android中提供的音视频编/解码工具。它主要是完成上层接口的封装&#xff0c;供给开发者使用&#xff0c;编解码功能实际是在native底层服务中完成的 MediaCodec工作流程 包括两个缓冲区队列 一个输入缓冲区队列&#xff0c;包含一组输入缓冲区(格…

Android MediaCodec 完全解析

MediaCodec是什么&#xff1f; MediaCodec类为开发者提供了能访问到Android底层媒体Codec&#xff08;Encoder/Decoder&#xff09;的能力&#xff0c;它是Android底层多媒体基础架构的一部分&#xff08;通常和MediaExtractor、MediaSync、MediaMuxer、MediaCrypto、MediaDrm…

Android MediaCodec解析

Android MediaCodec解析 1 引言 MediaCodec是Android平台提供的一个底层的音视频编解码框架&#xff0c;它是安卓底层多媒体基础框架的重要组成部分。它经常和 MediaExtractor, MediaSync, MediaMuxer, MediaCrypto, MediaDrm, Image, Surface, AudioTrack一起使用。解码的作…

Android原生编解码接口MediaCodec详解

作者&#xff1a;躬行之 了解了音视频的相关知识&#xff0c;可以先阅读同系列文章&#xff1a; 音视频开发基础知识音频帧、视频帧及其同步Camera2、MediaCodec录制mp4 MediaCodec 是 Android 中的编解码器组件&#xff0c;用来访问底层提供的编解码器&#xff0c;通常与 Me…

MediaCodec视频解码流程详解及参考demo

一、MediaCodec简介 MediaCodec是Android自带的底层多媒体支持架构的一部分&#xff08;通常与 MediaExtractor&#xff0c;MediaSync&#xff0c;MediaMuxer&#xff0c;MediaCrypto&#xff0c;MediaDrm&#xff0c;Image&#xff0c;Surface 和 AudioTrack 一起使用&#xf…

Android MediaCodec简单总结

#.MedaiCodec简介 MediaCodec是Android中提供的音视频编码、解码工具。它主要是完成上层接口的封装&#xff0c;提供给开发者使用&#xff0c;编解码功能实际是在native底层服务中完成的。 #.MediaCodec工作的宏观流程&#xff1a; ##.包换两个缓冲区队列 一个输入缓冲区队列&a…

软件测试面试指导之自我介绍

面试自我介绍虽然人人都准备&#xff0c;但是做到让人印象深刻可不容易啊。 本篇就具体来聊聊人人都要经历的面试&#xff0c;怎么做自我介绍&#xff0c;才能让你在面试官的眼睛里像金子一样闪闪发光&#xff1f; 面试是什么&#xff1f; 它是个机会&#xff0c;让面试官更…

软件测试面试要注意的细节以及处理(自我介绍篇)

面试问题第一问&#xff0c;95%都会是&#xff1a; 请简单的做个自我介绍吧~ 分以下几点说明。 一、个人的基本信息&#xff0c;扬长避短 1、年纪太大与太小&#xff0c;都不需要主动去说明。 比如我年纪只有21岁 例子&#xff1a;面试官您好&#xff0c;我叫***&#xff…

【软件测试】企业测试面试题9道,从自我介绍到项目考察+回答......

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、自我介绍 您好…

软件测试面试怎样介绍自己的项目?会问到什么程度?

最近收到很多粉丝的私信说找不到工作&#xff0c;简历投了百十来份&#xff0c;邀约都没几个&#xff0c;更别说offer了&#xff0c;是不是软件测试要黄了&#xff1f; 说句实话&#xff0c;现在大环境确实不好&#xff0c;互联网大厂裁员这是摆在明面上的原因。时代的一粒沙&…

软件测试面试怎样介绍自己的测试项目?会问到什么程度?

想知道面试时该怎样介绍测试项目&#xff1f;会问到什么程度&#xff1f;那就需要换位思考&#xff0c;思考HR在这个环节想知道什么。 HR在该环节普遍想获得的情报主要是下面这2个方面&#xff1a; 1&#xff09;应聘者的具体经验和技术能力&#xff0c; 2&#xff09;应聘者的…

【软件测试】面试中介绍项目你该这么说!

黑马程序员视频库 播妞微信号&#xff1a;heiniu526 传智播客旗下互联网资讯、学习资源免费分享平台 测试人员在找工作的过程中&#xff0c;通常有一个问题是很难绕开的。就是要如何向别人介绍自己之前做过的项目。下面我们就这个问题简单的做一些分析。 大体上可以分为如下几个…

软件测试面试自我介绍/项目介绍居然还有模板?我要是早点发现就好了

目录 1、自我介绍 2、项目介绍 2.1、最全电商项目介绍 2.2、电商项目介绍 2.3、在线教育项目介绍 2.4、互联网金融项目介绍 总结 1、自我介绍 以XXX简历来举例&#xff08;参照下面的案例&#xff0c;编写你的自我介绍&#xff0c;框架就是&#xff1a;我是谁&#xff0…

软件测试面试,如何自我介绍?如何介绍项目?如何介绍个人技术?(提供面试话术)

前准备不足而导致面试失败那可就亏大了&#xff01;为了提高面试成功率&#xff0c;帮助大家尽快拿到高薪offer&#xff0c;我们盘点了面试环节必问的三类问题&#xff0c;希望对即将参加软件测试面试的小伙伴们有所帮助。 01 如何自我介绍 面试过程中一定要放慢语速&#xf…

软件测试面试,如何自我介绍?

01 如何自我介绍 面试过程中一定要放慢语速&#xff0c;做到条理清晰。特别是做自我介绍时&#xff0c;可以适当多介绍自己会什么&#xff0c;有哪些重要经验。 例如&#xff1a; 面试官&#xff0c;上午/下午好。 我是XXX&#xff0c;今天来面试贵公司的软件测试工程师岗位&a…

软件测试工程师面试如何做好自我介绍?

听了很多提问者和我的学生&#xff0c;在做自我自我介绍的时候&#xff0c;一般存在的问题&#xff1a; 1、表述不太流畅。多练习表述&#xff0c;自己录音&#xff0c;听回放&#xff0c;有问题改正。 2、表述太溜&#xff0c;语速太快。不自信表现&#xff0c;隐含紧张的情绪…

软件测试三分钟自我介绍

目录 一、个人的基本信息&#xff0c;扬长避短 二、突出自己的工作经验 三、突出自己的技能 四、个人兴趣爱好与结尾 自我介绍在面试中常常作为第一个问题而出现&#xff0c;好的自我介绍可以带来良好的第一印象&#xff0c;如何讲好自我介绍呢。我建议从三部分下手 一、个…