File size: 5,118 Bytes
dde1cc7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
from moviepy.editor import VideoFileClip, concatenate_videoclips,ColorClip,CompositeVideoClip
from find_steps import find_all_steps
import json
import random
import string
step={
   "path" :"/Users/georgia.bucea/products/ShortsAI/21_aug/IMG_8299.MOV",
   "start":0.0,
   "end": '',
}
        
def crop_video(step, target_resolution=(1080, 1920), target_fps=30):
    """
    Crop a video clip to the specified start and end times, and resize to target resolution
    while maintaining the original aspect ratio with padding if necessary.
    
    Args:
        step (dict): Dictionary with 'path', 'start', and 'end' keys.
        target_resolution (tuple): Desired output resolution (width, height).
        target_fps (int): Desired frame rate for the output video.
    
    Returns:
        VideoClip: Cropped and resized video clip with preserved audio.
    """
    video = VideoFileClip(step["path"])
    
    # Crop the video based on start and end times
    if step.get("end"):
        video = video.subclip(step["start"], step["end"])
    else:
        video = video.subclip(step["start"])
    
    # Set consistent frame rate
    video = video.set_fps(target_fps)
    
    # Calculate target aspect ratio
    target_width, target_height = target_resolution
    target_aspect = target_width / target_height
    video_aspect = video.w / video.h
    
    # Resize or pad to match target resolution while preserving aspect ratio
    if abs(video_aspect - target_aspect) > 0.01:  # Allow small tolerance
        print("I'm here in abs")
        if video_aspect > target_aspect:
            # Video is wider than target: scale to match height, add black bars on sides
            print("I'm here in video aspect >")
            new_width = int(target_height * video_aspect)
            video = video.resize(height=target_height)
            # Create a background clip with black padding
            background = ColorClip(size=(target_width, target_height), color=(0, 0, 0))
            video = video.set_position(("center", "center")).on_color(size=(target_width, target_height), color=(0, 0, 0))
        else:
            print("I'm here in video aspect")
            # Video is taller than target: scale to match width, add black bars on top/bottom
            new_height = int(target_width / video_aspect)
            video = video.resize(width=target_width)
            # Create a background clip with black padding
            background = ColorClip(size=(target_width, target_height), color=(0, 0, 0))
            video = video.set_position(("center", "center")).on_color(size=(target_width, target_height), color=(0, 0, 0))
    else:
        print("I'm here in video aspect")
        # Aspect ratio matches, resize directly
        video = video.resize(target_resolution)
    
    # Ensure audio is preserved
    if video.audio is None:
        print(f"Warning: No audio in {step['path']}")
    
    return video

def get_final_video(subclips, aspect_ratio="9:16"):
    """
    Concatenate video clips and save the final video with consistent resolution and audio.
    
    Args:
        subclips (list): List of VideoClip objects.
        aspect_ratio (str): Desired aspect ratio (e.g., '9:16').
    
    Returns:
        str: Path to the saved video file.
    """
    # Parse aspect ratio
    width_ratio, height_ratio = map(int, aspect_ratio.split(":"))
    target_aspect = width_ratio / height_ratio
    
    # Set target resolution (e.g., 1080x1920 for 9:16)
    target_height = 1920  # Standard for vertical videos
    target_width = int(target_height * target_aspect)
    target_resolution = (target_width, target_height)
    
    # Concatenate clips
    final_clip = concatenate_videoclips(subclips, method="compose")
    
    # Generate unique filename
    random_string = ''.join(random.choices(string.ascii_lowercase + string.digits, k=8))
    file_name = f"edited_videos/video_edited{random_string}.mp4"  # Changed to .mp4 for compatibility
    
    # Write the final video file
    final_clip.write_videofile(
        file_name,
        codec='libx264',
        audio_codec='aac',
        fps=30,  # Consistent frame rate
        preset='medium',
        ffmpeg_params=['-pix_fmt', 'yuv420p', '-aspect', aspect_ratio],  # Ensure compatibility with most players
        verbose=False,
        temp_audiofile=f"temp_audio_{random_string}.m4a",  # Explicit temp audio file
    )
    
    # Close clips to free memory
    final_clip.close()
    # for clip in sub:
    #     clip.close()
    
    return file_name





if __name__ == "__main__":
    file_path = '/Users/georgia.bucea/products/ShortsAI/all_files_metadata.json'  # Update this with the actual file path

    context = """I am putting stuff in a car, with pipes and a guy in a red shirt. I am walking past a band with a DJ. I am explaining something on the phone"""
 
    with open(file_path, 'r') as file:
         data = json.load(file)

    steps=find_all_steps(data,context)
    all_videos=[]
    for step in steps:
        v=crop_video(step)
        all_videos.append(v)

    # v=crop_video(step)

    get_final_video(all_videos)