欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

从mpeg ts文件中提取I帧(2):PAT,PMT解释

程序员文章站 2022-03-23 09:05:24
...

一、PAT用途
1、描述当前传输流中 PMT 的 PID 信息。
2、描述PMT,与SDT的对应关系。
3、program_number=0时为network pid即nit的pid,接收pmt时注意跳过这nit。
4、pat是整个ts流的入口,依据pat描述的pmt pid就可以搜索出所有的pmt信息。

其语法结构如下图所示:
从mpeg ts文件中提取I帧(2):PAT,PMT解释

PAT解析代码:

int mpeg_psi_pat_parse(uint8_t *sec_buf, int32_t sec_len, int16_t pid)
{
    uint8_t* buf = sec_buf;
    uint32_t program_loop_length = (uint16_t)(((buf[1]&0x0f)<<8)|buf[2]) - 9;

    if (MPEGPSI_TID_PAT != buf[0]) {
        print_err("pat tid=%d\n", buf[0]);
        return -1;
    }

    printf("pat section pid=0x%04x\n", pid);
    printf(" |-table_id                =0x%x\n", (uint8_t )(  buf[0])                 );
    printf(" |-section_syntax_indicator=0x%x\n", (uint8_t )(( buf[1]&0x80)>>7)        );
    printf(" |-section_length          =0x%x\n", (uint16_t)(((buf[1]&0x0f)<<8)|buf[2]));
    printf(" |-extend_table_id         =0x%x\n", (uint16_t)(( buf[3]<<8)|buf[4])      );
    printf(" |-version_number          =0x%x\n", (uint8_t )(( buf[5]&0x3e)>>1)        );
    printf(" |-current_next_indicator  =0x%x\n", (uint8_t )(  buf[5]&0x01)            );
    printf(" |-section_number          =0x%x\n", (uint8_t )(  buf[6])                 );
    printf(" |-last_section_number     =0x%x\n", (uint8_t )(  buf[7])                 );

    g_mpeg_transport.transport_stream_id = (uint16_t)(( buf[3]<<8)|buf[4]);
    g_mpeg_transport.program_numb        = 0;
    buf = sec_buf + 8;
    while( program_loop_length > 0 ) {   
        uint16_t program_number  = (uint16_t)( buf[0]<<8       | buf[1]);
        uint16_t program_map_pid = (uint16_t)((buf[2]&0x1f)<<8 | buf[3]);
        printf("   |-program_number=0x%04x program_map_pid=0x%04x (%d)\n", program_number, program_map_pid, program_map_pid);           

        if (g_mpeg_transport.program_numb < MPEGPSI_MAX_PROGRAM) {
            g_mpeg_transport.program_info[g_mpeg_transport.program_numb].program_number  = program_number;
            g_mpeg_transport.program_info[g_mpeg_transport.program_numb].program_map_pid = program_map_pid;
            g_mpeg_transport.program_numb ++;
        }
        else {
            print_err("MPEGPSI_MAX_PROGRAM=%d overflow.\n", MPEGPSI_MAX_PROGRAM);
        }

        if( program_loop_length >= 4 ) {
            program_loop_length = program_loop_length - 4;    
            buf = buf + 4;
        }
        else {
            printf("pat parse error !!!\n");
            break;
        }   
    }

    buf = sec_buf + (sec_len-4);
    printf(" |-crc_32 = 0x%x 0x%x\n", (uint32_t)((buf[0]<<24)|(buf[1]<<16)|(buf[2]<<8)|(buf[3])), mpeg_crc32(sec_buf, sec_len-4));
    printf("\n");

    return 0;
}

PAT解析运行结果:

pat section pid=0x0000
 |-table_id                =0x0
 |-section_syntax_indicator=0x1
 |-section_length          =0x25
 |-extend_table_id         =0x2
 |-version_number          =0x1
 |-current_next_indicator  =0x1
 |-section_number          =0x0
 |-last_section_number     =0x0
   |-program_number=0x0000 program_map_pid=0x0010 (16)
   |-program_number=0x00c9 program_map_pid=0x0100 (256)
   |-program_number=0x00ca program_map_pid=0x0200 (512)
   |-program_number=0x00cb program_map_pid=0x0300 (768)
   |-program_number=0x00cc program_map_pid=0x0400 (1024)
   |-program_number=0x00cd program_map_pid=0x0500 (1280)
   |-program_number=0x00ce program_map_pid=0x0600 (1536)
 |-crc_32 = 0x6012d6e2 0x6012d6e2

二、PMT用途
1、当前频道中包含的所有Video数据的PID
2、当前频道中包含的所有Audio数据的PID
3、和当前频道关联在一起的其他数据的PID(如数字广播等使用的PID)
4、加扰节目授权控制信息 ECM PID

从mpeg ts文件中提取I帧(2):PAT,PMT解释
PMT解析代码:

int mpeg_psi_pmt_parse(uint8_t *sec_buf, int32_t sec_len, int16_t pid)
{
    uint8_t *buf                 = sec_buf;
    uint8_t *ptr                 = NULL;
    uint16_t program_info_length = (uint16_t)(((buf[10]&0x0f)<<8)|buf[11]);
    uint16_t stream_loop_length  = 0;
    uint16_t section_length      = (uint16_t)(((buf[1]&0x0f)<<8)|buf[2]);
    mpeg_program_t *program      = NULL;
    int i                        = 0;

    if (MPEGPSI_TID_PMT != buf[0]) {
        print_err("pat tid=%d\n", buf[0]);
        return -1;
    }

    for (i=0; i<g_mpeg_transport.program_numb; i++) {
        if (g_mpeg_transport.program_info[i].program_map_pid == pid) {
            program = &(g_mpeg_transport.program_info[i]);
            break;
        }
    }

    printf("pmt section pid=0x%04x(%d)\n", pid, pid);
    printf("|-table_id                 = 0x%x\n", (uint8_t)(   buf[0])                 );
    printf("|-section_syntax_indicator = 0x%x\n", (uint8_t)((  buf[1]&0x80)>>7)        );
    printf("|-section_length           = 0x%x\n", (uint16_t)(((buf[1]&0x0f)<<8)|buf[2]));
    printf("|-program_number           = 0x%x\n", (uint16_t)(( buf[3]<<8)|buf[4])      );
    printf("|-version_number           = 0x%x\n", (uint8_t)((  buf[5]&0x3e)>>1)        );
    printf("|-current_next_indicator   = 0x%x\n", (uint8_t)(   buf[5]&0x01)            );
    printf("|-section_number           = 0x%x\n", (uint8_t)(   buf[6])                 );
    printf("|-last_section_number      = 0x%x\n", (uint8_t)(   buf[7])                 );
    printf("|-pcr_pid                  = 0x%x\n", (uint16_t)(((buf[8]&0x1f)<<8)|buf[9]));
    printf("|-program_info_length      = 0x%x\n", program_info_length                  );

    pmt_descriptor_parse(buf+12, program_info_length, 0);

    stream_loop_length = section_length - program_info_length - 13;
    ptr = buf + 12 + program_info_length;
    while (stream_loop_length) {
        uint16_t es_info_length = 0;
        uint16_t stream_type    = 0;
        uint16_t elementary_pid = 0;
        char     x              = '-';

        es_info_length = (uint16_t)(((ptr[3]&0x0f)<<8)|ptr[4]);
        if (es_info_length!=0) {
            x = '+';
        }

        elementary_pid = (uint16_t)(((ptr[1] & 0x1f) << 8) | ptr[2]);
        stream_type    = ptr[0];
        printf("|%ces_pid = 0x%x stream_type = 0x%x\n", x, elementary_pid, stream_type);
        
        if (NULL != program) {
            if (program->stream_numb < MPEGPSI_MAX_STREAM) {
                program->stream_info[program->stream_numb].elementary_pid = elementary_pid;
                program->stream_info[program->stream_numb].stream_type    = stream_type;
                program->stream_numb ++;
            }
            else {
                print_err("MPEGPSI_MAX_STREAM=%d overflow.\n", MPEGPSI_MAX_STREAM);
            }
        }

        pmt_descriptor_parse(ptr+5, es_info_length, 1);

        es_info_length += 5;
        if (stream_loop_length >= es_info_length) {
            stream_loop_length -= es_info_length;
            ptr +=es_info_length;
        }
        else {
            break;
        }
    }
    
    buf = sec_buf + (sec_len-4);
    printf("|-crc_32 = 0x%x 0x%x\n", (uint32_t)((buf[0]<<24)|(buf[1]<<16)|(buf[2]<<8)|(buf[3])), mpeg_crc32(sec_buf, sec_len-4));
    printf("\n");

    return 0;
}

PMT解析运行结果:

mt section pid=0x0100(256)
|-table_id                 = 0x2
|-section_syntax_indicator = 0x1
|-section_length           = 0x4f
|-program_number           = 0xc9
|-version_number           = 0x1
|-current_next_indicator   = 0x1
|-section_number           = 0x0
|-last_section_number      = 0x0
|-pcr_pid                  = 0x1ffe
|-program_info_length      = 0x17
|+descriptor
 |-unknown_descriptor tag=0x0b len=0x2 4a 1f 
 |-unknown_descriptor tag=0x0c len=0x4 80 b4 81 68 
 |-unknown_descriptor tag=0x0e len=0x3 c0 1e c6 
 |-unknown_descriptor tag=0x10 len=0x6 c0 1e c6 c0 08 00 
|+es_pid = 0x101 stream_type = 0x2
 |-unknown_descriptor tag=0x02 len=0x3 1a 48 5f 
 |-unknown_descriptor tag=0x52 len=0x1 00 
 |-unknown_descriptor tag=0x0e len=0x3 c0 1c f0 
 |-unknown_descriptor tag=0x06 len=0x1 02 
|+es_pid = 0x102 stream_type = 0x4
 |-unknown_descriptor tag=0x03 len=0x1 67 
 |-unknown_descriptor tag=0x0a len=0x4 65 6e 67 00 
 |-unknown_descriptor tag=0x52 len=0x1 8a 
 |-unknown_descriptor tag=0x0e len=0x3 c0 01 68 
|-crc_32 = 0x580343a4 0x580343a4

三、为什要解析pat pmt
1、用来校验输入的视频pid是否合法,免去了遍历整个ts的开销。
2、当不知道视频pid时,可以通过pat pmt的解析,显示所有的视音频pid。

mpeg2标准:https://download.csdn.net/download/maxzero/10402761
完整的代码:https://download.csdn.net/download/maxzero/10572383