視頻處理過程中有很多都是十分耗時的,如果都放在一個大的線程空間中。使用者體驗的效果可想而知。所以通常都是做非同步作業。
AwesomePlayer是通過event事件調度來實現這些功能之間的驅動和調用的。
AwesomePlayer中的內部變數
[cpp]
TimedEventQueue mQueue;
這個mQueue就是AwesomePlayer的事件隊列,也是事件調度器。從他類型的名字上就能很清楚的看出他是以時間為基礎事件隊列。接下來看看它是怎麼玩轉的。
1.先來看TimedEventQueue的內部結構,TimedEventQueue內部有一個 List<QueueItem>,每個QueueItem包含enent和時間
[cpp]
struct QueueItem {
sp<Event> event;
int64_t realtime_us;
};
有一個獨立線程threadEntry是在TimedEventQueue::start被建立,TimedEventQueue::stop被銷毀的。
[cpp]
void TimedEventQueue::start() {
if (mRunning) {
return;
}
mStopped = false;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
pthread_create(&mThread, &attr, ThreadWrapper, this);
pthread_attr_destroy(&attr);
mRunning = true;
}
void TimedEventQueue::stop(bool flush) {
if (!mRunning) {
return;
}
if (flush) {
postEventToBack(new StopEvent);
} else {
postTimedEvent(new StopEvent, INT64_MIN);
}
void *dummy;
pthread_join(mThread, &dummy);
mQueue.clear();
mRunning = false;
}
2.List<QueueItem>目的就是按照延時時間維護一個event事件隊列,threadEntry線程就是不斷的從隊列的頭取出一個event,然後通過 event->fire(this, now_us); 回調到這個event事件提前註冊好的相對應功能函數。
3.然後看看AwesomePlayer是怎麼用TimedEventQueue,AwesomePlayer會定義很多類型的event事件,並把和這些事件相關的功能函數一定綁定起來。
[cpp]
mVideoEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoEvent);
mVideoEventPending = false;
mStreamDoneEvent = new AwesomeEvent(this, &AwesomePlayer::onStreamDone);
mStreamDoneEventPending = false;
mBufferingEvent = new AwesomeEvent(this, &AwesomePlayer::onBufferingUpdate);
mBufferingEventPending = false;
mVideoLagEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoLagUpdate);
mVideoEventPending = false;
mCheckAudioStatusEvent = new AwesomeEvent(this, &AwesomePlayer::onCheckAudioStatus);
原因之前也說了,因為好多音視頻處理的功能是十分耗時間的,假如AwesomePlayer 想用某個功能,他並不是直線去調用它,而是抽象成一種AwesomeEvent,將想要調用的功能函數與事件捆綁。通過TimedEventQueue::postTimedEvent(),按照延時的優先順序把它放到TimedEventQueue的隊列之中。然後AwesomePlayer就不管了。TimedEventQueue start之後,自己內部的線程會從隊列中依次取出這些事件,然後通過event->fire回調事件的功能函數。這樣就達到了AwesomePlayer的目的。
4.之前也介紹過mediaPlayer大致流程就是
mediaPlayer.setDataSource(path);
mediaPlayer.prepare();
mediaPlayer.start();
在AwesomePlayer 也是這種流程,在AwesomePlayer prepare()相關函數中。
[cpp]
status_t AwesomePlayer::prepareAsync_l() {
if (mFlags & PREPARING) {
return UNKNOWN_ERROR; // async prepare already pending
}
if (!mQueueStarted) {
mQueue.start();
mQueueStarted = true;
}
modifyFlags(PREPARING, SET);
mAsyncPrepareEvent = new AwesomeEvent(
this, &AwesomePlayer::onPrepareAsyncEvent);
mQueue.postEvent(mAsyncPrepareEvent);
return OK;
}
他並沒有實際的調用onPrepareAsyncEvent()真正的功能函數,他只是把mQueue start之後,然後建立個mAsyncPrepareEvent事件,把它插入到mQueue之中就不管了,具體調用是由mQueue中的threadEntry線程來做。