日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

ffmpeg解析TS流

發布時間:2025/3/8 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ffmpeg解析TS流 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

介紹:?
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?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;
  • }
  • buf[i] == 0x47 ? 其中的sync_byte固定為0x47,即上面的.? !(buf[i+1] & 0x80) ?? 由于transport_error_indicator為1的TS Packet實際有錯誤, 表示攜帶的數據無意義, 這樣的Packet顯然沒什么意義. buf[i+3] & 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: 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;
  • }
  • 對于這部分代碼,需要分析數據結構的定義: 依次為: 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 ? ? ? ? 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
  • ????}?
  • ??}?
  • }
  • 而8192,是2^13=8192(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

    創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

    總結

    以上是生活随笔為你收集整理的ffmpeg解析TS流的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。