news 2026/4/18 6:02:22

FFmepg-- 32-ffplay源码- PacketQueue 的线程安全机制 以及 serial 字段的作用

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
FFmepg-- 32-ffplay源码- PacketQueue 的线程安全机制 以及 serial 字段的作用

文章目录

      • 一 PacketQueue 的线程安全设计
      • 线程同步手段
      • 二 serial 字段的作用详解
        • 为什么需要 serial?
        • serial 的工作机制
      • 三 简化版示例代码
        • 使用场景(解码线程伪代码)
        • Seek 发生时
      • 四 总结

一 PacketQueue 的线程安全设计

在 ffplay.c 中,PacketQueue 是一个典型的生产者-消费者队列:

生产者:read_thread(从文件/网络读取 AVPacket 并放入队列)
消费者:解码线程(如 audio_thread / video_thread)从队列中取出 AVPacket 解码

线程同步手段

typedefstructPacketQueue{AVPacketList*first_pkt,*last_pkt;intnb_packets;// 当前包数量intsize;// 总字节数(用于限流)int64_tduration;// 总时长(毫秒)intabort_request;// 是否请求终止intserial;// 👈 关键字段:播放序列号SDL_mutex*mutex;// 互斥锁SDL_cond*cond;// 条件变量}PacketQueue;

SDL_mutex:保护对队列结构体(如 first_pkt, last_pkt, nb_packets 等)的并发访问。
SDL_cond:用于阻塞/唤醒:
消费者调用 packet_queue_get(…, block=1) 时,若队列为空,则 SDL_CondWait(cond, mutex) 阻塞;
生产者调用 packet_queue_put() 后,调用 SDL_CondSignal(cond) 唤醒等待的消费者。

二 serial 字段的作用详解

为什么需要 serial?

当用户执行 seek(快进/快退)操作时,旧的 AVPacket 已经无效,必须被丢弃。此时可能出现以下情况:

read_thread 可能还在往队列里塞旧数据;
解码线程可能还在处理旧数据;
如果不清除这些“过期”数据,就会出现:
音频“回放杂音”
视频跳帧混乱
音画不同步

serial 用于标识“当前播放上下文”的版本号。

serial 的工作机制

初始化时:q->serial = 0

执行 seek 时:
调用packet_queue_flush(&is->audioq)清空队列;
插入一个特殊的flush_pkt(其data == NULL);
执行q->serial++(例如从 0 → 1)

此后所有新入队的 packet 都会设置pkt->serial = q->serial

解码线程在取到 packet 后,会检查:

if(pkt->serial!=decoder->pkt_serial){av_packet_unref(pkt);continue;// 丢弃旧序列数据}

其中decoder->pkt_serial会在 flush 后被更新为新的 serial。

三 简化版示例代码

以下是一个高度简化但功能完整的PacketQueue实现,突出serial和线程安全逻辑:

#include<SDL2/SDL.h>#include<libavcodec/avcodec.h>#defineMAX_QUEUE_SIZE(15*1024*1024)typedefstructMyAVPacketList{AVPacket pkt;intserial;structMyAVPacketList*next;}MyAVPacketList;typedefstructPacketQueue{MyAVPacketList*first,*last;intnb_packets;intsize;int64_tduration;intabort_request;intserial;// 序列号SDL_mutex*mutex;SDL_cond*cond;}PacketQueue;voidpacket_queue_init(PacketQueue*q){memset(q,0,sizeof(PacketQueue));q->mutex=SDL_CreateMutex();q->cond=SDL_CreateCond();q->serial=0;}intpacket_queue_put(PacketQueue*q,AVPacket*pkt){MyAVPacketList*pkt1;SDL_LockMutex(q->mutex);if(q->abort_request){SDL_UnlockMutex(q->mutex);return-1;}pkt1=av_malloc(sizeof(MyAVPacketList));if(!pkt1)gotofail;pkt1->pkt=*pkt;pkt1->serial=q->serial;// 绑定当前 serialpkt1->next=NULL;if(!q->last)q->first=pkt1;elseq->last->next=pkt1;q->last=pkt1;q->nb_packets++;q->size+=pkt1->pkt.size+sizeof(*pkt1);q->duration+=pkt1->pkt.duration;SDL_CondSignal(q->cond);// 唤醒消费者SDL_UnlockMutex(q->mutex);return0;fail:SDL_UnlockMutex(q->mutex);return-1;}// 获取 packet,block=1 表示阻塞等待intpacket_queue_get(PacketQueue*q,AVPacket*pkt,intblock,int*serial){MyAVPacketList*pkt1;intret;SDL_LockMutex(q->mutex);for(;;){if(q->abort_request){ret=-1;break;}pkt1=q->first;if(pkt1){q->first=pkt1->next;if(!q->first)q->last=NULL;q->nb_packets--;q->size-=pkt1->pkt.size+sizeof(*pkt1);q->duration-=pkt1->pkt.duration;*pkt=pkt1->pkt;if(serial)*serial=pkt1->serial;// 返回 packet 的 serialav_free(pkt1);ret=1;break;}elseif(!block){ret=0;break;}else{SDL_CondWait(q->cond,q->mutex);// 阻塞等待}}SDL_UnlockMutex(q->mutex);returnret;}// seek 时调用:清空队列 + serial++voidpacket_queue_flush(PacketQueue*q){MyAVPacketList*pkt,*pkt1;SDL_LockMutex(q->mutex);for(pkt=q->first;pkt;pkt=pkt1){pkt1=pkt->next;av_packet_unref(&pkt->pkt);av_free(pkt);}q->first=q->last=NULL;q->nb_packets=0;q->size=0;q->duration=0;q->serial++;// 关键:序列号递增SDL_UnlockMutex(q->mutex);}
使用场景(解码线程伪代码)
intwanted_serial=is->audioq.serial;// 期望的 serialwhile(1){intserial;AVPacket pkt;if(packet_queue_get(&is->audioq,&pkt,1,&serial)<0)break;if(serial!=wanted_serial){av_packet_unref(&pkt);continue;// 丢弃旧序列数据}// 正常解码...decode_audio(&pkt);av_packet_unref(&pkt);}
Seek 发生时
// 用户 seek 到新位置packet_queue_flush(&is->audioq);// serial 自增packet_queue_flush(&is->videoq);// read_thread 会重新开始读取,并给新 packet 打上新 serial

四 总结

机制作用
SDL_mutex + SDL_cond实现线程安全的生产者-消费者队列
serial 字段标识“播放上下文”,避免 seek 后旧数据污染
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 7:03:28

Qwen3-14B-MLX-6bit:单模型双模式切换,开启大语言模型效率新纪元

导语 【免费下载链接】Qwen3-14B-MLX-6bit 项目地址: https://ai.gitcode.com/hf_mirrors/Qwen/Qwen3-14B-MLX-6bit 阿里通义千问Qwen3系列模型以创新的双模式切换技术和6bit量化优化&#xff0c;重新定义了大语言模型的效率标准&#xff0c;为企业级AI应用提供了性能与…

作者头像 李华
网站建设 2026/4/18 6:25:12

单卡驱动千亿智能:GPT-OSS-120B如何重构企业AI成本结构

单卡驱动千亿智能&#xff1a;GPT-OSS-120B如何重构企业AI成本结构 【免费下载链接】gpt-oss-120b-unsloth-bnb-4bit 项目地址: https://ai.gitcode.com/hf_mirrors/unsloth/gpt-oss-120b-unsloth-bnb-4bit 导语&#xff1a;当千亿模型走进单GPU时代 2025年AI行业迎来…

作者头像 李华
网站建设 2026/4/18 6:24:40

夸克在线解析 - 网盘在线下载工具

今天教大家一招能解决夸克网盘限制的在线工具。这个工具也是完全免费使用的。下面让大家看看我用这个工具的下载速度咋样。地址获取&#xff1a;放在这里了&#xff0c;可以直接获取 这个速度还是不错的把。对于平常不怎么下载的用户还是很友好的。下面开始今天的教学 输入我给…

作者头像 李华
网站建设 2026/4/18 6:25:05

化工泵阀17-4PH不锈钢螺栓耐腐蚀强,高强度螺丝,支持来图加工

栢尔斯道弗供应17-7PH是以18-8CrNi为基础发展起来的奥氏体-马氏体沉淀硬化不锈钢&#xff0c;又称为控制相变不锈钢。固溶处理后为不稳定的奥氏体组织&#xff0c;有良好的塑韧性和加工性&#xff0c;经过调整&#xff0c;使奥氏体析出碳化物候成分发生变化&#xff0c;再经过马…

作者头像 李华
网站建设 2026/4/18 3:17:10

震惊!揭秘GEO推广优化真相,选错平台损失巨大!

震惊&#xff01;揭秘GEO推广优化真相&#xff0c;选错平台损失巨大&#xff01;引言在当今数字化时代&#xff0c;企业要想在竞争激烈的市场中脱颖而出&#xff0c;必须充分利用各种先进的营销工具和技术。GEO推广优化&#xff08;Geographic Optimization&#xff09;作为一种…

作者头像 李华
网站建设 2026/4/18 6:24:37

光储设计仿真系统推荐

一、国际品牌1.PVSYST作为光储设计仿真领域的经典工具&#xff0c;PVSYST深受全球建筑师、工程师和研究人员青睐。它支持并网、离网等多种光伏储能系统的设计与数据分析&#xff0c;内置广泛的气象数据库和组件数据库&#xff0c;能满足项目从初步设计到详细数据分析的全流程需…

作者头像 李华