Расчет / оптимизация битрейта FFMPEG

Я написал следующую оболочку для FFMPEG:

function Video($input, $crop = null, $scale = null, $output = null, $extra = null) { $input = @new ffmpeg_movie($input); if ((is_object($input) === true) && ($input->hasVideo() === true)) { $size = array($input->getFrameWidth(), $input->getFrameHeight()); $crop = array_values(array_filter(explode('/', $crop), 'is_numeric')); $scale = array_values(array_filter(explode('*', $scale), 'is_numeric')); if ((is_callable('shell_exec') === true) && (is_executable($ffmpeg = trim(shell_exec('which ffmpeg'))) === true)) { if (count($crop) == 2) { $crop = array($size[0] / $size[1], $crop[0] / $crop[1]); if ($crop[0] > $crop[1]) { $size[0] = round($size[1] * $crop[1]); } else if ($crop[0] < $crop[1]) { $size[1] = round($size[0] / $crop[1]); } $crop = array($input->getFrameWidth() - $size[0], $input->getFrameHeight() - $size[1]); } else { $crop = array(0, 0); } if (count($scale) >= 1) { if (empty($scale[0]) === true) { $scale[0] = round($scale[1] * $size[0] / $size[1] / 2) * 2; } else if (empty($scale[1]) === true) { $scale[1] = round($scale[0] * $size[1] / $size[0] / 2) * 2; } } else { $scale = array(round($size[0] / 2) * 2, round($size[1] / 2) * 2); } $result = array(); if (array_product($scale) > 0) { $result[] = sprintf('%s -i %s', escapeshellcmd($ffmpeg), escapeshellarg($input->getFileName())); if (array_sum($crop) > 0) { if (stripos(shell_exec(escapeshellcmd($ffmpeg) . ' -h | grep crop'), 'removed') !== false) { $result[] = sprintf('-vf "crop=in_w-2*%u:in_h-2*%u"', round($crop[0] / 4) * 2, round($crop[1] / 4) * 2); } else if ($crop[0] > 0) { $result[] = sprintf('-cropleft %u -cropright %u', round($crop[0] / 4) * 2, round($crop[0] / 4) * 2); } else if ($crop[1] > 0) { $result[] = sprintf('-croptop %u -cropbottom %u', round($crop[1] / 4) * 2, round($crop[1] / 4) * 2); } } if ($input->hasAudio() === true) { $result[] = sprintf('-ab %u -ar %u', $input->getAudioBitRate(), $input->getAudioSampleRate()); } $result[] = sprintf('-b %u -r %u -s %s', $input->getBitRate(), min(25, $input->getFrameRate()), implode('x', $scale)); if (strlen($format = strtolower(ltrim(strrchr($output, '.'), '.'))) > 0) { $result[] = sprintf('-f %s %s -y %s', $format, escapeshellcmd($extra), escapeshellarg($output . '.ffmpeg')); if ((strncmp('flv', $format, 3) === 0) && (is_executable($flvtool2 = trim(shell_exec('which flvtool2'))) === true)) { $result[] = sprintf('&& %s -U %s %s', escapeshellcmd($flvtool2), escapeshellarg($output . '.ffmpeg'), escapeshellarg($output . '.ffmpeg')); } $result[] = sprintf('&& mv -u %s %s', escapeshellarg($output . '.ffmpeg'), escapeshellarg($output)); if ((is_writable(dirname($output)) === true) && (is_resource($stream = popen('(' . implode(' ', $result) . ') 2>&1 &', 'r')) === true)) { while (($buffer = fgets($stream)) !== false) { if (strpos($buffer, 'to stop encoding') !== false) { return (is_int(pclose($stream)) === true) ? true : false; } } if (is_file($output . '.ffmpeg') === true) { unlink($output . '.ffmpeg'); } pclose($stream); } } } } } return false; } 

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

Я очень мало знаю об этих вопросах, но из моего понимания битрейты напрямую связаны с продолжительностью, качеством и разрешением средств массовой информации, не так ли? Если да, как я могу использовать эти значения для определения подходящего битрейта аудио и видео для поддержания качества ввода и уменьшения размера файла?

Заранее спасибо!

В общем, вы не должны указывать битрейт вообще. Это полезно только для потоковой передачи, и в этом случае вам нужно также уважать VBV (который определяет максимальный битрейт с течением времени, а также средний битрейт).

Используйте x264 crf 23 – его режим постоянного качества по умолчанию – и будьте счастливы. В случае ffmpeg это что-то вроде:

 ffmpeg -i <file> -vcodec libx264 -vpre slower -acodec copy <outfile> 

Что касается звука, лучше всего скопировать его, если вход был сжат. Это невозможно в некоторых ситуациях, например, если вход был vorbis, а выход – это .flv-файл. В этом случае я буду придерживаться того, что выбрано по умолчанию для выбранного аудиокодера.

Вы хотите найти Shannon-Entropy -log (P) / log (2). Это минимальные бит, о которых может думать любая информация. Но я не уверен, что это вам полезно.

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

Во всяком случае, я столкнулся с этим сценарием Bash, который говорит о том, что мое мышление правильное, я до сих пор не знаю, как вычислить выходную скорость передачи, не имея выходного размера в качестве ограничения. Если кто-нибудь знает, пожалуйста, поделитесь!