2017-02-03 13 views
3

私のテストプログラムはffmpegの出力を定期的なチャンクで受け取るように見えるので、Perlプログラムでffmpegの出力を処理しようとしています。バッファリングが続行されます。それをリアルタイムで処理させるにはどうしたらいいですか?perlバッファリングffmpegの出力を停止する方法

私のテストプログラム(私は多分ffmpegののキャリッジリターンはperlが一つの大きな長い行か何かを見ることが原因と思っていたので、trコマンドがあります):私はffmpegコマンドを交換する際に

#!/usr/bin/perl 

$i = "test.mkv"; # big file, long encode time 
$o = "test.mp4"; 

open(F, "-|", "ffmpeg -y -i '$i' '$o' 2>&1 | tr '\r' '\n'") 
     or die "oh no"; 

while(<F>) { 
     print "A12345: $_"; # some random text so i know the output was processed in perl 
} 

すべてが正常に動作しますこのスクリプト:

#!/bin/bash 

echo "hello"; 

for i in `seq 1 10`; do 
     sleep 1; 
     echo "hello $i"; 
done 

echo "bye"; 

上記のスクリプトを使用すると、毎秒出力が表示されます。 ffmpegの場合、出力するまでには5〜10秒程度かかりますが、出力ごとに100行も出力されることがあります。

コマンドコールでffmpegより先にunbufferプログラムを使用しようとしましたが、効果がないようです。バッファリングしている可能性があります2>&1ですか? 何か助けていただければ幸いです。

あなたはffmpegのの出力に慣れていない場合、それはSTDOUTにファイル情報や原料の束を出力し、エンコード時に、それは、キャリッジで始まる

frame= 332 fps= 93 q=28.0 size=  528kB time=00:00:13.33 bitrate= 324.2kbits/s speed=3.75x 

のような行を出力は、したがって、(代わりに新しい行を返しますtr )をSTDERR(したがって2>&1)に設定します。

+0

を@Borodinに行く必要がありますF、 ' - |:unix'、 "ffmpeg ......") ' –

+0

@ChankeyPathak私はunixを追加しようとしましたが、残念なことに違いはありません。 –

+0

@SebastianKing: '2>&1'は何をするのですか?どうしてそこに置いたのですか? – Borodin

答えて

1

問題はtrが出力をバッファリングされたということでした、とunbufferが適用されていましたコマンドの冒頭にあるffmpegにのみ送信されます。つまり、unbufferはperlにパイプに影響を与えることができませんでした。

unbuffer -pは、パイプコマンドのバッファを解除するためのものです(<cmd1> | unbuffer -p <cmd2>アンバッファーの両方がcmd1cmd2)。

しかし、私はまた、stdbufを標準として来るとき、それは大規模かつ不必要なパッケージであるため、expectパッケージの依存を取り除くためにstdbuf -i0 -o0 -eLunbufferを置き換えます。また、-eLオプションでは、stdbufという行をバッファにしているので、バッファをまったく持っていない場合よりCPUを効率的にする必要があります。完全に動作するコードは以下の通りです:

#!/usr/bin/perl 

$i = "test.mkv"; # big file, long encode time 
$o = "test.mp4"; 

open(F, "-|", "ffmpeg -y -i '$i' '$o' 2>&1 | stdbuf -i0 -o0 -eL tr '\r' '\n'") 
     or die "oh no"; 

while(<F>) { 
     print "A12345: $_"; # some random text so i know the output was processed in perl 
} 

この質問はコメントで答えたし、何の正解が掲載されなかった、私はこのwikiの答え作られておりますので、クレジットは(オープン `てみ

+1

ありがとうございます。私は解決策を書くことを意図しましたが、これは私が書いたよりもずっと便利です。あなたは質問を閉じてマークできるようになるとすぐに回答を受け入れるべきです。 – Borodin

0

まず、出力バッファリングは、出力を行うものによって実行されるものです。

ほとんどのプログラムは、端末に接続されていない限り出力をバッファします。したがって、バッファリングを無効にするオプションを提供する非常に少数のプログラムがない限り、代わりに擬似ttyを使用してそれらをだますだけですパイプのこれはunbufferの機能です。

この場合の問題は、出力バッファリングを行うプログラムが2つあることです。ffmpegtrです。バッファリングを避けるために両方を納得させる必要があります。それぞれunbufferを使用する必要があります。うまくいけば、それは彼らを納得させないように説得するでしょう。

残念ながら、... | unbuffer ...は機能しません。 (理由は分かりません)<>の代わりにsysreadを使ってtrを取り除いてください。もちろん

my $buf = ''; 
while (1) { 
    my $rv = sysread($PIPE, $buf, 64*1024, length($buf)); 
    die $! if !defined($rv); 
    last if !$rv; 

    while ($buf =~ s/^([^\r\n]*)[\r\n]//) { 
     my $line = $1; 
     print("[$line]\n"); 
    } 
} 

print("[$buf]\n") if $buf ne ""; 

、このすべては、unbufferは、おそらくそれに役立つことはありませんので、ffmpegフラッシュは、それがキャリッジリターンを送信した後、バッファだということを前提としています。 (その場合はunbufferは、おそらくすべてで必要とされていないもちろん、。単純sysreadに切り替えてtrを回避することはトリックを行う必要があります。)

+0

'unbuffer ffmpeg -y -i 'を使う$ i" $ o' 2>&1 | unbuffer tr '\ r "' \ n" 'シェルで実行しても出力が得られません。 unbuffer tr '\ r "' \ n"と出力を取得しないで、私は間違って何ですか?エコーコマンドが返されないと、何も出力せずに実行し続けます。 –

+0

確かに。 ( 'echo' hi "| unbuffer perl -pe1'でテストして、' tr'とは何の関係もないことを確認しました。 – ikegami

関連する問題