当前位置: 首页 > news >正文

mpegts.c中handle_packet() 函数代码注释


author: hjjdebug
date : 2025年 07月 14日 星期一 17:13:07 CST
descrip: mpegts.c中handle_packet() 函数代码注释


文章目录

  • 1. handle_packet() 的功能
  • 2. 上层调用接口
  • 3. 代码注释
  • 4. 概括归纳.

1. handle_packet() 的功能

ffmpeg 中函数调用链为: handle_packets → handle_packet,
hanle_packet 每次分析188字节
解析TS包头部信息,并根据PID(包标识符)将数据分发给对应的过滤器进行处理.
简单说就是解析,组包.
handle_packets 就是循环调用handle_packet 来处理一系列小包
可见handle_packet 是数据包处理的核心函数,承上启下.
其再上一层往往是是为了读取一个pkt

2. 上层调用接口

举3个响当当的上层接口.

例如1: avformat_open_input.
0 in handle_packet of libavformat/mpegts.c:2950
1 in handle_packets of libavformat/mpegts.c:3231
2 in mpegts_read_header of libavformat/mpegts.c:3362
3 in avformat_open_input of libavformat/demux.c:316例如2: avformat_find_stream_info
0 in handle_packet of libavformat/mpegts.c:2950
1 in handle_packets of libavformat/mpegts.c:3231
2 in mpegts_read_packet of libavformat/mpegts.c:3500
3 in ff_read_packet of libavformat/demux.c:576
4 in read_frame_internal of libavformat/demux.c:1264
5 in avformat_find_stream_info of libavformat/demux.c:2624例如3: av_read_frame 
0 in handle_packet of libavformat/mpegts.c:2950
1 in handle_packets of libavformat/mpegts.c:3231
2 in mpegts_read_packet of libavformat/mpegts.c:3500
3 in ff_read_packet of libavformat/demux.c:576
4 in read_frame_internal of libavformat/demux.c:1264
5 in av_read_frame of libavformat/demux.c:1473

3. 代码注释

来自ffmpeg6.1.1 libavformat/mpegts.c

static int handle_packet(MpegTSContext* ts, const uint8_t* packet, int64_t pos)
{MpegTSFilter* tss;int len, pid, cc, expected_cc, cc_ok, afc, is_start, is_discontinuity,has_adaptation, has_payload;const uint8_t *p, *p_end;pid = AV_RB16(packet + 1) & 0x1fff; //提取pidis_start = packet[1] & 0x40;  //判断数据包起始位tss = ts->pids[pid]; //获取过滤器if (ts->auto_guess && !tss && is_start){add_pes_stream(ts, pid, -1); //没有过滤器,添加pes 流tss = ts->pids[pid];}if (!tss)return 0;if (is_start)tss->discard = discard_pid(ts, pid); //判读pid 是否被抛弃if (tss->discard)return 0;ts->current_pid = pid;afc = (packet[3] >> 4) & 3;if (afc == 0) /* reserved value */return 0;has_adaptation = afc & 2;has_payload = afc & 1;is_discontinuity = has_adaptation && packet[4] != 0 && /* with length > 0 */(packet[5] & 0x80); /* and discontinuity indicated *//* continuity check (currently not used) */cc = (packet[3] & 0xf);expected_cc = has_payload ? (tss->last_cc + 1) & 0x0f : tss->last_cc;cc_ok = pid == 0x1FFF || // null packet PIDis_discontinuity || tss->last_cc < 0 || expected_cc == cc;tss->last_cc = cc;if (!cc_ok){av_log(ts->stream, AV_LOG_DEBUG,"Continuity check failed for pid %d expected %d got %d\n",pid, expected_cc, cc);if (tss->type == MPEGTS_PES){PESContext* pc = tss->u.pes_filter.opaque;pc->flags |= AV_PKT_FLAG_CORRUPT;}}if (packet[1] & 0x80){ //检查错误标志av_log(ts->stream, AV_LOG_DEBUG, "Packet had TEI flag set; marking as corrupt\n");if (tss->type == MPEGTS_PES){PESContext* pc = tss->u.pes_filter.opaque;pc->flags |= AV_PKT_FLAG_CORRUPT;}}p = packet + 4;  //跳过头部字节if (has_adaptation){int64_t pcr_h;int pcr_l;if (parse_pcr(&pcr_h, &pcr_l, packet) == 0)tss->last_pcr = pcr_h * 300 + pcr_l;/* skip adaptation field */p += p[0] + 1; //跳过适配域字段}/* if past the end of packet, ignore */p_end = packet + TS_PACKET_SIZE;if (p >= p_end || !has_payload)return 0;if (pos >= 0)  //pos 是当前的文件位置{av_assert0(pos >= TS_PACKET_SIZE);ts->pos47_full = pos - TS_PACKET_SIZE;}if (tss->type == MPEGTS_SECTION){  //已经跳过了adaption fieldif (is_start){/* pointer field present */len = *p++;  //这个len 一般为0if (len > p_end - p)return 0;if (len && cc_ok){/* write remaining section bytes */write_section_data(ts, tss,p, len, 0);/* check whether filter has been closed */if (!ts->pids[pid])return 0;}p += len;if (p < p_end){write_section_data(ts, tss,p, p_end - p, 1);}}else{if (cc_ok){write_section_data(ts, tss,p, p_end - p, 0);}}// stop find_stream_info from waiting for more streams// when all programs have received a PMTif (ts->stream->ctx_flags & AVFMTCTX_NOHEADER && ts->scan_all_pmts <= 0){int i;for (i = 0; i < ts->nb_prg; i++){if (!ts->prg[i].pmt_found)break;}if (i == ts->nb_prg && ts->nb_prg > 0){av_log(ts->stream, AV_LOG_DEBUG, "All programs have pmt, headers found\n");ts->stream->ctx_flags &= ~AVFMTCTX_NOHEADER;}}}else{int ret;// Note: The position here points actually behind the current packet.if (tss->type == MPEGTS_PES){if ((ret = tss->u.pes_filter.pes_cb(tss, p, p_end - p, is_start,pos - ts->raw_packet_size))< 0)return ret;}}return 0;
}

4. 概括归纳.

TS包头解析
通过AV_RB16(packet + 1) & 0x1fff提取PID,
判断是否为有效数据包起始(is_start = packet[1] & 0x40),

检查连续性计数器(CRC)确保数据完整性
检查错误标志

适配域处理
根据afc = (packet[3] >> 4) & 3的值跳过适配字段(adaptation field),
仅处理有效负载数据。当afc == 3时需跳过适配域长度p[0] + 1字节812。

PID路由机制
通过ts->pids[pid]查找对应的过滤器(MpegTSFilter * tss),
根据过滤器类型(MPEGTS_PES或MPEGTS_SECTION)调用相应的处理回调函数.
例如
PSI/SI表数据会调用 write_section_data(ts,tss,p,p_end_p,1); //1代表is_start
由tss->section_cb 去回调pat_cb, pmt_cb, sdt_cb, scte_data_cb. 依据section_cb 指针的值
PES流会触发tss->u.pes_filter.pes_cb,其指针是mpegts_push_data

各回调函数就不详细解释了.
简单介绍一下组包过程. pes 保留了状态,
switch (pes->state)
{
case MPEGTS_HEADER:
case MPEGTS_PESHEADER:
case MPEGTS_PESHEADER_FILL:
case MPEGTS_PAYLOAD:
case MPEGTS_SKIP:
}
根据不同的状态对小包进行处理,最后合成一个合格的pkt,
然后通过ts->stop_parse标志控制退出循环.
不仅pes_cb 可以组包, 发现scte_data_cb 也能组包. pat_cb,pmt_cb,sdt_cb是不会组包的,
它们会影响ts状态, 例如会添加过滤器等

http://www.dtcms.com/a/278748.html

相关文章:

  • 每天10个单词 20250714 day4
  • CompletableFuture 源码解析
  • vLLM与SGLang在自然语言处理领域的技术架构与性能对比研究
  • Linux中的系统日志(Rsyslog)
  • 【机器人编程基础】python文件的打开和关闭
  • 【Python3教程】Python3高级篇之MySQL - mysql-connector 驱动介绍及示例
  • [论文阅读] 人工智能 + 软件工程 | 用大语言模型+排名机制,让代码评论自动更新更靠谱
  • Mybatis(黑马)
  • H.264编解码(NAL)
  • 本地小市值miniqmt开发成功
  • 【无标题】Go迭代器完全指南:从基础到实战
  • 行为模式-观察者模式
  • grpo nl2sql qwen3 模型强化学习训练有效果的成立条件有哪些
  • java+vue+SpringBoo智慧草莓基地管理系统(程序+数据库+报告+部署教程+答辩指导)
  • 岳飞:精忠报国的千古英雄
  • 【基础架构】——架构设计流程第三步(评估和选择备选方案)
  • 什么是实时数仓?实时数仓又有哪些应用场景?
  • Kubernetes 高级调度01
  • 【Linux】基本指令详解(一) 树状文件结构、家目录、绝对/相对路径、linux文件类型
  • 【Linux】Jenkins Lts 配置构建 Maven 项目
  • 制作一款打飞机游戏80:道具碰撞
  • FastAPI-P1:Pydantic模型与参数额外信息
  • ThreadLocal结构
  • 02 51单片机之LED闪烁
  • 用TensorFlow进行逻辑回归(三)
  • 计算机网络通信的相关知识总结
  • Faiss库
  • 玩转Docker | 使用Docker部署TeamMapper思维导图应用程序
  • JavaScript 性能优化实战:深入性能瓶颈,精炼优化技巧与最佳实践
  • 深入理解MyBatis延迟加载:原理、配置与实战优化