【后期制作】网课剪辑:自动化流程基于免费软件

wish
发布于 2023-12-16 / 44 阅读
0
0

【后期制作】网课剪辑:自动化流程基于免费软件

应用场景

网课剪辑:

  • 大批次旧网课需要替换片头片尾,这些网课格式(编码、分辨率、帧率、音频格式等)均不一致

  • 大批次新网课录制源文件需要处理,主要需要进行声音降噪统一、空白内容删除、添加片头片尾

  • 基于文稿的快速切片流程以及内容检查(部分课程因内容被举报而需要剪辑)

需求拆分

旧网课

  • 需求:替换=删除+添加, 格式统一

  • 难点:每批次网课格式不一、片头片尾长度不统一→不能所有一起处理,只能一批批处理

新网课

  • 需求:音频处理,空白内容删除,添加片头片尾

  • 难点:空白内容自动识别

快速切片及检查

  • 需求:快速检查=语音转文字+快速剪辑

环境选择

片头片尾处理

FFmpeg

音频批处理

Audacity+免费vst

空白内容处理

自动剪辑神器

快速切片及检查

语音转文字方案1:剪映专业版

语音转文字方案2:FastWhisperGUI

快速剪辑:Losslesscut

根据字幕剪辑视频方案1:Autocut(命令行,不推荐)

根据字幕剪辑视频方案2:MediaToolkit(GUI,推荐)

FFmpeg

FFmpeg 是一个开源的音视频处理工具,诞生已22年。它可以用来处理音视频的编解码、格式转换、剪辑、合并、抽取、压缩、解压缩、滤镜、字幕等等。它可以在 Windows、Linux、Mac 等多种平台上使用。

FFmpeg GUI

令人欣喜的是,我们现阶段并不需要完全使用命令行执行ffmpeg,而是使用一些GUI图形界面实现,以下介绍一些好用的开源软件

losslesscut

QuickCut

  • 开源地址:https://gitee.com/haujet/QuickCut

  • 压缩视频、转码视频、倒放视频、合并片段、根据字幕裁切片段、自动配字幕、自动剪辑……功能非常多

  • 没有针对批处理优化

格式工厂

  • 不开源,不要下载最新版本(有流氓后台)

  • 但是旧版本是可以用的

FFmpeg Batch AV Converter

片头片尾批处理

测试多款FFmpeg GUI,要么功能不完善,要么自定义性太低,要么可能运行出错,最终没有一款能够令人满意的软件成品。不过,FFmpeg毕竟是命令行软件,批量化处理可以通过写脚本实现,以下是一些已经实现好的脚本。

最终根据最简化原则选用bat文件+ffmpeg编写脚本方案,参考网络资源,结合生成式人工智能辅助代码编写

实操流程:视频切割

视频切割的实现难点在于FFmpeg并无由后向前的检索功能,需要获取全长之后计算结束时间,再进行切割,功能较为简单,但是实践上市面上各种GUI在批处理我这些格式不太规范的网课时常常出现问题(猜测有可能是动态帧率、音频或者GUI封装等问题,会有报错的情况,更多的是正常运行但输出的视频有片段缺失、音画错位等问题),最终还是脚本运行能够完全正确地应对所有视频。

@echo off&title MP4 批量掐头去尾(运行版)
setlocal enabledelayedexpansion
echo 该脚本可以批量将目录内MP4文件,从头尾裁减固定时间。(如将多个视频,开头剪3s,结尾剪5s)
echo 如需批量指定视频的开始结束时间,请打开另一个脚本。(如指定多个视频,都从1分12秒开始,到5分27秒结束)
echo 如果您是从其他地方获取的该脚本,请先看一下b站视频,有详细介绍,谢谢。https://www.bilibili.com/video/BV1ic411N7ny/
echo 该脚本基于ffmpeg,请确保您已将ffmpeg添加到环境。
echo 时间作差部分依靠 @随风 @https://pokes.blog.csdn.net/
echo 获取视频文件时长借鉴 @亦良Cool @https://blog.csdn.net/annita2019/article/details/128747458
echo 作者虎啸ROAR b站:https://space.bilibili.com/19075528 个人网站:https://www.luotianyi.blue

rem 提示用户输入开头裁剪的时间,或者跳过
echo 若当前选项为0,可直接按回车
set /p sh=请输入开头切割的 小时部分(如开头无需切割,输入-1):
if "%sh%" == "-1" goto zs  
if not "%sh%" == "-1" goto os
:zs
set st=00:00:00.00
echo 开头裁剪时长 %st%
goto end
exit
:os
rem 用户输入小时、分钟、秒和毫秒,设置开头裁剪时间
set sh=00
set /p sm=请输入开头切割的 分钟部分:
if "%sm%" == ""  set sm=00
set /p ss=请输入开头切割的 秒部分:
if "%ss%" == ""  set ss=00
set /p sms=请输入开头切割的 毫秒部分:
if "%sms%" == ""  set sms=00
set st=%sh%:%sm%:%ss%.%sms%
echo 开头裁剪时长 %st%
goto end
exit

:end
rem 提示用户输入结尾裁剪的时间,或者跳过
set /p eh=请输入结尾切割的 小时部分(如结尾无需切割,输入-1):
if "%eh%" == "-1" ( goto ze) else ( goto oe)
exit

:ze
set et=00:00:00.00
echo 结尾裁剪时长 %et%
goto fin
exit
:oe
rem 用户输入小时、分钟、秒和毫秒,设置结尾裁剪时间
set eh=00
set /p em=请输入开头切割的 分钟部分:
if "%em%" == ""  set em=00
set /p es=请输入开头切割的 秒部分:
if "%es%" == ""  set es=00
set /p ems=请输入开头切割的 毫秒部分:
if "%ems%" == ""  set ems=00
set et=%eh%:%em%:%es%.%ems%
echo 结尾裁剪时长 %et%
goto fin
exit
:fin

rem set st=0
rem set et=00:00:02.80 
rem 创建结果目录
cd /d %~dp0
md result

rem 对每个MP4文件进行裁剪
for /f "delims=" %%i in ('dir /b /s /a-d *.mp4') do (
rem 获取视频持续时间
for /f "tokens=2 delims=, " %%a in ('ffmpeg -i "%%i" 2^>^&1 ^| find "Duration:"') do (
    set str=%%a
)
rem 设置裁剪结束时间为输入的结束时间
set time=%et%:!str!
set t=!time!
call :time0 "!t!" "!time!" ok
echo  本视频开始时间为 %st%  结束时间为:!ok!
rem 执行裁剪操作
ffmpeg -ss %st% -to !ok! -accurate_seek -i "%%~si" -c:v copy -c:a copy "result\%%~ni.mp4"
)

pause

rem 将输入的时间转换为ffmpeg可识别的格式
:time0  
@echo off&setlocal&set /a n=0
for /f "tokens=1-8 delims=.: " %%a in ("%~1:%~2") do (
set /a n+=10%%a%%100*360000+10%%b%%100*6000+10%%c%%100*100+10%%d%%100
set /a n-=10%%e%%100*360000+10%%f%%100*6000+10%%g%%100*100+10%%h%%100)
set /a s=n/360000,n=n%%360000,f=n/6000,n=n%%6000,m=n/100,n=n%%100
set "ok=%s%:%f%:%m%.%n%"
endlocal&set %~3=%ok:-=%

实操流程:视频合并

视频合并按理来说是更容易实现的,但是全网看下来没有直接可用的参考,于是当时完全不懂编程的我通过GPT边学边写探索出了完全不会出问题的视频合并方案。

编写时出现的问题:FFmpeg提供了两种合并方式,针对MPEG格式的concat协议直接连接和通用的concat分离器连接,均可以采用无损和重新编码方式进行连接。但是经过测试,规格不同的视频合并后可能会有无法预测的结果。

最终选用使用 FFmpeg concat 过滤器(filter_complex) 重新编码(有损),即在拼接重新编码之前,先统一编码格式各项参数。虽然需要消耗时间,但是最为保险。经过测试,发现统一以下五个要素后在我的项目中即可应对所有视频:视频帧率、分辨率、像素宽高比(怎么会有人不选1:1导致这里会不一致啊喂(#`O′))和音频采样率、音频通道数。

rem 此为核心内容

for %a in ("*.mp4") do
ffmpeg -i ".\input\op.mp4" -i %a -i .\output\ed.mp4" -filter_complex "[0:v]fps=30,scale=1280:720,setsar=1[v0];[1:v]fps=30,scale=1280:720,setsar=1[v1];[2:v]fps=30,scale=1280:720,setsar=1[v2];[0:a]aformat=sample_rates=44100:channel_layouts=stereo[a0];[1:a]aformat=sample_rates=44100:channel_layouts=stereo[a1];[2:a]aformat=sample_rates=44100:channel_layouts=stereo[a2];[v0][a0][v1][a1][v2][a2]concat=n=3:v=1:a=1[vout][aout]" -map "[vout]" -map "[aout]" -c:v libx264 -preset veryfast -crf 23 -c:a aac -b:a 192k -ar 44100 -ac 2 "!output_file!"
rem 此为封装使用的文件源码

@echo off
setlocal enabledelayedexpansion

rem 设置输入文件夹和输出文件夹路径
set input_folder=input
set output_folder=output

rem 检查输出文件夹是否存在,如果不存在则创建
if not exist !output_folder! mkdir !output_folder!

rem 遍历当前目录的所有mp4文件
for %%a in (*.mp4) do (
    set input_file=%%a
    set output_file=!output_folder!\%%~na.mp4

    rem 使用FFmpeg进行连接,调整编码参数
    ffmpeg -i "!input_folder!\op.mp4" -i "!input_file!" -i "!input_folder!\ed.mp4" -filter_complex "[0:v]fps=30,scale=1280:720,setsar=1[v0];[1:v]fps=30,scale=1280:720,setsar=1[v1];[2:v]fps=30,scale=1280:720,setsar=1[v2];[0:a]aformat=sample_rates=44100:channel_layouts=stereo[a0];[1:a]aformat=sample_rates=44100:channel_layouts=stereo[a1];[2:a]aformat=sample_rates=44100:channel_layouts=stereo[a2];[v0][a0][v1][a1][v2][a2]concat=n=3:v=1:a=1[vout][aout]" -map "[vout]" -map "[aout]" -c:v libx264 -preset veryfast -crf 23 -c:a aac -b:a 192k -ar 44100 -ac 2 "!output_file!"

    echo !output_file! created.
)

echo All files processed.
endlocal

rem 这个命令的解释如下:
rem 这个FFmpeg命令是用来合并视频文件的。具体来说,它首先会在当前目录下查找所有的mp4文件(使用通配符"*.mp4"来匹配),然后针对每一个文件执行以下操作:
rem 执行ffmpeg命令,将当前目录下的op.mp4(在input目录下)作为第一个输入文件,将当前遍历到的mp4文件作为第二个输入文件,将当前目录下的ed.mp4(在input目录下)作为第三个输入文件。
使用-filter_complex进行过滤操作。三个文件分别表示为[0:0], [0:1];[1:0], [1:1];[2:0], [2:1],然后使用concat过滤器将它们拼接起来。n=3表示有三个输入流,v=1表示合并视频流,a=1表示合并音频流,合并后的视频流和音频流分别为[v]和[a]。
rem 使用-map选项将拼接后的视频流和音频流分别映射到输出文件中。
rem 设置视频编码器为libx264,使用预设,设置视频码率为800000,帧率为30。
rem 设置音频编码器为aac,音频码率为192k,音频采样率为44100,声道数为2。
rem 将合并后的视频和频流输出至output目录下,输出的文件名与原文件相同但扩展名为.mp4。

重新编码部分根据实际情况可选用的参数如下

-c:v h264_nvenc -preset fast -b:v 800000 -r 30 
-c:v h264_nvenc -preset fast -crf 23 -c:a copy
-c:v h264_qsv -global_quality:v 22
-c:v libx264 -preset veryfast -crf 23 -c:a aac -b:a 256k
-c:v libx264 -preset veryfast -b:v 800000 -r 30 -c:a aac -b:a 256k
-c:v libx264 -preset veryfast -b:v 800000 -vf "scale=1280:-1" -c:a copy

空白内容处理

使用场景

对长视频进行气口(停顿、等待、卡壳)部分切除

实现原理

利用声音振幅识别气口片段,可以导出xml文件以得到进一步检查、复原和修改的空间

方案1:自动剪辑神器

完整的成品软件,经过多次迭代,功能已经比较完善

方案2:FFmpeg静音检测

ffmpeg -i input.mp4 -af silencedetect=noise=-30dB:d=0.5 -vn -sn -dn -f null /dev/null

# -af:silencedetect 的作用是获取音频的最大音量、平均音量以及音量直方图。它只支持 AV_SAMPLE_FMT_S16 、 AV_SAMPLE_FMT_S32 、 AV_SAMPLE_FMT_FLT 和 AV_SAMPLE_FMT_DBL 这四种格式——如果不是当然 FFmpeg 能够自动转换
# 多大音量认为是静音由参数 noise 确定,默认是 -60dB 或 0.001;多长的连续时长认为是静音由参数 duration 确定,默认是 2 秒。参数 mono 为非 0 表示各个声道分别检测,默认是合并在一起检测
# 合并在一起检测:比如认为 2 秒连续无声(或小声)认为是静音,那么其中一个声道达标,另一个声道在该时段内不达标也不认为是静音
# -vn、 -sn 和 -dn 告知 FFmpeg 忽略非音频流。能够在分析时避免不必要的操作从而更快速.
# 注意:在 Windows 中使用需将 /dev/null 替换为 NUL

# 对于多声道音频,可以指定各个声道分别检测:
ffmpeg -i input.mp3 -af "silencedetect=mono=1" -vn -sn -dn -f null /dev/null

快速切片及检查

这个我就不展开细说了,列举一些需要注意的地方

  • 语音转文字得到的只是参考,主要用于定位,找到需要剪辑的时间点

  • 也有通过字幕剪切视频的功能实现,但是具体的实现效果差强人意

  • 更推荐在字幕找好时间点后到Losslesscut进行剪辑,无损导出速度快


评论