MediaPlayer_Analyze-6-MediaCodec和ACodec

本文详细分析了Android系统中MediaCodec和ACodec的交互流程,从初始化、设置数据源、准备、开始播放等步骤,揭示了MediaCodec如何通过ACodec与OMX组件进行通信,涉及组件创建、配置、启动等关键过程。
摘要由CSDN通过智能技术生成

MediaPlayer Analyze - MediaCodec和ACodec

Refrence

  1. Android ACodec MediaCodec NuPlayer flow
  2. MediaCodec对接到OMX的简单分析
  3. ACodec详细解析
  4. MediaPlayer

文中序列图用 websequencediagrams 在线工具画的

ACodec在整个NuPlayer架构中的位置

buffer传输过程


一 初始化

framework层的MediaPlayer初始化未调用NuPlayer用关的函数,进而未调用MediaCodec。

二 设置Source setDataSource

NuPlayer的setDataSource直接返回结果给NuPlayerDriver,没有调用到MediaCodec。

三 准备 prepare

NuPlayer的prepare设置了一些参数,没有调用到MediaCodec。

四 开始/恢复播放 start/resume

4.1 NuPlayerDecoder中mCodec = MediaCodec::CreateByComponentName(mCodecLooper, mComponentName.c_str(), NULL /* err */, mPid, mUid);

frameworks\av\media\libstagefright\MediaCodec.cpp

sp<MediaCodec> MediaCodec::CreateByType(const sp<ALooper> &looper, const AString &mime, bool encoder, status_t *err, pid_t pid, uid_t uid) {
    Vector<AString> matchingCodecs;

    MediaCodecList::findMatchingCodecs(
            mime.c_str(),
            encoder,
            0,
            &matchingCodecs);

    if (err != NULL) {
        *err = NAME_NOT_FOUND;
    }
    for (size_t i = 0; i < matchingCodecs.size(); ++i) {
        // 创建MediaCodec实例对象
        sp<MediaCodec> codec = new MediaCodec(looper, pid, uid);
        AString componentName = matchingCodecs[i];
        // 调用MediaCodec::init进行初始化
        status_t ret = codec->init(componentName);
        if (err != NULL) {
            *err = ret;
        }
        if (ret == OK) {
            return codec;
        }
        ALOGD("Allocating component '%s' failed (%d), try next one.", componentName.c_str(), ret);
    }
    return NULL;
}

status_t MediaCodec::init(const AString &name) {
    ......
    // 实例化ACodec,此处的mCodec未ACodec实例
    mCodec = GetCodecBase(localname, owner);
    ......
    // 注册hanlder用于消息处理
    mLooper->registerHandler(this);
    ......
    // 发送kWhatInit消息
    sp<AMessage> msg = new AMessage(kWhatInit, this);
    ......
    status_t err;
    std::vector<MediaResourceParcel> resources;
    resources.push_back(MediaResource::CodecResource(secureCodec, mIsVideo));
    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;
            }
        }

        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 (strcmp(owner, "default") == 0) {
            return new ACodec;
        } else if (strncmp(owner, "codec2", 6) == 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;
    }
}

void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
    switch (msg->what()) {
        ......
        case kWhatInit:
        {
            ......
            // 调用ACodec::initiateAllocateComponent
            mCodec->initiateAllocateComponent(format);
            break;
        }
        ......
    }
}

frameworks\av\media\libstagefright\ACodec.cpp

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;
        }
        ......
    }
}

bool ACodec::UninitializedState::onAllocateComponent(const sp<AMessage> &msg) {
    ......
    sp<CodecObserver> observer = new CodecObserver(notify);
    sp<IOMX> omx;
    sp<IOMXNode> omxNode;

    status_t err = NAME_NOT_FOUND;
    // 获取OMX的binder对象
    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);
    // 申请omx组件
    err = omx->allocateNode(componentName.c_str(), observer, &omxNode);
    androidSetThreadPriority(tid, prevPriority);

    if (err != OK) {
        ALOGE("Unable to instantiate codec '%s' with err %#x.", componentName.c_str(), err);

        mCodec->signalError((OMX_ERRORTYPE)err, makeNoSideEffectStatus(err));
        return false;
    }
    ......
    // 保存OMX相关对象,此时就和OMX关联起来了
    mCodec->mOMX = omx;
    mCodec->mOMXNode = omxNode;
    // 回调通知MediaCodec
    mCodec->mCallback->onComponentAllocated(mCodec->mComponentName.c_str());
    mCodec->changeState(mCodec->mLoadedState);

    return true;
}

4.2 NuPlayerDecoder中err = mCodec->configure(format, mSurface, crypto, 0 /* flags */);

frameworks\av\media\libstagefright\MediaCodec.cpp

status_t MediaCodec::configure(
        const sp<AMessage> &format,
        const sp<Surface> &surface,
        const sp<ICrypto> &crypto,
        const sp<IDescrambler> &descrambler,
        uint32_t flags) {
    sp<AMessage> msg = new AMessage(kWhatConfigure, this);
    ......
}

void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
    switch (msg->what()) {
        ......
        case kWhatConfigure:
        {
            ......
            setState(CONFIGURING);
            ......
            mCodec->initiateConfigureComponent(format);
            break;
        }
        ......
    }
}

frameworks\av\media\libstagefright\ACodec.cpp

void ACodec::initiateConfigureComponent(const sp<AMessage> &msg) {
    msg->setWhat(kWhatConfigureComponent);
    msg->setTarget(this);
    msg->post();
}

bool ACodec::LoadedState::onMessageReceived(const sp<AMessage> &msg) {
    bool handled = false;

    switch (msg->what()) {
        case ACodec::kWhatConfigureComponent:
        {
            onConfigureComponent(msg);
            handled = true;
            break;
        }
        ......
    }
}


bool ACodec::LoadedState::onConfigureComponent(
        const sp<AMessage> &msg) {
    ALOGV("onConfigureComponent");

    CHECK(mCodec->mOMXNode != NULL);

    status_t err = OK;
    AString mime;
    if (!msg->findString("mime", &mime)) {
        err = BAD_VALUE;
    } else {
        err = mCodec->configureCodec(mime.c_str(), msg);
    }
    if (err != OK) {
        ALOGE("[%s] configureCodec returning error %d", mCodec->mComponentName.c_str(), err);

        mCodec->signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err));
        return false;
    }

    mCodec->mCallback->onComponentConfigured(mCodec->mInputFormat, mCodec->mOutputFormat);

    return true;
}


status_t ACodec::configureCodec(const char *mime, const sp<AMessage> &msg) {
    // 内容很多,主要是通过mCodec->mOMXNode对OMX进行参数配置
    ......
}

4.3 NuPlayerDecoder中err = mCodec->start();

frameworks\av\media\libstagefright\MediaCodec.cpp

status_t MediaCodec::start() {
    sp<AMessage> msg = new AMessage(kWhatStart, this);
    ......
}

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;
        }
        ......
    }
}

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);
    }
}

五 暂停 pause

TODO

六 停止 stop

TODO

七 重置 reset

TODO

八 释放 release

TODO

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值