LoginSignup
2
1

More than 3 years have passed since last update.

ATS(Arrival Timestamp)つきトランスポートストリーム(Timestamped Transport Stream)の仕組み

Last updated at Posted at 2021-01-21

はじめに

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パケットは比較器のところで留め置かれます。
このような比較的簡単な仕組みで、可変レートから固定レートへの変換を実現しています。(下図 参照)

tts.png

ATSつきTSのファイル拡張子

.m2tsが使われることが多いですが、.mtsや.ttsが使われることもあります。

サンプルプログラム

各TSパケットのATSを抽出して、その値と1つ前のATSとの差分を表示するプログラムです。

log_ats.c
/*
 * 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;
}

参考リンク

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1