1inkusFace commited on
Commit
205f29e
·
verified ·
1 Parent(s): ae0ac19

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +96 -116
app.py CHANGED
@@ -1,6 +1,5 @@
1
  import spaces
2
  import os
3
- import sys
4
  import shutil
5
  import subprocess
6
  import glob
@@ -12,174 +11,155 @@ BASE_DIR = os.getcwd()
12
  RIFE_DIR = os.path.join(BASE_DIR, "Practical-RIFE")
13
  MODEL_URL = "https://huggingface.co/hzwer/RIFE/resolve/main/RIFEv4.26_0921.zip"
14
 
 
15
  def run_command(command):
16
- """Helper to run shell commands"""
17
  subprocess.run(command, shell=True, check=True)
18
 
19
  def setup_environment():
20
- """
21
- 1. Clones the RIFE repo.
22
- 2. Downloads weights.
23
- 3. Re-organizes folders (User's Fix).
24
- 4. Patches scikit-video.
25
- """
26
  print("--- Starting Environment Setup ---")
27
-
28
- # 1. Clone Repo if not exists
29
  if not os.path.exists(RIFE_DIR):
30
  print("Cloning Practical-RIFE...")
31
  run_command(f"git clone https://github.com/hzwer/Practical-RIFE {RIFE_DIR}")
32
 
33
- # 2. Download and Organize Weights
34
- # We check if 'HDv3' exists to avoid re-downloading on restart
35
  if not os.path.exists(os.path.join(RIFE_DIR, "HDv3")):
36
  print("Downloading RIFE v4.26 model weights...")
37
  zip_path = os.path.join(RIFE_DIR, "RIFEv4.26_0921.zip")
38
-
39
- # Download
40
  run_command(f"wget -O {zip_path} {MODEL_URL}")
41
-
42
- # Unzip
43
- print("Unzipping...")
44
  run_command(f"unzip -o {zip_path} -d {RIFE_DIR}")
45
 
46
- # --- APPLY USER'S DIRECTORY FIX ---
47
- print("Applying directory structure fix...")
48
-
49
- # Create train_log
50
  train_log_dir = os.path.join(RIFE_DIR, "train_log")
51
  os.makedirs(train_log_dir, exist_ok=True)
52
-
53
- # Move Python files
54
  extract_folder = os.path.join(RIFE_DIR, "RIFEv4.26_0921")
55
  shutil.move(os.path.join(extract_folder, "RIFE_HDv3.py"), train_log_dir)
56
  shutil.move(os.path.join(extract_folder, "IFNet_HDv3.py"), train_log_dir)
57
-
58
- # Create __init__.py
59
- with open(os.path.join(train_log_dir, "__init__.py"), 'w') as f:
60
- pass
61
-
62
- # Create HDv3 and move weights
63
  hdv3_dir = os.path.join(RIFE_DIR, "HDv3")
64
  os.makedirs(hdv3_dir, exist_ok=True)
65
  shutil.move(os.path.join(extract_folder, "flownet.pkl"), hdv3_dir)
66
-
67
- # Cleanup
68
  shutil.rmtree(extract_folder)
69
- if os.path.exists(zip_path):
70
- os.remove(zip_path)
71
-
72
- print("Files moved and directories created.")
73
 
74
- # 3. Patch skvideo (The numpy fix)
75
- print("Checking skvideo for necessary patches...")
76
  try:
77
  spec = importlib.util.find_spec('skvideo.io.abstract')
78
  if spec and spec.origin:
79
- abstract_path = spec.origin
80
-
81
- # Read file to see if patching is needed
82
- with open(abstract_path, 'r') as f:
83
- content = f.read()
84
-
85
- if 'np.float' in content or 'np.int' in content:
86
- print(f"Patching {abstract_path}...")
87
- run_command(f"sed -i 's/np.float/float/g' {abstract_path}")
88
- run_command(f"sed -i 's/np.int/int/g' {abstract_path}")
89
- print("skvideo patched.")
90
- else:
91
- print("skvideo already patched or compatible.")
92
  except Exception as e:
93
- print(f"Warning: Could not patch skvideo: {e}")
94
 
95
- # 4. Patch inference_video.py for libx264
96
  inference_script = os.path.join(RIFE_DIR, "inference_video.py")
97
  if os.path.exists(inference_script):
98
- # Read to check if already patched
99
- with open(inference_script, 'r') as f:
100
- script_content = f.read()
101
-
102
- if "libx264" not in script_content:
103
- print("Patching inference_video.py for libx264...")
104
- # Replicating the sed command using python replace for safety
105
- new_content = script_content.replace(
106
- "-c:v', 'mpeg4', '-qscale:v', '1'",
107
- "-c:v', 'libx264', '-preset', 'medium', '-crf', '23'"
108
- )
109
- with open(inference_script, 'w') as f:
110
- f.write(new_content)
111
-
112
  print("--- Setup Complete ---")
113
 
114
- # Run Setup immediately upon app launch
115
  setup_environment()
116
 
117
- @spaces.GPU(required=True)
118
- def interpolate_video(input_video_path):
119
- if input_video_path is None:
120
- return None
121
-
122
- print(f"Processing video: {input_video_path}")
123
-
124
  output_path = os.path.join(BASE_DIR, "output_rife.mp4")
125
- final_output_path = os.path.join(BASE_DIR, "final_output.mp4")
126
 
127
- # Clean up previous runs
128
  if os.path.exists(output_path): os.remove(output_path)
129
  if os.path.exists(final_output_path): os.remove(final_output_path)
130
 
131
- # Change dir to RIFE for execution
132
  os.chdir(RIFE_DIR)
133
-
134
  try:
135
- # Run RIFE inference
136
- # Note: --multi 4 means 4x interpolation (e.g. 30fps -> 120fps)
137
- cmd = [
138
- 'python3', 'inference_video.py',
139
- '--video', input_video_path,
140
- '--output', output_path,
141
- '--multi', '4',
142
- '--model', 'HDv3'
143
- ]
144
  subprocess.run(cmd, check=True)
145
-
146
- # Post-process for Web Compatibility (Faststart + h264)
147
  if os.path.exists(output_path):
148
- print("Re-encoding for web compatibility...")
149
- ffmpeg_cmd = [
150
- 'ffmpeg', '-i', output_path,
151
- '-c:v', 'libx264',
152
- '-pix_fmt', 'yuv420p',
153
- '-preset', 'medium',
154
- '-crf', '23',
155
- '-movflags', '+faststart',
156
- '-y', final_output_path
157
- ]
158
- subprocess.run(ffmpeg_cmd, check=True)
159
-
160
  return final_output_path
161
- else:
162
- return None
163
-
164
  except Exception as e:
165
- print(f"Error during inference: {e}")
166
  return None
167
  finally:
168
- # Reset directory
169
  os.chdir(BASE_DIR)
170
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
171
  # --- Gradio Interface ---
172
  with gr.Blocks() as demo:
173
- gr.Markdown("# 🎞️ RIFE Video Interpolation (v4.26)")
174
- gr.Markdown("Upload a video to smoothen it (4X Frame Interpolation). **Note:** This process is slow on CPU. Using a GPU Space is recommended.")
175
-
176
- with gr.Row():
177
- with gr.Column():
178
- video_input = gr.Video(label="Input Video")
179
- submit_btn = gr.Button("Interpolate Frames", variant="primary")
180
- with gr.Column():
181
- video_output = gr.Video(label="Smoothed Output")
182
 
183
- submit_btn.click(fn=interpolate_video, inputs=video_input, outputs=video_output)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
184
 
185
  demo.launch()
 
1
  import spaces
2
  import os
 
3
  import shutil
4
  import subprocess
5
  import glob
 
11
  RIFE_DIR = os.path.join(BASE_DIR, "Practical-RIFE")
12
  MODEL_URL = "https://huggingface.co/hzwer/RIFE/resolve/main/RIFEv4.26_0921.zip"
13
 
14
+ # --- Setup Functions ---
15
  def run_command(command):
 
16
  subprocess.run(command, shell=True, check=True)
17
 
18
  def setup_environment():
19
+ """Sets up RIFE, downloads weights, and patches libraries."""
 
 
 
 
 
20
  print("--- Starting Environment Setup ---")
 
 
21
  if not os.path.exists(RIFE_DIR):
22
  print("Cloning Practical-RIFE...")
23
  run_command(f"git clone https://github.com/hzwer/Practical-RIFE {RIFE_DIR}")
24
 
 
 
25
  if not os.path.exists(os.path.join(RIFE_DIR, "HDv3")):
26
  print("Downloading RIFE v4.26 model weights...")
27
  zip_path = os.path.join(RIFE_DIR, "RIFEv4.26_0921.zip")
 
 
28
  run_command(f"wget -O {zip_path} {MODEL_URL}")
 
 
 
29
  run_command(f"unzip -o {zip_path} -d {RIFE_DIR}")
30
 
31
+ # Fix directory structure
 
 
 
32
  train_log_dir = os.path.join(RIFE_DIR, "train_log")
33
  os.makedirs(train_log_dir, exist_ok=True)
 
 
34
  extract_folder = os.path.join(RIFE_DIR, "RIFEv4.26_0921")
35
  shutil.move(os.path.join(extract_folder, "RIFE_HDv3.py"), train_log_dir)
36
  shutil.move(os.path.join(extract_folder, "IFNet_HDv3.py"), train_log_dir)
37
+ with open(os.path.join(train_log_dir, "__init__.py"), 'w') as f: pass
 
 
 
 
 
38
  hdv3_dir = os.path.join(RIFE_DIR, "HDv3")
39
  os.makedirs(hdv3_dir, exist_ok=True)
40
  shutil.move(os.path.join(extract_folder, "flownet.pkl"), hdv3_dir)
 
 
41
  shutil.rmtree(extract_folder)
42
+ if os.path.exists(zip_path): os.remove(zip_path)
 
 
 
43
 
44
+ # Patch skvideo
 
45
  try:
46
  spec = importlib.util.find_spec('skvideo.io.abstract')
47
  if spec and spec.origin:
48
+ with open(spec.origin, 'r') as f: content = f.read()
49
+ if 'np.float' in content:
50
+ run_command(f"sed -i 's/np.float/float/g' {spec.origin}")
51
+ run_command(f"sed -i 's/np.int/int/g' {spec.origin}")
 
 
 
 
 
 
 
 
 
52
  except Exception as e:
53
+ print(f"Warning: skvideo patch failed: {e}")
54
 
55
+ # Patch RIFE inference for libx264
56
  inference_script = os.path.join(RIFE_DIR, "inference_video.py")
57
  if os.path.exists(inference_script):
58
+ with open(inference_script, 'r') as f: content = f.read()
59
+ if "libx264" not in content:
60
+ new_content = content.replace("-c:v', 'mpeg4', '-qscale:v', '1'", "-c:v', 'libx264', '-preset', 'medium', '-crf', '23'")
61
+ with open(inference_script, 'w') as f: f.write(new_content)
 
 
 
 
 
 
 
 
 
 
62
  print("--- Setup Complete ---")
63
 
 
64
  setup_environment()
65
 
66
+ @spaces.GPU(requires=True)
67
+ def interpolate_video(input_video_path, multi_factor):
68
+ if input_video_path is None: return None
69
+ factor = str(multi_factor).replace("x", "").strip()
 
 
 
70
  output_path = os.path.join(BASE_DIR, "output_rife.mp4")
71
+ final_output_path = os.path.join(BASE_DIR, "final_interpolated.mp4")
72
 
 
73
  if os.path.exists(output_path): os.remove(output_path)
74
  if os.path.exists(final_output_path): os.remove(final_output_path)
75
 
 
76
  os.chdir(RIFE_DIR)
 
77
  try:
78
+ cmd = ['python3', 'inference_video.py', '--video', input_video_path, '--output', output_path, '--multi', factor, '--model', 'HDv3']
 
 
 
 
 
 
 
 
79
  subprocess.run(cmd, check=True)
80
+
 
81
  if os.path.exists(output_path):
82
+ # Re-encode for web compatibility
83
+ subprocess.run(['ffmpeg', '-i', output_path, '-c:v', 'libx264', '-pix_fmt', 'yuv420p', '-movflags', '+faststart', '-y', final_output_path], check=True)
 
 
 
 
 
 
 
 
 
 
84
  return final_output_path
 
 
 
85
  except Exception as e:
86
+ print(f"Error: {e}")
87
  return None
88
  finally:
 
89
  os.chdir(BASE_DIR)
90
 
91
+ # --- Stitching Logic ---
92
+ def stitch_videos(video_files):
93
+ if not video_files: return None
94
+
95
+ print(f"Stitching {len(video_files)} videos...")
96
+ stitch_list_path = os.path.join(BASE_DIR, "stitch_list.txt")
97
+ output_stitched = os.path.join(BASE_DIR, "final_stitched.mp4")
98
+ temp_dir = os.path.join(BASE_DIR, "temp_stitch")
99
+
100
+ if os.path.exists(temp_dir): shutil.rmtree(temp_dir)
101
+ os.makedirs(temp_dir)
102
+
103
+ # 1. Normalize Step: Convert all inputs to same Codec, FPS (60), and Scale
104
+ # This prevents the "glitch" when combining different framerates
105
+ normalized_files = []
106
+ for i, vid_path in enumerate(video_files):
107
+ temp_filepath = os.path.join(temp_dir, f"norm_{i}.mp4")
108
+ print(f"Normalizing clip {i+1}...")
109
+
110
+ # We force 60fps (-r 60) and 1080p scale to ensure they match
111
+ cmd = [
112
+ 'ffmpeg', '-i', vid_path,
113
+ '-r', '60', # Force Framerate
114
+ '-vf', 'scale=1920:1080:force_original_aspect_ratio=decrease,pad=1920:1080:(ow-iw)/2:(oh-ih)/2', # Fit to 1080p box
115
+ '-c:v', 'libx264', '-crf', '23',
116
+ '-c:a', 'aac', # Force Audio Codec
117
+ '-ar', '44100', # Force Audio Rate
118
+ '-y', temp_filepath
119
+ ]
120
+ subprocess.run(cmd, check=True)
121
+ normalized_files.append(temp_filepath)
122
+
123
+ # 2. Create List File
124
+ with open(stitch_list_path, 'w') as f:
125
+ for path in normalized_files:
126
+ f.write(f"file '{path}'\n")
127
+
128
+ # 3. Concatenate
129
+ print("Concatenating...")
130
+ subprocess.run(['ffmpeg', '-f', 'concat', '-safe', '0', '-i', stitch_list_path, '-c', 'copy', '-y', output_stitched], check=True)
131
+
132
+ # Cleanup
133
+ shutil.rmtree(temp_dir)
134
+ return output_stitched
135
+
136
  # --- Gradio Interface ---
137
  with gr.Blocks() as demo:
138
+ gr.Markdown("# 🎞️ RIFE: Interpolate & Stitch")
 
 
 
 
 
 
 
 
139
 
140
+ with gr.Tabs():
141
+ # TAB 1: Interpolate
142
+ with gr.TabItem("1. Smooth Video (Interpolate)"):
143
+ gr.Markdown("Upload a single video to increase its framerate (make it smoother).")
144
+ with gr.Row():
145
+ with gr.Column():
146
+ video_input = gr.Video(label="Input Video")
147
+ multi_select = gr.Dropdown(["2", "4", "8"], value="2", label="Multiplier (2x, 4x, etc.)")
148
+ interp_btn = gr.Button("Interpolate", variant="primary")
149
+ with gr.Column():
150
+ video_output = gr.Video(label="Smoothed Output")
151
+ interp_btn.click(interpolate_video, inputs=[video_input, multi_select], outputs=video_output)
152
+
153
+ # TAB 2: Stitch
154
+ with gr.TabItem("2. Stitch Videos"):
155
+ gr.Markdown("Upload multiple videos. They will be **normalized to 60fps 1080p** and joined together.")
156
+ with gr.Row():
157
+ with gr.Column():
158
+ # file_count="multiple" allows selecting multiple files
159
+ stitch_inputs = gr.File(label="Upload Clips", file_count="multiple")
160
+ stitch_btn = gr.Button("Stitch Videos", variant="primary")
161
+ with gr.Column():
162
+ stitch_output = gr.Video(label="Stitched Result")
163
+ stitch_btn.click(stitch_videos, inputs=stitch_inputs, outputs=stitch_output)
164
 
165
  demo.launch()