TS流解析 ffmpeg
ffmpeg关于mpegts码流解析部分:
1、 首先来看main函数
通过av_register_all()来注册所有的编解码器、解复用器(这里只用到mpegts_demuxer)、注册所使用的协议(这里用到文件打开的协议file_protocol,类似的还有http_protocal,pipe_protocol,rtp_protocol,tcp_protocol,udp_protocol).
代码如下:
Void av_register_all()
{
Avcodec_register_all();// 注册所有的编解码器
REGISTER_MUXDEMUX(MPEGTS,mpegts);//注册的实质是把所有的解复用器也好还是复//用器也好都加入到一个链表里面
REGISTER_PROTOCOL(FILE,file);//协议的注册也是如此,都是加入到一个链表里面
}
2、 调用av_open_input_file(&ic,filename,iformat,0,ap);
a) 只是传参一个filename,其他的内容会根据不同的数据内容自动填充
b) 通过url_fopen(&pb,filename,URL_RDONLY)打开文件,在url_fopen中调用了url_open()来判断打开的流是文件流还是网络流,会根据不同的内容自动匹配协议xxx_protocol,然后会根据不同的协议会调用相应的url_open打开流。
这里用到URLProtocol file_protocol = {
"file",
file_open,
file_read,
file_write,
file_seek,
file_close,
};
c) 这里用到一个重要的结构体ByteIOContext封装了媒体流的细节,用它来承载媒体流信息。
d) 接着来探测文件格式。首先通过get_buffer()为pb->buf得到数据,然后通过av_probe_input_format2(pb,1,&score)来探测输入流格式,并返回得到的格式fmt。
这里得到的文件格式为AVInputFormat mpegts_demuxer = {
"mpegts",
NULL_IF_CONFIG_SMALL("MPEG-2 transport stream format"),
sizeof(MpegTSContext),
mpegts_probe,
mpegts_read_header,
mpegts_read_packet,
mpegts_read_close,
read_seek,
mpegts_get_pcr,
AVFMT_SHOW_IDS|AVFMT_TS_DISCONT,
};
e) 调用av_open_input_stream(ic_ptr,pb,filename,fmt,ap)来解析包头信息。
在其中调用ic->iformat->read_header(ic, ap)实质上是调用mpegts_read_header(ic,ap);
现在程序进入到核心的部分mpegts.c中,下面来依次分析mpegts.c中的各个函数。
1.在mpegts_read_header中,先读取1024字节来得到包大小
pos = url_ftell(pb);
len = get_buffer(pb, buf, sizeof(buf));
if (len != sizeof(buf))
goto fail;
ts->raw_packet_size = get_packet_size(buf, sizeof(buf));
2.然后通过if(s->iformat==&mpegts_demuxer)来判断是解复用还是复用。先看解复用的情况。程序先挂载sdt表和pat表。
Mpegts_scan_sdt(ts);//挂在sdt表到ts->pids[pid]
Mpegts_set_service(ts);//挂在pat表到ts->pids[pid]
Handle_packets(ts,s->probesize);//真正处理包信息的地方在这里
3.进入到handle_packets()中来看。
For(;;)
{
Read_packet(pb,packet,ts->raw_packet_size);//得到一个包到packet
Handle_packet(ts,packet);//对包进行解析
}
4.下面分析handle_packets()
static void handle_packet(MpegTSContext *ts, const uint8_t *packet)
{
pid = AV_RB16(packet + 1) & 0x1fff;//得到pid,pid=0代表是pat表
if(pid && discard_pid(ts, pid))
return;
is_start = packet[1] & 0x40;
tss = ts->pids[pid];
if (ts->auto_guess && tss == NULL && is_start) {
add_pes_stream(ts, pid, -1, 0);
tss = ts->pids[pid];
}
if (!tss)
return;
cc = (packet[3] & 0xf);
cc_ok = (tss->last_cc < 0) || ((((tss->last_cc + 1) & 0x0f) == cc));
tss->last_cc = cc;
afc = (packet[3] >> 4) & 3;
p = packet + 4;
if (afc == 0)
return;
if (afc == 2)
return;
if (afc == 3) {
p += p[0] + 1;
}
p_end = packet + TS_PACKET_SIZE;
if (p >= p_end)//指针到到负载部分
return;
ts->pos47= url_ftell(ts->stream->pb) % ts->raw_packet_size;
if (tss->type == MPEGTS_SECTION) {//如果包类型是section
if (is_start) {
len = *p++;
if (p + len > p_end)
return;
if (len && cc_ok) {
write_section_data(s, tss,
p, len, 0);
if (!ts->pids[pid])
return;
}
p += len;
if (p < p_end) {
write_section_data(s, tss,//对section段进行解析
p, p_end - p, 1);
}
} else {
if (cc_ok) {
write_section_data(s, tss,
p, p_end - p, 0);
}
}
} else {
tss->u.pes_filter.pes_cb(tss,//这里先对section进行解析完之后才能进到这里对pes进行解析
p, p_end - p, is_start);
}
}
3.进入到write_section_data()
static void write_section_data(AVFormatContext *s, MpegTSFilter *tss1,
const uint8_t *buf, int buf_size, int is_start)
{
if (tss->section_h_size == -1 && tss->section_index >= 3) {
len = (AV_RB16(tss->section_buf + 1) & 0xfff) + 3;//得到段长度
}
if (tss->section_h_size != -1 && tss->section_index >= tss->section_h_size) {
tss->end_of_section_reached = 1;
if (!tss->check_crc ||
av_crc(av_crc_get_table(AV_CRC_32_IEEE), -1,
tss->section_buf, tss->section_h_size) == 0)
{
tss->section_cb(tss1, tss->section_buf, tss->section_h_size);//这是个重要的函数,是对一个包中的负载进行解析,section_cb会根据包类型的不同来调用不同的函数
}
}
}
Section_cb是一个回调函数,调用的函数有pat_cb,sdt_cb,pmt_cb,
Table_id 00代表pat表,02代表pmt表
关于ffmpeg程序的结构层次关系:
URLProtocol、URLContext和ByteIOContext是ffmpeg文件操作的结构,
AVFormatContext是相当于容器之类的东西,会把解析到的信息都记录在这里
AVFormatContext{
AVInputFormat
ByteIOContext{
URLContext{
URLProtocol;
}
}
Void *priv_data//指向MpegtsContext结构体
}
对TS码流分析:
第一个包 负载为pat表
00000000h: 04 CA 63 A0 包头:47 4pid0 00 afc10 00 00 B0 section_length11 00 01 C1 00 ; .蔯燝@....?..?
00000010h: 00 sid00 00 network_pidE0 1F sid00 01 Epmt_pid1 00 24 AC 48 84 FF FF FF ; ...?..?$琀?
00000020h: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ; 后面的省略
分析:pid=0,表明后面跟的负载为pat表
Afc=01,表明没有适应段
Section_length=17,表明此段后有17个字节,包括crc
Sid为节目
第二个包 负载为pmt表
000000c0h: 04 CA 63 A0 包头47 4pid1 00 10 00 段开始:table_id:02 B0 section_length:46program_number00 01 C1 section_number00 ; .蔯燝A....癋..?
000000d0h: last_sec_number00 F PCR_PID0 01 F0 program_info_length0C tag05 len04 bytes48 44 4D 56tag88 len04 0F FF FC ; .??..HDMV?.?
000000e0h: FC stream_type1B es_pidF0 11 Fes_info_len0 06 desc_tag28 desc_len04 64 00 29 BFstream_type81 es_pidF1 00 Fes_info_len0 ; ???(.d.)縼??
000000f0h: 12 desc_tag05 desc_len04 41 43 2D 33 desc_tag81 desc_len04 08 48 0E 00 desc_tag0Adesc_len04 6A ; ...AC-3?.H....j
00000100h: 70 6E 00 stream_type90 Fes_pid2 00 Fes_info_len0 06 desc_tag0A desc_len04 7A 68 6F 004C 3A ; pn.愹.?..zho.L:
00000110h: EA 06 FF FF FF FF FF FF FF FF FF FF FF FF FF FF ; ?未完待续。。。。
TS流解析 ffmpeg相关推荐
- 数字电视之TS流解析
做了这么久的TV方案,对数字电视也很了解,今天来总结一下,MPEG-2 TS流解析的细节: TS流中有两种标识符,一种是包标识符,一种是表标识符.具有相同PID的不用信息表由表标识符table Id来 ...
- ffmpeg——TS流解析
RTSP(Real Time Streaming Protocol),实时流传输协议,是TCP/IP协议体系中的一个应用层协议,该协议定义了一对多应用程序如何有效地通过IP网络传送多媒体数据.RTSP ...
- TS流解析之PMT表格解析
from:http://blog.csdn.net/xioahw/article/details/4093491 PMT结构定义: typedef struct TS_PMT_Stream { un ...
- TS流解析之PAT表格解析
from: http://blog.csdn.net/xioahw/article/details/4093488 PAT表格定义如下: typedef struct TS_PAT_Program { ...
- TS流解析 二 *****
1.TS格式介绍 TS:全称为MPEG2-TS.TS即"Transport Stream"的缩写.它是分包发送的,每一个包长为188字节(还有192和204个字节的包).包的结构为 ...
- TS流解析【PCR】自己的总结
http://www.cnblogs.com/ztteng/articles/3166025.html http://blog.csdn.net/liuhongxiangm/article/detai ...
- c语言解析ts流文件,TS流解析
1. 介绍:TS即是"Transport Stream"的缩写.他是分包发送的,每一个包长为188字节或者是204的字节(204字节的就是在后面添加了16字节主要用于高清解码), ...
- python处理ts_[python]TS流解析
据说TS包长度是188个字节,真的是这样?实验一下(原理:0x47是TS包头的第一个字节,作为同步字段): file = open('test.ts', 'rb') offset = 0 start ...
- DVB中TS流数据解析
引 言 数字生活方式是现代文明的一个重要标志.在与人们工作生活密切相关的电脑.手机和电视三大信息平台中,电脑和手机已实现了数字化和网络化,为人们带来了多姿多彩的资讯和娱乐服务,也为相关企业带来了巨额 ...
最新文章
- 关于java线程同步的笔记_线程同步(JAVA笔记-线程基础篇)
- stringBuffer、StringBuilder、排序、Arrays、Jdk1.5新特性(java基础知识十三)
- 计算机专业 毕业论文 百度云,计算机专业毕业论文.pdf
- 安全性配置-定义任务流节点
- php分页类示例下载,PHP 通用分页类的简单示例
- ROS学习笔记1(配置ROS环境和创建工作空间)
- IM系统中聊天记录模块的设计与实现
- 实验室双显示屏安装使用记录
- hane nfs win 配置_win7下搭建nfs-server的方法
- mac vs 返回上一步_mac 后退一步 快捷键
- xutils中dbutils的使用
- Using ‘UTF-8‘ encoding to copy filtered resources. skip non existing resourceDirectory
- 华为云sql工程师评测答题[青铜+白银]
- 最小生成树——克鲁斯卡尔(Kruskal)算法
- command not found: conda
- 【java】java中输出字符串中的单个字符及获得其长度
- Android 9 (P)版本解决VNDK library: XXX‘s ABI has EXTENDING CHANGES
- 同轴连接器有哪些种类?
- html网页中在一个表格中去除部分表格线
- 【机器人学习】三自由度康复机器人运动学分析()