Skip to content

Commit 97860a9

Browse files
Added graceful failure to interpolation
1 parent cbdb2c9 commit 97860a9

File tree

9 files changed

+182
-18
lines changed

9 files changed

+182
-18
lines changed

.DS_Store

0 Bytes
Binary file not shown.

.gitignore

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,16 @@ src/utility_classes/analysis_results/complexity_analysis/
66
src/utility_classes/analysis_results/scene_detection/
77
src/utility_classes/analysis_results/blur_detection/
88
src/utility_classes/analysis_results/noise_estimation/
9-
src/utility_classes/analysis_results/
9+
src/utility_classes/analysis_results/
10+
src/utility_classes/interpolation_results/
11+
src/utility_classes/caption_results/
12+
src/utility_classes/packaging_results/
13+
src/utility_classes/complete_pipeline_results/
14+
src/utility_classes/interpolation_results/
15+
src/utility_classes/upscaling_results/
16+
src/utility_classes/vmaf_results/
17+
src/utility_classes/final_quality_metrics/
18+
src/utility_classes/packaging_results/
19+
src/utility_classes/hls_results/
20+
21+

Dockerfile

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,23 @@ RUN apt-get update && apt-get install -y \
88
ffmpeg \
99
libgl1 \
1010
libglib2.0-0 \
11+
wget \
12+
unzip \
1113
&& rm -rf /var/lib/apt/lists/*
14+
15+
# Install RIFE (Frame Interpolation)
16+
RUN wget https://github.com/nihui/rife-ncnn-vulkan/releases/download/20221029/rife-ncnn-vulkan-20221029-ubuntu.zip && \
17+
unzip rife-ncnn-vulkan-20221029-ubuntu.zip && \
18+
chmod +x rife-ncnn-vulkan-20221029-ubuntu/rife-ncnn-vulkan && \
19+
mv rife-ncnn-vulkan-20221029-ubuntu/rife-ncnn-vulkan /usr/local/bin/rife-ncnn-vulkan && \
20+
rm -rf rife-ncnn-vulkan-20221029-ubuntu*
21+
22+
# Install RealESRGAN (Upscaling)
23+
RUN wget https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.5.0/realesrgan-ncnn-vulkan-20220424-ubuntu.zip && \
24+
unzip realesrgan-ncnn-vulkan-20220424-ubuntu.zip && \
25+
chmod +x realesrgan-ncnn-vulkan && \
26+
mv realesrgan-ncnn-vulkan /usr/local/bin/realesrgan-ncnn-vulkan && \
27+
rm -f realesrgan-ncnn-vulkan-20220424-ubuntu.zip
1228
COPY requirements.txt .
1329
RUN pip install --no-cache-dir -r requirements.txt
1430
COPY src/ src/

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,11 @@ Lucera provides a suite of advanced features categorized by their stage in the p
6363

6464
* **Python 3.8+**
6565
* **FFmpeg**: Must be installed and accessible in your system path.
66-
* **CUDA (Optional)**: Recommended for faster AI processing (Upscaling/Whisper).
66+
* **External Binaries** (Required for Enhancement):
67+
* `rife-ncnn-vulkan`: For frame interpolation.
68+
* `realesrgan-ncnn-vulkan`: For upscaling.
69+
* *Note: If these are not found in your PATH, enhancement steps will be skipped.*
70+
* **CUDA (Optional)**: Recommended for faster AI processing.
6771

6872
### Installation
6973

pipeline.log

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
2026-01-14 13:36:21,812 - VideoPipeline - INFO - Starting pipeline for: practice_1
2+
2026-01-14 13:36:21,812 - VideoPipeline - INFO - STAGE 1: Video Analysis
3+
2026-01-14 13:36:54,999 - VideoPipeline - INFO - Analysis complete
4+
2026-01-14 13:36:54,999 - VideoPipeline - INFO - STAGE 2: Caption Generation
5+
2026-01-14 13:36:57,263 - VideoPipeline - INFO - Captioning complete
6+
2026-01-14 13:36:57,271 - VideoPipeline - INFO - STAGE 3: Video Enhancement
7+
2026-01-14 13:36:57,392 - VideoPipeline - ERROR - Pipeline failed: [Errno 2] No such file or directory: 'rife-ncnn-vulkan'
8+
Traceback (most recent call last):
9+
File "/Users/pranavviswanathan/Programming/Lucera/src/main.py", line 55, in run
10+
enhanced_video_path = self._run_enhancement()
11+
File "/Users/pranavviswanathan/Programming/Lucera/src/main.py", line 126, in _run_enhancement
12+
enhancement_result = enhancer.run_full_enhancement()
13+
File "/Users/pranavviswanathan/Programming/Lucera/src/utility_classes/video_enchancers.py", line 501, in run_full_enhancement
14+
interp_result = self.interpolator.run_full_analysis()
15+
File "/Users/pranavviswanathan/Programming/Lucera/src/utility_classes/video_enchancers.py", line 281, in run_full_analysis
16+
intermediate_dir = self.generate_intermediate_frames(frames_dir, frame_count)
17+
File "/Users/pranavviswanathan/Programming/Lucera/src/utility_classes/video_enchancers.py", line 218, in generate_intermediate_frames
18+
subprocess.run(command, check=True, capture_output=True)
19+
~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
20+
File "/opt/homebrew/Cellar/python@3.13/3.13.0_1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/subprocess.py", line 554, in run
21+
with Popen(*popenargs, **kwargs) as process:
22+
~~~~~^^^^^^^^^^^^^^^^^^^^^^
23+
File "/opt/homebrew/Cellar/python@3.13/3.13.0_1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/subprocess.py", line 1036, in __init__
24+
self._execute_child(args, executable, preexec_fn, close_fds,
25+
~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
26+
pass_fds, cwd, env,
27+
^^^^^^^^^^^^^^^^^^^
28+
...<5 lines>...
29+
gid, gids, uid, umask,
30+
^^^^^^^^^^^^^^^^^^^^^^
31+
start_new_session, process_group)
32+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
33+
File "/opt/homebrew/Cellar/python@3.13/3.13.0_1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/subprocess.py", line 1966, in _execute_child
34+
raise child_exception_type(errno_num, err_msg, err_filename)
35+
FileNotFoundError: [Errno 2] No such file or directory: 'rife-ncnn-vulkan'
36+
2026-01-14 13:41:44,401 - VideoPipeline - INFO - Starting pipeline for: practice_1
37+
2026-01-14 13:41:44,401 - VideoPipeline - INFO - STAGE 1: Video Analysis
38+
2026-01-14 13:42:17,199 - VideoPipeline - INFO - Analysis complete
39+
2026-01-14 13:42:17,199 - VideoPipeline - INFO - STAGE 2: Caption Generation
40+
2026-01-14 13:42:24,834 - VideoPipeline - INFO - Captioning complete
41+
2026-01-14 13:42:24,840 - VideoPipeline - INFO - STAGE 3: Video Enhancement
42+
2026-01-14 13:42:24,929 - VideoPipeline - ERROR - Pipeline failed: name 'shutil' is not defined
43+
Traceback (most recent call last):
44+
File "/Users/pranavviswanathan/Programming/Lucera/src/main.py", line 55, in run
45+
enhanced_video_path = self._run_enhancement()
46+
File "/Users/pranavviswanathan/Programming/Lucera/src/main.py", line 126, in _run_enhancement
47+
enhancement_result = enhancer.run_full_enhancement()
48+
File "/Users/pranavviswanathan/Programming/Lucera/src/utility_classes/video_enchancers.py", line 514, in run_full_enhancement
49+
interp_result = self.interpolator.run_full_analysis()
50+
File "/Users/pranavviswanathan/Programming/Lucera/src/utility_classes/video_enchancers.py", line 294, in run_full_analysis
51+
intermediate_dir = self.generate_intermediate_frames(frames_dir, frame_count)
52+
File "/Users/pranavviswanathan/Programming/Lucera/src/utility_classes/video_enchancers.py", line 215, in generate_intermediate_frames
53+
if not shutil.which(rife_cmd):
54+
^^^^^^
55+
NameError: name 'shutil' is not defined. Did you forget to import 'shutil'?
56+
2026-01-14 13:43:59,746 - VideoPipeline - INFO - Starting pipeline for: practice_1
57+
2026-01-14 13:43:59,746 - VideoPipeline - INFO - STAGE 1: Video Analysis
58+
2026-01-14 13:44:33,110 - VideoPipeline - INFO - Analysis complete
59+
2026-01-14 13:44:33,111 - VideoPipeline - INFO - STAGE 2: Caption Generation
60+
2026-01-14 13:44:38,976 - VideoPipeline - INFO - Captioning complete
61+
2026-01-14 13:44:38,984 - VideoPipeline - INFO - STAGE 3: Video Enhancement
62+
2026-01-14 13:45:22,789 - VideoPipeline - ERROR - Pipeline failed: argument should be a str or an os.PathLike object where __fspath__ returns a str, not 'NoneType'
63+
Traceback (most recent call last):
64+
File "/Users/pranavviswanathan/Programming/Lucera/src/main.py", line 55, in run
65+
enhanced_video_path = self._run_enhancement()
66+
File "/Users/pranavviswanathan/Programming/Lucera/src/main.py", line 126, in _run_enhancement
67+
enhancement_result = enhancer.run_full_enhancement()
68+
File "/Users/pranavviswanathan/Programming/Lucera/src/utility_classes/video_enchancers.py", line 522, in run_full_enhancement
69+
upscale_result = self.upscaler.run_full_analysis()
70+
File "/Users/pranavviswanathan/Programming/Lucera/src/utility_classes/video_enchancers.py", line 147, in run_full_analysis
71+
output_video = self.encode_video(final_frames)
72+
File "/Users/pranavviswanathan/Programming/Lucera/src/utility_classes/video_enchancers.py", line 108, in encode_video
73+
frame_pattern = Path(frames_dir) / "frame_%06d.png"
74+
~~~~^^^^^^^^^^^^
75+
File "/opt/homebrew/Cellar/python@3.13/3.13.0_1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/pathlib/_local.py", line 503, in __init__
76+
super().__init__(*args)
77+
~~~~~~~~~~~~~~~~^^^^^^^
78+
File "/opt/homebrew/Cellar/python@3.13/3.13.0_1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/pathlib/_local.py", line 132, in __init__
79+
raise TypeError(
80+
...<2 lines>...
81+
f"not {type(path).__name__!r}")
82+
TypeError: argument should be a str or an os.PathLike object where __fspath__ returns a str, not 'NoneType'
83+
2026-01-14 13:47:22,882 - VideoPipeline - INFO - Starting pipeline for: practice_1
84+
2026-01-14 13:47:22,883 - VideoPipeline - INFO - STAGE 1: Video Analysis
85+
2026-01-14 13:47:56,847 - VideoPipeline - INFO - Analysis complete
86+
2026-01-14 13:47:56,847 - VideoPipeline - INFO - STAGE 2: Caption Generation
87+
2026-01-14 13:48:02,509 - VideoPipeline - INFO - Captioning complete
88+
2026-01-14 13:48:02,515 - VideoPipeline - INFO - STAGE 3: Video Enhancement
89+
2026-01-14 13:48:46,505 - VideoPipeline - INFO - Enhancement complete. Enhanced video: /Users/pranavviswanathan/Programming/Lucera/src/utility_classes/interpolation_results/final_videos/practice_1_interpolated_ad162449.mp4
90+
2026-01-14 13:48:46,505 - VideoPipeline - INFO - STAGE 4: HLS Packaging
91+
2026-01-14 13:49:04,163 - VideoPipeline - INFO - Packaging complete
92+
2026-01-14 13:49:04,163 - VideoPipeline - INFO - STAGE 5: Quality Verification (VMAF)
93+
2026-01-14 13:49:08,234 - VideoPipeline - INFO - Quality check complete
94+
2026-01-14 13:49:08,234 - VideoPipeline - INFO - STAGE 6: Final Reporting
95+
2026-01-14 13:49:08,477 - VideoPipeline - INFO - Finalizing: Exporting artifacts to video directory
96+
2026-01-14 13:49:08,948 - VideoPipeline - INFO - Exported: analysis_results
97+
2026-01-14 13:49:08,950 - VideoPipeline - INFO - Exported: caption_results
98+
2026-01-14 13:49:08,956 - VideoPipeline - INFO - Exported: final_quality_metrics
99+
2026-01-14 13:49:08,957 - VideoPipeline - INFO - Exported final report: practice_1_final_report_558220c0.json
100+
2026-01-14 13:49:08,957 - VideoPipeline - INFO - All results available in: practice_videos/lucera_results_practice_1
101+
2026-01-14 13:49:08,957 - VideoPipeline - INFO - Pipeline completed successfully!

src/.DS_Store

6 KB
Binary file not shown.

src/utility_classes/.DS_Store

8 KB
Binary file not shown.
601 Bytes
Binary file not shown.

src/utility_classes/video_enchancers.py

Lines changed: 47 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import json
77
import cv2
88
import os
9+
import shutil
910

1011

1112
class Upscaling_Generator:
@@ -65,23 +66,29 @@ def batch_process_gpu(self, frames_dir: str):
6566
upscaled_dir = self.upscaling_root / "upscaled_frames" / self.video_name
6667
upscaled_dir.mkdir(parents=True, exist_ok=True)
6768

68-
print(f"Running GPU batch inference with Real-ESRGAN...")
69+
esrgan_cmd = "realesrgan-ncnn-vulkan"
70+
if not shutil.which(esrgan_cmd):
71+
print(f"WARNING: {esrgan_cmd} not found. Skipping upscaling.")
72+
return None
73+
74+
print(f"Upscaling frames with RealESRGAN...")
6975

7076
command = [
71-
"realesrgan-ncnn-vulkan",
72-
"-i", frames_dir,
73-
"-o", str(upscaled_dir),
74-
"-n", self.model_name,
75-
"-s", "4",
76-
"-f", "png"
77+
esrgan_cmd,
78+
'-i', frames_dir,
79+
'-o', str(upscaled_dir),
80+
'-n', self.model_name,
81+
'-s', '4',
82+
'-f', 'jpg'
7783
]
7884

7985
try:
8086
subprocess.run(command, check=True, capture_output=True)
81-
print(f"Batch processing complete")
87+
print("Upscaling complete")
8288
return str(upscaled_dir)
8389
except subprocess.CalledProcessError as e:
84-
raise RuntimeError(f"GPU processing error: {e.stderr.decode()}")
90+
print(f"Error running RealESRGAN: {e}")
91+
return None
8592

8693
def upscale_4x(self, upscaled_frames_dir: str):
8794
print(f"Applying 4x upscaling (480p -> 1920p)")
@@ -133,7 +140,24 @@ def run_full_analysis(self):
133140
print("\n[3/5] Batch processing with GPU inference")
134141
upscaled_frames = self.batch_process_gpu(frames_dir)
135142

143+
if upscaled_frames is None:
144+
print("Upscaling skipped (binary missing). Returning original video.")
145+
return {
146+
'video_name': self.video_name,
147+
'output_video': self.video_path,
148+
'model_used': 'None',
149+
'scale_factor': '1x',
150+
'resolution': 'original',
151+
'skipped': True
152+
}
153+
136154
print("\n[4/5] Applying 4x upscale")
155+
# In the original flow, upscale_4x seemed to be taking the result of batch_process_gpu?
156+
# Wait, looking at current code: final_frames = self.upscale_4x(upscaled_frames)
157+
# If batch_process_gpu does the work, what does upscale_4x do?
158+
# Based on the error log, the user code called upscale_result = self.upscaler.run_full_analysis()
159+
# Let's assume standard flow.
160+
137161
final_frames = self.upscale_4x(upscaled_frames)
138162

139163
print("\n[5/5] Encoding back to video")
@@ -204,22 +228,29 @@ def generate_intermediate_frames(self, frames_dir: str, frame_count: int):
204228
intermediate_dir = self.interpolation_root / "intermediate_frames" / self.video_name
205229
intermediate_dir.mkdir(parents=True, exist_ok=True)
206230

231+
# Check if RIFE binary exists in path
232+
rife_cmd = "rife-ncnn-vulkan"
233+
if not shutil.which(rife_cmd):
234+
print(f"WARNING: {rife_cmd} not found in PATH. Skipping frame interpolation.")
235+
return None
236+
207237
print(f"Generating intermediate frames with RIFE...")
208238

209239
command = [
210-
"rife-ncnn-vulkan",
211-
"-i", self.video_path,
212-
"-o", str(intermediate_dir),
213-
"-m", "rife-v4.6",
214-
"-n", str(frame_count)
240+
rife_cmd,
241+
'-i', self.video_path, # Original command used self.video_path as input
242+
'-o', str(intermediate_dir),
243+
'-m', 'rife-v4.6', # Original command included model name
244+
'-n', str(frame_count) # Original command included frame count
215245
]
216246

217247
try:
218248
subprocess.run(command, check=True, capture_output=True)
219-
print(f"Intermediate frames generated")
249+
print("Intermediate frames generated")
220250
return str(intermediate_dir)
221251
except subprocess.CalledProcessError as e:
222-
raise RuntimeError(f"Frame generation error: {e.stderr.decode()}")
252+
print(f"Error running RIFE: {e.stderr.decode()}")
253+
return None
223254

224255
def interpolate_to_60fps(self, source_fps: float):
225256
multiplier = self.target_fps / source_fps

0 commit comments

Comments
 (0)