iOSでCordovaでffmpegを使わずにmp4をmux、demuxする方法


mp4のオーディオを劣化なしで差し替える方法を調べました。
mp4のmux/demuxができればできそうです。
ffmpegでできそうですが、オープンソースではなくLGPLの例外にも当てはまらないケースでやる方法を調べました。iphone/androidアプリを想定しています。
特許は調べられていません。mp4のmux/demuxだけなら問題無いと予想しているのですが、もし知っていたら教えてください。
(aacのエンコードはスコープ外とする)

まとめ

  • Cordovaプラグインをつくった。
  • 機能: mp4のmux/demux
  • 対応プラットフォーム: iOS
  • ライセンス: BSD 3 clause

選択肢

dlb_mp4baseを使う。

demux

dlb_mp4demuxを使う。

ライブラリ詳細

https://github.com/lieff/minimp4

mp4をmux,demuxするライブラリ。
ライセンスCC0。
demuxerがうまく機能しない。
muxerは機能する(サンプルでハードコードされているFPSやtime scaleは調整する必要あり)。
しかし、muxerのサンプルはpcmからaacエンコードしてmuxするサンプルなので、aacを直接やる方法は少し調べないとわからない。

https://github.com/DolbyLaboratories/dlb_mp4demux

mp4をdemuxするライブラリ。
ライセンス BSD 3-Clause License
demuxerが機能する。

https://github.com/DolbyLaboratories/dlb_mp4base

mp4をmuxするライブラリ。
ライセンス BSD 3-Clause License
muxが機能する。

https://github.com/DigiDNA/ISOBMFF

mp4をパースするライブラリ。
ライセンスMIT
これを使ったdemuxの実装方法は少し調べないとわからない。

その他の手法との関係

ios AVAssetExportSession

あまり調べていませんが多分再エンコードされるので無劣化にならなそうです。

ffmpeg

https://github.com/tanersener/mobile-ffmpeg
LGPL

LGPLとiosアプリについて
https://blog.tai2.net/lgpl_and_appstore.html

cordovaプラグイン

雑ですが作りました。
https://github.com/contribu/mp4muxdemux

問題

dlb_mp4baseで作ったmp4をsafariブラウザやmacやiphoneで再生できません。
ffprobeで確認すると、video, audio trackがどちらもdefaultになっていません。
mp4boxで確認すると、Track is disabledになっています。
mp4boxでenableにしたら再生できました。

dlb_mp4baseで出力されるmp4のトラックをenableにする方法を調べます。

まず、mp4boxは以下の箇所でtrack is disabledを出力する。
https://github.com/gpac/gpac/blob/14352eb2a5fde3b2ed380865bdfdd4bb915e1902/applications/mp4box/filedump.c#L2299

gf_isom_is_track_enabledは、トラックのヘッダーの1ビット目が立っているとtrue
https://github.com/gpac/gpac/blob/2c65e5604b469d4a4e1a1dc0c6cbe351f2d39a17/src/isomedia/isom_read.c#L856

dlb_mp4baseでトラックのヘッダーはいつ書き込まれるか?
勘だがここ
https://github.com/DolbyLaboratories/dlb_mp4base/blob/ad46704703d2f558a61c2dba444ae43a8e3effff/src/mp4_muxer.c#L7003

しかし、現状はこのフラグが使われていない。

おそらく、オプションを追加してここで渡してあげれば良さそう。
https://github.com/DolbyLaboratories/dlb_mp4base/blob/98fc2f52f318f41eeedcfc44bc2f430d7ca4eabd/frontend/mp4_muxer_app.c#L260

ema_mp4_mux_set_inputの中で
usr_cfg_es->force_tkhd_flags = 1;
を行ったら、safariやmacで再生可能なmp4ができました。

修正版リポジトリ
https://github.com/contribu/dlb_mp4base/compare/master...feature/enable_track?w=1

こういう調査は楽しいですが、
mp4boxを最初に見つけていれば時間を浪費しなくてすんだかもしれません

問題2

stdio.hで定義されたP_tmpdirというものが使われていて、
P_tmpdirはiosでは/var/tmpになっている。
dlb_mp4baseは処理の一時ファイルをここに書き込もうとするので
iphone simulatorでは動くが、iphoneでは動かない。

TMPDIR環境変数を使えばOK

iosでのTMPDIR環境変数
https://chaosinmotion.blog/2012/03/26/how-do-i-know-what-environment-variables-are-on-ios/

問題3

iphoneで撮影した動画をdemuxするとファイルが出力されない問題。

修正差分
https://github.com/contribu/mp4muxdemux/blob/master/src/common/demuxer.c#L320

問題4

iphoneで撮影した動画をdemux -> muxすると90度回転する問題。

iphoneで撮影したものの

mvhd
{ a = 65536, b = 0, u = 0, c = 0, d = 65536, v = 0, x = 0, y = 0, w = 1073741824 }

tkhd
{ a = 0, b = 65536, u = 0, c = 4294901760, d = 0, v = 0, x = 70778880, y = 0, w = 1073741824 }

demux -> muxしたものの

mvhd
{ a = 65536, b = 0, u = 0, c = 0, d = 65536, v = 0, x = 0, y = 0, w = 1073741824 }

tkhd
{ a = 65536, b = 0, u = 0, c = 0, d = 65536, v = 0, x = 0, y = 0, w = 1073741824 }

おそらくmatrixを受け継げば良さそう。
chromeでだめだみたいな情報があったが、試したら、iphone動画はちゃんと表示される。多分古い情報。

参考情報
https://developer.apple.com/standards/qtff-2001.pdf

cordovaプラグインに実装DONE

問題4.1

mux後のファイルで、preferredtransformが少しだけ小さい値(1のはずが0.98など)を返す。

原因は不明。mp4のmatrixやwidth,heightは正しい値になっているので、おそらくpreferredtransformが悪い。

matrix引き継ぎの元データをpreferredtransformから取得すると問題がありそうなので、demuxerを改造して、tkhdをjsonで出力するようにした。

-> 再現しなくなったので誤認の可能性あり

objective-cで以下のコードを使ったせいかも

[track preferredtransform].a

いつもC++だから意識してない。もしそうだとしたら警告出して欲しい。
https://srad.jp/~Yak!/journal/533577/

↑要検証

代替案

libmp4v2

同じことができるかもしれません

mp4box.js

マジか。こんなのあったのか。最初に見つけていれば・・・
cordovaプラグイン作る必要なかったかもしれません
https://github.com/gpac/mp4box.js