ffmpeg で、静止画 scroll, roll な動画

相変わらず疲れりる。

ffmpeg で、静止画 scroll, roll な動画

なんのことやら

あるでしょ、こういう「見せる/見る」のに「適さない」静止画:
large_img
こうやってブログに貼り付けるぶんにはブラウザのスクロールがあるからいいけれど、この一枚絵をダウンロードしてビューワで見ようと思うと、なかなかストレスがたまる、みたいな。

こういうことがしたいわけよね:

てのは前々からやりたいと思っていたことなわけよ。特にワタシは地図とか大好きなので、「地図めぐり動画」なんかまさにやりたいこと。なのだけれど、一つ前の投稿からの流れで、roll な動画も作りたくなった。roll は NumPy ndarray の roll みたいなのね。要するに「グルグル回したい」みたいな。スロットゲームでスロットがぐるぐる回ってるのをイメージして欲しい。そんなの。

そのものズバリの解はなくて

公式の filter のドキュメントを探してみるも、そもそも非常に使いにくいドキュメントであることも手伝って、ともあれ「見つからない」。これはきっとワタシが怠慢で阿呆で節穴だからだ…。

てことではなくて、やむなくググってみたら、どうやらこんな方法しかないらしい

これ、何を考えて何をしてるかと言うと:

  1. そのものズバリはない。
  2. 「ビューポート」に相当することが考えられればいい。
  3. フィルタたちのうち、時間経過に関与出来るものを使えばいいぢゃないか。
  4. そうか、overlay は時間経過に関与出来て、「ビューポート」相当の発想に使えるぢゃぁないか。

非常にまわりくどいアプローチにはなるのだけれど、これしかないということならこれしかないのであろう。

当然のことながら「overlay」の名が意味する通り、「overlay されるもと」(bottom layer)が必要、てこと。だからやりたいことから考えれば滅茶苦茶ばかばかしい。ともあれ、上にあげた動画はこんな風に作った:

 1 #! /bin/sh
 2 
 3 #
 4 # large_img.png: 1020x2100
 5 # destination movie -> 1020x720
 6 #
 7 "/c/Program Files/ffmpeg-3.3.2-win64-shared/bin/ffmpeg" -y \
 8   -i large_img.png \
 9   -filter_complex "
10 color=s=1020x720:d=10[bg];
11 [0:v]loop=loop=-1:size=2[fg];
12 [bg][fg]overlay=y=-'t*h*0.1':shortest=1[v]
13 " -map '[v]' scrolled.mp4
14 
15 # NOTE(1): ffmpeg 4.1 の Windows バイナリ(Shared) がクラッシュすることを確認している。
16 #          ゆえ、やむなく 3.3.2 でやっている。
17 # NOTE(2): loop=loop=-1:size=2 の「size=2」については一つ前の投稿参照。

roll は scroll の応用だべな、きっと

scroll な解法にたどり着く前は crop と hstack/vstack、してこれを concat…という愚直なやりかたしかなかろうなぁ、と考えていたが、scroll な解法にたどり着いた今なら、所詮はこれの応用だろう、と考えてみるなら考えて見れるだろうか。

こんなだね:

 1 #! /bin/sh
 2 
 3 #
 4 # img_charabg04.png: 293x1163
 5 #
 6 "/c/Program Files/ffmpeg-3.3.2-win64-shared/bin/ffmpeg" \
 7   -y \
 8   -i img_charabg04.png \
 9   -filter_complex "
10 color=s=293x1163:d=10[bg];
11 [0:v]loop=loop=-1:size=2[fg1];
12 [0:v]loop=loop=-1:size=2[fg2];
13 [bg][fg1]overlay=y=-'t*h*0.1':shortest=1[v1];
14 [v1][fg2]overlay=y=H-'t*h*0.1':shortest=1[v]
15 " -map '[v]' rolled.mp4
16 # scroll のほうで説明しなかったが y= の中に書いている expression 内の
17 # t やら h やら H は https://ffmpeg.org/ffmpeg-filters.html#overlay-1 で
18 # 「The x, and y expressions can contain the following parameters.」と
19 # して説明されてる。

実は一発で思ったとおりになって自分でビックリしたのは内緒である。

06:40 追記: 逆方向

y 方向でなく x 方向に、なら書くまでもないこと、それはいいよね? で、「所詮逆向き」についても「書くまでもないこと」と思ってたがそうでもなかったので。

単に思いつけなかっただけなのか、アプローチの原理上不可能なのか、どちらなのか断言は出来ないんだけれど、なんとなく直感的には後者なんじゃないかという気がしてる。気がしてる、なんていい方をしなければならんのは、結局のところは上でうまくいってるコードを「ちゃんと」理解しきれていないから。

ともあれワタシは「逆方向」の「素直な」コードを編み出せなかった。ゆえ、まずは「最後の手段」:

 1 #! /bin/sh
 2 
 3 #
 4 # img_charabg02.png: 293x1163
 5 #
 6 "/c/Program Files/ffmpeg-3.3.2-win64-shared/bin/ffmpeg" \
 7   -y \
 8   -i img_charabg02.png \
 9   -filter_complex "
10 color=s=293x1163:d=10[bg];
11 [0:v]loop=loop=-1:size=2[fg1];
12 [0:v]loop=loop=-1:size=2[fg2];
13 [bg][fg1]overlay=y=-'t*h*0.1':shortest=1[v1];
14 [v1][fg2]overlay=y=H-'t*h*0.1':shortest=1[v]
15 " -map '[v]' /tmp/hoge.mp4
16 
17 # reverse フィルタで…
18 ffmpeg -y -i /tmp/hoge.mp4 -vf 'reverse' rolled_img_charabg02_rev.mp4

「最後の手段」というだけあって、アプローチとしては「最悪最凶」の部類。無論「逆再生」している。公式ドキュメントが警告する通り、というか「reverse」と名のつく処理はいつだってそうだが、「メモリを大量に必要とする(かもしれない)」てことだ。とはいえね、こういうことをしたい場合にさ、「とてつもなく大きな動画をスクロールさせるのだっ」なんてことを、まぁ普通はせんわな。なので「今の場合はこれだって別に悪かぁない」。

では「最悪最凶」以外のマシな手はあるか? ある。結構このシチュエーションと解、よく使うんじゃないかしらね。例えば「ペイント」とかのお絵かきソフトでね、「左端を切り取りたい」なんてとき、一番楽な方法は? そう、「flip horizontal」してからキャンバスサイズを削って、「flip horizontal」し直す。右端を削る方が簡単だろ、てことだ。これとまったく同じことをすればいい:

 1 #! /bin/sh
 2 
 3 "/c/Program Files/ffmpeg-3.3.2-win64-shared/bin/ffmpeg" \
 4   -y \
 5   -i img_charabg02.png \
 6   -filter_complex "
 7 color=s=293x1163:d=10[bg];
 8 [0:v]vflip,loop=loop=-1:size=2[fg1];
 9 [0:v]vflip,loop=loop=-1:size=2[fg2];
10 [bg][fg1]overlay=y=-'t*h*0.1':shortest=1[v1];
11 [v1][fg2]overlay=y=H-'t*h*0.1':shortest=1,vflip[v]
12 " -map '[v]' rolled_img_charabg02_rev.mp4
13 
14 # vflip で上下逆さまにしとるわけな。

2019-01-26 追記: Youtube に整理した動画あげた