PLAY DEVELOPERS BLOG

HuluやTVerなどの日本最大級の動画配信を支える株式会社PLAYが運営するテックブログです。

HuluやTVerなどの日本最大級の動画配信を支える株式会社PLAYが運営するテックブログです。

フロントエンジニアなら知っておきたいトランスマックス入門

こんにちは、クラウド推進技術部開発第1グループの石川です。

突然ですが、トランスマックス (Transmux) とはなんでしょうか?
動画は内容を表すコーデック (H.264, H.265, mp3, AAC, ...) と、コーデックを多重化するコンテナ (MPEG-TS, fmp4, FLV, ...) で構成されています。
トランスマックスは、コーデックはそのまま、コンテナを移し替えることを指します。

ここまでの話だと、全然フロントエンドと関係ないと思われるかもしれませんが、実はブラウザでのメディア再生には欠かせない技術になります。 何故かというと、ブラウザでの視聴の際に、非対応なコンテナからの変換で fmp4 へ JavaScript 上でトランスマックスしているからです。

今回は、実はよく使われているが説明の少ない、トランスマックスの世界を説明します。

コンテナについて

トランスマックスを説明する前に、まず動画のコンテナ自体について説明します。
よく使われる配信系のコンテナとしては、 MPEG-TS, fmp4, FLV が有名どころですので、それぞれ簡単に解説します。

MPEG-TS

MPEG-TS は 188 バイト (ヘッダ 4 バイト) で構成される TS パケットで多重化します。
MPEG が策定した MPEG-2 System の中の トランポートストリーム (TS) として定義されているため、略称として MPEG-TS が使われます。

特徴としては、金太郎飴みたいな 188 バイトのパケットで構成されているため、伝送路で誤りや欠落が生じるような場合でも、検知、回復した際の復帰ができます。
また、ユーザ定義 (放送系に特に多い) のメタデータが多く、メタデータも豊富なコンテナです。

デジタルテレビなどの放送や、HLS での配信でよく使われています。

fmp4

fmp4 は mp4 (ISOBMFF) コンテナを フラグメント化 (fragmented) して多重化します。

元々の mp4 は MPEG-4 ISO base Media File Format で策定されたコンテナであり、Box を入れ子にした構造によって、各メディアを多重化します。
fmp4 は mp4 では 動画の一部分だけを利用する、ということが難しいために、フラグメント化 (fragmented) して分割し、細切れに利用しやすくしたものです。
実際の配信では、派生した CMAF (ISO/IEC 23000-19) を用いることが多いですが、それらを総称して fmp4 と呼びます。

特徴としては、mp4 (ISOBMFF) は、QTFF (QuickTime File Format) が元であり、QTFF 自体が編集用フォーマットとして生まれたものです。
ですので、コーデックに依存せず編集するために、映像/音声に関する様々なメタ情報が充実しています。

配信では、上述した CMAF による HLS や MPEG-DASH での配信でのコンテナとしてよく使われています。 *1

FLV

FLV は FLVヘッダ(FLVの構成を示す固定長) と FLVタグ(可変長) で構成されており、FLV タグによって、映像や音声、スクリプトデータなどを多重化します。
FLV は Flash Video の略で、Flash のストリーミング用フォーマットであり、現時点では Adobe のプロプライエタリなコンテナです。

データを ECMAScript オブジェクトをシリアライズした、AMF (Action Message Format) として送る点が非常にユニークです。

現時点でも RTMP での動画コンテナとしてよく使われているコンテナになります。

なぜブラウザ内で fmp4 に変換するの?

動画配信では、ライブで動画をどんどん追加していく、巻き戻って最初から見る、などの操作をする事があります。
この際に、動的なバッファ管理が必要になりますが、それを可能にする API が MSE (Media Source Extension) です。

MSE で扱いやすい形式が fmp4 と webm なのですが、 webm は H.264, H.265, AAC には対応していません。
このため、基本的に配信で使われる H.264/AAC の組み合わせは、fmp4 へとトランスマックスされます。

MSE (Media Source Extension)

MSE (Media Source Extension) は、以下の 2 つのクラスで構成されています

  • MediaSource: 動的なバッファを管理して仲介するクラス
  • SourceBuffer: バッファ自体に相当するクラス

基本的に SourceBuffer で受け付けるコンテナは主に webm, fmp4 が主流です。
しかし、上述の通り、トランスマックスする際には、コンテナ自体の対応フォーマットの多さから fmp4 にする事が多いです。

余談ですが、Chrome 108 からは、WebWorker 内で MSE の処理ができるようになり、バッファ管理の処理を全て WebWorker 側に記載できるようになりました。

H.264 と AAC の構成

配信で使われる主要なコーデックは H.264 (映像) と AAC (音声) です。
H.264, AAC 共にトランスマックスで大きく形式が変わるため、これらも説明します。

H.264 の構成について

H.264 は NAL*2ユニット で構成されています。
その NALユニット のコンテナへの格納の仕方は、以下の 2 種類となります。

  • NAL File Format: FLV, fmp4 (ISOBMFF) で使われている形式です
  • Byte Stream Format (AnnexB): MPEG-TS で使われている形式です

Byte Stream Format で送られた場合には、MSE で管理するために NAL File Format に変換する必要があります。

ここから 2 種類の格納の仕方について説明します。

NAL File Format

各 NAL ユニット (EBSP *3 ) の先頭に、別途記載されたバイト数で EBSP の長さを Big Endian で記載するフォーマットです。
例えば、mp4 (ISOBMFF) や FLV では、AVCDecoderConfigurationRecord に記載する lengthSizeMinusOne から取得します。

Byte Stream Format (AnnexB)

各 NAL ユニット (EBSP) の先頭に、スタートコード (0x00000001 or 0x000001) を目標として記載するフォーマットです。
ランダムアクセス可能な先頭の NALu (AUD: Access Unit Delimiter など) では 0x00000001 の 4 バイト、
それ以外の時には 0x000001 の 3 バイトのスタートコードを付加します。

AAC の構成について

AAC のコンテナへの格納の仕方は、主流なのは以下の 3 種類となります。

  • RAW: FLV, fmp4 (ISOBMFF) で使われています
  • ADTS: MPEG-TS でよく使われています
  • LATM/LOAS: 次世代系の放送で使われる事があります

さらっと言うと、生の AAC を別の構成情報と共に送る方式と、ADTS ヘッダ (固定長) を付加する方式と、可変長のヘッダを付加する形式です。
これも ADTS や LATM/LOAS で送られた場合には、MSE で管理するため RAW に変換する必要があります。

それぞれについて、以下で説明します。

RAW

ADTS が付加されていない、生の AAC ペイロードで構成されるフォーマットです。
例えば、mp4 (ISOBMFF) や FLV では、別途 AudioSpecificConfig に構成情報を記載します。 *4

このフォーマット単体では再生はできません。

ADTS (Audio Data Transport Stream)

AAC ペイロードに ADTS (Audio Data Transport Stream) ヘッダがついたフォーマットです。
ADTS ヘッダに音声の構成情報が載っているため、ADTS フォーマットであれば再生が可能です。

LATM/LOAS (Low-overhead MPEG-4 Audio Transport Multiplex / Low Overhead Audio Stream)

AAC ペイロードを可変長のヘッダを持つ LATM で多重化し、同期のために LOAS を使う形式です。

LATM/LOAS は MPEG4 Audio で規定されているため、 AudioSpecificConfig を付けた上でのストリーム伝送ができます。
ADTS は MPEG2 で規定されているため、マルチチャンネルオーディオのチャンネル数で対応していないものもあります。
そういった、新しい規格を使う必要がある場合に、LATM/LOAS が使われます。

このため、次世代の配信において使われることがありますが、ここでは詳しくは説明しません。

トランスマックス

本題となる、コンテナのトランスマックスの話にようやく入ります。
ここでは、MPEG-TS に入っている H.264/AAC を fmp4 に入る形式に移し替える、という例で説明します。

基本的な流れは、MPEG-TS の PAT *5, PMT *6 から対象のコーデックの PES を探し、そこからコーデックの Access Unit を取り出します。
そこで取得したコーデックの内容を変換し、fmp4 へと詰め直す作業を行います。

fmp4 に詰め直す部分コードは、OSS でよく使われている実装として hls.js/mp4-generator.tsmux.js/mp4-generator.js があります。

ここでは、上記のコードの補完の説明にとどめ、各コンテナの詳細なコーデック情報の取得、構成方法については省略し、コーデックの変換部分について説明します。

H.264 の変換

MPEG-TS では Byte Stream Format で H.264 のデータが伝送されるため、NAL File Format に変換するという作業が必要です。
このために、スタートコードがあるかどうかを 1 バイトづつ見て、NAL ユニットを分離します。

NAL File Format で必要な AVCDecoderConfigurationRecord は Byte Stream Format で送られる SPS, PPS の情報から作成できます。

作成した AVCDecoderConfigurationRecord は fmp4 では Initialization Segment の avcC に記載します。
mp4dump での表記で示すと moov/trak/mdia/minf/stbl/stsd/avc1/avcC という階層で avcC を配置します。

AAC の変換

MPEG-TS では ADTS で AAC のデータが伝送されるため、AudioSpecificConfig + RAW AAC に変換する作業が必要です。
ADTS なので、同期信号を元に先頭を特定して、そこからヘッダ情報に従って RAW AAC を分離します。

RAW AAC での再生に必要な AudioSpecificConfig は ADTS ヘッダの情報から構成します。

作成した AudioSpecificConfig は fmp4 では esds 内の DS Descriptor に記載します。
mp4dump での表記で示すと moov/trak/mdia/minf/stbl/stsd/mp4a/esds になります。

おわりに

トランスマックス周りの前提知識と、MPEG-TS での H.264/AAC 配信のコンテナを fmp4 へトランスマックスする際の処理を紹介しました。
hls.js や mux.js などで行う MPEG-TS の動画を再生する際の変換は、大雑把にいうと、こんなものになります。

ちなみに、トランスマックスのボトルネックは H.264 の Byte Stream Format を NAL File Format へと変換する部分になります。 何故かというと、ビットレートのほとんどが映像である上に、1バイトずつスキャンするためビットレートに比例する計算量があるためです。
高画質の場合に CPU 負荷が高くなる原因は、この部分の変換がほぼ支配的になります。

最初から fmp4 であったり、NAL File Format であると、処理の計算量は大幅に下がります。
また、MSE for WebCodecs によってコーデックが直接入れられるようになれば、コンテナ変換について考えなくても良くなります。
WebCodecs 共々、今後が楽しみで期待が膨らみますね。

今回は、ほんのさわりであるため、各コンテナの詳細、構成方法についてなど、省略した部分が多数あります。
実際に fmp4 を作るなど、実践的な内容は、機会があったら少しづつ書いていきたいところです。

*1:実は HLS では CMAF 準拠ではない fmp4(ISOBMFF) も再生可能でして、mediastreamsegmenter にも ISO/CMAF の区別があります

*2:Network Abstraction Layer の略で伝送プロトコルによらないデータ伝送部分の決め事の部分です

*3:Encapsulate Byte Sequence Payload の略でNALuのバイト列がエスケープされたものです

*4:主に使われているのは MPEG4 Audio 扱いですので AudioSpecificConfig と説明しています

*5:Program Association Table の略で、各 Program の PMT の PID を保持するテーブルです

*6:Program Mapping Table の略で、各 Program を構成する ES の PID を保持するテーブルです