可能重复:
ffmpeg:转换前后的视频;t相同长度的
最近,我一直在尝试将FFmpeg用于一个应用程序,该应用程序在时间参数(毫秒分辨率)方面需要非常准确的操作。不幸的是,我惊讶地发现FFmpeg的操作功能返回了一些不准确的结果。
以下是"ffmpeg"的输出:
ffmpeg version 0.11.1 Copyright (c) 2000-2012 the FFmpeg developers
built on Jul 25 2012 19:55:05 with gcc 4.2.1 (Apple Inc. build 5664)
configuration: --enable-gpl --enable-shared --enable-pthreads --enable-libx264 --enable-libmp3lame
libavutil 51. 54.100 / 51. 54.100
libavcodec 54. 23.100 / 54. 23.100
libavformat 54. 6.100 / 54. 6.100
libavdevice 54. 0.100 / 54. 0.100
libavfilter 2. 77.100 / 2. 77.100
libswscale 2. 1.100 / 2. 1.100
libswresample 0. 15.100 / 0. 15.100
libpostproc 52. 0.100 / 52. 0.100
现在,让我们假设我想翻录"foo.mov"的音轨
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'foo.mov':
Metadata:
major_brand : qt
minor_version : 0
compatible_brands: qt
creation_time : 2012-07-24 23:16:08
Duration: 00:00:40.38, start: 0.000000, bitrate: 805 kb/s
Stream #0:0(und): Video: h264 (Baseline) (avc1 / 0x31637661), yuv420p, 480x360, 733 kb/s, 24.46 fps, 29.97 tbr, 600 tbn, 1200 tbc
Metadata:
rotate : 90
creation_time : 2012-07-24 23:16:08
handler_name : Core Media Data Handler
Stream #0:1(und): Audio: aac (mp4a / 0x6134706D), 44100 Hz, mono, s16, 63 kb/s
Metadata:
creation_time : 2012-07-24 23:16:08
handler_name : Core Media Data Handler
您可能已经注意到,视频文件的持续时间为00:00:44.38。使用以下命令,我撕下了它的音轨:
"ffmpeg-i foo.mov foo.wav"
输出:
Output #0, wav, to 'foo.wav':
Metadata:
major_brand : qt
minor_version : 0
compatible_brands: qt
creation_time : 2012-07-24 23:16:08
encoder : Lavf54.6.100
Stream #0:0(und): Audio: pcm_s16le ([1][0][0][0] / 0x0001), 44100 Hz, mono, s16, 705 kb/s
Metadata:
creation_time : 2012-07-24 23:16:08
handler_name : Core Media Data Handler
Stream mapping:
Stream #0:1 -> #0:0 (aac -> pcm_s16le)
Press [q] to stop, [?] for help
size=3482kB time=00:00:40.42 bitrate= 705.6kbits/s
video:0kB audio:3482kB global headers:0kB muxing overhead 0.001290%
正如您所看到的,输出文件比输入中的文件长。
另一个例子是音频(和视频)文件修剪:假设我想使用ffmpeg进行音频文件修剪。我使用了下一个命令:
'ffmpeg-t 00:00:10.000-i foo.wav trimmed_fo.wav-ss 00:00:25.000'
输出:
[wav @ 0x10180e800] max_analyze_duration 5000000 reached at 5015510
Guessed Channel Layout for Input Stream #0.0 : mono
Input #0, wav, from 'foo.wav':
Duration: 00:00:40.42, bitrate: 705 kb/s
Stream #0:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 44100 Hz, mono, s16, 705 kb/s
Output #0, wav, to 'trimmed_foo.wav':
Metadata:
encoder : Lavf54.6.100
Stream #0:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 44100 Hz, mono, s16, 705 kb/s
Stream mapping:
Stream #0:0 -> #0:0 (pcm_s16le -> pcm_s16le)
Press [q] to stop, [?] for help
size=864kB time=00:00:10.03 bitrate= 705.6kbits/s
video:0kB audio:864kB global headers:0kB muxing overhead 0.005199%
同样,输出文件比我预期的要长30毫秒。
很长一段时间以来,我试图研究这个问题,但没有成功。当我对相同的功能使用大胆时,它做得非常准确!
有人知道如何解决这个问题吗?
TL;DR:FFmpeg和您的iOS设备不适合您的需求。
有很多问题需要解决,所以没有特别的顺序:
-
无论是FFmpeg还是您正在使用的底层编解码器都不是为您想要的时间分辨率而设计的。40ms是每秒25帧的1帧,这在大多数视频和音频文件中并不算多。超精确定时不是常见音频编解码器的设计特征,比如源AAC数据,FFmpeg也紧随其后。
-
不要进行任何代码转换!如果你想尽可能少地更改数据。。。不要更改它。你可以使用
ffmpeg -i in.mov -c:a copy out.m4a
来准确地提取音频流,而不是将其转码为wav格式。 -
使用FFprobe而不是FFmpeg来获取文件信息。FFmpeg只是提供了一些关于输入和输出文件的粗略信息,因为它的默认日志记录过于冗长。FFprobe通常与FFmpeg捆绑在一起,专门设计用于以方便的形式提取信息。使用
ffprobe -show_streams -show_format in.mov
获取信息。 -
增加你的
-analyzeduration
!您可能已经注意到输出中关于max_analyze_duration reached
的注释。根据文档,在FFmpeg估计总长度之前,文件将实际读取多少微秒。同样,对于大多数目的来说,将文件长度精确到微秒是不可行或不可取的,而且成本高昂。如果您想要超精确性,请确保该参数设置得更高,可能比实际输入更长。 -
要更加小心你的期权放置。这是一个很小的问题,但我想我应该把它提出来,以防你不知道。FFmpeg的许多选项的行为不同,这取决于它们相对于输入和输出的顺序。特别是您正在使用的
-ss
。你在输入之后有它,这就是你想要的地方,但你在开头也有只输出的选项-t
,这很奇怪。更自然的命令方式是:ffmpeg -i foo.wav -ss 00:00:25.000 -t 00:00:10.000 trimmed_foo.wav
-
所有定时命令都接受以秒为单位的输入(包括小数秒),因此不必用
00:00:
来准备所有内容。 -
区分容器长度和实际流长度。我不使用Audacity,但如果它显示出极高的准确性,我不会感到惊讶,因为它在做什么时对你撒谎。实际上,以毫秒精度修剪音频或视频数据不仅需要选择输入中的哪些帧包含在输出中(在25fps下精确到40ms!),还需要更改帧数据以在结尾插入静音。更容易的是,只需根据帧包含进行修剪,然后将超精确的长度放入容器文件元数据中。一些播放软件实际上可能会根据这个数字而中断,但同样,大多数AV软件并不是为这个准确度而设计的。我很想看看FFmpeg显示的是Audacity修剪的文件长度。
这就是现在脑海中浮现的全部内容,但一旦你有机会结合以上内容,我很乐意提供更多反馈。我的猜测是,这种准确性是研究拘谨所必需的,在这种情况下,快乐的研究!