ijkplayer系列4:消息隊列MessageQueue

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;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章