【问题标题】:How to add progress bar to FFMPEG android如何将进度条添加到 FFMPEG android
【发布时间】:2026-02-07 05:35:02
【问题描述】:

我想在FFMPEG执行android期间添加一个进度条。

当我启动 FFMPEG 命令时,进度条以百分比进度开始。

【问题讨论】:

    标签: android ffmpeg progress-bar


    【解决方案1】:

    以百分比计算ffmpeg进度

    ffmpeg.execute(command, new ExecuteBinaryResponseHandler() {
                @Override
                public void onFailure(String s) {
                    Log.d(TAG, "FAILED with output : " + s);
                }
    
                @Override
                public void onSuccess(String s) {
                    Log.d(TAG, "SUCCESS with output : " + s);
                }
    
                @Override
                public void onProgress(String s) {
                    Log.d(TAG, "Started command : ffmpeg " + Arrays.toString(command));
                    Log.d(TAG, "progress : " + s);
                    Pattern timePattern = Pattern.compile("(?<=time=)[\\d:.]*");
                    Scanner sc = new Scanner(s);
    
                    String match = sc.findWithinHorizon(timePattern, 0);
                    if (match != null) {
                        String[] matchSplit = match.split(":");
                        if (totalDur != 0) {
                            float progress = (Integer.parseInt(matchSplit[0]) * 3600 +
                                    Integer.parseInt(matchSplit[1]) * 60 +
                                    Float.parseFloat(matchSplit[2])) / totalDur;
                            float showProgress = (progress * 100);
                            Log.d(TAG, "=======PROGRESS======== " + showProgress);
                        }
                    }
                }
    
                @Override
                public void onStart() {
                    Log.d(TAG, "Started command : ffmpeg " + Arrays.toString(command));
                    progressDialog.setMessage("Processing...");
                    progressDialog.show();
                }
    
                @Override
                public void onFinish() {
                    Log.d(TAG, "Finished command : ffmpeg " + Arrays.toString(command));
                    progressDialog.dismiss();
                }
            });
    

    totalDur=25; // 25 秒视频

    但是 totalDur 会根据操作而改变,例如对于 2x 慢速视频,您必须给出 totalDur=2*25; //50秒视频

    【讨论】:

    • @Dastan.lqbal 如果您不知道要保存的视频长度怎么办?
    • 在这种情况下,您可以从视频中抓取总帧数,然后进行匹配
    • 您能否编辑/扩展您的答案并举例说明我如何实现这一目标?
    • 我在Scanner sc = new Scanner(s); Cannot resolve symbol "s" 也收到一个错误----对不起,这是我的错,S 是字符串名称。
    • @H.*s 你可以检查这个答案以获得总帧数*.com/questions/2017843/…
    【解决方案2】:

    如果您使用的是https://github.com/tanersener/mobile-ffmpeg,以下是具有进度值的解决方案。

    获取视频时长:

    int videoLength = MediaPlayer.create(mContext, selectedUri).getDuration();

    配置enableStatisticsCallback方法:

         Config.enableStatisticsCallback(new StatisticsCallback() {
                    public void apply(Statistics newStatistics) {
                        float progress = Float.parseFloat(String.valueOf(newStatistics.getTime())) / videoLength;
                        float progressFinal = progress * 100;
                        Log.d(TAG, "Video Length: " + progressFinal);
                        Log.d(Config.TAG, String.format("frame: %d, time: %d", newStatistics.getVideoFrameNumber(), newStatistics.getTime()));
                        Log.d(Config.TAG, String.format("Quality: %f, time: %f", newStatistics.getVideoQuality(), newStatistics.getVideoFps()));
                        progressDialog.setProgress((int) progressFinal);
                    }
                });
    
         com.arthenica.mobileffmpeg.FFmpeg.executeAsync(command, (executionId, returnCode) -> {
                    progressDialog.dismiss();
                    if (returnCode == RETURN_CODE_SUCCESS) {
                        Toast.makeText(mContext, "Video Saved in Folder : " + getString(R.string.app_name), Toast.LENGTH_SHORT).show();
                        Log.i(Config.TAG, "Async command execution completed successfully.");
                    } else if (returnCode == RETURN_CODE_CANCEL) {
                        Log.i(Config.TAG, "Async command execution cancelled by user.");
                    } else {
                        Toast.makeText(mContext, "Something Went Wrong", Toast.LENGTH_SHORT).show();
                        Log.i(Config.TAG, String.format("Async command execution failed with rc=%d.", returnCode));
                    }
                });
    

    希望对您有所帮助。

    【讨论】:

    • 如何在创建视频之前获取视频时长,这就是视频时长无法获取的原因。
    【解决方案3】:

    我使用视频时间添加了一个 ProgressDialog

    final int msec = MediaPlayer.create(this, Uri.fromFile(new File(path))).getDuration();
    
     final ProgressDialog dialog = new ProgressDialog(this);
            dialog.setMax(msec);
            dialog.setMessage("Progress");
            dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
            dialog.setProgress(0);
    

    然后在OnStartExecuteBinaryResponseHandler的方法中调用dialog.show() 并更新onProgress(String message) 方法中的进度

    @Override
    public void onProgress(String message) {
        int start = message.indexOf("time=");
            int end = message.indexOf(" bitrate");
            if (start != -1 && end != -1) {
                String duration = message.substring(start + 5, end);
                if (duration != "") {
                    try {
                        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
                        sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
                        dialog.setProgress((int)sdf.parse("1970-01-01 " + duration).getTime());                        
                    }catch (ParseException e)
                    {
                        e.printStackTrace();
                    }
                }
        }
    }
    

    关闭 OnFinish() 方法中的对话框

    @Override
    public void onFinish() {
        String s = System.currentTimeMillis() - MainActivity.this.startTime + "";
        dialog.dismiss();
    }
    

    【讨论】:

      【解决方案4】:

      我在任何地方都使用它:

      Pattern timePattern = Pattern.compile("(?<=time=)[\\d:.]*");
      Scanner sc = new Scanner(message);
      
      String match = sc.findWithinHorizon(timePattern, 0);
      if (match != null) {
        String[] matchSplit = match.split(":");
        if (totalDur != 0) {
          float progress = (Integer.parseInt(matchSplit[0]) * 3600 +
                Integer.parseInt(matchSplit[1]) * 60 +
                Float.parseFloat(matchSplit[2])) / totalDur;
          int showProgress = (int) (progress * 100000);
          progressDialog.setProgress(showProgress);
        }
      }

      onProgress 方法中使用它。

      【讨论】: