必威体育Betway必威体育官网
当前位置:首页 > IT技术

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

时间:2019-10-15 19:45:47来源:IT技术作者:seo实验室小编阅读:63次「手机版」
 

stagefright

转载请注明出处:http://blog.csdn.net/itachi85/article/details/7216639

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中,若要播放一个影片,我們通常会这样写:

[java] view plain copy print?

  1. mediaplayermp=newMediaPlayer();
  2. mp.setdatasource(PATH_TO_FILE);
  3. mp.prepare();
  4. mp.start();

MediaPlayer mp = new MediaPlayer();
mp.setDataSource(PATH_TO_FILE);
mp.prepare();
mp.start();

在Stagefright中,会看到如下的处理:

1.将影片文件的绝对路径指定给uri:

[cpp] view plain copy print?

  1. status_tAwesomePlayer::setDataSource(
  2. constchar*uri,constKeyedvector<String8,String8>*headers){
  3. mutex::AutolockautoLock(mLock);
  4. returnsetDataSource_l(uri,headers);
  5. }
  6. status_tAwesomePlayer::setDataSource_l(
  7. constchar*uri,constKeyedVector<String8,String8>*headers){
  8. reset_l();
  9. mUri=uri;
  10. if(headers){
  11. mUriHeaders=*headers;
  12. }
  13. //Theactualworkwillbedoneduringpreparationinthecallto
  14. //::finishSetDataSource_ltoavoidblockingthecallingthreadin
  15. //setDataSourceforanysignificanttime.
  16. returnOK;
  17. }

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.启动mqueue:

[cpp] view plain copy print?

  1. status_tAwesomePlayer::prepare(){
  2. Mutex::AutolockautoLock(mLock);
  3. returnprepare_l();
  4. }
  5. status_tAwesomePlayer::prepare_l(){
  6. if(mFlags&PREPARED){
  7. returnOK;
  8. }
  9. if(mFlags&PREPARING){
  10. returnUNKNOWN_ERROR;
  11. }
  12. mIsAsyncPrepare=false;
  13. status_terr=prepareAsync_l();
  14. if(err!=OK){
  15. returnerr;
  16. }
  17. while(mFlags&PREPARING){
  18. mPreparedCondition.wait(mLock);
  19. }
  20. returnmPrepareResult;
  21. }
  22. status_tAwesomePlayer::prepareAsync(){
  23. Mutex::AutolockautoLock(mLock);
  24. if(mFlags&PREPARING){
  25. returnUNKNOWN_ERROR;//asyncpreparealreadypending
  26. }
  27. mIsAsyncPrepare=true;
  28. returnprepareAsync_l();
  29. }
  30. status_tAwesomePlayer::prepareAsync_l(){
  31. if(mFlags&PREPARING){
  32. returnUNKNOWN_ERROR;//asyncpreparealreadypending
  33. }
  34. if(!mQueueStarted){
  35. mQueue.start();
  36. mQueueStarted=true;
  37. }
  38. mFlags|=PREPARING;
  39. mAsyncPrepareEvent=newAwesomeEvent(
  40. this,&AwesomePlayer::onPrepareAsyncEvent);
  41. mQueue.postEvent(mAsyncPrepareEvent);
  42. returnOK;
  43. }

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被触发,根据传来文件的header来创建相应的解析器,并初始化音视频解码器:

[cpp] view plain copy print?

  1. voidAwesomePlayer::onPrepareAsyncEvent(){
  2. sp<prefetcher>prefetcher;
  3. {
  4. Mutex::AutolockautoLock(mLock);
  5. if(mFlags&PREPARE_CANCELLED){
  6. LOGI(”preparewascancelledbeforedoinganything”);
  7. abortPrepare(UNKNOWN_ERROR);
  8. return;
  9. }
  10. if(mUri.size()>0){
  11. //在这个方法中创建解析器
  12. <strong>status_terr=finishSetDataSource_l();</strong>
  13. if(err!=OK){
  14. abortPrepare(err);
  15. return;
  16. }
  17. }
  18. if(mVideoTrack!=NULL&&mVideoSource==NULL){
  19. //初始化视频解码器
  20. <strong>status_terr=initVideoDecoder();</strong>
  21. if(err!=OK){
  22. abortPrepare(err);
  23. return;
  24. }
  25. }
  26. if(mAudioTrack!=NULL&&mAudiOSource==NULL){
  27. //初始化音频解码器
  28. <strong>status_terr=initAudioDecoder();
  29. </strong>
  30. if(err!=OK){
  31. abortPrepare(err);
  32. return;
  33. }
  34. }
  35. prefetcher=mPrefetcher;
  36. }
  37. if(prefetcher!=NULL){
  38. {
  39. Mutex::AutolockautoLock(mLock);
  40. if(mFlags&PREPARE_CANCELLED){
  41. LOGI(”preparewascancelledbeforepreparingtheprefetcher”);
  42. prefetcher.clear();
  43. abortPrepare(UNKNOWN_ERROR);
  44. return;
  45. }
  46. }
  47. LOGI(”callingprefetcher->prepare()”);
  48. status_tresult=
  49. prefetcher->prepare(&AwesomePlayer::ContinuePreparation,this);
  50. prefetcher.clear();
  51. if(result==OK){
  52. LOGI(”prefetcherisdonepreparing”);
  53. }else{
  54. Mutex::AutolockautoLock(mLock);
  55. CHECK_EQ(result,-EINTR);
  56. LOGI(”prefetcher->prepare()wascancelledearly.”);
  57. abortPrepare(UNKNOWN_ERROR);
  58. return;
  59. }
  60. }
  61. Mutex::AutolockautoLock(mLock);
  62. if(mIsAsyncPrepare){
  63. if(mVideoWidth<0||mVideoHeight<0){
  64. notifyListener_l(MEDIA_SET_VIDEO_SIZE,0,0);
  65. }else{
  66. notifyListener_l(MEDIA_SET_VIDEO_SIZE,mVideoWidth,mVideoHeight);
  67. }
  68. notifyListener_l(MEDIA_PREPARED);
  69. }
  70. mPrepareResult=OK;
  71. mFlags&=~(PREPARING|PREPARE_CANCELLED);
  72. mFlags|=PREPARED;
  73. mAsyncPrepareEvent=NULL;
  74. mPreparedCondition.broadcast();
  75. postBufferingEvent_l();
  76. }

void AwesomePlayer::onPrepareAsyncEvent() {
    sp<Prefetcher> prefetcher;

    {
        Mutex::Autolock autoLock(mLock);

        if (mFlags & PREPARE_CANCELLED) {
            LOGI("prepare was cancelled before doing anything");
            abortPrepare(UNKNOWN_ERROR);
            return;
        }

        if (mUri.size() > 0) {
           //在这个方法中创建解析器
          <strong>status_t err = finishSetDataSource_l();</strong>

            if (err != OK) {
                abortPrepare(err);
                return;
            }
        }

        if (mVideoTrack != NULL && mVideoSource == NULL) {
            //初始化视频解码器
           <strong>status_t err = initVideoDecoder();</strong>

            if (err != OK) {
                abortPrepare(err);
                return;
            }
        }

        if (mAudioTrack != NULL && mAudioSource == NULL) {
            //初始化音频解码器
           <strong>status_t err = initAudioDecoder();
</strong>
            if (err != OK) {
                abortPrepare(err);
                return;
            }
        }

        prefetcher = mPrefetcher;
    }
 if (prefetcher != NULL) {
        {
            Mutex::Autolock autoLock(mLock);
            if (mFlags & PREPARE_CANCELLED) {
                LOGI("prepare was cancelled 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 autoLock(mLock);

            CHECK_EQ(result, -EINTR);

            LOGI("prefetcher->prepare() was cancelled early.");
            abortPrepare(UNKNOWN_ERROR);
            return;
        }
    }

 Mutex::Autolock autoLock(mLock);

    if (mIsAsyncPrepare) {
        if (mVideoWidth < 0 || mVideoHeight < 0) {
            notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);
        } else {
            notifyListener_l(MEDIA_SET_VIDEO_SIZE, mVideoWidth, mVideoHeight);
        }

        notifyListener_l(MEDIA_PREPARED);
    }

    mPrepareResult = OK;
    mFlags &= ~(PREPARING|PREPARE_CANCELLED);
    mFlags |= PREPARED;
    mAsyncPrepareEvent = NULL;
    mPreparedCondition.broadcast();

    postBufferingEvent_l();
}

[cpp] view plain copy print?

  1. status_tAwesomePlayer::finishSetDataSource_l(){
  2. sp<DataSource>dataSource;
  3. if(!strncasecmp(“http://”,mUri.string(),7)){
  4. mconnectingDataSource=newHTTPDataSource(mUri,&mUriHeaders);
  5. mLock.unlock();
  6. status_terr=mConnectingDataSource->connect();
  7. mLock.lock();
  8. if(err!=OK){
  9. mConnectingDataSource.clear();
  10. LOGI(”mConnectingDataSource->connect()returned%d”,err);
  11. returnerr;
  12. }
  13. dataSource=newCachingDataSource(
  14. mConnectingDataSource,64*1024,10);
  15. mConnectingDataSource.clear();
  16. }else{
  17. dataSource=DataSource::CreateFromURI(mUri.string(),&mUriHeaders);
  18. }
  19. if(dataSource==NULL){
  20. returnUNKNOWN_ERROR;
  21. }
  22. <strong>sp<Mediaextractor>extractor=MediaExtractor::Create(dataSource);
  23. </strong>
  24. if(extractor==NULL){
  25. returnUNKNOWN_ERROR;
  26. }
  27. dataSource->getDrmInfo(&mDecrypthandle,&mDrmManagerClient);
  28. if(mDecryptHandle!=NULL
  29. &&RightsStatus::RIGHTS_valid!=mDecryptHandle->status){
  30. notifyListener_l(MEDIA_ERROR,MEDIA_ERROR_UNKNOWN,ERROR_NO_LICENSE);
  31. }
  32. if(dataSource->flags()&DataSource::kWantsPrefetching){
  33. mPrefetcher=newPrefetcher;
  34. }
  35. <strong>returnsetDataSource_l(extractor)</strong>;
  36. }

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;
    }

    <strong>sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
</strong>
    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;
    }

   <strong> return setDataSource_l(extractor)</strong>;
}

4.使用extractor对文件进行A/V分离:

[cpp] view plain copy print?

  1. status_tAwesomePlayer::setDataSource_l(constsp<MediaExtractor>&extractor){
  2. boolhaveAudio=false;
  3. boolhaveVideo=false;
  4. for(size_ti=0;i<extractor->countTracks();++i){
  5. sp<MetaData>meta=extractor->getTrackMetaData(i);
  6. constchar*mime;
  7. CHECK(meta->findCString(kKeyMIMEType,&mime));
  8. if(!haveVideo&&!strncasecmp(mime,“video/”,6)){
  9. setVideoSource(extractor->getTrack(i));
  10. haveVideo=true;
  11. }elseif(!haveAudio&&!strncasecmp(mime,“audio/”,6)){
  12. setAudioSource(extractor->getTrack(i));
  13. haveAudio=true;
  14. }
  15. if(haveAudio&&haveVideo){
  16. break;
  17. }
  18. }
  19. if(!haveAudio&&!haveVideo){
  20. returnUNKNOWN_ERROR;
  21. }
  22. mExtractorFlags=extractor->flags();
  23. returnOK;
  24. }

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;
}

5.将解析后的音视频数据分别交给VideoTrack和AudioTrack:

[cpp] view plain copy print?

  1. voidAwesomePlayer::setVideoSource(sp<MediaSource>source){
  2. CHECK(source!=NULL);
  3. if(mPrefetcher!=NULL){
  4. source=mPrefetcher->addSource(source);
  5. }
  6. mVideoTrack=source;
  7. }
  8. voidAwesomePlayer::setAudioSource(sp<MediaSource>source){
  9. CHECK(source!=NULL);
  10. if(mPrefetcher!=NULL){
  11. source=mPrefetcher->addSource(source);
  12. }
  13. mAudioTrack=source;
  14. }

void AwesomePlayer::setVideoSource(sp<MediaSource> source) {
    CHECK(source != NULL);

    if (mPrefetcher != NULL) {
        source = mPrefetcher->addSource(source);
    }

    mVideoTrack = source;
}

void AwesomePlayer::setAudioSource(sp<MediaSource> source) {
 CHECK(source != NULL);

 if (mPrefetcher != NULL) {
 source = mPrefetcher->addSource(source);
 }

 mAudioTrack = source;
}

6.根据mVideoTrck中的编码类型来选择 video decoder 同理根据mAudioTrack中的编码类型来选择 audio decoder:

[cpp] view plain copy print?

  1. status_tAwesomePlayer::initVideoDecoder(){
  2. mVideoSource=OMXCodec::Create(
  3. mClient.interface(),mVideoTrack->getFormat(),
  4. false,//createEncoder
  5. mVideoTrack);
  6. if(mVideoSource!=NULL){
  7. int64_tdurationUs;
  8. if(mVideoTrack->getFormat()->findInt64(kKeyDuration,&durationUs)){
  9. Mutex::AutolockautoLock(mMiscStateLock);
  10. if(mDurationUs<0||durationUs>mDurationUs){
  11. mDurationUs=durationUs;
  12. }
  13. }
  14. CHECK(mVideoTrack->getFormat()->findInt32(kKeyWidth,&mVideoWidth));
  15. CHECK(mVideoTrack->getFormat()->findInt32(kKeyHeight,&mVideoHeight));
  16. status_terr=mVideoSource->start();
  17. if(err!=OK){
  18. mVideoSource.clear();
  19. returnerr;
  20. }
  21. }
  22. returnmVideoSource!=NULL?OK:UNKNOWN_ERROR;
  23. }

status_t AwesomePlayer::initVideoDecoder() {
    mVideoSource = OMXCodec::Create(
            mClient.interface(), mVideoTrack->getFormat(),
            false, // createEncoder
            mVideoTrack);

    if (mVideoSource != NULL) {
        int64_t durationUs;
        if (mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
            Mutex::Autolock autoLock(mMiscStateLock);
            if (mDurationUs < 0 || durationUs > mDurationUs) {
                mDurationUs = durationUs;
            }
        }

        CHECK(mVideoTrack->getFormat()->findInt32(kKeyWidth, &mVideoWidth));
        CHECK(mVideoTrack->getFormat()->findInt32(kKeyHeight, &mVideoHeight));

        status_t err = mVideoSource->start();

        if (err != OK) {
            mVideoSource.clear();
            return err;
        }
    }

    return mVideoSource != NULL ? OK : UNKNOWN_ERROR;
}

7.将mVideoEvent放入mQueue中,开始解码播放,并交由mvideoRenderer来画出 audio的数据则交由audioplayer来管理,它最终将解码的数据交给audioTrack并由audioTrack和audioFlinger进行交互,最终将数据交给audio hal层,这个我们以后会做讲解:

[cpp] view plain copy print?

  1. status_tAwesomePlayer::play(){
  2. Mutex::AutolockautoLock(mLock);
  3. returnplay_l();
  4. }
  5. status_tAwesomePlayer::play_l(){
  6. if(mFlags&PLAYING){
  7. returnOK;
  8. }
  9. if(!(mFlags&PREPARED)){
  10. status_terr=prepare_l();
  11. if(err!=OK){
  12. returnerr;
  13. }
  14. }
  15. mFlags|=PLAYING;
  16. mFlags|=FIRST_FRAME;
  17. booldeferredAudioSeek=false;
  18. if(mAudioSource!=NULL){
  19. if(mAudioPlayer==NULL){
  20. if(mAudioSink!=NULL){
  21. //音频数据由audioplayer进行管理
  22. mAudioPlayer=newAudioPlayer(mAudioSink);
  23. mAudioPlayer->setSource(mAudioSource);
  24. //We’vealreadystartedtheMediaSourceinordertoenable
  25. //theprefetchertoreaditsdata.
  26. //调用audioPlayer的start方法则是调用audioSource对数据进行解码
  27. //并将解码似得数据最终交给audioTrack,并调用audioTrack的start方法与audioFlinger进行交互
  28. status_terr=mAudioPlayer->start(
  29. true/*sourceAlreadyStarted*/);
  30. if(err!=OK){
  31. deletemAudioPlayer;
  32. mAudioPlayer=NULL;
  33. mFlags&=~(PLAYING|FIRST_FRAME);
  34. returnerr;
  35. }
  36. deletemTimeSource;
  37. mTimeSource=mAudioPlayer;
  38. deferredAudioSeek=true;
  39. mWatchForAudioSeekComplete=false;
  40. mWatchForAudioEOS=true;
  41. }
  42. }else{
  43. mAudioPlayer->resume();
  44. }
  45. postCheckAudioStatusEvent_l();
  46. }
  47. if(mTimeSource==NULL&&mAudioPlayer==NULL){
  48. mTimeSource=newSystemTimeSource;
  49. }
  50. if(mVideoSource!=NULL){
  51. //Kickoffvideoplayback
  52. //将mVideoEvent放入queue中
  53. postVideoEvent_l();
  54. }
  55. if(deferredAudioSeek){
  56. //Iftherewasaseekrequestwhilewewerepaused
  57. //andwe’rejuststartingupagain,honortherequestnow.
  58. seekAudioIfNecessary_l();
  59. }
  60. if(mFlags&AT_EOS){
  61. //Legacybehaviour,ifastreamfinishesplayingandthen
  62. //isstartedagain,weplayfromthestart…
  63. seekto_l(0);
  64. }
  65. if(mDecryptHandle!=NULL){
  66. int64_tposition;
  67. getPosition(&position);
  68. mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
  69. Playback::START,position/1000);
  70. }
  71. returnOK;
  72. }
  73. voidAwesomePlayer::postVideoEvent_l(int64_tdelayUs){
  74. if(mVideoEventPending){
  75. return;
  76. }
  77. mVideoEventPending=true;
  78. mQueue.postEventwithDelay(mVideoEvent,delayUs<0?10000:delayUs);
  79. }

status_t AwesomePlayer::play() {
    Mutex::Autolock autoLock(mLock);
    return play_l();
}
status_t AwesomePlayer::play_l() {
    if (mFlags & PLAYING) {
        return OK;
    }

    if (!(mFlags & PREPARED)) {
        status_t err = prepare_l();

        if (err != OK) {
            return err;
        }
    }

    mFlags |= PLAYING;
    mFlags |= FIRST_FRAME;

    bool deferredAudioSeek = false;

    if (mAudioSource != NULL) {
        if (mAudioPlayer == NULL) {
            if (mAudioSink != NULL) {
                //音频数据由audioplayer进行管理
               mAudioPlayer = new AudioPlayer(mAudioSink);
                mAudioPlayer->setSource(mAudioSource);

                // We've already started the MediaSource in order to enable
                // the prefetcher to read its data.
                  //调用audioPlayer的start方法则是调用audioSource对数据进行解码
                   //并将解码似得数据最终交给audioTrack,并调用audioTrack的start方法与audioFlinger进行交互
                  status_t err = mAudioPlayer->start(
                        true /* sourceAlreadyStarted */);

                if (err != OK) {
                    delete mAudioPlayer;
                    mAudioPlayer = NULL;

                    mFlags &= ~(PLAYING | FIRST_FRAME);

                    return err;
                }

                delete mTimeSource;
                mTimeSource = mAudioPlayer;

                deferredAudioSeek = true;

                mWatchForAudioSeekComplete = false;
                mWatchForAudioEOS = true;
            }
        } else {
            mAudioPlayer->resume();
        }

        postCheckAudioStatusEvent_l();
    }

    if (mTimeSource == NULL && mAudioPlayer == NULL) {
        mTimeSource = new SystemTimeSource;
    }

    if (mVideoSource != NULL) {
        // Kick off video playback
        //将mVideoEvent放入queue中
         postVideoEvent_l();
    }

    if (deferredAudioSeek) {
        // If there was a seek request while we were paused
        // and we're just starting up again, honor the request now.
        seekAudioIfNecessary_l();
    }

    if (mFlags & AT_EOS) {
        // Legacy behaviour, if a stream finishes playing and then
        // is started again, we play from the start...
        seekTo_l(0);
    }

    if (mDecryptHandle != NULL) {
        int64_t position;
        getPosition(&position);
        mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
                Playback::START, position / 1000);
    }

    return OK;
}

void AwesomePlayer::postVideoEvent_l(int64_t delayUs) {
 if (mVideoEventPending) {
 return;
 }

 mVideoEventPending = true;
 mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs);
}

[cpp] view plain copy print?

  1. voidAwesomePlayer::onVideoEvent()
  2. {
  3. mVideoSource->read(&mVideoBuffer,&options);
  4. mVideoRenderer->render(mVideoBuffer);
  5. postVideoEvent_l();
  6. }

void AwesomePlayer::onVideoEvent()
{
  mVideoSource->read(&mVideoBuffer, &options);
  mVideoRenderer->render(mVideoBuffer);

  postVideoEvent_l();
}

转自:https://blog.csdn.net/itachi85/article/details/7216639

相关阅读

淘宝开店的流程是什么?应该怎么开店?

多少的商家想要进入到淘宝的平台中去销售自己的产品,那么有一个步骤是需要去做的,那就是淘宝开店,那么淘宝开店的流程是什么,应该怎么

中国银行网上银行怎么交话费具体流程图解

进入http://www.boc.cn中国银行网上银行后点击【个人客户网银登录】输入用户名、密码、验证码。如果是第一次使用还需要下载安装

返利网F币怎么兑换现金?兑换流程有哪些

返利网F币怎么兑换现金?兑换流程有哪些?很多使用返利网或者是返还网的用户不知道返利网F币怎么兑换现金,要知道,其实F币是返利类网

项目工作流程

企业开发项目立项书 https://wenku.baidu.com/view/2bc5b7db6429647d27284b73f242336c1fb9304e.html from=search 项目名称,项目

PPPoE工作流程

PPPoE(英语:Point-to-Point Protocol Over Ethernet) 以太网上的点对点协议,是将点对点协议(PPP)封装在以太网(Ethernet)框架中的一种网络

分享到:

栏目导航

推荐阅读

热门阅读