我使用 ffmpeg 将从各种流媒体网站下载的一些视频编码为 HEVC。在 Windows 中,我使用批处理文件将目录中的所有这些文件进行转换。
ffmpeg -n -i input.mp4 -c:v libx265 -crf 22 -c:a libopus -b:a 48k -vbr on -compression_level 10 -frame_duration 60 -application audio output.mkv
这些视频的总体比特率在 300 kb/s 到 1500 kb/s 之间变化。在我的测试中,对所有这些视频使用相同的 CRF,如果视频比特率高,则输出文件更大,如果视频比特率低,则视频质量低。因此,我手动更改了一堆类似比特率视频的 CRF。如何使用批处理文件实现此目的。例如,如果总体比特率高于 950 = crf 26 如果总体比特率在 750 到 949 之间 = crf 24 如果总体比特率在 500 到 749 之间 = crf 22 如果总体比特率低于 499 = crf 18
答案1
@echo off & color 0A & cls
cd /d "%~dp0" && setlocal enabledelayedexpansion
set "_ffmpeg=F:\2020-SU\Q1569837\ffmpeg\bin\ffmpeg.exe"
set "_ffprobe=F:\2020-SU\Q1569837\ffmpeg\bin\ffprobe.exe"
set "_range_crf=99999-950-26,949-750-24,749-500-22,499-0-18"
for %%# in (*.mp4)do echo; && set /a "_c+=1+0" && for /f tokens^=2^,6^delims^=^,^ %%i in ('
2^>^&1 "!_ffprobe!" -show_entries stream^=bit_rate "%%~f#"^|%__APPDIR__%findstr.exe /e [0-9].kb/s
')do echo\Check File: "%%~nx#" ^| Bite Rate: %%~j kb/s && call :^) "!_range_crf!" "%%~j" "%%~n#" "%%~f#"
echo\ & <con: rem./ && echo\Total Files: 000!_c! && %__APPDIR__%timeout.exe /t -1 & endlocal && goto=:EOF
:^)
echo\ && for %%i in (%~1)do for /f "tokens=1-3delims=-" %%a in ('echo\%%~i
')do if %~2 leq %%~a if %~2 geq %%~b title<nul & title .:^| File Name:"..\%~nx4" ^| Bite Rate: %~2 kb/s ^|:. && (
"!_ffmpeg!" -y -i "%~4" -hide_banner -v error -stats -c:v libx265 -crf %%~c -c:a libopus -b:a 48k -vbr on ^
-compression_level 10 -frame_duration 60 -application audio "%~3.mkv" && exit /b 0 )
- 背后的机械师
for
和ifs
......
%2 %%a %2 %%b %%c
:: if 951 leq 99999 and if 951 GEQ 950 = True crf = 26 then Exit /loop :label
:: if 951 leq 949 and if 951 GEQ 750 crf = 24 then /loop :label
:: if 951 leq 749 and if 951 GEQ 500 crf = 22 then /loop :label
:: if 951 leq 499 and if 951 GEQ 0 crf = 18 then /loop :label
::
:: if 800 leq 999 and if 800 GEQ 950 = False crf = 26 then Keep /loop :label
:: if 800 leq 949 and if 800 GEQ 750 = True crf = 24 then Exit /loop :label
:: if 800 leq 749 and if 800 GEQ 500 crf = 22 then /loop :label
:: if 800 leq 499 and if 500 GEQ 0 crf = 18 then /loop :label
::
:: if 600 leq 999 and if 600 GEQ 950 = False crf = 26 then Keep /loop :label
:: if 600 leq 949 and if 600 GEQ 750 = False crf = 24 then Keep /loop :label
:: if 600 leq 749 and if 600 GEQ 500 = True crf = 22 then Exit /loop :label
:: if 600 leq 499 and if 600 GEQ 0 crf = 18 then /loop :label
::
:: if 501 leq 999 and if 501 GEQ 950 = False crf = 26 then Keep /loop :label
:: if 501 leq 949 and if 501 GEQ 750 = False crf = 24 then Keep /loop :label
:: if 501 leq 749 and if 501 GEQ 500 = True crf = 22 then Exit /loop :label
:: if 501 leq 499 and if 501 GEQ 0 crf = 18 then /loop :label
::
:: if 498 leq 999 and if 498 GEQ 950 = False crf = 26 then Keep /loop :label
:: if 498 leq 949 and if 498 GEQ 750 = False crf = 24 then Keep /loop :label
:: if 498 leq 749 and if 498 GEQ 500 = False crf = 22 then Keep /loop :label
:: if 498 leq 499 and if 498 GEQ 0 = True crf = 18 then Exit /loop :label
观察:1有两个空格之间^=^,^⟵⟶%%i在: delims^=^,^spacespace%%i
for %%# in (*.mp4)do for /f tokens^=2^,6^delims^=^,^spacespace%%i in (...
1.- 你的家庭作业:以与你的场景兼容的方式替换下面的变量,同时转到你的 bat 文件夹:
set "_ffmpeg=F:\2020-SU\Q1569837\ffmpeg\bin\ffmpeg.exe"
set "_ffprobe=F:\2020-SU\Q1569837\ffmpeg\bin\ffprobe.exe"
cd /d "%~dp0"
rem :: if your *.pm4 files are not in the same directory
rem :: as your bat file, use the full path to drive/folder
rem :: Example for drive D: folder/subfolder \Media\MP4\Convert
cd /d "D:\Midia\MP4\Convet"
2.此批次使用多个for loop
,为了使其工作,您需要启用Deleyed Expansion
,以便变量在运行时接收更新/扩展的值:
Setlocal EnableDelayedExpansion
3.if
定义一个用逗号分隔的变量,分隔符之间包含在循环内使用的值for
,以便可以使用最大值、最小值和兼容的 crf:
set "_range_crf= max-min-crf,max-min-24,max-500-22,499-0-18"
set "_range_crf=99999-950-26,949-750-24,749-500-22,499-0-18"
4.使用一个简单的for
循环和一个列出你的.mp4
文件,此外,使用计数器(set /a "_c+=1+0"
)在运行结束时获得总数:
for %%# in (*.mp4)do echo; && set /a "_c+=1+0"
- 观察:2这
echo;
仅用于换行并尝试使可视化在执行中更容易,在循环中创建分隔线。
5.使用附加功能来利用此循环变量(在),您从中获得 mp4 文件的完整路径/名称(),并将此循环作为输入传递给已经定义的(解释于for /f
1st/for/var==%%#
%%~f#
ffprobe
第 5 项。),该命令中要采用的标记和分隔符。
for /f tokens^=2^,6^delims^=^,^ %%i in (ffmprobe ... %%~f# ...
6.这ffprobe
循环中使用的命令是:for /f
..\ffprobe.exe -show_entries stream=bit_rate "Google Chrome - Now Everywhere.mp4"
7.首先使用StdErr
带有StdOut
ffprobe
findstr
/End of a line
regex
数字([0-9]
)与字符串连接.kb/s
,并使用适当的转义for
环形:
2^>^&1 "!_ffprobe!" -show_entries stream^=bit_rate "%%~f#" ^| "%__APPDIR__%findstr.exe" /e [0-9].kb/s
8.上述扩展命令没有转义,结果是:
2>&1 ..\ffprobe.exe -show_entries stream=bit_rate "Google Chrome - Now Everywhere.mkv" | "%__APPDIR__%findstr.exe" /e [0-9].kb/s
9.经过过滤器处理后,上述命令的输出结果findstr
如下:
时长:00:01:00.08,开始:-0.007000,比特率:350 kb/s
10.经过过滤器处理后,上述命令的输出结果findstr
如下:
时长:00:01:00.08,开始:-0.007000,比特率:350 kb/s
11.通过使用多个分隔符,%%i
和%%j
输出将是00:01:00.08
和350
: 是最后一个命令的输出,将是00:01:00.08
和350
:
... for /f tokens^=2^,6^delims^=^,^space %%i in (...
Duration: 00:01:00.08, start: -0.007000, bitrate: 350 kb/s
12.
假设你的极限值是350
(包括的)对于比特率,您将需要if
在工作部分使用一些选项:
if %%~j > Bit_Rate ∕∕ the same: if %%~j > 349 (349 exclusive)
if %%~j ≥ Bit_Rate ∕∕ the same: if %%~j ≥ 350 (350 inclusive)
set "_bit_rate=349"
if %%~j > %_bit_rate% ∕∕ the same: if %%~j > 349 (349 exclusive)
set "_bit_rate=350"
if %%~j ≥ %_bit_rate% ∕∕ the same: if %%~j ≥ 350 (350 inclusive)
if LSS - Less Than if [integer or int(var)] < [integer or int(var)]
if GTR - Greater Than if [integer or int(var)] > [integer or int(var)]
if LEQ - Less Than or Equals if [integer or int(var)] ≤ [integer or int(var)]
if GEQ - Greater Than or Equals if [integer or int(var)] ≥ [integer or int(var)]
13.的结果if
是true
或者false
,并将根据情况采取行动,出于教学目的,我们将当前文件视为true
案件:
if %%~j GTR 349 (
case true
ffmpeg transcode file mp4
) else (
case false
skip this file .mp4
save the full path name
)
if %%~j gtr 349 2>&1 ("!_ffmpeg!" -y -i "%%~f#" -hide_banner -v error -stats -c:v libx265 -crf 22 ^ -c:a libopus -b:a 48k -vbr on -compression_level 10 -frame_duration 60 -application audio "%%~n#.mkv"
观察:2那些角色:space^,位于行尾,就在换行符处,在执行时,命令解释器会将其视为一行,转义应用的换行符。
// 抱歉,明天还要继续解释……