我有一个奇怪的艰巨的任务来执行。 我认为这将是容易的,但我所有的努力都石沉大海。
我将上传到PHP脚本从各种格式的(.AVI,.MPG,.WMV,.MOV,等等),以单一的FLV格式的视频。 转换工作不错,但就是我遇到的麻烦是的视频分辨率。
这是我目前正在运行(与PHP瓦尔)的命令:
ffmpeg -i $original -ab 96k -b 700k -ar 44100 -s 640x480 -acodec mp3 $converted
无论$原始和$转换包含完整路径的文件。 我的问题是,这总是转换为640×480(像我告诉它来)即使源较小。 显然,这是的磁盘空间和带宽的浪费视频下载时。 此外,这并不考虑输入视频在4以外的任何纵横比为:3,从而产生“压扁”的转换,如果我上传16:9视频。
有3个东西,我需要做的:
- 确定原始视频的纵横比。
- 如果不是4:3,垫顶部和底部出现黑条。
- 转换为640×480如果原始的任一尺寸大于或4:与原稿的宽度/高度(取接近640×480)3的纵横比。
我已经运行ffmpeg -i
在一些影片,但我没有看到一个统一的格式或位置找到原来的从分辨率。 一旦我能明白这一点,我知道我可以“做数学”,以找出正确的大小并指定填充修复与-padttop,-padbottom等长宽比
这对我的作品:
$data = 'ffmpeg output';
$matches = array();
if (!preg_match('/Stream #(?:[0-9\.]+)(?:.*)\: Video: (?P<videocodec>.*) (?P<width>[0-9]*)x(?P<height>[0-9]*)/',$data,$matches)
preg_match('/Could not find codec parameters \(Video: (?P<videocodec>.*) (?P<width>[0-9]*)x(?P<height>[0-9]*)\)/',$data,$matches)
这可能并不总是工作,但它的作品的时代,这是在我的情况不够好,大部分:)
好。 我有一个全功能的解决方案。 这是任何人谁发现这个问题,希望做同样的事情。 我的代码可能不是很优雅,但它能够完成任务。
获取FFmpeg的输出
首先我必须得到的ffmpeg -i,这是一个挑战本身的输出。 由于霸主对回答我的其他问题 ,我终于能够得到它一起工作2>&1
在我的命令结束。 并感谢埃弗特的回答这个问题,我能够解析输出用preg_match
找到原文件的高度和宽度。
function get_vid_dim($file)
{
$command = '/usr/bin/ffmpeg -i ' . escapeshellarg($file) . ' 2>&1';
$dimensions = array();
exec($command,$output,$status);
if (!preg_match('/Stream #(?:[0-9\.]+)(?:.*)\: Video: (?P<videocodec>.*) (?P<width>[0-9]*)x(?P<height>[0-9]*)/',implode('\n',$output),$matches))
{
preg_match('/Could not find codec parameters \(Video: (?P<videocodec>.*) (?P<width>[0-9]*)x(?P<height>[0-9]*)\)/',implode('\n',$output),$matches);
}
if(!empty($matches['width']) && !empty($matches['height']))
{
$dimensions['width'] = $matches['width'];
$dimensions['height'] = $matches['height'];
}
return $dimensions;
}
确定最佳的尺寸
我写了这个功能,以确定最佳的尺寸用于转换。 它采用原始的尺寸,靶的尺寸,以及是否不强迫转换到目标纵横比(从它的宽度/高度来确定)。 目标尺寸将永远是这个函数可以返回的最大结果。
function get_dimensions($original_width,$original_height,$target_width,$target_height,$force_aspect = true)
{
// Array to be returned by this function
$target = array();
// Target aspect ratio (width / height)
$aspect = $target_width / $target_height;
// Target reciprocal aspect ratio (height / width)
$raspect = $target_height / $target_width;
if($original_width/$original_height !== $aspect)
{
// Aspect ratio is different
if($original_width/$original_height > $aspect)
{
// Width is the greater of the two dimensions relative to the target dimensions
if($original_width < $target_width)
{
// Original video is smaller. Scale down dimensions for conversion
$target_width = $original_width;
$target_height = round($raspect * $target_width);
}
// Calculate height from width
$original_height = round($original_height / $original_width * $target_width);
$original_width = $target_width;
if($force_aspect)
{
// Pad top and bottom
$dif = round(($target_height - $original_height) / 2);
$target['padtop'] = $dif;
$target['padbottom'] = $dif;
}
}
else
{
// Height is the greater of the two dimensions relative to the target dimensions
if($original_height < $target_height)
{
// Original video is smaller. Scale down dimensions for conversion
$target_height = $original_height;
$target_width = round($aspect * $target_height);
}
//Calculate width from height
$original_width = round($original_width / $original_height * $target_height);
$original_height = $target_height;
if($force_aspect)
{
// Pad left and right
$dif = round(($target_width - $original_width) / 2);
$target['padleft'] = $dif;
$target['padright'] = $dif;
}
}
}
else
{
// The aspect ratio is the same
if($original_width !== $target_width)
{
if($original_width < $target_width)
{
// The original video is smaller. Use its resolution for conversion
$target_width = $original_width;
$target_height = $original_height;
}
else
{
// The original video is larger, Use the target dimensions for conversion
$original_width = $target_width;
$original_height = $target_height;
}
}
}
if($force_aspect)
{
// Use the target_ vars because they contain dimensions relative to the target aspect ratio
$target['width'] = $target_width;
$target['height'] = $target_height;
}
else
{
// Use the original_ vars because they contain dimensions relative to the original's aspect ratio
$target['width'] = $original_width;
$target['height'] = $original_height;
}
return $target;
}
用法
下面是你将得到什么几个例子get_dimensions()
使事情变得更加清晰:
get_dimensions(480,360,640,480,true);
-returns: Array([width] => 480, [height] => 360)
get_dimensions(480,182,640,480,true);
-returns: Array([padtop] => 89, [padbottom] => 89, [width] => 480, [height] => 360)
get_dimensions(480,182,640,480,false);
-returns: Array([width] => 480, [height] => 182)
get_dimensions(640,480,480,182,true);
-returns: Array([padleft] => 119, [padright] => 119, [width] => 480, [height] => 182)
get_dimensions(720,480,640,480,true);
-returns: Array([padtop] => 27, [padbottom] => 27, [width] => 640, [height] => 480)
get_dimensions(720,480,640,480,false);
-returns: Array([width] => 640, [height] => 427)
成品
现在,把它放在一起:
$src = '/var/videos/originals/original.mpg';
$original = get_vid_dim($src);
if(!empty($original['width']) && !empty($original['height']))
{
$target = get_dimensions($original['width'],$original['height'],640,480,true);
$command = '/usr/bin/ffmpeg -i ' . $src . ' -ab 96k -b 700k -ar 44100 -s ' . $target['width'] . 'x' . $target['height'];
$command .= (!empty($target['padtop']) ? ' -padtop ' . $target['padtop'] : '');
$command .= (!empty($target['padbottom']) ? ' -padbottom ' . $target['padbottom'] : '');
$command .= (!empty($target['padleft']) ? ' -padleft ' . $target['padleft'] : '');
$command .= (!empty($target['padright']) ? ' -padright ' . $target['padright'] : '');
$command .= ' -acodec mp3 /var/videos/converted/target.flv 2>&1';
exec($command,$output,$status);
if($status == 0)
{
// Success
echo 'Woohoo!';
}
else
{
// Error. $output has the details
echo '<pre>',join('\n',$output),'</pre>';
}
}
我不熟悉PHP,但我写了一个实用程序与几个月前在C#中的ffmpeg工作。 我用正则表达式来做到这一点。 有一些正则表达式可以帮助你从那里:
// this is for version detection
"FFmpeg version (?<version>(\w|\d|\.|-)+)"
// this is for duration parsing
"Duration: (?<hours>\d{1,3}):(?<minutes>\d{2}):(?<seconds>\d{2})(.(?<fractions>\d{1,3}))?"
// these are connected:
// 0) this is base for getting stream info
"Stream #(?<number>\d+?\.\d+?)(\((?<language>\w+)\))?: (?<type>.+): (?<data>.+)"
// 1) if the type is audio:
"(?<codec>\w+), (?<frequency>[\d]+) (?<frequencyUnit>[MK]?Hz), (?<chanel>\w+), (?<format>\w+)(, (?<bitrate>\d+) (?<bitrateUnit>[\w/]+))?"
// 2) if the type is video:
"(?<codec>\w+), (?<format>\w+), (?<width>\d+)x(?<height>\d+), (?<bitrate>\d+(\.\d+)?) (?<bitrateUnit>[\w\(\)]+)"
因此让宽度和高度,你可以计算的纵横比。
注:我知道,在某些情况下,表现可能会失败。