FFmpeg で Dolby Digital Plus JOC を MP4 に mux すると Dolby Atmos として認識されなくなる問題

最終更新日

「E-AC-3 JOC」などの検索ワードで来られた方へ

この記事は、コーデックやフォーマット自体の解説記事ではありません。これらの詳細については、以下の記事をご覧ください。

問題の事象

この問題は、Codec 2.0 仕様のデコーダーを搭載した最近の Android 端末においては気にする必要がなくなっている可能性があります。この記事では、従来の OpenMAX IL のデコーダーの挙動のみを載せています。後日、Codec 2.0 の方も調査する予定です。

Dolby Digital Plus JOC (E-AC-3 JOC) 音声を Android 10 の Dolby Atmos 対応端末の一部 (AQUOS や arrows など) で再生すると、再生中に以下のような通知が出る。ちなみに、JOC (Joint Object Coding) とは、Dolby Digital Plus (Enhanced AC-3、E-AC-3) で Dolby Atmos を実現するためのフォーマットのことである。

arrows NX9 で再生

Dolby ATOMS と誤字っているが、Dolby Atmos として認識されている事はわかる。

同じものを Dolby Atmos 対応の iPhone (iOS 15) / iPad (iPadOS 15) で再生し、AirPods Pro などで聴くと、音量調整画面に「ドルビーアトモス」の表記が出る。

iPad mini (第6世代) + AirPods Pro で再生

ログでも確認できる。

mediaserverd(AudioCodecs)[35] <Notice>: ACDDPAtmosDecoder.cpp:476:Initialize: (0x10f954040) Input format: 12 ch,  48000 Hz, 'ec+3' (0x00000000) 0 bits/channel, 0 bytes/packet, 1536 frames/packet, 0 bytes/frame
mediaserverd(AudioCodecs)[35] <Notice>: ACDDPAtmosDecoder.cpp:479:Initialize: (0x10f954040) Output format: 12 ch,  48000 Hz, Float32, non-inter

12ch は 7.1.4ch のことで、iPhone / iPad は Dolby Atmos を 7.1.4ch にデコードしている (audio channel layout tag = Atmos_7_1_4)。

mediaserverd(libAudioDSP.dylib)[33] <Notice>: InputElement #0: Setting stream format: 12 ch,  48000 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved
mediaserverd(libAudioDSP.dylib)[33] <Notice>: SetAudioChannelLayout: Setting input 0 audio channel layout tag = Atmos_7_1_4
mediaserverd(libAudioDSP.dylib)[33] <Notice>: Setting output type = 1
mediaserverd(libAudioDSP.dylib)[33] <Notice>: Setting frequency domain only filtering = 1
mediaserverd(libAudioDSP.dylib)[33] <Notice>: Setting input 0 spatialization algorithm = 7
mediaserverd(libAudioDSP.dylib)[33] <Notice>: OutputElement: Setting output stream format:  2 ch,  48000 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved
mediaserverd(libAudioDSP.dylib)[33] <Notice>: SetAudioChannelLayout: Setting output audio channel layout tag = Stereo
mediaserverd(libAudioDSP.dylib)[33] <Notice>: Restore state
mediaserverd(libAudioDSP.dylib)[33] <Notice>: Setting render quality = 64

ec+3 は Dolby Digital Plus JOC (E-AC-3 JOC) のことを指す。

code: ec+3
description: Enhanced AC-3 audio with JOC

The ‘MP4’ Registration Authority

一方、Dolby Digital や Dolby Digital Plus の 2.0ch や 5.1ch、7.1ch 音声を再生すると、先程の Android 端末の通知は「Dolby Audio」となる。

arrows NX9 で再生

iOS 15 / iPadOS 15 では、「マルチチャンネル」という表記になる。

iPad mini (第6世代) + AirPods Pro で再生

不思議なことに、Android や iOS / iPadOS に Dolby Atmos として認識されている Dolby Digital Plus JOC (E-AC-3 JOC) 音声を、FFmpeg で -c:a copy (再エンコードせずそのままコピー) して MP4 コンテナに mux (multiplex: 多重化) すると、Android 10 では「Dolby Audio」、iOS / iPadOS では「マルチチャンネル」として認識されてしまう。

念の為 iPadOS のログを確認すると、このようになっている。

mediaserverd(AudioCodecs)[35] <Notice>: ACDDPAtmosDecoder.cpp:476:Initialize: (0x10f95c040) Input format:  6 ch,  48000 Hz, 'ec-3' (0x00000000) 0 bits/channel, 0 bytes/packet, 1536 frames/packet, 0 bytes/frame
mediaserverd(AudioCodecs)[35] <Notice>: ACDDPAtmosDecoder.cpp:479:Initialize: (0x10f95c040) Output format:  6 ch,  48000 Hz, Float32, non-inter

この 6ch とは 5.1ch のことである (audio channel layout tag = MPEG_5_1_C)。

mediaserverd(libAudioDSP.dylib)[35] <Notice>: InputElement #0: Setting stream format:  6 ch,  48000 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved
mediaserverd(libAudioDSP.dylib)[35] <Notice>: SetAudioChannelLayout: Setting input 0 audio channel layout tag = MPEG_5_1_C
mediaserverd(libAudioDSP.dylib)[35] <Notice>: Setting output type = 2
mediaserverd(libAudioDSP.dylib)[35] <Notice>: Setting frequency domain only filtering = 1
mediaserverd(libAudioDSP.dylib)[35] <Notice>: Setting input 0 spatialization algorithm = 7
mediaserverd(libAudioDSP.dylib)[35] <Notice>: OutputElement: Setting output stream format:  2 ch,  48000 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved
mediaserverd(libAudioDSP.dylib)[35] <Notice>: SetAudioChannelLayout: Setting output audio channel layout tag = Stereo
mediaserverd(libAudioDSP.dylib)[35] <Notice>: Restore state
mediaserverd(libAudioDSP.dylib)[35] <Notice>: Setting render quality = 64

この時再生していた Dolby Digital Plus JOC 音声の、Dolby Atmos 非対応機器向け互換用ダウンミックス部分は 5.1ch となっているため Dolby Atmos として認識されていないように見える。

そして、先程 ec+3 となっていた箇所は、Dolby Atmos でない Dolby Digital Plus のことを指す ec-3 になっている。

code: ec-3
description: Enhanced AC-3 audio

The ‘MP4’ Registration Authority

やはり Dolby Atmos として認識されていないようだ。

参考

Dolby Audio の詳細や Dolby Digital Plus JOC の構造等に関しては、以下の記事で解説している。

何が違うのか

-c:a copy だけでは Dolby Atmos 用のメタデータか何かが引き継がれないのかとも思ったが、MediaArea の MediaInfo では問題なく Dolby Digital Plus with Dolby Atmos として認識れさている。

さらに、PC から AV アンプに音声をビットストリーム出力しても、きちんと Dolby Digital Plus with Dolby Atmos として認識されている。

これらのことから、音声ストリーム自体には問題がないようだ。

そこで、Dolby Stream Validator で検証してみると、以下のようなエラーが出た。

ERROR: For [EC3] stream, in MP4, the bitstream indicates Dolby Atmos content (the “addbsil” isn’t 0), but the EC3SpecificBox indicates non-atmos content (the “flag_ec3_extension_type_a” in EC3SpecificBox is FALSE).

validation result: FAILED

Dolby Stream Validator

Dolby Digital Plus のビットストリーム内の addbsil が0ではない (= Dolby Atmos のフラグが立っている) にも関わらず、MP4 コンテナ内の EC3SpecificBox の flag_ec3_extension_type_a は FALSE になっている (= Dolby Atmos フラグが立っていない) といった状況のようだ。詳細は [PDF] ETSI のホワイトペーパー にて。

これを FFmpeg でなんとかできないものかと、ffprobe で MP4 ファイルの情報を比較してみると、以下の部分が違っていた。

Dolby Atmos として扱われる Dolby Digital Plus (1)

major_brand     : mp42
minor_version   : 1
compatible_brands: mp42dby1isom

Dolby Atmos として扱われる Dolby Digital Plus (2)

major_brand     : dby1
minor_version   : 0
compatible_brands: dby1isommp42

Dolby Atmos として扱われる Dolby Digital Plus (3)

major_brand     : mp42
minor_version   : 1
compatible_brands: mp42dby1

5.1ch として扱われてしまう Dolby Digital Plus (FFmpeg で mux したもの)

major_brand     : isom
minor_version   : 512
compatible_brands: isomiso2avc1mp41

ffprobe では addbsil や flag_ec3_extension_type_a については確認できなかったものの、やはり Dolby Digital Plus のビットストリームのメタデータ自体には違いはなく、MP4 コンテナのメタデータ、具体的には Major Brand (major_brand) や Compatible Brands (compatible_brands) が違っていた。

うち、Dolby Atmos として認識される MP4 ファイルに共通して入っている dby1 が、どうやら Dolby 関連の Brand らしい。

code: dby1
description: MP4 files with Dolby content (e.g. Dolby AC-4, Dolby Digital Plus, Dolby TrueHD (Dolby MLP))

The ‘MP4’ Registration Authority

一方 FFmpeg で MP4 を mux した際は、デフォルトでは Major Brand が isom、Compatible Brands が isom、iso2、avc1、mp41 となるようで、そこに dby1 の姿はない。

Compatible Brands に dby1 を追加することで、もしかすると Dolby Atmos として認識してくれるのかもしれない。

何を試したのか

FFmpeg で flag_ec3_extension_type_a を操作する方法は分からなかったので、とりあえず Major Brand と Compatible Brands だけでもなんとかしてみようと思った。

FFmpeg で mux する際に -brand dby1 してみると、 Major Brand が dby1 に、Compatible Brands が dby1、iso2、avc1、mp41 になった。これを AQUOS / arrows や iPhone / iPad で再生してみたところ、Dolby Atmos としては扱われなかった。どうやら mp42 も必要らしい。

-brand mp42 では Major Brand が mp42 に、Compatible brands は mp42、iso2、avc1、mp41 となり、dby1 が入らない。これも Dolby Atmos として扱われなかったことから、mp42 と dby1 の両方が必要ということになる。

-brand mp42,dby1-brand mp42dby1isom を試してみても、 -brand mp42 と同じ結果になり、dby1 は無視された。

直接メタデータを叩こうと、-metadata:g compatible_brands=mp42dby1isom をしてもうまく行かなかった。

FFmpeg では、MP4 の Major Brand は任意の値に設定することはできても、Compatible Brands は FFmpeg が用意した Major Brand ごとのプリセットにしか設定できないようだ。

そもそも、Compatible Brands に mp42 と dby1 を同時設定できたところで、MP4 コンテナに「Dolby Digital Plus のビットストリームには Dolby Atmos 用の JOC のデータが含まれている」という情報を持たせる (flag_ec3_extension_type_a を TRUEにする) ことができるのかどうかは不明ではあるが…。

どう解決したのか

色々調べていると、どうやら The Dolby MP4 streaming muxer (dlb_mp4base) であれば、--mpeg4-brand で Major Brand を、--mpeg4-comp-brand で Compatible Brands を、それぞれ任意の値に設定することができるらしいという情報を得た。

dlb_mp4base は Dolby 公式ツールであるため、dby1 にも対応しているし、Dolby AC-4 や Dolby Vision の mux もできるときた。これならもしかすると何とかできるかもしれない。

せっかくなので、一括変換するバッチファイルを作成した。以下は、既に FFmpeg で mux した MP4 を Dolby Atmos として読み込ませるべく、カレントディレクトリ内の MP4 ファイルをすべて FFmpeg で demux し、dlb_mp4base で remux している。(dlb_mp4base は直接 MP4 を読み込むことができない)

FFmpeg (ffmpeg.exe) と dlb_mp4base (mp4muxer.exe) の PATH は既に通している、あるいはカレントディレクトリに置いてあるものとする。なお、dlb_mp4base はファイル名に日本語などが含まれていると処理できないので、そういった場合は予めリネームしておく、あるいはバッチファイル中でリネームする必要がある。

@echo off

rem 作業用フォルダ兼出力先フォルダとして、
rem dlb_mp4base フォルダを作成
md dlb_mp4base

for %%f in (*.mp4) do (

    rem 今回作業した映像のコーデックは全て MPEG-4 AVC / H.264 のため、
    rem 拡張子 .264 で出力
    ffmpeg -i "%%f" -c:v copy -an "dlb_mp4base\%%f.264"

    rem dlb_mp4base は DD+ / E-AC-3 音声の拡張子が .ec3 でないと認識しないが、
    rem FFmpeg は .ec3 では出せないので、一旦 .eac3 で出力
    ffmpeg -i "%%f" -c:a copy -vn "dlb_mp4base\%%f.eac3"

    rem DD+ / E-AC-3 音声の拡張子を .ec3 へ変更
    ren "dlb_mp4base\%%f.eac3" "*.ec3"

    rem demux した映像と音声を dlb_mp4base に入力し、Compatible Brands を mp42、iso6、isom、dby1 とした上で、MP4 に mux
    mp4muxer -i "dlb_mp4base\%%f.264" -i "dlb_mp4base\%%f.ec3" -o "dlb_mp4base\%%f" --mpeg4-comp-brand mp42,iso6,isom,dby1

    rem 一時ファイルを削除
    del "dlb_mp4base\%%f.264"
    del "dlb_mp4base\%%f.ec3"

)

なお、Compatible Brands に関しては、ヘルプ (mp4muxer -h で表示される他、GitHub 上の ソースコードからも読むことができる) によると、msdh も入れることが推奨されている。

mp4muxer usage examples:

To create an audio-only .mp4 file with EC-3 audio:
mp4muxer -o output.mp4 -i audio.ec3 –mpeg4-comp-brand mp42,iso6,isom,msdh,dby1

To multiplex AC-4 audio and H.264 video:
mp4muxer -o output.mp4 -i audio.ac4 -i video.h264 –mpeg4-comp-brand mp42,iso6,isom,msdh,dby1

dlb_mp4base

しかし、 msdh は MPEG-DASH 用の Brand で、今回はローカル再生したいだけなので、不必要と判断し省いている。

code: msdh
description: Media Segment conforming to the general format type for ISO base media file format.
specification: DASH

The ‘MP4’ Registration Authority

--mpeg4-brand を指定しない場合は (Compatible Brands に mp42 を入れなくとも) Major Brand は mp42 になる。

なお、今回は元のファイルは拡張子が .mp4 のため 出力ファイル名を %%f としても問題ないが、元が MKV や TS 等の場合は %%f.mp4 とする必要がある。その場合ファイル名が hoge.mkv.mp4 などとなってしまうので、気になる場合は ren コマンドで適宜修正すればよい。


これを行うことで、AQUOS / arrows や iPhone / iPad にて MP4 内の Dolby Digital Plus を Dolby Atmos として扱うことができるようになった。

また、Dolby Stream Validator のチェックもパスできるようになった。

なお、一部のファイルでは

ERROR: For [EC3] stream, the bitstream fails the validation in "DDPInfoLib". 
validation result: FAILED

というエラーが出てしまうが、DDPInfoLib について検索しても、見事に何の情報もない。(今検索するとこの記事だけがヒットするようになっているはず)

とりあえず再生する分には問題がなかったし、ZTE の AXON 7 に元から入っている Leaf トレーラーを何もいじらずそのまま検証かけてもこのエラーが出たりもしたため (AmazeHorizon は問題なし)、とりあえずこのままで行こうと思う。

余談その1: Amazon Music や Apple Music ではどうしているのか

別記事で解析の際取得した、Amazon Music や Apple Music の Dolby Atmos 音源の入った MP4 ファイルではどうなっているのかを確認してみる。

まずは Amazon Music。Amazon Music は Dolby Atmos のフォーマットとしては、Echo Studio やサウンドバー向けには E-AC-3 JOC を、スマホやタブレット向けには AC-4 IMS を使用しているが、MP4 コンテナのメタデータは共通で以下の通りだった。

major_brand     : mp41
minor_version   : 0
compatible_brands: iso8isommp41dashcmfc

Amazon Music は iso8、isom、mp41、dash、cmfc となっている (それぞれの詳細は こちら )。dby1 も mp42 もないが、これでも Dolby Stream Validator には怒られていない。とはいえ Amazon Music はアプリ内でソフトウェアでコードを行っているため、本件のような問題は起きない。

一方端末側の E-AC-3 JOC デコーダーを使用する Apple Music ではどうか。

major_brand     : iso5
minor_version   : 1
compatible_brands: isomiso5hlsfcmfcccea

Apple Music は isom、iso5、hlsf、cmfc、ccea となっている。こちらも mp42 も dby1 もないが、Dolby Stream Validator には怒られないし、スマホやタブレットにも Dolby Atmos だと認識される。

ということは、flag_ec3_extension_type_a さえ適切に設定されていれば、Major Brand や Minor Brands は特に関係なかったということである。今までの苦労は何だったのか。

余談その2: Apple と HEVC と Dolby Vision の話

dlb_mp4base では、Dolby Vision の mux をすることもできる。Base Layer (BL) + Reference Processing Unit (RPU) の単層 Dolby Vision はもちろん、そこに Enhancement Layer (EL) も加えた2層式の Dolby Vision を扱うことも可能となっている。使い方に関してはプロファイルごとに異なるので、ヘルプを参照してほしい。

(参考) Dolby Vision 対応スマホ / タブレットはこちら:

なお、dlb_mp4base では UHD BD で使用される Dolby Vision Profile 7 (BL が UHD BD の HDR10 互換 (7.6) の2層 12bit Dolby Vision) の mux にも対応しているのだが、Dolby Stream Validator に

WARNING: For [DoVi] stream, in MP4, the profile 7 is not supported.

と怒られてしまう (エラーではなく警告ではあるが)。

端末が対応していないプロファイルの Dolby Vision を扱う際や、そもそも Dolby Vision 非対応な機器で再生する場合は、2層の Dolby Vision であれば映像の Base Layer のみと音声 (+必要に応じて字幕なども) を demux し、MP4 に mux したほうがファイルサイズは少なく済む。Dolby Vision のプロファイルについて 詳細はこちら

参考までに、iPhone / iPad が対応している Dolby Vision のプロファイルを載せておく (ソース)。

  • Profile 5: BL + RPU で 10bit。BL は独自の IPT 色空間を使用しており、非対応機器との互換性なし (5.0)。Apple TV+ 等で仕様。
  • Profile 8: BL + RPU で 10bit。BL は HDR10 互換のもの (8.1) と SDR 互換のもの (8.2) と HLG 互換のもの (8.4) とがある。うち iPhone / iPad が対応しているのは、HLG ベースの Profile 8.4 のみ。Profile 8.4 は、iPhone のカメラの Dolby Vision 撮影で使用。

AQUOS (R2 / R2 compact / R3 / R5G / R6、zero / zero2) が対応している Dolby Vision は以下の通り (ソース)。

  • Profile 4: BL + RPU で 10bit。BL は SDR 互換 (4.2)。用途不明。
  • Profile 5: 先述の通り。
  • Profile 8: 仕様は先述の通り。AQUOS が 8.1、8.2、8.4のどれに対応しているのかまでは不明。
  • Profile 9: BL + RPU で8bit。BL は SDR 互換 (9.2)。用途不明。

なお、dlb_mp4base で MPEG-H HEVC (H.265) を mux した場合、映像の Codec ID (FourCC) は強制的に hev1 (非 Dolby Vision) か dvhe (Dolby Vision) になるのだが、iPhone / iPad は hvc1 (非 Dolby Vision) か dvh1 (Dolby Vision) の HEVC しか対応していない (再生方法によっては再生できる場合もあるが、推奨されていない)。

FFmpeg であれば -tag:v hvc1 で hvc1 を指定することもできるのだが、hev1 や hvc1 は MP4 などのコンテナフォーマット用のメタデータであり、FFmpeg で demux する際に -c:v copy -tag:v hvc1 hoge.265 などをしても意味はない。

SDR であれば AVC にでも変換すればいいが、HDR の AVC となると Dolby Vision の Profile 0.2 (今は使われない)、Profile 1 (今は使われない) 、Profile 9.2 といった、いずれも FFmpeg 等では変換できない上に、そもそも iPhone / iPad が非対応なフォーマットぐらいしかない。

なので、現状 HDR な HEVC と Dolby Atmos な Dolby Digital Plus / Dolby AC-4 の組み合わせをうまく iPhone / iPad で再生する手段はない。困った。


井戸水

ガジェットやオーディオビジュアルが好きな人。モバイル機器における空間オーディオなどを調査しています。

コメントを残す…