|
23 | 23 | from matplotlib.externals import six
|
24 | 24 | from matplotlib.externals.six.moves import xrange, zip
|
25 | 25 |
|
| 26 | +import os |
26 | 27 | import platform
|
27 | 28 | import sys
|
28 | 29 | import itertools
|
| 30 | +import base64 |
29 | 31 | import contextlib
|
| 32 | +import tempfile |
30 | 33 | from matplotlib.cbook import iterable, is_string_like
|
31 | 34 | from matplotlib.compat import subprocess
|
32 | 35 | from matplotlib import verbose
|
@@ -383,7 +386,6 @@ def cleanup(self):
|
383 | 386 |
|
384 | 387 | # Delete temporary files
|
385 | 388 | if self.clear_temp:
|
386 |
| - import os |
387 | 389 | verbose.report(
|
388 | 390 | 'MovieWriter: clearing temporary fnames=%s' %
|
389 | 391 | str(self._temp_names),
|
@@ -885,6 +887,59 @@ def _end_redraw(self, evt):
|
885 | 887 | self._resize_id = self._fig.canvas.mpl_connect('resize_event',
|
886 | 888 | self._handle_resize)
|
887 | 889 |
|
| 890 | + def to_html5_video(self): |
| 891 | + r'''Returns animation as an HTML5 video tag. |
| 892 | +
|
| 893 | + This saves the animation as an h264 video, encoded in base64 |
| 894 | + directly into the HTML5 video tag. This respects the rc parameters |
| 895 | + for the writer as well as the bitrate. This also makes use of the |
| 896 | + ``interval`` to control the speed, and uses the ``repeat`` |
| 897 | + paramter to decide whether to loop. |
| 898 | + ''' |
| 899 | + VIDEO_TAG = r'''<video {size} {options}> |
| 900 | + <source type="video/mp4" src="data:video/mp4;base64,{video}"> |
| 901 | + Your browser does not support the video tag. |
| 902 | +</video>''' |
| 903 | + # Cache the the rendering of the video as HTML |
| 904 | + if not hasattr(self, '_base64_video'): |
| 905 | + # First write the video to a tempfile. Set delete to False |
| 906 | + # so we can re-open to read binary data. |
| 907 | + with tempfile.NamedTemporaryFile(suffix='.m4v', |
| 908 | + delete=False) as f: |
| 909 | + # We create a writer manually so that we can get the |
| 910 | + # appropriate size for the tag |
| 911 | + Writer = writers[rcParams['animation.writer']] |
| 912 | + writer = Writer(codec='h264', |
| 913 | + bitrate=rcParams['animation.bitrate'], |
| 914 | + fps=1000. / self._interval) |
| 915 | + self.save(f.name, writer=writer) |
| 916 | + |
| 917 | + # Now open and base64 encode |
| 918 | + with open(f.name, 'rb') as video: |
| 919 | + vid64 = base64.encodebytes(video.read()) |
| 920 | + self._base64_video = vid64.decode('ascii') |
| 921 | + self._video_size = 'width="{0}" height="{1}"'.format( |
| 922 | + *writer.frame_size) |
| 923 | + |
| 924 | + # Now we can remove |
| 925 | + os.remove(f.name) |
| 926 | + |
| 927 | + # Default HTML5 options are to autoplay and to display video controls |
| 928 | + options = ['controls', 'autoplay'] |
| 929 | + |
| 930 | + # If we're set to repeat, make it loop |
| 931 | + if self.repeat: |
| 932 | + options.append('loop') |
| 933 | + return VIDEO_TAG.format(video=self._base64_video, |
| 934 | + size=self._video_size, |
| 935 | + options=' '.join(options)) |
| 936 | + |
| 937 | + def _repr_html_(self): |
| 938 | + r'IPython display hook for rendering.' |
| 939 | + fmt = rcParams['animation.html'] |
| 940 | + if fmt == 'html5': |
| 941 | + return self.to_html5_video() |
| 942 | + |
888 | 943 |
|
889 | 944 | class TimedAnimation(Animation):
|
890 | 945 | '''
|
|
0 commit comments