Many of the video processing processes are very time-consuming, if all are placed in a large thread space. The effects of user experience can be imagined. Therefore, asynchronous operations are usually performed.
AwesomePlayer uses event scheduling to implement drivers and calls between these functions.
Internal variables in AwesomePlayer
[Cpp]
TimedEventQueue mQueue;
This mQueue is the event queue of AwesomePlayer and also the event scheduler. From the name of his type, we can clearly see that he is a time-based event queue. Next, let's see how it works.
1. First, let's look at the internal structure of TimedEventQueue. There is a List <QueueItem> In TimedEventQueue. Each QueueItem contains the enent and time.
[Cpp]
Struct QueueItem {
Sp <Event> event;
Int64_t realtime_us;
};
One independent thread threadEntry is created in TimedEventQueue: start, and 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. the purpose of List <QueueItem> is to maintain an event queue according to the delay time. The threadEntry thread constantly extracts an event from the queue header, and then uses event-> fire (this, now_us ); calls back the corresponding function registered in advance to this event.
3. Then, let's see how AwesomePlayer uses TimedEventQueue. AwesomePlayer defines many types of event Events and binds function functions related to these events.
[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 );
The reason has also been mentioned before, because many audio and video processing functions are time-consuming. If AwesomePlayer wants to use a function, it is not called in a straight line, but abstracted into an AwesomeEvent, bind the function to be called with the event. TimedEventQueue: postTimedEvent () is used to place the message in the queue of TimedEventQueue according to the delay priority. Then AwesomePlayer does not work. After TimedEventQueue start, the Internal Threads will extract these events from the queue in sequence, and then use the event-> fire callback event function. In this way, AwesomePlayer is achieved.
4. The general process of mediaPlayer is described earlier.
MediaPlayer. setDataSource (path );
MediaPlayer. prepare ();
MediaPlayer. start ();
This is also the process in AwesomePlayer, In the AwesomePlayer prepare () related functions.
[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;
}
He does not actually call the real function of onPrepareAsyncEvent (). He just creates a mAsyncPrepareEvent after mQueue start and inserts it into mQueue, the specific call is done by the threadEntry thread in the mQueue.