TS流解析 ffmpeg

ffmpeg关于mpegts码流解析部分:

1、  首先来看main函数

通过av_register_all()来注册所有的编解码器、解复用器(这里只用到mpegts_demuxer)、注册所使用的协议(这里用到文件打开的协议file_protocol,类似的还有http_protocal,pipe_protocol,rtp_protocol,tcp_protocol,udp_protocol.

代码如下:

Void av_register_all()

{

Avcodec_register_all();// 注册所有的编解码器

REGISTER_MUXDEMUXMPEGTS,mpegts;//注册的实质是把所有的解复用器也好还是复//用器也好都加入到一个链表里面

REGISTER_PROTOCOL(FILE,file);//协议的注册也是如此,都是加入到一个链表里面

}

2、  调用av_open_input_file(&ic,filename,iformat,0,ap);

a)         只是传参一个filename,其他的内容会根据不同的数据内容自动填充

b)         通过url_fopen&pb,filename,URL_RDONLY)打开文件,在url_fopen中调用了url_open()来判断打开的流是文件流还是网络流,会根据不同的内容自动匹配协议xxx_protocol,然后会根据不同的协议会调用相应的url_open打开流。

这里用到URLProtocol file_protocol = {

    "file",

    file_open,

    file_read,

    file_write,

    file_seek,

    file_close,

};

         c)      这里用到一个重要的结构体ByteIOContext封装了媒体流的细节,用它来承载媒体流信息。

         d)      接着来探测文件格式。首先通过get_buffer()pb->buf得到数据,然后通过av_probe_input_format2(pb,1,&score)来探测输入流格式,并返回得到的格式fmt

         这里得到的文件格式为AVInputFormat 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,

    AVFMT_SHOW_IDS|AVFMT_TS_DISCONT,

};

         e)      调用av_open_input_stream(ic_ptr,pb,filename,fmt,ap)来解析包头信息。

 在其中调用ic->iformat->read_header(ic, ap)实质上是调用mpegts_read_header(ic,ap);

现在程序进入到核心的部分mpegts.c中,下面来依次分析mpegts.c中的各个函数。

1.mpegts_read_header中,先读取1024字节来得到包大小

 

 

    pos = url_ftell(pb);

    len = get_buffer(pb, buf, sizeof(buf));

    if (len != sizeof(buf))

        goto fail;

    ts->raw_packet_size = get_packet_size(buf, sizeof(buf));

 

2.然后通过if(s->iformat==&mpegts_demuxer)来判断是解复用还是复用。先看解复用的情况。程序先挂载sdt表和pat表。

Mpegts_scan_sdt(ts);//挂在sdt表到ts->pids[pid]

Mpegts_set_service(ts);//挂在pat表到ts->pids[pid]

Handle_packets(ts,s->probesize);//真正处理包信息的地方在这里

3.进入到handle_packets()中来看。

For(;;)

{

         Read_packet(pb,packet,ts->raw_packet_size);//得到一个包到packet

         Handle_packet(ts,packet);//对包进行解析

}

         4.下面分析handle_packets()

         static void handle_packet(MpegTSContext *ts, const uint8_t *packet)

{

    pid = AV_RB16(packet + 1) & 0x1fff;//得到pidpid=0代表是pat

    if(pid && discard_pid(ts, pid))

        return;

    is_start = packet[1] & 0x40;

    tss = ts->pids[pid];

    if (ts->auto_guess && tss == NULL && is_start) {

        add_pes_stream(ts, pid, -1, 0);

        tss = ts->pids[pid];

    }

    if (!tss)

        return;

 

   

    cc = (packet[3] & 0xf);

    cc_ok = (tss->last_cc < 0) || ((((tss->last_cc + 1) & 0x0f) == cc));

    tss->last_cc = cc;

 

   

    afc = (packet[3] >> 4) & 3;

    p = packet + 4;

    if (afc == 0)

        return;

    if (afc == 2)

        return;

    if (afc == 3) {

       

        p += p[0] + 1;

    }

   

    p_end = packet + TS_PACKET_SIZE;

    if (p >= p_end)//指针到到负载部分

        return;

 

    ts->pos47= url_ftell(ts->stream->pb) % ts->raw_packet_size;      

 

    if (tss->type == MPEGTS_SECTION) {//如果包类型是section

        if (is_start) {

           

            len = *p++;

            if (p + len > p_end)

                return;

            if (len && cc_ok) {

               

                write_section_data(s, tss,

                                   p, len, 0);

               

                if (!ts->pids[pid])

                    return;

            }

            p += len;

            if (p < p_end) {

                write_section_data(s, tss,//section段进行解析

                                   p, p_end - p, 1);

            }

        } else {

            if (cc_ok) {

                write_section_data(s, tss,

                                   p, p_end - p, 0);

            }

        }

    } else {

        tss->u.pes_filter.pes_cb(tss,//这里先对section进行解析完之后才能进到这里对pes进行解析

                                 p, p_end - p, is_start);

    }

}

         3.进入到write_section_data()

static void write_section_data(AVFormatContext *s, MpegTSFilter *tss1,

                               const uint8_t *buf, int buf_size, int is_start)

{

   

    if (tss->section_h_size == -1 && tss->section_index >= 3) {

        len = (AV_RB16(tss->section_buf + 1) & 0xfff) + 3;//得到段长度

    }

 

    if (tss->section_h_size != -1 && tss->section_index >= tss->section_h_size) {

        tss->end_of_section_reached = 1;

        if (!tss->check_crc ||

            av_crc(av_crc_get_table(AV_CRC_32_IEEE), -1,

                   tss->section_buf, tss->section_h_size) == 0)

                   {

            tss->section_cb(tss1, tss->section_buf, tss->section_h_size);//这是个重要的函数,是对一个包中的负载进行解析,section_cb会根据包类型的不同来调用不同的函数

                   }

    }

}

         Section_cb是一个回调函数,调用的函数有pat_cb,sdt_cb,pmt_cb,

                   Table_id 00代表pat表,02代表pmt

 

 

关于ffmpeg程序的结构层次关系:

URLProtocolURLContextByteIOContextffmpeg文件操作的结构,

AVFormatContext是相当于容器之类的东西,会把解析到的信息都记录在这里

AVFormatContext{

         AVInputFormat

ByteIOContext{

         URLContext{

                   URLProtocol;

}

}

Void *priv_data//指向MpegtsContext结构体

}

 

 

 

TS码流分析:

第一个包  负载为pat

00000000h: 04 CA 63 A0 包头:47 4pid0 00 afc10 00 00 B0 section_length11 00 01 C1 00 ; .蔯燝@....?..?

00000010h: 00 sid00 00 network_pidE0 1F sid00 01 Epmt_pid1 00 24 AC 48 84 FF FF FF ; ...?..?$?

00000020h: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ; 后面的省略

 

分析:pid=0,表明后面跟的负载为pat

Afc=01,表明没有适应段

Section_length=17,表明此段后有17个字节,包括crc

Sid为节目

第二个包  负载为pmt

000000c0h: 04 CA 63 A0 包头47 4pid1 00 10 00 段开始:table_id:02 B0 section_length:46program_number00 01 C1 section_number00 ; .蔯燝A......?

000000d0h: last_sec_number00 F PCR_PID0 01 F0 program_info_length0C tag05 len04 bytes48 44 4D 56tag88 len04 0F FF FC ; .??..HDMV?.?

000000e0h: FC stream_type1B es_pidF0 11 Fes_info_len0 06 desc_tag28 desc_len04 64 00 29 BFstream_type81 es_pidF1 00 Fes_info_len0 ; ???(.d.)??

000000f0h: 12 desc_tag05 desc_len04 41 43 2D 33 desc_tag81 desc_len04 08 48 0E 00 desc_tag0Adesc_len04 6A ; ...AC-3?.H....j

00000100h: 70 6E 00 stream_type90 Fes_pid2 00 Fes_info_len0 06 desc_tag0A desc_len04 7A 68 6F 004C 3A ; pn..?..zho.L:

00000110h: EA 06 FF FF FF FF FF FF FF FF FF FF FF FF FF FF ; ?未完待续。。。。

你可能感兴趣的:(ffmpeg技术文档,TS流,ffmpeg)