2nzi's picture
update app
16c970a verified
import cv2
from moviepy.editor import VideoFileClip, concatenate_videoclips
import tempfile
import os
class ClipGenerator:
def __init__(self, target_duration: int = 60, min_confidence: float = 0.9):
self.target_duration = target_duration # durée cible en secondes
self.min_confidence = min_confidence
print(f"[DEBUG] Initialized ClipGenerator with target_duration={target_duration}s, min_confidence={min_confidence}")
def _time_to_seconds(self, time_str: str) -> float:
h, m, s = time_str.split(':')
return int(h) * 3600 + int(m) * 60 + float(s)
def _seconds_to_time(self, seconds: float) -> str:
h = int(seconds // 3600)
m = int((seconds % 3600) // 60)
s = seconds % 60
return f"{h:02d}:{m:02d}:{s:06.3f}"
def generate_clips(self, video_path: str, scenes: list, sport_id: str) -> list:
print(f"\n[DEBUG] Starting clip generation for {sport_id}")
print(f"[DEBUG] Input scenes: {len(scenes)}")
# Debug chaque scène avant filtrage
for scene in scenes:
print(f"[DEBUG] Pre-filter scene:")
print(f" - Start: {scene['start']}")
print(f" - End: {scene['end']}")
print(f" - Sport: {scene['recognized_sport']}")
print(f" - Confidence: {scene['confidence']}")
print(f" - Would pass sport filter: {scene['recognized_sport'] == sport_id}")
print(f" - Would pass confidence filter: {scene['confidence'] >= self.min_confidence}")
filtered_scenes = [
scene for scene in scenes
if scene["recognized_sport"].lower() == sport_id.lower()
and scene["confidence"] >= self.min_confidence
]
print(f"[DEBUG] Filtered scenes: {len(filtered_scenes)}")
for scene in filtered_scenes:
print(f"[DEBUG] Scene: {scene['start']} -> {scene['end']} (conf: {scene['confidence']:.2%}) sport_id: {sport_id}")
if not filtered_scenes:
print("[DEBUG] No valid scenes found after filtering")
return []
clips_data = []
current_segments = []
current_duration = 0
clip_number = 1
for scene in filtered_scenes:
print(f"\n[DEBUG] Processing scene {scene['start']} -> {scene['end']}")
scene_start = self._time_to_seconds(scene["start"])
scene_end = self._time_to_seconds(scene["end"])
scene_duration = scene_end - scene_start
print(f"[DEBUG] Scene duration: {scene_duration:.2f}s")
print(f"[DEBUG] Current accumulated duration: {current_duration:.2f}s")
if current_duration + scene_duration > self.target_duration:
remaining_duration = self.target_duration - current_duration
print(f"[DEBUG] Scene would exceed target duration. Remaining space: {remaining_duration:.2f}s")
if remaining_duration > 0:
segment_end = self._seconds_to_time(scene_start + remaining_duration)
current_segments.append({
"start": scene["start"],
"end": segment_end,
"confidence": scene["confidence"]
})
print(f"[DEBUG] Added partial segment: {scene['start']} -> {segment_end}")
clip_data = self._create_clip(video_path, current_segments, clip_number)
clips_data.append(clip_data)
print(f"[DEBUG] Created clip {clip_number} with {len(current_segments)} segments")
clip_number += 1
current_segments = []
current_duration = 0
remaining_scene_duration = scene_duration - remaining_duration
print(f"[DEBUG] Remaining scene duration to process: {remaining_scene_duration:.2f}s")
while remaining_scene_duration > 0:
if remaining_scene_duration >= self.target_duration:
segment_start = self._seconds_to_time(scene_start + scene_duration - remaining_scene_duration)
segment_end = self._seconds_to_time(scene_start + scene_duration - remaining_scene_duration + self.target_duration)
segment = {
"start": segment_start,
"end": segment_end,
"confidence": scene["confidence"]
}
print(f"[DEBUG] Creating full clip from remaining: {segment_start} -> {segment_end}")
clip_data = self._create_clip(video_path, [segment], clip_number)
clips_data.append(clip_data)
clip_number += 1
remaining_scene_duration -= self.target_duration
else:
segment_start = self._seconds_to_time(scene_end - remaining_scene_duration)
current_segments = [{
"start": segment_start,
"end": scene["end"],
"confidence": scene["confidence"]
}]
print(f"[DEBUG] Keeping remainder for next clip: {segment_start} -> {scene['end']}")
current_duration = remaining_scene_duration
break
else:
current_segments.append({
"start": scene["start"],
"end": scene["end"],
"confidence": scene["confidence"]
})
current_duration += scene_duration
print(f"[DEBUG] Added full scene to current clip. New duration: {current_duration:.2f}s")
if current_segments:
print(f"\n[DEBUG] Processing remaining segments")
clip_data = self._create_clip(video_path, current_segments, clip_number)
clips_data.append(clip_data)
print(f"[DEBUG] Created final clip {clip_number} with {len(current_segments)} segments")
print(f"\n[DEBUG] Generated {len(clips_data)} clips in total")
return clips_data
def _create_clip(self, video_path: str, segments: list, clip_number: int) -> dict:
"""Crée un clip à partir des segments donnés."""
total_duration = sum(
self._time_to_seconds(segment["end"]) - self._time_to_seconds(segment["start"])
for segment in segments
)
print(f"[DEBUG] Creating clip {clip_number}")
print(f"[DEBUG] Total duration: {total_duration:.2f}s")
# Créer les sous-clips pour chaque segment
subclips = []
video = VideoFileClip(video_path)
for segment in segments:
start_time = self._time_to_seconds(segment["start"])
end_time = self._time_to_seconds(segment["end"])
print(f"[DEBUG] Extracting segment: {segment['start']} -> {segment['end']}")
subclip = video.subclip(start_time, end_time)
subclips.append(subclip)
# Concaténer tous les sous-clips
final_clip = concatenate_videoclips(subclips)
# Créer un fichier temporaire pour le clip
temp_clip_file = tempfile.NamedTemporaryFile(suffix='.mp4', delete=False)
final_clip.write_videofile(
temp_clip_file.name,
codec='libx264',
audio_codec='aac',
temp_audiofile='temp-audio.m4a',
remove_temp=True
)
# Fermer les clips pour libérer la mémoire
final_clip.close()
for subclip in subclips:
subclip.close()
video.close()
total_confidence = sum(segment["confidence"] for segment in segments)
avg_confidence = total_confidence / len(segments)
return {
"segments": segments,
"clip_number": clip_number,
"confidence": avg_confidence,
"duration": total_duration,
"file_path": temp_clip_file.name # Ajouter le chemin du fichier
}
if __name__ == "__main__":
# Test local
test_video_path = "test_video.mp4" # Remplacer par un chemin réel
test_scenes = [
{
"start": "00:00:00.000",
"end": "00:00:30.000",
"recognized_sport": "surf",
"confidence": 0.95
},
{
"start": "00:00:40.000",
"end": "00:01:20.000",
"recognized_sport": "surf",
"confidence": 0.92
},
{
"start": "00:01:30.000",
"end": "00:02:00.000",
"recognized_sport": "not_surf",
"confidence": 0.88
}
]
clip_generator = ClipGenerator(target_duration=60, min_confidence=0.9)
clips = clip_generator.generate_clips(test_video_path, test_scenes, "surf")
print("\nClips générés :")
for i, clip in enumerate(clips, 1):
print(f"\nClip {i}:")
print(f"Confidence: {clip['confidence']:.2%}")
print("Segments:")
for segment in clip['segments']:
print(f" {segment['start']} -> {segment['end']} (conf: {segment['confidence']:.2%})")