TransWikia.com

ffmpeg - Skip file if the bitrate is lower than certain amount

Super User Asked by Metallizer on November 3, 2021

I use ffmpeg to encode some videos I downloaded from various streaming sites to hevc. In windows I use a batch file to convert these files.

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"

Some of these files have very low bitrate and I don’t want to touch those. Is there any way in ffmpeg to skip these files? Or any command I can include in the batch file, like using ffprobe to get the bitrate and skip it using command.

One Answer

@echo off 

cd /d "%~dp0" && setlocal enabledelayedexpansion
set "_ffmpeg=F:2020-SUQ1569837ffmpegbinffmpeg.exe"
set "_ffprobe=F:2020-SUQ1569837ffmpegbinffprobe.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
  • Output:
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

Obs.: 1 There are two spaces between ^=^,^⟵⟶%%i in: delims^=^,^spacespace%%i

for %%# in (*.mp4)do for /f tokens^=2^,6^delims^=^,^spacespace%%i in (...


1. - You home work: Replace the variables below in a way compatible with your scenario, also go to your bat folder:

set "_ffmpeg=F:2020-SUQ1569837ffmpegbinffmpeg.exe"
set "_ffprobe=F:2020-SUQ1569837ffmpegbinffprobe.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 MediaMP4Convert 

cd /d "D:MidiaMP4Convet"

2. This batch is using multiple for loop, for it to work you will need to enable Deleyed Expansion so that the variables receive the updated/expanded values ​​at run time:

Setlocal EnableDelayedExpansion

3. Unfortunately your current for /f ... dir .mp4 ... doesn't help much, so replace it with a simple for to get all the .mp4 listed in a loop:

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

4. Use an additional for /f to make use of this loop variable (in the 1st/for/var==%%#) where you got the full path/name (%%~f#) of the mp4 file, and pass this loop as input to ffprobe already defining (explained on item 5.), the tokens and delimiters to be taken in that command.

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

5. The ffprobe command used in for /f loop is:

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

6. Starting with redirecting StdErr to StdOut of the ffprobe output to be filtered by findstr by using the switch /End of a line with the regex numbers ([0-9]) concatenated with the string .kb/s and using proper scaping in for loop:

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

7. The above expanded command and without the escapes, results in:

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

8. The output of the above command treated by the findstr filter results in:

Duration: 00:01:00.08, start: -0.007000, bitrate: 350 kb/s

9. The output of the above command treated by the findstr filter results in:

Duration: 00:01:00.08, start: -0.007000, bitrate: 350 kb/s

10. By using multiple delimiters, the strings in %%i and %%j output will be 00:01:00.08 and 350: is for last command output, will be 00:01:00.08 and 350:

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

enter image description here

11. Assuming your limit value is 350 (inclusive) for Bite Rate, you will need to use some if option in the work part:

 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. The result of if is true or false, and will perform actions depending on the case, for didactic purposes, we will consider the current file as a true case:

 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"
  • Obs.:2 The characters: space^, are at the end of the line, right at the line break, where in execution, the command interpreter will treat it as a single line, escaping the applied line break.

13. For those files with lower bite rates, that is, false cases in the if command, you have the actions to save the files that were excluded from the ffmpeg conversion, and will be listed at the end of the run:

 if %%~j GTR 349 (
      case true
      ffmpeg transcode file mp4
    ) else (
      case false
      skip this file .mp4
      save the full path name
    )
  • Obs.:3 The if also work in differents layouts like:

    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. Using the values ​​in the %%~f#, %%~i and %%~j variables, where respectively are the path and full name of the current file, its duration and its bit rate, we can easily add a counter (set/a "_c+=1+0") and in execution time we increment to create/define, one by one the information of files excluded from the conversion:

)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. The set command can also be used for variable and value listings, and using a set user, all variables with defined user+(strings) will be listed like this:

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

16. In the last line, where we have a for /f loop, it will be used to echo each variable defined with name _skip_*, which was defined by saving the files that were ignored during execution, and this looping will take everything that comes after the sign of = (2nd/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. The second and last part of the last in the bat file, will let the loop occur (isolated) and only after listing all the files that were skipped, it will pause / indefinite timeout, waiting for some key to be pressed, thus closing / finalizing the setlocal, and ending the execution:

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. To avoid any possible error message (Environment variable _skip_ not defined), in cases where no file was ignored by if, just add 2^>nul in 'set _skip_*2^>nul', inside the last loop for:

(for /f tokens^=2^delims^=^= %%i in ('set _skp_ 2^>nul')do echo%%~i)do...
  • Obs.4 Here, the echo; is only for create one separatist line before to list the skipped files..


  • The same code in conventional/didactic layout:
@echo off 

cd /d "%~dp0"
setlocal enabledelayedexpansion

set "_ffmpeg=F:2020-SUQ1569837ffmpegbinffmpeg.exe"
set "_ffprobe=F:2020-SUQ1569837ffmpegbinffprobe.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

Answered by Io-ol on November 3, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP