播放器线程模型
1:主线程输入文件 — 然后创建解复用线程 –
2 :解复用线程解码书pkt放入各自AV队列中 ---- 然后创建视频解码线程
3:音频解码在主线程中 由音频参数定义的回调函数决定 视频解码在视频解码线程中 并且将解码好的frame 放入解码视频队列
4:SDL开启一个音频渲染线程 从音频回调函数中取出解码好的音频文件传入声卡驱动
5:视频渲染有定义好的函数从视频解码队列中获取解码文件进行渲染
###队列定义
typedef struct PacketQueue {
AVPacketList *first_pkt, *last_pkt;
int nb_packets;
int size;
SDL_mutex *mutex;
SDL_cond *cond;
} PacketQueue;
队列首尾
队列个数
队列中内容总大小
定义一个线程锁
定义一个条件变量
队列相关函数
初始化
void packet_queue_init(PacketQueue *q) {
memset(q, 0, sizeof(PacketQueue));
q->mutex = SDL_CreateMutex();
q->cond = SDL_CreateCond();
}
从加速 从队列中取pkt 如果为空等待信号量… 得到数据返回给pkt 然后解锁
int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block)
{
AVPacketList *pkt1;
int ret;
SDL_LockMutex(q->mutex);
for(;;) {
if(global_video_state->quit) {
fprintf(stderr, "quit from queue_get\n");
ret = -1;
break;
}
pkt1 = q->first_pkt;
if (pkt1) {
q->first_pkt = pkt1->next;
if (!q->first_pkt)
q->last_pkt = NULL;
q->nb_packets--;
q->size -= pkt1->pkt.size;
*pkt = pkt1->pkt;
av_free(pkt1);
ret = 1;
break;
} else if (!block) {
ret = 0;
break;
} else {
fprintf(stderr, "queue is empty, so wait a moment and wait a cond signal\n");
SDL_CondWait(q->cond, q->mutex);
}
}
SDL_UnlockMutex(q->mutex);
return ret;
}
给队列中增加pkt 加锁 增加pkt 发送信号量-> 解锁
int packet_queue_put(PacketQueue *q, AVPacket *pkt) {
AVPacketList *pkt1;
if(av_dup_packet(pkt) < 0) {
return -1;
}
pkt1 = av_malloc(sizeof(AVPacketList));
if (!pkt1)
return -1;
pkt1->pkt = *pkt;
pkt1->next = NULL;
SDL_LockMutex(q->mutex);
if (!q->last_pkt)
q->first_pkt = pkt1;
else
q->last_pkt->next = pkt1;
q->last_pkt = pkt1;
q->nb_packets++;
q->size += pkt1->pkt.size;
//fprintf(stderr, "enqueue, packets:%d, send cond signal\n", q->nb_packets);
SDL_CondSignal(q->cond);
SDL_UnlockMutex(q->mutex);
return 0;
}