ffmpeg解析TS流
介绍:
- AVInputFormat ff_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,
- .flags = AVFMT_SHOW_IDS|AVFMT_TS_DISCONT,
- #ifdef USE_SYNCPOINT_SEARCH
- .read_seek2 = read_seek2,
- #endif
- };
- /*
- * 出现3种格式,主要原因是:
- * TS标准是 188Bytes;
- * 日本标准是192Bytes的DVH-S格式;
- * 第三种的 204Bytes则是在188Bytes的基础上,加上16Bytes的FEC(前向纠错).
- */
- #define TS_PACKET_SIZE 188
- #define TS_DVHS_PACKET_SIZE 192
- #define TS_FEC_PACKET_SIZE 204
- #define TS_MAX_PACKET_SIZE 204
- //< maximum score, half of that is used for file-extension-based detection
- #define AVPROBE_SCORE_MAX 100
- /*
- * 函数功能:
- * 分析流中是三种TS格式的哪一种
- */
- static int mpegts_probe(AVProbeData *p)
- {
- #define CHECK_COUNT 10
- const int size= p->buf_size;
- int score, fec_score, dvhs_score;
- int check_count= size / TS_FEC_PACKET_SIZE;
- if (check_count < CHECK_COUNT)
- return -1;
- score = analyze(p->buf, TS_PACKET_SIZE *check_count, TS_PACKET_SIZE , NULL)
- * CHECK_COUNT / check_count;
- dvhs_score= analyze(p->buf, TS_DVHS_PACKET_SIZE*check_count, TS_DVHS_PACKET_SIZE, NULL)
- * CHECK_COUNT / check_count;
- fec_score = analyze(p->buf, TS_FEC_PACKET_SIZE *check_count, TS_FEC_PACKET_SIZE , NULL)
- * CHECK_COUNT / check_count;
- /*
- * we need a clear definition for the returned score ,
- * otherwise things will become messy sooner or later
- */
- if (score > fec_score && score > dvhs_score && score > 6)
- return AVPROBE_SCORE_MAX + score - CHECK_COUNT;
- else if(dvhs_score > score && dvhs_score > fec_score && dvhs_score > 6)
- return AVPROBE_SCORE_MAX + dvhs_score - CHECK_COUNT;
- else if(fec_score > 6)
- return AVPROBE_SCORE_MAX + fec_score - CHECK_COUNT;
- else
- return -1;
- }
- /*
- * 函数功能:
- * 在size大小的buf中,寻找满足特定格式,长度为packet_size的
- * packet的个数;
- * 显然,返回的值越大越可能是相应的格式(188/192/204)
- */
- static int analyze(const uint8_t *buf, int size, int packet_size, int *index){
- int stat[TS_MAX_PACKET_SIZE];
- int i;
- int x=0;
- int best_score=0;
- memset(stat, 0, packet_size*sizeof(int));
- for (x=i=0; i < size-3; i++)
- {
- if ((buf[i] == 0x47) && !(buf[i+1] & 0x80) && (buf[i+3] & 0x30))
- {
- stat[x]++;
- if (stat[x] > best_score)
- {
- best_score= stat[x];
- if (index)
- *index= x;
- }
- }
- x++;
- if (x == packet_size)
- x= 0;
- }
- return best_score;
- }
- #define NB_PID_MAX 8192
- #define MAX_SECTION_SIZE 4096
- /* pids */
- #define PAT_PID 0x0000
- #define SDT_PID 0x0011
- /* table ids */
- #define PAT_TID 0x00
- #define PMT_TID 0x02
- #define SDT_TID 0x42
- /*
- * 函数功能:
- *
- */
- int mpegts_read_header(AVFormatContext *s, AVFormatParameters *ap)
- {
- /*
- * MpegTSContext , 是为了解码不同容器格式所使用的私有数据,
- * 只有在相应的诸如mpegts.c文件才可以使用的.
- * 这样,增加了这个库的模块化.
- */
- MpegTSContext *ts = s->priv_data;
- AVIOContext *pb = s->pb;
- uint8_t buf[8*1024];
- int len;
- int64_t pos;
- /* read the first 8*1024 bytes to get packet size */
- pos = avio_tell(pb); // 获取buf的当前位置
- len = avio_read(pb, buf, sizeof(buf)); // 从pb->opaque中读取sizeof(buf)个字节到buf
- if (len != sizeof(buf))
- goto fail;
- /*
- * 获得TS包的实际长度
- */
- ts->raw_packet_size = get_packet_size(buf, sizeof(buf));
- if (ts->raw_packet_size <= 0)
- {
- av_log(s, AV_LOG_WARNING, "Could not detect TS packet size, defaulting to non-FEC/DVHS\n");
- ts->raw_packet_size = TS_PACKET_SIZE;
- }
- ts->stream = s;
- ts->auto_guess = 0;
- if (s->iformat == &ff_mpegts_demuxer)
- {
- /* normal demux */
- /* first do a scaning to get all the services */
- if (avio_seek(pb, pos, SEEK_SET) < 0)
- {
- av_log(s, AV_LOG_ERROR, "Unable to seek back to the start\n");
- }
- /*
- * 挂载了两个Section类型的过滤器,
- * 其实在TS的两种负载中,section是PES的元数据,
- * 只有先解析了section,才能进一步解析PES数据,因此先挂上section的过滤器。
- */
- mpegts_open_section_filter(ts, SDT_PID, sdt_cb, ts, 1);
- mpegts_open_section_filter(ts, PAT_PID, pat_cb, ts, 1);
- /*
- */
- handle_packets(ts, s->probesize / ts->raw_packet_size);
- /* if could not find service, enable auto_guess */
- ts->auto_guess = 1;
- av_dlog(ts->stream, "tuning done\n");
- s->ctx_flags |= AVFMTCTX_NOHEADER;
- }
- else
- {
- ...
- }
- avio_seek(pb, pos, SEEK_SET);
- return 0;
- fail:
- return -1;
- }
- MpegTSFilter *mpegts_open_section_filter(MpegTSContext* ts,
- unsigned int pid,
- SectionCallback* section_cb,
- void* opaque,
- int check_crc)
- {
- MpegTSFilter *filter;
- MpegTSSectionFilter *sec;
- av_dlog(ts->stream, "Filter: pid=0x%x\n", pid);
- if (pid >= NB_PID_MAX || ts->pids[pid])
- return NULL;
- filter = av_mallocz(sizeof(MpegTSFilter));
- if (!filter)
- return NULL;
- ts->pids[pid] = filter;
- filter->type = MPEGTS_SECTION;
- filter->pid = pid;
- filter->last_cc = -1;
- sec = &filter->u.section_filter;
- sec->section_cb = section_cb;
- sec->opaque = opaque;
- sec->section_buf= av_malloc(MAX_SECTION_SIZE);
- sec->check_crc = check_crc;
- if (!sec->section_buf)
- {
- av_free(filter);
- return NULL;
- }
- return filter;
- }
- Syntax No. of bits Mnemonic
- transport_packet(){
- sync_byte 8 bslbf
- transport_error_indicator 1 bslbf
- payload_unit_start_indicator 1 bslbf
- transport_priority 1 bslbf
- PID 13 uimsbf
- transport_scrambling_control 2 bslbf
- adaptation_field_control 2 bslbf
- continuity_counter 4 uimsbf
- if (adaptation_field_control=='10' ||
- adaptation_field_control=='11' )
- {
- adaptation_field()
- }
- if (adaptation_field_control=='01' ||
- adaptation_field_control=='11' )
- {
- for (i=0;i<N;i++)
- {
- data_byte 8 bslbf
- }
- }
- }
- int handle_packets(MpegTSContext *ts, int nb_packets)
- {
- AVFormatContext *s = ts->stream;
- uint8_t packet[TS_PACKET_SIZE];
- int packet_num, ret;
- ts->stop_parse = 0;
- packet_num = 0;
- for ( ; ; )
- {
- packet_num++;
- if (nb_packets != 0 && packet_num >= nb_packets ||
- ts->stop_parse > 1)
- {
- ret = AVERROR(EAGAIN);
- break;
- }
- if (ts->stop_parse > 0)
- break;
- ret = read_packet(s, packet, ts->raw_packet_size);
- if (ret != 0)
- return ret;
- ret = handle_packet(ts, packet);
- if (ret != 0)
- return ret;
- }
- return 0;
- }
- /*
- * 功能: handle one TS packet
- */
- int handle_packet(MpegTSContext *ts, const uint8_t *packet)
- {
- AVFormatContext *s = ts->stream;
- MpegTSFilter *tss;
- int len, pid, cc, expected_cc, cc_ok, afc, is_start;
- const uint8_t *p, *p_end;
- int64_t pos;
- /* 获取该包的PID */
- pid = AV_RB16(packet + 1) & 0x1fff;
- if (pid && discard_pid(ts, pid))
- return 0;
- /*
- * 是否是PES或者Section的开头
- * 即syntax element: payload_unit_start_indicator
- */
- is_start = packet[1] & 0x40;
- tss = ts->pids[pid];
- /*
- * ts->auto_guess此时为0,因此不考虑下面的代码
- */
- if (ts->auto_guess && tss == NULL && is_start)
- {
- add_pes_stream(ts, pid, -1);
- tss = ts->pids[pid];
- }
- if (!tss)
- return 0;
- /*
- * continuity check (currently not used)
- * 虽然检查,但不利用检查的结果
- */
- cc = (packet[3] & 0xf);
- expected_cc = (packet[3] & 0x10) ? (tss->last_cc + 1) & 0x0f : tss->last_cc;
- cc_ok = (tss->last_cc < 0) || (expected_cc == cc);
- tss->last_cc = cc;
- /*
- * 解析 adaptation_field_control 语法元素
- * =======================================================
- * 00 | Reserved for future use by ISO/IEC
- * 01 | No adaptation_field, payload only
- * 10 | Adaptation_field only, no payload
- * 11 | Adaptation_field follwed by payload
- * =======================================================
- */
- afc = (packet[3] >> 4) & 3;
- p = packet + 4;
- if (afc == 0) /* reserved value */
- return 0;
- if (afc == 2) /* adaptation field only */
- return 0;
- if (afc == 3)
- {
- /*
- * 跳过 adapation field
- * p[0]对应的语法元素为: adaptation_field_length
- */
- p += p[0] + 1;
- }
- /*
- * if past the end of packet, ignore
- * p已近到达TS包中的有效负载的地方
- */
- p_end = packet + TS_PACKET_SIZE;
- if (p >= p_end)
- return 0;
- pos = avio_tell(ts->stream->pb);
- ts->pos47= pos % ts->raw_packet_size;
- if (tss->type == MPEGTS_SECTION)
- {
- /*
- * 针对Section, 第一个字节对应的语法元素为:pointer_field(见2.4.4.1),
- * 它表示在当前TS包中,从pointer_field开始到第一个section的第一个字节间的字节数。
- * 当TS包中有至少一个section的起始时,
- * payload_unit_start_indicator = 1 且 TS负载的第一个字节为pointer_field;
- * pointer_field = 0x00时,表示section的起始就在这个字节之后;
- * 当TS包中没有section的起始时,
- * payload_unit_start_indicator = 0 且 TS负载中没有pointer_field;
- */
- if (is_start)
- {
- /* pointer field present */
- len = *p++;
- if (p + len > p_end)
- return 0;
- if (len && cc_ok)
- {
- /*
- * write remaining section bytes
- * TS包的负载部分由Section A的End部分和Section B的Start组成,
- * 先把Section A的End部分写入
- */
- write_section_data(s, tss, p, len, 0);
- /* check whether filter has been closed */
- if (!ts->pids[pid])
- return 0;
- }
- p += len;
- if (p < p_end)
- {
- /*
- * 再将Section B的Start部分写入
- */
- write_section_data(s, tss, p, p_end - p, 1);
- }
- }
- else
- {
- /* TS包负载仅是一个Section的中间部分部分,将其写入*/
- if (cc_ok)
- {
- write_section_data(s, tss, p, p_end - p, 0);
- }
- }
- }
- else
- {
- int ret;
- /*
- * 如果是PES类型,直接调用其Callback,
- * 但显然,只有Section部分解析完成后才可能解析PES
- */
- // Note: The position here points actually behind the current packet.
- 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;
- }
- /*
- * PAT(Program Association Table) 节目相关表
- * 提供了节目号与PID值的对应关系
- * 见ISO/IEC 13818-1 2.4.4.3 Table 2-30
- */
- void pat_cb(MpegTSFilter *filter, const uint8_t *section, int section_len);
- /*
- * PMT(Program Map Table) 节目映射表
- * 提供了节目号与组成节目的元素之间的映射关系--或者称为"节目定义"
- * 见ISO/IEC 13818-1 2.4.4.8 Table 2-33
- */
- void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len);
- /*
- * SDT(Transport Stream Description Table) TS描述表
- * 用于定义TS描述子的表
- * 见ISO/IEC 13818-1 2.4.4.12 Table 2-36
- */
- void sdt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len)
- /*
- * 见ISO/IEC 13818-1 2.4.3.6 Table 2-21
- */
- int mpegts_push_data(MpegTSFilter* filter,
- const uint8_t* buf,
- int buf_size,
- int is_start,
- int64_t pos);
ffmpeg解析TS流的更多相关文章
- 分析ffmpeg解析ts流信息的源码
花费一些时间,然后全部扔了.为了不忘记和抛砖引玉,特发此贴. ffmpeg解析ts流 1.目的 打算软件方式解析出pat,pmt等码流信息 2.源代码所在位置 下载ffmpeg ...
- (原)关于获取ffmpeg解析rtsp流sdp中带有sps,pps的情况
转载请注明出处:http://www.cnblogs.com/lihaiping/p/6612511.html 今天同事准备在android下使用ffmpeg来获取rtsp流,问我如何获取获取sps ...
- TS流解析 二 *****
1.TS格式介绍 TS:全称为MPEG2-TS.TS即"Transport Stream"的缩写.它是分包发送的,每一个包长为188字节(还有192和204个字节的包).包的结构为 ...
- TS流解析 一
一 从TS流开始 数字电视机顶盒接收到的是一段段的码流,我们称之为TS(Transport Stream,传输流),每个TS流都携带一些信息,如Video.Audio以及我们需要学习的PAT.PMT等 ...
- TS流解析 四
一 从TS流开始 数字电视机顶盒接收到的是一段段的码流,我们称之为TS(Transport Stream,传输流),每个TS流都携带一些信息,如Video.Audio以及我们需要学习的PAT.PMT等 ...
- (原)关于MEPG-2中的TS流数据格式学习
关于MEPG-2中的TS流数据格式学习 Author:lihaiping1603 原创:http://www.cnblogs.com/lihaiping/p/8572997.html 本文主要记录了, ...
- TS流格式(转)
一 从TS流开始 数字电视机顶盒接收到的是一段段的码流,我们称之为TS(Transport Stream,传输流),每个TS流都携带一些信息,如Video.Audio以及我们需要学习的PAT.PMT等 ...
- TS流PAT/PMT详解
一 从TS流开始 从MPEG-2到DVB,看着看着突然就出现了一大堆表格,什么PAT.PMT.CAT……如此多的表该怎样深入了解呢? 我们知道,数字电视机顶盒接收到的是一段段的码流,我们称之为TS(T ...
- [视频播放] HLS协议之M3U8、TS流详解
本文转载自:<hls之m3u8.ts流格式详解> HLS,Http Live Streaming 是由Apple公司定义的用于实时流传输的协议,HLS基于HTTP协议实现,传输内容包括两部 ...
随机推荐
- 如何优雅地停止Java进程
目录 理解停止Java进程的本质 应该如何正确地停止Java进程 如何注册关闭钩子 使用关闭钩子的注意事项 信号量机制 总结 理解停止Java进程的本质 我们知道,Java程序的运行需要一个运行时环境 ...
- Django学习:ORM
Object Relational Mapping(ORM) ORM介绍 ORM概念 对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据 ...
- 第十八篇 .NET高级技术之Linq与EF Code-First Fluent API基础讲解
1.FluentApi简介 在这里提供了一个fluentapi基础的DEMO然后咱们在进一步的学习,直接上干货. 第一步在数据库创建一个表:person 第二步:新建控制台程序FluentAPI 第三 ...
- ES6中的Rest参数和默认参数
ES6中的Rest参数和默认参数 Rest参数 一个例子 编写一个函数, 用来判断, 某个字符串中, 是否其他的字符串, 如果第一参数以后的字符串, 都包含在第一参数中, 都包含在, 就返回true ...
- 解决Android 打包为apk文件时已设置签名,在OPPO手机上安装时却出现“未设置签名”的错误
解决办法:
- ios app跳转拨打电话界面,调用拨打电话功能
DNLogFUNC //两种方法都可以用 //这种据说是可以上appstore NSURL *phoneURL = [NSURL URLWithString:[NSString stringWithF ...
- 谈谈对Android中的消息机制的理解
Android中的消息机制主要由Handler.MessageQueue.Looper三个类组成,他们的主要作用是 Handler负责发送.处理Message MessageQueue负责维护Mess ...
- EditText输入手机号自动带空格
xml: <EditText android:id="@+id/edit_main" android:layout_width="match_parent" ...
- loadrunner:文本检查点web_reg_find和web_find两个函数的区别
web_reg_find是先注册(register)后查找的:使用时将它放在请求语句的前面. 而web_find是查找前面的请求结果:使用时将它放在请求语句的后面. 另二者的参数也完成不一样的,web ...
- LR 两种录制:html与url
一直在使用LR,对于Html_based script和Url-based script 两种录制方式之间,要如何选择,仍是一知半解.最近测试时遇到同样的业务功能,两种录制方式的脚本,单次执行时间差别 ...