Analysis of mediaplayer local playback process (2)

Source: Internet
Author: User

In the previous article, the local playback process of mediaplayer (1) describes the setdatasource process of mediaplayer. This article describes the prepare process of mediaplayer.

The process before prepare goes to awesomeplayer, which is basically the same as that of setdatasource. Here, it is omitted directly. The following will start with 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;}
The onprepareasyncevent method will be executed after mqueue. postevent (masyncprepareevent) is known. Next, let's look at the implementation of the onprepareasyncevent method.

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();    }}
The implementation of initvideodecoder is similar to that of initaudiodecoder. Here we only talk about the implementation of 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 interacts with openmax through omxcodec. The hardware manufacturer provides the. So library to implement the openmax interface, which can be called by awesomeplayer to achieve hard decoding and accelerate performance.

Omxcodec: What is returned by mclient. Interface (), the first parameter of create?

1. mclient initialization during awesomeplayer Construction: mclient. Connect ().

2. mclient. Interface () is defined in omxclient. H, and momx is returned, a bpomx type object.

The following code is used to initialize 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;}
Continue to check the implementation of omxcodec: Create. In create, the awesomeplayer and openmax interaction paths are enabled.

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 finds all the codec that can be decoded to the current mimetype provided by the system, and sorts it by soft decoding priority. Codec is provided by the chip manufacturer through "/etc/media_codecs.xml" and automatically generated after full build. After findmatchingcodecs is executed, it will get some codecs names and other information, which will be saved in matchingcodecs.

Allocatenode creates a decoder library instance based on componentname and establishes contact with observer and node_id to help awesomeplayer locate the decoder based on node_id. the decoder notifies awesomeplayer through the callback function of observer.

Status_t OMX: allocatenode (const char * Name, const sp <iomxobserver> & observer, node_id * node) {mutex: autolock (mlock); * node = 0; // create instance omxnodeinstance * instance = new omxnodeinstance (this, observer); // create a decoding database instance based on the name and return component through the handle parameter. The component structure saves some function pointers, implement external program calls to the decoder library. Mmaster initializes // In the OMX constructor and loads the decoding library provided by the external chip vendor and the soft decoding library provided by Google. Omx_componenttype * handle; omx_errortype err = mmaster-> makecomponentinstance (name, & omxnodeinstance: kcallbacks, instance, & handle );...... // All of the following are links and connections * node = makenodeid (instance); mdispatchers. add (* node, new callbackdispatcher (Instance); instance-> sethandle (* node, handle); mlivenodes. add (observer-> asbinder (), instance); Observer-> asbinder ()-> linktodeath (this); Return OK ;}
Initialize the omxmaster in the omx constructor.

OMX::OMX()    : mMaster(new OMXMaster),      mNodeCounter(0) {}
Load the decoding library in the omxmaster Constructor

Omxmaster: omxmaster (): mvendorlibhandle (null) {// decoder library addvendorplugin () provided by the chip vendor; // soft decoding library addplugin (New softomxplugin );}
The following uses softplugin as an example to describe makecomponentinstance.

Omx_errortype omxmaster: makecomponentinstance (const char * Name, const omx_callbacktype * callbacks, omx_ptr appdata, omx_componenttype ** component) {mutex: autolock (mlock); * Component = NULL; ssize_t Index = mpluginbycomponentname. indexofkey (string8 (name); If (index <0) {return omx_errorinvalidcomponentname;} // makecomponentinstance omxpluginbase * plugin = mpluginbycompone Ntname. 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) {// locate the specific decoder library 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 **); // Find the method createsoftomxcomponentfunc createsoftomxcomponent = (createsoftomxcomponentfunc) dlsym (libhandle, "_ blank" "pvpp17omx_componenttype") in the library file "); if (createsoftomxcomponent = NULL) {dlclose (libhandle); libhandle = NULL; return omx_errorcomponentnotfound;} // execute this method, and create the decoding library 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); omreturn x_errornone ;} return omx_errorinvalidcomponentname ;}
// MP3 decoder Creation Method

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

The last step of create is configurecodec (Meta), which mainly sets the output width and initnativewindow.

Finally, 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 is mvideotrack, which is not mentioned here. Check Init () directly ()

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;}
It is mainly allocatebuffers, and then sets the loaded_to_idle status.

status_t OMXCodec::allocateBuffers() {    status_t err = allocateBuffersOnPort(kPortIndexInput);    if (err != OK) {        return err;    }    return allocateBuffersOnPort(kPortIndexOutput);}
At this point, the prepare process is basically analyzed.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.