def ffmpeg_write_video(clip, filename, fps, codec="libx264", bitrate=None, preset="medium", withmask=False, write_logfile=False, audiofile=None, verbose=True, threads=None, ffmpeg_params=None): """ Write the clip to a videofile. See VideoClip.write_videofile for details on the parameters. """ if write_logfile: logfile = open(filename + ".log", 'w+') else: logfile = None verbose_print(verbose, "[MoviePy] Writing video %s\n"%filename) writer = FFMPEG_VideoWriter(filename, clip.size, fps, codec = codec, preset=preset, bitrate=bitrate, logfile=logfile, audiofile=audiofile, threads=threads, ffmpeg_params=ffmpeg_params) nframes = int(clip.duration*fps) for t,frame in clip.iter_frames(progress_bar=True, with_times=True, fps=fps, dtype="uint8"): if withmask: mask = (255*clip.mask.get_frame(t)) if mask.dtype != "uint8": mask = mask.astype("uint8") frame = np.dstack([frame,mask]) writer.write_frame(frame) writer.close() if write_logfile: logfile.close() verbose_print(verbose, "[MoviePy] Done.\n")
def ffmpeg_audiowrite(clip, filename, fps, nbytes, buffersize, codec='libvorbis', bitrate=None, write_logfile=False, verbose=True, ffmpeg_params=None, progress_bar=False): """ A function that wraps the FFMPEG_AudioWriter to write an AudioClip to a file. """ if write_logfile: logfile = open(filename + ".log", 'w+') else: logfile = None verbose_print(verbose, "[MoviePy] Writing audio in %s\n" % filename) writer = FFMPEG_AudioWriter(filename, fps, nbytes, clip.nchannels, codec=codec, bitrate=bitrate, logfile=logfile, ffmpeg_params=ffmpeg_params) try: for chunk in clip.iter_chunks(chunksize=buffersize, progress_bar=progress_bar, quantize=True, nbytes=nbytes, fps=fps): writer.write_frames(chunk) """ totalsize = int(fps*clip.duration) if (totalsize % buffersize == 0): nchunks = totalsize // buffersize else: nchunks = totalsize // buffersize + 1 pospos = list(range(0, totalsize, buffersize))+[totalsize] for i in tqdm(range(nchunks)): tt = (1.0/fps)*np.arange(pospos[i],pospos[i+1]) sndarray = clip.to_soundarray(tt, nbytes= nbytes) writer.write_frames(sndarray) """ finally: writer.close() if write_logfile: logfile.close() verbose_print(verbose, "[MoviePy] Done.\n")
def ffmpeg_write_video(clip, filename, fps, codec="libx264", bitrate=None, preset = "medium", withmask=False, write_logfile=False, audiofile=None, verbose=True): if write_logfile: logfile = open(filename + ".log", 'w+') else: logfile = 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) nframes = int(clip.duration*fps) for t,frame in clip.iter_frames(progress_bar=True, with_times=True, fps=fps): if withmask: mask = 255*clip.mask.get_frame(t) frame = np.dstack([frame,mask]) writer.write_frame(frame.astype("uint8")) writer.close() if write_logfile: logfile.close() verbose_print(verbose, "Done writing video in %s !"%filename)
def ffmpeg_write_video(clip, filename, fps, codec="libx264", bitrate=None, preset="medium", withmask=False, write_logfile=False, audiofile=None, verbose=True, threads=None, ffmpeg_params=None): if write_logfile: logfile = open(filename + ".log", 'w+') else: logfile = None verbose_print(verbose, "[MoviePy] Writing video %s\n"%filename) writer = FFMPEG_VideoWriter(filename, clip.size, fps, codec = codec, preset=preset, bitrate=bitrate, logfile=logfile, audiofile=audiofile, threads=threads, ffmpeg_params=ffmpeg_params) nframes = int(clip.duration*fps) for t,frame in clip.iter_frames(progress_bar=True, with_times=True, fps=fps, dtype="uint8"): if withmask: mask = (255*clip.mask.get_frame(t)) if mask.dtype != "uint8": mask = mask.astype("uint8") frame = np.dstack([frame,mask]) writer.write_frame(frame) writer.close() if write_logfile: logfile.close() verbose_print(verbose, "[MoviePy] Done.\n")
def ffmpeg_audiowrite(clip, filename, fps, nbytes, buffersize, codec='libvorbis', bitrate=None, write_logfile = False, verbose=True, ffmpeg_params=None): """ A function that wraps the FFMPEG_AudioWriter to write an AudioClip to a file. """ if write_logfile: logfile = open(filename + ".log", 'w+') else: logfile = None verbose_print(verbose, "[MoviePy] Writing audio in %s\n"%filename) writer = FFMPEG_AudioWriter(filename, fps, nbytes, clip.nchannels, codec=codec, bitrate=bitrate, logfile=logfile, ffmpeg_params=ffmpeg_params) for chunk in clip.iter_chunks(chunksize=buffersize, progress_bar=verbose, quantize=True, nbytes= nbytes, fps=fps): writer.write_frames(chunk) writer.close() if write_logfile: logfile.close() verbose_print(verbose, "[MoviePy] Done.\n")
def write_gif_with_image_io(clip, filename, fps=None, opt="wu", loop=0, colors=None, verbose=True): """ Writes the gif with the Python library ImageIO (calls FreeImage). For the moment ImageIO is not installed with MoviePy. You need to install imageio (pip install imageio) to use this. Parameters ----------- opt """ if colors is None: colors = 256 if not IMAGEIO_FOUND: raise ImportError("Writing a gif with imageio requires ImageIO installed," " with e.g. 'pip install imageio'") if fps is None: fps = clip.fps quantizer = "wu" if opt != "nq" else "nq" writer = imageio.save(filename, duration=1.0 / fps, quantizer=quantizer, palettesize=colors) verbose_print(verbose, "\n[MoviePy] Building file %s with imageio\n" % filename) for frame in clip.iter_frames(fps=fps, progress_bar=True, dtype="uint8"): writer.append_data(frame)
def ffmpeg_write_video(clip, filename, fps, codec="libx264", bitrate=None, withmask=False, write_logfile=False, verbose=True): if write_logfile: logfile = open(filename + ".log", 'w+') else: logfile = None verbose_print(verbose, "\nWriting video into %s\n"%filename) writer = FFMPEG_VideoWriter(filename, clip.size, fps, codec = codec, bitrate=bitrate, logfile=logfile) nframes = int(clip.duration*fps) for i in tqdm(range(nframes)): frame = clip.get_frame(1.0*i/fps) if withmask: mask = (255*clip.mask.get_frame(1.0*i/fps)) frame = np.dstack([frame,mask]) writer.write_frame(frame.astype("uint8")) writer.close() if write_logfile: logfile.close() verbose_print(verbose, "Done writing video in %s !"%filename)
def write_gif_with_image_io(clip, filename, fps=None, opt='wu', loop=0, colors=None, verbose=True): """ Writes the gif with the Python library ImageIO (calls FreeImage). For the moment ImageIO is not installed with MoviePy. You need to install imageio (pip install imageio) to use this. Parameters ----------- opt """ if colors is None: colors=256 if not IMAGEIO_FOUND: raise ImportError("Writing a gif with imageio requires ImageIO installed," " with e.g. 'pip install imageio'") if fps is None: fps = clip.fps quantizer = 'wu' if opt!= 'nq' else 'nq' writer = imageio.save(filename, duration=1.0/fps, quantizer=quantizer, palettesize=colors) verbose_print(verbose, "\n[MoviePy] Building file %s with imageio\n"%filename) for frame in clip.iter_frames(fps=fps, progress_bar=True, dtype='uint8'): writer.append_data(frame)
def write_gif_with_image_io(clip, filename, fps=None, opt=0, loop=0, colors=None, verbose=True, progress_bar=True, progress_cb=None): """ Writes the gif with the Python library ImageIO (calls FreeImage). Parameters ----------- opt progress_bar Boolean indicating whether to display a progress bar in the terminal while exporting the file. progress_cb Callback function to call during export. It should accept the current frame index being exported and the total number of frames. It can be used to update a gui progressbar while running in a separate thread. """ if colors is None: colors = 256 if not IMAGEIO_FOUND: raise ImportError("Writing a gif with imageio requires ImageIO installed," " with e.g. 'pip install imageio'") if fps is None: fps = clip.fps quantizer = 0 if opt != 0 else 'nq' writer = imageio.save( filename, duration=1.0/fps, quantizer=quantizer, palettesize=colors, loop=loop ) verbose_print(verbose, "\n[MoviePy] Building file %s with imageio\n" % filename) # if progress callback was define, call it if callable(progress_cb): nframes = int(clip.duration*fps)+1 count = 1 for frame in clip.iter_frames(fps=fps, progress_bar=progress_bar, dtype='uint8'): writer.append_data(frame) # if progress callback was define, call it if callable(progress_cb): progress_cb(count, nframes) count += 1
def write_images_sequence(self, nameformat, fps=None, verbose=True): """ Writes the videoclip to a sequence of image files. Parameters ----------- nameformat A filename specifying the numerotation format and extension of the pictures. For instance "frame%03d.png" for filenames indexed with 3 digits and PNG format. Also possible: "some_folder/frame%04d.jpeg", etc. fps Number of frames per second to consider when writing the clip. If not specified, the clip's ``fps`` attribute will be used if it has one. verbose Verbose output ? Returns -------- names_list A list of all the files generated. Notes ------ The resulting image sequence can be read using e.g. the class ``DirectoryClip``. """ verbose_print(verbose, "MoviePy: Writing frames %s."%(nameformat)) if fps is None: fps = self.fps tt = np.arange(0, self.duration, 1.0/fps) filenames = [] total = int(self.duration/fps)+1 for i, t in tqdm(enumerate(tt), total=total): name = nameformat%(i+1) filenames.append(name) self.save_frame(name, t, savemask=True) verbose_print(verbose, "MoviePy: Done writing frames %s."%(nameformat)) return filenames
def ffmpeg_audiowrite(clip, filename, fps, nbytes, buffersize, codec='libvorbis', bitrate=None, write_logfile=False, verbose=True): """ A function that wraps the FFMPEG_AudioWriter to write an AudioClip to a file. """ if write_logfile: logfile = open(filename + ".log", 'w+') else: logfile = None verbose_print(verbose, "Writing audio in %s\n" % filename) writer = FFMPEG_AudioWriter(filename, fps, nbytes, clip.nchannels, codec=codec, bitrate=bitrate, logfile=logfile) totalsize = int(fps * clip.duration) if (totalsize % buffersize == 0): nchunks = totalsize // buffersize else: nchunks = totalsize // buffersize + 1 pospos = list(range(0, totalsize, buffersize)) + [totalsize] for i in tqdm(range(nchunks)): tt = (1.0 / fps) * np.arange(pospos[i], pospos[i + 1]) sndarray = clip.to_soundarray(tt, nbytes=nbytes) writer.write_frames(sndarray) writer.close() if write_logfile: logfile.close() verbose_print(verbose, "Done writing Audio in %s !\n" % filename)
def ffmpeg_audiowrite(clip, filename, fps, nbytes, buffersize, codec='libvorbis', bitrate=None, write_logfile = False, verbose=True, ffmpeg_params=None): """ A function that wraps the FFMPEG_AudioWriter to write an AudioClip to a file. """ if write_logfile: logfile = open(filename + ".log", 'w+') else: logfile = None verbose_print(verbose, "[MoviePy] Writing audio in %s\n"%filename) writer = FFMPEG_AudioWriter(filename, fps, nbytes, clip.nchannels, codec=codec, bitrate=bitrate, logfile=logfile, ffmpeg_params=ffmpeg_params) for chunk in clip.iter_chunks(chunksize=buffersize, progress_bar=True, quantize=True, nbytes= nbytes, fps=fps): writer.write_frames(chunk) """ totalsize = int(fps*clip.duration) if (totalsize % buffersize == 0): nchunks = totalsize // buffersize else: nchunks = totalsize // buffersize + 1 pospos = list(range(0, totalsize, buffersize))+[totalsize] for i in tqdm(range(nchunks)): tt = (1.0/fps)*np.arange(pospos[i],pospos[i+1]) sndarray = clip.to_soundarray(tt, nbytes= nbytes) writer.write_frames(sndarray) """ writer.close() if write_logfile: logfile.close() verbose_print(verbose, "[MoviePy] Done.\n")
def write_gif(clip, filename, fps=None, program='ImageMagick', opt="OptimizeTransparency", fuzz=1, verbose=True, loop=0, dispose=False, colors=None): """ Write the VideoClip to a GIF file, without temporary files. Converts a VideoClip into an animated GIF using ImageMagick or ffmpeg. Parameters ----------- filename Name of the resulting gif file. fps Number of frames per second (see note below). If it isn't provided, then the function will look for the clip's ``fps`` attribute (VideoFileClip, for instance, have one). program Software to use for the conversion, either 'ImageMagick' or 'ffmpeg'. opt (ImageMagick only) optimalization to apply, either 'optimizeplus' or 'OptimizeTransparency'. fuzz (ImageMagick only) Compresses the GIF by considering that the colors that are less than fuzz% different are in fact the same. Notes ----- The gif will be playing the clip in real time (you can only change the frame rate). If you want the gif to be played slower than the clip you will use :: >>> # slow down clip 50% and make it a gif >>> myClip.speedx(0.5).write_gif('myClip.gif') """ # # We use processes chained with pipes. # # if program == 'ffmpeg' # frames --ffmpeg--> gif # # if program == 'ImageMagick' and optimize == (None, False) # frames --ffmpeg--> bmp frames --ImageMagick--> gif # # # if program == 'ImageMagick' and optimize != (None, False) # frames -ffmpeg-> bmp frames -ImagMag-> gif -ImagMag-> better gif # delay = 100.0 / fps cmd1 = [ get_setting("FFMPEG_BINARY"), '-y', '-loglevel', 'error', '-f', 'rawvideo', '-vcodec', 'rawvideo', '-r', "%.02f" % fps, '-s', "%dx%d" % (clip.w, clip.h), '-pix_fmt', 'rgb24', '-i', '-' ] popen_params = {"stdout": DEVNULL, "stderr": DEVNULL, "stdin": DEVNULL} if os.name == "nt": popen_params["creationflags"] = 0x08000000 if program == "ffmpeg": popen_params["stdin"] = sp.PIPE popen_params["stdout"] = DEVNULL proc1 = sp.Popen(cmd1 + ['-r', "%.02f" % fps, filename], **popen_params) else: popen_params["stdin"] = sp.PIPE popen_params["stdout"] = sp.PIPE proc1 = sp.Popen(cmd1 + ['-f', 'image2pipe', '-vcodec', 'bmp', '-'], **popen_params) if program == 'ImageMagick': cmd2 = [ get_setting("IMAGEMAGICK_BINARY"), '-delay', "%.02f" % (delay), "-dispose", "%d" % (2 if dispose else 1), '-loop', '%d' % loop, '-', '-coalesce' ] if (opt in [False, None]): popen_params["stdin"] = proc1.stdout popen_params["stdout"] = DEVNULL proc2 = sp.Popen(cmd2 + [filename], **popen_params) else: popen_params["stdin"] = proc1.stdout popen_params["stdout"] = sp.PIPE proc2 = sp.Popen(cmd2 + ['gif:-'], **popen_params) if opt: cmd3 = [ get_setting("IMAGEMAGICK_BINARY"), '-', '-layers', opt, '-fuzz', '%d' % fuzz + '%' ] + (["-colors", "%d" % colors] if colors is not None else []) + [filename] popen_params["stdin"] = proc2.stdout popen_params["stdout"] = DEVNULL proc3 = sp.Popen(cmd3, **popen_params) # We send all the frames to the first process verbose_print( verbose, "\nMoviePy: building GIF file %s\n" % filename + 40 * "-" + "\n") verbose_print(verbose, "Generating GIF frames...\n") try: for frame in clip.iter_frames(fps=fps, progress_bar=True): proc1.stdin.write(frame.tostring()) verbose_print(verbose, "Done.\n") except IOError as err: error = ("MoviePy Error: creation of %s failed because " "of the following error:\n\n%s.\n\n." % (filename, str(err))) if program == "ImageMagick": error = error + ( "This can be due to the fact that " "ImageMagick is not installed on your computer, or " "(for Windows users) that you didn't specify the " "path to the ImageMagick binary in file conf.py.") raise IOError(error) verbose_print(verbose, "Writing GIF... ") proc1.stdin.close() proc1.wait() if program == 'ImageMagick': proc2.wait() if opt: proc3.wait() verbose_print(verbose, 'Done. Your GIF is ready !')
def write_gif_with_tempfiles(clip, filename, fps=None, program='ImageMagick', opt="OptimizeTransparency", fuzz=1, verbose=True, loop=0, dispose=False, colors=None, tempfiles=False): """ Write the VideoClip to a GIF file. Converts a VideoClip into an animated GIF using ImageMagick or ffmpeg. Does the same as write_gif (see this one for more docstring), but writes every frame to a file instead of passing them in the RAM. Useful on computers with little RAM. """ fileName, fileExtension = os.path.splitext(filename) tt = np.arange(0, clip.duration, 1.0 / fps) tempfiles = [] verbose_print( verbose, "\nMoviePy: building GIF file %s\n" % filename + 40 * "-" + "\n") verbose_print(verbose, "Generating GIF frames.\n") total = int(clip.duration * fps) + 1 for i, t in tqdm(enumerate(tt), total=total): name = "%s_GIFTEMP%04d.png" % (fileName, i + 1) tempfiles.append(name) clip.save_frame(name, t, savemask=True) verbose_print(verbose, "Done generating GIF frames.\n") delay = int(100.0 / fps) if program == "ImageMagick": cmd = [ get_setting("IMAGEMAGICK_BINARY"), '-delay', '%d' % delay, "-dispose", "%d" % (2 if dispose else 1), "-loop", "%d" % loop, "%s_GIFTEMP*.png" % fileName, "-coalesce", "-layers", "%s" % opt, "-fuzz", "%02d" % fuzz + "%", ] + (["-colors", "%d" % colors] if colors is not None else []) + [filename] elif program == "ffmpeg": cmd = [ get_setting("FFMPEG_BINARY"), '-y', '-f', 'image2', '-r', str(fps), '-i', fileName + '_GIFTEMP%04d.png', '-r', str(fps), filename ] try: subprocess_call(cmd, verbose=verbose) except (IOError, OSError) as err: error = ("MoviePy Error: creation of %s failed because " "of the following error:\n\n%s.\n\n." % (filename, str(err))) if program == "ImageMagick": error = error + ( "This error can be due to the fact that " "ImageMagick is not installed on your computer, or " "(for Windows users) that you didn't specify the " "path to the ImageMagick binary in file conf.py.") raise IOError(error) for f in tempfiles: os.remove(f)
def write_gif(self, filename, fps=None, program= 'ImageMagick', opt="OptimizeTransparency", fuzz=1, verbose=True, loop=0, dispose=False): """ Write the VideoClip to a GIF file. Converts a VideoClip into an animated GIF using ImageMagick or ffmpeg. Parameters ----------- filename Name of the resulting gif file. fps Number of frames per second (see note below). If it isn't provided, then the function will look for the clip's ``fps`` attribute (VideoFileClip, for instance, have one). program Software to use for the conversion, either 'ImageMagick' or 'ffmpeg'. opt (ImageMagick only) optimalization to apply, either 'optimizeplus' or 'OptimizeTransparency'. fuzz (ImageMagick only) Compresses the GIF by considering that the colors that are less than fuzz% different are in fact the same. Notes ----- The gif will be playing the clip in real time (you can only change the frame rate). If you want the gif to be played slower than the clip you will use :: >>> # slow down clip 50% and make it a gif >>> myClip.speedx(0.5).to_gif('myClip.gif') """ if fps is None: fps = self.fps fileName, fileExtension = os.path.splitext(filename) tt = np.arange(0,self.duration, 1.0/fps) tempfiles = [] verbose_print(verbose, "\nMoviePy: building GIF file %s\n"%filename +40*"-"+"\n") verbose_print(verbose, "Generating GIF frames.\n") total = int(self.duration*fps)+1 for i, t in tqdm(enumerate(tt), total=total): name = "%s_GIFTEMP%04d.png"%(fileName, i+1) tempfiles.append(name) self.save_frame(name, t, savemask=True) verbose_print(verbose, "Done generating GIF frames.\n") delay = int(100.0/fps) if program == "ImageMagick": cmd = [IMAGEMAGICK_BINARY, '-delay' , '%d'%delay, "-dispose" ,"%d"%(2 if dispose else 1), "-loop" , "%d"%loop, "%s_GIFTEMP*.png"%fileName, "-coalesce", "-fuzz", "%02d"%fuzz + "%", "-layers", "%s"%opt, filename] elif program == "ffmpeg": cmd = [FFMPEG_BINARY, '-y', '-f', 'image2', '-r',str(fps), '-i', fileName+'_GIFTEMP%04d.bmp', '-r',str(fps), filename] try: subprocess_call( cmd, verbose = verbose ) except IOError as err: error = ("MoviePy Error: creation of %s failed because " "of the following error:\n\n%s.\n\n."%(filename, str(err))) if program == "ImageMagick": error = error + ("This can be due to the fact that " "ImageMagick is not installed on your computer, or " "(for Windows users) that you didn't specify the " "path to the ImageMagick binary in file conf.py." ) raise IOError(error) for f in tempfiles: os.remove(f)
def write_gif2(self, filename, fps=None, program= 'ImageMagick', opt="OptimizeTransparency", fuzz=1, verbose=True, loop=0, dispose=False): """ Write the VideoClip to a GIF file, without temporary files. Converts a VideoClip into an animated GIF using ImageMagick or ffmpeg. Parameters ----------- filename Name of the resulting gif file. fps Number of frames per second (see note below). If it isn't provided, then the function will look for the clip's ``fps`` attribute (VideoFileClip, for instance, have one). program Software to use for the conversion, either 'ImageMagick' or 'ffmpeg'. opt (ImageMagick only) optimalization to apply, either 'optimizeplus' or 'OptimizeTransparency'. fuzz (ImageMagick only) Compresses the GIF by considering that the colors that are less than fuzz% different are in fact the same. Notes ----- The gif will be playing the clip in real time (you can only change the frame rate). If you want the gif to be played slower than the clip you will use :: >>> # slow down clip 50% and make it a gif >>> myClip.speedx(0.5).write_gif('myClip.gif') """ # # We use processes chained with pipes. # # if program == 'ffmpeg' # frames --ffmpeg--> gif # # if program == 'ImageMagick' and optimize == (None, False) # frames --ffmpeg--> bmp frames --ImageMagick--> gif # # # if program == 'ImageMagick' and optimize != (None, False) # frames -ffmpeg-> bmp frames -ImagMag-> gif -ImagMag-> better gif # if fps is None: fps=self.fps cmd1 = [FFMPEG_BINARY, '-y', '-loglevel', 'error', '-f', 'rawvideo', '-vcodec','rawvideo', '-r', "%.02f"%fps, '-s', "%dx%d"%(self.w, self.h), '-pix_fmt', 'rgb24', '-i', '-'] cmd1a = cmd1+['-r', "%.02f"%fps, filename] cmd1b = cmd1+['-f', 'image2pipe','-vcodec', 'bmp', '-'] cmd2 = [IMAGEMAGICK_BINARY, '-', '-delay', "%d"%int(100.0/fps), '-loop', '%d'%loop] cmd2a = cmd2+[filename] cmd2b = cmd2+['gif:-'] proc1 = (sp.Popen(cmd1a, stdin=sp.PIPE, stdout=DEVNULL) if (program =='ffmpeg') else sp.Popen(cmd1b, stdin=sp.PIPE, stdout=sp.PIPE)) if program == 'ImageMagick': proc2 = (sp.Popen(cmd2a, stdin=proc1.stdout) if (opt in [False, None]) else sp.Popen(cmd2b, stdin=proc1.stdout, stdout=sp.PIPE)) if opt: cmd3 = [IMAGEMAGICK_BINARY, '-', '-layers', opt, '-fuzz', '%d'%fuzz+'%',filename] proc3 = sp.Popen(cmd3, stdin=proc2.stdout) # We send all the frames to the first process verbose_print(verbose, "\nMoviePy: building GIF file %s\n"%filename +40*"-"+"\n") verbose_print(verbose, "Generating GIF frames...\n") nframes = int(self.duration*fps)+1 try: for frame in tqdm(self.iter_frames(fps=fps), total=nframes): proc1.stdin.write(frame.tostring()) verbose_print(verbose, "Done.\n") except IOError as err: error = ("MoviePy Error: creation of %s failed because " "of the following error:\n\n%s.\n\n."%(filename, str(err))) if program == "ImageMagick": error = error + ("This can be due to the fact that " "ImageMagick is not installed on your computer, or " "(for Windows users) that you didn't specify the " "path to the ImageMagick binary in file conf.py." ) raise IOError(error) verbose_print(verbose, "Writing GIF... ") proc1.stdin.close() proc1.wait() if program == 'ImageMagick': proc2.wait() if opt: proc3.wait() verbose_print(verbose, 'Done. Your GIF is ready !')
def write_gif(clip, filename, fps=None, program= 'ImageMagick', opt="OptimizeTransparency", fuzz=1, verbose=True, withmask=True, loop=0, dispose=True, colors=None, progress_bar=True, progress_cb=None): """ Write the VideoClip to a GIF file, without temporary files. Converts a VideoClip into an animated GIF using ImageMagick or ffmpeg. Parameters ----------- filename Name of the resulting gif file. fps Number of frames per second (see note below). If it isn't provided, then the function will look for the clip's ``fps`` attribute (VideoFileClip, for instance, have one). program Software to use for the conversion, either 'ImageMagick' or 'ffmpeg'. opt (ImageMagick only) optimalization to apply, either 'optimizeplus' or 'OptimizeTransparency'. fuzz (ImageMagick only) Compresses the GIF by considering that the colors that are less than fuzz% different are in fact the same. progress_bar Determines whether to display a progress bar in the terminal while exporting the file. progress_cb Callback function to call during export. It should accept the current frame index being exported and the total number of frames. It can be used to update a gui progressbar while running in a separate thread. Notes ----- The gif will be playing the clip in real time (you can only change the frame rate). If you want the gif to be played slower than the clip you will use :: >>> # slow down clip 50% and make it a gif >>> myClip.speedx(0.5).write_gif('myClip.gif') """ # # We use processes chained with pipes. # # if program == 'ffmpeg' # frames --ffmpeg--> gif # # if program == 'ImageMagick' and optimize == (None, False) # frames --ffmpeg--> bmp frames --ImageMagick--> gif # # # if program == 'ImageMagick' and optimize != (None, False) # frames -ffmpeg-> bmp frames -ImagMag-> gif -ImagMag-> better gif # delay= 100.0/fps if clip.mask is None: withmask = False cmd1 = [get_setting("FFMPEG_BINARY"), '-y', '-loglevel', 'error', '-f', 'rawvideo', '-vcodec','rawvideo', '-r', "%.02f"%fps, '-s', "%dx%d"%(clip.w, clip.h), '-pix_fmt', ('rgba' if withmask else 'rgb24'), '-i', '-'] popen_params = {"stdout": DEVNULL, "stderr": DEVNULL, "stdin": DEVNULL} if os.name == "nt": popen_params["creationflags"] = 0x08000000 if program == "ffmpeg": popen_params["stdin"] = sp.PIPE popen_params["stdout"] = DEVNULL proc1 = sp.Popen(cmd1+[ '-pix_fmt', ('rgba' if withmask else 'rgb24'), '-r', "%.02f"%fps, filename], **popen_params) else: popen_params["stdin"] = sp.PIPE popen_params["stdout"] = sp.PIPE proc1 = sp.Popen(cmd1+ ['-f', 'image2pipe', '-vcodec', 'bmp', '-'], **popen_params) if program == 'ImageMagick': cmd2 = [get_setting("IMAGEMAGICK_BINARY"), '-delay', "%.02f"%(delay), "-dispose" ,"%d"%(2 if dispose else 1), '-loop', '%d'%loop, '-', '-coalesce'] if (opt in [False, None]): popen_params["stdin"] = proc1.stdout popen_params["stdout"] = DEVNULL proc2 = sp.Popen(cmd2+[filename], **popen_params) else: popen_params["stdin"] = proc1.stdout popen_params["stdout"] = sp.PIPE proc2 = sp.Popen(cmd2+['gif:-'], **popen_params) if opt: cmd3 = [get_setting("IMAGEMAGICK_BINARY"), '-', '-layers', opt, '-fuzz', '%d'%fuzz+'%' ]+(["-colors", "%d"%colors] if colors is not None else [])+[ filename] popen_params["stdin"] = proc2.stdout popen_params["stdout"] = DEVNULL proc3 = sp.Popen(cmd3, **popen_params) # We send all the frames to the first process verbose_print(verbose, "\n[MoviePy] >>>> Building file %s\n"%filename) verbose_print(verbose, "[MoviePy] Generating GIF frames...\n") try: # if progress callback was define, call it if callable(progress_cb): nframes = int(clip.duration*fps)+1 count = 1 for t,frame in clip.iter_frames(fps=fps, progress_bar=progress_bar, with_times=True, dtype="uint8"): if withmask: mask = 255 * clip.mask.get_frame(t) frame = np.dstack([frame, mask]).astype('uint8') proc1.stdin.write(frame.tostring()) # if progress callback was define, call it if callable(progress_cb): progress_cb(count, nframes) count += 1 except IOError as err: error = ("[MoviePy] Error: creation of %s failed because " "of the following error:\n\n%s.\n\n."%(filename, str(err))) if program == "ImageMagick": error = error + ("This can be due to the fact that " "ImageMagick is not installed on your computer, or " "(for Windows users) that you didn't specify the " "path to the ImageMagick binary in file conf.py." ) raise IOError(error) if program == 'ImageMagick': verbose_print(verbose, "[MoviePy] Optimizing the GIF with ImageMagick...\n") proc1.stdin.close() proc1.wait() if program == 'ImageMagick': proc2.wait() if opt: proc3.wait() verbose_print(verbose, "[MoviePy] >>>> File %s is ready!"%filename)
def write_videofile(self, filename, fps=24, codec='libx264', bitrate=None, audio=True, audio_fps=44100, audio_nbytes = 4, audio_codec= 'libmp3lame', audio_bitrate = None, audio_bufsize = 2000, temp_audiofile=None, rewrite_audio = True, remove_temp = True, write_logfile=False, para = False, verbose = True): """Write the clip to a videofile. Parameters ----------- filename Name of the video file. The extension must correspond to the codec used (see below), ar simply be '.avi'. fps Number of frames per second in the resulting video file. codec Codec to use for image encoding. Can be any codec supported by ffmpeg, but the extension of the output filename must be set accordingly. Some examples of codecs are: ``'libx264'`` (default codec, use file extension ``.mp4``) makes well-compressed videos (quality tunable using 'bitrate'). ``'mpeg4'`` (use file extension ``.mp4``) can be an alternative to ``'libx264'``, and produces higher quality videos by default. ``'rawvideo'`` (use file extension ``.avi``) will produce a video of perfect quality, of possibly very huge size. ``png`` (use file extension ``.avi``) will produce a video of perfect quality, of smaller size than with ``rawvideo`` ``'libvorbis'`` (use file extension ``.ogv``) is a nice video format, which is completely free/ open source. However not everyone has the codecs installed by default on their machine. ``'libvpx'`` (use file extension ``.webm``) is tiny a video format well indicated for web videos (with HTML5). Open source. audio Either ``True``, ``False``, or a file name. If ``True`` and the clip has an audio clip attached, this audio clip will be incorporated as a soundtrack in the movie. If ``audio`` is the name of an audio file, this audio file will be incorporated as a soundtrack in the movie. audiofps frame rate to use when generating the sound. temp_audiofile the name of the temporary audiofile to be generated and incorporated in the the movie, if any. audio_codec Which audio codec should be used. Examples are 'libmp3lame' for '.mp3', 'libvorbis' for 'ogg', 'libfdk_aac':'m4a', 'pcm_s16le' for 16-bit wav and 'pcm_s32le' for 32-bit wav. audio_bitrate Audio bitrate, given as a string like '50k', '500k', '3000k'. Will determine the size/quality of audio in the output file. Note that it mainly an indicative goal, the bitrate won't necessarily be the this in the final file. write_logfile If true, will write log files for the audio and the video. These will be files ending with '.log' with the name of the output file in them. """ name, ext = os.path.splitext(os.path.basename(filename)) if audio_codec == 'raw16': audio_codec = 'pcm_s16le' elif audio_codec == 'raw32': audio_codec = 'pcm_s32le' if isinstance(audio, str): # audio is some audiofile it is maybe not a wav file. It is # NOT temporary file, it will NOT be removed at the end. temp_audiofile = audio make_audio = False merge_audio = True elif self.audio is None: # audio not provided as a file and no clip.audio make_audio = merge_audio = False elif audio: # The audio will be the clip's audio if temp_audiofile is None: # make a name for the temporary audio file D_ext = {'libmp3lame': 'mp3', 'libvorbis':'ogg', 'libfdk_aac':'m4a', 'aac':'m4a', 'pcm_s16le':'wav', 'pcm_s32le': 'wav'} if audio_codec in D_ext.values(): audio_ext = audio_codec else: if audio_codec in D_ext.keys(): audio_ext = D_ext[audio_codec] else: raise ValueError('audio_codec for file' '%s unkown !'%filename) temp_audiofile = (name+Clip._TEMP_FILES_PREFIX + "write_videofile_SOUND.%s"%audio_ext) make_audio = ( (not os.path.exists(temp_audiofile)) or rewrite_audio) merge_audio = True else: make_audio = False merge_audio = False if merge_audio: # make a name for the temporary video file videofile = (name + Clip._TEMP_FILES_PREFIX + "write_videofile%s"%ext) else: videofile = filename # enough cpu for multiprocessing ? enough_cpu = (multiprocessing.cpu_count() > 2) verbose_print(verbose, "\nMoviePy: building video file %s\n"%filename +40*"-"+"\n") if para and make_audio and enough_cpu: # Parallelize verbose_print(verbose, "Writing audio/video in parrallel.\n") audioproc = multiprocessing.Process( target=self.audio.write_audiofile, args=(temp_audiofile,audio_fps,audio_nbytes, audio_bufsize,audio_codec, audio_bitrate, verbose)) audioproc.start() ffmpeg_write_video(self, videofile, fps, codec, bitrate=bitrate, write_logfile=write_logfile, verbose=verbose) audioproc.join() if audioproc.exitcode: print ("WARNING: something went wrong with the audio"+ " writing, Exit code %d"%audioproc.exitcode) else: # Don't parallelize if make_audio: self.audio.write_audiofile(temp_audiofile,audio_fps, audio_nbytes, audio_bufsize, audio_codec, bitrate=audio_bitrate, write_logfile=write_logfile, verbose=verbose) ffmpeg_write_video(self, videofile, fps, codec, bitrate=bitrate, write_logfile=write_logfile, verbose=verbose) # Merge with audio if any and trash temporary files. if merge_audio: verbose_print(verbose, "\n\nNow merging video and audio:\n") ffmpeg_merge_video_audio(videofile,temp_audiofile, filename, ffmpeg_output=True) if remove_temp: os.remove(videofile) if not isinstance(audio,str): os.remove(temp_audiofile) verbose_print(verbose, "\nYour video is ready !\n")
def write_gif_with_tempfiles(clip, filename, fps=None, program= 'ImageMagick', opt="OptimizeTransparency", fuzz=1, verbose=True, loop=0, dispose=True, colors=None, tempfiles=False, progress_bar=True, progress_cb=None): """ Write the VideoClip to a GIF file. Converts a VideoClip into an animated GIF using ImageMagick or ffmpeg. Does the same as write_gif (see this one for more docstring), but writes every frame to a file instead of passing them in the RAM. Useful on computers with little RAM. Parameters ----------- filename Name of the resulting gif file. fps Number of frames per second (see note below). If it isn't provided, then the function will look for the clip's ``fps`` attribute (VideoFileClip, for instance, have one). program Software to use for the conversion, either 'ImageMagick' or 'ffmpeg'. opt (ImageMagick only) optimalization to apply, either 'optimizeplus' or 'OptimizeTransparency'. fuzz (ImageMagick only) Compresses the GIF by considering that the colors that are less than fuzz% different are in fact the same. progress_bar Boolean indicating whether to display a progress bar in the terminal while exporting the file. progress_cb Callback function to call during export. It should accept the current frame index being exported and the total number of frames. It can be used to update a gui progressbar while running in a separate thread. """ fileName, fileExtension = os.path.splitext(filename) tt = np.arange(0,clip.duration, 1.0/fps) tempfiles = [] verbose_print(verbose, "\n[MoviePy] Building file %s\n"%filename +40*"-"+"\n") verbose_print(verbose, "[MoviePy] Generating GIF frames...\n") total = int(clip.duration*fps)+1 if progress_bar: # Show a terminal-based progress bar while exporting iterator = tqdm(enumerate(tt), total=total) else: iterator = enumerate(tt) for i, t in iterator: name = "%s_GIFTEMP%04d.png"%(fileName, i+1) tempfiles.append(name) clip.save_frame(name, t, withmask=True) # if progress callback was define, call it if callable(progress_cb): progress_cb(i+1, total) delay = int(100.0/fps) if program == "ImageMagick": verbose_print(verbose, "[MoviePy] Optimizing GIF with ImageMagick... ") cmd = [get_setting("IMAGEMAGICK_BINARY"), '-delay' , '%d'%delay, "-dispose" ,"%d"%(2 if dispose else 1), "-loop" , "%d"%loop, "%s_GIFTEMP*.png"%fileName, "-coalesce", "-layers", "%s"%opt, "-fuzz", "%02d"%fuzz + "%", ]+(["-colors", "%d"%colors] if colors is not None else [])+[ filename] elif program == "ffmpeg": cmd = [get_setting("FFMPEG_BINARY"), '-y', '-f', 'image2', '-r',str(fps), '-i', fileName+'_GIFTEMP%04d.png', '-r',str(fps), filename] try: subprocess_call( cmd, verbose = verbose ) verbose_print(verbose, "[MoviePy] GIF %s is ready."%filename) except (IOError,OSError) as err: error = ("MoviePy Error: creation of %s failed because " "of the following error:\n\n%s.\n\n."%(filename, str(err))) if program == "ImageMagick": error = error + ("This error can be due to the fact that " "ImageMagick is not installed on your computer, or " "(for Windows users) that you didn't specify the " "path to the ImageMagick binary in file conf.py." ) raise IOError(error) for f in tempfiles: os.remove(f)
def write_gif(clip, filename, fps=None, program= 'ImageMagick', opt="OptimizeTransparency", fuzz=1, verbose=True, withmask=True, loop=0, dispose=True, colors=None): """ Write the VideoClip to a GIF file, without temporary files. Converts a VideoClip into an animated GIF using ImageMagick or ffmpeg. Parameters ----------- filename Name of the resulting gif file. fps Number of frames per second (see note below). If it isn't provided, then the function will look for the clip's ``fps`` attribute (VideoFileClip, for instance, have one). program Software to use for the conversion, either 'ImageMagick' or 'ffmpeg'. opt (ImageMagick only) optimalization to apply, either 'optimizeplus' or 'OptimizeTransparency'. fuzz (ImageMagick only) Compresses the GIF by considering that the colors that are less than fuzz% different are in fact the same. Notes ----- The gif will be playing the clip in real time (you can only change the frame rate). If you want the gif to be played slower than the clip you will use :: >>> # slow down clip 50% and make it a gif >>> myClip.speedx(0.5).write_gif('myClip.gif') """ # # We use processes chained with pipes. # # if program == 'ffmpeg' # frames --ffmpeg--> gif # # if program == 'ImageMagick' and optimize == (None, False) # frames --ffmpeg--> bmp frames --ImageMagick--> gif # # # if program == 'ImageMagick' and optimize != (None, False) # frames -ffmpeg-> bmp frames -ImagMag-> gif -ImagMag-> better gif # delay= 100.0/fps if clip.mask is None: withmask = False cmd1 = [get_setting("FFMPEG_BINARY"), '-y', '-loglevel', 'error', '-f', 'rawvideo', '-vcodec','rawvideo', '-r', "%.02f"%fps, '-s', "%dx%d"%(clip.w, clip.h), '-pix_fmt', ('rgba' if withmask else 'rgb24'), '-i', '-'] popen_params = {"stdout": DEVNULL, "stderr": DEVNULL, "stdin": DEVNULL} if os.name == "nt": popen_params["creationflags"] = 0x08000000 if program == "ffmpeg": popen_params["stdin"] = sp.PIPE popen_params["stdout"] = DEVNULL proc1 = sp.Popen(cmd1+[ '-pix_fmt', ('rgba' if withmask else 'rgb24'), '-r', "%.02f"%fps, filename], **popen_params) else: popen_params["stdin"] = sp.PIPE popen_params["stdout"] = sp.PIPE proc1 = sp.Popen(cmd1+ ['-f', 'image2pipe', '-vcodec', 'bmp', '-'], **popen_params) if program == 'ImageMagick': cmd2 = [get_setting("IMAGEMAGICK_BINARY"), '-delay', "%.02f"%(delay), "-dispose" ,"%d"%(2 if dispose else 1), '-loop', '%d'%loop, '-', '-coalesce'] if (opt in [False, None]): popen_params["stdin"] = proc1.stdout popen_params["stdout"] = DEVNULL proc2 = sp.Popen(cmd2+[filename], **popen_params) else: popen_params["stdin"] = proc1.stdout popen_params["stdout"] = sp.PIPE proc2 = sp.Popen(cmd2+['gif:-'], **popen_params) if opt: cmd3 = [get_setting("IMAGEMAGICK_BINARY"), '-', '-layers', opt, '-fuzz', '%d'%fuzz+'%' ]+(["-colors", "%d"%colors] if colors is not None else [])+[ filename] popen_params["stdin"] = proc2.stdout popen_params["stdout"] = DEVNULL proc3 = sp.Popen(cmd3, **popen_params) # We send all the frames to the first process verbose_print(verbose, "\n[MoviePy] >>>> Building file %s\n"%filename) verbose_print(verbose, "[MoviePy] Generating GIF frames...\n") try: for t,frame in clip.iter_frames(fps=fps, progress_bar=True, with_times=True, dtype="uint8"): if withmask: mask = 255 * clip.mask.get_frame(t) frame = np.dstack([frame, mask]).astype('uint8') proc1.stdin.write(frame.tostring()) except IOError as err: error = ("[MoviePy] Error: creation of %s failed because " "of the following error:\n\n%s.\n\n."%(filename, str(err))) if program == "ImageMagick": error = error + ("This can be due to the fact that " "ImageMagick is not installed on your computer, or " "(for Windows users) that you didn't specify the " "path to the ImageMagick binary in file conf.py." ) raise IOError(error) if program == 'ImageMagick': verbose_print(verbose, "[MoviePy] Optimizing the GIF with ImageMagick...\n") proc1.stdin.close() proc1.wait() if program == 'ImageMagick': proc2.wait() if opt: proc3.wait() verbose_print(verbose, "[MoviePy] >>>> File %s is ready!"%filename)
def write_gif_with_tempfiles(clip, filename, fps=None, program= 'ImageMagick', opt="OptimizeTransparency", fuzz=1, verbose=True, loop=0, dispose=True, colors=None): """ Write the VideoClip to a GIF file. Converts a VideoClip into an animated GIF using ImageMagick or ffmpeg. Does the same as write_gif (see this one for more docstring), but writes every frame to a file instead of passing them in the RAM. Useful on computers with little RAM. """ fileName, fileExtension = os.path.splitext(filename) tt = np.arange(0,clip.duration, 1.0/fps) tempfiles = [] verbose_print(verbose, "\n[MoviePy] Building file %s\n"%filename +40*"-"+"\n") verbose_print(verbose, "[MoviePy] Generating GIF frames...\n") total = int(clip.duration*fps)+1 for i, t in tqdm(enumerate(tt), total=total): name = "%s_GIFTEMP%04d.png"%(fileName, i+1) tempfiles.append(name) clip.save_frame(name, t, withmask=True) delay = int(100.0/fps) if program == "ImageMagick": verbose_print(verbose, "[MoviePy] Optimizing GIF with ImageMagick... ") cmd = [get_setting("IMAGEMAGICK_BINARY"), '-delay' , '%d'%delay, "-dispose" ,"%d"%(2 if dispose else 1), "-loop" , "%d"%loop, "%s_GIFTEMP*.png"%fileName, "-coalesce", "-layers", "%s"%opt, "-fuzz", "%02d"%fuzz + "%", ]+(["-colors", "%d"%colors] if colors is not None else [])+[ filename] elif program == "ffmpeg": cmd = [get_setting("FFMPEG_BINARY"), '-y', '-f', 'image2', '-r',str(fps), '-i', fileName+'_GIFTEMP%04d.png', '-r',str(fps), filename] try: subprocess_call( cmd, verbose = verbose ) verbose_print(verbose, "[MoviePy] GIF %s is ready."%filename) except (IOError,OSError) as err: error = ("MoviePy Error: creation of %s failed because " "of the following error:\n\n%s.\n\n."%(filename, str(err))) if program == "ImageMagick": error = error + ("This error can be due to the fact that " "ImageMagick is not installed on your computer, or " "(for Windows users) that you didn't specify the " "path to the ImageMagick binary in file conf.py." ) raise IOError(error) for f in tempfiles: os.remove(f)