Commit ·
bdb2cf1
1
Parent(s): afa947b
Fix infinite retry loop in video upload transcode
Browse filesLive logs (pulled via `hf spaces logs`) showed 39 repeated failures
alternating between "SDR_Render__h264.mp4" and "SDR_Render__gr_conv.mp4"
"No such file or directory" for a single upload — an infinite loop
between _transcode_for_browser and Gradio's own internal conversion,
each re-triggering on the other's (since-cleaned-up) output via the
cross-tab _sync propagation.
_transcode_for_browser now short-circuits to a no-op gr.update() when
its input is already one of these generated filenames, or no longer
exists on disk — breaking the cycle regardless of the exact re-trigger
mechanism, since there's no longer a path for a re-triggered handler to
chase.
app.py
CHANGED
|
@@ -338,7 +338,7 @@ def strip_audio_from_video(video_path: str, output_path: str) -> None:
|
|
| 338 |
pix_fmt="yuv420p", an=None,
|
| 339 |
).run(overwrite_output=True, quiet=True)
|
| 340 |
|
| 341 |
-
def _transcode_for_browser(video_path: str)
|
| 342 |
"""Re-encode uploaded video to H.264/AAC MP4 so the browser preview widget can play it.
|
| 343 |
|
| 344 |
Returns a NEW path in a fresh /tmp/gradio/ subdirectory. Gradio probes the
|
|
@@ -346,9 +346,26 @@ def _transcode_for_browser(video_path: str) -> str:
|
|
| 346 |
slow fallback converter. The in-place overwrite approach loses the race
|
| 347 |
because Gradio probes the original path at upload time before this callback runs.
|
| 348 |
Only called on upload — not during generation.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 349 |
"""
|
| 350 |
if video_path is None:
|
| 351 |
return video_path
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 352 |
try:
|
| 353 |
probe = ffmpeg.probe(video_path)
|
| 354 |
has_audio = any(s["codec_type"] == "audio" for s in probe.get("streams", []))
|
|
|
|
| 338 |
pix_fmt="yuv420p", an=None,
|
| 339 |
).run(overwrite_output=True, quiet=True)
|
| 340 |
|
| 341 |
+
def _transcode_for_browser(video_path: str):
|
| 342 |
"""Re-encode uploaded video to H.264/AAC MP4 so the browser preview widget can play it.
|
| 343 |
|
| 344 |
Returns a NEW path in a fresh /tmp/gradio/ subdirectory. Gradio probes the
|
|
|
|
| 346 |
slow fallback converter. The in-place overwrite approach loses the race
|
| 347 |
because Gradio probes the original path at upload time before this callback runs.
|
| 348 |
Only called on upload — not during generation.
|
| 349 |
+
|
| 350 |
+
Cross-tab sync (_sync) mirrors whatever this returns onto the other two
|
| 351 |
+
tabs' Video components, and each of THEIR .upload() handlers can re-fire
|
| 352 |
+
on that reassignment — without the guards below, that reprocesses an
|
| 353 |
+
already-transcoded "_h264.mp4"/"_gr_conv.mp4" file, and if it has since
|
| 354 |
+
been cleaned up this turns into an infinite failed-retry loop (observed
|
| 355 |
+
in prod: 39 repeated "No such file" failures alternating between the two
|
| 356 |
+
names for one upload). Both guards return gr.update() (no-op, doesn't
|
| 357 |
+
touch the component's value) instead of re-assigning a path, so there's
|
| 358 |
+
nothing for a re-triggered handler to chase.
|
| 359 |
"""
|
| 360 |
if video_path is None:
|
| 361 |
return video_path
|
| 362 |
+
base = os.path.basename(video_path)
|
| 363 |
+
if base.endswith("_h264.mp4") or base.endswith("_gr_conv.mp4"):
|
| 364 |
+
print(f"[transcode_for_browser] already processed ({base}), skipping")
|
| 365 |
+
return gr.update()
|
| 366 |
+
if not os.path.exists(video_path):
|
| 367 |
+
print(f"[transcode_for_browser] input vanished before processing: {video_path!r}")
|
| 368 |
+
return gr.update()
|
| 369 |
try:
|
| 370 |
probe = ffmpeg.probe(video_path)
|
| 371 |
has_audio = any(s["codec_type"] == "audio" for s in probe.get("streams", []))
|