Spaces:
Runtime error
Runtime error
Update services/video_service.py
Browse files- services/video_service.py +65 -84
services/video_service.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1 |
import cv2
|
2 |
-
import os
|
3 |
import logging
|
|
|
|
|
4 |
|
5 |
# Setup logging
|
6 |
logging.basicConfig(
|
@@ -9,98 +10,78 @@ logging.basicConfig(
|
|
9 |
format="%(asctime)s - %(levelname)s - %(message)s"
|
10 |
)
|
11 |
|
12 |
-
# Global
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
cap = None
|
17 |
-
FRAME_SKIP = 3
|
18 |
-
PRELOADED_FRAMES = []
|
19 |
-
|
20 |
-
def update_video_files(video_path: str = None):
|
21 |
-
global video_files
|
22 |
-
if video_path and os.path.exists(video_path) and video_path.endswith((".mp4", ".avi")):
|
23 |
-
video_files = [video_path]
|
24 |
-
else:
|
25 |
-
if os.path.exists(VIDEO_DIR):
|
26 |
-
video_files = [
|
27 |
-
os.path.join(VIDEO_DIR, file)
|
28 |
-
for file in sorted(os.listdir(VIDEO_DIR))
|
29 |
-
if file.endswith((".mp4", ".avi"))
|
30 |
-
]
|
31 |
-
else:
|
32 |
-
video_files = []
|
33 |
-
if not video_files:
|
34 |
-
logging.warning("No video files found.")
|
35 |
-
else:
|
36 |
-
logging.info(f"Found video files: {video_files}")
|
37 |
-
|
38 |
-
def preload_video(video_path: str = None):
|
39 |
-
global cap, video_index, PRELOADED_FRAMES, video_files
|
40 |
-
update_video_files(video_path)
|
41 |
-
if not video_files:
|
42 |
-
logging.error("No video files available to preload.")
|
43 |
-
raise RuntimeError("No video files found in the 'data' directory or provided path.")
|
44 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
45 |
try:
|
46 |
-
|
47 |
-
cap = cv2.VideoCapture(video_files[video_index])
|
48 |
if not cap.isOpened():
|
49 |
-
raise RuntimeError(f"Failed to open video {
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
frame = cv2.resize(frame, (320, 240))
|
55 |
-
PRELOADED_FRAMES.append(frame)
|
56 |
-
else:
|
57 |
-
break
|
58 |
-
cap.release()
|
59 |
-
cap = None
|
60 |
-
logging.info(f"Preloaded {len(PRELOADED_FRAMES)} frames from {video_files[video_index]}")
|
61 |
except Exception as e:
|
62 |
-
logging.error(f"Error
|
63 |
-
raise RuntimeError(f"
|
64 |
|
65 |
-
def
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
if
|
71 |
-
|
72 |
-
|
73 |
-
return frame
|
74 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
75 |
if cap is None or not cap.isOpened():
|
76 |
-
|
|
|
77 |
|
78 |
try:
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
|
|
91 |
return frame
|
92 |
except Exception as e:
|
93 |
logging.error(f"Error retrieving frame: {str(e)}")
|
94 |
-
|
95 |
-
|
96 |
-
def reset_video_index():
|
97 |
-
global video_index
|
98 |
-
video_index = 0
|
99 |
-
logging.info("Reset video index to 0.")
|
100 |
-
|
101 |
-
def release_video():
|
102 |
-
global cap
|
103 |
-
if cap is not None:
|
104 |
-
cap.release()
|
105 |
-
cap = None
|
106 |
-
logging.info("Released video capture object.")
|
|
|
1 |
import cv2
|
|
|
2 |
import logging
|
3 |
+
from typing import Optional
|
4 |
+
import numpy as np
|
5 |
|
6 |
# Setup logging
|
7 |
logging.basicConfig(
|
|
|
10 |
format="%(asctime)s - %(levelname)s - %(message)s"
|
11 |
)
|
12 |
|
13 |
+
# Global video capture object
|
14 |
+
cap: Optional[cv2.VideoCapture] = None
|
15 |
+
FRAME_SKIP: int = 5
|
16 |
+
current_frame_idx: int = 0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
17 |
|
18 |
+
def preload_video(video_path: str) -> None:
|
19 |
+
"""
|
20 |
+
Load a video file for processing.
|
21 |
+
Args:
|
22 |
+
video_path: Path to the video file.
|
23 |
+
Raises:
|
24 |
+
RuntimeError: If the video cannot be loaded.
|
25 |
+
"""
|
26 |
+
global cap, current_frame_idx
|
27 |
+
release_video()
|
28 |
try:
|
29 |
+
cap = cv2.VideoCapture(video_path)
|
|
|
30 |
if not cap.isOpened():
|
31 |
+
raise RuntimeError(f"Failed to open video: {video_path}. Ensure the file exists and is a supported format (.mp4, .avi).")
|
32 |
+
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
|
33 |
+
fps = cap.get(cv2.CAP_PROP_FPS)
|
34 |
+
logging.info(f"Loaded video: {video_path}, Total Frames: {total_frames}, FPS: {fps}")
|
35 |
+
current_frame_idx = 0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
36 |
except Exception as e:
|
37 |
+
logging.error(f"Error loading video {video_path}: {str(e)}")
|
38 |
+
raise RuntimeError(f"Error loading video {video_path}: {str(e)}")
|
39 |
|
40 |
+
def release_video() -> None:
|
41 |
+
"""
|
42 |
+
Release the video capture object.
|
43 |
+
"""
|
44 |
+
global cap
|
45 |
+
if cap is not None:
|
46 |
+
cap.release()
|
47 |
+
cap = None
|
|
|
48 |
|
49 |
+
def reset_video_index() -> None:
|
50 |
+
"""
|
51 |
+
Reset the video frame index to the beginning.
|
52 |
+
"""
|
53 |
+
global current_frame_idx
|
54 |
+
if cap is not None:
|
55 |
+
cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
|
56 |
+
current_frame_idx = 0
|
57 |
+
logging.info("Reset video to start.")
|
58 |
+
|
59 |
+
def get_next_video_frame() -> Optional[np.ndarray]:
|
60 |
+
"""
|
61 |
+
Retrieve the next frame from the video, skipping frames as specified.
|
62 |
+
Returns:
|
63 |
+
The next frame as a numpy array, or None if no frame is available.
|
64 |
+
"""
|
65 |
+
global cap, current_frame_idx
|
66 |
if cap is None or not cap.isOpened():
|
67 |
+
logging.error("Video capture not initialized.")
|
68 |
+
return None
|
69 |
|
70 |
try:
|
71 |
+
# Skip frames to reduce processing load
|
72 |
+
target_frame = current_frame_idx + FRAME_SKIP
|
73 |
+
cap.set(cv2.CAP_PROP_POS_FRAMES, target_frame)
|
74 |
+
success, frame = cap.read()
|
75 |
+
if not success or frame is None:
|
76 |
+
# Video ended, reset to start
|
77 |
+
reset_video_index()
|
78 |
+
success, frame = cap.read()
|
79 |
+
if not success or frame is None:
|
80 |
+
logging.warning("Reached end of video and failed to reset.")
|
81 |
+
return None
|
82 |
+
current_frame_idx = int(cap.get(cv2.CAP_PROP_POS_FRAMES))
|
83 |
+
logging.info(f"Retrieved frame {current_frame_idx}")
|
84 |
return frame
|
85 |
except Exception as e:
|
86 |
logging.error(f"Error retrieving frame: {str(e)}")
|
87 |
+
return None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|