ladybug11 commited on
Commit
4af6b12
·
1 Parent(s): a4bf1f9
Files changed (1) hide show
  1. modal_video_processing.py +38 -11
modal_video_processing.py CHANGED
@@ -41,7 +41,14 @@ def process_quote_video(
41
  - Overlays `quote_text` using a chosen `text_style`.
42
  - If `audio_b64` is provided, decodes it and:
43
  * sets it as the audio track
44
- * loops the video so its duration is at least the audio duration (+ small buffer).
 
 
 
 
 
 
 
45
 
46
  Returns:
47
  Raw bytes of the final MP4 video.
@@ -77,13 +84,17 @@ def process_quote_video(
77
  # 2. Load video
78
  # ---------------------------
79
  video = VideoFileClip(temp_video.name)
 
80
 
81
  # ---------------------------
82
- # 3. Optional audio handling
83
  # ---------------------------
84
  audio_clip = None
85
  temp_audio_path = None
86
 
 
 
 
87
  if audio_b64:
88
  try:
89
  temp_audio = tempfile.NamedTemporaryFile(delete=False, suffix=".mp3")
@@ -97,20 +108,36 @@ def process_quote_video(
97
  audio_clip = AudioFileClip(temp_audio_path)
98
  audio_duration = audio_clip.duration
99
 
100
- # Small buffer so we don't cut off the last word
101
- target_duration = audio_duration + 0.5
 
 
 
 
 
 
102
 
103
- # If audio is longer than the clip, loop the video to at least cover it
104
  if target_duration > video.duration:
105
  video = vfx_loop(video, duration=target_duration)
 
 
106
 
107
- # IMPORTANT: we do NOT crop video when audio is shorter;
108
- # it's fine if video runs a bit longer than the narration.
109
  except Exception as e:
110
  print(f"⚠️ Audio handling error: {e}")
111
  audio_clip = None
 
 
 
 
 
 
 
 
 
 
112
 
113
- # If no audio, keep original video duration
114
  w, h = video.size
115
 
116
  # ---------------------------
@@ -193,11 +220,10 @@ def process_quote_video(
193
  # ---------------------------
194
  final_video = CompositeVideoClip([video, text_clip])
195
 
196
- # If we have audio, attach it (no extra duration forcing)
197
  if audio_clip is not None:
198
  try:
199
  final_video = final_video.set_audio(audio_clip)
200
- # Do NOT call set_duration() again: video is already long enough.
201
  except Exception as e:
202
  print(f"⚠️ Could not attach audio: {e}")
203
 
@@ -254,7 +280,8 @@ def process_quote_video(
254
 
255
  total_time = time.time() - start_time
256
  print(
257
- f"🎉 Total: {total_time:.1f}s, Size: {len(video_bytes) / 1024 / 1024:.2f}MB, text_style={text_style}"
 
258
  )
259
 
260
  return video_bytes
 
41
  - Overlays `quote_text` using a chosen `text_style`.
42
  - If `audio_b64` is provided, decodes it and:
43
  * sets it as the audio track
44
+ * makes video duration roughly match audio (with min/max bounds).
45
+
46
+ Duration rules:
47
+ - With audio:
48
+ target = audio_duration + 0.5s
49
+ MIN = 7s, MAX = 20s
50
+ - Without audio:
51
+ target = min(original_video_duration, 15s)
52
 
53
  Returns:
54
  Raw bytes of the final MP4 video.
 
84
  # 2. Load video
85
  # ---------------------------
86
  video = VideoFileClip(temp_video.name)
87
+ orig_duration = video.duration
88
 
89
  # ---------------------------
90
+ # 3. Duration logic + optional audio
91
  # ---------------------------
92
  audio_clip = None
93
  temp_audio_path = None
94
 
95
+ # Default target when no audio
96
+ target_duration = orig_duration
97
+
98
  if audio_b64:
99
  try:
100
  temp_audio = tempfile.NamedTemporaryFile(delete=False, suffix=".mp3")
 
108
  audio_clip = AudioFileClip(temp_audio_path)
109
  audio_duration = audio_clip.duration
110
 
111
+ # Proportional rules with audio
112
+ MIN_DUR = 7.0
113
+ MAX_DUR = 20.0
114
+ target_duration = audio_duration + 0.5 # small buffer
115
+ if target_duration < MIN_DUR:
116
+ target_duration = MIN_DUR
117
+ if target_duration > MAX_DUR:
118
+ target_duration = MAX_DUR
119
 
120
+ # Adjust video to target_duration
121
  if target_duration > video.duration:
122
  video = vfx_loop(video, duration=target_duration)
123
+ elif target_duration < video.duration:
124
+ video = video.subclip(0, target_duration)
125
 
 
 
126
  except Exception as e:
127
  print(f"⚠️ Audio handling error: {e}")
128
  audio_clip = None
129
+ # Fall back to no-audio behavior below
130
+
131
+ if audio_clip is None:
132
+ # No audio path: clamp to reasonable length
133
+ MAX_NO_AUDIO = 15.0
134
+ if orig_duration > MAX_NO_AUDIO:
135
+ target_duration = MAX_NO_AUDIO
136
+ video = video.subclip(0, target_duration)
137
+ else:
138
+ target_duration = orig_duration
139
 
140
+ # At this point, video.duration target_duration
141
  w, h = video.size
142
 
143
  # ---------------------------
 
220
  # ---------------------------
221
  final_video = CompositeVideoClip([video, text_clip])
222
 
223
+ # Attach audio if available (no extra duration forcing)
224
  if audio_clip is not None:
225
  try:
226
  final_video = final_video.set_audio(audio_clip)
 
227
  except Exception as e:
228
  print(f"⚠️ Could not attach audio: {e}")
229
 
 
280
 
281
  total_time = time.time() - start_time
282
  print(
283
+ f"🎉 Total: {total_time:.1f}s, Size: {len(video_bytes) / 1024 / 1024:.2f}MB, "
284
+ f"text_style={text_style}, target_duration≈{target_duration:.1f}s"
285
  )
286
 
287
  return video_bytes