2017年12月12日

ffmpegって名前付きパイプだとうまくいかないのかなぁ…と思いかけた落とし穴にハマる

(1)ネット経由でストリーミング受信した音声ファイル(rtmpdumpでflvを生成)を、(2)ffmpegでm4aに変換し、(3)さらに1.45倍速にしたものもm4aにする自動処理を行っていました。これは、Raspberry PiのLinux上で実施しています。
(Raspberry Piでffmpegを使うには、通常以上の手間が必要になるのですが、それについてはまた今度)

今までは、(1)(2)(3)の処理を逐次行っていたため、処理時間は非常に長かったのですが、

(1)で必要とするCPU利用率は0.2%程度。必要な時間は2時間30分。
(2)で必要とするCPU利用率はほぼ100%。必要な時間は13分。
(3)で必要とするCPU利用率はほぼ100%。必要な時間は13分。

という感じでした。
もし、(1)と並行して、ゆっくりと(2)(3)を行うことができるなら、うしろの26分間をほぼゼロに近づけることができるんじゃないか?と思いまして。

試しに、(1)と(2)を並行で実施することにしてみました。
rtmpdumpは、出力ファイル名を指定しなければ(-o ファイル名 を付けない)、ファイルの内容は標準出力に出力されます。
ffmpeg は -i pipe 0 というオプションを付けると、標準入力から入力を受け付けます。
指定するコマンドはこんな感じ。

$ rtmpdump (様々なオプション) | ffmpeg -i pipe 0 -ab 64k 出力ファイル名.m4a

参考サイト:rtmpdumpとffmpegをつかったライブトランスコーディング - 別館 子子子子子子(ねこのここねこ)

さて、(1)(2)に加え、(3)も並行で実行するにはどうしたらよいか?
パイプを2分岐させれば良いことになります。

rtmpdump→標準出力→標準入力→tee→→→ ファイル 
    └→→標準出力→標準入力→ffmpeg

パイプの2分岐は、teeコマンドを用います。
teeコマンドは、標準入力を、「ファイル」と「標準出力」に2分岐させるためのコマンドです。

このうち「標準出力」は、別のコマンド(今回の場合はffmpeg)の入力にすることができますが、「ファイル」を別のコマンドへの入力にするにはどうしたらよいか?

色々調べたところ、名前付きパイプを使えば良いことが分かりました。
名前付きパイプは、ファイル名を媒介にして、2つのプロセス同士の標準出力と標準入力を繋ぐための方法です。

名前付きパイプはmkfifoコマンドで、あたかもファイルのように作成できます。
以後、そのファイル名へ書き込みをすれば、別のプロセスへの標準入力になるというわけです。
(なお、1つの標準出力を2つのプロセスの標準入力に割り当てることはできません。手元の環境で実験したところ、後から名前付きパイプをオープンしたプロセスに対してのみ、入力が行われました)

mkfifo temp_pipe
ffmpeg -i pipe:0 -ab 64k -af atempo=1.45 出力ファイル名_x145.m4a < temp_pipe &
rtmpdump (様々なオプション) | tee temp_pipe | ffmpeg -i pipe 0 -ab 64k 出力ファイル名.m4a
rm temp_pipe

2行目の最後に & を付けないと、パイプからの入力待ちでブロックされてしまいます。以後のコマンドと並列処理をさせるために & を付けています。

で、これで実行してみると、なんだか上手くいきません。
音楽再生プレイヤーで開くと、「出力ファイル名_x145.m4a」の内容が不正という扱いになります。

色々見直してみましたが、何がおかしいのかよく分からない…。
うーん、名前付きパイプからの入力を、ffmpeg が受け付けられないとか?そんなことはないよなぁ…。

ここで悩むこと5時間。

 :
 :
 :
 :



続きを読む
posted by ayacy at 00:00 | Comment(0) | TrackBack(0) | PC