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协议实现,传输内容包括两部 ...
随机推荐
- HDU 1270 小希的数表 (暴力枚举+数学)
题意:... 析:我们可以知道,a1+a2=b1,那么我们可以枚举a1,那么a2就有了,并且a1+a3=b2,所以a3就有了,我们再从把里面的剩下的数两两相加,并从b数组中去掉, 那么剩下的最小的就是 ...
- 所读STL文章摘要集结
在网上看了一些STL相关文章,这里将它们的摘要进行集结,方便以后查找. 1.黄常标,林俊义,江开勇.快速成形中STL文件拓扑信息的快速建立.2004 摘要:在分析现有建立拓扑信息方法的基础上,提出基于 ...
- OC静态代码检查实战
此文已由作者杨晓授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 在Mac OS系统上,采用Xcodebuild Analyze命令和OClint工具,对iOS项目进行静态代码 ...
- python list生成表达式
列表生成式即List Comprehensions,是Python内置的非常简单却强大的可以用来创建list的生成式.运用列表生成式,可以写出非常简洁的代码. >>> list(ra ...
- vbox虚拟机配置Redhat6.4本地yum源
作为一个新手,配置这个yum源配了4天,遇到了各种问题,也按照网络上面一些方法在163上面下载CentOS6的yum源来替换Redhat本地的yum源,但是配置过程中,出现很多错误,发现直接在本地配置 ...
- java webRoot 路径问题
项目部署后的目录结构 src 生成到 WEB-INF\classes文件下; WebRoot 为项目的根目录,应用中“/action”就相当于是系统目录中的”WebRoot/action" ...
- linux虚拟机时间不准的问题
如果时区不准, 使用tzselect命令(timezone选择),选择北京时间.然后把输出的命令写入/etc/profile.d/time.sh里. 然后用crontab写定时任务,每天执行一次. 3 ...
- IE css hack整理
CSS hack由于不同的浏览器,比如Internet Explorer 6,Internet Explorer 7,Mozillafirefox等,对CSS的解析认识不一样,因此会导致生成的页面效果 ...
- 洛谷1736(二维dp+预处理)
洛谷1387的进阶版,但很像. 1387要求是“全为1的正方形”,取dp[i][j] = min(dp[i-1][j-1], min(dp[i-1][j], dp[i][j-1]))吧?这个有“只有对 ...
- AtCoder Grand Contest 012 A
A - AtCoder Group Contest Time limit : 2sec / Memory limit : 256MB Score : 300 points Problem Statem ...