AAC/HE-AAC/HE-AAC v2 の ADTS + RawDataBlocks を読み解き、AudioObjectType (2/5/29) を取得するコードを実装しようとした時に調べまわった点と点
- MPEG-2 AAC
- ISO/IEC 13818-7:2004
- MPEG-4 AAC
- ISO/IEC 14496-3:2005
- MPEG-4 AAC を読み解くためには、まず MPEG-2 AAC を一読する必要があります
- cb (Code Book) というワードは、MPEG-4 AAC では Band Type というワードに変化しているようです。
- AAC wikipedia
- Understanding AAC
- Apple - AAC Audio - Encoder Delay and Synchronization
- 第22回 アップルの「iPod」で一躍有名に AACオーディオ圧縮規格を解剖する
AAC は ファイル単位に Priming と Remainder が挿入されます。
Priming が入っているファイルの先頭部分は、波形が鈍っている可能性があります(要)
https://github.com/nu774/qaac/wiki/Encoder-configuration#smart-padding
圧縮音声でずれるというのであれば、エンコーダディレイかな。 んー、でも0.07秒ずれるというのはしっくりこないな。qaacなら約0.04~5秒なら分かるんですが。Neroなら0.054~0.06秒くらい。faacなら0.02秒くらい。(44100Hz, 48000Hzを想定してます)
エンコーダディレイはMDCTを使用する音声コーデック(MP3, AAC, AC-3, Vorbis等)では必ず生じるものです。 これを解決するためにMP3ではLameタグ、MP4に格納された音声ではiTunSMPBやedit listといったものががプレイヤーにこれだけエンコーダディレイがあるからスキップしてね-、という情報を送るための用途として考えられているんですが、FLVとかMKVとかの規格やソフトウェアの作者はこれを大体にして考慮してないので、ユーザーが意識して使用しているコンテナにエンコーダディレイを打ち消すディレイを設定しないと、エンコーダディレイの分だけずれたり、あるいはデコーダがペアとなっているエンコーダのエンコーダディレイを暗黙に想定してスキップして、想定と違うエンコーダが違う場合、結果としてずれるといったケースがあります。 libavcodecのAACデコーダは勝手にスキップしないので、スプリッタ次第では、コンテナに設定したものが正確に反映されます。
そこら辺をちゃんと設定出来ていて且つデコーダなりスプリッタ(demuxer)がそれらを正しく解釈できるのであれば、ずれるということは無いはずです。
ADTS AACにはエンコーダディレイの大きさを示す機能が存在しません。 エンコードしたファイルフォーマットがエンコーダディレイの大きさを明示する機能を備えていない場合、あるいは規格でエンコーダディレイの大きさを規定していない場合では、エンコーダディレイをユーザーが意識せず設定する方法は、エンコーダがmuxerに直接その大きさを教えてあげる以外の方法はありません。 エンコードしたストリームにエンコーダディレイが書かれてない、エンコーダとmuxerの連携が取れていない、のであれば、手動で指定してあげる必要が出てきます。 例えば、qaacでLC-AACで既にエンコードしたものをx264_L-SMASHに渡す場合では --audiofile "%{audpath}" --acodec copy --priming 2112 というようにエンコーダディレイ(priming samples)をこちらが手動で教えてあげなければなりません。
qaacはデフォルトでiTunSMPBを書き込みますから、サポートしているdemuxerやプレイヤーならエンコーダディレイはそのままでも打ち消せるでしょう。 しかし、大抵のdemuxerやプレイヤーはiTunSMPBをサポートしてないので(ffmpeg/libavもサポートしてません)、再生時に役に立つかというと、ビミョー、としか言えません。
ですので、edit listを付与してエンコーダディレイを打ち消すようにするのがよろしいと思います。 不完全ながらサポートしているdemuxerやプレイヤーがiTunSMPBよりは存在します。
MP4Boxなら MP4Box -delay -44 -add input.m4a -new output.m4a
ここで-48は2112を48000Hzを仮定してmsに直したモノです。
2112 * 1000 / 48000 = 44
44100Hzなら
2112 * 1000 / 44100 ≒ 48となります。 頭を落とすので負の値をここでは指定します
AAC BitStream だけを見て、AAC/HE-AAC/HE-AAC v2 を判別するには、最新の規格書(ISO/IEC 14496-3:2005 や :2009)に基づき RadDataBlocks をデコードする必要がある(SBR と PS の情報を知るには ID_FIL の中まで分解する必要がある)が、AAC BitStream は先頭に長さを持たないbit列の結合体なため、必要な情報までデータを読み飛ばす事ができず、大変。
そこでこのようにする
var masterPlayList = load("http://example.com/playlist.m3u8");
var m3u8 = M3U8.parse(masterPlayList); // MasterPlaylistStreamObject // M3U8.js
var audioObjectType = m3u8.stream[0].audio.objectType; // 2(AAC-LC), 5(HE-AAC), 29(HE-AAC v2")
var adts = ADTS.parse(aacByteStream);
var blob = ADTS.toBlob(aacByteStream, audioObjectType, adts.channels, 0);
m3u8 の CODEC に付与された情報を見て AAC の AudioObjectType を判別する
CODEC | AudioObjectType |
---|---|
mp4a.40.2 |
AAC-LC |
mp4a.40.5 |
HE-AAC |
mp4a.40.29 |
HE-AAC v2 |