ffmpeg - 如果位元率低於一定量則跳過文件

ffmpeg - 如果位元率低於一定量則跳過文件

我使用 ffmpeg 將從各種串流媒體網站下載的一些影片編碼為 hevc。在 Windows 中,我使用批次檔來轉換這些檔案。

FOR /F "tokens=*" %%G IN ('dir /b *.mp4') DO ffmpeg -n -i "%%G" -c:v libx265 -crf 22 -c:a libopus -b:a 48k -vbr on -compression_level 10 -frame_duration 60 -application audio "%%~nG.mkv"

其中一些文件的比特率非常低,我不想碰它們。 ffmpeg 有辦法跳過這些檔案嗎?或者我可以包含在批次檔中的任何命令,例如用於ffprobe獲取比特率並使用命令跳過它。

答案1

@echo off 

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"

for %%# in (*.mp4)do 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 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" 
     )else set/a "_c+=1+0" && <con: call set "_skp_!_c!=Skipped File: %%~nx# Duration: %%~i Bit Rate: %%~j"
      
echo;& (for /f tokens^=2^delims^=^= %%i in ('set _skp_ 2^>nul')do echo\%%~i) & %__APPDIR__%timeout.exe -1 & endlocal
  • 輸出:
x265 [info]: HEVC encoder version 3.4+2-73ca1d7be377
x265 [info]: build info [Windows][GCC 9.3.1][64 bit] 8bit+10bit
x265 [info]: using cpu capabilities: MMX2 SSE2Fast LZCNT SSSE3 SSE4.2 AVX FMA3 BMI2 AVX2
x265 [info]: Main profile, Level-3.1 (Main tier)
x265 [info]: Thread pool created using 4 threads
x265 [info]: Slices                              : 1
x265 [info]: frame threads / pool features       : 2 / wpp(12 rows)
x265 [info]: Coding QT: max CU size, min CU size : 64 / 8
x265 [info]: Residual QT: max TU size, max depth : 32 / 1 inter / 1 intra
x265 [info]: ME / range / subpel / merge         : hex / 57 / 2 / 3
x265 [info]: Keyframe min / max / scenecut / bias  : 23 / 250 / 40 / 5.00
x265 [info]: Lookahead / bframes / badapt        : 20 / 4 / 2
x265 [info]: b-pyramid / weightp / weightb       : 1 / 1 / 0
x265 [info]: References / ref-limit  cu / depth  : 3 / off / on
x265 [info]: AQ: mode / str / qg-size / cu-tree  : 2 / 1.0 / 32 / 1
x265 [info]: Rate Control / qCompress            : CRF-22.0 / 0.60
x265 [info]: tools: rd=3 psy-rd=2.00 early-skip rskip mode=1 signhide tmvp
x265 [info]: tools: b-intra strong-intra-smoothing lslices=4 deblock sao
frame= 1440 fps= 55 q=29.8 Lsize=    2570kB time=00:01:00.11 bitrate= 350.3kbits/s speed=2.32x
x265 [info]: frame I:      6, Avg QP:22.93  kb/s: 1138.86
x265 [info]: frame P:    705, Avg QP:25.55  kb/s: 498.87
x265 [info]: frame B:    729, Avg QP:28.95  kb/s: 98.52
x265 [info]: Weighted P-Frames: Y:0.9% UV:0.6%
x265 [info]: consecutive B-frames: 58.8% 11.0% 11.4% 6.6% 12.2%

encoded 1440 frames in 25.96s (55.47 fps), 298.86 kb/s, Avg QP:27.26

Skipped File: Live_TV_-_Bloomberg.mp4 Duration: 00:00:36.42 Bit Rate: 315
Skipped File: HVDC Light - ABB 3D.mp4 Duration: 00:03:32.16 Bit Rate: 336

觀察次數: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.不幸的是您目前的for /f ... dir .mp4 ...沒有多大幫助,所以將其替換為簡單的for以獲得所有.mp4循環列出:

for %%# in (*.mp4)do ....

4.使用附加項來利用此循環變數(在 中),您在其中獲得了 mp4 檔案的完整路徑/名稱 ( ),並將此循環作為輸入傳遞給已經定義的(已在for /f1st/for/var==%%#%%~f#ffprobe第 5 項。)、該指令中要採用的標記和分隔符號。

for /f tokens^=2^,6^delims^=^,^  %%i in (ffmprobe ...  %%~f# ... 

5.ffprobe循環中使用的命令是:for /f

..\ffprobe.exe -show_entries stream=bit_rate "Google Chrome - Now Everywhere.mp4"

6.首先使用具有以下命令的開關重定向StdErr到要過濾的StdOut輸出ffprobefindstr/End of a lineregex數字([0-9]) 與字串連接.kb/s並使用適當的縮放for環形:

2^>^&1 "!_ffprobe!" -show_entries stream^=bit_rate "%%~f#" ^| "%__APPDIR__%findstr.exe" /e [0-9].kb/s

7.上面的擴展命令在沒有轉義的情況下會導致:

2>&1 ..\ffprobe.exe -show_entries stream=bit_rate "Google Chrome - Now Everywhere.mkv" | "%__APPDIR__%findstr.exe" /e [0-9].kb/s

8.過濾器處理上述指令的輸出結果findstr為:

持續時間:00:01:00.08,開始:-0.007000,位元速率:350 kb/s

9.過濾器處理上述指令的輸出結果findstr為:

持續時間:00:01:00.08,開始:-0.007000,位元速率:350 kb/s

10.透過使用多個分隔符,中的字串%%i%%j輸出將是00:01:00.08350: 用於最後一個命令輸出,將是00:01:00.08350:

... for /f tokens^=2^,6^delims^=^,^space %%i in (...
Duration: 00:01:00.08, start: -0.007000, bitrate: 350 kb/s

在此輸入影像描述

11.假設你的極限值為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)]

12.的結果iftrue或者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^,位於行的末尾,就在換行符處,在執行時,命令解釋器會將其視為單行,轉義所應用的換行符。

13.對於那些比特率較低的文件,即false案件在if命令,您可以執行以下操作來保存從該命令中排除的文件ffmpeg轉換,並將在運行結束時列出:

 if %%~j GTR 349 (
      case true
      ffmpeg transcode file mp4
    ) else (
      case false
      skip this file .mp4
      save the full path name
    )
  • 觀察次數:3if也可以在不同的佈局中工作,例如:

    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 (case true && ffmpeg transcode file mp4 ) else (
        case false && skip this file .mp4 && save the full path name )
    if %%~j GTR 349 (case true && ffmpeg transcode file mp4
        )else case false && skip this file .mp4 && save the full path name 

14.使用中的值%%~f#,%%~i%%~j變量,其中分別是當前文件的路徑和全名,其持續時間和比特率,我們可以輕鬆地添加一個計數器(set/a "_c+=1+0"),並在執行時遞增以創建/定義,一一排除在外的文件資訊轉換:

)else set/a "_c+=1+0" && <con: call set "_skp_!_c!=Skipped File: %%~nx# Duration: %%~i Bit Rate: %%~j"

%%~f# == Live_TV_-_Bloomberg.mp4
%%~i  == 00:00:36.42
%%~j  == 315

set "_c+=1+0" && call set "_skp_1=Skipped File: Live_TV_-_Bloomberg.mp4 Duration: 00:00:36.42 Bit Rate: 315"

15.set 指令也可以用於變數和值列表,並使用set user,所有定義的變數user+(strings)將像這樣列出:

>set USER
USERDOMAIN=LAME_SLUG
USERDOMAIN_ROAMINGPROFILE=LAME_SLUG
USERNAME=ecker
USERPROFILE=C:\Users\ecker

16.在最後一行,我們有一個for /f循環,它將用於回顯用名稱定義的每個變數_skip_*,它是透過保存執行期間被忽略的檔案來定義的,並且此循環將採用 符號之後的所有內容=(第二/tokens^=2):

for /f tokens^=2^delims^=^= ... set _skp_1 .... echo\%%~i
 _skp_1=Skipped File: Live_TV_-_Bloomberg.mp4 Duration: 00:00:36.42 Bit Rate: 315
       
tokens^=2Skipped File: Live_TV_-_Bloomberg.mp4 Duration: 00:00:36.42 Bit Rate: 315
echo;& (for /f tokens^=2^delims^=^= %%i in ('set _skp_')do echo\%%~i)...

17.bat 檔案中最後一個的第二部分和最後一部分,將讓循環發生(隔離),並且只有在列出所有跳過的檔案後,它才會暫停/無限期超時,等待按下某個鍵,從而關閉/完成 setlocal 並結束執行:

1st part: (for /f .....)
2nd part: %__APPDIR__%timeout.exe -1 & endlocal 

echo; & (for /f tokens^=2^delims^=^= %%i in ('set _skp_')do echo\%%~i) & %__APPDIR__%timeout.exe -1 & endlocal

18.為了避免任何可能的錯誤訊息(Environment variable _skip_ not defined),如果沒有文件被 忽略if,只需添加2^>nul'set _skip_*2^>nul',在最後一個循環內for:

(for /f tokens^=2^delims^=^= %%i in ('set _skp_ 2^>nul')do echo\%%~i)do...
  • 觀察4在這裡,echo;僅用於在列出跳過的檔案之前建立一個分離行。


  • 傳統/教學佈局中的相同代碼:
@echo off 

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"

for %%# in (*.mp4) do (

     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 (
         
         if %%~j gtr 3200 (
         
             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" 
             
           ) else (
             
             set /a "_c+=1+0"
             set "_skp_!_c!=Skipped File: %%~nx# Duration: %%~i Bit Rate: %%~j"
                 
           )
      )
    
  )

echo.
for /f "tokens=2 delims==" %%i in ('2^>nul set _skp_')do echo\%%~i

%__APPDIR__%timeout.exe -1 
endlocal

相關內容