ffmpeg -r 25 -i 348.mp4 -vcodec libx264 -s 640x360 -aspect 640:360 -f mp4 -r 25 out.mp4
转码成功!问题解决,视频不再丢失,视频中间编辑插入的静态图片也可以正常显示。
事后推测了一下原因,有待进一步确认,欢迎大拿解惑:
1 视频中插入了静态图片,静态图片存储的帧率很可能是1,或者至少也是和原视频25帧是不相同的。
2 视频是多个视频拼接的,不同的视频之间也很可能存在帧率不相同,所以导致以一个动态的帧率去读取视频后按统一帧率输出的时候出现问题。
后续再继续深入研究MP4的视频格式,以及视频信息是如果存储的,这里面要学习的东西太多了。
上篇说到解决的方法以及推测,这篇继续深入说说后来的一些发现
1、-r参数:
‘-r[:stream_specifier] fps (input/output,per-stream)’
Set frame rate (Hz value, fraction or abbreviation).
As an input option, ignore any timestamps stored in the file and instead generate timestamps assuming constant frame rate fps.
As an output option, duplicate or drop input frames to achieve constant output frame rate fps.
作为输入选项,忽略任何存储在文件时间戳,而生成时间戳假设固定帧速率的fps。这里特别注意一下: ignore any timestamps stored in the file,忽略任何存储在文件里的时间戳。实际上正是因为忽略原因时间戳,生成了新的时间戳,才保证了视频转码的成功。
2、-vf showinfo:查看视频帧详情滤镜
这个滤镜会将视频每一帧的详细信息都输出,在做视频详细分析的时候很好用,具体的参数信息可以参考FFmpeg官方文档:
http://ffmpeg.org/ffmpeg-filters.html#showinfo
当我把整个视频的showinfo信息都输出到文件里查看时,发现里重复的时间戳:
[Parsed_showinfo_0 @ 0x266c740] n:0 pts:0 pts_time:0 pos:324675 fmt:yuv420p sar:1/1 s:1280x720 i:P iskey:1 type:I checksum:A5217CD1 plane_checksum:[308C60A8 4FA1B85C A41363BE]
[Parsed_showinfo_0 @ 0x266c740] n:1 pts:1200 pts_time:0.04 pos:370498 fmt:yuv420p sar:1/1 s:1280x720 i:P iskey:0 type:B checksum:CF15D48E plane_checksum:[CB69A1EF 637DBF49 5FAF7347]
[Parsed_showinfo_0 @ 0x266c740] n:2 pts:2400 pts_time:0.08 pos:373819 fmt:yuv420p sar:1/1 s:1280x720 i:P iskey:0 type:B checksum:5974D3B6 plane_checksum:[53AAA123 0C00BF3F 976C7345]
[Parsed_showinfo_0 @ 0x266c740] n:8001 pts:1200pts_time:0.04 pos:193039178 fmt:yuv420p sar:1/1 s:1280x720 i:P iskey:0 type:B checksum:82A44DE5 plane_checksum:[8C58E469 A22C2B6F BD6D3DFE]
[Parsed_showinfo_0 @ 0x266c740] n:8002 pts:2400 pts_time:0.08 pos:193044398 fmt:yuv420p sar:1/1 s:1280x720 i:P iskey:0 type:B checksum:8D024E55 plane_checksum:[2F9BE463 CDA42BB3 0D943E30]
[Parsed_showinfo_0 @ 0x266c740] n:8003 pts:3600 pts_time:0.12 pos:193025293 fmt:yuv420p sar:1/1 s:1280x720 i:P iskey:0 type:P checksum:DD4E870A plane_checksum:[A54708BD 3AFD263D 26455810]
这个应该才是导致转码失败的核心问题,由于用编辑软件拼接的视频,没有很好地处理时间戳,导致视频出现了相同的时间戳,在转码的时候,后面部分重复时间戳的视频内容被丢弃,导致视频和音频不同步,视频转码后时间变短。而-r参数正好可以抛弃原有时间戳,生成新的时间戳,从而保证了转码的成功。
3、-vsync:对视频帧和时间戳处理的另外一个参数
‘-vsync parameter’
Video sync method. For compatibility reasons old values can be specified as numbers. Newly added values will have to be specified as strings always.
Each frame is passed with its timestamp from the demuxer to the muxer.
Frames will be duplicated and dropped to achieve exactly the requested constant frame rate.
Frames are passed through with their timestamp or dropped so as to prevent 2 frames from having the same timestamp.
As passthrough but destroys all timestamps, making the muxer generate fresh timestamps based on frame-rate.
Chooses between 1 and 2 depending on muxer capabilities. This is the default method.
Note that the timestamps may be further modified by the muxer, after this. For example, in the case that the format option ‘avoid_negative_ts’ is enabled.
With -map you can select from which stream the timestamps should be taken. You can leave either video or audio unchanged and sync the remaining stream(s) to the unchanged one.
从官方文档里可以看到,使用-vsync drop同样可以得到跟-r参数一样的效果,实验了一下,果然也可以成功转码。并且这个参数可以有更大的自由度,可以使用不同的模式去控制视频帧。
但是以上的解决办法目前都遇到一个问题,就是在一个通用的转码命令里,在视频是可变帧率的情况下,以及视频实际帧率和容器里申明的帧率不一致的情况下,会导致转码后的视频帧率出现错误,还得进一步研究同样的识别和转码方案。