diff --git a/moviepy/video/io/VideoFileClip.py b/moviepy/video/io/VideoFileClip.py index 9b18fa105..3d5913d3b 100644 --- a/moviepy/video/io/VideoFileClip.py +++ b/moviepy/video/io/VideoFileClip.py @@ -32,6 +32,17 @@ class VideoFileClip(VideoClip): audio: Set to `False` if the clip doesn't have any audio or if you do not wish to read the audio. + + target_resolution: + Set to (desired_height, desired_width) to have ffmpeg resize the frames before return them. + This is much faster than streaming in high-res and then resizing. + if either size is None, the frames are resized by keeping the existing aspect ratio. + + resize_algorithm: + The algorithm used for resizing. Default: "bicubic", other popular options include "bilinear" + and "fast_bilinear". + For more information, see https://ffmpeg.org/ffmpeg-scaler.html + Attributes ----------- @@ -48,14 +59,17 @@ class VideoFileClip(VideoClip): def __init__(self, filename, has_mask=False, audio=True, audio_buffersize = 200000, + target_resolution=None, resize_algorithm='bicubic', audio_fps=44100, audio_nbytes=2, verbose=False): VideoClip.__init__(self) - + # Make a reader pix_fmt= "rgba" if has_mask else "rgb24" - self.reader = None #need this just in case FFMPEG has issues (__del__ complains) - self.reader = FFMPEG_VideoReader(filename, pix_fmt=pix_fmt) + self.reader = None # need this just in case FFMPEG has issues (__del__ complains) + self.reader = FFMPEG_VideoReader(filename, pix_fmt=pix_fmt, + target_resolution=target_resolution, resize_algo=resize_algorithm) + # Make some of the reader's attributes accessible from the clip self.duration = self.reader.duration self.end = self.reader.duration diff --git a/moviepy/video/io/ffmpeg_reader.py b/moviepy/video/io/ffmpeg_reader.py index 6ac83c32e..ec5ba99ec 100644 --- a/moviepy/video/io/ffmpeg_reader.py +++ b/moviepy/video/io/ffmpeg_reader.py @@ -23,12 +23,25 @@ class FFMPEG_VideoReader: def __init__(self, filename, print_infos=False, bufsize = None, - pix_fmt="rgb24", check_duration=True): + pix_fmt="rgb24", check_duration=True, + target_resolution=None, resize_algo='bicubic'): self.filename = filename infos = ffmpeg_parse_infos(filename, print_infos, check_duration) self.fps = infos['video_fps'] self.size = infos['video_size'] + + if target_resolution: + if None in target_resolution: + ratio = 1 + for idx, target in enumerate(target_resolution): + if target: + ratio = min(ratio, float(target) / self.size[idx]) + self.size = (int(self.size[0] * ratio), int(self.size[1] * ratio)) + else: + self.size = target_resolution + self.resize_algo = resize_algo + self.duration = infos['video_duration'] self.ffmpeg_duration = infos['duration'] self.nframes = infos['video_nframes'] @@ -66,13 +79,13 @@ def initialize(self, starttime=0): else: i_arg = [ '-i', self.filename] - - cmd = ([get_setting("FFMPEG_BINARY")]+ i_arg + - ['-loglevel', 'error', + cmd = ([get_setting("FFMPEG_BINARY")] + i_arg + + ['-loglevel', 'error', '-f', 'image2pipe', + '-vf', 'scale=%d:%d' % tuple(self.size), + '-sws_flags', self.resize_algo, "-pix_fmt", self.pix_fmt, '-vcodec', 'rawvideo', '-']) - popen_params = {"bufsize": self.bufsize, "stdout": sp.PIPE, "stderr": sp.PIPE,