FFMPEG:当输入为可变帧频视频时,如何避免交叉渐变剪辑的输出中的音频/视频不同步

时间:2018-12-21 20:30:50

标签: ffmpeg

我正在使用NVIDIA显卡GeForce Experience硬件记录(NVEC编码器)对游戏性(Dota2)进行屏幕记录。这将创建可变帧率输出视频。我的NVIDIA设置为60 fps 15000 kbps。我付钱给一个人制作了一个程序,该程序可以生成脚本,给定开始/停止时间点可以从视频中提取剪辑,并将它们与crossfade合并。请参见下面的示例代码。该脚本适用于许多输入记录,但经常失败:在许多剪辑中,音频和视频不同步(通常是音频延迟),大约0.5秒。我认为当录制期间帧频下降更多时,故障会更多。他不知道如何解决该问题,我想知道是否有人指出脚本中是否可以解决任何问题(下面的示例)?

处理速度非常重要(现在制作10分钟的“突出显示”视频大约需要7-10分钟)。不幸的是,大大增加该数量的解决方案并没有太大的意义。他的方法是将音频和视频分开工作,最后进行合并。他已经有一个程序可以制作ffmpeg代码,以用于不同的场景(还可以添加叠加,添加音乐,前奏/外奏),因此最好对他的代码进行一些简单的修复,而不用对逻辑进行大幅度的重新设计。但是,如果没有其他方法可以解决问题,则可以重新设计逻辑。使用ffmpeg以外的其他工具也是可以的,但是应该是可自动化的(脚本/ cli),并且不会增加处理时间。

在输入视频上运行程序“ mediainfo”显示该输入视频的帧率降低得很低:

帧频模式:可变

帧速率:60.000 FPS

最低帧频:3.059帧/秒

最大帧速率:63.739 FPS

完整报告在这里:https://pastebin.com/TX061Wih

可以从此处的保管箱下载输入视频(6 GB): https://www.dropbox.com/s/ftwdgapazbi62pr/fullgame.mp4?dl=0

这里是一个脚本示例,当要求从9:57(41秒长)和15:45(28秒长)的输入视频中提取两个剪辑,并进行淡入淡出合并时,交叉淡入淡出时间为0.5。在此示例中可能没有使用一些来自选项的代码残留(覆盖,音乐,前奏/外奏)。使用上面的输入视频,这将创建音频/视频不同步。

依次执行6条命令:

ffmpeg.exe -loglevel warning -ss 00:09:57 -i fullgame.mp4 -t 00:00:41 -filter_complex "[0:a]afade=t=out:st=40.5:d=0.5[a1]" -map "[a1]" -y out_temp_00.mp4.wav

ffmpeg.exe -loglevel warning -i fullgame.mp4 -ss 00:09:57 -t 00:00:41 -an -vcodec copy -f mpegts -avoid_negative_ts make_zero -y out_temp_00.mp4.ts

ffmpeg.exe -loglevel warning -ss 00:15:45 -i fullgame.mp4 -t 00:00:28 -filter_complex "[0:a]afade=t=in:st=0:d=0.5[a1]" -map "[a1]" -y out_temp_01.mp4.wav

ffmpeg.exe -loglevel warning -i fullgame.mp4 -ss 00:15:45 -t 00:00:28 -an -vcodec copy -f mpegts -avoid_negative_ts make_zero -y out_temp_01.mp4.ts

ffmpeg.exe -loglevel warning -i out_temp_00.mp4.wav -i out_temp_01.mp4.wav -y -filter_complex "[0:a]adelay=0|0[a0];[1:a]adelay=40500|40500[a1];[a0][a1]amix=inputs=2:dropout_transition=68.5,atrim=duration=68.5[outa0];[outa0]loudnorm[outa]" -map "[outa]" -ar 48000 -acodec aac -strict -2 fullgame_Output.mp4.aac

ffmpeg.exe -loglevel warning -i out_temp_00.mp4.ts -i out_temp_01.mp4.ts -y -i fullgame_Output.mp4.aac  -filter_complex "[0:v]trim=start=0.5,setpts=PTS-STARTPTS[0c];[1:v]trim=start=0.5,setpts=PTS-STARTPTS[1c];[0:v]trim=40.5:41,setpts=PTS-STARTPTS[fo];[1:v]trim=0:0.5[fi];[fi]format=pix_fmts=yuva420p,fade=t=in:st=0:d=0.5:alpha=1[z];[fo]format=pix_fmts=yuva420p,fade=t=out:st=0:d=0.5:alpha=1[x];[z]fifo[w];[x]fifo[q];[q][w]overlay[r];[0c][r][1c]concat=n=3[outv]" -map "[outv]" -map 2:a -shortest -acodec copy -vcodec libx264 -preset ultrafast -b 15000k -aspect 1920:1080 fullgame_Output.mp4

P.S。

我已经在ffmpeg聊天室寻求帮助。一个人说他知道问题出在哪里,但不知道如何解决(?):

[00:10] <kepstin> oh, wait, you're using -vcodec copy
[00:10] <kepstin> that explains everything.
[00:10] <kepstin> when you're using -vcodec copy, the start time (set with -ss) is rounded to the nearest keyframe
[00:10] <kepstin> it's not exact
[00:11] <kepstin> depending on the keyframe interval, this will result in possibly quite large shifts
[00:11] <kepstin> (also, your commands are applying audio filters on commands with -an, which is confusing/contradictory)
[00:12] <birdboy88> so the problem is that the audio temporary clips are not being extracted from the same excat timepoints?
[00:13] <kepstin> birdboy88: yeah, your audio is being re-encoded to wav so it's being cut sample-accurate, but the video's not being precisely cut.
[00:16] <birdboy88> kepstin: so I need to use slow seek (?) to extract video accurately? Or somehow extract audio only where there are video keyframes?
[00:17] <kepstin> birdboy88: i don't know how to extract audio starting at video keyframes with ffmpeg cli. You're already doing slow seek, which doesn't help (you should move the -ss option to before the -i option to speed it up)
[00:17] <kepstin> if you want accurate video cutting when saving to a file, you have to re-encode the video
[00:18] <kepstin> (doing this in a single ffmpeg command means you don't have to save to a file, so you can avoid the issue)
[00:18] * kepstin is off for a bit now

编辑: 一切都使用最新的ffmpeg版本完成。

我无法让Gyan的代码正常工作。它总是会丢失一些音频(音频为40.5或27.5,因此仅使用一种音频)。这是唯一对我有用的工具(更改为adelay = 40500 | 40500和amix = inputs = 2 [a0]; [a0] loudnorm):

ffmpeg -i fullgame.mp4 -filter_complex "[0]split=2[vpre][vpost];
[0]asplit=2[apre][apost];
[vpre]trim=start='00:09:57':duration='00:00:41',setpts=PTS-STARTPTS[vpre-t];
[apre]atrim=start='00:09:57':duration='00:00:41',asetpts=PTS-STARTPTS,afade=t=out:st=40.5:d=0.5[apre-t];
[vpost]trim=start='00:15:45':duration='00:00:28',setpts=PTS-STARTPTS,format=yuva420p,fade=t=in:st=0:d=0.5:alpha=1,setpts=PTS+40.5/TB[vpost-t];
[apost]atrim=start='00:15:45':duration='00:00:28',asetpts=PTS-STARTPTS,afade=t=in:st=0:d=0.5,adelay=40500|40500[apost-t];
[vpre-t][vpost-t]overlay[v];
[apre-t][apost-t]amix=inputs=2[a0];[a0]loudnorm[a]" -map "[v]" -map "[a]" -y -c:v libx264 -preset ultrafast -b:v 15000k -aspect 1920:1080 -c:a aac fullgame_Output.mp4

然后,我尝试使用类似的设置,但包含3个剪辑,但是在一台计算机上出现错误:“筛选时出错:无法分配内存”。而我的16 GB内存机器的处理速度是0.02倍!有什么办法可以避免这种情况?这是我尝试的代码:

ffmpeg -i fullgame.mp4 -filter_complex "[0]split=3[vpre][vpost][v3];
[0]asplit=3[apre][apost][a3];
[vpre]trim=start=357:duration=41,setpts=PTS-STARTPTS[vpre-t];
[apre]atrim=start=357:duration=41,asetpts=PTS-STARTPTS,afade=t=out:st=40.5:d=0.5[apre-t];
[vpost]trim=start=795:duration=28,setpts=PTS-STARTPTS,format=yuva420p,fade=t=in:st=0:d=0.5:alpha=1,fade=t=out:st=40.5:d=0.5:alpha=1,setpts=PTS+40.5/TB[vpost-t];
[apost]atrim=start=795:duration=28,asetpts=PTS-STARTPTS,afade=t=in:st=0:d=0.5,afade=t=out:st=27.5:d=0.5,adelay=40500|40500[apost-t];
[v3]trim=start=95:duration=30,setpts=PTS-STARTPTS,format=yuva420p,fade=t=in:st=0:d=0.5,setpts=PTS+41+28-0.5/TB[v3-t];
[a3]atrim=start=95:duration=30,asetpts=PTS-STARTPTS,afade=t=in:st=0:d=0.5,adelay=68500|68500[a3-t];
[vpre-t][vpost-t]overlay[v1];
[v1][v3-t]overlay[v];
[apre-t][apost-t][a3-t]amix=inputs=3[a0];
[a0]loudnorm[a]" -map "[v]" -map "[a]" -y -c:v libx264 -preset ultrafast -b:v 15000k -aspect 1920:1080 -c:a aac fullgame_Output.mp4

1 个答案:

答案 0 :(得分:0)

只需执行一个命令即可。

除了关键帧查找问题(确实如此)之外,您当前的序列在最后一个命令中还有错误。您有[0:v]trim=start=0.5...[0c],它会修剪前0.5秒,并会导致其自身不同步。由于这是第一个剪辑,因此应为[0:v]trim=0:40.5

完整的单个命令应为

ffmpeg -i fullgame.mp4 -filter_complex
       "[0]split=2[vpre][vpost];[0]asplit=2[apre][apost];
        [vpre]trim=start='00:09:57':duration='00:00:41',setpts=PTS-STARTPTS[vpre-t];
        [apre]atrim=start='00:09:57':duration='00:00:41',asetpts=PTS-STARTPTS,afade=t=out:st=40.5:d=0.5[apre-t];
        [vpost]trim=start='00:15:45':duration='00:00:28',setpts=PTS-STARTPTS,format=yuva420p,fade=t=in:st=0:d=0.5:alpha=1,setpts=PTS+40.5/TB[vpost-t];
        [apost]atrim=start='00:15:45':duration='00:00:28',asetpts=PTS-STARTPTS,afade=t=in:st=0:d=0.5[apost-t];
        [vpre-t][vpost-t]overlay[v];
        [apre-t][apost-t]acrossfade=d=0.5,loudnorm,aresample=48000[a]"
       -map "[v]" -map "[a]" -c:v libx264 -preset ultrafast -b:v 15000k -aspect 1920:1080 -c:a aac fullgame_Output.mp4

您的原始序列包含-strict -2用于音频AAC编码。自2015年12月以来就不再需要它了。如果ffmpeg抛出错误而没有该错误,则您的ffmpeg版本非常旧。首先升级。


我没有对您的文件进行上述测试,因为过滤16分钟的全高清60 fps视频会花费很长时间,但是我测试了以下更快的命令,并且在ffmpeg的最新git版本中可以正常工作:< / p>

ffmpeg -ss 00:09:57 -t 00:00:41 -i fullgame.mp4 -ss 00:15:45 -t 00:00:28 -i fullgame.mp4 -filter_complex
       "[0]afade=t=out:st=40.5:d=0.5[apre-t];
        [1]format=yuva420p,fade=t=in:st=0:d=0.5:alpha=1,setpts=PTS+40.5/TB[vpost-t];
        [1]afade=t=in:st=0:d=0.5[apost-t];
        [0][vpost-t]overlay[v];
        [apre-t][apost-t]acrossfade=d=0.5,loudnorm,aresample=48000:ocl=stereo[a]"
       -map "[v]" -map "[a]" -c:v libx264 -preset ultrafast -b:v 15000k -aspect 1920:1080 -c:a aac fullgame_Output.mp4
相关问题