ffmpeg でデバイス(やプラットホーム)のご機嫌を取らねばならんとき

「正しくてわかりやすい情報」に仕立て上げる気がない「場当たり的」な情報としてしか書かないので、正確な情報が欲しい人はほかをあたってくたされ。

たとえば「あたいはべっつにこーがしつだとか 2K、4K にたいするこだわりなんかないんだもんね」だとしても、だ。デバイス、例えばワタシの場合は DIGA、あるいはプラットホーム、たとえば YouTube やニコニコだね、こうした「相手」が、「HD じゃなきゃ受け付けないもんね!」みたいな制約を持っていることがあるわけだ。こういうのはどうしたって避けられない。歴史的に仕様があれこれ発散してきたなかで、製品としては「なんでも扱えます」てのは至極リスキーなのであって、「扱えるものだけ扱えます」てのは商売としてはもちろん正しい。

この「制約」が明示されてることもあるし、ほかの制約起因で「暗黙の制約」になってることもあるのだろうが、とにかくワタシの DIGA が、ある特定のパターンで「取り込めるがプレビュー出来ない」ものがあることに気付いた。

こういう動画があることは結構前に気付いてはいたんだけれど、さっきやっと(場当たり的な)「解決方法」を見つけた。

一応取説にはこう書いてあるのだよね:

  • ビデオ圧縮方式:
    • MPEG-4 AVC/H.264: High profile 4.2 以下
    • 解像度 1920×1080 まで
  • 音声圧縮方式:
    • MPEG-4 AAC-LC
      • サンプリング周波数: 8kHz ~ 48kHz
      • チャンネル数 1 または 2
      • 音声の内容によっては、映像のみ再生し、音声が出力できない場合があります

どこかに書かれているわけではないのでわからないけれど、DIGA の中身はおそらく android とかあるいは何か linux/BSD 派生の組み込み系 OS で、きっとそれこそ ffmpeg が中で動いてるんだろうと想像している。なのでなにゆえにこの種の制約が生じるのかかえって不思議にも思うのだが、最初の想像の通り「なんでも出来ます、とは言わない」という戦略なのであろう。(ちなみにもうひとつ、「著作権保護」の観点からの制約もある。持ち出しを高画質のまま取り出せないようになっているのはこれは「出来ないから」ではなく「させてはならない」から。)

で、その事象が発生するヤツとしないヤツを比較すると気付くのはこれなのである:

 1 [me@host: ~] $ ffprobe 1.mp4 2>&1 | grep -v configuration
 2 ffprobe version N-91245-g550372d0c4 Copyright (c) 2007-2018 the FFmpeg developers
 3   built with gcc 7.3.0 (GCC)
 4   libavutil      56. 18.102 / 56. 18.102
 5   libavcodec     58. 19.105 / 58. 19.105
 6   libavformat    58. 17.100 / 58. 17.100
 7   libavdevice    58.  4.100 / 58.  4.100
 8   libavfilter     7. 25.100 /  7. 25.100
 9   libswscale      5.  2.100 /  5.  2.100
10   libswresample   3.  2.100 /  3.  2.100
11   libpostproc    55.  2.100 / 55.  2.100
12 Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '1.mp4':
13   Metadata:
14     major_brand     : isom
15     minor_version   : 512
16     compatible_brands: isomiso2avc1mp41
17     encoder         : Lavf56.40.101
18   Duration: 00:09:21.11, start: 0.000000, bitrate: 1724 kb/s
19     Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709), 1920x1080 [SAR 1:1 DAR 16:9], 1588 kb/s, 29.97 fps, 29.97 tbr, 30k tbn, 59.94 tbc (default)
20     Metadata:
21       handler_name    : VideoHandler
22     Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 128 kb/s (default)
23     Metadata:
24       handler_name    : SoundHandler
25 
26 [me@host: ~] $ ffprobe 4.mp4 2>&1 | grep -v configuration
27 ffprobe version N-91245-g550372d0c4 Copyright (c) 2007-2018 the FFmpeg developers
28   built with gcc 7.3.0 (GCC)
29   libavutil      56. 18.102 / 56. 18.102
30   libavcodec     58. 19.105 / 58. 19.105
31   libavformat    58. 17.100 / 58. 17.100
32   libavdevice    58.  4.100 / 58.  4.100
33   libavfilter     7. 25.100 /  7. 25.100
34   libswscale      5.  2.100 /  5.  2.100
35   libswresample   3.  2.100 /  3.  2.100
36   libpostproc    55.  2.100 / 55.  2.100
37 Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '4.mp4':
38   Metadata:
39     major_brand     : isom
40     minor_version   : 512
41     compatible_brands: isomiso2avc1mp41
42     encoder         : Lavf58.17.100
43   Duration: 00:08:27.61, start: 0.000000, bitrate: 4074 kb/s
44     Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 1920x1080 [SAR 1:1 DAR 16:9], 3938 kb/s, 29.97 fps, 29.97 tbr, 30k tbn, 59.94 tbc (default)
45     Metadata:
46       handler_name    : VideoHandler
47     Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 128 kb/s (default)
48     Metadata:
49       handler_name    : SoundHandler

2つ目のヤツが DIGA で「選んで取り込み」UI でプレビュー出来ない。取り込めるならいいじゃないか、という考えもあるかもしれないけれども、本当に全然扱えないものとの区別がつかないのもやだし、そもそも「選んで取り込み」UI がファイル名の情報等々「ありとあらゆる情報」を失ってしまうので、プレビュー(と duration と「ファイルの更新時刻」)しか「おぬしはなにものか」を知る術がないのもね、癇癪の種になるわけだよ。

「(tv, bt709)の有無の差なのか? かもしれんなぁ」と思い、(tv, bt709) に変換する方法、というキーワードで検索するも、そのものズバリは見つからず。いくつか見つけたものを試してみた結果としては この StackExchange の解だけがワタシの場合は唯一の正解だった:

 1 [me@host: ~]$ ffmpeg -y -i 4.mp4 -color_primaries bt709 -color_trc bt709 -colorspace bt709 4_c.mp4
 2     ...
 3 [me@host: ~]$ fprobe 4_c.mp4
 4 ffprobe version N-91245-g550372d0c4 Copyright (c) 2007-2018 the FFmpeg developers
 5   built with gcc 7.3.0 (GCC)
 6   libavutil      56. 18.102 / 56. 18.102
 7   libavcodec     58. 19.105 / 58. 19.105
 8   libavformat    58. 17.100 / 58. 17.100
 9   libavdevice    58.  4.100 / 58.  4.100
10   libavfilter     7. 25.100 /  7. 25.100
11   libswscale      5.  2.100 /  5.  2.100
12   libswresample   3.  2.100 /  3.  2.100
13   libpostproc    55.  2.100 / 55.  2.100
14 Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '4_c.mp4':
15   Metadata:
16     major_brand     : isom
17     minor_version   : 512
18     compatible_brands: isomiso2avc1mp41
19     encoder         : Lavf58.17.100
20   Duration: 00:08:27.61, start: 0.000000, bitrate: 3599 kb/s
21     Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709), 1920x1080 [SAR 1:1 DAR 16:9], 3463 kb/s, 29.97 fps, 29.97 tbr, 30k tbn, 59.94 tbc (default)
22     Metadata:
23       handler_name    : VideoHandler
24     Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 128 kb/s (default)
25     Metadata:
26       handler_name    : SoundHandler

変換後のこれは DIGA のプレビューでもちゃんと再生できて、もちろん取り込んで問題なかった。

ワタシのように「このての扱いのあまちゅあ」にとっては「BT709 ってなんやねん」てなことである。実際こういう情報ははっきりいって「詳しい人が詳しい人に説明するもの」になってて、何言われてるかワタシにはさっぱりわからない。StackExchange の質問内容からどうやら BT709 だの BT609 てのが一般人でも認識している「High Definition (HD)」「Standard Definition (SD)」に関係しているんだな、てことがかろうじて推察出来る程度。

わからないからさぁ、このワタシにとっての不正解のどこが間違いなのかは当然説明出来ないんだよね。やってることが違うことはわかるけれど、out_color_matrix だけでなぜ用を足せないのか、全然わからない。


2019-02-21追記:
最近気付いたことを一応書いとく。

「結構 YUV420p しか扱えないものが多いなか、最近はかなり YUV444p も転がってて簡単に手に入る」。CC0 (パブリックドメイン相当)の動画欲しさに Pexels なんぞに行ってダウンロードしてくると、結構 YUV444p のものがある。

420 と 444 については単純な古い新しいの関係ではなくて、「輝度と色差に対する人間の感度の差」を利用して色差成分を小さくするのが 420 なんだけれど、つまりは「そうしない」444 は発想も方式も当然最初からあったわけ。つまり「そうしなくても」あるいは「そうしたくないので」が「許容される」ならば、「そりゃ情報量を削らない方が美しい」んだもん、「高画質用途」に 444 を採用するのは自然な流れ。すなわち、「許される率が高くなってくれば」444 が増えていく、てことね。なので関係としては「昔ほど 420 ばかりで、だんだん 444 が増えてくる」ということ。

なので、古い機器だと「YUV444p を扱えない」ことが多い、てことね。この場合、ffmpeg では「format=yuv420p」などね。(ちなみにワタシの DIGA の場合は「YUV444p」を扱えない、というよりは、フォーマットを正しく参照してなくて、映像が壊れる。)