webm file supported
This commit is contained in:
@@ -29,6 +29,60 @@ from .transcription import (
|
|||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
MOSS_ALGORITHM_VERSION = "moss-punctuation-v3"
|
MOSS_ALGORITHM_VERSION = "moss-punctuation-v3"
|
||||||
SILENCE_ALGORITHM_VERSION = "silence-rms-v1"
|
SILENCE_ALGORITHM_VERSION = "silence-rms-v1"
|
||||||
|
_CUES_ID = b"\x1e\x53\xb6\x80"
|
||||||
|
_CLUSTER_ID = b"\x1f\x43\xb6\x75"
|
||||||
|
_HEADER_SCAN_SIZE = 64 * 1024
|
||||||
|
_WEBM_SUFFIXES = {".webm", ".mkv"}
|
||||||
|
|
||||||
|
|
||||||
|
def _webm_cues_at_front(filepath: Path) -> bool:
|
||||||
|
"""Return True if WebM/MKV CUES appear before the first Cluster."""
|
||||||
|
try:
|
||||||
|
with open(filepath, "rb") as f:
|
||||||
|
header = f.read(_HEADER_SCAN_SIZE)
|
||||||
|
except OSError:
|
||||||
|
return True # can't read → assume OK, don't touch
|
||||||
|
cues_pos = header.find(_CUES_ID)
|
||||||
|
cluster_pos = header.find(_CLUSTER_ID)
|
||||||
|
if cues_pos != -1 and (cluster_pos == -1 or cues_pos < cluster_pos):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def _ensure_webm_cues_front(filepath: Path) -> None:
|
||||||
|
"""Re-mux a WebM/MKV file (stream copy) if CUES are not at the front.
|
||||||
|
|
||||||
|
YouTube-dl / yt-dlp writes CUES at the end by default, which slows HTTP
|
||||||
|
Range seeking. This runs once during upload processing and takes seconds.
|
||||||
|
"""
|
||||||
|
if filepath.suffix.lower() not in _WEBM_SUFFIXES:
|
||||||
|
return
|
||||||
|
if _webm_cues_at_front(filepath):
|
||||||
|
return
|
||||||
|
ffmpeg = shutil.which("ffmpeg")
|
||||||
|
if not ffmpeg:
|
||||||
|
logger.warning("ffmpeg not found; skipping WebM CUES optimization.")
|
||||||
|
return
|
||||||
|
tmp = filepath.with_suffix(".cues_tmp" + filepath.suffix)
|
||||||
|
try:
|
||||||
|
result = subprocess.run(
|
||||||
|
[ffmpeg, "-y", "-loglevel", "error",
|
||||||
|
"-i", str(filepath), "-c", "copy",
|
||||||
|
"-cues_to_front", "1", str(tmp)],
|
||||||
|
capture_output=True, timeout=300,
|
||||||
|
)
|
||||||
|
if result.returncode == 0 and tmp.is_file() and tmp.stat().st_size > 0:
|
||||||
|
tmp.replace(filepath)
|
||||||
|
logger.info("WebM CUES moved to front: %s", filepath.name)
|
||||||
|
else:
|
||||||
|
logger.warning(
|
||||||
|
"WebM CUES re-mux failed for %s: rc=%d stderr=%s",
|
||||||
|
filepath.name, result.returncode, result.stderr.decode()[-200:],
|
||||||
|
)
|
||||||
|
except (subprocess.TimeoutExpired, OSError) as exc:
|
||||||
|
logger.warning("WebM CUES re-mux error for %s: %s", filepath.name, exc)
|
||||||
|
finally:
|
||||||
|
tmp.unlink(missing_ok=True)
|
||||||
|
|
||||||
|
|
||||||
class VideoProcessor:
|
class VideoProcessor:
|
||||||
@@ -55,6 +109,7 @@ class VideoProcessor:
|
|||||||
self.repository.mark_processing(video_hash)
|
self.repository.mark_processing(video_hash)
|
||||||
work_path: Optional[Path] = None
|
work_path: Optional[Path] = None
|
||||||
try:
|
try:
|
||||||
|
_ensure_webm_cues_front(media_path)
|
||||||
if self.transcriber.available:
|
if self.transcriber.available:
|
||||||
work_path = self.settings.work_dir / f"{video_hash}-{uuid.uuid4().hex}.wav"
|
work_path = self.settings.work_dir / f"{video_hash}-{uuid.uuid4().hex}.wav"
|
||||||
extract_audio(media_path, work_path)
|
extract_audio(media_path, work_path)
|
||||||
|
|||||||
Reference in New Issue
Block a user