Android13 MediaCodec start流程分析

下面通过代码分析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章节继续分析。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值