jbilcke-hf HF staff commited on
Commit
decd441
·
verified ·
1 Parent(s): 3656746

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +33 -20
app.py CHANGED
@@ -67,12 +67,13 @@ def export_to_video_file(video_frames, output_video_path=None, fps=10):
67
  # those are way too slow for a AiTube which needs things to be as fast as possible
68
  # -----------------------------------------------------------------------------------
69
 
70
- def interpolate_video_frames(file_path, output_fps=10, desired_duration=2):
71
  """
72
  Interpolates frames in a video file to adjust frame rate and duration using ffmpeg's minterpolate.
73
 
74
  Parameters:
75
- file_path (str): Path to the input video file.
 
76
  output_fps (int): Target frames per second for the output video.
77
  desired_duration (int): Desired duration of the video in seconds.
78
 
@@ -80,7 +81,7 @@ def interpolate_video_frames(file_path, output_fps=10, desired_duration=2):
80
  str: The file path of the modified video.
81
  """
82
  # Calculate the input fps required to stretch the video to the desired duration
83
- input_fps = find_input_fps(file_path, desired_duration)
84
 
85
  # Construct the ffmpeg command for interpolation
86
  cmd = [
@@ -88,19 +89,18 @@ def interpolate_video_frames(file_path, output_fps=10, desired_duration=2):
88
  '-i', file_path, # input file
89
  '-filter:v', f'minterpolate=fps={output_fps}', # minterpolate filter options
90
  '-r', str(output_fps), # output frame rate
91
- '-y', # Overwrite output files without asking
92
- file_path # Output file (Overwrites the original)
93
  ]
94
 
95
  # Execute the command
96
  try:
97
  subprocess.run(cmd, check=True)
98
  print("Video interpolation successful.")
 
99
  except subprocess.CalledProcessError as e:
100
  print("Failed to interpolate video. Error:", e)
 
101
 
102
- return file_path
103
-
104
  def find_input_fps(file_path, desired_duration):
105
  """
106
  Determine the input fps that, when stretched to the desired duration, matches the original video length.
@@ -168,28 +168,41 @@ def generate_image(secret_token, prompt, base, width, height, motion, step, desi
168
  guidance_scale=1.0,
169
  num_inference_steps=step,
170
  )
171
-
172
- name = str(uuid.uuid4()).replace("-", "")
173
- path = f"/tmp/{name}.webm"
174
 
175
- # I think we are looking time here too, converting to webm is too slow, we should return
176
- # the frames unencoded to the frontend renderer
177
- path = export_to_video_file(output.frames[0], path, fps=10)
 
178
 
179
- # Optional frame interpolation
 
 
 
 
 
 
 
 
 
180
  if desired_duration != 2 or desired_fps != 10:
181
- path = interpolate_video_frames(path, output_fps=desired_fps, desired_duration=desired_duration)
182
 
183
  # Read the content of the video file and encode it to base64
184
- with open(path, "rb") as video_file:
185
  video_base64 = base64.b64encode(video_file.read()).decode('utf-8')
186
 
 
 
 
 
 
 
 
 
 
 
187
  # Prepend the appropriate data URI header with MIME type
188
  video_data_uri = 'data:video/webm;base64,' + video_base64
189
-
190
- # clean-up (otherwise there is always a risk of "ghosting", eg. someone seeing the previous generated video",
191
- # of one of the steps go wrong)
192
- os.remove(path)
193
 
194
  return video_data_uri
195
 
 
67
  # those are way too slow for a AiTube which needs things to be as fast as possible
68
  # -----------------------------------------------------------------------------------
69
 
70
+ def interpolate_video_frames(input_file_path, output_file_path, output_fps=10, desired_duration=2):
71
  """
72
  Interpolates frames in a video file to adjust frame rate and duration using ffmpeg's minterpolate.
73
 
74
  Parameters:
75
+ input_file_path (str): Path to the input video file.
76
+ output_file_path (str): Path to the output video file.
77
  output_fps (int): Target frames per second for the output video.
78
  desired_duration (int): Desired duration of the video in seconds.
79
 
 
81
  str: The file path of the modified video.
82
  """
83
  # Calculate the input fps required to stretch the video to the desired duration
84
+ input_fps = find_input_fps(input_file_path, desired_duration)
85
 
86
  # Construct the ffmpeg command for interpolation
87
  cmd = [
 
89
  '-i', file_path, # input file
90
  '-filter:v', f'minterpolate=fps={output_fps}', # minterpolate filter options
91
  '-r', str(output_fps), # output frame rate
92
+ output_file_path # Output file
 
93
  ]
94
 
95
  # Execute the command
96
  try:
97
  subprocess.run(cmd, check=True)
98
  print("Video interpolation successful.")
99
+ return input_file_path
100
  except subprocess.CalledProcessError as e:
101
  print("Failed to interpolate video. Error:", e)
102
+ return output_file_path
103
 
 
 
104
  def find_input_fps(file_path, desired_duration):
105
  """
106
  Determine the input fps that, when stretched to the desired duration, matches the original video length.
 
168
  guidance_scale=1.0,
169
  num_inference_steps=step,
170
  )
 
 
 
171
 
172
+ video_uuid = str(uuid.uuid4()).replace("-", "")
173
+ raw_video_path = f"/tmp/{video_uuid}_raw.webm"
174
+ enhanced_video_path = f"/tmp/{video_uuid}_enhanced.webm"
175
+
176
 
177
+ # note the fps is hardcoded, this is a limitation from AnimateDiff I think?
178
+ # (could we change this?)
179
+ #
180
+ # maybe to make things faster, we could *not* encode the video (as this uses files and external processes, which can be slow)
181
+ # and instead return the unencoded frames to the frontend renderer?
182
+ raw_video_path = export_to_video_file(output.frames[0], path, fps=10)
183
+
184
+ final_video_path = raw_video_path
185
+
186
+ # Optional frame interpolation
187
  if desired_duration != 2 or desired_fps != 10:
188
+ final_video_path = interpolate_video_frames(raw_video_path, enhanced_video_path, output_fps=desired_fps, desired_duration=desired_duration)
189
 
190
  # Read the content of the video file and encode it to base64
191
+ with open(final_video_path, "rb") as video_file:
192
  video_base64 = base64.b64encode(video_file.read()).decode('utf-8')
193
 
194
+ # clean-up (otherwise there is always a risk of "ghosting", eg. someone seeing the previous generated video,
195
+ # of one of the steps go wrong - also we need to absolutely delete videos as we generate random files,
196
+ # we can't afford to get a "tmp disk full" error)
197
+ try:
198
+ os.remove(raw_video_path):
199
+ if final_video_path != raw_video_path:
200
+ os.remove(final_video_path)
201
+ except Exception as e:
202
+ print("Failed to delete a video path:", e)
203
+
204
  # Prepend the appropriate data URI header with MIME type
205
  video_data_uri = 'data:video/webm;base64,' + video_base64
 
 
 
 
206
 
207
  return video_data_uri
208