@@ -57,6 +57,21 @@ def to_av_frame_rate(fps):
57
57
return av .utils .Fraction (num , denom )
58
58
59
59
60
+ def convert_audio (input_path : Path , output_path : Path , codec_name : str ):
61
+ with (
62
+ av .open (input_path ) as input_audio ,
63
+ av .open (output_path , "w" ) as output_audio ,
64
+ ):
65
+ input_audio_stream = input_audio .streams .audio [0 ]
66
+ output_audio_stream = output_audio .add_stream (codec_name )
67
+ for frame in input_audio .decode (input_audio_stream ):
68
+ for packet in output_audio_stream .encode (frame ):
69
+ output_audio .mux (packet )
70
+
71
+ for packet in output_audio_stream .encode ():
72
+ output_audio .mux (packet )
73
+
74
+
60
75
class SceneFileWriter :
61
76
"""
62
77
SceneFileWriter is the object that actually writes the animations
@@ -350,19 +365,7 @@ def add_sound(
350
365
# we need to pass delete=False to work on Windows
351
366
# TODO: figure out a way to cache the wav file generated (benchmark needed)
352
367
wav_file_path = NamedTemporaryFile (suffix = ".wav" , delete = False )
353
- with (
354
- av .open (file_path ) as input_container ,
355
- av .open (wav_file_path , "w" , format = "wav" ) as output_container ,
356
- ):
357
- for audio_stream in input_container .streams .audio :
358
- output_stream = output_container .add_stream ("pcm_s16le" )
359
- for frame in input_container .decode (audio_stream ):
360
- for packet in output_stream .encode (frame ):
361
- output_container .mux (packet )
362
-
363
- for packet in output_stream .encode ():
364
- output_container .mux (packet )
365
-
368
+ convert_audio (file_path , wav_file_path , "pcm_s16le" )
366
369
new_segment = AudioSegment .from_file (wav_file_path .name )
367
370
logger .info (f"Automatically converted { file_path } to .wav" )
368
371
wav_file_path .close ()
@@ -748,21 +751,17 @@ def combine_to_movie(self):
748
751
# but tries to call ffmpeg via its CLI -- which we want
749
752
# to avoid. This is why we need to do the conversion
750
753
# manually.
751
- if config .format == "webm" :
752
- with (
753
- av .open (sound_file_path ) as wav_audio ,
754
- av .open (sound_file_path .with_suffix (".ogg" ), "w" ) as opus_audio ,
755
- ):
756
- wav_audio_stream = wav_audio .streams .audio [0 ]
757
- opus_audio_stream = opus_audio .add_stream ("libvorbis" )
758
- for frame in wav_audio .decode (wav_audio_stream ):
759
- for packet in opus_audio_stream .encode (frame ):
760
- opus_audio .mux (packet )
761
-
762
- for packet in opus_audio_stream .encode ():
763
- opus_audio .mux (packet )
764
-
765
- sound_file_path = sound_file_path .with_suffix (".ogg" )
754
+ out_suffix = movie_file_path .suffix .lower ()
755
+ if config .format == "webm" or out_suffix == ".webm" :
756
+ ogg_sound_file_path = sound_file_path .with_suffix (".ogg" )
757
+ convert_audio (sound_file_path , ogg_sound_file_path , "libvorbis" )
758
+ sound_file_path = ogg_sound_file_path
759
+ elif config .format == "mp4" or out_suffix == ".mp4" :
760
+ # Similarly, pyav may reject wav audio in an .mp4 file;
761
+ # convert to AAC.
762
+ aac_sound_file_path = sound_file_path .with_suffix (".aac" )
763
+ convert_audio (sound_file_path , aac_sound_file_path , "aac" )
764
+ sound_file_path = aac_sound_file_path
766
765
767
766
temp_file_path = movie_file_path .with_name (
768
767
f"{ movie_file_path .stem } _temp{ movie_file_path .suffix } "
0 commit comments