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

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

> ISO/IEC 13818-1 より引用 「Transport Stream syntax diagram」
>> ![TS_packet.png](https://qiita-image-store.s3.amazonaws.com/0/286729/0cd1d96c-46f2-59dc-84ea-faed2e97ffba.png)


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を取り出してみます。