9

私はJavaでffmpegのプログレスバーを作成する作業をしています。そのためには、コマンドを実行してから、すべての進行状況を読み取る必要があります。

String[] command = {"gnome-terminal", "-x", "/bin/sh", "-c","ffmpeg -i /home/tmp/F.webm /home/tmp/converted1.mp4"};

Process process = Runtime.getRuntime().exec(command);

これは完全に実行されます。ただし、プログレスバーを作成するには、すべての進行状況をキャプチャする必要があります。では、どうすればJavaからそのデータを読み取ることができますか?

4

3 に答える 3

21

これがあなたが始めるべきあなたのための完全な例です

import java.io.*;
import java.util.Scanner;
import java.util.regex.Pattern;

class Test {
  public static void main(String[] args) throws IOException {
    ProcessBuilder pb = new ProcessBuilder("ffmpeg","-i","in.webm","out.mp4");
    final Process p = pb.start();

    new Thread() {
      public void run() {

        Scanner sc = new Scanner(p.getErrorStream());

        // Find duration
        Pattern durPattern = Pattern.compile("(?<=Duration: )[^,]*");
        String dur = sc.findWithinHorizon(durPattern, 0);
        if (dur == null)
          throw new RuntimeException("Could not parse duration.");
        String[] hms = dur.split(":");
        double totalSecs = Integer.parseInt(hms[0]) * 3600
                         + Integer.parseInt(hms[1]) *   60
                         + Double.parseDouble(hms[2]);
        System.out.println("Total duration: " + totalSecs + " seconds.");

        // Find time as long as possible.
        Pattern timePattern = Pattern.compile("(?<=time=)[\\d.]*");
        String match;
        while (null != (match = sc.findWithinHorizon(timePattern, 0))) {
          double progress = Double.parseDouble(match) / totalSecs;
          System.out.printf("Progress: %.2f%%%n", progress * 100);
        }
      }
    }.start();

  }
}

出力:

Total duration: 117.7 seconds.
Progress: 7.71%
Progress: 16.40%
Progress: 25.00%
Progress: 33.16%
Progress: 42.67%
Progress: 51.35%
Progress: 60.57%
Progress: 69.07%
Progress: 78.02%
Progress: 86.49%
Progress: 95.94%
Progress: 99.97%

また、 jjmpegなどのffmpegに何らかのJavaバインディングを使用することを検討することもできます。これにより、より堅牢な方法で必要なものが提供される場合があります。

編集

ffmpeg 2.0では、時間出力が必要になるHH:mm:ss.Sため、timePattern:

Pattern timePattern = Pattern.compile("(?<=time=)[\\d:.]*");

さらに、を分割して合計durする必要があります:

String[] matchSplit;
while (null != (match = sc.findWithinHorizon(timePattern, 0))) {
    matchSplit = match.split(":")
    double progress = Integer.parseInt(matchSplit[0]) * 3600 +
        Integer.parseInt(matchSplit[1]) * 60 +
        Double.parseDouble(matchSplit[2]) / totalSecs;
//...
于 2012-06-07T08:22:17.380 に答える
1

出力の解析を試みてffmpeg、何とかしてすでに行われている作業を理解することができます。しかし、これは難しく、とにかく安定していません。私たち(ffmpegユーザー)もffmpeg自体も、処理にかかる時間を知りませんし、時間の観点からも知ることができません。

私の経験によると、最も簡単な方法は、一種のヒューリスティックを実装することです。処理時間はファイルサイズに直線的に依存すると仮定します。このアプローチは「間違っています」が、十分に優れており、非常に単純です。次に、サイズの異なる複数のファイルを使用して、実際に使用しているのとまったく同じオプションを使用して処理を実行します。サイズから時間へのマッピングを作成します。統計分析を行い、のような式を作成しますtime = something + coef * size

これで、プロセスバーを作成できます。ほとんどのプロセスバーとして、それは約95%に到達し、プロセスの実際の終了を待つ必要があります。

これは非常にシンプルで、他のより洗練されたソリューションよりも悪くはありません。

于 2012-06-07T08:11:31.103 に答える
0

*次のコードを使用してffmpegコマンドのProgressBarを正常に表示しました。

  try {
                Scanner sc = new Scanner(process.getErrorStream());

                // Find duration
                Pattern durPattern = Pattern.compile("(?<=Duration: )[^,]*");
                String dur = sc.findWithinHorizon(durPattern, 0);
                Log.e("duration"+dur);
                String givenDateString = dur;
                SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.S");
                sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
                try {
                    Date mDate = sdf.parse(givenDateString);
                    totalDuration = mDate.getTime();
                    System.out.println("Duration in milli :: " + totalDuration);
                } catch (ParseException e) {
                    e.printStackTrace();
                }

                // Find time as long as possible.
                Pattern timePattern = Pattern.compile("(?<=time=)[\\d:.]*");
                String match;
                String[] matchSplit;
                while (null != (match = sc.findWithinHorizon(timePattern, 0))) {
                    if (isCancelled()) {
                        return;
                    }
                    Log.e("match"+match);
                    String givenDateString1 = match;
                    SimpleDateFormat sdf1 = new SimpleDateFormat("HH:mm:ss.S");
                    sdf1.setTimeZone(TimeZone.getTimeZone("GMT"));
                    try {
                        Date mDate = sdf1.parse(givenDateString1);
                        currentDuration = mDate.getTime();
                        System.out.println("Time in milli :: " + currentDuration);
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                    Double percentage = (double) 0;

                    long currentSeconds = (int) (currentDuration);
                    long totalSeconds = (int) (totalDuration);

                    // calculating percentage
                     percentage =(((double)currentSeconds)/totalSeconds)*100;


                    Log.e("Progress"+percentage);
                    publishProgress(""+percentage);
                }
            }catch (Exception e){
                e.printStackTrace();
            }
于 2016-02-01T09:55:02.757 に答える