PacketQueue
typedef struct PacketQueue {
MyAVPacketList *first_pkt, *last_pkt; //队首,队尾指针
int nb_packets; //队列中一共有多少个节点
int size; //队列所有节点字节总数,用于计算cache大小
int64_t duration; //队列所有节点的合计时长
int abort_request; //1终止 0正常运行
int serial; 队列序列号(=最后节点的serial,≥前面节点的serial)当插入flush_pkt时+1
SDL_mutex *mutex; // 互斥信号量-----保证对队列的多线程安全(正确读写)👈因为有“主线程和callback函数”2个线程要访问
SDL_cond *cond; // 条件变量----------保证线程的同步操作👈因为有“主线程和callback函数”2个线程要访问
} PacketQueue;
typedef struct MyAVPacketList {
AVPacket pkt;
struct MyAVPacketList *next;
int serial; //ffplay中多处用到serial的概念,一般用于区分是否连续数据
} MyAVPacketList;//单个节点
PacketQueue操作提供以下方法:
//serial用于识别是否属于连续的图像
packet_queue_init 初始化 //初始化用于初始各个字段的值,并创建mutex和cond:
packet_queue_destroy销毁//销毁过程负责清理mutex和cond.
packet_queue_start 启用
packet_queue_abort 中止
packet_queue_get 获取一个节点 = PacketQuene更新 + 拿出后free,没有且就阻塞等/非阻塞返回
packet_queue_put 存入一个节点 = 写入packet_queue_put_private + 释放av_packet_unref
真正放入:packet_queue_put_private = av_malloc + 填充 + 入队(链表) + PacketQuene更新
packet_queue_put_nullpacket:存入一个空节点
packet_queue_flush 清除队列内所有的节点
由于向队列的插入数据实在主线程中完成的,而取数据则是在callback线程中进行的,所以有可能在
取数据的时候,队列为空。在packet_queue_get中有一个block参数,指定在无数据的时候是否阻塞线程等待。
1、创建(设abort_request = 1)
static int packet_queue_init(PacketQueue *q)
{
memset(q, 0, sizeof(PacketQueue));
q->mutex = SDL_CreateMutex();
//if (!q->mutex) {av_log(NULL, AV_LOG_FATAL, "SDL_CreateMutex(): %s\n", SDL_GetError());return AVERROR(ENOMEM);}
q->cond = SDL_CreateCond();
//if (!q->cond) {av_log(NULL, AV_LOG_FATAL, "SDL_CreateCond(): %s\n", SDL_GetError());return AVERROR(ENOMEM);}
q->abort_request = 1;//
return 0;
}
2、销毁
static void packet_queue_destroy(PacketQueue *q)
{
packet_queue_flush(q);
SDL_DestroyMutex(q->mutex);
SDL_DestroyCond(q->cond);
}
2.1 清空队列中的所有节点。比如用于销毁队列、seek操作等
static void packet_queue_flush(PacketQueue *q)
{
MyAVPacketList *pkt, *pkt1;
SDL_LockMutex(q->mutex);
for (pkt = q->first_pkt; pkt; pkt = pkt1) {
pkt1 = pkt->next;
av_packet_unref(&pkt->pkt);
av_freep(&pkt);
}
q->last_pkt = NULL;
q->first_pkt = NULL;
q->nb_packets