我使用 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.此批次使用 multiple 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^,位於行的末尾,就在換行符處,在執行時,命令解釋器會將其視為單行,轉義所應用的換行符。
// 抱歉,明天繼續解釋...