@@ -292,31 +292,9 @@ def _encode_gif(images, fps):
292292 Raises:
293293 IOError: If the ffmpeg command returns an error.
294294 """
295- from subprocess import Popen , PIPE # pylint: disable=g-import-not-at-top,g-multiple-import
296- ffmpeg = "ffmpeg"
297- height , width , channels = images [0 ].shape
298- cmd = [
299- ffmpeg , "-y" ,
300- "-f" , "rawvideo" ,
301- "-vcodec" , "rawvideo" ,
302- "-r" , "%.02f" % fps ,
303- "-s" , "%dx%d" % (width , height ),
304- "-pix_fmt" , {1 : "gray" , 3 : "rgb24" }[channels ],
305- "-i" , "-" ,
306- "-filter_complex" , "[0:v]split[x][z];[z]palettegen[y];[x][y]paletteuse" ,
307- "-r" , "%.02f" % fps ,
308- "-f" , "gif" ,
309- "-"
310- ]
311- proc = Popen (cmd , stdin = PIPE , stdout = PIPE , stderr = PIPE )
312- for image in images :
313- proc .stdin .write (image .tostring ())
314- out , err = proc .communicate ()
315- if proc .returncode :
316- err = "\n " .join ([" " .join (cmd ), err .decode ("utf8" )])
317- raise IOError (err )
318- del proc
319- return out
295+ writer = VideoWriter (fps )
296+ writer .write_multi (images )
297+ return writer .finish ()
320298
321299
322300def py_gif_summary (tag , images , max_outputs , fps ):
@@ -521,3 +499,89 @@ def beta_schedule(schedule, global_step, final_beta, decay_start, decay_end):
521499 tf .greater (global_step , decay_end ): lambda : final_beta },
522500 default = lambda : increased_value )
523501 return beta
502+
503+
504+ class VideoWriter (object ):
505+ """Helper class for writing videos."""
506+
507+ def __init__ (self , fps , file_format = "gif" ):
508+ self .fps = fps
509+ self .file_format = file_format
510+ self .proc = None
511+
512+ def __init_ffmpeg (self , image_shape ):
513+ """Initializes ffmpeg to write frames."""
514+ from subprocess import Popen , PIPE # pylint: disable=g-import-not-at-top,g-multiple-import
515+ ffmpeg = "ffmpeg"
516+ height , width , channels = image_shape
517+ self .cmd = [
518+ ffmpeg , "-y" ,
519+ "-f" , "rawvideo" ,
520+ "-vcodec" , "rawvideo" ,
521+ "-r" , "%.02f" % self .fps ,
522+ "-s" , "%dx%d" % (width , height ),
523+ "-pix_fmt" , {1 : "gray" , 3 : "rgb24" }[channels ],
524+ "-i" , "-" ,
525+ "-filter_complex" , "[0:v]split[x][z];[z]palettegen[y];[x][y]paletteuse" ,
526+ "-r" , "%.02f" % self .fps ,
527+ "-f" , self .file_format ,
528+ "-"
529+ ]
530+ self .proc = Popen (self .cmd , stdin = PIPE , stdout = PIPE , stderr = PIPE )
531+
532+ def write (self , frame ):
533+ if self .proc is None :
534+ self .__init_ffmpeg (frame .shape )
535+ self .proc .stdin .write (frame .tostring ())
536+
537+ def write_multi (self , frames ):
538+ for frame in frames :
539+ self .write (frame )
540+
541+ def finish (self ):
542+ if self .proc is None :
543+ return None
544+ out , err = self .proc .communicate ()
545+ if self .proc .returncode :
546+ err = "\n " .join ([" " .join (self .cmd ), err .decode ("utf8" )])
547+ raise IOError (err )
548+ del self .proc
549+ self .proc = None
550+ return out
551+
552+ def finish_to_file (self , path ):
553+ with tf .gfile .open (path ) as f :
554+ f .write (self .finish ())
555+
556+ def __del__ (self ):
557+ self .finish ()
558+
559+
560+ class BatchVideoWriter (object ):
561+ """Helper class for writing videos in batch."""
562+
563+ def __init__ (self , fps , file_format = "gif" ):
564+ self .fps = fps
565+ self .file_format = file_format
566+ self .writers = None
567+
568+ def write (self , batch_frame ):
569+ if self .writers is None :
570+ self .writers = [
571+ VideoWriter (self .fps , self .file_format ) for _ in batch_frame ]
572+ for i , frame in enumerate (batch_frame ):
573+ self .writers [i ].write (frame )
574+
575+ def write_multi (self , batch_frames ):
576+ for batch_frame in batch_frames :
577+ self .write (batch_frame )
578+
579+ def finish (self ):
580+ outs = [w .finish () for w in self .writers ]
581+ return outs
582+
583+ def finish_to_files (self , path_template ):
584+ for i , writer in enumerate (self .writers ):
585+ path = path_template .format (i )
586+ writer .finish_to_file (path )
587+
0 commit comments