ffmpeg详解,内含常用脚本大全

时间:2025-03-08 21:17:21

一、视频信息的获取

获取视频文件时长

获取视频文件时长
@echo off
for /f "tokens=2 delims=, " %%a in ('ffmpeg -i "1.mp4" 2^>^&1 ^| find "Duration:"') do (
    set str=%%a
)
echo %str%
pause

案例:手中有一些视频课 分别存放在当下目录下的不同子文件夹中,

如:视频文件\1
\2
\3
1、2、3 目录下存放视频文件,想在每个视频文件文件名后追加这个文件的播放时长

如:

第1课 春天.mp4

执行批处理后为

第1课 春天【89】.mp4

在视频文件名后追加文件时长
下载 和下面这个 放在“视频文件”这个目录下执行

@echo off
setlocal enabledelayedexpansion
cd /d "%~dp0"
for /f "delims=" %%i in ('dir /b /s /a-d *.mp4') do (
    for /f "tokens=2 delims=, " %%a in ('ffmpeg -i "%%i" 2^>^&1 ^| find "Duration:"') do (
        set "str=%%a"
    )
    set str=!str:~0,-3!
    set str=!str::=!
    ren "%%i" "%%~ni【!str!】%%~xi"
)

获取视频文件比特率

@echo off
for /f "tokens=6 delims=:" %%a in ('ffmpeg -i "1.mp4" 2^>^&1 ^| find "bitrate:"') do (
    set str=%%a
)
set str=%str:~1%
echo %str%
pause

获取视频文件分辨率

@echo off
for /f "tokens=11" %%a in ('ffmpeg -i "1.mp4" 2^>^&1 ^| find "Video:"') do (
    set str=%%a
)
echo %str%
pause

获取视频文件帧数

@echo off
for /f "tokens=2" %%i in ('ffmpeg -i 1.mp4 -map 0:v:0 -c copy -f null - 2^>^&1 ^| findstr /b "frame="') do (
    set "FrameCount=%%i"
)
echo %FrameCount%
pause

二、无损切割与合并

无损视频剪切

比如其中一个视频文件总时长为
00:55:09.095

含有片头2分 13秒150毫秒
00:02:13.150
含有片尾3分 13秒030毫秒
00:03:13.030
获得了视频时间,计算和分割不知道怎么弄了

@CD /D "%~dp0"
@echo off&title ffmpeg获取视频时间
for %%a in (*.avi *.mkv *.mp4 *.flv) do (
ffmpeg -i "%%a" 2>&1 | grep -oP "(?<=from ')%%a(?=')|(?<=DURATION        : )[^\.]+\.\d{3}(?=0+)" |  "3,$d"
)>> 视频时间长度.txt

pause

想00:55:09.095减去片尾时间00:03:13;030,从片头00:02:13;150到00:51:56.065处保存为新视频文件。

某文件夹内很多个视频,视频总长时间不等,所有视频片头片尾时间一致,如何获取视频总长时间后去掉片头片尾,直接截取中间部分放入目录下的“已切割”文件夹?

问题解决:
片头:s1=00:00:45.240
片尾:s2=00:01:30.090

@echo off & setlocal enabledelayedexpansion
set "s1=00:00:45.240"
set "s2=00:01:30.090"
for /f "tokens=1-4delims=:." %%a in ("%s2%") do (
    set /a "t2=(1%%a %% 100 *3600 + 1%%b %% 100 * 60 + 1%%c %% 100) * 1000 + 1%%d %% 1000"
)

md NEW 2>nul
for %%i in (*.avi *.mkv *.mp4 *.flv) do (
    for /f "tokens=2-5delims=:., " %%a in ('ffmpeg -i "%%i" 2^>^&1 ^| find "Duration:"') do (
        set /a "t=(1%%a%%100*3600+1%%b%%100*60+1%%c%%100)*1000+1%%d0%%1000,t-=t2,ms=t%%1000,t/=1000"
        set /a h=t/3600,m=t%%3600/60,s=t%%60,h+=100,m+=100,s+=100,ms+=1000
        set "t=!h:~1!:!m:~1!:!s:~1!.!ms:~1!"
        ffmpeg -i "%%i" -ss !s1! -to !t! -vcodec copy -acodec copy "NEW\%%i" -y
    )
)
pause

无损视频合并

::无损视频合并
::用法:按顺序拖入要合并的视频文件,然后回车。完成后按Ctrl+Z再回车,拖入输出路径。
::要求:音频编码为AAC。
@echo off
Setlocal enabledelayedexpansion
::CODER BY 老刘 POWERD BY iBAT
copy con "%temp%\">nul
set /p outputpath=输出路径:
set /a n=1
for /f "delims=" %%. in ('type "%temp%\"') do (
	ffmpeg -i "%%~f." -c:v copy -c:a copy -vbsf h264_mp4toannexb -y "%temp%\!n!.ts"
	Set "concat=!concat!%temp%\!n!.ts|"
	Set /a n+=1
)
ffmpeg -i "concat:!concat:~,-1!" -acodec copy -vcodec copy -absf aac_adtstoasc "!outputpath:"=!\output.mp4"
pause

视频剪切+合并

::视频剪辑合并
::用法:
::1、第一个分段中一定要有关键帧(不要截太短),否则会合并失败,变成只有音频流的mp4。
::2、分段信息例: 1:37-7:21 8:40~10:00 (冒号全角半角都可,-或~分割起始点和终点,空格分隔每一段)
::缺点:剪切的视频开头有黑屏或卡顿,因为ffmpeg无法seek到关键帧上。 
::优点:不用转码,剪辑真的很快;可编程,可自动化,适合批量粗略剪辑。
@echo off
Setlocal enabledelayedexpansion
:start
::CODER BY 老刘 POWERD BY iBAT
set /p Filepath=视频文件路径:
set "FilePath=!FilePath:"=!"
Set /p SplitInfo=分段信息:

set SplitInfo=!SplitInfo:-=~!
set SplitInfo=!SplitInfo::=:!
set /a n=1
rem set concat=
cd.>%temp%\concatlist
for %%a in (!SplitInfo!) do (
	for /f "tokens=1-2 delims=~" %%b in ("%%a") do (
		for /f "tokens=1-2 delims=:" %%d in ("%%b") do (
			set SplitFromMinute=%%d
			if "!SplitFromMinute:~1!" Equ "" set SplitFromMinute=0%%d
			set SplitFromSecond=%%e
			if "!SplitFromSecond:~1!" Equ "" set SplitFromSecond=0%%e
			if "!SplitFromMinute!:!SplitFromSecond!" Equ "00:00" set SplitFromSecond=01
		)
		
		for /f "tokens=1-2 delims=:" %%d in ("%%c") do (
			set SplitToMinute=%%d
			if "!SplitToMinute:~1!" Equ "" set SplitToMinute=0%%d
			set SplitToSecond=%%e
			if "!SplitToSecond:~1!" Equ "" set SplitToSecond=0%%e
		)
		Echo 截取分段 !n!!SplitFromMinute!:!SplitFromSecond! -^> !SplitToMinute!:!SplitToSecond!
		for %%A in ("!Filepath!") do (
			rem >nul 2>nul 
			>nul 2>nul ffmpeg ^
				-i "%%~fA" ^
				-ss !SplitFromMinute!:!SplitFromSecond! ^
				-to !SplitToMinute!:!SplitToSecond! ^
				-c:v copy ^
				-c:a copy ^
				%-vbsf% %h264_mp4toannexb% ^
				-y ^
				"%temp%\!n!.ts.mp4"
			rem Set "concat=!concat!%temp%\!n!.ts.mp4|"
			echo file '%temp%\!n!.ts.mp4' >>"%temp%\concatlist"
			Set /a n+=1
		)
	)
)
rem notepad %temp%\concatlist
rem exit
Set /a n-=1
for %%A in ("!Filepath!") do (
	ren "%%~fA" "%%~"
	echo 合并 !n! 个分段
	rem >nul 2>nul 
	>nul 2>nul ffmpeg ^
		-f concat ^
		-safe 0 ^
		-i "%temp%\concatlist" ^
		-vcodec copy ^
		-acodec copy ^
		-y ^
		"%%~fA"
)
echo.
goto start


rem 以下命令已弃用,仅作备份
ffmpeg ^
	-i "concat:!concat:~,-1!" ^
	-vcodec copy ^
	-absf aac_adtstoasc ^
	-acodec copy ^
	-y ^
	"%%~fA"

三、视频转码

视频动态码率压缩

::视频动态码率压缩。
::压缩到crf=30。
@rem echo %time%
@ -i "%~f1" -c:a copy -c:v libx264 -preset slower -crf 30 "%~.mp4"
@rem echo %time%
@pause

四、字幕处理

视频嵌入ASS字幕,即合并为硬字幕,另外一种叫外挂字幕,各有优缺点,这里不在赘述。

::嵌入ASS字幕
::若出现Could not create a libass track when reading file 错误,请将字幕编码改为UTF-8
ffmpeg -i input.mp4 -i  -vf ass= output.mp4

截图和缩略图

提取某个时间点的帧为图片

ffmpeg -i "1.mp4" -ss 00:00:35 -frames:v 1 ""

案例1:
我有1000多个视频mp4格式,每个视频的时长不一样,有什么方法或软件可以批量截取位于视频结尾最后3秒处的截图,并截图的图片文件名和视频名相同?

@echo off & setlocal enabledelayedexpansion
title ffmpeg视频尾部X秒批量截图
:a
set /p "str=输入1-9秒:"
   echo %str%|findstr /x "[1-9]" >nul||(echo 输入有误,按任意键返回&goto :a ) 

for /f "delims=" %%i in ('dir /b /a-d *.avi *.mkv *.mp4 *.flv') do (
    for /f "tokens=2-5delims=:., " %%a in ('ffmpeg -i "%%i" 2^>^&1 ^| find "Duration:"') do (
        set /a "t=(1%%a%%100*3600+1%%b%%100*60+1%%c%%100)*1000+1%%d0%%1000,t-=%str%*1000,ms=t%%1000,t/=1000"
        set /a h=t/3600,m=t%%3600/60,s=t%%60,h+=100,m+=100,s+=100,ms+=1000
        set "t=!h:~1!:!m:~1!:!s:~1!.!ms:~1!"
        echo 文件:%%i 将在!t!处截图,请耐心等待……
        ffmpeg -v quiet -ss !t! -i "%%i" -frames:v 1 "%%~"
    )
)
pause
@if(0)==(0) echo off& setlocal EnableDelayedExpansion&cd %~dp0
title ffmpeg视频尾部XX秒批量截图
:ss
set /p ss=请输入秒数(例:5或21): 
@for /f "delims=" %%i in ('echo %ss%^|cscript -nologo -e:jscript "%~f0"') do (
if not "%%i"=="正确" echo. & echo 时间格式不对,请重新输入1-59内数字 & goto ss
)
for /f "delims=" %%i in ('dir /b /a-d *.avi *.mkv *.mp4 *.flv') do (
    for /f "tokens=2-5delims=:., " %%a in ('ffmpeg -i "%%i" 2^>^&1 ^| find "Duration:"') do (
        set /a "t=(1%%a%%100*3600+1%%b%%100*60+1%%c%%100)*1000+1%%d0%%1000,t-=%ss%*1000,ms=t%%1000,t/=1000"
        set /a h=t/3600,m=t%%3600/60,s=t%%60,h+=100,m+=100,s+=100,ms+=1000
        set "t=!h:~1!:!m:~1!:!s:~1!.!ms:~1!"
        echo 文件:%%i	将在!t!处截图,请耐心等待……
    )
    ffmpeg -v quiet -ss !t! -i "%%i" -frames:v 1 "%%~"
)

pause & exit /b
@end
(().replace(/^[1-5]\d|^[1-9]/, '正确').match(/^[^\r\n]+/).join('\r\n'));

五、音频处理

视频、音频转mp3

for %%a in (%*) do ffmpeg -i "%%~fa" "%%~dpna.MP3"

音频去噪

::音频去噪
::用法:媒体文件拖到bat上,然后按提示输入参数
@echo off
Setlocal enabledelayedexpansion
::CODER BY 老刘 POWERD BY iBAT
set /p t=噪音出现时间点(MM:SS):
set /p x=去噪效果(0~1,推荐0.2~0.3):
ffmpeg -i "%~1" "%tmp%\"
ffmpeg -i "%~1" -ss 00:!t! -t 1 "%tmp%\n"
sox "%tmp%\n" -n noiseprof "%tmp%\n"
sox "%tmp%\" "%~dp1[NO_Noise]%~" noisered "%tmp%\n" !x!
pause

视频音量调整

::视频音量调整
::音频编码会被转为mp3
@set /p vpath=拖入视频路径:
@set /p volume=输入音量增幅(单位dB):
@set /p audio_bitrate=输入音频码率(单位kbps):
@Call :处理 "%vpath:"=%"
@Exit
:处理
@ffmpeg -i "%~1" -c:v copy -c:a libmp3lame -b:a %audio_bitrate%k -af "volume=%volume%dB" "%~dp1(+%volume%dB)%~nx1"

加入双语

视频+第二个音频流生成新视频

ffmpeg -i ".\2019.10.12 - 21.28.39.02.mp4" -map 0:v  -c:v copy -map 0:a:1 -c:a copy 1.mp4

导出第二个音频流

ffmpeg -i ".\2019.10.12 - 21.28.39.02.mp4" -map 0:a:1 -c:a copy 1.aac

音频无损分割

根据时长分割mp3音频文件,分割为每60秒一个文件

@echo off
cd /d "%~dp0"
ffmpeg -i "in.mp3" -f segment -segment_time 60 -c copy "out_%%03d.mp3"

六、录制桌面

无音频流(无声音),FPS(帧率) 6

 -f gdigrab -framerate 25 -i desktop out.mp4

这个要进行一系列的设置比较麻烦,设置好之后测试效果不佳,不建议使用。
还是使用第三方录频软件吧!

七、图片处理

图片压缩

ffmpeg -i image_source -q compress_level out_source
#compress_level:压缩等级为正整数,数值越大压缩等级越高

约束比例压缩
ffmpeg -i image_source -vf scale=width:height out_source
#width为压缩后的图片宽度
#height为压缩后的图片高度
#当width或height其中有一个数值为-1时将保持原来图片尺寸比例压缩

图片裁剪
ffmpeg -i image_source -vf crop=width:height:from_x:from_y out_source
#width是要裁剪出的图片的宽度
#height是要裁剪出的图片的高度
#from_x是裁剪的起始X轴的位置
#from_y是裁剪的起始Y轴的位置
#如果不指定from_x和from_y表示从原始图片中心位置开始裁剪

添加水印图片
ffmpeg -i image_source -vf movie=logo_source,scale=logo_width:logo_height,lut=a=val*opacity_num[watermask];[in][watermask] overlay=from_x:from_y[out] -y  out_source
#logo_source为水印图片地址
#logo_width为水印图片的宽度
#logo_height为水印图片的高度
#opacity_num为水印图片的透明度
#from_x为水印的起始X轴的位置
#from_y为水印的起始Y轴的位置

图片旋转指定的角度
ffmpeg -i image_source -vf rotate=route_num*PI/180 -y  out_source
#route_num是要旋转的角度
#当route_num大于0的时候顺时针旋转,当route_num小于0的时候逆时针旋转

ffmpeg -i image_source -vf transpose=route_number -y out_source
#route_number=0顺时针旋转90度再左右镜像
#route_number=1顺时针旋转90度
#route_number=2逆时针旋转90度
#route_number=3逆时针旋转90度再左右镜像

图片左右镜像
ffmpeg -i image_source -vf hflip out_source

将图片上下镜像
ffmpeg -i image_source -vf vflip out_source

/