487 lines
15 KiB
Batchfile
487 lines
15 KiB
Batchfile
@echo off
|
||
chcp 65001 >nul
|
||
setlocal EnableExtensions EnableDelayedExpansion
|
||
|
||
rem ============================================================
|
||
rem Express Video Encoder
|
||
rem Подготовка видео для отправки через мессенджер Express
|
||
rem ============================================================
|
||
|
||
set "TARGET_BYTES=39500000"
|
||
set "TARGET_MB=39.5"
|
||
set "AUDIO_KBPS=128"
|
||
set "OVERHEAD_KBPS=20"
|
||
set "FIRST_PASS_PRESET=8"
|
||
set "SECOND_PASS_PRESET=3"
|
||
|
||
if "%~1"=="" (
|
||
echo.
|
||
echo Перетащите видеофайл на encode-for-express.bat.
|
||
echo.
|
||
pause
|
||
exit /b 1
|
||
)
|
||
|
||
if not exist "%~f1" (
|
||
echo.
|
||
echo ОШИБКА: исходный файл не найден.
|
||
echo.
|
||
pause
|
||
exit /b 1
|
||
)
|
||
|
||
rem ============================================================
|
||
rem Поиск FFmpeg
|
||
rem ============================================================
|
||
|
||
set "FFMPEG="
|
||
set "FFPROBE="
|
||
|
||
if exist "%~dp0ffmpeg\ffmpeg.exe" set "FFMPEG=%~dp0ffmpeg\ffmpeg.exe"
|
||
if exist "%~dp0ffmpeg\ffprobe.exe" set "FFPROBE=%~dp0ffmpeg\ffprobe.exe"
|
||
|
||
if not defined FFMPEG (
|
||
where ffmpeg.exe >nul 2>&1
|
||
if not errorlevel 1 set "FFMPEG=ffmpeg.exe"
|
||
)
|
||
|
||
if not defined FFPROBE (
|
||
where ffprobe.exe >nul 2>&1
|
||
if not errorlevel 1 set "FFPROBE=ffprobe.exe"
|
||
)
|
||
|
||
if not defined FFMPEG (
|
||
echo.
|
||
echo ОШИБКА: ffmpeg.exe не найден.
|
||
echo Положите его в папку:
|
||
echo %~dp0ffmpeg
|
||
echo или добавьте FFmpeg в системный PATH.
|
||
echo.
|
||
pause
|
||
exit /b 1
|
||
)
|
||
|
||
if not defined FFPROBE (
|
||
echo.
|
||
echo ОШИБКА: ffprobe.exe не найден.
|
||
echo Положите его в папку:
|
||
echo %~dp0ffmpeg
|
||
echo или добавьте FFmpeg в системный PATH.
|
||
echo.
|
||
pause
|
||
exit /b 1
|
||
)
|
||
|
||
"%FFMPEG%" -hide_banner -encoders 2>nul | findstr /I /C:"libsvtav1" >nul
|
||
if errorlevel 1 (
|
||
echo.
|
||
echo ОШИБКА: эта сборка FFmpeg не содержит libsvtav1.
|
||
echo Нужна сборка FFmpeg с поддержкой SVT-AV1.
|
||
echo.
|
||
pause
|
||
exit /b 1
|
||
)
|
||
|
||
rem ============================================================
|
||
rem Чтение параметров исходного файла
|
||
rem Используем временные файлы вместо FOR /F вокруг команды ffprobe.
|
||
rem Это надежно работает с пробелами и русскими символами в путях.
|
||
rem ============================================================
|
||
|
||
set "PROBE_DIR=%TEMP%\express_video_encoder_%RANDOM%_%RANDOM%"
|
||
mkdir "%PROBE_DIR%" >nul 2>&1
|
||
|
||
set "SRC_VCODEC=Н/Д"
|
||
set "SRC_PROFILE=Н/Д"
|
||
set "SRC_WIDTH=Н/Д"
|
||
set "SRC_HEIGHT=Н/Д"
|
||
set "SRC_FPS_RAW=Н/Д"
|
||
set "SRC_FPS=Н/Д"
|
||
set "SRC_PIXFMT=Н/Д"
|
||
set "SRC_VBIT_BPS="
|
||
set "SRC_VBIT_KBPS=Н/Д"
|
||
set "DURATION="
|
||
|
||
"%FFPROBE%" -v error -select_streams v:0 -show_entries stream=codec_name -of default=noprint_wrappers=1:nokey=1 "%~f1" > "%PROBE_DIR%\vcodec.txt" 2>nul
|
||
"%FFPROBE%" -v error -select_streams v:0 -show_entries stream=profile -of default=noprint_wrappers=1:nokey=1 "%~f1" > "%PROBE_DIR%\profile.txt" 2>nul
|
||
"%FFPROBE%" -v error -select_streams v:0 -show_entries stream=width -of default=noprint_wrappers=1:nokey=1 "%~f1" > "%PROBE_DIR%\width.txt" 2>nul
|
||
"%FFPROBE%" -v error -select_streams v:0 -show_entries stream=height -of default=noprint_wrappers=1:nokey=1 "%~f1" > "%PROBE_DIR%\height.txt" 2>nul
|
||
"%FFPROBE%" -v error -select_streams v:0 -show_entries stream=avg_frame_rate -of default=noprint_wrappers=1:nokey=1 "%~f1" > "%PROBE_DIR%\fps.txt" 2>nul
|
||
"%FFPROBE%" -v error -select_streams v:0 -show_entries stream=pix_fmt -of default=noprint_wrappers=1:nokey=1 "%~f1" > "%PROBE_DIR%\pixfmt.txt" 2>nul
|
||
"%FFPROBE%" -v error -select_streams v:0 -show_entries stream=bit_rate -of default=noprint_wrappers=1:nokey=1 "%~f1" > "%PROBE_DIR%\vbit.txt" 2>nul
|
||
"%FFPROBE%" -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "%~f1" > "%PROBE_DIR%\duration.txt" 2>nul
|
||
|
||
set /p SRC_VCODEC=<"%PROBE_DIR%\vcodec.txt"
|
||
set /p SRC_PROFILE=<"%PROBE_DIR%\profile.txt"
|
||
set /p SRC_WIDTH=<"%PROBE_DIR%\width.txt"
|
||
set /p SRC_HEIGHT=<"%PROBE_DIR%\height.txt"
|
||
set /p SRC_FPS_RAW=<"%PROBE_DIR%\fps.txt"
|
||
set /p SRC_PIXFMT=<"%PROBE_DIR%\pixfmt.txt"
|
||
set /p SRC_VBIT_BPS=<"%PROBE_DIR%\vbit.txt"
|
||
set /p DURATION=<"%PROBE_DIR%\duration.txt"
|
||
|
||
if not defined DURATION (
|
||
rd /s /q "%PROBE_DIR%" >nul 2>&1
|
||
echo.
|
||
echo ОШИБКА: не удалось определить длительность видео.
|
||
echo.
|
||
pause
|
||
exit /b 1
|
||
)
|
||
|
||
for /f "delims=" %%A in ('powershell.exe -NoProfile -Command "$p='!SRC_FPS_RAW!'.Split('/'); if($p.Count -eq 2 -and [double]$p[1] -ne 0){[math]::Round([double]$p[0]/[double]$p[1],3)}else{'!SRC_FPS_RAW!'}"') do set "SRC_FPS=%%A"
|
||
|
||
if defined SRC_VBIT_BPS (
|
||
for /f "delims=" %%A in ('powershell.exe -NoProfile -Command "[math]::Round([double]'!SRC_VBIT_BPS!'/1000)"') do set "SRC_VBIT_KBPS=%%A"
|
||
)
|
||
|
||
rem ============================================================
|
||
rem Аудио
|
||
rem ============================================================
|
||
|
||
set "SRC_ACODEC=Нет"
|
||
set "SRC_ABIT_BPS="
|
||
set "SRC_ABIT_KBPS=Н/Д"
|
||
set "SRC_SAMPLE_RATE=Н/Д"
|
||
set "SRC_CHANNELS=Н/Д"
|
||
set "HAS_AUDIO=0"
|
||
|
||
"%FFPROBE%" -v error -select_streams a:0 -show_entries stream=codec_name -of default=noprint_wrappers=1:nokey=1 "%~f1" > "%PROBE_DIR%\acodec.txt" 2>nul
|
||
for %%F in ("%PROBE_DIR%\acodec.txt") do if %%~zF GTR 0 set "HAS_AUDIO=1"
|
||
|
||
if "!HAS_AUDIO!"=="1" (
|
||
set /p SRC_ACODEC=<"%PROBE_DIR%\acodec.txt"
|
||
|
||
"%FFPROBE%" -v error -select_streams a:0 -show_entries stream=bit_rate -of default=noprint_wrappers=1:nokey=1 "%~f1" > "%PROBE_DIR%\abit.txt" 2>nul
|
||
"%FFPROBE%" -v error -select_streams a:0 -show_entries stream=sample_rate -of default=noprint_wrappers=1:nokey=1 "%~f1" > "%PROBE_DIR%\arate.txt" 2>nul
|
||
"%FFPROBE%" -v error -select_streams a:0 -show_entries stream=channels -of default=noprint_wrappers=1:nokey=1 "%~f1" > "%PROBE_DIR%\channels.txt" 2>nul
|
||
|
||
set /p SRC_ABIT_BPS=<"%PROBE_DIR%\abit.txt"
|
||
set /p SRC_SAMPLE_RATE=<"%PROBE_DIR%\arate.txt"
|
||
set /p SRC_CHANNELS=<"%PROBE_DIR%\channels.txt"
|
||
|
||
if defined SRC_ABIT_BPS (
|
||
for /f "delims=" %%A in ('powershell.exe -NoProfile -Command "[math]::Round([double]'!SRC_ABIT_BPS!'/1000)"') do set "SRC_ABIT_KBPS=%%A"
|
||
)
|
||
)
|
||
|
||
rd /s /q "%PROBE_DIR%" >nul 2>&1
|
||
|
||
for /f "delims=" %%A in ('powershell.exe -NoProfile -Command "$s=[double]::Parse('!DURATION!',[Globalization.CultureInfo]::InvariantCulture); [TimeSpan]::FromSeconds($s).ToString('hh\:mm\:ss\.fff')"') do set "DURATION_FORMATTED=%%A"
|
||
|
||
cls
|
||
echo.
|
||
echo ============================================================
|
||
echo ИСХОДНЫЙ ФАЙЛ
|
||
echo ============================================================
|
||
echo Файл : %~nx1
|
||
echo Длительность : !DURATION_FORMATTED!
|
||
echo.
|
||
echo ВИДЕО
|
||
echo Кодек : !SRC_VCODEC!
|
||
echo Профиль : !SRC_PROFILE!
|
||
echo Разрешение : !SRC_WIDTH!x!SRC_HEIGHT!
|
||
echo Частота кадров : !SRC_FPS! FPS
|
||
echo Формат пикселей : !SRC_PIXFMT!
|
||
echo Видеобитрейт : !SRC_VBIT_KBPS! кбит/с
|
||
echo.
|
||
echo АУДИО
|
||
echo Кодек : !SRC_ACODEC!
|
||
echo Аудиобитрейт : !SRC_ABIT_KBPS! кбит/с
|
||
echo Частота : !SRC_SAMPLE_RATE! Гц
|
||
echo Каналы : !SRC_CHANNELS!
|
||
echo ============================================================
|
||
echo.
|
||
pause
|
||
|
||
rem ============================================================
|
||
rem Выбор разрешения
|
||
rem ============================================================
|
||
|
||
cls
|
||
echo.
|
||
echo ============================================================
|
||
echo ВЫБЕРИТЕ ВЫХОДНОЕ РАЗРЕШЕНИЕ
|
||
echo ============================================================
|
||
echo [1] 1920x1080 - Full HD
|
||
echo [2] 1600x900
|
||
echo [3] 1536x864
|
||
echo [4] 1280x720 - HD
|
||
echo [5] Указать вручную
|
||
echo ============================================================
|
||
echo.
|
||
|
||
:resolution_menu
|
||
set "RES_CHOICE="
|
||
set /p "RES_CHOICE=Выберите 1, 2, 3, 4 или 5: "
|
||
|
||
if "!RES_CHOICE!"=="1" (
|
||
set "OUT_WIDTH=1920"
|
||
set "OUT_HEIGHT=1080"
|
||
goto resolution_selected
|
||
)
|
||
if "!RES_CHOICE!"=="2" (
|
||
set "OUT_WIDTH=1600"
|
||
set "OUT_HEIGHT=900"
|
||
goto resolution_selected
|
||
)
|
||
if "!RES_CHOICE!"=="3" (
|
||
set "OUT_WIDTH=1536"
|
||
set "OUT_HEIGHT=864"
|
||
goto resolution_selected
|
||
)
|
||
if "!RES_CHOICE!"=="4" (
|
||
set "OUT_WIDTH=1280"
|
||
set "OUT_HEIGHT=720"
|
||
goto resolution_selected
|
||
)
|
||
if "!RES_CHOICE!"=="5" goto custom_resolution
|
||
|
||
echo.
|
||
echo Неверный выбор. Введите число от 1 до 5.
|
||
echo.
|
||
goto resolution_menu
|
||
|
||
:custom_resolution
|
||
echo.
|
||
set /p "OUT_WIDTH=Введите ширину: "
|
||
set /p "OUT_HEIGHT=Введите высоту: "
|
||
|
||
if not defined OUT_WIDTH goto invalid_resolution
|
||
if not defined OUT_HEIGHT goto invalid_resolution
|
||
|
||
echo(!OUT_WIDTH!| findstr /R "^[0-9][0-9]*$" >nul || goto invalid_resolution
|
||
echo(!OUT_HEIGHT!| findstr /R "^[0-9][0-9]*$" >nul || goto invalid_resolution
|
||
goto resolution_selected
|
||
|
||
:invalid_resolution
|
||
echo.
|
||
echo ОШИБКА: ширина и высота должны быть целыми положительными числами.
|
||
echo.
|
||
pause
|
||
exit /b 1
|
||
|
||
:resolution_selected
|
||
|
||
rem ============================================================
|
||
rem Выбор FPS
|
||
rem ============================================================
|
||
|
||
cls
|
||
echo.
|
||
echo ============================================================
|
||
echo ВЫБЕРИТЕ ЧАСТОТУ КАДРОВ
|
||
echo ============================================================
|
||
echo Исходная частота: !SRC_FPS! FPS
|
||
echo.
|
||
echo [1] 24 FPS
|
||
echo [2] 30 FPS
|
||
echo [3] Оставить исходную
|
||
echo [4] Указать вручную
|
||
echo ============================================================
|
||
echo.
|
||
|
||
:fps_menu
|
||
set "FPS_CHOICE="
|
||
set /p "FPS_CHOICE=Выберите 1, 2, 3 или 4: "
|
||
|
||
if "!FPS_CHOICE!"=="1" (
|
||
set "FPS=24"
|
||
goto fps_selected
|
||
)
|
||
if "!FPS_CHOICE!"=="2" (
|
||
set "FPS=30"
|
||
goto fps_selected
|
||
)
|
||
if "!FPS_CHOICE!"=="3" (
|
||
set "FPS=!SRC_FPS!"
|
||
goto fps_selected
|
||
)
|
||
if "!FPS_CHOICE!"=="4" goto custom_fps
|
||
|
||
echo.
|
||
echo Неверный выбор. Введите число от 1 до 4.
|
||
echo.
|
||
goto fps_menu
|
||
|
||
:custom_fps
|
||
echo.
|
||
set /p "FPS=Введите FPS: "
|
||
if not defined FPS (
|
||
echo.
|
||
echo ОШИБКА: FPS не указан.
|
||
echo.
|
||
pause
|
||
exit /b 1
|
||
)
|
||
|
||
:fps_selected
|
||
|
||
if "!HAS_AUDIO!"=="0" set "AUDIO_KBPS=0"
|
||
|
||
rem ============================================================
|
||
rem Расчет видеобитрейта
|
||
rem ============================================================
|
||
|
||
for /f "delims=" %%B in ('powershell.exe -NoProfile -Command "$d=[double]::Parse('!DURATION!',[Globalization.CultureInfo]::InvariantCulture); [math]::Floor((!TARGET_BYTES!*8/1000/$d)-!AUDIO_KBPS!-!OVERHEAD_KBPS!)"') do set "VIDEO_KBPS=%%B"
|
||
|
||
if not defined VIDEO_KBPS (
|
||
echo.
|
||
echo ОШИБКА: не удалось рассчитать видеобитрейт.
|
||
echo.
|
||
pause
|
||
exit /b 1
|
||
)
|
||
|
||
if !VIDEO_KBPS! LSS 300 (
|
||
echo.
|
||
echo ОШИБКА: рассчитанный видеобитрейт слишком низкий.
|
||
echo Получено: !VIDEO_KBPS! кбит/с
|
||
echo Выберите меньшее разрешение или увеличьте целевой размер.
|
||
echo.
|
||
pause
|
||
exit /b 1
|
||
)
|
||
|
||
for /f "delims=" %%I in ('powershell.exe -NoProfile -Command "Get-Date -Format yyyy-MM-dd_HH-mm-ss"') do set "TODAY=%%I"
|
||
|
||
set "OUTPUT_DIR=%~dp0output"
|
||
if not exist "!OUTPUT_DIR!" mkdir "!OUTPUT_DIR!" >nul 2>&1
|
||
|
||
set "OUT=!OUTPUT_DIR!\!TODAY!_Express_!OUT_WIDTH!x!OUT_HEIGHT!_!FPS!fps.mp4"
|
||
set "PASSLOG=%TEMP%\express_svtpass_!RANDOM!_!RANDOM!"
|
||
|
||
set "VIDEO_FILTER=fps=!FPS!,scale=!OUT_WIDTH!:!OUT_HEIGHT!:force_original_aspect_ratio=decrease:flags=lanczos,pad=!OUT_WIDTH!:!OUT_HEIGHT!:(ow-iw)/2:(oh-ih)/2"
|
||
|
||
cls
|
||
echo.
|
||
echo ============================================================
|
||
echo ПОДГОТОВКА ВИДЕО ДЛЯ EXPRESS
|
||
echo ============================================================
|
||
echo Разрешение : !OUT_WIDTH!x!OUT_HEIGHT!
|
||
echo Частота кадров : !FPS! FPS
|
||
echo Видеокодек : AV1 (SVT-AV1)
|
||
echo Видеобитрейт : !VIDEO_KBPS! кбит/с
|
||
if "!HAS_AUDIO!"=="1" (
|
||
echo Аудио : AAC, !AUDIO_KBPS! кбит/с, стерео
|
||
) else (
|
||
echo Аудио : отсутствует
|
||
)
|
||
echo Формат пикселей : yuv420p10le
|
||
echo Целевой размер : около !TARGET_MB! МБ
|
||
echo Первый проход : preset !FIRST_PASS_PRESET!
|
||
echo Второй проход : preset !SECOND_PASS_PRESET!
|
||
echo.
|
||
echo Результат будет сохранен в:
|
||
echo !OUTPUT_DIR!
|
||
echo ============================================================
|
||
echo.
|
||
|
||
:confirm_menu
|
||
set "CONFIRM="
|
||
set /p "CONFIRM=Начать кодирование? [Y/N]: "
|
||
|
||
if /I "!CONFIRM!"=="Y" goto start_encoding
|
||
if /I "!CONFIRM!"=="N" (
|
||
echo.
|
||
echo Кодирование отменено.
|
||
echo.
|
||
pause
|
||
exit /b 0
|
||
)
|
||
|
||
echo.
|
||
echo Введите Y или N.
|
||
echo.
|
||
goto confirm_menu
|
||
|
||
:start_encoding
|
||
|
||
echo.
|
||
echo [1/2] Анализ видео...
|
||
echo.
|
||
|
||
"%FFMPEG%" -y -i "%~f1" ^
|
||
-map 0:v:0 ^
|
||
-vf "!VIDEO_FILTER!" ^
|
||
-c:v libsvtav1 ^
|
||
-b:v !VIDEO_KBPS!k ^
|
||
-preset !FIRST_PASS_PRESET! ^
|
||
-pass 1 ^
|
||
-passlogfile "!PASSLOG!" ^
|
||
-pix_fmt yuv420p10le ^
|
||
-an ^
|
||
-f null NUL
|
||
|
||
if errorlevel 1 goto error
|
||
|
||
echo.
|
||
echo [2/2] Кодирование видео...
|
||
echo.
|
||
|
||
if "!HAS_AUDIO!"=="1" (
|
||
"%FFMPEG%" -y -i "%~f1" ^
|
||
-map 0:v:0 ^
|
||
-map 0:a:0? ^
|
||
-vf "!VIDEO_FILTER!" ^
|
||
-c:v libsvtav1 ^
|
||
-b:v !VIDEO_KBPS!k ^
|
||
-preset !SECOND_PASS_PRESET! ^
|
||
-pass 2 ^
|
||
-passlogfile "!PASSLOG!" ^
|
||
-pix_fmt yuv420p10le ^
|
||
-tag:v av01 ^
|
||
-c:a aac ^
|
||
-b:a !AUDIO_KBPS!k ^
|
||
-ac 2 ^
|
||
-movflags +faststart ^
|
||
-f mp4 ^
|
||
"!OUT!"
|
||
) else (
|
||
"%FFMPEG%" -y -i "%~f1" ^
|
||
-map 0:v:0 ^
|
||
-vf "!VIDEO_FILTER!" ^
|
||
-c:v libsvtav1 ^
|
||
-b:v !VIDEO_KBPS!k ^
|
||
-preset !SECOND_PASS_PRESET! ^
|
||
-pass 2 ^
|
||
-passlogfile "!PASSLOG!" ^
|
||
-pix_fmt yuv420p10le ^
|
||
-tag:v av01 ^
|
||
-an ^
|
||
-movflags +faststart ^
|
||
-f mp4 ^
|
||
"!OUT!"
|
||
)
|
||
|
||
if errorlevel 1 goto error
|
||
|
||
del /q "!PASSLOG!*" >nul 2>&1
|
||
|
||
for %%F in ("!OUT!") do set "FINAL_BYTES=%%~zF"
|
||
for /f "delims=" %%M in ('powershell.exe -NoProfile -Command "[math]::Round(!FINAL_BYTES!/1000000,2)"') do set "FINAL_MB=%%M"
|
||
|
||
echo.
|
||
echo ============================================================
|
||
echo ГОТОВО
|
||
echo ============================================================
|
||
echo Файл : !OUT!
|
||
echo Размер : !FINAL_MB! МБ
|
||
echo ============================================================
|
||
echo.
|
||
pause
|
||
exit /b 0
|
||
|
||
:error
|
||
del /q "!PASSLOG!*" >nul 2>&1
|
||
if defined OUT if exist "!OUT!" del /q "!OUT!" >nul 2>&1
|
||
|
||
echo.
|
||
echo ============================================================
|
||
echo ОШИБКА КОДИРОВАНИЯ
|
||
echo ============================================================
|
||
echo FFmpeg завершил работу с ошибкой.
|
||
echo.
|
||
pause
|
||
exit /b 1
|