文章目录
消息队列,用于发送,设置播放器的状态,实现ui界面,jikpalyer以及ffplay之间的通信
播放器状态转换图
实线箭头 连接的状态变化通过 API 调⽤完成
虚线箭头 连接的状态变化是通过 播放器内部执⾏完特定任务或者发⽣错误 ⽽⾃动发⽣的状态
变化
播放器状态对应的消息:
- idle: MP_STATE_IDLE 闲置状态,刚完成构造的 FijkPlaye
- initialized: MP_STATE_INITIALIZED 初始化完成状态,和 idle 状态相⽐,仅是多了输⼊媒体
数据源的信息 - async_preparing:MP_STATE_ASYNC_PREPARING 异步准备状态,进行打开媒体⽂件,打开解码器以及新建解码线程,新建数据 read 线程,打开⾳频输出设备,新建视频输出线程等
- prepared:MP_STATE_PREPARED,完成指定任务后⾃动转化为此状态。此状态下已经缓冲并解码了⼀部分⾳视频数据,可以随时进⾏播放
- started:MP_STATE_STARTED 媒体(视频、⾳频)正在播放中
- paused:MP_STATE_PAUSED 媒体(视频、⾳频)播放暂停
- completed:MP_STATE_COMPLETED 媒体(视频、⾳频)播放完成。 可重新从头开始播
放。 - stop: MP_STATE_STOPPED 播放器各种线程占⽤资源都已经释放。 ⾳频设备关闭
- error: MP_STATE_ERROR 播放器出现错误
消息对象
cpp
typedef struct AVMessage {
int what; // 消息类型
int arg1; // 参数1
int arg2; // 参数2
void *obj; // 如果arg1 arg2还不够存储消息则使⽤该参数
void (*free_l)(void *obj); // 释放obj指向的函数
struct AVMessage *next; // 下⼀个消息
} AVMessage;
消息队列
cpp
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;
recycle_msg:
用于回收消息,消息使用链表进行存储,当消息取出时,通过recycle_msg链接该消息,重新用做新消息使用
作用:节省了对新消息申请空间,以及对取出的消息释放内存操作
消息队列api
插入消息
cpp
// 消息队列内部重新去构建 AVMessage(重新申请AVMessage,或者来自于recycle_msg)
// 新的消息插入到尾部
int msg_queue_put_private(MessageQueue *q, AVMessage *msg)
{
AVMessage *msg1;
if(q->abort_request)
return -1;
//1. 消息体使用回收的资源还是重新malloc
msg1 = q->recycle_msg;
if(msg1) {
q->recycle_msg = msg1->next;
q->recycle_count++;
} else {
q->alloc_count++;
msg1 = (AVMessage *)av_malloc(sizeof(AVMessage));
}
*msg1 = *msg;
msg1->next = NULL;
if(!q->first_msg) {
q->first_msg = msg1;
} else {
q->last_msg->next = msg1;
}
q->last_msg = msg1;
q->nb_messages++;
SDL_CondSignal(q->cond);
return 0;
}
获取消息
cpp
int msg_queue_get(MessageQueue *q, AVMessage *msg, int block)
{
AVMessage *msg1;
int ret;
SDL_LockMutex(q->mutex);
for(;;) {
if(q->abort_request) {
ret = -1;
break;
}
//获取消息
msg1 = q->first_msg;
if(msg1) {
q->first_msg = msg1->next;
if(!q->first_msg)
q->last_msg = NULL;
q->nb_messages--;
*msg = *msg1;
msg1->obj = NULL;
msg1->next = q->recycle_msg;
q->recycle_msg = msg1;
ret =1;
break; // 记得这里有个break的
} else if (!block) {
ret = 0;
break;
} else {
SDL_CondWait(q->cond, q->mutex);
}
}
SDL_UnlockMutex(q->mutex);
return ret;
}
初始化消息
cpp
// 消息队列初始化
void msg_queue_init(MessageQueue *q)
{
memset(q, 0, sizeof(MessageQueue));
q->mutex = SDL_CreateMutex();
q->cond = SDL_CreateCond();
q->abort_request = 1;
}
插入消息加锁
cpp
int msg_queue_put(MessageQueue *q, AVMessage *msg)
{
int ret;
SDL_LockMutex(q->mutex);
ret = msg_queue_put_private(q, msg);
SDL_UnlockMutex(q->mutex);
return ret;
}
初始化消息
cpp
void msg_init_msg(AVMessage *msg)
{
memset(msg, 0, sizeof(AVMessage));
}
设置消息参数
cpp
void msg_queue_put_simple1(MessageQueue *q, int what)
{
AVMessage msg;
msg_init_msg(&msg);
msg.what = what;
msg_queue_put(q, &msg);
}
// 释放msg的obj资源
void msg_obj_free_l(void *obj)
{
av_free(obj);
}
//插入消息,带消息类型,带2个参数,带obj
void msg_queue_put_simple4(MessageQueue *q, int what, int arg1, int arg2, void *obj, int obj_len)
{
AVMessage msg;
msg_init_msg(&msg);
msg.what = what;
msg.arg1 = arg1;
msg.arg2 = arg2;
msg.obj = av_malloc(obj_len);
memcpy(msg.obj, obj, obj_len);
msg.free_l = msg_obj_free_l;
msg_queue_put(q, &msg);
}
消息队列初始化
cpp
void msg_queue_init(MessageQueue *q)
{
memset(q, 0, sizeof(MessageQueue));
q->mutex = SDL_CreateMutex();
q->cond = SDL_CreateCond();
q->abort_request = 1;
}
清空消息
cpp
// 消息队列flush,清空所有的消息
void msg_queue_flush(MessageQueue *q)
{
AVMessage *msg, *msg1;
SDL_LockMutex(q->mutex);
for (msg = q->first_msg; msg != NULL; msg = msg1) { // 这个时候的obj没有清空?那会导致泄漏,实际是把消息对象暂存到了recycle_msg
msg1 = msg->next;
msg->next = q->recycle_msg;
q->recycle_msg = msg;
}
q->last_msg = NULL;
q->first_msg = NULL;
q->nb_messages = 0;
SDL_UnlockMutex(q->mutex);
}
销毁消息
cpp
void msg_queue_destroy(MessageQueue *q)
{
msg_queue_flush(q);
SDL_LockMutex(q->mutex);
while(q->recycle_msg) {
AVMessage *msg = q->recycle_msg;
if (msg)
q->recycle_msg = msg->next;
msg_free_res(msg);
av_freep(&msg);
}
SDL_UnlockMutex(q->mutex);
SDL_DestroyMutex(q->mutex);
SDL_DestroyCond(q->cond);
}
启动消息队列
cpp
void msg_queue_start(MessageQueue *q)
{
SDL_LockMutex(q->mutex);
q->abort_request = 0;
// 插入一个消息
AVMessage msg;
msg_init_msg(&msg);
msg.what = FFP_MSG_FLUSH;
msg_queue_put_private(q, &msg);
SDL_UnlockMutex(q->mutex);
}
终止消息队列
cpp
void msg_queue_abort(MessageQueue *q)
{
SDL_LockMutex(q->mutex);
q->abort_request = 1;
SDL_CondSignal(q->cond);
SDL_UnlockMutex(q->mutex);
}
删除消息
cpp
// 消息删除 把队列里同一消息类型的消息全删除掉
void msg_queue_remove(MessageQueue *q, int what)
{
AVMessage **p_msg, *msg, *last_msg;
SDL_LockMutex(q->mutex);
last_msg = q->first_msg;
if (!q->abort_request && q->first_msg) {
p_msg = &q->first_msg;
while (*p_msg) {
msg = *p_msg;
if (msg->what == what) { // 同类型的消息全部删除
*p_msg = msg->next;
msg_free_res(msg);
msg->next = q->recycle_msg; // 消息体回收
q->recycle_msg = msg;
q->nb_messages--;
} else {
last_msg = msg;
p_msg = &msg->next;
}
}
if (q->first_msg) {
q->last_msg = last_msg;
} else {
q->last_msg = NULL;
}
}
SDL_UnlockMutex(q->mutex);
}