Utilizo ffmpeg para codificar algunos videos que descargué de varios sitios de transmisión en HEVC. En Windows utilizo un archivo por lotes para convertir todos estos archivos en un directorio.
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
La tasa de bits general de estos videos varía entre 300 kb/s y 1500 kb/s. En mis pruebas, el uso del mismo CRF para todos estos videos produjo un archivo de salida más grande en el caso de videos con alta tasa de bits o video de baja calidad en el caso de baja tasa de bits. Entonces cambio manualmente el CRF para un montón de videos con velocidad de bits similar. ¿Cómo puedo lograr esto usando un archivo por lotes? Por ejemplo, si la tasa de bits general es superior a 950 = crf 26 si la tasa de bits general está entre 750 y 949 = crf 24 si la tasa de bits general está entre 500 y 749 = crf 22 si la tasa de bits general es inferior a 499 = crf 18
Respuesta1
@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 )
- El mecánico detrás
for
yifs
...
%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
Obs.: 1Haydos espaciosentre^=^,^⟵⟶%%ien: delims^=^,^spacespace%%i
for %%# in (*.mp4)do for /f tokens^=2^,6^delims^=^,^spacespace%%i in (...
1.- Tu trabajo en casa: Reemplaza las variables a continuación de una manera compatible con tu escenario, también ve a tu carpeta 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.Este lote utiliza múltiples for loop
, para que funcione deberá habilitarlo Deleyed Expansion
para que las variables reciban los valores actualizados/expandidos en tiempo de ejecución:
Setlocal EnableDelayedExpansion
3.Defina una variable delimitada por una coma, y que contenga entre el delimitador, los valores a utilizar en el if
interior del for
bucle, de modo que pueda trabajar con valor máximo, valor mínimo y crf compatible:
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.Utilice un for
bucle simple y uno para enumerar sus.mp4
archivos y además, utilizar un contador (set /a "_c+=1+0"
)para obtener un total al final de la ejecución:
for %%# in (*.mp4)do echo; && set /a "_c+=1+0"
- Observaciones: 2El
echo;
se utiliza únicamente para romper la línea e intentar facilitar la visualización en la ejecución, creando una línea separadora en el bucle.
5.Utilice un adicional para hacer uso de esta variable de bucle (en ) donde obtuvo la ruta/nombre completo ( ) del archivo mp4, y pase este bucle como entrada a la definición que ya está definida (explicada enfor /f
1st/for/var==%%#
%%~f#
ffprobe
artículo 5.), los tokens y delimitadores que se tomarán en ese comando.
for /f tokens^=2^,6^delims^=^,^ %%i in (ffmprobe ... %%~f# ...
6.Elffprobe
El comando utilizado en el bucle es:for /f
..\ffprobe.exe -show_entries stream=bit_rate "Google Chrome - Now Everywhere.mp4"
7.Comenzando con la redirección StdErr
a StdOut
la ffprobe
salida a filtrar findstr
usando el interruptor con el/End of a line
regex
números ([0-9]
) concatenado con la cadena .kb/s
y usando el escape adecuado enfor
bucle:
2^>^&1 "!_ffprobe!" -show_entries stream^=bit_rate "%%~f#" ^| "%__APPDIR__%findstr.exe" /e [0-9].kb/s
8.El comando expandido anterior y sin los escapes da como resultado:
2>&1 ..\ffprobe.exe -show_entries stream=bit_rate "Google Chrome - Now Everywhere.mkv" | "%__APPDIR__%findstr.exe" /e [0-9].kb/s
9.La salida del comando anterior tratada por el findstr
filtro da como resultado:
Duración: 00:01:00.08, inicio: -0.007000, tasa de bits: 350 kb/s
10.La salida del comando anterior tratada por el findstr
filtro da como resultado:
Duración: 00:01:00.08, inicio: -0.007000, tasa de bits: 350 kb/s
11.Al utilizar múltiples delimitadores, las cadenas en%%i
y%%j
la salida será00:01:00.08
y350
: es para la salida del último comando, será00:01:00.08
y350
:
... for /f tokens^=2^,6^delims^=^,^space %%i in (...
Duration: 00:01:00.08, start: -0.007000, bitrate: 350 kb/s
12.
Suponiendo que su valor límite es350
(inclusivo) para Bite Rate, necesitarás usar alguna if
opción en la parte de trabajo:
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.El resultado deif
estrue
ofalse
, y realizará acciones según el caso, a efectos didácticos, consideraremos el expediente actual como untrue
caso:
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.:2Los caracteres:space^, están al final de la línea, justo en el salto de línea, donde durante la ejecución, el intérprete de comandos lo tratará como una sola línea, escapando del salto de línea aplicado.
// Lo siento, la explicación continuará mañana...