regex - ffmpeg Progress Bar-نسبة الترميز في PHP




parsing (4)

لقد كتبت نظامًا كاملاً في PHP وباش على الخادم لتحويل مقاطع الفيديو وتدفقها في HTML5 على VPS. يتم التحويل بواسطة ffmpeg في الخلفية ويتم إخراج المحتويات إلى block.txt .

بعد الاطلاع على المشاركات التالية:

يمكن ffmpeg تظهر شريط التقدم؟

و

شريط ترميز الفيديو ffmpeg

من بين أمور أخرى ، لا يمكنني العثور على مثال عملي.

أحتاج إلى الحصول على التقدم المشفر حاليًا كنسبة مئوية.

أول مشاركة قمت بربطها أعلاه تعطي:

$log = @file_get_contents('block.txt');

preg_match("/Duration:([^,]+)/", $log, $matches);
list($hours,$minutes,$seconds,$mili) = split(":",$matches[1]);
$seconds = (($hours * 3600) + ($minutes * 60) + $seconds);
$seconds = round($seconds);

$page = join("",file("$txt"));
$kw = explode("time=", $page);
$last = array_pop($kw);
$values = explode(' ', $last);
$curTime = round($values[0]);
$percent_extracted = round((($curTime * 100)/($seconds)));

echo $percent_extracted;

المتغير $ percent_extracted يكرر صفر ، وبما أن الرياضيات ليست نقطة قوية ، فأنا لا أعرف كيف أتقدم هنا.

هنا خط واحد من إخراج ffmpeg من block.txt (إذا كان مفيدًا)

time = 00: 19: 25.16 bitrate = 823.0kbits / s frame = 27963 fps = 7 q = 0.0 size = 117085kB time = 00: 19: 25.33 bitrate = 823.1kbits / s frame = 27967 fps = 7 q = 0.0 size = 117085kB time = 00: 19: 25.49 bitrate = 823.0kbits / s frame = 27971 fps = 7 q = 0.0 size = 117126kB

الرجاء مساعدتي في إخراج هذه النسبة المئوية ، وبمجرد الانتهاء من ذلك ، يمكنني إنشاء شريط التقدم الخاص بي. شكر.


Answers

إذا كان javascript يقوم بتحديث شريط التقدم الخاص بك ، فيمكن أن يقوم javascript بتنفيذ الخطوة 2 مباشرة ":

[هذا المثال يتطلب dojo ]

dojo 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: grab the progress from the file:

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

حسنًا ، لقد وجدت ما أحتاجه - ونأمل أن يساعد هذا شخصًا آخر أيضًا!

أولاً وقبل كل شيء ، تريد إخراج بيانات ffmpeg إلى ملف نصي على الخادم.

ffmpeg -i path/to/input.mov -vcodec videocodec -acodec audiocodec path/to/output.flv 1> block.txt 2>&1

لذا ، فإن إخراج ffmpeg هو block.txt. الآن في PHP ، دعونا نفعل ذلك!

$content = @file_get_contents('../block.txt');

if($content){
    //get duration of source
    preg_match("/Duration: (.*?), start:/", $content, $matches);

    $rawDuration = $matches[1];

    //rawDuration is in 00:00:00.00 format. This converts it to seconds.
    $ar = array_reverse(explode(":", $rawDuration));
    $duration = floatval($ar[0]);
    if (!empty($ar[1])) $duration += intval($ar[1]) * 60;
    if (!empty($ar[2])) $duration += intval($ar[2]) * 60 * 60;

    //get the time in the file that is already encoded
    preg_match_all("/time=(.*?) bitrate/", $content, $matches);

    $rawTime = array_pop($matches);

    //this is needed if there is more than one match
    if (is_array($rawTime)){$rawTime = array_pop($rawTime);}

    //rawTime is in 00:00:00.00 format. This converts it to seconds.
    $ar = array_reverse(explode(":", $rawTime));
    $time = floatval($ar[0]);
    if (!empty($ar[1])) $time += intval($ar[1]) * 60;
    if (!empty($ar[2])) $time += intval($ar[2]) * 60 * 60;

    //calculate the progress
    $progress = round(($time/$duration) * 100);

    echo "Duration: " . $duration . "<br>";
    echo "Current Time: " . $time . "<br>";
    echo "Progress: " . $progress . "%";

}

هذا يخرج النسبة المئوية من الوقت المتبقي.

يمكنك الحصول على هذا كقطعة واحدة من النص مرددًا إلى صفحة ، ومن صفحة أخرى يمكنك تنفيذ طلب AJAX باستخدام jQuery للحصول على هذا النص وإخراجه في div ، على سبيل المثال ، للتحديث على صفحتك كل 10 ثواني. :)


يحتوي ffmpeg الآن على خيار تقدم ، والذي يعطي مخرجات بسهولة أكبر.

ffmpeg -progress block.txt -i path / to / input.mov -vcodec videocodec -acodec audiocodec path / to / output.flv 2> & 1

قبل البدء في الترميز ، يمكنك الحصول على إجمالي الإطارات ، والكثير من المعلومات الأخرى بهذا (هذا ما يمكن فعله مع bash. أنا مبرمج Perl لذا لا أعرف كيف ستحصل على المعلومات في PHP النصي).

eval $ (ffprobe -of flat = s = _ -show_entries stream = height، width، nb_frames، duration، codec_name path / to / input.mov)؛
العرض = $ {streams_stream_0_width}؛
ارتفاع = $ {streams_stream_0_height}؛
إطارات = $ {streams_stream_0_nb_frames}؛
videoduration = $ {streams_stream_0_duration}؛
audioduration = $ {streams_stream_1_duration}؛
الترميز = $ {streams_stream_0_codec_name}؛
صدى عرض $ ، $ height ، $ frame ، $ videoduration ، $ audioduration ، $ codec؛

من flate = s = _ تقول لوضع كل اسم = قيمة على سطر منفصل. -show_entries يخبرها أن تظهر الإدخالات من ما يلي (دفق ل -show_streams ، تنسيق -show_format ، إلخ) دفق = ... يقول لإظهار هذه العناصر من إخراج -show_streams. جرب ما يلي لمعرفة ما هو متاح:

ffprobe -show_streams path / to / input.mov

تتم إضافة الإخراج إلى ملف التقدم إلى مرة واحدة تقريبًا في الثانية. المحتوى ، بعد الانتهاء من الترميز ، يبدو كما يلي. في البرنامج النصي الخاص بي ، مرة واحدة في الثانية وأنا أضع الملف في مصفوفة ، وعبر الصفيف في ترتيب عكسي ، فقط باستخدام ما هو بين أول خطين (التقدم قبل الأخير) اثنين "التقدم" أجد ، بحيث أستخدم أحدث المعلومات من نهاية الملف. قد يكون هناك طرق أفضل. هذا من MP4 مع أي صوت حتى لا يكون هناك سوى تيار واحد.

إطار = 86
إطارا في الثانية = 0.0
stream_0_0_q = 23.0
TOTAL_SIZE = 103173
out_time_ms = 1120000
out_time = 00: 00: 01.120000
dup_frames = 0
drop_frames = 0
تقدم = الاستمرار
إطار = 142
إطارا في الثانية = 140.9
stream_0_0_q = 23.0
TOTAL_SIZE = 415861
out_time_ms = 3360000
out_time = 00: 00: 03.360000
dup_frames = 0
drop_frames = 0
تقدم = الاستمرار
إطار = 185
إطارا في الثانية = 121.1
stream_0_0_q = 23.0
TOTAL_SIZE = 1268982
out_time_ms = 5080000
out_time = 00: 00: 05.080000
dup_frames = 0
drop_frames = 0
تقدم = الاستمرار
إطار = 225
إطارا في الثانية = 110.9
stream_0_0_q = 23.0
TOTAL_SIZE = 2366000
out_time_ms = 6680000
out_time = 00: 00: 06.680000
dup_frames = 0
drop_frames = 0
تقدم = الاستمرار
إطار = 262
إطارا في الثانية = 103.4
stream_0_0_q = 23.0
TOTAL_SIZE = 3810570
out_time_ms = 8160000
out_time = 00: 00: 08.160000
dup_frames = 0
drop_frames = 0
تقدم = الاستمرار
إطار = 299
إطارا في الثانية = 84.9
stream_0_0_q = -1.0
TOTAL_SIZE = 6710373
out_time_ms = 11880000
out_time = 00: 00: 11.880000
dup_frames = 0
drop_frames = 0
تقدم = نهاية


function multiexplode ($delimiters,$string) {

    $ready = str_replace($delimiters, $delimiters[0], $string);
    $launch = explode($delimiters[0], $ready);
    return  $launch;
}

$text = "here is a sample: this text, and this will be exploded. this also | this one too :)";


$exploded = multiexplode(array(",",".","|",":"),$text);

print_r($exploded);

//And output will be like this:
// Array
// (
//    [0] => here is a sample
//    [1] =>  this text
//    [2] =>  and this will be exploded
//    [3] =>  this also 
//    [4] =>  this one too 
//    [5] => )
// )

المصدر: php @ metehanarslan على php.net





php regex parsing ffmpeg