jkplayer中傳遞消息一般採用的是生產者-消費者模式。大致原理如下:
生產者可以位於任何一個線程向隊列中添加消息,而消費者(通常只有一個)則通過一個獨立的線程不斷地從隊列中獲取消息,當沒有消息時阻塞(也可以配置成不阻塞,但通常我們會阻塞),當隊列中止使用時線程退出。隊列何時中止一般由生產者決定。顯然,這種模式的核心就是這個消息隊列。
ijkplayer的消息隊列命名爲MessageQueue,不論是從名稱還是結構體的字段定義,你都可以從中看到Android的影子,所以ijkplayer的MessageQueue應該是仿照Android中消息隊列的設計。
MessageQueue聲明和實現都位於ff_ffmsg_queue.h中,關聯的結構體有以下兩個:
typedef struct AVMessage {
// 參考Android Message#what
int what;
// 參考Android Message#arg1
int arg1;
// 參考Android Message#arg2
int arg2;
// 參考Android Message#obj
void *obj;
// 釋放obj,僅當使用msg_queue_put_simple4來添加消息時不爲NULL
void (*free_l)(void *obj);
// 指向下一個消息
struct AVMessage *next;
} AVMessage;
typedef struct MessageQueue {
AVMessage *first_msg, *last_msg;
int nb_messages;
int abort_request;
SDL_mutex *mutex;
SDL_cond *cond;
AVMessage *recycle_msg;
int recycle_count;
int alloc_count;
} MessageQueue;
AVMessage存儲消息內容,並且可以指向下一條消息,而MessageQueue即爲消息隊列。我們不需要關心MessageQueue的成員信息,因爲不會直接使用到,我們對MessageQueue的所有操作都是通過函數來達成,
而AVMessage的成員則可能會直接使用到。
下面我們來看下MessageQueue和AVMessage都提供了哪些函數來操作它們。首先來看下AVMessage相關的函數:
void msg_free_res(AVMessage *msg)
釋放msg的obj成員內存,並將obj置爲NULL。注意,不是釋放msg本身。
void msg_init_msg(AVMessage *msg)
初始化msg,其實就是調用memset清零。
AVMessage相關的函數就只有上面兩個了,好像可有可無的樣子,下面我們來看下MessageQueue的相關函數:
void msg_queue_init(MessageQueue *q)
初始化MessageQueue,這裏面是有實實在在做事情的,所以創建完MessageQueue後不要忘了調用此方法進行初始化工作。
void msg_queue_start(MessageQueue *q)
啓用MessageQueue,初始化完成後還不能使用MessageQueue,必須在調用此方法後纔可以進行後續操作。同時觸發FFP_MSG_FLUSH事件。
void msg_queue_abort(MessageQueue *q)
中止MessageQueue的使用,可以再次調用msg_queue_start()來重新啓用MessageQueue。
void msg_queue_destroy(MessageQueue *q)
銷燬MessageQueue,釋放成員內存,可以再次調用msg_queue_init()來重新初始化。注意,不會釋放MessageQueue本身。
int msg_queue_put(MessageQueue *q, AVMessage *msg)
添加消息,MessageQueue abort時返回-1,正常返回>=0的數。
void msg_queue_put_simple1(MessageQueue *q, int what);
void msg_queue_put_simple2(MessageQueue *q, int what, int arg1);
void msg_queue_put_simple3(MessageQueue *q, int what, int arg1, int arg2);
void msg_queue_put_simple4(MessageQueue *q, int what, int arg1, int arg2, void *obj, int obj_len);
添加消息,不同函數表示傳入的參數的多寡。這裏返回值居然是void而不是和msg_queue_put()相同的int類型,真令人費解。
int msg_queue_get(MessageQueue *q, AVMessage *msg, int block)
獲取隊首消息,同時將該消息從隊列中移除。block不爲0時表示阻塞模式,爲0表示非阻塞模式,阻塞模式下如果當前隊列中沒有消息,則會阻塞直到有新的消息加入才返回該消息,否則直接返回0。MessageQueue abort時返回-1,正常返回>=0的數。
void msg_queue_remove(MessageQueue *q, int what)
移除指定what的所有消息。
void msg_queue_flush(MessageQueue *q)
清空隊列。
創建和銷燬隊列的正確姿勢如下:
// create
MessageQueue* q = (MessageQueue*)malloc(sizeof(MessageQueue);
msg_queue_init(q);
msg_queue_start(q);
// destroy
msg_queue_abort(q);
msg_queue_destroy(q);
free(q);
q = NULL;