【问题标题】:ffmpeg video encoding progress barffmpeg 视频编码进度条
【发布时间】:2011-04-15 19:35:36
【问题描述】:

当我在浏览器中运行转换时,它只会显示白色空白区域。只有经过转换过程页面才会加载。

请建议如何实现一个进度条,在视频转换发生时向用户显示进度。

我的 php 脚本中有这个

exec("ffmpeg -i filename.flv -sameq -ab 128 -s 640x480 filename.mp4");

那么我应该如何更改此脚本以获取进度详细信息,甚至是文件或直接作为页面中的输出。请任何人都可以给我一个完整的脚本/代码来详细解释它。因为我认为我无法得到完整的答案,所以我对如何处理这个问题感到困惑

【问题讨论】:

    标签: php jquery ffmpeg


    【解决方案1】:

    javascript 应该告诉 php 开始转换 [1] 然后执行 [2] ...


    [1] php: 开始转换并将状态写入文本文件 - 示例语法:

    exec("ffmpeg -i path/to/input.mov path/to/output.flv 1>path/to/output.txt 2>&1");
    

    对于第二部分,我们需要只需 javascript 来读取文件。 以下示例使用 dojo.request 进行 AJAX,但您也可以使用 jQuery 或 vanilla 或其他:

    [2] js:从文件中获取进度:

    var _progress = function(i){
        i++;
        // THIS MUST BE THE PATH OF THE .txt FILE SPECIFIED IN [1] : 
        var logfile = 'path/to/output.txt';
    
    /* (example requires dojo) */
    
    request.post(logfile).then( function(content){
    // AJAX success
        var duration = 0, time = 0, progress = 0;
        var result = {};
    
        // get duration of source
        var matches = (content) ? content.match(/Duration: (.*?), start:/) : [];
        if( matches.length>0 ){
            var rawDuration = matches[1];
            // convert rawDuration from 00:00:00.00 to seconds.
            var ar = rawDuration.split(":").reverse();
            duration = parseFloat(ar[0]);
            if (ar[1]) duration += parseInt(ar[1]) * 60;
            if (ar[2]) duration += parseInt(ar[2]) * 60 * 60;
    
            // get the time 
            matches = content.match(/time=(.*?) bitrate/g);
            console.log( matches );
    
            if( matches.length>0 ){
                var rawTime = matches.pop();
                // needed if there is more than one match
                if (lang.isArray(rawTime)){ 
                    rawTime = rawTime.pop().replace('time=','').replace(' bitrate',''); 
                } else {
                    rawTime = rawTime.replace('time=','').replace(' bitrate','');
                }
    
                // convert rawTime from 00:00:00.00 to seconds.
                ar = rawTime.split(":").reverse();
                time = parseFloat(ar[0]);
                if (ar[1]) time += parseInt(ar[1]) * 60;
                if (ar[2]) time += parseInt(ar[2]) * 60 * 60;
    
                //calculate the progress
                progress = Math.round((time/duration) * 100);
            }
    
            result.status = 200;
            result.duration = duration;
            result.current  = time;
            result.progress = progress;
    
            console.log(result);
    
            /* UPDATE YOUR PROGRESSBAR HERE with above values ... */
    
            if(progress==0 && i>20){
                // TODO err - giving up after 8 sec. no progress - handle progress errors here
                console.log('{"status":-400, "error":"there is no progress while we tried to encode the video" }'); 
                return;
            } else if(progress<100){ 
                setTimeout(function(){ _progress(i); }, 400);
            }
        } else if( content.indexOf('Permission denied') > -1) {
            // TODO - err - ffmpeg is not executable ...
            console.log('{"status":-400, "error":"ffmpeg : Permission denied, either for ffmpeg or upload location ..." }');    
        } 
    },
    function(err){
    // AJAX error
        if(i<20){
            // retry
            setTimeout(function(){ _progress(0); }, 400);
        } else {
            console.log('{"status":-400, "error":"there is no progress while we tried to encode the video" }');
            console.log( err ); 
        }
        return; 
    });
    
    }
    setTimeout(function(){ _progress(0); }, 800);
    

    【讨论】:

      【解决方案2】:

      可以做到,尽管为较小的文件使用更简单的 ajax 指示器是个好主意,但对于 >50-80 MB 的较大文件,您可以这样做:

      您可以通过 PHP 读取 FFMPEG 返回值。 ffmpeg(最后几行)返回:

      Press [q] to stop encoding
      frame= 1850 fps=115 q=31.0 Lsize=    5789kB time=74.00 bitrate= 640.8kbits/s   
      video:5135kB audio:580kB
      

      time=74.00 是当前文件时间(不是执行时间)。您可以使用一些正则表达式来解析该值,并且通过一些数学运算,您可以获得完成百分比条。

      如果您不知道文件时间长度。 FFMPEG 前几行返回:

      Input #0, flv, from 'cf_video_3728.flv':
        Duration: 00:01:14.13, start: 0.000000, bitrate: 864 kb/s
      

      您可以解析 Duration 并获取总时间。

      希望这会有所帮助。

      【讨论】:

        【解决方案3】:

        如果您使用的是 PHP-FFMpeg,他们添加了一个 on 函数,您可以监听进度并执行回调。您可以像这样在视频格式容器上进行设置:

        $format = new Format\Video\X264();
        $format->on('progress', function ($video, $format, $percentage) {
            echo "$percentage % transcoded";
        });
        

        更多信息参见文档https://github.com/PHP-FFMpeg/PHP-FFMpeg

        【讨论】:

          【解决方案4】:

          我不相信这是可能的。

          问题是您需要您的PHP 脚本来了解当前的ffmpeg 处理状态。如果您通过命令行进行ffmpeg 转换,它会向用户显示进度,但是当您使用 PHP 中的命令(如exec)生成 ffmpeg 时,您无法访问该输出流。

          与其尝试向用户显示真正的“进度指示器”,我建议您只需在页面上添加一个等待指示器灯箱即可。您可以找到许多适合此目的的图像,或通过http://ajaxload.info/ 等工具生成一个。

          【讨论】:

          • 这会很尴尬且效率低下,但我想你应该能够将 ffmpeg 输出重定向到一个临时文件,然后可以由 php.ini 读取。不过,我宁愿选择等待指示器 - 简单得多。
          【解决方案5】:

          您可能有兴趣阅读COMET。

          这是一种编程技术,允许您将信息从服务器推送到浏览器,而无需浏览器请求。

          这里有一篇文章解释了如何通过使用隐藏的 iframe 使用 PHP 来实现它。

          http://www.zeitoun.net/articles/comet_and_php/start

          也许您可以将它与 Stewie 提供的有关从 ffmpeg 读取返回值的答案结合使用。

          【讨论】:

          • 基本上我同意,Comet D 会让我的回答变得完整,应该首选任何推送技术。
          猜你喜欢
          • 1970-01-01
          • 2020-09-24
          • 2020-11-09
          • 2011-12-23
          • 1970-01-01
          • 2015-02-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多