flash网站素材下载,怀化找什么人做网站,搜索引擎调词平台价格,嘉兴网站推广介绍: MPEG的系统层编码为不同的应用场景设计了两种格式: TS(Transport Stream) 和PS(Program Stream),它们两者之间不具有层级关系#xff0c;在逻辑上#xff0c;它们两者都是由PES(Packetized Elementary Stream)包组成的#xff0c;所以可以很方便地实现相互转换.TS(Tra…介绍: MPEG的系统层编码为不同的应用场景设计了两种格式: TS(Transport Stream) 和PS(Program Stream), 它们两者之间不具有层级关系 在逻辑上它们两者都是由PES(Packetized Elementary Stream)包组成的 所以可以很方便地实现相互转换. TS(Transport Stream): 是将具有一个或多个独立时间基的一个或多个节目(包括音频和视频)组成一个流, 组成同一个节目的基本流(如一个视频流多个音频流)的PES包有一个共用的时间基。 TS的包长标准为188bytes. 从上面的定义可以分成三层来看TS/PS。 ES层 : 由单独的音频(如mp3)视频流(如h.264)组成基本的ES(Elementary Stream)。 PES层 : 将基本的ES按一定的规则(如H.264以AU)进行封装并打上时间戳组成PES。 TS/PS层: 将PES包进行切分后再封装成188bytes大小的TS包 同时还将一些节目信息也封装成TS包(称为section), 两者共同组成TS层。 从上面的总结TS/PS总体上来说是一种封装格式用来承载数据。 所以FFmpeg 将TS/PS的解析文件定义在libavformat/mpegts.c文件中 将音频视频的解码定义在libavcodec/mpeg12.c文件中 下面来看FFmpeg是如何进行TS的demuxer的。 1. MPEG2-TS的demuxer函数 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 }; 2. 解析流中的TS格式 /* * 出现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 x0; int best_score0; memset(stat, 0, packet_size*sizeof(int)); for (xi0; i size-3; i) { if ((buf[i] 0x47) !(buf[i1] 0x80) (buf[i3] 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;} buf[i] 0x47 其中的sync_byte固定为0x47,即上面的. !(buf[i1] 0x80) 由于transport_error_indicator为1的TS Packet实际有错误, 表示携带的数据无意义, 这样的Packet显然没什么意义. buf[i3] 0x30 对于adaptation_field_control, 如果取值为0x00,则表示为未来保留现在不用. 这就是MPEG TS的侦测过程. 3. MPEG2-TS头解析 #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: pid0x%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;} 对于这部分代码需要分析数据结构的定义 依次为 struct MpegTSContext; | V struct MpegTSFilter; | V ----------------------------- | | V V MpegTSPESFilter MpegTSSectionFilter 就是struct MpegTSContext中有NB_PID_MAX(8192)个TS的Filter 而每个struct MpegTSFilter 可能是 PES 的Filter 或者是 Section的Filter。 为什么NB_PID_MAX 是 8192, 需要看TS的语法结构(ISO/IEC 138138-1 page 19): Syntax No. of bits Mnemonictransport_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_control10 || adaptation_field_control11 ) { adaptation_field() } if (adaptation_field_control01 || adaptation_field_control11 ) { for (i0;iN;i) { data_byte 8 bslbf } } } 而8192,是2^138192(PID)的最大数目 为什么会有PES和Section的区分更详细的可以参考ISO/IEC-13818-1. 挂载上了两种section过滤器如下 PID |Section Name |Callback SDT_PID(0x0011) |ServiceDescriptionTable|sdt_cb | | PAT_PID(0x0000) |ProgramAssociationTable|pat_cb 设计成回调函数是为了在后面使用。 4. MPEG2-TS的包处理 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_packets() | -read_packet() | -handle_packet() | -write_section_data() read_packet(), 很简单, 就是去找sync_byte(0x47), handle_packet(),是真正处理数据的地方.它的代码如下: /* * 功能: 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;} write_section_data()函数: 反复收集buffer中的数据指导完成相关Section的重组过程, 然后调用之前注册的两个section_cb. 5. 节目指定信息的解析 /* * 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) 6. 解析PES包 /* * 见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); 至此整个TS层的解析基本完成。转载于:https://www.cnblogs.com/yulang314/p/3737854.html