我正在使用 ffmpeg 在 CentOS Web 服务器上处理用户上传的视频。我需要将每个视频转换为标准大小和格式,然后从每个视频中提取 30 秒的样本剪辑。我想在提取命令中使用“-vcodec copy”标志,以避免第二次编码。
此命令适用于我的初始转换:
ffmpeg -i uploaded.mov -f mp4 -vcodec libx264 -vpre medium -acodec libfaac -r 15 -b 360k -ab 48k -ar 22050 -s 480x320 formatted.mp4
和这个有时提取工作:
ffmpeg -i formatted.mp4 -vcodec copy -acodec copy -ss 0 -t 30 formatted_sample.mp4
但是,当我对某些视频运行提取命令时,提取的样本剪辑以几秒钟的空白视频开始。音频立即开始,但视频在 3-6 秒内不会开始。
为了演示这个问题,我上传了两个视频片段并在其上运行了上述命令。我在 Final Cut Express 中创建了第一个片段,并在将其上传到 Web 服务器之前使用 Handbrake 对其进行了编码:
1a)已上传的片段
1b)使用第一个命令转换
相比之下,第二个视频来自苹果网站,并没有显示出这个问题:
2a)已上传的片段
2b)使用第一个命令转换
2c)用第二条命令提取,没问题
有人能看出这两个源剪辑有什么不同吗?如果能,我可以在转换命令中做些什么,以便在提取命令运行时设置剪辑以避免丢失视频?
顺便说一句,我最初从 yum 安装的 ffmpeg 0.6.1 遇到了问题,但我升级到最新的 git 版本,问题仍然存在。
答案1
Matt 关于关键帧的建议,加上及时发布到 ffmpeg 邮件列表的提示,让我找到了解决方案,尽管我不确定这是否是最好的解决方案。
首先,我必须将提取命令中的 -ss 和 -t 选项移到 -i 选项之前。这样提取将从下一个最早的关键帧开始。假设我使用 -ss 25 -t 15 从剪辑中的 0:25 到 0:40 提取,但关键帧每 10 秒一次。以前,我会得到一个 15 秒的样本,从 5 秒的空白视频开始。现在,我将得到一个 20 秒的样本,从 0:20 到 0:40,但没有空白视频。换句话说,我避免了空白视频,但失去了剪辑选择的准确性。
为了解决这个问题,我不得不在转换命令中添加 -g 选项来重新格式化关键帧。我使用 -g 15 和 -r 15 每秒制作一个关键帧。这允许我选择最接近秒的采样位置,因此 -ss 25 -t 15 将为我提供我要求的 15 秒剪辑。我预计额外的关键帧会使我的完整剪辑更大,但在我的测试中它只大了约 2%,这对我的项目来说是一个很好的权衡。
因此,我将上面的两个命令改为:
ffmpeg -i uploaded.mov -f mp4 -vcodec libx264 -vpre medium -acodec libfaac -r 15 -g 15 -b 360k -ab 48k -ar 22050 -s 480x320 formatted.mp4
ffmpeg -ss 0 -t 30 -i formatted.mp4 -vcodec copy -acodec copy formatted_sample.mp4
一切似乎都很好。如果有人有更有效的解决方案,请发布,我会更改我选择的答案。