广州开发者沙龙

Android开发论坛 - 安卓开发论坛 - Android开发 - 安卓论坛 - 移动互联网门户

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 2984|回复: 4

stagefright框架解读(—)音视频Playback流程

[复制链接]

该用户从未签到

发表于 2012-1-28 22:59:34 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?注册

x
本帖最后由 Joan 于 2012-1-28 23:04 编辑

从Android 2.0,Google引进了Stagefright,并在android2.3时用Stagefright在Android中是以shared library的形式存在(libstagefright.so),其中AwesomePlayer可用來播放video/audio。AwesomePlayer提供許多API,可以让上层的应用用程式(Java/JNI)來呼叫,我在这里简单说明一下video playback的流程(采用的是android2.2的源码)。

在Java中,若要播放一个影片,我們通常会这样写:
  1. MediaPlayer mp = new MediaPlayer();  
  2. mp.setDataSource(PATH_TO_FILE);  
  3. mp.prepare();  
  4. mp.start();  
复制代码
在Stagefright中,会看到如下的处理:
1.将影片文件的绝对路径指定给uri:
  1. status_t AwesomePlayer::setDataSource(  
  2.         const char *uri, const KeyedVector<String8, String8> *headers) {  
  3.     Mutex::Autolock autoLock(mLock);  
  4.     return setDataSource_l(uri, headers);  
  5. }  
  6.   
  7. status_t AwesomePlayer::setDataSource_l(  
  8.         const char *uri, const KeyedVector<String8, String8> *headers) {  
  9.     reset_l();  
  10.   
  11.     mUri = uri;  
  12.   
  13.     if (headers) {  
  14.         mUriHeaders = *headers;  
  15.     }  
  16.   
  17.     // The actual work will be done during preparation in the call to  
  18.     // ::finishSetDataSource_l to avoid blocking the calling thread in  
  19.     // setDataSource for any significant time.  
  20.   
  21.     return OK;  
  22. }  
复制代码
2.启动mQueue:
  1. status_t AwesomePlayer::prepare() {  
  2.     Mutex::Autolock autoLock(mLock);  
  3.     return prepare_l();  
  4. }  
  5.   
  6. status_t AwesomePlayer::prepare_l() {  
  7.     if (mFlags & PREPARED) {  
  8.         return OK;  
  9.     }  
  10.   
  11.     if (mFlags & PREPARING) {  
  12.         return UNKNOWN_ERROR;  
  13.     }  
  14.   
  15.     mIsAsyncPrepare = false;  
  16.     status_t err = prepareAsync_l();  
  17.   
  18.     if (err != OK) {  
  19.         return err;  
  20.     }  
  21.   
  22.     while (mFlags & PREPARING) {  
  23.         mPreparedCondition.wait(mLock);  
  24.     }  
  25.   
  26.     return mPrepareResult;  
  27. }  
  28.   
  29.   
  30. status_t AwesomePlayer::prepareAsync() {  
  31.     Mutex::Autolock autoLock(mLock);  
  32.   
  33.     if (mFlags & PREPARING) {  
  34.         return UNKNOWN_ERROR;  // async prepare already pending  
  35.     }  
  36.   
  37.     mIsAsyncPrepare = true;  
  38.     return prepareAsync_l();  
  39. }  
  40.   
  41. status_t AwesomePlayer::prepareAsync_l() {  
  42.     if (mFlags & PREPARING) {  
  43.         return UNKNOWN_ERROR;  // async prepare already pending  
  44.     }  
  45.   
  46.     if (!mQueueStarted) {  
  47.         mQueue.start();  
  48.         mQueueStarted = true;  
  49.     }  
  50.   
  51.     mFlags |= PREPARING;  
  52.     mAsyncPrepareEvent = new AwesomeEvent(  
  53.             this, &AwesomePlayer::onPrepareAsyncEvent);  
  54.   
  55.     mQueue.postEvent(mAsyncPrepareEvent);  
  56.   
  57.     return OK;  
  58. }  
复制代码
3.onprepareAsyncEvent被触发,根据传来文件的header来创建相应的解析器,并初始化音视频解码器:
  1. void AwesomePlayer::onPrepareAsyncEvent() {  
  2.     sp<Prefetcher> prefetcher;  
  3.   
  4.     {  
  5.         Mutex::Autolock autoLock(mLock);  
  6.   
  7.         if (mFlags & PREPARE_CANCELLED) {  
  8.             LOGI("prepare was cancelled before doing anything");  
  9.             abortPrepare(UNKNOWN_ERROR);  
  10.             return;  
  11.         }  
  12.   
  13.         if (mUri.size() > 0) {  
  14.            //在这个方法中创建解码器  
  15.            <strong>status_t err = finishSetDataSource_l();</strong>  
  16.   
  17.             if (err != OK) {  
  18.                 abortPrepare(err);  
  19.                 return;  
  20.             }  
  21.         }  
  22.   
  23.         if (mVideoTrack != NULL && mVideoSource == NULL) {  
  24.             //初始化视频解码器  
  25.             <strong>status_t err = initVideoDecoder();</strong>  
  26.   
  27.             if (err != OK) {  
  28.                 abortPrepare(err);  
  29.                 return;  
  30.             }  
  31.         }  
  32.   
  33.         if (mAudioTrack != NULL && mAudioSource == NULL) {  
  34.             //初始化音频解码器  
  35.             <strong>status_t err = initAudioDecoder();  
  36. </strong>  
  37.             if (err != OK) {  
  38.                 abortPrepare(err);  
  39.                 return;  
  40.             }  
  41.         }  
  42.   
  43.         prefetcher = mPrefetcher;  
  44.     }  
  45. if (prefetcher != NULL) {  
  46.         {  
  47.             Mutex::Autolock autoLock(mLock);  
  48.             if (mFlags & PREPARE_CANCELLED) {  
  49.                 LOGI("prepare was cancelled before preparing the prefetcher");  
  50.   
  51.                 prefetcher.clear();  
  52.                 abortPrepare(UNKNOWN_ERROR);  
  53.                 return;  
  54.             }  
  55.         }  
  56.   
  57.         LOGI("calling prefetcher->prepare()");  
  58.         status_t result =  
  59.             prefetcher->prepare(&AwesomePlayer::ContinuePreparation, this);  
  60.   
  61.         prefetcher.clear();  
  62.   
  63.         if (result == OK) {  
  64.             LOGI("prefetcher is done preparing");  
  65.         } else {  
  66.             Mutex::Autolock autoLock(mLock);  
  67.   
  68.             CHECK_EQ(result, -EINTR);  
  69.   
  70.             LOGI("prefetcher->prepare() was cancelled early.");  
  71.             abortPrepare(UNKNOWN_ERROR);  
  72.             return;  
  73.         }  
  74.     }  
  75.   
  76. Mutex::Autolock autoLock(mLock);  
  77.   
  78.     if (mIsAsyncPrepare) {  
  79.         if (mVideoWidth < 0 || mVideoHeight < 0) {  
  80.             notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);  
  81.         } else {  
  82.             notifyListener_l(MEDIA_SET_VIDEO_SIZE, mVideoWidth, mVideoHeight);  
  83.         }  
  84.   
  85.         notifyListener_l(MEDIA_PREPARED);  
  86.     }  
  87.   
  88.     mPrepareResult = OK;  
  89.     mFlags &= ~(PREPARING|PREPARE_CANCELLED);  
  90.     mFlags |= PREPARED;  
  91.     mAsyncPrepareEvent = NULL;  
  92.     mPreparedCondition.broadcast();  
  93.   
  94.     postBufferingEvent_l();  
  95. }  
复制代码
  1. status_t AwesomePlayer::finishSetDataSource_l() {  
  2.     sp<DataSource> dataSource;  
  3.   
  4.     if (!strncasecmp("http://", mUri.string(), 7)) {  
  5.         mConnectingDataSource = new HTTPDataSource(mUri, &mUriHeaders);  
  6.   
  7.         mLock.unlock();  
  8.         status_t err = mConnectingDataSource->connect();  
  9.         mLock.lock();  
  10.   
  11.         if (err != OK) {  
  12.             mConnectingDataSource.clear();  
  13.   
  14.             LOGI("mConnectingDataSource->connect() returned %d", err);  
  15.             return err;  
  16.         }  
  17.   
  18.         dataSource = new CachingDataSource(  
  19.                 mConnectingDataSource, 64 * 1024, 10);  
  20.   
  21.         mConnectingDataSource.clear();  
  22.     } else {  
  23.         dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders);  
  24.     }  
  25.   
  26.     if (dataSource == NULL) {  
  27.         return UNKNOWN_ERROR;  
  28.     }  
  29.   
  30.     <strong>sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);  
  31. </strong>  
  32.     if (extractor == NULL) {  
  33.         return UNKNOWN_ERROR;  
  34.     }  
  35.   
  36.     dataSource->getDrmInfo(&mDecryptHandle, &mDrmManagerClient);  
  37.     if (mDecryptHandle != NULL  
  38.             && RightsStatus::RIGHTS_VALID != mDecryptHandle->status) {  
  39.         notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_NO_LICENSE);  
  40.     }  
  41.   
  42.     if (dataSource->flags() & DataSource::kWantsPrefetching) {  
  43.         mPrefetcher = new Prefetcher;  
  44.     }  
  45.   
  46.    <strong> return setDataSource_l(extractor)</strong>;  
  47. }  
复制代码
4.使用extractor对文件进行A/V分离:
  1. status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) {  
  2.     bool haveAudio = false;  
  3.     bool haveVideo = false;  
  4.     for (size_t i = 0; i < extractor->countTracks(); ++i) {  
  5.         sp<MetaData> meta = extractor->getTrackMetaData(i);  
  6.   
  7.         const char *mime;  
  8.         CHECK(meta->findCString(kKeyMIMEType, &mime));  
  9.   
  10.         if (!haveVideo && !strncasecmp(mime, "video/", 6)) {  
  11.             setVideoSource(extractor->getTrack(i));  
  12.             haveVideo = true;  
  13.         } else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) {  
  14.             setAudioSource(extractor->getTrack(i));  
  15.             haveAudio = true;  
  16.         }  
  17.   
  18.         if (haveAudio && haveVideo) {  
  19.             break;  
  20.         }  
  21.     }  
  22.   
  23.     if (!haveAudio && !haveVideo) {  
  24.         return UNKNOWN_ERROR;  
  25.     }  
  26.   
  27.     mExtractorFlags = extractor->flags();  
  28.   
  29.     return OK;  
  30. }  
复制代码
5.将解析后的音视频数据分别交给VideoTrack和AudioTrack:
  1. void AwesomePlayer::setVideoSource(sp<MediaSource> source) {  
  2.     CHECK(source != NULL);  
  3.   
  4.     if (mPrefetcher != NULL) {  
  5.         source = mPrefetcher->addSource(source);  
  6.     }  
  7.   
  8.     mVideoTrack = source;  
  9. }  
  10.   
  11. void AwesomePlayer::setAudioSource(sp<MediaSource> source) {  
  12.     CHECK(source != NULL);  
  13.   
  14.     if (mPrefetcher != NULL) {  
  15.         source = mPrefetcher->addSource(source);  
  16.     }  
  17.   
  18.     mAudioTrack = source;  
  19. }  
复制代码

6.根据mVideoTrck中的编码类型来选择 video decoder 同理根据mAudioTrack中的编码类型来选择 audio decoder:
  1. status_t AwesomePlayer::initVideoDecoder() {  
  2.     mVideoSource = OMXCodec::Create(  
  3.             mClient.interface(), mVideoTrack->getFormat(),  
  4.             false, // createEncoder  
  5.             mVideoTrack);  
  6.   
  7.     if (mVideoSource != NULL) {  
  8.         int64_t durationUs;  
  9.         if (mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {  
  10.             Mutex::Autolock autoLock(mMiscStateLock);  
  11.             if (mDurationUs < 0 || durationUs > mDurationUs) {  
  12.                 mDurationUs = durationUs;  
  13.             }  
  14.         }  
  15.   
  16.         CHECK(mVideoTrack->getFormat()->findInt32(kKeyWidth, &mVideoWidth));  
  17.         CHECK(mVideoTrack->getFormat()->findInt32(kKeyHeight, &mVideoHeight));  
  18.   
  19.         status_t err = mVideoSource->start();  
  20.   
  21.         if (err != OK) {  
  22.             mVideoSource.clear();  
  23.             return err;  
  24.         }  
  25.     }  
  26.   
  27.     return mVideoSource != NULL ? OK : UNKNOWN_ERROR;  
  28. }  
复制代码
6.将mVideoEvent放入mQueue中,开始解码播放,并交由mvideoRenderer来画出   audio的数据则交由audioplayer来管理,它最终将解码的数据交给audioTrack并由audioTrack和audioFlinger进行交互,最终将数据交给audio hal层,这个我们以后会做讲解:
  1. status_t AwesomePlayer::play() {  
  2.     Mutex::Autolock autoLock(mLock);  
  3.     return play_l();  
  4. }  
  5. status_t AwesomePlayer::play_l() {  
  6.     if (mFlags & PLAYING) {  
  7.         return OK;  
  8.     }  
  9.   
  10.     if (!(mFlags & PREPARED)) {  
  11.         status_t err = prepare_l();  
  12.   
  13.         if (err != OK) {  
  14.             return err;  
  15.         }  
  16.     }  
  17.   
  18.     mFlags |= PLAYING;  
  19.     mFlags |= FIRST_FRAME;  
  20.   
  21.     bool deferredAudioSeek = false;  
  22.   
  23.     if (mAudioSource != NULL) {  
  24.         if (mAudioPlayer == NULL) {  
  25.             if (mAudioSink != NULL) {  
  26.                 //音频数据由audioplayer进行管理  
  27.                 mAudioPlayer = new AudioPlayer(mAudioSink);  
  28.                 mAudioPlayer->setSource(mAudioSource);  
  29.   
  30.                 // We've already started the MediaSource in order to enable  
  31.                 // the prefetcher to read its data.  
  32.                   //调用audioPlayer的start方法则是调用audioSource对数据进行解码  
  33.                    //并将解码似得数据最终交给audioTrack,并调用audioTrack的start方法与audioFlinger进行交互  
  34.                    status_t err = mAudioPlayer->start(  
  35.                         true /* sourceAlreadyStarted */);  
  36.   
  37.                 if (err != OK) {  
  38.                     delete mAudioPlayer;  
  39.                     mAudioPlayer = NULL;  
  40.   
  41.                     mFlags &= ~(PLAYING | FIRST_FRAME);  
  42.   
  43.                     return err;  
  44.                 }  
  45.   
  46.                 delete mTimeSource;  
  47.                 mTimeSource = mAudioPlayer;  
  48.   
  49.                 deferredAudioSeek = true;  
  50.   
  51.                 mWatchForAudioSeekComplete = false;  
  52.                 mWatchForAudioEOS = true;  
  53.             }  
  54.         } else {  
  55.             mAudioPlayer->resume();  
  56.         }  
  57.   
  58.         postCheckAudioStatusEvent_l();  
  59.     }  
  60.   
  61.     if (mTimeSource == NULL && mAudioPlayer == NULL) {  
  62.         mTimeSource = new SystemTimeSource;  
  63.     }  
  64.   
  65.     if (mVideoSource != NULL) {  
  66.         // Kick off video playback  
  67.         //将mVideoEvent放入queue中  
  68.           postVideoEvent_l();  
  69.     }  
  70.   
  71.     if (deferredAudioSeek) {  
  72.         // If there was a seek request while we were paused  
  73.         // and we're just starting up again, honor the request now.  
  74.         seekAudioIfNecessary_l();  
  75.     }  
  76.   
  77.     if (mFlags & AT_EOS) {  
  78.         // Legacy behaviour, if a stream finishes playing and then  
  79.         // is started again, we play from the start...  
  80.         seekTo_l(0);  
  81.     }  
  82.   
  83.     if (mDecryptHandle != NULL) {  
  84.         int64_t position;  
  85.         getPosition(&position);  
  86.         mDrmManagerClient->setPlaybackStatus(mDecryptHandle,  
  87.                 Playback::START, position / 1000);  
  88.     }  
  89.   
  90.     return OK;  
  91. }  
  92.   
  93. void AwesomePlayer::postVideoEvent_l(int64_t delayUs) {  
  94.     if (mVideoEventPending) {  
  95.         return;  
  96.     }  
  97.   
  98.     mVideoEventPending = true;  
  99.     mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs);  
  100. }  
复制代码
  1. void AwesomePlayer::onVideoEvent()  
  2. {  
  3.   mVideoSource->read(&mVideoBuffer, &options);  
  4.   mVideoRenderer->render(mVideoBuffer);  
  5.   
  6.   postVideoEvent_l();  
  7. }  
复制代码

回复

使用道具 举报

该用户从未签到

发表于 2012-5-22 13:55:41 | 显示全部楼层
强大             正需求着
  • TA的每日心情
    无聊
    2013-11-5 09:59
  • 签到天数: 4 天

    连续签到: 1 天

    [LV.2]偶尔看看I

    发表于 2012-5-25 16:42:58 | 显示全部楼层
    这玩意能解析那些格式的视频
  • TA的每日心情
    开心
    2013-1-7 12:02
  • 签到天数: 2 天

    连续签到: 1 天

    [LV.1]初来乍到

    发表于 2013-4-6 16:22:05 | 显示全部楼层
    有没有例程可供学习啊啊啊
    您需要登录后才可以回帖 登录 | 注册

    本版积分规则

    关闭

    今日头条上一条 /1 下一条

    QQ|小黑屋|手机版|Archiver|广告投放apkbus@apkbus.com|安卓巴士 ( 京ICP备09016390号-8  

    GMT+8, 2014-10-23 15:57 , Processed in 0.252616 second(s), 34 queries .

    Powered by Weekend Design Discuz! X3.1

    © 2001-2013 Comsenz Inc.

    快速回复 返回顶部 返回列表