103 lines
2.4 KiB
Python
103 lines
2.4 KiB
Python
"""
|
|
Generate and cache low-bitrate preview proxies for browser playback.
|
|
|
|
Goal:
|
|
- Improve Remotion Player preview smoothness by serving smaller/faster-to-decode videos.
|
|
- Keep original `source_path` for accurate export; only swap `source_url` for preview.
|
|
|
|
Design:
|
|
- Deterministic cache key based on (path, mtime, size).
|
|
- Proxy lives under config.TEMP_DIR / "proxy".
|
|
- Generated with ffmpeg: scale/pad + fps downsample + faststart + no audio.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import hashlib
|
|
import os
|
|
from pathlib import Path
|
|
from typing import Optional, Tuple
|
|
|
|
import config
|
|
from modules import ffmpeg_utils
|
|
|
|
|
|
def _key_for_file(path: str) -> str:
|
|
st = os.stat(path)
|
|
raw = f"{path}|{st.st_mtime_ns}|{st.st_size}".encode("utf-8")
|
|
return hashlib.sha1(raw).hexdigest() # short, deterministic
|
|
|
|
|
|
def ensure_video_proxy(
|
|
source_path: str,
|
|
*,
|
|
target_w: int = 540,
|
|
target_h: int = 960,
|
|
target_fps: int = 24,
|
|
crf: int = 28,
|
|
preset: str = "veryfast",
|
|
) -> Tuple[Optional[str], Optional[str]]:
|
|
"""
|
|
Ensure a preview proxy exists for source_path.
|
|
|
|
Returns: (proxy_path, proxy_url) or (None, None) if source_path invalid.
|
|
"""
|
|
if not source_path or not os.path.exists(source_path):
|
|
return None, None
|
|
|
|
proxy_dir = Path(config.TEMP_DIR) / "proxy"
|
|
proxy_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
key = _key_for_file(source_path)
|
|
out_name = f"proxy_{key}.mp4"
|
|
out_path = proxy_dir / out_name
|
|
|
|
if out_path.exists() and out_path.stat().st_size > 1024:
|
|
return str(out_path), f"/static/temp/proxy/{out_name}"
|
|
|
|
vf = (
|
|
f"scale={target_w}:{target_h}:force_original_aspect_ratio=decrease,"
|
|
f"pad={target_w}:{target_h}:(ow-iw)/2:(oh-ih)/2:black,"
|
|
f"fps={target_fps}"
|
|
)
|
|
|
|
cmd = [
|
|
ffmpeg_utils.FFMPEG_PATH,
|
|
"-y",
|
|
"-i",
|
|
source_path,
|
|
"-an", # preview 不要音轨,减少解码负担(旁白/BGM 走单独轨道)
|
|
"-vf",
|
|
vf,
|
|
"-c:v",
|
|
"libx264",
|
|
"-preset",
|
|
preset,
|
|
"-crf",
|
|
str(crf),
|
|
"-tune",
|
|
"fastdecode",
|
|
"-pix_fmt",
|
|
"yuv420p",
|
|
"-movflags",
|
|
"+faststart",
|
|
str(out_path),
|
|
]
|
|
|
|
ffmpeg_utils._run_ffmpeg(cmd)
|
|
if out_path.exists() and out_path.stat().st_size > 1024:
|
|
return str(out_path), f"/static/temp/proxy/{out_name}"
|
|
return None, None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|