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协议实现,传输内容包括两部 ...
随机推荐
- ASP.NET Core MVC 2.x 全面教程_ASP.NET Core MVC 21. Model 验证 Again
深入的将Model验证 手动添加验证的错误 view里面显示每个属性的验证错误信息 显示整个model级别错误 自定义验证 如果业务逻辑需要比较复杂的验证.而且这个验证逻辑可能到处复用的话就应该考虑使 ...
- [msf]CentOS VPS创建pptpd 并搭建msf
安装pptpd服务 vps下 下载 centos 6 一键安装包 wget --no-check-certificate https://raw.githubusercontent.com/teddy ...
- Objective-C中的字符串格式化输出(转载)
转自:http://www.cnblogs.com/jackbutler/archive/2012/04/05/2432828.html %@ 对象 %d, %i 整数 %u 无符整形 %f 浮点/双 ...
- POJ2488【DFS】
阿西吧,搞清楚谁是行,谁是列啊!!! #include <stdio.h> #include <string.h> #include <math.h> #inclu ...
- P1218 过路费
奋斗了两天,终于写过了这道题...... 这道题不仅要求最短路,还要加上路径上最大的点权: 先用结构体记录点的序号和点的值这是毋庸置疑的:再用另外一个数组来记录当前点权也是可以理解的,毕竟后面要排序: ...
- notepad++插件选项没有plugin manager解决
在 https://github.com/bruderstein/nppPluginManager/releases 下载最新的PluginManager_vXXXX_UNI.zip 解压,将里面的p ...
- OpenCv图像像素操作
1:像素 有两种直接操作像素点的方法: 第一种: 将其转化为numpy.array格式,直接进行操作. 第二种:使用Opencv提供的Get1D,Get2D等函数. 2:获取行和列像素 有一下四个函数 ...
- hdu 2818 Building Block 种类并查集
在进行并的时候不能瞎jb并,比如(x, y)就必须把x并给y ,即fa[x] = y #include <iostream> #include <string> #includ ...
- websocket实现单聊
server# @File: ws from flask import Flask, request, render_template from geventwebsocket.handler imp ...
- 简单几何(求交点) UVA 11178 Morley's Theorem
题目传送门 题意:莫雷定理,求三个点的坐标 分析:训练指南P259,用到了求角度,向量旋转,求射线交点 /*********************************************** ...