Analysis of the creation process of Android4.2.2 Multimedia Architecture Mediaplay (ii): parser creation

Source: Internet
Author: User

This article is the source of their own reading a bit summary, transfer Please specify the source thank you.

Welcome to communicate with you. qq:1037701636 Email: [email protected]

In the previous article, we analyzed that the Setdatasource_pre () function eventually actually returned the Stagefrightplayer class (class Stagefrightplayer:public Mediaplayerinterface).

1. Continue analyzing the Setdatasource function:

    Now set data source    Setdatasource_post (p, P->setdatasource (FD, offset, length));

The implementation of the Setdatasource function of the Stagefrightplayer is actually polymorphic:

status_t Stagefrightplayer::setdatasource (        const char *url, const KEYEDVECTOR<STRING8, string8> *headers) { C1/>return mplayer->setdatasource (URL, headers);}

MPlayer This member function is new Awesomeplayer out of the object, it is finally into the stagefright to do further processing:

status_t awesomeplayer::setdatasource (        int fd, int64_t offset, int64_t length) {    Mutex::autolock autolock (   MLock);                                                                                                      ...                             .....                                                                                        Return setdatasource_l (DataSource);}
status_t awesomeplayer::setdatasource_l (        const sp<datasource> &datasource) {    sp< mediaextractor> extractor = mediaextractor::create (dataSource);//Create a parser Mpeg4extractor,mime = NULL    if ( Extractor = = NULL) {        return unknown_error;    }    if (Extractor->getdrmflag ()) {        checkdrmstatus (dataSource);    }    return setdatasource_l (extractor);}

The Mediaextractor class, which can be understood as a parser for the audio and video data source, we look at its creation process, passing in the default parameter Mime= NULL:

Sp<mediaextractor> mediaextractor::create (const sp<datasource> &source, const char *mime) {sp& Lt    Amessage> Meta;    STRING8 tmp;        if (MIME = = NULL) {float confidence; if (!source->sniff (&tmp, &confidence, &meta)) {//Extract MIME value ALOGV ("FAILED to AutoDetect Media cont            Ent. ");        return NULL;             MIME = tmp.string ();//Gets the MIME value ALOGV ("autodetected Media content as '%s ' with confidence%.2f",    MIME, confidence);    }//creates a extractor parser mediaextractor *ret = NULL based on different formats for file parsing; if (!STRCASECMP (MIME, media_mimetype_container_mpeg4) | |!strcasecmp (MIME, "Audio/mp4")) {int Fragmente        d = 0; if (meta! = NULL && meta->findint32 ("fragmented", &fragmented) && fragmented) {ret = NE        W fragmentedmp4extractor (source);        } else {ret = new mpeg4extractor (source); } ... and ...... return ret; "}"

Here interspersed explained under the MIME type concept, Google comes, should be represented in a variety of video formats a word string:

VIDEO/X-MS-ASF asfvideo/mpeg mpeg Mpgvideo/x-msvideo aviapplication/vnd.rn-realmedia rmaudio/x-pn-realaudio RAM Raaudio/x-aiff AIF AIFF Aifcaudio/mpeg MPGA mp3audio/midi mid midiaudio/wav wavaudio/x-ms-wma wmavideo/x-ms-wmv wmv

2. Here and everyone simple analysis of SOURCE->SNIFF implementation process, its purpose is very clear is to obtain the current video source MIME type.

BOOL Datasource::sniff (        String8 *mimetype, float *confidence, sp<amessage> *meta) {    *mimetype = "";    *confidence = 0.0f;    Meta->clear ();    Mutex::autolock Autolock (Gsniffermutex);    for (List<snifferfunc>::iterator it = Gsniffers.begin ();         It! = Gsniffers.end (); ++it) {        String8 newmimetype;        float newconfidence;        Sp<amessage> Newmeta;        if ((*it) (this, &newmimetype, &newconfidence, &newmeta)) {            if (Newconfidence > *confidence) {                *mimetype = Newmimetype;                *confidence = newconfidence;                *meta = Newmeta;}}    }    return *confidence > 0.0;}

The function in a gsnifers global variable looks for registered function it, the function pointer type is SNIFFERFUNC. So how do these functions register, and we go back to the Awesomeplay constructor:

  Datasource::registerdefaultsniffers ();
void Datasource::registerdefaultsniffers () {    registersniffer (SniffMPEG4);    Registersniffer (SniffFragmentedMP4), ...    .. Char Value[property_value_max];    if (Property_get ("drm.service.enabled", Value, NULL)            && (!strcmp (Value, "1") | |!strcasecmp (value, "true") ) {        registersniffer (SNIFFDRM);    }}

We see that it registers multiple function pointers, which are registered for different formats and maintained in this gsniffers iterator:

void Datasource::registersniffer (Snifferfunc func) {    mutex::autolock autolock (Gsniffermutex);    for (List<snifferfunc>::iterator it = Gsniffers.begin ();         It! = Gsniffers.end (); ++it) {        if (*it = = func) {            return;        }    }    Gsniffers.push_back (func);//Save function pointer}


Finally, the callback is to the function pointer:

BOOL SniffMPEG4 (        const sp<datasource> &source, String8 *mimetype, float *confidence,        sp<amessage > *meta) {    if (BetterSniffMPEG4 (source, mimeType, confidence, Meta)) {        return true;    }    if (LegacySniffMPEG4 (source, MimeType, confidence)) {        ALOGW ("identified supported MPEG4 through LEGACYSNIFFMPEG4.");        return true;    }    return false;}

The BetterSniffMPEG4 () function logic here is complex, but the overall idea is to read some of the header information from source, and return if the information required for the current MPEG4 format is the same.

Finally, a miem type that belongs to the source is returned, as is assumed to be the MEDIA_MIMETYPE_CONTAINER_MPEG4 format.

3. Creation of parsers

After experiencing the above process, continue to go back to the sp<mediaextractor> mediaextractor::create () function, according to the type of meme extracted, do the following operations.

  ret = new Mpeg4extractor (source);

After we have created the parser above, we go back to awesomeplayer::setdatasource_l () and proceed to setdatasource_l (extractor) to do the new parser, which essentially shows the separation of the audio and video A/V.

Setvideosource (Extractor->gettrack (i));//set video source Mvideotrack;

Setaudiosource (Extractor->gettrack (i));//Set the audio source maudiotrack;

Mvideotrack and Maudiotrack are created as member functions of the Awesomeplay, which are of type Mpeg4source and inherit MediaSource.

Sp<mediasource> mpeg4extractor::gettrack (size_t index) {    status_t err;    if (err = Readmetadata ()) = OK) {        return NULL;    }    Track *track = Mfirsttrack;    while (Index > 0) {        if (track = = null) {            return null;        }        Track = track->next;        --index;    }    if (track = = null) {        return null;    }    return new Mpeg4source (            Track->meta, Mdatasource, Track->timescale, track->sampletable);}

This is where the video source is a\v separated, and the process is-->awesomeplay-->mpeg4extractor-->mpeg4source through Stagefrightplay Multimedia framework. These processes.

4. Prepare the decoder

After completing the Setdatasource on the app side, enter the prepare operation. The MPs side is implemented by the following functions:

status_t mediaplayerservice::client::p repareasync () {    ALOGV ("[%d] prepareasync", Mconnid);    Sp<mediaplayerbase> p = getplayer ()//stragefrightplay class    if (P = = 0) return unknown_error;    status_t ret;     ret = P->prepareasync ();    #if callback_antagonizer    alogd ("Start Antagonizer");    if (ret = = No_error) Mantagonizer->start (); #endif    return ret;}

Getplayer gets the previously created player Stagefrightplayer This object and continues execution:

status_t Stagefrightplayer::p repareasync () {    return Mplayer->prepareasync ();}

MPlayer is the awesomeplayer, the actual implementation is as follows:

status_t Awesomeplayer::p repareasync_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);// Onprepareasyncevent callback function, event handling    mqueue.postevent (masyncprepareevent);//Incoming class object awesomeevent,masyncprepareevent    return OK;}

The process of registering and processing the events mentioned in (a) will be answered here.

The event handling mechanism in 4.1 awesomeplayer.

A. First, here you need to see Mqueue, which is the object of the Timedeventqueue class, called the time event queue. The first call is that a start is required.

void Timedeventqueue::start () {    if (mrunning) {        return;    }    mstopped = false;    pthread_attr_t attr;    Pthread_attr_init (&attr);    Pthread_attr_setdetachstate (&attr, pthread_create_joinable);    Pthread_create (&mthread, &attr, Threadwrapper, this);//Create a process    Pthread_attr_destroy (&attr);    Mrunning = true;}

Obviously, this e-event-handling mechanism is detached from awesomeplayer, creating a thread thradwrapper, which internally calls Thredentry to handle

void Timedeventqueue::threadentry () {    prctl (pr_set_name, (unsigned long) "Timedeventqueue", 0, 0, 0);    for (;;) {        int64_t now_us = 0;        Sp<event> Event;            while (Mqueue.empty ()) {mqueuenotemptycondition.wait (mLock); }.......}

This function is constantly waiting for an event to be processed, similar to a queue that is not empty and is blocked, waiting for signal to wake up.

B. Let's see that the Awesomeevent class inherits the Timedeventqueue event inner class. Its constructor indicates that a function pointer is maintained in Mmethod as a parameter. It is possible to guess that this function will act as the handler when the event occurs. So how does this process trigger?

struct Awesomeevent:public timedeventqueue::event {    awesomeevent (            awesomeplayer *player,            Void ( Awesomeplayer::* method) ())        : MPlayer (player),          Mmethod (method) {    }protected:    virtual ~awesomeevent () {}    virtual void Fire (Timedeventqueue *queue, int64_t/* Now_us */) {        (Mplayer->*mmethod) ();//Call the final registered handler function    }private:    awesomeplayer *mplayer;    void (awesomeplayer::* Mmethod) ();    Awesomeevent (const awesomeevent &);    Awesomeevent &operator= (const awesomeevent &);};

C. mqueue.postevent (masyncprepareevent);//Incoming class object Awesomeevent,masyncprepareevent to implement event wake-up and processing

timedeventqueue::event_id timedeventqueue::p osttimedevent (        const sp<event> &event, int64_t realtime_ US) {    mutex::autolock autolock (mLock);    Event->seteventid (mnexteventid++);    List<queueitem>::iterator it = Mqueue.begin ();    while (It! = Mqueue.end () && realtime_us >= (*it). Realtime_us) {        ++it;    }    Queueitem item;    Item.event = event;    Item.realtime_us = Realtime_us;    if (it = = Mqueue.begin ()) {        mqueueheadchangedcondition.signal ();    }    Mqueue.insert (it, item);//Insert Event    mqueuenotemptycondition.signal () in Mqueue,//Send signal to trigger event    return event- >eventid ();}

Inserts the current event object into the Mqueue queue of the awesomeplayer, then emits signal, wakes the threadentry thread, and lets the thread handle the current event.

5. Truly into the world of decoder creation

void Awesomeplayer::onprepareasyncevent () {//Mutex::autolock Autolock (MLock) is called based on queue and event mechanism;        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 ();//Initialize Video decoder            if (err! = OK) {abortprepare (err);        Return        }} if (Maudiotrack! = null && Maudiosource = = null) {status_t err = Initaudiodecoder ();//Initialize Drink decoder            if (err! = OK) {abortprepare (err);        Return    }} modifyflags (preparing_connected, SET);    if (Isstreaminghttp ()) {postbufferingevent_l (); } else {finishasyncprepare_l ();//completion of asynchronous prepare}}

For the creation and invocation of audio and video decoders here is not doing analysis, considering that he is a unique module, will be in another article analysis, oneself also has a lot of content needs to further digest.












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.