@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