47 lines
1.3 KiB
Python
47 lines
1.3 KiB
Python
import asyncio
|
||
from pathlib import Path
|
||
import shutil
|
||
import subprocess
|
||
|
||
FFMPEG_BIN = shutil.which("ffmpeg") or "ffmpeg"
|
||
|
||
async def transcode_to_mobile_mp4(src: Path) -> Path:
|
||
"""
|
||
Перекодировать видео в MP4, совместимый с мобильными клиентами Telegram:
|
||
- H.264 (libx264), профиль main
|
||
- pix_fmt yuv420p
|
||
- movflags +faststart
|
||
- AAC 128k
|
||
Возвращает путь к новому файлу (.tg.mp4).
|
||
"""
|
||
if not src.exists():
|
||
raise FileNotFoundError(f"Source file not found: {src}")
|
||
|
||
dst = src.with_suffix(".tg.mp4")
|
||
cmd = [
|
||
FFMPEG_BIN,
|
||
"-y",
|
||
"-i", str(src),
|
||
"-c:v", "libx264",
|
||
"-preset", "veryfast",
|
||
"-crf", "23",
|
||
"-profile:v", "main",
|
||
"-pix_fmt", "yuv420p",
|
||
"-movflags", "+faststart",
|
||
"-c:a", "aac",
|
||
"-b:a", "128k",
|
||
str(dst),
|
||
]
|
||
|
||
def _run():
|
||
proc = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||
if proc.returncode != 0:
|
||
raise RuntimeError(f"ffmpeg failed: {proc.stderr.decode('utf-8', errors='ignore')}")
|
||
|
||
loop = asyncio.get_running_loop()
|
||
await loop.run_in_executor(None, _run)
|
||
|
||
if not dst.exists():
|
||
raise RuntimeError("Transcode failed: output file not created")
|
||
return dst
|