Call process of mediaplay and opencore in Android Multimedia Framework

Source: Internet
Author: User
This article analyzes how mediaplay calls opencore In the android multimedia framework from the perspective of code.

Summary
For the android Multimedia Framework, Google has implemented stagefright in Android 2.2, but opencore is retained;
In the new version 2.3, opencore was officially abandoned and stagefright was adopted. There are many articles on the android opencore architecture on the Internet, such as the following link: http://www.360doc.com/content/10/0207/22/155970_15398760.shtml. But most of them are based on the framework, and there is no more detailed implementation process of the Code. This article starts with mediaplayer: setdatasource and analyzes the initialization process of the entire opcncore.

Introduction
When playing a video file, we often do this:
Step 1: Create a mediaplayer object;
Step 2: Call the setdatasource, prepare, and start functions of the mediaplayer in sequence;
This article only analyzes setdatasource (opencore Initialization is completed in this function ).

Code Analysis
1. mediaplayer: setdatasource (int fd, int64_t offset, int64_t length)

When we call the setdatasource function at the Java layer, it will call the mediaplayer: setdatasource (int fd, int64_t offset, int64_t length) function at the C ++ layer through JNI. Its implementation is as follows:
Status_t mediaplayer: setdatasource (int fd, int64_t offset, int64_t length );
1) getmediaplayerservice ()
1.1 getservice (string16 ("media. Player ")
2) Service-> Create (getpid (), this, FD, offset, length)
2.1 c = new client, // This Is A mediaplayerservice: client object. See the mediaplayerservice class diagram.
2.2 C-> setdatasource (FD, offset, length)
Getplayertype
Sp <mediaplayerbase> P = createplayer (playertype); // The real instance is pvplayer, midifile or vorbisplayer.
Android: createplayer (playertype, this, Policy)
Sp <mediaplayerbase> P;
Case 1: P = new pvplayer (); // defined media/pvplayer. h
Case 2: P = new midifile (); // defined libmediaplayerservice/pvplayer. h
Case 3: P = new vorbisplayer (); // same as midifile
Case 4: P = new stagefright; // 2.2 is added, and 2.3 is used completely.

3) setdatasource (player): saves the player reference to mediaplayer.

The above three steps are briefly analyzed as follows:
First, obtain mediaplayerservice;
Second, use mediaplayerservice to create a client and then use the client to create a player (that is, call the createplayer function). In fact, the instances pvplayer, midifile, or vorbisplayer are actually created, this is the only bridge between opencore and mediaplayer.
Finally, the instance of the Adaptation Layer Created by calling setdatasource (which is a mediaplayer function) is saved in the member object mplayer of the mediaplayer class (For details, refer to the setdatasource function ).

2. pvplayer Initialization
1) distribution of related files:
Since the most pvplayer (call New pvplayer () is created in the createplayer (playertype) function, it is necessary to take a look at the implementation of the pvplayer construction:
The pvplayer header file is pvplayer. h and the path is base/include/media. The implementation is in playerdriver. cpp and the path is opencore/android.
From the perspective of this small file distribution, it can be concluded that pvplayer is a bridge between mediaserver and opencore at the C ++ layer.
2) Why is the header file and implementation not the same prefix name?
A: You can see the playerdriver. CPP Code. It turns out that the final tasks dealing with opencore fall into the playerdriver class,
It is also a data member of the pvplayer class. Therefore, to match the upper-layer mediaplayer (note that the pvplayer class is a data member of the mediaplayer class-> actually sp <imediaplayer> mplayer. Here, pvplayer inherits sp <imediaplayer>) the header file is named pvplayer. In addition, playerdriver is used to deal with opencore. Therefore, the implemented CPP file is playerdriver. CPP. The author believes that, to make the code clearer, you can write a pvplayer. cpp file and write the pvplayer. cpp code in this pvplayer. cpp file, although the Code is not too much.
3) Check the initialization process of pvplayer:

Looking at the pvplayer constructor, the most important thing is to create a playerdriver object (mplayerdriver = new playerdriver (this);). Therefore, the construction of playerdriver is the core.

3. playerdriver Construction

During the construction of playerdriver, three main tasks are done:
1) semaphore (semaphore) creation:
Msyncsem = new osclsemaphore (); <br/> msyncsem-> Create ();2) Load libopencorehw. So:
Mlibhandle =: dlopen (mio_library_name, rtld_now); // mio_library_name = "libopencorehw. So ";3) Start player thread
Createthreadetc (playerdriver: startplayerthread, this, "PV player ");4. playerdriver: playerthread implementation

Startplayerthread calls playerthread, which is a function used to create a PV thread.

Int playerdriver: playerthread () <br/>{< br/> int error; </P> <p> logv ("initializeforthread"); <br/> If (! Initializeforthread () <br/>{< br/> logv ("initializeforthread fail"); <br/> mplayer = NULL; <br/> msyncsem-> signal (); <br/> return-1; <br/>}</P> <p> logv ("omx_masterinit"); <br/> omx_masterinit (); </P> <p> logv ("osclscheduler: init"); <br/> osclscheduler: Init ("androidpvwrapper "); </P> <p> logv ("createplayer"); <br/> oscl_try (error, mplayer = pvplayerfactory: createplayer (this, this, this )); <br/> If (Error) {<br/> // just crash the first time someone tries to use it for now? <Br/> mplayer = NULL; <br/> msyncsem-> signal (); <br/> return-1; <br/>}</P> <p> logv ("addtoscheduler"); <br/> addtoscheduler (); <br/> logv ("pendforexec "); <br/> pendforexec (); </P> <p> logv ("osclactivescheduler: Current"); <br/> osclexecscheduler * sched = osclexecscheduler: Current (); <br/> logv ("startschedone"); <br/> error = osclerrnone; <br/> oscl_try (error, sched-> startscheduler (msyncsem )); <br/> oscl_first_catch_any (error, <br/> // some AO did a leave, log it <br/> LogE ("Player engine AO did a leave, error = % d ", error) <br/>); </P> <p> logv (" deleteplayer "); <br/> pvplayerfactory: deleteplayer (mplayer ); </P> <p> Delete mdownloadcontextdata; <br/> mdownloadcontextdata = NULL; </P> <p> Delete mdatasource; <br/> mdatasource = NULL; <br/> Delete maudiosink; <br/> pvmediaoutputnodefactory: deletemediaoutputnode (maudionode); <br/> Delete maudiooutputmio; <br/> Delete mvideosink; <br/> If (mvideonode) {<br/> pvmediaoutputnodefactory: deletemediaoutputnode (mvideonode); <br/> Delete mvideooutputmio; <br/>}</P> <p> msyncstatus = OK; <br/> msyncsem-> signal (); <br/> // note that we only signal msyncsem. deleting it is handled <br/> // In enqueuecommand (). this is done because waiting for an <br/> // already-deleted osclsemaphore doesn't work (it blocks ), <br/> // and it's entirely possible for this thread to exit before <br/> // enqueuecommand () gets around to waiting for the semaphore. </P> <p> // do some of destructor's work here <br/> // Goodbye cruel world <br/> Delete this; </P> <p> // moved after the delete this, as oscl cleanup shocould be done in the end. <br/> // Delete this was cleaning up osclsemaphore objects, eventually causing a crash <br/> osclschedash: cleanup (); <br/> logv ("osclscheduler :: cleanup "); </P> <p> omx_masterdeinit (); <br/> uninitializeforthread (); <br/> return 0; <br/>}Analysis:
1) Call omx_masterinit, which is exactly the first function to be called in the OMX Protocol definition.
2) osclscheduler: Init ("androidpvwrapper ");
3) oscl_try (error, mplayer = pvplayerfactory: createplayer (this, this, this); Create a player in factory mode.
In pv_player_factory.cpp, there are:
Export pvplayerinterface * pvplayerfactory: createplayer (pvcommandstatusobserver * acmdstatusobserver, <br/> using * aerroreventobserver, <br/> using * handle, <br/> bool ahwaccelerated) <br/>{ <br/> return pvplayerengine: New (acmdstatusobserver, aerroreventobserver, ainfoeventobserver, ahwaccelerated); // A pvplayerengine instance is created. <Br/>}4) addtoscheduler ();
5) pendforexec ();
6) oscl_try (error, sched-> startscheduler (msyncsem ));
Implementation of startscheduler:
(1) Call blockingloopl
A. Call callrunexec (pvactive); // pvactivebase * pvactive, the real object is the playerdriver instance.
A. Call pvactive-> Run () // call run of playerdriver.
Analysis: In the run function of playerdriver, execute the corresponding handle function according to the command.
7) you can see that the code for creating the engine is called with the OCL layer. For details, see the source code.

5 definition and understanding of command in pvplayerdriver
You can use various commands to perform various pvplayerdriver operations. These commands are defined in playerdriver. h.
Enum player_command_type {<br/> player_quit = 1, <br/> player_setup = 2, <br/> player_set_data_source = 3, <br/> player_set_video_surface = 4, <br/> player_set_audio_sink = 5, <br/> player_init = 6, <br/> player_prepare = 7, <br/> player_start = 8, <br/> player_stop = 9, <br/> player_pause = 10, <br/> player_reset = 11, <br/> player_set_loop = 12, <br/> player_seek = 13, <br/> player_get_position = 14, <br/> player_get_duration = 15, <br/> player_get_status = 16, <br/> player_remove_data_source = 17, <br/> player_cancel_all_commands = 18, <br/> player_check_live_streaming = 19 <br/> };These commands generally implement simple encapsulation of each interface of pvplayerinterface. For example, for a relatively simple pause operation, the entire system execution process is as follows:
(1) pause function in pvplayer (in the playerdriver. cpp file)
Status_t pvplayer: Pause () <br/>{< br/> logv ("pause"); <br/> return mplayerdriver-> enqueuecommand (New playerpause (0, 0 )); <br/>}In this case, call the function of its member mplayerdriver (playerdriver type) and add a playerpause command to the command sequence. The specific command functions are in the playerdriver. h file.
(2) The enqueuecommand of the playerdriver class indirectly calls all functions starting with handle. For the playerpause command, the handlepause function is called.
Void playerdriver: handlepause (playerpause * EC) <br/>{< br/> logv ("Call pause"); <br/> mplayer-> pause (0 ); <br/> finishsynccommand (EC); <br/>}Here mplayer is a pointer of the pvplayerinterface type, which is used to call the pvplayerengine class in the player engine of opencore.
In the implementation of this player adapter, a major task is to convert the output of the media defined in the android framework (including the output of audio and video), the form required by the player engine of opencore. Here, two important classes are androidsurfaceoutput implemented by android_surface_output.cpp, and androidaudiooutput implemented by android_audio_output.cpp.
For the video output setting process, three members are defined in the playerdriver class:
Pvplayerdatasink * mvideosink; <br/> pvmfnodeinterface * mvideonode; <br/> pvmiocontrol * mvideooutputmio;The mvideosink type here is pvplayerdatasink, which is a class interface defined in player engine. The mvideonode type is pvmfnodeinterface, which is defined in pvmi/pvmf/include pvmf_node_interface.h, this is the unified interface that all pvmf nodes need to inherit. The mvideooutputmio type is pvmiocontrol, which is also defined in pvmi/pvmf/include. This is the interface class of media map output control.
(1) setvideosurface of pvplayer is used to set a video output interface. The parameter type here is isurface pointer:
Status_t pvplayer: setvideosurface (const sp <isurface> & surface) <br/> {<br/> logv ("setvideosurface (% P)", surface. get (); <br/> msurface = surface; <br/> Return OK; <br/>}The setvideosurface function is set to msurface, a member of pvplayer. The function of setting the video output page is implemented in the run_set_video_surface () function:
Void pvplayer: run_set_video_surface (status_t S, void * cookie) <br/>{< br/> logv ("run_set_video_surface S = % d", S ); <br/> If (S = no_error) {<br/> pvplayer * P = (pvplayer *) cookie; <br/> If (p-> msurface = NULL) {<br/> run_set_audio_output (S, cookie); <br/>}else {<br/> P-> mplayerdriver-> enqueuecommand (New playersetvideosurface (p-> msurface, run_set_audio_output, cookie); <br/>}< br/>}In this case, the playersetvideosurface command will be used to call the handlesetvideosurface function in playerdriver.
(2) The implementation of the handlesetvideosurface function is as follows:
Void playerdriver: handlesetvideosurface (playersetvideosurface * EC) <br/>{< br/> int error = 0; <br/> response = new androidsurfaceoutput (EC-> surface (); <br/> mvideonode = pvmediaoutputnodefactory: createmediaoutputnode (mvideooutputmio); <br/> mvideosink = new response; </P> <p> (optional *) mvideosink)-> setdatasinknode (mvideonode); <br/> (pvplayerdatasinkpvmfnode *) mvideosink)-> setdatasinkformattype (pvmf_yuv420 ); </P> <p> oscl_try (error, mplayer-> adddatasink (* mvideosink, EC); <br/> oscl_first_catch_any (error, commandfailed (EC )); <br/>}Create mvideooutputmio (type: pvmiocontrol) as a member. The class is androidsurfaceoutput. This class inherits pvmimiocontrol and can be used as pvmiocontrol. Then, call pvmediaoutputnodefactory: createmediaoutputnode to create mvideonode of the pvmfnodeinterface type. Create a pvplayerdatasinkpvmfnode
Pvplayerdatasinkpvmfnode inherits pvplayerdatasink and can be used as pvplayerdatasink. Call the setdatasinknode function to set mvideonode to the data output node of mvideosink.

Conclusion: once again, opencore will completely disappear in Version 2.3, but OMX will continue to be used in stagefright. However, for upper-layer applications, you do not need to worry about this because the interface has not changed.

In the MK file, no code is displayed for the specific connection library. For example, only the link libopencore_player is displayed in MK of libmediaplayerservice,
In the opencore/Android directory, the MK file is compiled by this module to generate libandroidpv. In opencore/Android. mk, there are:
Include $ (pv_top)/build_config/opencore_dynamic/android_opencore_common.mk
Include $ (pv_top)/build_config/opencore_dynamic/android_opencore_author.mk
Include $ (pv_top)/build_config/opencore_dynamic/android_opencore_player.mk
In the third MK file, opencore/build_config/opencore_dynamic/android_opencore_player.mk
Local_module: = libopencore_player.
In libmediaplayerservice, It is the libopencore_player.so compiled by the MK File above.

Http://blog.csdn.net/liranke/article/details/6167043

Related Article

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.