victor HF Staff commited on
Commit
5c95722
·
1 Parent(s): bbc25a7

feat: Implement GPU optimization for FFmpeg commands and enhance filter conversion

Browse files
Files changed (1) hide show
  1. app.py +71 -1
app.py CHANGED
@@ -139,6 +139,8 @@ Key requirements:
139
  - If the user asks for waveform visualization make sure to set the mode to `line` with and the use the full width of the video. Also concatenate the audio into a single channel.
140
  - For image sequences: Use -framerate and pattern matching (like 'img%d.jpg') when possible, falling back to individual image processing with -loop 1 and appropriate filters only when necessary.
141
  - When showing file operations or commands, always use explicit paths and filenames without wildcards - avoid using asterisk (*) or glob patterns. Instead, use specific numbered sequences (like %d), explicit file lists, or show the full filename.
 
 
142
 
143
  Remember: Simpler is better. Only use advanced ffmpeg features if absolutely necessary for the requested output.
144
  """,
@@ -229,12 +231,80 @@ YOUR RESPONSE:
229
  @spaces.GPU(duration=120)
230
  def execute_ffmpeg_command(args, temp_dir, output_file_path):
231
  """Execute FFmpeg command with GPU acceleration"""
232
- final_command = args + ["-y", output_file_path]
 
 
233
  print(f"\n=== EXECUTING FFMPEG COMMAND ===\nffmpeg {' '.join(final_command[1:])}\n")
234
  subprocess.run(final_command, cwd=temp_dir)
235
  return output_file_path
236
 
237
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
238
  def compose_video(
239
  prompt: str,
240
  files: list = None,
 
139
  - If the user asks for waveform visualization make sure to set the mode to `line` with and the use the full width of the video. Also concatenate the audio into a single channel.
140
  - For image sequences: Use -framerate and pattern matching (like 'img%d.jpg') when possible, falling back to individual image processing with -loop 1 and appropriate filters only when necessary.
141
  - When showing file operations or commands, always use explicit paths and filenames without wildcards - avoid using asterisk (*) or glob patterns. Instead, use specific numbered sequences (like %d), explicit file lists, or show the full filename.
142
+ - GPU optimization will be handled automatically - use standard CPU filter names (scale, overlay, etc.) and they will be converted to GPU equivalents when possible
143
+ - Prefer using standard codecs like libx264 or libx265 - GPU acceleration for decoding will be added automatically
144
 
145
  Remember: Simpler is better. Only use advanced ffmpeg features if absolutely necessary for the requested output.
146
  """,
 
231
  @spaces.GPU(duration=120)
232
  def execute_ffmpeg_command(args, temp_dir, output_file_path):
233
  """Execute FFmpeg command with GPU acceleration"""
234
+ # Add GPU acceleration options if not already present
235
+ optimized_args = optimize_ffmpeg_for_gpu(args)
236
+ final_command = optimized_args + ["-y", output_file_path]
237
  print(f"\n=== EXECUTING FFMPEG COMMAND ===\nffmpeg {' '.join(final_command[1:])}\n")
238
  subprocess.run(final_command, cwd=temp_dir)
239
  return output_file_path
240
 
241
 
242
+ def optimize_ffmpeg_for_gpu(args):
243
+ """Optimize FFmpeg command for GPU acceleration without NVENC"""
244
+ optimized = ["ffmpeg"]
245
+
246
+ # Add hardware acceleration for decoding
247
+ if "-hwaccel" not in args:
248
+ optimized.extend(["-hwaccel", "cuda"])
249
+
250
+ # Add CUDA device selection (use GPU 0 by default)
251
+ if "-hwaccel_device" not in args:
252
+ optimized.extend(["-hwaccel_device", "0"])
253
+
254
+ # Add pixel format for CUDA processing
255
+ cuda_filters_needed = any("-vf" in str(arg) or "-filter_complex" in str(arg) for arg in args)
256
+
257
+ # Add the rest of the original arguments (skip the first 'ffmpeg')
258
+ for i, arg in enumerate(args[1:], 1):
259
+ if arg == "-c:v" and i < len(args) - 1:
260
+ # Use GPU-accelerated codecs when available
261
+ next_arg = args[i + 1]
262
+ if next_arg == "libx264":
263
+ optimized.extend(["-c:v", "h264_cuvid" if cuda_filters_needed else "libx264"])
264
+ continue
265
+ elif next_arg == "libx265":
266
+ optimized.extend(["-c:v", "hevc_cuvid" if cuda_filters_needed else "libx265"])
267
+ continue
268
+
269
+ # Convert CPU filters to GPU equivalents where possible
270
+ if arg == "-vf" and i < len(args) - 1:
271
+ gpu_filter = convert_filters_to_gpu(args[i + 1])
272
+ optimized.extend(["-vf", gpu_filter])
273
+ continue
274
+ elif arg == "-filter_complex" and i < len(args) - 1:
275
+ gpu_filter = convert_filters_to_gpu(args[i + 1])
276
+ optimized.extend(["-filter_complex", gpu_filter])
277
+ continue
278
+
279
+ optimized.append(arg)
280
+
281
+ return optimized
282
+
283
+
284
+ def convert_filters_to_gpu(filter_string):
285
+ """Convert CPU filters to GPU-accelerated equivalents"""
286
+ # Common filter conversions for CUDA
287
+ gpu_filters = {
288
+ 'scale=': 'scale_cuda=',
289
+ 'overlay=': 'overlay_cuda=',
290
+ 'transpose=': 'transpose_cuda=',
291
+ 'crop=': 'crop_cuda=',
292
+ 'pad=': 'pad_cuda=',
293
+ 'format=yuv420p': 'format=nv12', # Better GPU format
294
+ }
295
+
296
+ gpu_filter = filter_string
297
+ for cpu_filter, gpu_equivalent in gpu_filters.items():
298
+ if cpu_filter in gpu_filter:
299
+ gpu_filter = gpu_filter.replace(cpu_filter, gpu_equivalent)
300
+
301
+ # Add format conversion for GPU processing
302
+ if 'cuda' in gpu_filter and 'format=' not in gpu_filter:
303
+ gpu_filter = f"format=nv12,{gpu_filter},format=yuv420p"
304
+
305
+ return gpu_filter
306
+
307
+
308
  def compose_video(
309
  prompt: str,
310
  files: list = None,