MediaPlayer本地播放流程解析(二)

来源:互联网 发布:网络众筹 编辑:程序博客网 时间:2024/04/29 03:22

上一篇MediaPlayer本地播放流程解析(一)讲了MediaPlayer的setDataSource流程,本篇将接着讲MediaPlayer的prepare流程。

Prepare前面的流程一直到AwesomePlayer,和setDataSource都基本上一样,这里直接略掉。下面将从AwesomePlayer开始。

status_t AwesomePlayer::prepare() {    ATRACE_CALL();    Mutex::Autolock autoLock(mLock);    return prepare_l();}status_t AwesomePlayer::prepare_l() {    if (mFlags & PREPARED) {        return OK;    }    if (mFlags & PREPARING) {        return UNKNOWN_ERROR;    }    mIsAsyncPrepare = false;    status_t err = prepareAsync_l();    if (err != OK) {        return err;    }    while (mFlags & PREPARING) {        mPreparedCondition.wait(mLock);    }    return mPrepareResult;}status_t AwesomePlayer::prepareAsync_l() {    if (mFlags & PREPARING) {        return UNKNOWN_ERROR;  // async prepare already pending    }    if (!mQueueStarted) {        mQueue.start();        mQueueStarted = true;    }    modifyFlags(PREPARING, SET);    mAsyncPrepareEvent = new AwesomeEvent(            this, &AwesomePlayer::onPrepareAsyncEvent);    mQueue.postEvent(mAsyncPrepareEvent);    return OK;}
这里涉及到一个时间事件队列模型,下一篇来详细分析之,这里我们只要知道mQueue.postEvent(mAsyncPrepareEvent)后,onPrepareAsyncEvent方法将会被执行。接着看onPrepareAsyncEvent方法的实现。

void AwesomePlayer::onPrepareAsyncEvent() {    Mutex::Autolock autoLock(mLock);    beginPrepareAsync_l();}void AwesomePlayer::beginPrepareAsync_l() {    if (mFlags & PREPARE_CANCELLED) {        ALOGI("prepare was cancelled before doing anything");        abortPrepare(UNKNOWN_ERROR);        return;    }    if (mUri.size() > 0) {        status_t err = finishSetDataSource_l();        if (err != OK) {            abortPrepare(err);            return;        }    }    if (mVideoTrack != NULL && mVideoSource == NULL) {        status_t err = initVideoDecoder();        if (err != OK) {            abortPrepare(err);            return;        }    }    if (mAudioTrack != NULL && mAudioSource == NULL) {        status_t err = initAudioDecoder();        if (err != OK) {            abortPrepare(err);            return;        }    }    modifyFlags(PREPARING_CONNECTED, SET);    if (isStreamingHTTP()) {        postBufferingEvent_l();    } else {        finishAsyncPrepare_l();    }}
initVideoDecoder和initAudioDecoder实现差不多,这里只讲initVideoDecoder的实现。

status_t AwesomePlayer::initVideoDecoder(uint32_t flags) {    ……    mVideoSource = OMXCodec::Create(            mClient.interface(), mVideoTrack->getFormat(),            false, // createEncoder            mVideoTrack,            NULL, flags, USE_SURFACE_ALLOC ? mNativeWindow : NULL);    if (mVideoSource != NULL) {        int64_t durationUs;        if (mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {            Mutex::Autolock autoLock(mMiscStateLock);            if (mDurationUs < 0 || durationUs > mDurationUs) {                mDurationUs = durationUs;            }        }        status_t err = mVideoSource->start();        if (err != OK) {            ALOGE("failed to start video source");            mVideoSource.clear();            return err;        }    }    ……    return mVideoSource != NULL ? OK : UNKNOWN_ERROR;}

AwesomePlayer通过OMXCodec与openMax交互。硬件厂家提供.so库,实现openMax的接口,即可被AwesomePlayer调用,实现硬解码,加速性能。

OMXCodec::Create 的第一个参数mClient.interface()返回什么呢?

1、  mClient在AwesomePlayer构造时初始化:mClient.connect()。

2、  mClient.interface()在OMXClient.h中定义,返回mOMX,一个BpOMX类型的对象。

初始化connect看下面的代码:

status_t OMXClient::connect() {    sp<IServiceManager> sm = defaultServiceManager();    sp<IBinder> binder = sm->getService(String16("media.player"));    sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);    CHECK(service.get() != NULL);    mOMX = service->getOMX();    CHECK(mOMX.get() != NULL);    if (!mOMX->livesLocally(NULL /* node */, getpid())) {        ALOGI("Using client-side OMX mux.");        mOMX = new MuxOMX(mOMX);    }    return OK;}virtual sp<IOMX> getOMX() {    Parcel data, reply;    data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());    remote()->transact(GET_OMX, data, &reply);    return interface_cast<IOMX>(reply.readStrongBinder());}sp<IOMX> MediaPlayerService::getOMX() {    Mutex::Autolock autoLock(mLock);    if (mOMX.get() == NULL) {        mOMX = new OMX;    }    return mOMX;}
继续看OMXCodec::Create的实现,在Create中将打开AwesomePlayer和openMax交互的通路。

sp<MediaSource> OMXCodec::Create(        const sp<IOMX> &omx,        const sp<MetaData> &meta, bool createEncoder,        const sp<MediaSource> &source,        const char *matchComponentName,        uint32_t flags,        const sp<ANativeWindow> &nativeWindow) {    ……    Vector<CodecNameAndQuirks> matchingCodecs;    findMatchingCodecs(            mime, createEncoder, matchComponentName, flags, &matchingCodecs);    sp<OMXCodecObserver> observer = new OMXCodecObserver;    IOMX::node_id node = 0;    for (size_t i = 0; i < matchingCodecs.size(); ++i) {        const char *componentNameBase = matchingCodecs[i].mName.string();        uint32_t quirks = matchingCodecs[i].mQuirks;        const char *componentName = componentNameBase;        ……        status_t err = omx->allocateNode(componentName, observer, &node);        if (err == OK) {            sp<OMXCodec> codec = new OMXCodec(                    omx, node, quirks, flags,                    createEncoder, mime, componentName,                    source, nativeWindow);            observer->setCodec(codec);            err = codec->configureCodec(meta);            if (err == OK) {                if (!strcmp("OMX.Nvidia.mpeg2v.decode", componentName)) {                    codec->mFlags |= kOnlySubmitOneInputBufferAtOneTime;                }                return codec;            }        }    }    return NULL;}

findMatchingCodecs找到系统提供的所有能对当前mimeType解码的codec,并按照软解码优先的顺序排序。Codec通过"/etc/media_codecs.xml"由芯片厂商提供,在full build后自动生成,findMatchingCodecs执行完后,会得到一些codecs的名称等信息,保存在matchingCodecs里面。

allocateNode会根据componentName创建解码库实例,并将observer、node_id等和它建立联系,方便AwesomePlayer根据node_id找到解码器,解码器通过observer的回调函数通知AwesomePlayer。

status_t OMX::allocateNode(        const char *name, const sp<IOMXObserver> &observer, node_id *node) {    Mutex::Autolock autoLock(mLock);    *node = 0;    // 创建instance    OMXNodeInstance *instance = new OMXNodeInstance(this, observer);    // 根据name创建解码库实例,并通过参数handle返回component,component结构保存了一些函数指针,实现外部程序对解码库的调用。mMaster在OMX的构造函数中初始化     // ,并加载了外部芯片厂商提供的解码库和google提供的软解码库。    OMX_COMPONENTTYPE *handle;    OMX_ERRORTYPE err = mMaster->makeComponentInstance(            name, &OMXNodeInstance::kCallbacks,            instance, &handle);    ……    // 后面的这些就都是建立通路和联系了    *node = makeNodeID(instance);    mDispatchers.add(*node, new CallbackDispatcher(instance));    instance->setHandle(*node, handle);    mLiveNodes.add(observer->asBinder(), instance);    observer->asBinder()->linkToDeath(this);    return OK;}
在OMX的构造函数中初始化OMXMaster

OMX::OMX()    : mMaster(new OMXMaster),      mNodeCounter(0) {}
在OMXMaster的构造函数中加载解码库

OMXMaster::OMXMaster(): mVendorLibHandle(NULL) {    // 芯片厂商提供的解码库    addVendorPlugin();    // 软解码库    addPlugin(new SoftOMXPlugin);}
下面以softPlugin为例来看makeComponentInstance

OMX_ERRORTYPE OMXMaster::makeComponentInstance(        const char *name,        const OMX_CALLBACKTYPE *callbacks,        OMX_PTR appData,        OMX_COMPONENTTYPE **component) {    Mutex::Autolock autoLock(mLock);    *component = NULL;    ssize_t index = mPluginByComponentName.indexOfKey(String8(name));    if (index < 0) {        return OMX_ErrorInvalidComponentName;    }// 最终会调用解码库实现的makeComponentInstance    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;}OMX_ERRORTYPE SoftOMXPlugin::makeComponentInstance(        const char *name,        const OMX_CALLBACKTYPE *callbacks,        OMX_PTR appData,        OMX_COMPONENTTYPE **component) {    ALOGV("makeComponentInstance '%s'", name);for (size_t i = 0; i < kNumComponents; ++i) {    // 根据name找到具体的解码库        if (strcmp(name, kComponents[i].mName)) {            continue;        }        AString libName = "libstagefright_soft_";        libName.append(kComponents[i].mLibNameSuffix);        libName.append(".so");        void *libHandle = dlopen(libName.c_str(), RTLD_NOW);        if (libHandle == NULL) {            ALOGE("unable to dlopen %s", libName.c_str());            return OMX_ErrorComponentNotFound;        }        typedef SoftOMXComponent *(*CreateSoftOMXComponentFunc)(                const char *, const OMX_CALLBACKTYPE *,                OMX_PTR, OMX_COMPONENTTYPE **);        // 找到库文件中创建解码库的方法        CreateSoftOMXComponentFunc createSoftOMXComponent =            (CreateSoftOMXComponentFunc)dlsym(                    libHandle,                    "_Z22createSoftOMXComponentPKcPK16OMX_CALLBACKTYPE"                    "PvPP17OMX_COMPONENTTYPE");        if (createSoftOMXComponent == NULL) {            dlclose(libHandle);            libHandle = NULL;            return OMX_ErrorComponentNotFound;        }        // 执行该方法,并创建解码库        sp<SoftOMXComponent> codec =            (*createSoftOMXComponent)(name, callbacks, appData, component);        if (codec == NULL) {            dlclose(libHandle);            libHandle = NULL;            return OMX_ErrorInsufficientResources;        }        OMX_ERRORTYPE err = codec->initCheck();        if (err != OMX_ErrorNone) {            dlclose(libHandle);            libHandle = NULL;            return err;        }        codec->incStrong(this);        codec->setLibHandle(libHandle);        return OMX_ErrorNone;    }    return OMX_ErrorInvalidComponentName;}
//MP3类型的解码器创建方法

android::SoftOMXComponent *createSoftOMXComponent(        const char *name, const OMX_CALLBACKTYPE *callbacks,        OMX_PTR appData, OMX_COMPONENTTYPE **component) {    return new android::SoftMP3(name, callbacks, appData, component);}

create的最后一步configureCodec(meta),主要是设置下输出的宽高和initNativeWindow。

最后来讲status_t err = mVideoSource->start();

status_t OMXCodec::start(MetaData *meta) {    ……    // Decoder case    if ((err = mSource->start(params.get())) != OK) {        CODEC_LOGE("source failed to start: %d", err);        return err;    }    return init();}
mSource为mVideoTrack,这里不多讲,直接看init()

status_t OMXCodec::init() {    // mLock is held.    CHECK_EQ((int)mState, (int)LOADED);    status_t err;    if (!(mQuirks & kRequiresLoadedToIdleAfterAllocation)) {        err = mOMX->sendCommand(mNode, OMX_CommandStateSet, OMX_StateIdle);        CHECK_EQ(err, (status_t)OK);        setState(LOADED_TO_IDLE);    }    err = allocateBuffers();    if (err != (status_t)OK) {        return err;    }    if (mQuirks & kRequiresLoadedToIdleAfterAllocation) {        err = mOMX->sendCommand(mNode, OMX_CommandStateSet, OMX_StateIdle);        CHECK_EQ(err, (status_t)OK);        setState(LOADED_TO_IDLE);    }    while (mState != EXECUTING && mState != ERROR) {        mAsyncCompletion.wait(mLock);    }    return mState == ERROR ? UNKNOWN_ERROR : OK;}
主要就是allocateBuffers,然后设置LOADED_TO_IDLE状态。

status_t OMXCodec::allocateBuffers() {    status_t err = allocateBuffersOnPort(kPortIndexInput);    if (err != OK) {        return err;    }    return allocateBuffersOnPort(kPortIndexOutput);}
到此,prepare的流程就基本分析完成了。

2 0
原创粉丝点击