File size: 5,301 Bytes
70f6f47
c9f042d
 
 
230dec4
70f6f47
 
 
c9f042d
 
 
70f6f47
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c9f042d
 
3d72431
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
679995a
3d72431
 
 
 
 
679995a
3d72431
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c9f042d
 
70f6f47
c9f042d
70f6f47
 
 
 
 
 
 
 
 
 
 
 
 
c9f042d
 
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
from moviepy import *
import pysrt
import gradio as gr



def time_to_seconds(time_obj):
    return time_obj.hours * 3600 + time_obj.minutes * 60 + time_obj.seconds + time_obj.milliseconds / 1000

def create_subtitle_clips(subtitles, videosize, fontsize, font, color, debug):
    subtitle_clips = []
    color_clips=[]
    for subtitle in subtitles:
        start_time = time_to_seconds(subtitle.start) # Add 2 seconds offset
        end_time = time_to_seconds(subtitle.end)
        duration = end_time - start_time
        video_width, video_height = videosize
        max_width = video_width * 0.8
        max_height = video_height * 0.2
        #reshaped_text = arabic_reshaper.reshape(subtitle.text)
        #bidi_text = get_display(reshaped_text)
        text_clip = TextClip(font, subtitle.text, font_size=fontsize, size=(int(video_width * 0.8), int(video_height * 0.2)) ,text_align="center" ,color=color, method='caption').with_start(start_time).with_duration(duration)
        #myclip = ColorClip(size=(int(video_width * 0.8), int(video_height * 0.2)) , color=(225, 0, 0)).with_opacity(0.2).with_start(start_time).with_duration(duration)
        subtitle_x_position = 'center'
        subtitle_y_position = video_height * 0.68
        text_position = (subtitle_x_position, subtitle_y_position)
        subtitle_clips.append(text_clip.with_position(text_position))
        #color_clips.append(myclip.with_position(text_position))
    return subtitle_clips

import subprocess
import os

# Mapping of color names to FFmpeg-compatible hex codes
COLOR_MAP = {
    'white': '#FFFFFF',
    'yellow': '#FFFF00',
    'red': '#FF0000',
    'green': '#00FF00',
    'blue': '#0000FF',
    'black': '#000000'
}

def hex_to_ffmpeg_color(hex_code):
    """
    Convert standard hex color (#RRGGBB) to FFmpeg's PrimaryColour format (&HBBGGRR&).
    
    Args:
        hex_code (str): Standard hex color code (e.g., '#FFFFFF')
    Returns:
        str: FFmpeg color code (e.g., '&HFFFFFF&')
    """
    hex_code = hex_code.lstrip('#')
    r, g, b = hex_code[0:2], hex_code[2:4], hex_code[4:6]
    return f'&H{b}{g}{r}&'

def video_edit(srt, input_video, font_color, font_type, font_size, input_audio=None):
    """
    Burns subtitles into a video using FFmpeg with customizable styling.
    
    Args:
        srt (str): Path to SRT subtitle file
        input_video (dict or str): Input video path or dict with 'video' key
        font_color (str): Color name (e.g., 'white', 'yellow')
        font_type (str): Font name for subtitles
        font_size (int): Font size for subtitles
        input_audio (str, optional): Path to audio file (if provided)
    
    Returns:
        str: Path to output video file
    """
    # Handle input_video as dict or string
    if isinstance(input_video, dict):
        video_path = input_video.get('video', '')
    else:
        video_path = input_video

    # Validate input
    if not video_path or not os.path.exists(video_path):
        raise ValueError("Invalid or missing video file")
    if not os.path.exists(srt):
        raise ValueError("Subtitle file not found")

    # Generate output filename
    input_base = os.path.splitext(video_path)[0]
    output_video = f"{input_base}_subtitled.mp4"
    print(font_color, font_type)
    # Convert color name to FFmpeg format
    hex_color = COLOR_MAP.get(font_color.lower())
    if not hex_color:
        raise ValueError(f"Unsupported color: {font_color}. Supported colors: {', '.join(COLOR_MAP.keys())}")
    ffmpeg_color = hex_to_ffmpeg_color(hex_color)
    print(ffmpeg_color)
    # Build subtitle style
    subtitle_style = f"FontName={font_type},FontSize={font_size},PrimaryColour={ffmpeg_color}"
    fonts_dir = os.path.dirname(srt)

    # Construct FFmpeg command
    cmd = [
        'ffmpeg',
        '-i', video_path,  # Input video
    ]

    # Add audio input if provided (though we'll still keep original audio)
    if input_audio and os.path.exists(input_audio):
        cmd.extend(['-i', input_audio])

    cmd.extend([
        '-vf', f"subtitles={srt}:fontsdir={fonts_dir}:force_style='{subtitle_style}'",  # Burn subtitles
        '-c:v', 'libx264',  # Video codec
        '-c:a', 'copy',     # Always copy original audio
        '-r', '24',         # Frame rate
        '-preset', 'ultrafast',# Encoding preset
        '-y',               # Overwrite output
        output_video
    ])

    # Execute FFmpeg command
    try:
        subprocess.run(cmd, check=True, stderr=subprocess.PIPE, universal_newlines=True)
    except subprocess.CalledProcessError as e:
        raise RuntimeError(f"FFmpeg failed: {e.stderr}")

    print(f"Video processed successfully: {output_video}")
    return output_video


with gr.Blocks() as demo:
    gr.Markdown("Start typing below and then click **Run** to see the progress and final output.")
    with gr.Column():
        srt_file = gr.File()
        video_in = gr.Video()
        color = gr.Text()
        font = gr.Text()
        font_size = gr.Number()
        audio_in = gr.Audio(type = "filepath")
        btn = gr.Button("Create")
        output_video = gr.Video()
        btn.click(
            fn=video_edit,
            inputs=[srt_file, video_in, color, font, font_size, audio_in],
            outputs=output_video
        )

demo.launch(debug=True)