From 2c72eb92a1b318201c376234f3cda676d290d2dc Mon Sep 17 00:00:00 2001 From: harry Date: Wed, 10 Apr 2024 17:29:13 +0800 Subject: [PATCH] 1. reduce ffmpeg encoding pass to improve performance. 2. fix bug causing file lock that prevents deletion (issue 217). --- app/services/video.py | 94 +++++++++++++++++++------------------------ 1 file changed, 42 insertions(+), 52 deletions(-) diff --git a/app/services/video.py b/app/services/video.py index 3d08e11..6ada901 100644 --- a/app/services/video.py +++ b/app/services/video.py @@ -4,7 +4,6 @@ from typing import List from PIL import ImageFont from loguru import logger from moviepy.editor import * -from moviepy.video.fx.crop import crop from moviepy.video.tools.subtitles import SubtitlesClip from app.models.schema import VideoAspect, VideoParams, VideoConcatMode @@ -41,6 +40,7 @@ def combine_videos(combined_video_path: str, req_dur = audio_duration / len(video_paths) req_dur = max_clip_duration logger.info(f"each clip will be maximum {req_dur} seconds long") + output_dir = os.path.dirname(combined_video_path) aspect = VideoAspect(video_aspect) video_width, video_height = aspect.to_resolution() @@ -103,7 +103,12 @@ def combine_videos(combined_video_path: str, final_clip = final_clip.set_fps(30) logger.info(f"writing") # https://github.com/harry0703/MoneyPrinterTurbo/issues/111#issuecomment-2032354030 - final_clip.write_videofile(combined_video_path, threads=threads, logger=None) + final_clip.write_videofile(filename=combined_video_path, + threads=threads, + logger=None, + temp_audiofile_path=output_dir, + audio_codec="aac", + ) logger.success(f"completed") return combined_video_path @@ -179,6 +184,11 @@ def generate_video(video_path: str, logger.info(f" ③ subtitle: {subtitle_path}") logger.info(f" ④ output: {output_file}") + # https://github.com/harry0703/MoneyPrinterTurbo/issues/217 + # PermissionError: [WinError 32] The process cannot access the file because it is being used by another process: 'final-1.mp4.tempTEMP_MPY_wvf_snd.mp3' + # write into the same directory as the output file + output_dir = os.path.dirname(output_file) + font_path = "" if params.subtitle_enabled: if not params.font_name: @@ -217,50 +227,29 @@ def generate_video(video_path: str, ) return clip - clips = [ - VideoFileClip(video_path), - ] + video_clip = VideoFileClip(video_path) + audio_clip = AudioFileClip(audio_path).volumex(params.voice_volume) if subtitle_path and os.path.exists(subtitle_path): sub = SubtitlesClip(subtitles=subtitle_path, make_textclip=generator, encoding='utf-8') sub_clip = sub.set_position(lambda _t: ('center', position_height)) - clips.append(sub_clip) - - result = CompositeVideoClip(clips) - - audio = AudioFileClip(audio_path) - try: - audio = audio.volumex(params.voice_volume) - except Exception as e: - logger.warning(f"failed to set audio volume: {e}") - - result = result.set_audio(audio) - - temp_output_file = f"{output_file}.temp.mp4" - logger.info(f"writing to temp file: {temp_output_file}") - result.write_videofile(temp_output_file, threads=params.n_threads or 2, logger=None) - - video_clip = VideoFileClip(temp_output_file) + video_clip = CompositeVideoClip([video_clip, sub_clip]) bgm_file = get_bgm_file(bgm_type=params.bgm_type, bgm_file=params.bgm_file) if bgm_file: - logger.info(f"adding background music: {bgm_file}") - # Add song to video at 30% volume using moviepy - original_duration = video_clip.duration - original_audio = video_clip.audio - song_clip = AudioFileClip(bgm_file).set_fps(44100) - # Set the volume of the song to 10% of the original volume - song_clip = song_clip.volumex(params.bgm_volume) - # Add the song to the video - comp_audio = CompositeAudioClip([original_audio, song_clip]) - video_clip = video_clip.set_audio(comp_audio) - video_clip = video_clip.set_fps(30) - video_clip = video_clip.set_duration(original_duration) + bgm_clip = (AudioFileClip(bgm_file) + .set_duration(video_clip.duration) + .volumex(params.bgm_volume) + .audio_fadeout(3)) - logger.info(f"encoding audio codec to aac") - video_clip.write_videofile(output_file, audio_codec="aac", threads=params.n_threads or 2, logger=None) + audio_clip = CompositeAudioClip([audio_clip, bgm_clip]) + video_clip = video_clip.set_audio(audio_clip) + video_clip.write_videofile(output_file, + audio_codec="aac", + temp_audiofile_path=output_dir, + threads=params.n_threads or 2, + logger=None) - os.remove(temp_output_file) logger.success(f"completed") @@ -272,25 +261,25 @@ if __name__ == "__main__": t = wrap_text(text=txt, max_width=1000, font=font, fontsize=60) print(t) - task_id = "69232dfa-f6c5-4b5e-80ba-be3098d3f930" + task_id = "aa563149-a7ea-49c2-b39f-8c32cc225baf" task_dir = utils.task_dir(task_id) video_file = f"{task_dir}/combined-1.mp4" audio_file = f"{task_dir}/audio.mp3" subtitle_file = f"{task_dir}/subtitle.srt" output_file = f"{task_dir}/final.mp4" - video_paths = [] - for file in os.listdir(utils.storage_dir("test")): - if file.endswith(".mp4"): - video_paths.append(os.path.join(task_dir, file)) - - combine_videos(combined_video_path=video_file, - audio_file=audio_file, - video_paths=video_paths, - video_aspect=VideoAspect.portrait, - video_concat_mode=VideoConcatMode.random, - max_clip_duration=5, - threads=2) + # video_paths = [] + # for file in os.listdir(utils.storage_dir("test")): + # if file.endswith(".mp4"): + # video_paths.append(os.path.join(utils.storage_dir("test"), file)) + # + # combine_videos(combined_video_path=video_file, + # audio_file=audio_file, + # video_paths=video_paths, + # video_aspect=VideoAspect.portrait, + # video_concat_mode=VideoConcatMode.random, + # max_clip_duration=5, + # threads=2) cfg = VideoParams() cfg.video_aspect = VideoAspect.portrait @@ -300,14 +289,15 @@ if __name__ == "__main__": cfg.stroke_width = 1.5 cfg.text_fore_color = "#FFFFFF" cfg.text_background_color = "transparent" + cfg.bgm_type = "random" cfg.bgm_file = "" - cfg.bgm_volume = 0.2 + cfg.bgm_volume = 1.0 cfg.subtitle_enabled = True cfg.subtitle_position = "bottom" cfg.n_threads = 2 cfg.paragraph_number = 1 - cfg.voice_volume = 3.0 + cfg.voice_volume = 1.0 generate_video(video_path=video_file, audio_path=audio_file,