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