JS6969 commited on
Commit
9075525
·
verified ·
1 Parent(s): 92bbe23

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +38 -21
app.py CHANGED
@@ -20,8 +20,8 @@ def render_logo_html(px: int = 96) -> str:
20
  <div style="display:flex;align-items:center;gap:16px;">
21
  {img}
22
  <div>
23
- <div style="font-size:1.6rem;font-weight:800;">Bifröst · Re-encode Video</div>
24
- <div style="opacity:0.8;">Frames → Video, optional audio mux</div>
25
  </div>
26
  </div>
27
  <hr>
@@ -69,24 +69,34 @@ def prepare_frames_from_upload(files: List[gr.File] | None, prefix: str = "enc")
69
  counter += 1
70
  return str(frames_dir), prefix
71
 
72
- def build_ffmpeg_encode(frames_dir: str, prefix: str, fps: float, fmt: str, include_audio: bool, orig_video: str | None) -> list[str]:
73
- pattern_jpg = Path(frames_dir) / f"{prefix}_%05d.jpg"
74
- pattern_png = Path(frames_dir) / f"{prefix}_%05d.png"
75
- pattern = str(pattern_jpg if pattern_jpg.exists() else pattern_png)
76
- if not Path(pattern.replace("%05d", "00001")).with_suffix(Path(pattern).suffix).exists():
77
- # if first frame isn't 00001, we still let ffmpeg start_number 1; files must be named *_00001.*
78
- pass
79
- args = [FFMPEG, "-y", "-start_number", "1", "-framerate", f"{fps:.6f}", "-i", pattern]
 
 
 
 
 
 
 
80
  if include_audio and orig_video:
81
  args += ["-i", orig_video, "-map", "0:v:0", "-map", "1:a:0", "-shortest"]
 
82
  if fmt == "h265":
83
  vcodec = ["-c:v", "libx265"]
84
  elif fmt == "vp9":
85
  vcodec = ["-c:v", "libvpx-vp9"]
86
  else:
87
  vcodec = ["-c:v", "libx264"]
88
- args += vcodec + ["-pix_fmt", "yuv420p", "-crf", "18", "output.mp4" if fmt in ("h264", "h265") else "output.webm"]
89
- return args
 
 
90
 
91
  def step3_encode(
92
  uploaded_frames: List[gr.File] | None,
@@ -109,16 +119,21 @@ def step3_encode(
109
 
110
  # Add progress pipe and run in frames_dir for clean output pathing
111
  cmd = [cmd[0], "-progress", "pipe:2"] + cmd[1:]
112
- proc = subprocess.Popen(cmd, stderr=subprocess.PIPE, stdout=subprocess.DEVNULL, text=True, bufsize=1, cwd=frames_dir)
113
-
 
 
 
114
  # Approximate by counting files
115
  total_frames = len(list(Path(frames_dir).glob(f"{prefix}_*.jpg"))) + len(list(Path(frames_dir).glob(f"{prefix}_*.png")))
116
  current = 0
117
-
 
118
  while True:
119
  line = proc.stderr.readline()
120
  if not line and proc.poll() is not None:
121
  break
 
122
  if "frame=" in line:
123
  try:
124
  current = int(line.strip().split("=")[-1])
@@ -129,18 +144,20 @@ def step3_encode(
129
  yield None, f"Encoding… {current}/{total_frames} frames", render_progress(pct, f"Encoding {pct:.0f}%")
130
  else:
131
  yield None, "Encoding…", render_progress(50.0, "Encoding…")
132
-
 
 
 
 
133
  ret = proc.wait()
134
  out_file = Path(frames_dir) / ("output.mp4" if fmt in ("h264", "h265") else "output.webm")
 
135
  if ret != 0 or not out_file.exists():
136
- err = ""
137
- try:
138
- err = proc.stderr.read() if proc.stderr else ""
139
- except Exception:
140
- pass
141
  yield None, f"Encoding failed.\n\n{err}", render_progress(0.0, "Failed")
142
  return
143
 
 
144
  yield str(out_file), f"Video created: {out_file.name}", render_progress(100.0, "Encoding complete")
145
 
146
  def build_ui():
 
20
  <div style="display:flex;align-items:center;gap:16px;">
21
  {img}
22
  <div>
23
+ <div style="font-size:1.6rem;font-weight:800;">Valknut · Re-encode Video</div>
24
+ <div style="opacity:0.8;">Frames → Video, optional audio mix</div>
25
  </div>
26
  </div>
27
  <hr>
 
69
  counter += 1
70
  return str(frames_dir), prefix
71
 
72
+ def build_ffmpeg_encode(frames_dir: str, prefix: str, fps: float, fmt: str,
73
+ include_audio: bool, orig_video: str | None) -> list[str]:
74
+ jpgs = sorted(Path(frames_dir).glob(f"{prefix}_*.jpg"))
75
+ pngs = sorted(Path(frames_dir).glob(f"{prefix}_*.png"))
76
+ imgs = jpgs if jpgs else pngs
77
+ if not imgs:
78
+ return []
79
+
80
+ first_frame = imgs[0].name
81
+ pattern = str(imgs[0].with_name(f"{prefix}_%05d{imgs[0].suffix}"))
82
+ start_num = int(Path(first_frame).stem.split("_")[-1])
83
+
84
+ args = [FFMPEG, "-y", "-start_number", str(start_num),
85
+ "-framerate", f"{fps:.6f}", "-i", pattern]
86
+
87
  if include_audio and orig_video:
88
  args += ["-i", orig_video, "-map", "0:v:0", "-map", "1:a:0", "-shortest"]
89
+
90
  if fmt == "h265":
91
  vcodec = ["-c:v", "libx265"]
92
  elif fmt == "vp9":
93
  vcodec = ["-c:v", "libvpx-vp9"]
94
  else:
95
  vcodec = ["-c:v", "libx264"]
96
+
97
+ out_name = "output.mp4" if fmt in ("h264", "h265") else "output.webm"
98
+ return args + vcodec + ["-pix_fmt", "yuv420p", "-crf", "18", out_name]
99
+
100
 
101
  def step3_encode(
102
  uploaded_frames: List[gr.File] | None,
 
119
 
120
  # Add progress pipe and run in frames_dir for clean output pathing
121
  cmd = [cmd[0], "-progress", "pipe:2"] + cmd[1:]
122
+ proc = subprocess.Popen(
123
+ cmd, stderr=subprocess.PIPE, stdout=subprocess.DEVNULL,
124
+ text=True, bufsize=1, cwd=frames_dir
125
+ )
126
+
127
  # Approximate by counting files
128
  total_frames = len(list(Path(frames_dir).glob(f"{prefix}_*.jpg"))) + len(list(Path(frames_dir).glob(f"{prefix}_*.png")))
129
  current = 0
130
+ errors = [] # ✅ collect errors while streaming
131
+
132
  while True:
133
  line = proc.stderr.readline()
134
  if not line and proc.poll() is not None:
135
  break
136
+
137
  if "frame=" in line:
138
  try:
139
  current = int(line.strip().split("=")[-1])
 
144
  yield None, f"Encoding… {current}/{total_frames} frames", render_progress(pct, f"Encoding {pct:.0f}%")
145
  else:
146
  yield None, "Encoding…", render_progress(50.0, "Encoding…")
147
+
148
+ # ✅ collect suspicious lines (errors, missing files, etc.)
149
+ if "Error" in line or "No such file" in line:
150
+ errors.append(line.strip())
151
+
152
  ret = proc.wait()
153
  out_file = Path(frames_dir) / ("output.mp4" if fmt in ("h264", "h265") else "output.webm")
154
+
155
  if ret != 0 or not out_file.exists():
156
+ err = "\n".join(errors) or "Unknown ffmpeg error."
 
 
 
 
157
  yield None, f"Encoding failed.\n\n{err}", render_progress(0.0, "Failed")
158
  return
159
 
160
+
161
  yield str(out_file), f"Video created: {out_file.name}", render_progress(100.0, "Encoding complete")
162
 
163
  def build_ui():