JakeFake222 commited on
Commit
460258b
·
verified ·
1 Parent(s): 3c05175

Upload app.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. app.py +213 -0
app.py ADDED
@@ -0,0 +1,213 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Video Processing Space - Gradio Interface for AI Video Analysis."""
2
+
3
+ import gradio as gr
4
+ import cv2
5
+ import numpy as np
6
+ import json
7
+ import tempfile
8
+ import os
9
+
10
+
11
+ def get_metadata(video_file):
12
+ """Extract video metadata."""
13
+ if video_file is None:
14
+ return "No video uploaded"
15
+
16
+ cap = cv2.VideoCapture(video_file)
17
+
18
+ if not cap.isOpened():
19
+ return "Error: Could not open video"
20
+
21
+ metadata = {
22
+ "frame_count": int(cap.get(cv2.CAP_PROP_FRAME_COUNT)),
23
+ "fps": round(cap.get(cv2.CAP_PROP_FPS), 2),
24
+ "width": int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)),
25
+ "height": int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)),
26
+ }
27
+
28
+ if metadata["fps"] > 0:
29
+ metadata["duration_sec"] = round(metadata["frame_count"] / metadata["fps"], 2)
30
+ else:
31
+ metadata["duration_sec"] = 0
32
+
33
+ codec_int = int(cap.get(cv2.CAP_PROP_FOURCC))
34
+ metadata["codec"] = "".join([chr((codec_int >> 8 * i) & 0xFF) for i in range(4)])
35
+
36
+ cap.release()
37
+ return json.dumps(metadata, indent=2)
38
+
39
+
40
+ def create_contact_sheet(video_file, grid_size):
41
+ """Generate contact sheet grid from video."""
42
+ if video_file is None:
43
+ return None, "No video uploaded"
44
+
45
+ grid_size = int(grid_size)
46
+ cap = cv2.VideoCapture(video_file)
47
+
48
+ if not cap.isOpened():
49
+ return None, "Error: Could not open video"
50
+
51
+ total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
52
+ fps = cap.get(cv2.CAP_PROP_FPS)
53
+ width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
54
+ height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
55
+ duration = total_frames / fps if fps > 0 else 0
56
+
57
+ total_cells = grid_size * grid_size
58
+ step = max(1, total_frames // total_cells)
59
+
60
+ thumb_width = 200
61
+ thumb_height = int(height * (thumb_width / width))
62
+
63
+ frames = []
64
+
65
+ for i in range(total_cells):
66
+ frame_idx = i * step
67
+ cap.set(cv2.CAP_PROP_POS_FRAMES, frame_idx)
68
+ ret, frame = cap.read()
69
+
70
+ if ret:
71
+ thumb = cv2.resize(frame, (thumb_width, thumb_height))
72
+ cv2.putText(thumb, str(i), (5, 20),
73
+ cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1)
74
+ frames.append(thumb)
75
+ else:
76
+ blank = np.zeros((thumb_height, thumb_width, 3), dtype=np.uint8)
77
+ frames.append(blank)
78
+
79
+ cap.release()
80
+
81
+ rows = []
82
+ for r in range(grid_size):
83
+ start_idx = r * grid_size
84
+ end_idx = start_idx + grid_size
85
+ row_frames = frames[start_idx:end_idx]
86
+ if row_frames:
87
+ rows.append(np.hstack(row_frames))
88
+
89
+ if rows:
90
+ grid_image = np.vstack(rows)
91
+ grid_image_rgb = cv2.cvtColor(grid_image, cv2.COLOR_BGR2RGB)
92
+
93
+ info = {
94
+ "grid_size": grid_size,
95
+ "total_cells": total_cells,
96
+ "video_duration_sec": round(duration, 2),
97
+ "seconds_per_cell": round(duration / total_cells, 2),
98
+ }
99
+
100
+ return grid_image_rgb, json.dumps(info, indent=2)
101
+
102
+ return None, "Error: Could not generate contact sheet"
103
+
104
+
105
+ def extract_clip(video_file, start_sec, end_sec):
106
+ """Extract video segment by timestamps."""
107
+ if video_file is None:
108
+ return None, "No video uploaded"
109
+
110
+ cap = cv2.VideoCapture(video_file)
111
+
112
+ if not cap.isOpened():
113
+ return None, "Error: Could not open video"
114
+
115
+ fps = cap.get(cv2.CAP_PROP_FPS)
116
+ width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
117
+ height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
118
+ total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
119
+ duration = total_frames / fps if fps > 0 else 0
120
+
121
+ if start_sec < 0:
122
+ start_sec = 0
123
+ if end_sec > duration:
124
+ end_sec = duration
125
+ if start_sec >= end_sec:
126
+ cap.release()
127
+ return None, f"Invalid time range: {start_sec} to {end_sec}"
128
+
129
+ start_frame = int(start_sec * fps)
130
+ end_frame = int(end_sec * fps)
131
+
132
+ # Create temp output file
133
+ output_path = tempfile.mktemp(suffix='.mp4')
134
+
135
+ fourcc = cv2.VideoWriter_fourcc(*'mp4v')
136
+ out = cv2.VideoWriter(output_path, fourcc, fps, (width, height))
137
+
138
+ cap.set(cv2.CAP_PROP_POS_FRAMES, start_frame)
139
+
140
+ frames_written = 0
141
+ current_frame = start_frame
142
+
143
+ while current_frame < end_frame:
144
+ ret, frame = cap.read()
145
+ if not ret:
146
+ break
147
+ out.write(frame)
148
+ frames_written += 1
149
+ current_frame += 1
150
+
151
+ cap.release()
152
+ out.release()
153
+
154
+ info = {
155
+ "start_sec": start_sec,
156
+ "end_sec": end_sec,
157
+ "duration_sec": round(end_sec - start_sec, 2),
158
+ "frames_written": frames_written,
159
+ }
160
+
161
+ return output_path, json.dumps(info, indent=2)
162
+
163
+
164
+ # Gradio Interface
165
+ with gr.Blocks(title="Video Process - AI Video Analysis", theme=gr.themes.Soft()) as demo:
166
+ gr.Markdown("""
167
+ # 🎬 Video Process
168
+ **AI-powered video analysis and editing**
169
+
170
+ Upload a video to inspect, analyze, or extract clips.
171
+ """)
172
+
173
+ video_input = gr.Video(label="Upload Video")
174
+
175
+ with gr.Tabs():
176
+ # Tab 1: Metadata
177
+ with gr.TabItem("📊 Metadata"):
178
+ meta_btn = gr.Button("Get Metadata", variant="primary")
179
+ meta_output = gr.Code(language="json", label="Video Properties")
180
+ meta_btn.click(get_metadata, inputs=video_input, outputs=meta_output)
181
+
182
+ # Tab 2: Contact Sheet
183
+ with gr.TabItem("👁️ Inspect (Contact Sheet)"):
184
+ gr.Markdown("Generate a visual grid to 'see' the entire video at once")
185
+ grid_slider = gr.Slider(minimum=2, maximum=10, value=6, step=1, label="Grid Size")
186
+ inspect_btn = gr.Button("Generate Contact Sheet", variant="primary")
187
+ contact_sheet_output = gr.Image(label="Contact Sheet")
188
+ inspect_info = gr.Code(language="json", label="Info")
189
+ inspect_btn.click(create_contact_sheet,
190
+ inputs=[video_input, grid_slider],
191
+ outputs=[contact_sheet_output, inspect_info])
192
+
193
+ # Tab 3: Extract Clip
194
+ with gr.TabItem("✂️ Extract Clip"):
195
+ gr.Markdown("Cut a segment from the video by timestamps")
196
+ with gr.Row():
197
+ start_input = gr.Number(value=0, label="Start (seconds)")
198
+ end_input = gr.Number(value=5, label="End (seconds)")
199
+ extract_btn = gr.Button("Extract Clip", variant="primary")
200
+ clip_output = gr.Video(label="Extracted Clip")
201
+ extract_info = gr.Code(language="json", label="Info")
202
+ extract_btn.click(extract_clip,
203
+ inputs=[video_input, start_input, end_input],
204
+ outputs=[clip_output, extract_info])
205
+
206
+ gr.Markdown("""
207
+ ---
208
+ *Built with OpenCV + Gradio | VAM-Seek inspired contact sheet approach*
209
+ """)
210
+
211
+
212
+ if __name__ == "__main__":
213
+ demo.launch()