From android
2.0. Google introduced stagefright and used stagefright in android2.3 to share
Library format (libstagefright. So), where awesomeplayer can be used to play video/audio. Awesomeplayer provides many APIs that allow upper-layer applications to use Java/JNI for calling. Here I will briefly describe the video playback process (using the android2.2 source code ).
In Java, to play a video, we usually write as follows:
MediaPlayer mp = new MediaPlayer();mp.setDataSource(PATH_TO_FILE);mp.prepare();mp.start();
In stagefright, you will see the following processing:
1. Specify the absolute path of the video file to Uri:
status_t AwesomePlayer::setDataSource( const char *uri, const KeyedVector<String8, String8> *headers) { Mutex::Autolock autoLock(mLock); return setDataSource_l(uri, headers);}status_t AwesomePlayer::setDataSource_l( const char *uri, const KeyedVector<String8, String8> *headers) { reset_l(); mUri = uri; if (headers) { mUriHeaders = *headers; } // The actual work will be done during preparation in the call to // ::finishSetDataSource_l to avoid blocking the calling thread in // setDataSource for any significant time. return OK;}
2. Start mqueue:
status_t AwesomePlayer::prepare() { 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() { Mutex::Autolock autoLock(mLock); if (mFlags & PREPARING) { return UNKNOWN_ERROR; // async prepare already pending } mIsAsyncPrepare = true; return prepareAsync_l();}status_t AwesomePlayer::prepareAsync_l() { if (mFlags & PREPARING) { return UNKNOWN_ERROR; // async prepare already pending } if (!mQueueStarted) { mQueue.start(); mQueueStarted = true; } mFlags |= PREPARING; mAsyncPrepareEvent = new AwesomeEvent( this, &AwesomePlayer::onPrepareAsyncEvent); mQueue.postEvent(mAsyncPrepareEvent); return OK;}
3. onprepareasyncevent is triggered. Create a parser Based on the header of the sent file and initialize the audio/video decoder:
Void awesomeplayer: onprepareasyncevent () {sp <prefetcher> prefetcher; {mutex: autolock (mlock); If (mflags & prepare_cancelled) {Logi ("Prepare was canceled before doing anything"); abortprepare (unknown_error); return;} If (muri. size ()> 0) {// create a parser in this methodStatus_t err = finishsetperformance_l ();If (Err! = OK) {abortprepare (ERR); Return ;}} if (mvideotrack! = NULL & mvideosource = NULL) {// initialize the Video DecoderStatus_t err = initvideodecoder ();If (Err! = OK) {abortprepare (ERR); Return ;}} if (maudiotrack! = NULL & maudiosource = NULL) {// initialize the audio decoderStatus_t err = initaudiodecoder ();If (Err! = OK) {abortprepare (ERR); Return ;}} prefetcher = mprefetcher;} If (prefetcher! = NULL) {mutex: autolock (mlock); If (mflags & prepare_cancelled) {Logi ("Prepare was canceled before preparing the prefetcher"); prefetcher. clear (); abortprepare (unknown_error); Return ;}} Logi ("calling prefetcher-> prepare ()"); status_t result = prefetcher-> prepare (& awesomeplayer: continuepreparation, this); prefetcher. clear (); If (result = OK) {Logi ("prefetcher is done preparing ");} Else {mutex: autolock (mlock); check_eq (result,-eintr); Logi ("prefetcher-> prepare () was canceled early. "); abortprepare (unknown_error); Return ;}} mutex: autolock (mlock); If (misasyncprepare) {If (mvideowidth <0 | mvideoheight <0) {policylistener_l (media_set_video_size, 0, 0);} else {policylistener_l (media_set_video_size, mvideowidth, mvideoheight);} policylistener _ L (media_prepared);} mprepareresult = OK; mflags & = ~ (Preparing | prepare_cancelled); mflags | = prepared; masyncprepareevent = NULL; mpreparedcondition. Broadcast (); postbufferingevent_l ();}
status_t AwesomePlayer::finishSetDataSource_l() { sp<DataSource> dataSource; if (!strncasecmp("http://", mUri.string(), 7)) { mConnectingDataSource = new HTTPDataSource(mUri, &mUriHeaders); mLock.unlock(); status_t err = mConnectingDataSource->connect(); mLock.lock(); if (err != OK) { mConnectingDataSource.clear(); LOGI("mConnectingDataSource->connect() returned %d", err); return err; } dataSource = new CachingDataSource( mConnectingDataSource, 64 * 1024, 10); mConnectingDataSource.clear(); } else { dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders); } if (dataSource == NULL) { return UNKNOWN_ERROR; } sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource); if (extractor == NULL) { return UNKNOWN_ERROR; } dataSource->getDrmInfo(&mDecryptHandle, &mDrmManagerClient); if (mDecryptHandle != NULL && RightsStatus::RIGHTS_VALID != mDecryptHandle->status) { notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_NO_LICENSE); } if (dataSource->flags() & DataSource::kWantsPrefetching) { mPrefetcher = new Prefetcher; } return setDataSource_l(extractor);}
4. Use the extractor to separate the File A/V:
status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) { bool haveAudio = false; bool haveVideo = false; for (size_t i = 0; i < extractor->countTracks(); ++i) { sp<MetaData> meta = extractor->getTrackMetaData(i); const char *mime; CHECK(meta->findCString(kKeyMIMEType, &mime)); if (!haveVideo && !strncasecmp(mime, "video/", 6)) { setVideoSource(extractor->getTrack(i)); haveVideo = true; } else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) { setAudioSource(extractor->getTrack(i)); haveAudio = true; } if (haveAudio && haveVideo) { break; } } if (!haveAudio && !haveVideo) { return UNKNOWN_ERROR; } mExtractorFlags = extractor->flags(); return OK;}