awesomeplayer_event 分析

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来触发第一次onVideoEvent
void 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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值