Android MultiMedia框架——MediaCodec编码(上)
Posted VNanyesheshou
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android MultiMedia框架——MediaCodec编码(上)相关的知识,希望对你有一定的参考价值。
Android MultiMedia框架——OMX服务启动
Android MultiMedia框架——OMXPlugin
Android MultiMedia框架——MediaCodec编码(上)
Android MultiMedia框架——MediaCodec编码(下)
Android MultiMedia框架——ACodec加载OMX
基于Android 9.0源码分析
分析MediaCodec编码流程,以OMX.google.aac.encoder编码器为例;
MeidaCodec 使用方法可以参考之前的总结文档
初始化MediaCodec
public static MediaCodec createByCodecName(@NonNull String name)
throws IOException
return new MediaCodec(
name, false /* nameIsType */, false /* unused */);
private MediaCodec(
@NonNull String name, boolean nameIsType, boolean encoder)
Looper looper;
if ((looper = Looper.myLooper()) != null)
mEventHandler = new EventHandler(this, looper);
else if ((looper = Looper.getMainLooper()) != null)
mEventHandler = new EventHandler(this, looper);
else
mEventHandler = null;
mCallbackHandler = mEventHandler;
mOnFrameRenderedHandler = mEventHandler;
mBufferLock = new Object();
native_setup(name, nameIsType, encoder);
MeidaCodec构造器私有的,需要通过静态方法创建对象。
- 创建Handler;
- 创建对象锁;
- 调用native层方法;
接着看native_setup绑定的jni方法
frameworks/base/media/jni/android_media_MediaCodec.cpp
static void android_media_MediaCodec_native_setup(
JNIEnv *env, jobject thiz,
jstring name, jboolean nameIsType, jboolean encoder)
// ...
sp<JMediaCodec> codec = new JMediaCodec(env, thiz, tmp, nameIsType, encoder);
const status_t err = codec->initCheck();
// ...
codec->registerSelf();
setMediaCodec(env,thiz, codec);
- 创建JMediaCodec类型指针;
- JMediaCodec检查初始化状态;
- 保存codec指针;
JMediaCodec::JMediaCodec(
JNIEnv *env, jobject thiz,
const char *name, bool nameIsType, bool encoder)
: mClass(NULL),
mObject(NULL)
//.....
mLooper = new ALooper;
mLooper->setName("MediaCodec_looper");
mLooper->start(
false, // runOnCallingThread
true, // canCallJava
ANDROID_PRIORITY_VIDEO);
if (nameIsType)
mCodec = MediaCodec::CreateByType(mLooper, name, encoder, &mInitStatus);
else
mCodec = MediaCodec::CreateByComponentName(mLooper, name, &mInitStatus);
CHECK((mCodec != NULL) != (mInitStatus != OK));
- 创建ALooper对象,并start,开启一个线程运行;
- nameIsType为false,调用CreateByComponentName;
接着看MediaCodec::CreateByComponentName
路径frameworks/av/media/libstagefright/MediaCodec.cpp
// static
sp<MediaCodec> MediaCodec::CreateByComponentName(
const sp<ALooper> &looper, const AString &name, status_t *err, pid_t pid, uid_t uid)
sp<MediaCodec> codec = new MediaCodec(looper, pid, uid);
const status_t ret = codec->init(name);
if (err != NULL)
*err = ret;
return ret == OK ? codec : NULL; // NULL deallocates codec.
- 创建native层 MeiaCodec对象,其构造器主要是一些遍历初始化;
- 调用init方法;
status_t MediaCodec::init(const AString &name)
//判断是否是安全编解码、是不是vidoe编解码器
//........
mCodec = GetCodecBase(name, mCodecInfo->getOwnerName());
if (mIsVideo)
// video codec needs dedicated looper
//........
else
mLooper->registerHandler(mCodec);
mLooper->registerHandler(this);
sp<AMessage> msg = new AMessage(kWhatInit, this);
msg->setObject("codecInfo", mCodecInfo);
// name may be different from mCodecInfo->getCodecName() if we stripped
// ".secure"
msg->setString("name", name);
for (int i = 0; i <= kMaxRetry; ++i)
if (i > 0)
// Don't try to reclaim resource for the first time.
if (!mResourceManagerService->reclaimResource(resources))
break;
sp<AMessage> response;
err = PostAndAwaitResponse(msg, &response);
if (!isResourceError(err))
break;
return err;
sp<CodecBase> MediaCodec::GetCodecBase(const AString &name, const char *owner)
if (owner)
if (strncmp(owner, "default", 8) == 0)
return new ACodec;
else if (strncmp(owner, "codec2", 7) == 0)
return CreateCCodec();
if (name.startsWithIgnoreCase("c2."))
return CreateCCodec();
else if (name.startsWithIgnoreCase("omx."))
// at this time only ACodec specifies a mime type.
return new ACodec;
else if (name.startsWithIgnoreCase("android.filter."))
return new MediaFilter;
else
return NULL;
- 调用GetCodecBase创建 ACodec对象;
- mLooper注册handler, mCodec和MediaCodec本身;
- 发送 kWhatInit msg消息;
接着查看msg 回调
void MediaCodec::onMessageReceived(const sp<AMessage> &msg)
switch (msg->what())
case kWhatInit:
sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
if (mState != UNINITIALIZED)
PostReplyWithError(replyID, INVALID_OPERATION);
break;
mReplyID = replyID;
setState(INITIALIZING);
sp<RefBase> codecInfo;
CHECK(msg->findObject("codecInfo", &codecInfo));
AString name;
CHECK(msg->findString("name", &name));
sp<AMessage> format = new AMessage;
format->setObject("codecInfo", codecInfo);
format->setString("componentName", name);
mCodec->initiateAllocateComponent(format);
break;
调用ACodec initiateAllocateComponent函数
void ACodec::initiateAllocateComponent(const sp<AMessage> &msg)
msg->setWhat(kWhatAllocateComponent);
msg->setTarget(this);
msg->post();
bool ACodec::UninitializedState::onMessageReceived(const sp<AMessage> &msg)
bool handled = false;
switch (msg->what())
case ACodec::kWhatAllocateComponent:
onAllocateComponent(msg);
handled = true;
break;
接着看onAllocateComponent函数
bool ACodec::UninitializedState::onAllocateComponent(const sp<AMessage> &msg)
//.......
sp<CodecObserver> observer = new CodecObserver;
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();
err = omx->allocateNode(componentName.c_str(), observer, &omxNode);
//......
mCodec->mOMX = omx;
mCodec->mOMXNode = omxNode;
mCodec->mCallback->onComponentAllocated(mCodec->mComponentName.c_str());
mCodec->changeState(mCodec->mLoadedState);
return true;
- OMXClient connect 与media.codec 服务建立连接;
- 获取句柄 IOMX;
- 分配Node;
- 保存omx和omxNode;
- 将状态修改为LoadedState;
配置MeidaFormat
codec.configure(format, …)
由于代码太多,分析下大致流程:
MediaCodec.java
configure(MediaFormat format,Surface surface, @Nullable MediaCrypto crypto,
int flags)
native native_configure()
android_medai_MediaCodec.cpp
android_media_MediaCodec_native_configure()
JMediaCodec::configure()
MediaCodec.cpp
configure()
onMessageReceived() case kWhatConfigure:
ACodec.cpp
void ACodec::initiateConfigureComponent(const sp<AMessage> &msg)
ACodec::LoadedState::onMessageReceived() case ACodec::kWhatConfigureComponent
ACodec::LoadedState::onConfigureComponent()
ACodec::configureCodec(const char *mime, const sp<AMessage> &msg)
ACodec::configureCodec函数代码太长,大概有600多行,就不贴出来了,主要就是通过之前保存的IOMXNode,设置编解码的相关参数,
最终会设置到编码其中,如:SoftAACEncoder2 的internalSetParameter函数
开始
codec.start()
MediaCodec.java
start()
native native_start()
android_medai_MediaCodec.cpp
android_media_MediaCodec_start()
JMediaCodec::start()
MediaCodec.cpp
start()
onMessageReceived() case kWhatStart:
ACodec.cpp
void ACodec::initiateStart()
ACodec::LoadedState::onMessageReceived() case ACodec::kWhatStart
ACodec::LoadedState::onStart()
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);
mOMNode 发送command, omx处理状态。
ACodec 状态改为mLoadedToIdleState,allocateBuffers分配buffer;
void ACodec::LoadedToIdleState::stateEntered()
status_t err;
if ((err = allocateBuffers()) != OK)
//。。。。。。
OMX 处理信息 :OMX_CommandStateSet ,OMX_StateIdle,会发送event通知ACodec,看看ACodec是如何处理的:
bool ACodec::LoadedToIdleState::onOMXEvent(
OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2)
switch (event)
case OMX_EventCmdComplete:
//....
if (err == OK)
err = mCodec->mOMXNode->sendCommand(
OMX_CommandStateSet, OMX_StateExecuting);
if (err != OK)
mCodec->signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err));
else
mCodec->changeState(mCodec->mIdleToExecutingState);
return true;
LoadedToIdleState接收到event:OMX_EventCmdComplete后,向OMX 发送command OMX_StateExecuting, 并且ACodec 将状态切换为IdleToExecutingState。
继续。。。最终ACodec state切换为ExecutingState。
未完待续。。。。。
欢迎大家交流,指正问题。
以上是关于Android MultiMedia框架——MediaCodec编码(上)的主要内容,如果未能解决你的问题,请参考以下文章
Android MultiMedia框架——OMXPlugin
Android MultiMedia框架——ACodec加载OMX
Android MultiMedia框架——ALooper AHandler AMessage
Android MultiMedia框架——MediaCodec编码(下)