File size: 2,199 Bytes
af32e72
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
from __future__ import annotations

import subprocess
import threading
from pathlib import Path
from .startup import get_ffmpeg_path


def _transcode_file(src: Path, tmp_suffix: str = ".trans.mp4") -> bool:
    """Transcode `src` to H.264 mp4 using ffmpeg in-place (via temp file).
    Returns True if replaced successfully.
    """
    ffmpeg = get_ffmpeg_path()
    if not ffmpeg:
        return False
    tmp = src.with_suffix(src.suffix + tmp_suffix)
    cmd = [
        ffmpeg, "-y", "-i", str(src),
        "-c:v", "libx264", "-preset", "veryfast", "-crf", "23",
        "-pix_fmt", "yuv420p", "-movflags", "+faststart", str(tmp),
    ]
    try:
        ret = subprocess.run(cmd, capture_output=True, check=False)
        if ret.returncode != 0 or not tmp.exists() or tmp.stat().st_size == 0:
            try:
                tmp.unlink(missing_ok=True)
            except Exception:
                pass
            return False
        # replace original
        tmp.replace(src)
        return True
    except Exception:
        try:
            tmp.unlink(missing_ok=True)
        except Exception:
            pass
        return False


def transcode_clips_in_dir(dirpath: Path) -> int:
    """Transcode matching files under `dirpath`. Returns count replaced."""
    replaced = 0
    if not get_ffmpeg_path():
        return 0
    for p in dirpath.rglob("*.mp4"):
        # skip files that are already small or likely h264? We transcode anyway.
        try:
            if p.stat().st_size == 0:
                continue
            ok = _transcode_file(p)
            if ok:
                replaced += 1
        except Exception:
            continue
    return replaced


def transcode_clips_async(base_dir: Path) -> threading.Thread:
    """Start background thread to transcode clips under `base_dir` and return the Thread."""
    def _worker():
        try:
            count = transcode_clips_in_dir(base_dir)
            if count:
                print(f"[transcode] replaced {count} clip(s) with H.264-encoded MP4s")
        except Exception as exc:
            print(f"[transcode] error: {exc}")

    t = threading.Thread(target=_worker, daemon=True)
    t.start()
    return t