def _get_repr_html_ffmpeg(images: List[PilImage]) -> str: """Runs ffmpeg to get the mp4 encoded <video> str.""" # Find number of digits in len to give names. num_digits = len(str(len(images))) + 1 with tempfile.TemporaryDirectory() as video_dir: for i, img in enumerate(images): f = os.path.join(video_dir, f'img{i:0{num_digits}d}.png') img.save(f, format='png') ffmpeg_args = [ '-framerate', str(_VISU_FRAMERATE), '-i', os.path.join(video_dir, f'img%0{num_digits}d.png'), # Using native h264 to encode video stream to H.264 codec # Default encoding does not seems to be supported by chrome. '-vcodec', 'h264', # When outputting H.264, `-pix_fmt yuv420p` maximize compatibility # with bad video players. # Ref: https://trac.ffmpeg.org/wiki/Slideshow '-pix_fmt', 'yuv420p', # Native encoder cannot encode images of small scale # or the the hardware encoder may be busy which raises # Error: cannot create compression session # so allow software encoding # '-allow_sw', '1', ] video_path = utils.as_path(video_dir) / 'output.mp4' ffmpeg_args.append(os.fspath(video_path)) utils.ffmpeg_run(ffmpeg_args) video_str = utils.get_base64(video_path.read_bytes()) return ( f'<video height="{THUMBNAIL_SIZE}" width="175" ' 'controls loop autoplay muted playsinline>' f'<source src="data:video/mp4;base64,{video_str}" type="video/mp4" >' '</video>' )
def make_video_repr_html(ex, *, use_colormap: bool): """Returns the encoded `<video>` or GIF <img/> HTML.""" # Use GIF to generate a HTML5 compatible video if FFMPEG is not # installed on the system. images = [_create_thumbnail(frame, use_colormap=use_colormap) for frame in ex] if not images: return 'Video with 0 frames.' # Display the video HTML (either GIF of mp4 if ffmpeg is installed) try: utils.ffmpeg_run(['-version']) # Check for ffmpeg installation. except FileNotFoundError: # print as `stderr` is displayed poorly on Colab print('FFMPEG not detected. Falling back on GIF.') return _get_repr_html_gif(images) else: return _get_repr_html_ffmpeg(images)
def _ffmpeg_decode(self, path_or_fobj): if isinstance(path_or_fobj, type_utils.PathLikeCls): ffmpeg_args = ['-i', os.fspath(path_or_fobj)] ffmpeg_stdin = None else: ffmpeg_args = ['-i', 'pipe:0'] ffmpeg_stdin = path_or_fobj.read() ffmpeg_args += self._extra_ffmpeg_args with tempfile.TemporaryDirectory() as ffmpeg_dir: out_pattern = os.path.join(ffmpeg_dir, f'%010d.{self._encoding_format}') ffmpeg_args.append(out_pattern) utils.ffmpeg_run(ffmpeg_args, ffmpeg_stdin) frames = [ # Load all encoded images p.read_bytes() for p in sorted(utils.as_path(ffmpeg_dir).iterdir()) ] return frames