下面通过代码分析MediaCodec的start流程:
//frameworks/base/media/java/android/meida/MediaCodec.java
final public class MediaCodec {
public final void start() {
native_start();
synchronized(mBufferLock) {
cacheBuffers(true /* input */);
cacheBuffers(false /* input */);
}
}
}
调用native_start方法,native_start是一个native方法,通过查询调用android_media_MediaCodec_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");
}
调用JMediaCodec的start方法:
sp<MediaCodec> mCodec;
//frameworks/base/media/jni/android_media_MediaCodec.cpp
status_t JMediaCodec::start() {
return mCodec->start();
}
调用MediaCodec的start方法:
//frameworks/av/media/libstagefright/MediaCodec.cpp
status_t MediaCodec::start() {
sp<AMessage> msg = new AMessage(kWhatStart, this);
sp<AMessage> callback;
status_t err;
std::vector<MediaResourceParcel> resources;
resources.push_back(MediaResource::CodecResource(mFlags & kFlagIsSecure,
toMediaResourceSubType(mDomain)));
// 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) {
// Don't try to reclaim resource for the first time.
if (!mResourceManagerProxy->reclaimResource(resources)) {
break;
}
// Recover codec from previous error before retry start.
err = reset();
if (err != OK) {
ALOGE("retrying start: failed to reset codec");
break;
}
sp<AMessage> response;
err = PostAndAwaitResponse(mConfigureMsg, &response);
if (err != OK) {
ALOGE("retrying start: failed to configure codec");
break;
}
if (callback != nullptr) {
err = setCallback(callback);
if (err != OK) {
ALOGE("retrying start: failed to set callback");
break;
}
ALOGD("succeed to set callback for reclaim");
}
}
// Keep callback message after the first iteration if necessary.
if (i == 0 && mCallback != nullptr && mFlags & kFlagIsAsync) {
callback = mCallback;
ALOGD("keep callback message for reclaim");
}
sp<AMessage> response;
err = PostAndAwaitResponse(msg, &response); //发送kWhatStart消息
if (!isResourceError(err)) {
break;
}
}
return err;
}
发送kWhatStart消息,发送的消息在onMessageReceived中处理:
sp<CodecBase> mCodec;
//frameworks/av/media/libstagefright/MediaCodec.cpp
void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
switch (msg->what()) {
case kWhatStart:
{
if (mState == FLUSHED) {
setState(STARTED);
if (mHavePendingInputBuffers) {
onInputBufferAvailable();
mHavePendingInputBuffers = false;
}
mCodec->signalResume();
PostReplyWithError(msg, OK);
break;
} else if (mState != CONFIGURED) {
PostReplyWithError(msg, INVALID_OPERATION);
break;
}
if (mReplyID) {
mDeferredMessages.push_back(msg);
break;
}
sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
TunnelPeekState previousState = mTunnelPeekState;
if (previousState != TunnelPeekState::kLegacyMode) {
mTunnelPeekState = TunnelPeekState::kEnabledNoBuffer;
ALOGV("TunnelPeekState: %s -> %s",
asString(previousState),
asString(TunnelPeekState::kEnabledNoBuffer));
}
mReplyID = replyID;
setState(STARTING);
mCodec->initiateStart();
break;
}
}
}
上面方法主要处理如下:
1、调用ACodec的signalResume方法。
2、调用ACodec的initiateStart方法。
下面分别进行分析:
ACodec::signalResume
调用CodecBase的signalResume方法,ACodec继承于CodecBase,因此会调用ACodec的signalResume方法:
//frameworks/av/media/libstagefright/ACodec.cpp
void ACodec::signalResume() {
(new AMessage(kWhatResume, this))->post();
}
发送kWhatResume消息,发送的消息在onMessageReceived中处理:
//frameworks/av/media/libstagefright/ACodec.cpp
bool ACodec::ExecutingState::onMessageReceived(const sp<AMessage> &msg) {
bool handled = false;
switch (msg->what()) {
case kWhatResume:
{
resume();
handled = true;
break;
}
}
}
调用resume方法:
ACodec *mCodec;
//frameworks/av/media/libstagefright/ACodec.cpp
void ACodec::ExecutingState::resume() {
if (mActive) {
ALOGV("[%s] We're already active, no need to resume.", mCodec->mComponentName.c_str());
return;
}
submitOutputBuffers();
// Post all available input buffers
if (mCodec->mBuffers[kPortIndexInput].size() == 0u) {
ALOGW("[%s] we don't have any input buffers to resume", mCodec->mComponentName.c_str());
}
for (size_t i = 0; i < mCodec->mBuffers[kPortIndexInput].size(); i++) {
BufferInfo *info = &mCodec->mBuffers[kPortIndexInput].editItemAt(i);
if (info->mStatus == BufferInfo::OWNED_BY_US) {
postFillThisBuffer(info); //填充此缓冲区
}
}
mActive = true;
}
ACodec::initiateStart
调用CodecBase的initiateStart方法,ACodec继承于CodecBase,因此会调用ACodec的initiateStart方法:
//frameworks/av/media/libstagefright/ACodec.cpp
void ACodec::initiateStart() {
(new AMessage(kWhatStart, this))->post();
}
发送kWhatStart消息,发送的消息在onMessageReceived中处理:
//frameworks/av/media/libstagefright/ACodec.cpp
bool ACodec::ExecutingState::onMessageReceived(const sp<AMessage> &msg) {
switch (msg->what()) {
case ACodec::kWhatStart:
{
onStart();
handled = true;
break;
}
}
}
ACodec::LoadedState::onStart
调用onStart方法:
ACodec *mCodec;
sp<IOMXNode> mOMXNode;
//frameworks/av/media/libstagefright/ACodec.cpp
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); //切换到LoadedToIdleState状态
}
}
调用IOMXNode的sendCommand方法,这部分为OMX相关,我们在OMX章节继续分析。