diff --git a/moviepy/video/VideoClip.py b/moviepy/video/VideoClip.py index 059812f94..1c56bbebd 100644 --- a/moviepy/video/VideoClip.py +++ b/moviepy/video/VideoClip.py @@ -116,7 +116,7 @@ def save_frame(self, filename, t=0, savemask=False): Saves the frame of clip corresponding to time ``t`` in 'filename'. ``t`` can be expressed in seconds (15.35), in (min, sec), in (hour, min, sec), or as a string: '01:03:05.35'. - + If ``savemask`` is ``True`` the mask is saved in the alpha layer of the picture. @@ -136,7 +136,8 @@ def write_videofile(self, filename, fps=24, codec=None, audio_bitrate=None, audio_bufsize=2000, temp_audiofile=None, rewrite_audio=True, remove_temp=True, - write_logfile=False, verbose=True): + write_logfile=False, verbose=True, + ffmpeg_params=None): """Write the clip to a videofile. Parameters @@ -167,7 +168,7 @@ def write_videofile(self, filename, fps=24, codec=None, to ``'libx264'``, and produces higher quality videos by default. - ``'rawvideo'`` (use file extension ``.avi``) will produce + ``'rawvideo'`` (use file extension ``.avi``) will produce a video of perfect quality, of possibly very huge size. @@ -203,7 +204,7 @@ def write_videofile(self, filename, fps=24, codec=None, for '.mp3', 'libvorbis' for 'ogg', 'libfdk_aac':'m4a', 'pcm_s16le' for 16-bit wav and 'pcm_s32le' for 32-bit wav. Default is 'libmp3lame', unless the video extension is 'ogv' - or 'webm', at which case the default is 'libvorbis'. + or 'webm', at which case the default is 'libvorbis'. audio_bitrate Audio bitrate, given as a string like '50k', '500k', '3000k'. @@ -242,8 +243,8 @@ def write_videofile(self, filename, fps=24, codec=None, codec = extensions_dict[ext]['codec'][0] except KeyError: raise ValueError("MoviePy couldn't find the codec associated " - "with the filename. Provide the 'codec' " - "parameter in write_fideofile.") + "with the filename. Provide the 'codec' parameter in " + "write_fideofile.") if audio_codec is None: if (ext in ['ogv', 'webm']): @@ -276,12 +277,10 @@ def write_videofile(self, filename, fps=24, codec=None, audio_ext = find_extension(audio_codec) except ValueError: - raise ValueError("The audio_codec you chose is " - "unknown by MoviePy. You should " - "report this. In the meantime, " - "you can specify a temp_audiofile " - "with the right extension in " - "write_videofile.") + raise ValueError( + "The audio_codec you chose is unknown by MoviePy. " + "You should report this. In the meantime, you can specify a " + "temp_audiofile with the right extension in write_videofile.") audiofile = (name + Clip._TEMP_FILES_PREFIX + "write_videofile_SOUND.%s" % audio_ext) @@ -304,7 +303,8 @@ def write_videofile(self, filename, fps=24, codec=None, preset=preset, write_logfile=write_logfile, audiofile=audiofile, - verbose=verbose) + verbose=verbose, + ffmpeg_params=ffmpeg_params) if remove_temp and make_audio: os.remove(audiofile) @@ -541,8 +541,7 @@ def add_mask(self, constant_size=True): mask = ColorClip(self.size, 1.0, ismask=True) return self.set_mask(mask.set_duration(self.duration)) else: - make_frame = lambda t: np.ones(self.get_frame(t).shape, - dtype=float) + make_frame = lambda t: np.ones(self.get_frame(t).shape, dtype=float) mask = VideoClip(ismask=True, make_frame=make_frame) return self.set_mask(mask.set_duration(self.duration)) diff --git a/moviepy/video/io/ffmpeg_writer.py b/moviepy/video/io/ffmpeg_writer.py index 92d0aa8a3..b53b280ed 100644 --- a/moviepy/video/io/ffmpeg_writer.py +++ b/moviepy/video/io/ffmpeg_writer.py @@ -74,7 +74,7 @@ class FFMPEG_VideoWriter: def __init__(self, filename, size, fps, codec="libx264", audiofile=None, preset="medium", bitrate=None, withmask=False, - logfile=None): + logfile=None, ffmpeg_params=None): if logfile is None: logfile = sp.PIPE @@ -83,30 +83,42 @@ def __init__(self, filename, size, fps, codec="libx264", audiofile=None, self.codec = codec self.ext = self.filename.split(".")[-1] - cmd = ( - [FFMPEG_BINARY, '-y'] - + ["-loglevel", "error" if logfile == sp.PIPE else "info", - "-f", 'rawvideo', - "-vcodec", "rawvideo", - '-s', "%dx%d" % (size[0], size[1]), - '-pix_fmt', "rgba" if withmask else "rgb24", - '-r', "%.02f" % fps, - '-i', '-', '-an'] - + (["-i", audiofile, "-acodec", "copy"] - if (audiofile is not None) else []) - + ['-vcodec', codec, - '-preset', preset] - + (['-b', bitrate] if (bitrate != None) else []) - # http://trac.ffmpeg.org/ticket/658 - + (['-pix_fmt', 'yuv420p'] - if ((codec == 'libx264') and - (size[0] % 2 == 0) and - (size[1] % 2 == 0)) - - else []) - + ['-r', "%.02f" % fps, filename] - # + (["-acodec", "copy"] if (audiofile is not None) else []) - ) + # order is important + cmd = [ + FFMPEG_BINARY, + '-y', + '-loglevel', 'error' if logfile == sp.PIPE else 'info', + '-f', 'rawvideo', + '-vcodec', 'rawvideo', + '-s', '%dx%d' % (size[0], size[1]), + '-pix_fmt', 'rgba' if withmask else 'rgb24', + '-r', '%.02f' % fps, + '-i', '-', '-an', + ] + if audiofile is not None: + cmd.extend([ + '-i', audiofile, + '-acodec', 'copy' + ]) + cmd.extend([ + '-vcodec', codec, + '-preset', preset, + ]) + if ffmpeg_params is not None: + cmd.extend(ffmpeg_params) + if bitrate is not None: + cmd.extend([ + '-b', bitrate + ]) + if ((codec == 'libx264') and + (size[0] % 2 == 0) and + (size[1] % 2 == 0)): + cmd.extend([ + '-pix_fmt', 'yuv420p' + ]) + cmd.extend([ + filename + ]) self.proc = sp.Popen(cmd, stdin=sp.PIPE, stderr=logfile, @@ -166,7 +178,7 @@ def close(self): def ffmpeg_write_video(clip, filename, fps, codec="libx264", bitrate=None, preset="medium", withmask=False, write_logfile=False, - audiofile=None, verbose=True): + audiofile=None, verbose=True, ffmpeg_params=None): if write_logfile: logfile = open(filename + ".log", 'w+') else: @@ -175,7 +187,8 @@ def ffmpeg_write_video(clip, filename, fps, codec="libx264", bitrate=None, verbose_print(verbose, "\nWriting video into %s\n" % filename) writer = FFMPEG_VideoWriter(filename, clip.size, fps, codec=codec, preset=preset, bitrate=bitrate, - logfile=logfile, audiofile=audiofile) + logfile=logfile, audiofile=audiofile, + ffmpeg_params=ffmpeg_params) for t, frame in clip.iter_frames(progress_bar=True, with_times=True, fps=fps):