7 September 2011

Кодирование видео для веб-проектов

Working with video
Sandbox
image
Доброго времени суток.
Многим web-программистам рано или поздно нужно работать с видео. Такая задача возникла и у меня.
В Интернете есть много статей на форумах и блогах, как на русскоязычных, так и на зарубежных сайтах. Но, проделавши, так же как и предлагалось в инструкциях — результата ожидаемого не дало. Что и послужило поводом для этой статьи. Думаю, она поможет таким же как и я многим начинающим.

Приступим


Все производилось под рутом на машине с Ubuntu 11.04 (Natty Narwhal).
root@r2d2:~# uname -a
Linux r2d2 2.6.35-30-generic #57-Ubuntu SMP Tue Aug 9 18:00:33 UTC 2011 i686 GNU/Linux

Сначала удалим старое установленное, если оно присутствует

root@r2d2:~# apt-get remove ffmpeg x264 libx264-dev

Обновляем список пакетов

root@r2d2:~# apt-get update && apt-get upgrade

Устанавливаем нужное

root@r2d2:~# apt-get install build-essential checkinstall git git-core libfaac-dev libfaad-dev libjack-jackd2-dev libmp3lame-dev libopencore-amrnb-dev libopencore-amrwb-dev libsdl1.2-dev libtheora-dev libva-dev libvdpau-dev libvorbis-dev libx11-dev libxfixes-dev libxvidcore-dev subversion texi2html yasm zlib1g-dev libavcodec52 mencoder

Устанавливаем библиотеку для кодирования видеопотоков H.264

Почитать подробнее можно тут и тут.
root@r2d2:~# git clone git://git.videolan.org/x264.git
root@r2d2:~# cd x264
root@r2d2:~/x264# ./configure --enable-shared 

Тут нужно сделать отступление. При конфигурировании x264 БЕЗ параметра --enable-shared библиотека будет инсталлироваться в каталог по умолчанию (у меня это /usr/local/bin) и при запуске ffmpeg будет выдавать ошибку о неизвестном местоположении библиотеки libx264:
ERROR: libx264 not found

С параметром --enable-shared результат после команды checkinstall будет следующим:
install -d /usr/local/bin
install x264 /usr/local/bin
install -d /usr/local/include
install -d /usr/local/lib
install -d /usr/local/lib/pkgconfig
install -m 644 x264.h /usr/local/include
install -m 644 x264_config.h /usr/local/include
install -m 644 x264.pc /usr/local/lib/pkgconfig
ln -f -s libx264.so.116 /usr/local/lib/libx264.so
install -m 755 libx264.so.116 /usr/local/lib

При установке на Debian также были проблемы с библиотекой libx264.
Помог параметр --prefix=/shared при конфигурировании x264.
root@r2d2:~/x264# make
root@r2d2:~/x264# checkinstall -fstrans=no -install=yes -pkgname=x264 -pkgversion «1:0.svn`date +%Y%m%d`« -default

Установка ffmpeg

Почитать подробнее можно тут и тут.
root@r2d2:~# svn checkout svn://svn.ffmpeg.org/ffmpeg/trunk ffmpeg
root@r2d2:~# cd ffmpeg
root@r2d2:~# ./configure --enable-gpl --enable-version3 --enable-nonfree --enable-postproc --enable-libfaac --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libtheora --enable-libvorbis --enable-libx264 --enable-libxvid --enable-x11grab
root@r2d2:~# make
root@r2d2:~# checkinstall -fstrans=no -install=yes -pkgname=ffmpeg -pkgversion «4:0.5+svn`date +%Y%m%d`« -default

В результате имеем:
root@r2d2:~# x264 --version
x264 0.116.2074 2641b9e
built on Sep  6 2011, gcc: 4.4.5
configuration: --bit-depth=8
x264 license: GPL version 2 or later

root@r2d2:~# ffmpeg -version
FFmpeg version SVN-r26402, Copyright (c) 2000-2011 the FFmpeg developers
  built on Sep  6 2011 09:26:49 with gcc 4.4.5
  configuration: --enable-gpl --enable-version3 --enable-nonfree --enable-postproc --enable-libfaac --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libtheora --enable-libvorbis --enable-libx264 --enable-libxvid --enable-x11grab
libavutil     50.36. 0 / 50.36. 0
libavcore      0.16. 1 /  0.16. 1
libavcodec    52.108. 0 / 52.108. 0
libavformat   52.93. 0 / 52.93. 0
libavdevice   52. 2. 3 / 52. 2. 3
libavfilter    1.74. 0 /  1.74. 0
libswscale     0.12. 0 /  0.12. 0
libpostproc   51. 2. 0 / 51. 2. 0
FFmpeg SVN-r26402
libavutil     50.36. 0 / 50.36. 0
libavcore      0.16. 1 /  0.16. 1
libavcodec    52.108. 0 / 52.108. 0
libavformat   52.93. 0 / 52.93. 0
libavdevice   52. 2. 3 / 52. 2. 3
libavfilter    1.74. 0 /  1.74. 0
libswscale     0.12. 0 /  0.12. 0
libpostproc   51. 2. 0 / 51. 2. 0

Теперь, если набрать в консоли
ffmpeg -threads 4 -y -i "video.avi" -vcodec libx264 -vpre "hq" -b 2000k -acodec libfaac -ar 44100 -ab 128k -ac 2 "video.flv"
на выходе получаем сконвертированый файл, который можно использовать в своих целях.

Немного о параметрах конвертации

-i — имя исходного файла;
-ar — частота дискретизации звука (должна быть кратна 11кГц);
-ab — аудио битрейт;
-ac — количество каналов звука (1 — моно, 2 — стерео);
-f — формат исходящего видео-файла;
-b — битрейт видео (30k, 200k, 512k, 1024k);
-maxrate — максимальный битрейт кодирования видеопотока (9000k);
-r — кадров в сек (FPS);
-s — размер видео в пикселях;
-fs — установить максимальный размер выходного файла;
-vpre — файл с предустановленными параметрами конвертирования (preset);
-ss 00:02:00 — смещение по времени от начала файла (position). Здесь: пропустить первые 2 мин (сдвиг в сек.). Задается в сек. или временем в формате: hh:mm:ss[.xxx];
-vframes — ограничение на количество кадров видео;
-y — перезаписать файл, если он уже существует;
-aspect — соотношение сторон(4:3, 16:9, 1.3333);
-acodec — аудио-кодек (libfaac, aac, libmp3lame);
-vcodec — видео-кодек (libx264);
-threads 0 — количество ядер в компьютере. Значения: 0 — 4. 0 — автоматически определить количество ядер процессора и использовать их в процессе работы.

ffmpeg имеет файлы с предустановленными настройками для кодирования. Они находятся в папке ffmpeg/ffpresets
root@r2d2:~/ffmpeg/ffpresets# ls -al
libx264-baseline.ffpreset
libx264-faster.ffpreset
libx264-faster_firstpass.ffpreset
libx264-fast.ffpreset
libx264-fast_firstpass.ffpreset
libx264-ipod320.ffpreset
libx264-ipod640.ffpreset
libx264-lossless_fast.ffpreset
libx264-lossless_max.ffpreset
libx264-lossless_medium.ffpreset
libx264-lossless_slower.ffpreset
libx264-lossless_slow.ffpreset
libx264-lossless_ultrafast.ffpreset
libx264-main.ffpreset
libx264-medium.ffpreset
libx264-medium_firstpass.ffpreset
libx264-placebo.ffpreset
libx264-placebo_firstpass.ffpreset
libx264-slower.ffpreset
libx264-slower_firstpass.ffpreset
libx264-slow.ffpreset
libx264-slow_firstpass.ffpreset
libx264-superfast.ffpreset
libx264-superfast_firstpass.ffpreset
libx264-ultrafast.ffpreset
libx264-ultrafast_firstpass.ffpreset
libx264-veryfast.ffpreset
libx264-veryfast_firstpass.ffpreset
libx264-veryslow.ffpreset
libx264-veryslow_firstpass.ffpreset

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

Файл с настройками, который используется в примерах
root@r2d2:/usr/share/ffmpeg# cat libx264-hq.ffpreset
coder=1
flags=+loop
cmp=+chroma
partitions=+parti8x8+parti4x4+partp8x8+partb8x8
me_method=umh
subq=8
me_range=16
g=250
keyint_min=25
sc_threshold=40
i_qfactor=0.71
b_strategy=2
qcomp=0.6
qmin=10
qmax=51
qdiff=4
bf=3
refs=4
directpred=3
trellis=1
flags2=+wpred+mixed_refs+dct8x8+fastpskip

Откат от всего установленного

root@r2d2:~# apt-get remove build-essential checkinstall git git-core libfaac-dev libfaad-dev libjack-jackd2-dev libmp3lame-dev libopencore-amrnb-dev libopencore-amrwb-dev libsdl1.2-dev libtheora-dev libva-dev libvdpau-dev libvorbis-dev libx11-dev libxfixes-dev libxvidcore-dev subversion texi2html yasm zlib1g-dev libavcodec52 mencoder x264 ffmpeg

Получении информации о видео с помощью PHP

Для получения информации о видео я использую немного переделаную функцию, которую нашел в этом посте.
function get_video_size($videofile) {
    define('MAX_VIDEO_WIDTH', 200);
    $vwidth = 0;
    $vheight = 0;
    $owidth = 0;
    $oheight = 0;
    $duration = array();
    $bitrate = 0;
    $audio_bitrate = 0;
    $sfrequency = 0;

    ob_start();
    passthru('ffmpeg -i "' . $videofile . '" 2>&1 | egrep -e "(Duration|Stream)"');
    $ffmpeg_output = ob_get_contents();
    ob_end_clean();

    if (sizeof($ffmpeg_output) == 0) {
        return null;
    }

    foreach (explode("\n", $ffmpeg_output) as $line) {
        $ma = array();
        // get duration and video bitrate
        if (strpos($line, 'Duration:') !== false) {
            preg_match('/(?<hours>\d+):(?<minutes>\d+):(?<seconds>\d+)\.(?<fractions>\d+)/', $line, $ma);
            $duration = array(
                'raw' => $ma['hours'] . ':' . $ma['minutes'] . ':' . $ma['seconds'],
                'hours' => intval($ma['hours']),
                'minutes' => intval($ma['minutes']),
                'seconds' => intval($ma['seconds']),
                'fractions' => intval($ma['fractions']),
                'rawSeconds' => intval($ma['hours']) * 60 * 60 + intval($ma['minutes']) * 60 + intval($ma['seconds']) + (intval($ma['fractions']) != 0 ? 1 : 0)
            );

            preg_match('/bitrate:\s(?<bitrate>\d+)\skb\/s/', $line, $ma);
            $bitrate = $ma['bitrate'];
        }

        // get video info
        if (strpos($line, 'Video:') !== false) {
            preg_match('/Stream #(?:[0-9\.]+)(?:.*)\: Video: (?P<videocodec>.*) (?P<width>[0-9]*)x(?P<height>[0-9]*)/', $line, $ma);
            $vheight = $oheight = $ma['width'];
            $vwidth = $owidth = $ma['height'];
        }

        // get audio info
        if (strpos($line, 'Audio:') !== false) {
            preg_match('/,\s(?<sfrequency>\d+)\sHz,/', $line, $ma);
            $sfrequency = $ma['sfrequency'];

            preg_match('/,\s(?<bitrate>\d+)\skb\/s/', $line, $ma);
            $audio_bitrate = $ma['bitrate'];
        }
    }

    // calculate new size of the video
    if ($vwidth > MAX_VIDEO_WIDTH) {
        $coef = $vheight / $vwidth;
        $vwidth = MAX_VIDEO_WIDTH;
        $vheight = round($vwidth * $coef);
    }

    // frame size must be a multiple of 2
    $vwidth = $vwidth % 2 != 0 ? $vwidth - 1 : $vwidth;
    $vheight = $vheight % 2 != 0 ? $vheight - 1 : $vheight;

    return array(
        'width' => $vwidth,
        'height' => $vheight,
        'srcWidth' => $owidth,
        'srcHeight' => $oheight,
        'duration' => $duration,
        'bitrate' => $bitrate,
        'audioBitrate' => $audio_bitrate,
        'audioSampleFrequency' => $sfrequency
    );
}

В итоге имеем готовый пример

$ffmpeg_path = 'ffmpeg'; // Путь к ffmpeg
$in = 'ATB - Let You Go.avi'; // Входящий файл
$out = 'ATB - Let You Go.flv'; // Исходящий файл

$video = get_video_size($in);
$hq = 'hq'; // Подключаем файл с предустановленными настройками

$command = $ffmpeg_path . ' -threads 0 -y -i "' . $in . '" -vcodec libx264 -vpre "' . $hq . '" -b ' . $video['bitrate'] . 'k -s ' . $video['width'] . 'x' . $video['height'] . ' -acodec libfaac -ar ' . $video['audioSampleFrequency'] . ' -ab ' . $video['audioBitrate'] . 'k -ac 2 "' . $out . '"';
$conv = exec($command);
Tags:ffmpegx264web-разработкакодирование видео
Hubs: Working with video
+57
26.5k 261
Comments 57