MPEG-2 TSファイル処理 -TSヘッダのダンプ-


はじめに

前回はとりあえずMPEG-2 TSから1つのTSパケットを取り出し、それを1行でダンプしてみました。TSパケットを解析する場合、次にTSヘッダを解析します。TSパケットは大きく分けるとTSヘッダとペイロードの2つで構成されています。
下図の「header」と「payload」が該当します。

ISO/IEC 13818-1 より引用 「Transport Stream syntax diagram」

TSヘッダは通常4バイトになり、残りがペイロードとなります。ただし、adaptation fieldがある場合、4バイト+adaptation field長となります。

TSヘッダについて

TSヘッダに記述されているデータについては先ほどの図にあるようにsync byteからadaptation fieldとなります。

私がTSパケットを解析する際はsync byte(0x47)を始めに探し、次にPIDを探します。また別に記事を作成しますが、PIDからペイロードの中身が分かります。そのため、重要なデータとなります。また、ペイロードが複数のパケットに分割されている場合は、payload unit start indicatorが1となっているTSパケットを探してペイロードの始まりを確定します。

またとりあえずダンプしてみる

前回作成したプログラムに以下の様な処理を加えました。

static  void            ts_dump_header( const uint8_t* ts_packet, const uint8_t ts_packet_length )
{
    TS_HEADER       header;

    static  bool    show_header = true;

    assert( TS_PACKET_SIZE == ts_packet_length );

    header.SyncByte                      = ts_packet[ 0 ];
    header.TransportErrorIndicator       = ( 0x80 & ts_packet[ 1 ] ) >> 7;
    header.PayloadUnitStartIndicator     = ( 0x40 & ts_packet[ 1 ] ) >> 6;
    header.TransportPriority             = ( 0x20 & ts_packet[ 1 ] ) >> 6;
    header.Pid                           = GET_PID( ts_packet[ 1 ], ts_packet[ 2 ]  );
    header.TransportScramblingControl    = ( ts_packet[ 3 ] & 0xC0 ) >> 6;
    header.AdaptationFieldControl        = ( ts_packet[ 3 ] & 0x30 ) >> 4;
    header.ContinuityCounter             = ts_packet[ 3 ] & 0x0F;

    if( show_header ){
        printf( "Sync byte,Transport Error Indicator,Payload Unit Start Indicator,"\
                "Transport Priority,PID,Transport Scrambling Control,"\
                "Adaptation field control,Continuity counter,Adaptation field,"\
                "TS Packet raw data\n");
        show_header = false;
    }

    printf( "0x%02X,%s,%s,%s,0x%X,%s,%s,%d,", 
            header.SyncByte, 
            ( header.TransportErrorIndicator ) ? "NG" : "OK",
            ( header.PayloadUnitStartIndicator ) ? "ON" : "OFF",
            ( header.TransportPriority ) ? "Higher" : "Normal",
            header.Pid,
            ( ( TS_SCRAMBLE_NONE == header.TransportScramblingControl ) 
                    ? 
                        "Not scrambled"
                    :
                        ( ( TS_SCRAMBLE_EVEN == header.TransportScramblingControl ) 
                            ?
                                "Scrambled with even key"
                            :
                                ( ( TS_SCRAMBLE_EVEN == header.TransportScramblingControl ) 
                                    ?
                                        "Scrambled with even key"
                                    :
                                        "Reserved for future use" )
                        )
            ),
            ( ( TS_ADAPTATION_FIELD_CONTROL_NONE == header.AdaptationFieldControl ) 
                    ? 
                        "Payload only"
                    :
                        ( ( TS_ADAPTATION_FIELD_CONTROL_ONLY == header.AdaptationFieldControl ) 
                            ?
                                "Adaptation field only"
                            :
                                ( ( TS_ADAPTATION_FIELD_CONTROL_WITH_PAYLOAD == header.AdaptationFieldControl ) 
                                    ?
                                        "Adaptation field followed by payload"
                                    :
                                        "Reserved for future use" )
                        )
            ),
            header.ContinuityCounter
    );

    if(    ( PID_NULL == header.Pid )
        || ( TS_ADAPTATION_FIELD_CONTROL_NONE == header.AdaptationFieldControl ) ){
        printf( "-," );
    }else{
        int i;
        for( i = 0 ; i < ts_packet[ 4 ] ; i++ ){
            printf( "%02X ", ts_packet[ 4 + i ] );
        }
        printf( "," );
    }
}

おわりに

今回はTSヘッダを解析しました(adaptation fieldを除く)。次は、adaptation fieldからPCRを取り出してみます。