Скачать процентное соотношение видео с curl - PullRequest
0 голосов
/ 03 сентября 2018

У меня есть несколько видео, которые размещены на S3 (.mp4 и .mov), некоторые из которых довольно большие (1.2GB +).
Я хочу получить первый кадр из каждого видео, используя оболочку PHP для FFmpeg, но мне не нужно сначала загружать полный файл.

Что я действительно хочу сделать, так это загрузить определенный процент файла, примерно 2%, чтобы я мог гарантировать, что получу первый кадр.

Я нашел способ загрузить 1 МБ файла здесь: https://code.i -harness.com / ru / q / c09357

Тем не менее, это следующий фрагмент этого кода, который я не совсем понимаю, как он загружает только 1 МБ.

function myfunction($ch, $data)     {
    $length = fwrite($this->fh, $data);
    $size=&$this->size;

    if($length === FALSE) {
        return 0;
    } else {
        $size += $length;
    }

    // Downloads 1MB.

    return $size < 1024 * 1024 * 1 ? $length : 0;
}

Для меня это говорит, что установить размер равным размеру файла, а затем, если размер меньше 1 МБ, вернуть длину, в противном случае вернуть 0.
Теперь я знаю, что это работает, потому что я его запустил, но я не знаю, как это работает, так что я могу преобразовать это в получение процента от файла.

Загрузка 1 или 2 МБ файла подходит для небольших файлов и файлов mp4, однако файлам .mov не удается получить первый кадр, если он составляет менее 20 МБ, а некоторые кадры выдают ошибку division by zero, когда получение кадра, я думаю, из приведенной выше функции, возвращающей 0.

Может кто-нибудь пролить свет на то, как все это работает, пожалуйста, или даже лучше, если бы вы могли предложить улучшение?

1 Ответ

0 голосов
/ 11 сентября 2018

myfunction почти наверняка установлена ​​как функция обратного вызова CURLOPT_WRITEFUNCTION для curl_exec, и если эта функция возвращает 0 (или любое другое число, кроме размера $ data), то curl прекратит передачу, а curl_exec вернет CURLE_ABORTED_BY_CALLBACK код ошибки. таким образом, после того как вы загрузили> = 1 мегабайт, curl_exec остановится с ошибкой CURLE_ABORTED_BY_CALLBACK.

What I really want to do is download a certain percentage of the file, something like 2%, so that I can guarantee that I will get the first frame. - в зависимости от кодировки фильма первого мегабайта может быть недостаточно. Существуют некоторые схемы кодирования (например, фильмы .mpeg могут быть закодированы таким образом), где вам нужно несколько байтов от конца файла для рендеринга первого кадра (iirc для .mpeg это называется MOOV Atom - on Фильмы mpeg, в которых атом MOOV находится в конце файла, вам нужно несколько байтов от конца файла для рендеринга первого кадра. Для всех потоковых фильмов .mpeg, оптимизированных для потоковой передачи, атом MOOV находится в начале файла. , не конец, и ваша 1st mebibyte схема будет работать, но если она будет в конце, ваша схема не будет работать, если весь фильм не будет <1 мегабайт) </p>

  • гораздо лучший подход - просто позволить ffmpeg справиться с этим. ffmpeg будет знать, сколько данных нужно загрузить, и попытается загрузить только необходимые части, а не весь фильм, и вам понадобится программа наподобие ffmpeg, чтобы в любом случае извлечь первый кадр позже.

попробовать

function getFirstFrameAsJpg(string $url):string{
        if(file_exists("/dev/null")){
            $ret=shell_exec("ffmpeg -i ".escapeshellarg($url)." -f image2pipe -frames 1 -r 1 -c:v:1 jpeg - 2>/dev/null");
        }else{
            // windows, probably, where /dev/null isn't supported but NUL works the same way.
            $ret=shell_exec("ffmpeg -i ".escapeshellarg($url)." -f image2pipe -frames 1 -r 1 -c:v:1 jpeg - 2>NUL");
        }
        return $ret;
}

вернет первый кадр видео в URL как двоичный файл для изображения .jpg. (что означает, что вы можете сделать file_put_contents('image.jpg',getFirstFrameAsJpg($url)); - интересно, если ffmpeg не установлен, $ ret будет NULL, что означает, что если вы используете strict_types = 1, вы получите исключение, в противном случае вы получите пустую строку.)

ps, прежде чем вы позволите потенциальным хакерам указать URL-адрес для этой функции, убедитесь, что он действительно является http-URL, поскольку я не учитывал последствия для безопасности, позволяющие хакерам запускать getFirstFrameAsJpg("/etc/passwd") или подобное.

если вам нужно скачать с кучей заголовков, рассмотрите возможность настройки прокси-схемы для ffmpeg, где вместо этого ffmpeg предлагается загружать с уникального URL-адреса прокси-сервера, и пусть ffmpeg определяет, какие части фильма загружать, и убедитесь, что для такого прокси реализован заголовок диапазона http , так как ffmpeg понадобится, если для извлечения 1-го кадра из фильма требуется последняя часть фильма, чтобы извлечь первый кадр.

(спасибо c_14 @ freenode #ffmpeg за команду image2pipe)

...