简体   繁体   English

如何从java读取ffmpeg响应并使用它来创建进度条?

[英]How to read ffmpeg response from java and use it to create a progress bar?

I am working on creating a progress bar for ffmpeg in java. 我正在为java中的ffmpeg创建进度条。 So for that I need to execute a command, then read all of the progress: 因此,我需要执行一个命令,然后读取所有进度:

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

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

This runs perfectly. 这完美运行。 However, I need to capture the all of the progress to make a progress bar. 但是,我需要捕获所有进度来制作进度条。 So how can I read that data from java? 那么如何从java中读取数据呢?

Here's a complete example for you which should get you started 这是一个完整的例子,可以帮助您入门

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();

  }
}

Output: 输出:

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%

You may also consider using some kind of Java bindings for ffmpeg such as jjmpeg which may provide what you need in a more robust way. 您也可以考虑为ffmpeg使用某种Java绑定,例如jjmpeg ,它可以以更健壮的方式提供您所需的内容。

EDIT 编辑

With ffmpeg 2.0, time output is HH:mm:ss.S so the timePattern needs a to incorporate a : 使用ffmpeg 2.0,时间输出为HH:mm:ss.S所以timePattern需要包含一个:

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

In addition, the dur will need to be split on : and summed together 此外, 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;
//...

You can try to parse ffmpeg output and somehow understand what work is already done. 您可以尝试解析ffmpeg输出,并以某种方式了解已完成的工作。 But this is hard and not stable anyway. 但这很难并且不稳定。 Neither we (the ffmpeg users) nor ffmpeg itself does not know and cannot know in terms of time how long the processing will take. 我们(ffmpeg用户)和ffmpeg本身都不知道也无法知道处理需要多长时间。

According to my experience the easiest way is to implement a kind of heuristics. 根据我的经验,最简单的方法是实现一种启发式方法。 Assume that the time of processing linearly depends on the file size. 假设线性处理的时间取决于文件大小。 This approach is "wrong" but good enough and very simple. 这种方法“错误”但足够好且非常简单。 Now run your processing with exactly the same options you are using in real life with several files of different size. 现在运行您的处理与您在现实生活中使用的几个不同大小的文件完全相同的选项。 Create mapping of size-to-time. 创建大小到时间的映射。 Do statistical analysis and create formula like time = something + coef * size . 做统计分析并创建像time = something + coef * size这样的公式。

Now you can create you process bar. 现在您可以创建流程栏了。 As most process bars it should arrive to ~95% and then wait for real termination of the process. 作为大多数工艺条,它应该达到~95%,然后等待实际终止该过程。

It is very simple and works not worse than any other more sophisticated solution. 它非常简单,并且比任何其他更复杂的解决方案都更糟糕。

*I have Successfully Display ProgressBar for ffmpeg command using Following Code. *我使用以下代码成功显示了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();
            }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM