Скачать процентное соотношение видео с curl

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

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

Я нашел способ загрузить 1 МБ файла здесь: https://code.i-harness.com/en/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 ответ

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 - в фильмах mpeg, где атом MOOV находится в конце файла, вам нужно несколько байтов от конца файла для рендеринга первого кадра. для всех оптимизированных для потоковой передачи фильмов.mpeg атом MOOV находится в начале файла, а не в конце, а ваш 1st mebibyte схема будет работать, но если она в конце, ваша схема не будет работать, если весь фильм не <1 мегабайт)

  • намного лучший подход - просто позволить 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-адрес для этой функции, убедитесь, что он действительно является URL-адресом http, поскольку я не учел последствия для безопасности, позволяющие запускать хакеры getFirstFrameAsJpg("/etc/passwd") или похожие.

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

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

Другие вопросы по тегам