engine children: pass CREATE_NO_WINDOW on every ffmpeg/ffprobe spawn
The queues run the engines under pythonw.exe (no console). A console-subsystem child spawned by a console-less parent without CREATE_NO_WINDOW makes Windows allocate a NEW console and SHOW it - one visible window per ffprobe/ffmpeg call (measured 2026-10-11: Windows Terminal windows titled with the ffmpeg binary while two encodes ran). Fixed: transcode.run(), library_run.run()/run_watched() and the three gate helpers that call ffmpeg directly (SSIM filtergraph, per-offset pairs, VMAF). Proof (cache/scratch/nowin_test4.py, run in a DETACHED pythonw: GetConsoleWindow()==0, like the engine): raw Popen without the flag -> 1 new visible console window; with the flag -> none) -> 0; transcode.run() -> 0 windows, library_run.run() -> 0, library_run.run_watched() -> 0.
This commit is contained in:
+13
-4
@@ -38,6 +38,11 @@ import transcode as T # noqa: E402
|
||||
|
||||
FFMPEG = T.FFMPEG
|
||||
FFPROBE = T.FFPROBE
|
||||
# A console-less parent (the queues run the engines under pythonw.exe) makes every console-subsystem
|
||||
# child - ffmpeg, ffprobe - allocate a NEW console and SHOW it: measured 2026-10-11, one visible
|
||||
# Windows Terminal window per spawned child while two encodes ran. CREATE_NO_WINDOW suppresses that
|
||||
# (0 on POSIX, where the flag does not exist).
|
||||
NOWIN = getattr(subprocess, "CREATE_NO_WINDOW", 0)
|
||||
ROOT = r"Z:\Class\樊登读书\樊登读书会(每周更新)"
|
||||
WORK = r"C:\AI\transcode-run"
|
||||
STAGE = os.path.join(WORK, "stage")
|
||||
@@ -197,6 +202,7 @@ def probe(p, tries=3):
|
||||
|
||||
|
||||
def run(cmd, timeout=86400, **kw):
|
||||
kw.setdefault("creationflags", NOWIN) # never a visible console per call
|
||||
return subprocess.run(cmd, capture_output=True, text=True, encoding="utf-8",
|
||||
errors="replace", timeout=timeout, **kw)
|
||||
|
||||
@@ -223,7 +229,7 @@ def run_watched(cmd, watch, stall_s=STALL_S, timeout=86400):
|
||||
errf = watch + ".err"
|
||||
err = ""
|
||||
with open(errf, "wb") as ferr:
|
||||
p = subprocess.Popen(cmd, stdout=subprocess.DEVNULL, stderr=ferr)
|
||||
p = subprocess.Popen(cmd, stdout=subprocess.DEVNULL, stderr=ferr, creationflags=NOWIN)
|
||||
last, last_t, t0 = -1, time.time(), time.time()
|
||||
while p.poll() is None:
|
||||
time.sleep(30)
|
||||
@@ -538,7 +544,8 @@ def ssim_vs_source(src_local, out_local, info, workdir, tag, dur=SSIM_WINDOW):
|
||||
subprocess.run([FFMPEG, "-y", "-v", "error", "-f", "rawvideo", "-pix_fmt", "yuv420p", "-s", cmp_scale,
|
||||
"-i", ref, "-f", "rawvideo", "-pix_fmt", "yuv420p", "-s", cmp_scale, "-i", out,
|
||||
"-lavfi", "ssim=stats_file=ssim_%s.log" % tag, "-f", "null", "-"],
|
||||
capture_output=True, cwd=workdir, timeout=900)
|
||||
capture_output=True, cwd=workdir, timeout=900,
|
||||
creationflags=NOWIN)
|
||||
except subprocess.TimeoutExpired:
|
||||
# A wedged ffmpeg must not hang the item forever: without this the lane would sit on a dead
|
||||
# filtergraph until a human noticed (measured outside the engine 2026-10-11: a stalled
|
||||
@@ -674,7 +681,8 @@ def _ssim_series(ref_raw, out_raw, off, nf, workdir, tag):
|
||||
subprocess.run([FFMPEG, "-y", "-v", "error", "-f", "rawvideo", "-pix_fmt", "yuv420p", "-s", "480:270",
|
||||
"-i", pa, "-f", "rawvideo", "-pix_fmt", "yuv420p", "-s", "480:270", "-i", pb,
|
||||
"-lavfi", "ssim=stats_file=%s" % os.path.basename(log), "-f", "null", "-"],
|
||||
capture_output=True, cwd=workdir, timeout=900)
|
||||
capture_output=True, cwd=workdir, timeout=900,
|
||||
creationflags=NOWIN)
|
||||
except subprocess.TimeoutExpired:
|
||||
# one offset that cannot be scored is data we do not have - never a hang and never a verdict
|
||||
log(" ! pair ssim at off %+d timed out after 900 s - skipping this offset" % off)
|
||||
@@ -724,7 +732,8 @@ def vmaf_of_pair(ref_raw, out_raw, off, nf, workdir, tag):
|
||||
_copy_frames(out_raw, pb, max(0, -off), k, fs)
|
||||
subprocess.run([FFMPEG, "-y", "-v", "error"] + raw + ["-i", pb] + raw + ["-i", pa,
|
||||
"-lavfi", "libvmaf=log_path=%s:log_fmt=json" % os.path.basename(log),
|
||||
"-f", "null", "-"], capture_output=True, cwd=workdir, timeout=900)
|
||||
"-f", "null", "-"], capture_output=True, cwd=workdir, timeout=900,
|
||||
creationflags=NOWIN)
|
||||
with open(log, encoding="utf-8", errors="replace") as fh:
|
||||
m = json.load(fh)["pooled_metrics"]["vmaf"]
|
||||
return {"mean": float(m["mean"]), "min": float(m["min"]), "frames": k}
|
||||
|
||||
@@ -47,9 +47,16 @@ def log(*a):
|
||||
print(time.strftime("%H:%M:%S ") + " ".join(str(x) for x in a), flush=True)
|
||||
|
||||
|
||||
# A console-less parent (the queues run the engines under pythonw.exe) makes every console-subsystem
|
||||
# child - ffmpeg, ffprobe - allocate a NEW console and SHOW it: measured 2026-10-11, one visible
|
||||
# Windows Terminal window per spawned child while two encodes ran. CREATE_NO_WINDOW suppresses that
|
||||
# (0 on POSIX, where the flag does not exist).
|
||||
NOWIN = getattr(subprocess, "CREATE_NO_WINDOW", 0)
|
||||
|
||||
def run(cmd, timeout=86400):
|
||||
return subprocess.run(cmd, capture_output=True, text=True,
|
||||
encoding="utf-8", errors="replace", timeout=timeout)
|
||||
encoding="utf-8", errors="replace", timeout=timeout,
|
||||
creationflags=NOWIN)
|
||||
|
||||
|
||||
def _fps(v):
|
||||
|
||||
Reference in New Issue
Block a user