好的,我了解了视频格式的基础知识——有一些容器格式,然后你就有了核心视频/音频格式。我想编写一个基于 Web 的应用程序来确定文件使用的视频/音频编解码器。
如何最好地以编程方式确定视频编解码器?最好通过系统调用使用标准库并解析其输出?(例如ffmpeg、转码等?)
好的,我了解了视频格式的基础知识——有一些容器格式,然后你就有了核心视频/音频格式。我想编写一个基于 Web 的应用程序来确定文件使用的视频/音频编解码器。
如何最好地以编程方式确定视频编解码器?最好通过系统调用使用标准库并解析其输出?(例如ffmpeg、转码等?)
mplayer -identify
会成功的。只需调用ffmpeg
一个文件也可以——它会在开始时自动打印一组关于输入文件的信息,而不管你告诉 ffmpeg 实际做什么。
当然,如果您想从您的程序中执行此操作,而不需要对外部程序进行 exec 调用,您可以只包含 avcodec 库并直接运行它自己的识别例程。
虽然您可以实现自己的检测,但考虑到 libav* 支持的绝对大量的格式,它肯定不如现有的例程。这将是一个相当愚蠢的重新发明轮子的案例。
Linux 的“文件”命令也可以做到这一点,但它打印出的数据量取决于视频格式。例如,在 AVI 上,它会提供有关分辨率、FOURCC、fps 等的各种数据,而对于 MKV 文件,它只会显示“Matroska 数据”,而不会告诉您内部结构,甚至是使用的视频和音频格式。
我在 perl 脚本中使用了 FFMPEG 来实现这一点。
$info = `ffmpeg -i $path$file 2>&1 /dev/null`;
@fields = split(/\n/, $info);
只需找出您需要提取的 @fields 中的哪些项目。
您需要进一步开始。您需要了解容器格式以及它如何指定编解码器。
所以我会从一个识别容器格式的程序开始(不仅仅是从扩展,进入标题并确定真正的容器)。
然后找出您的程序将支持哪些容器,并放入解析存储在容器中的元数据所需的函数,其中将包括编解码器。
-亚当
您确实需要一个大型二进制识别标记数据库,以便在文件开头附近查找。幸运的是,您的问题被标记为“Linux”,并且那里已经存在这样的数据库;file(1) 将为您完成这项工作。
我建议使用ffprobe
并将输出格式强制为 json。解析起来会容易得多。最简单的例子:
$meta = json_decode(join(' ', `ffprobe -v quiet -print_format json -show_format -show_streams /path/to/file 2>&1`));
请注意,在文件损坏的情况下,您将null
根据您的错误报告设置获得结果和警告。具有正确错误处理的完整示例:
$file = '/path/to/file';
$cmd = 'ffprobe -v quiet -print_format json -show_format -show_streams ' . escapeshellarg($file).' 2>&1';
exec($cmd, $output, $code);
if ($code != 0) {
throw new ErrorException("ffprobe returned non-zero code", $code, $output);
}
$joinedOutput = join(' ', $output);
$parsedOutput = json_decode($joinedOutput);
if (null === $parsedOutput) {
throw new ErrorException("Unable to parse ffprobe output", $code, $output);
}
//here we can use $parsedOutput as simple stdClass
您可以使用媒体信息:
sudo apt-get install mediainfo
如果您只想获取视频/音频编解码器,可以执行以下操作:
$videoCodec = `mediainfo --Inform="Video;%Format%" $filename`;
$audioCodec = `mediainfo --Inform="Audio;%Format%" $filename`;
如果您想捕获更多信息,可以解析 mediainfo 返回的 XML 输出。这是示例函数:
function getCodecInfo($inputFile)
{
$cmdLine = 'mediainfo --Output=XML ' . escapeshellarg($inputFile);
exec($cmdLine, $output, $retcode);
if($retcode != 0)
return null;
try
{
$xml = new SimpleXMLElement(join("\n",$output));
$videoCodec = $xml->xpath('//track[@type="Video"]/Format');
$audioCodec = $xml->xpath('//track[@type="Audio"]/Format');
}
catch(Exception $e)
{
return null;
}
if(empty($videoCodec[0]) || empty($audioCodec[0]))
return null;
return array(
'videoCodec' => (string)$videoCodec[0],
'audioCodec' => (string)$audioCodec[0],
);
}