1""" 2This module implements ipython_display 3A function to embed images/videos/audio in the IPython Notebook 4""" 5 6# Notes: 7# All media are physically embedded in the IPython Notebook 8# (instead of simple links to the original files) 9# That is because most browsers use a cache system and they won't 10# properly refresh the media when the original files are changed. 11 12import os 13from base64 import b64encode 14 15from moviepy.audio.AudioClip import AudioClip 16from moviepy.tools import extensions_dict 17 18from ..VideoClip import ImageClip, VideoClip 19from .ffmpeg_reader import ffmpeg_parse_infos 20 21try: 22 from IPython.display import HTML 23 ipython_available = True 24 class HTML2(HTML): 25 def __add__(self, other): 26 return HTML2(self.data+other.data) 27 28except ImportError: 29 ipython_available = False 30 31 32sorry = "Sorry, seems like your browser doesn't support HTML5 audio/video" 33templates = {"audio":("<audio controls>" 34 "<source %(options)s src='data:audio/%(ext)s;base64,%(data)s'>" 35 +sorry+"</audio>"), 36 "image":"<img %(options)s " 37 "src='data:image/%(ext)s;base64,%(data)s'>", 38 "video":("<video %(options)s" 39 "src='data:video/%(ext)s;base64,%(data)s' controls>" 40 +sorry+"</video>")} 41 42 43def html_embed(clip, filetype=None, maxduration=60, rd_kwargs=None, 44 center=True, **html_kwargs): 45 """ Returns HTML5 code embedding the clip 46 47 clip 48 Either a file name, or a clip to preview. 49 Either an image, a sound or a video. Clips will actually be 50 written to a file and embedded as if a filename was provided. 51 52 53 filetype 54 One of 'video','image','audio'. If None is given, it is determined 55 based on the extension of ``filename``, but this can bug. 56 57 rd_kwargs 58 keyword arguments for the rendering, like {'fps':15, 'bitrate':'50k'} 59 60 61 **html_kwargs 62 Allow you to give some options, like width=260, autoplay=True, 63 loop=1 etc. 64 65 Examples 66 ========= 67 68 >>> import moviepy.editor as mpy 69 >>> # later ... 70 >>> clip.write_videofile("test.mp4") 71 >>> mpy.ipython_display("test.mp4", width=360) 72 73 >>> clip.audio.write_audiofile('test.ogg') # Sound ! 74 >>> mpy.ipython_display('test.ogg') 75 76 >>> clip.write_gif("test.gif") 77 >>> mpy.ipython_display('test.gif') 78 79 >>> clip.save_frame("first_frame.jpeg") 80 >>> mpy.ipython_display("first_frame.jpeg") 81 82 """ 83 84 if rd_kwargs is None: 85 rd_kwargs = {} 86 87 if "Clip" in str(clip.__class__): 88 TEMP_PREFIX = "__temp__" 89 if isinstance(clip,ImageClip): 90 filename = TEMP_PREFIX+".png" 91 kwargs = {'filename':filename, 'withmask':True} 92 kwargs.update(rd_kwargs) 93 clip.save_frame(**kwargs) 94 elif isinstance(clip,VideoClip): 95 filename = TEMP_PREFIX+".mp4" 96 kwargs = {'filename':filename, 'verbose':False, 'preset':'ultrafast'} 97 kwargs.update(rd_kwargs) 98 clip.write_videofile(**kwargs) 99 elif isinstance(clip,AudioClip): 100 filename = TEMP_PREFIX+".mp3" 101 kwargs = {'filename': filename, 'verbose':False} 102 kwargs.update(rd_kwargs) 103 clip.write_audiofile(**kwargs) 104 else: 105 raise ValueError("Unknown class for the clip. Cannot embed and preview.") 106 107 return html_embed(filename, maxduration=maxduration, rd_kwargs=rd_kwargs, 108 center=center, **html_kwargs) 109 110 filename = clip 111 options = " ".join(["%s='%s'"%(str(k), str(v)) for k,v in html_kwargs.items()]) 112 name, ext = os.path.splitext(filename) 113 ext = ext[1:] 114 115 if filetype is None: 116 ext = filename.split('.')[-1].lower() 117 if ext == "gif": 118 filetype = 'image' 119 elif ext in extensions_dict: 120 filetype = extensions_dict[ext]['type'] 121 else: 122 raise ValueError("No file type is known for the provided file. Please provide " 123 "argument `filetype` (one of 'image', 'video', 'sound') to the " 124 "ipython display function.") 125 126 127 if filetype== 'video': 128 # The next lines set the HTML5-cvompatible extension and check that the 129 # extension is HTML5-valid 130 exts_htmltype = {'mp4': 'mp4', 'webm':'webm', 'ogv':'ogg'} 131 allowed_exts = " ".join(exts_htmltype.keys()) 132 try: 133 ext = exts_htmltype[ext] 134 except: 135 raise ValueError("This video extension cannot be displayed in the " 136 "IPython Notebook. Allowed extensions: "+allowed_exts) 137 138 if filetype in ['audio', 'video']: 139 140 duration = ffmpeg_parse_infos(filename)['duration'] 141 if duration > maxduration: 142 raise ValueError("The duration of video %s (%.1f) exceeds the 'maxduration' "%(filename, duration)+ 143 "attribute. You can increase 'maxduration', by passing 'maxduration' parameter" 144 "to ipython_display function." 145 "But note that embedding large videos may take all the memory away !") 146 147 with open(filename, "rb") as f: 148 data= b64encode(f.read()).decode("utf-8") 149 150 template = templates[filetype] 151 152 result = template%{'data':data, 'options':options, 'ext':ext} 153 if center: 154 result = r"<div align=middle>%s</div>"%result 155 156 return result 157 158 159def ipython_display(clip, filetype=None, maxduration=60, t=None, fps=None, 160 rd_kwargs=None, center=True, **html_kwargs): 161 """ 162 clip 163 Either the name of a file, or a clip to preview. The clip will 164 actually be written to a file and embedded as if a filename was 165 provided. 166 167 filetype: 168 One of 'video','image','audio'. If None is given, it is determined 169 based on the extension of ``filename``, but this can bug. 170 171 maxduration 172 An error will be raised if the clip's duration is more than the indicated 173 value (in seconds), to avoid spoiling the browser's cache and the RAM. 174 175 t 176 If not None, only the frame at time t will be displayed in the notebook, 177 instead of a video of the clip 178 179 fps 180 Enables to specify an fps, as required for clips whose fps is unknown. 181 182 **kwargs: 183 Allow you to give some options, like width=260, etc. When editing 184 looping gifs, a good choice is loop=1, autoplay=1. 185 186 Remarks: If your browser doesn't support HTML5, this should warn you. 187 If nothing is displayed, maybe your file or filename is wrong. 188 Important: The media will be physically embedded in the notebook. 189 190 Examples 191 ========= 192 193 >>> import moviepy.editor as mpy 194 >>> # later ... 195 >>> clip.write_videofile("test.mp4") 196 >>> mpy.ipython_display("test.mp4", width=360) 197 198 >>> clip.audio.write_audiofile('test.ogg') # Sound ! 199 >>> mpy.ipython_display('test.ogg') 200 201 >>> clip.write_gif("test.gif") 202 >>> mpy.ipython_display('test.gif') 203 204 >>> clip.save_frame("first_frame.jpeg") 205 >>> mpy.ipython_display("first_frame.jpeg") 206 """ 207 208 if not ipython_available: 209 raise ImportError("Only works inside an IPython Notebook") 210 211 if rd_kwargs is None: 212 rd_kwargs = {} 213 214 if fps is not None: 215 rd_kwargs['fps'] = fps 216 217 if t is not None: 218 clip = clip.to_ImageClip(t) 219 220 return HTML2(html_embed(clip, filetype=filetype, maxduration=maxduration, 221 center=center, rd_kwargs=rd_kwargs, **html_kwargs)) 222