awesomeplayer_event 分析

来源:互联网 发布:博奥软件官网 编辑:程序博客网 时间:2024/05/26 12:58
awesomeplayer里面,最重要的一个函数,就是AwesomePlayer::onVideoEvent
这个函数囊括了AV同步,元数据读取,帧数据显示等很多工作。
我们前面提到过这个函数。现在针对这个函数总结一下他的工作流程

首先总结一下onVideoEvent是如何产生的
前面讲过,status_t AwesomePlayer::prepareAsync_l() 调用的时候,会调用mQueue.start
status_t AwesomePlayer::prepareAsync_l() {    if (!mQueueStarted) {        mQueue.start();        mQueueStarted = true;    }}
这里实际上就是创建一个线程
<pre name="code" class="cpp">void TimedEventQueue::start() {    pthread_create(&mThread, &attr, ThreadWrapper, this);}void *TimedEventQueue::ThreadWrapper(void *me) {    static_cast<TimedEventQueue *>(me)->threadEntry();}void TimedEventQueue::threadEntry() {    for (;;) {        {            event_id eventID = 0;            for (;;) {                List<QueueItem>::iterator it = mQueue.begin();                eventID = (*it).event->eventID();//取事件                now_us = ALooper::GetNowUs();                int64_t when_us = (*it).realtime_us; //获得约定等待时间                int64_t delay_us;                if (when_us < 0 || when_us == INT64_MAX) {                    delay_us = 0;                } else {                    delay_us = when_us - now_us;                }                if (delay_us <= 0) {                    break;                }                static int64_t kMaxTimeoutUs = 10000000ll;  // 10 secs                bool timeoutCapped = false;                if (delay_us > kMaxTimeoutUs) {                    delay_us = kMaxTimeoutUs;                    timeoutCapped = true;                }                status_t err = mQueueHeadChangedCondition.waitRelative(                        mLock, delay_us * 1000ll);//按照约定时间进行等待                if (!timeoutCapped && err == -ETIMEDOUT) {                    // We finally hit the time this event is supposed to                    // trigger.                    now_us = ALooper::GetNowUs();                    break;                }            }            event = removeEventFromQueue_l(eventID);//等待时间到,取事件,        }        if (event != NULL) {            event->fire(this, now_us); //执行事件的对应函数        }    }}    virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {        (mPlayer->*mMethod)(); }

//AwesomePlayer的构造函数里面,执行mVideoEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoEvent);//在AwesomeEvent的构造函数里,将onVideoEvent函数挂接到mMethod指针上。 

AwesomeEvent(AwesomePlayer *player,   void (AwesomePlayer::*method)())         : mPlayer(player),       mMethod(method) {     }  

mPlayer和mMethod 都是AwesomeEvent 的成员变量,(*mMethod)() 表示调用该指针指向的函数,  mPlayer-> 表示把mPlayer 指针作为(*mMethod)()的第一个参数:this。TimedEventQueue 是一个按照事件约定时间来执行事件携带动作的类。事件的约定时间存在 QueueItem::realtime_us 里,往TimedEventQueue发事件使用 TimedEventQueue::postTimedEvent ,该方法除this以外的第一个参数是事件,第二个参数是该事件约定的执行时间,它是按顺序往列表里填事件的,请看这段代码:

    TimedEventQueue::event_id TimedEventQueue::postTimedEvent() {....    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);  //这样就把事件填到了列表里面.... }
具体到AwesomePlayer::mVideoEvent这个事件,我们做如下说明:
首先被创建
AwesomePlayer::AwesomePlayer(){   mVideoEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoEvent);}//mVideoEvent 事件创建之后的 mPlayer是AwesomePlayer*, 动作是AwesomePlayer::onVideoEvent。首先在AwesomePlayer::play_l里面,会通过调用postVideoEvent_l来触发第一次onVideoEventvoid AwesomePlayer::postVideoEvent_l(int64_t delayUs) {    mVideoEventPending = true;    mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs);//默认延时10ms}
然后onVideoEvent开始进入第一次执行
void AwesomePlayer::onVideoEvent() {    for (;;) {        status_t err = mVideoSource->read(&mVideoBuffer, &options);  // mVideoSource is  a video decoder          options.clearSeekTo();        break;    }
//前面我们介绍过,awesomeplayer把一帧数据送给decoder后,会在mVideoSource->read(即OMXCodec::read)等待,
//一阵视频解码完,openmax component会触发FILL_BUFFER_DONE的onMessage,
//OMXCodec::on_message中会mBufferFilled.signal, 从而使mVideoSource->read跳出等待,继续往下执行
//以下进行AV同步。具体在前面文章介绍过
<pre name="code" class="cpp">    if (wasSeeking == NO_SEEK) { //忽略这一帧的显示        // Let's display the first frame after seeking right away.        int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;        int64_t latenessUs = nowUs - timeUs;        if (latenessUs > 500000ll ) {             mVideoBuffer->release(); // delete this mediabuffer            mVideoBuffer = NULL;            mSeeking = SEEK_VIDEO_ONLY;            mSeekTimeUs = mediaTimeUs;            ///给自己发一个10ms之后执行的事件。触发下一次执行,然后退出            postVideoEvent_l();               return;        }        if (latenessUs > 40000) { //忽略这一帧的显示            // We're more than 40ms late.                 mVideoBuffer->release(); // delete this mediabuffer                 mVideoBuffer = NULL;                 ++mStats.mNumVideoFramesDropped;                     ///给自己发一个10ms之后执行的事件。触发下一次执行,然后退出                 postVideoEvent_l();                return;                  }        if (latenessUs < -10000) {            // We're more than 10ms early.              ///给自己发一个10ms之后执行的事件。触发下一次执行,然后退出            postVideoEvent_l(10000); // to display after a while            return;        }    }//以上进行AV同步。具体在前面文章介绍过        mVideoRenderer->render(mVideoBuffer); //// 通过surfaceflinger把数据显示出来    mVideoBuffer->release(); //显示完毕,通过调用signalBufferReturned,掉用fillOutputBuffer    mVideoBuffer = NULL;    ///给自己发一个10ms之后执行的事件。触发下一次执行,然后退出    postVideoEvent_l();}
实际上onVideoEvent是通过一次次的触发自己下一次执行,来实现的一帧帧的解码。
并且通过控制触发自己下一次执行的时间,实现了AV同步。
并且通过mVideoSource->read实现了元数据读取,emptythisbuffer命令下发
通过mVideoRenderer->render实现了图像显示,
通过mVideoBuffer->release实现了fillthisbuffer命令下发



0 0
原创粉丝点击