はじめに
ATS (Arrival Timestamp) つきのトランスポートストリーム (TTS : Timestamped Transport Stream) は一般的に広く用いられているのですが、日本語で適切な説明があまりなさそうだったので記事にしました。
トランスポートストリーム録画の課題
デジタル放送で使われるトランスポートストリーム (TS : Transport Stream) は、
- 受信に必要な付加情報 (PSI/SI etc.)
- 複数チャンネル分のビデオ & オーディオストリーム
- TSの転送レートを固定に保つためのヌルパケット (何も情報を持たないパケット)
などから成り立っています。
放送受信時はこれで問題ない(これが望ましい)のですが、記録媒体に録画する場合、不要な付加情報やチャンネル、ヌルパケットなどで記憶容量を無駄に消費してしまいます。
とはいえ、単純に、不要なTSパケットを破棄して録画するだけでは、再生時にTSの転送レートを一定に保つことができず、ビデオ & オーディオのバッファオーバーフロー/アンダーフローの原因となります。(下図 参照)
その課題解決のために、ATSつきのトランスポートストリームの仕組みが考えられました。
ATS (Arrival Timestamp) を使った再生の仕組み
通常のTSパケットは1パケット188byteのサイズですが、ATSつきのTSパケットは先頭に4byteの拡張ヘッダがついた、計192ByteのTSパケットになります。
拡張ヘッダ 4byte (32bit) の内訳は以下の通りです。
- MSB 2bit (bit31-30) : コピー許可の情報
- LSB 30bit (bit29-0) : 時刻情報 (ATS : Arrival Timestamp)
ATSは27MHzでカウントアップされるカウンタであり、0x3FFFFFFFを超えると0にラップアラウンドします。
ATSに対応したデコーダは、通常のTS再生器 (demuxer) の前段に、27MHzの時計と比較器が追加されています。
デコード時は、デコーダの時計とATSとの値が比較されて、時刻が一致したときに、TSパケット188byte分が後段のTS再生器に送られます。デコーダの時計の値とATSの値が一致しない場合は、時計がATSの値に一致するまで、TSパケットは比較器のところで留め置かれます。
このような比較的簡単な仕組みで、可変レートから固定レートへの変換を実現しています。(下図 参照)
ATSつきTSのファイル拡張子
.m2tsが使われることが多いですが、.mtsや.ttsが使われることもあります。
サンプルプログラム
各TSパケットのATSを抽出して、その値と1つ前のATSとの差分を表示するプログラムです。
/*
* log_ats.c:
* pick up ATS (Arrival Time Stamp) and calculate the difference between the previous arrival time stamp.
*
* Input : TS-stream with ATS (4byte) ahead of each TSP (188byte).
* Output: TS packet number, ATS value, difference between the previous ATS
*/
# include <stdio.h>
# include <stdlib.h>
# define ATS_SZ 4
# define TSP_SZ 188
# define ATS_MAX 0x3fffffff
# define warn(msg) fprintf(stderr, msg, tsp_count)
# define GET_ATS(p) (((unsigned long)p[0] & 0x3f)<<24 | (unsigned long)p[1]<<16 | (unsigned long)p[2]<<8 | (unsigned long)p[3])
int main()
{
unsigned char buf[ATS_SZ + TSP_SZ];
unsigned char *tsp = buf + ATS_SZ;
unsigned long ats_diff;
unsigned long prev_ats, ats;
int tsp_count = 0;
while (1 == fread(buf, ATS_SZ + TSP_SZ, 1, stdin)) {
tsp_count++;
if ((int)*tsp != 0x47) {
warn("not 0x47 @%d\n");
// exit (EXIT_FAILURE);
}
ats = GET_ATS(buf);
if (tsp_count == 1) {
printf("%lu,---\n",ats);
} else {
ats_diff = (prev_ats > ats) ? (ats + ATS_MAX - prev_ats) : (ats - prev_ats);
printf("%lu,%lu\n",ats,ats_diff);
}
prev_ats = ats;
}
return 0;
}
参考リンク
-
英語のwikiが一番詳しいです。
-
MPEG2システム一般の説明(TTSの話もあります)。