Я использую 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.В этом пакете используется несколько for loop
, для его работы вам необходимо включить Deleyed Expansion
, чтобы переменные получали обновленные/расширенные значения во время выполнения:
Setlocal EnableDelayedExpansion
3.К сожалению, ваш текущийfor /f ... dir .mp4 ...
не поможет, поэтому замените его на простой, for
чтобы получить все.mp4
перечислены в цикле:
for %%# in (*.mp4)do ....
4.Используйте дополнительный параметр, чтобы использовать эту переменную цикла (в ), где вы получили полный путь/имя ( ) файла mp4, и передайте этот цикл в качестве входных данных для уже определенного (объясняется наfor /f
1st/for/var==%%#
%%~f#
ffprobe
пункт 5.), токены и разделители, которые следует использовать в этой команде.
for /f tokens^=2^,6^delims^=^,^ %%i in (ffmprobe ... %%~f# ...
5.Theffprobe
Команда, используемая в цикле:for /f
..\ffprobe.exe -show_entries stream=bit_rate "Google Chrome - Now Everywhere.mp4"
6.Начиная с перенаправления 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
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 кб/с
9.Вывод вышеуказанной команды, обработанный фильтром, findstr
приводит к следующему:
Продолжительность: 00:01:00.08, начало: -0.007000, битрейт: 350 кб/с
10.Используя несколько разделителей, строки в%%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
11.Предположим, что ваше предельное значение равно350
(включительно) для Bite Rate вам нужно будет использовать некоторую 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.Результат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^, находятся в конце строки, прямо на переносе строки, где при выполнении интерпретатор команд будет рассматривать его как одну строку, избегая примененного переноса строки.
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
)
Наблюд.:3The
if
также работают в различных макетах, таких как: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_*
, который был определен путем сохранения файлов, которые были проигнорированы во время выполнения, и этот цикл возьмет все, что идет после знака=
(2-й/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^=2 ⇄ Skipped 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
Дополнительная литература:
[√]если /?
[√]набор /?
[√]ЦМД /?
[√]Findstr
[√]Для цикла
[√]Для цикла /F
[√]Условное исполнение || && ...
[√]Почему набор вызовов работает по-другому
[√]Понимание start, 2>nul, cmd и других символов в пакетном файле
[√]Используйте скобки для группировки выражений в пакетном файле Windows.