Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b1af052

Browse files
authored
Merge pull request #7208 from efiring/h264_default
API: change dflt animation codec to h264
2 parents 64cee30 + 53cf940 commit b1af052

File tree

4 files changed

+65
-36
lines changed

4 files changed

+65
-36
lines changed

doc/users/whats_new.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,18 @@ Support for HiDPI (Retina) displays in the NbAgg and WebAgg backends
216216
The NbAgg and WebAgg backends will now use the full resolution of your
217217
high-pixel-density display.
218218

219+
Change in the default animation codec
220+
-------------------------------------
221+
222+
The default animation codec has been changed from ``mpeg4`` to ``h264``,
223+
which is more efficient. It can be set via the ``animation.codec`` rcParam.
224+
225+
Deprecated support for mencoder in animation
226+
--------------------------------------------
227+
228+
The use of mencoder for writing video files with mpl is problematic;
229+
switching to ffmpeg is strongly advised. All support for mencoder
230+
will be removed in version 2.2.
219231

220232

221233
Previous Whats New

lib/matplotlib/animation.py

Lines changed: 51 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
import contextlib
3737
import tempfile
3838
import warnings
39-
from matplotlib.cbook import iterable, is_string_like
39+
from matplotlib.cbook import iterable, is_string_like, deprecated
4040
from matplotlib.compat import subprocess
4141
from matplotlib import verbose
4242
from matplotlib import rcParams, rcParamsDefault, rc_context
@@ -60,6 +60,12 @@
6060
# how-to-encode-series-of-images-into-h264-using-x264-api-c-c )
6161

6262

63+
def adjusted_figsize(w, h, dpi, n):
64+
wnew = int(w * dpi / n) * n / dpi
65+
hnew = int(h * dpi / n) * n / dpi
66+
return wnew, hnew
67+
68+
6369
# A registry for available MovieWriter classes
6470
class MovieWriterRegistry(object):
6571
def __init__(self):
@@ -134,10 +140,6 @@ class MovieWriter(object):
134140
The format used in writing frame data, defaults to 'rgba'
135141
'''
136142

137-
# Specifies whether the size of all frames need to be identical
138-
# i.e. whether we can use savefig.bbox = 'tight'
139-
frame_size_can_vary = False
140-
141143
def __init__(self, fps=5, codec=None, bitrate=None, extra_args=None,
142144
metadata=None):
143145
'''
@@ -189,8 +191,20 @@ def __init__(self, fps=5, codec=None, bitrate=None, extra_args=None,
189191
@property
190192
def frame_size(self):
191193
'A tuple (width,height) in pixels of a movie frame.'
192-
width_inches, height_inches = self.fig.get_size_inches()
193-
return width_inches * self.dpi, height_inches * self.dpi
194+
w, h = self.fig.get_size_inches()
195+
return int(w * self.dpi), int(h * self.dpi)
196+
197+
def _adjust_frame_size(self):
198+
if self.codec == 'h264':
199+
wo, ho = self.fig.get_size_inches()
200+
w, h = adjusted_figsize(wo, ho, self.dpi, 2)
201+
if not (wo, ho) == (w, h):
202+
self.fig.set_size_inches(w, h, forward=True)
203+
verbose.report('figure size (inches) has been adjusted '
204+
'from %s x %s to %s x %s' % (wo, ho, w, h),
205+
level='helpful')
206+
verbose.report('frame size in pixels is %s x %s' % self.frame_size,
207+
level='debug')
194208

195209
def setup(self, fig, outfile, dpi):
196210
'''
@@ -207,6 +221,7 @@ def setup(self, fig, outfile, dpi):
207221
self.outfile = outfile
208222
self.fig = fig
209223
self.dpi = dpi
224+
self._adjust_frame_size()
210225

211226
# Run here so that grab_frame() can write the data to a pipe. This
212227
# eliminates the need for temp files.
@@ -316,10 +331,6 @@ def isAvailable(cls):
316331
class FileMovieWriter(MovieWriter):
317332
'`MovieWriter` subclass that handles writing to a file.'
318333

319-
# In general, if frames are writen to files on disk, it's not important
320-
# that they all be identically sized
321-
frame_size_can_vary = True
322-
323334
def __init__(self, *args, **kwargs):
324335
MovieWriter.__init__(self, *args, **kwargs)
325336
self.frame_format = rcParams['animation.frame_format']
@@ -345,6 +356,8 @@ def setup(self, fig, outfile, dpi, frame_prefix='_tmp', clear_temp=True):
345356
self.fig = fig
346357
self.outfile = outfile
347358
self.dpi = dpi
359+
self._adjust_frame_size()
360+
348361
self.clear_temp = clear_temp
349362
self.temp_prefix = frame_prefix
350363
self._frame_counter = 0 # used for generating sequential file names
@@ -500,7 +513,7 @@ class FFMpegFileWriter(FileMovieWriter, FFMpegBase):
500513
def _args(self):
501514
# Returns the command line parameters for subprocess to use
502515
# ffmpeg to create a movie using a collection of temp images
503-
return [self.bin_path(), '-r', str(self.fps),
516+
return [self.bin_path(), # -r option is not needed before -i option
504517
'-i', self._base_temp_name(),
505518
'-vframes', str(self._frame_counter),
506519
'-r', str(self.fps)] + self.output_args
@@ -560,9 +573,20 @@ def output_args(self):
560573
return args
561574

562575

563-
# Combine Mencoder options with pipe-based writing
576+
# The message must be a single line; internal newlines cause sphinx failure.
577+
mencoder_dep = ("Support for mencoder is only partially functional, "
578+
"and will be removed entirely in 2.2. "
579+
"Please use ffmpeg instead.")
580+
581+
564582
@writers.register('mencoder')
565583
class MencoderWriter(MovieWriter, MencoderBase):
584+
585+
@deprecated('2.0', message=mencoder_dep)
586+
def __init__(self, *args, **kwargs):
587+
with rc_context(rc={'animation.codec': 'mpeg4'}):
588+
super(MencoderWriter, self).__init__(*args, **kwargs)
589+
566590
def _args(self):
567591
# Returns the command line parameters for subprocess to use
568592
# mencoder to create a movie
@@ -577,6 +601,11 @@ def _args(self):
577601
class MencoderFileWriter(FileMovieWriter, MencoderBase):
578602
supported_formats = ['png', 'jpeg', 'tga', 'sgi']
579603

604+
@deprecated('2.0', message=mencoder_dep)
605+
def __init__(self, *args, **kwargs):
606+
with rc_context(rc={'animation.codec': 'mpeg4'}):
607+
super(MencoderFileWriter, self).__init__(*args, **kwargs)
608+
580609
def _args(self):
581610
# Returns the command line parameters for subprocess to use
582611
# mencoder to create a movie
@@ -788,7 +817,7 @@ def save(self, filename, writer=None, fps=None, dpi=None, codec=None,
788817
elif (not is_string_like(writer) and
789818
any(arg is not None
790819
for arg in (fps, codec, bitrate, extra_args, metadata))):
791-
raise RuntimeError('Passing in values for arguments for arguments '
820+
raise RuntimeError('Passing in values for arguments '
792821
'fps, codec, bitrate, extra_args, or metadata '
793822
'is not supported when writer is an existing '
794823
'MovieWriter instance. These should instead be '
@@ -844,26 +873,16 @@ def save(self, filename, writer=None, fps=None, dpi=None, codec=None,
844873
metadata=metadata)
845874
except IndexError:
846875
raise ValueError("Cannot save animation: no writers are "
847-
"available. Please install mencoder or "
876+
"available. Please install "
848877
"ffmpeg to save animations.")
849878

850879
verbose.report('Animation.save using %s' % type(writer),
851880
level='helpful')
852881

853-
# FIXME: Using 'bbox_inches' doesn't currently work with
854-
# writers that pipe the data to the command because this
855-
# requires a fixed frame size (see Ryan May's reply in this
856-
# thread: [1]). Thus we drop the 'bbox_inches' argument if it
857-
# exists in savefig_kwargs.
858-
#
859-
# [1] (http://matplotlib.1069221.n5.nabble.com/
860-
# Animation-class-let-save-accept-kwargs-which-
861-
# are-passed-on-to-savefig-td39627.html)
862-
#
863-
if 'bbox_inches' in savefig_kwargs and not writer.frame_size_can_vary:
882+
if 'bbox_inches' in savefig_kwargs:
864883
warnings.warn("Warning: discarding the 'bbox_inches' argument in "
865-
"'savefig_kwargs' as it not supported by "
866-
"{0}).".format(writer.__class__.__name__))
884+
"'savefig_kwargs' as it may cause frame size "
885+
"to vary, which is inappropriate for animation.")
867886
savefig_kwargs.pop('bbox_inches')
868887

869888
# Create a new sequence of frames for saved data. This is different
@@ -873,12 +892,10 @@ def save(self, filename, writer=None, fps=None, dpi=None, codec=None,
873892
# since GUI widgets are gone. Either need to remove extra code to
874893
# allow for this non-existent use case or find a way to make it work.
875894
with rc_context():
876-
# See above about bbox_inches savefig kwarg
877-
if (not writer.frame_size_can_vary and
878-
rcParams['savefig.bbox'] == 'tight'):
879-
verbose.report("Disabling savefig.bbox = 'tight', as it is "
880-
"not supported by "
881-
"{0}.".format(writer.__class__.__name__),
895+
if (rcParams['savefig.bbox'] == 'tight'):
896+
verbose.report("Disabling savefig.bbox = 'tight', as it "
897+
"may cause frame size to vary, which "
898+
"is inappropriate for animation.",
882899
level='helpful')
883900
rcParams['savefig.bbox'] = None
884901
with writer.saving(self._fig, filename, dpi):

lib/matplotlib/rcsetup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1324,7 +1324,7 @@ def validate_animation_writer_path(p):
13241324
# Animation settings
13251325
'animation.html': ['none', validate_movie_html_fmt],
13261326
'animation.writer': ['ffmpeg', validate_movie_writer],
1327-
'animation.codec': ['mpeg4', six.text_type],
1327+
'animation.codec': ['h264', six.text_type],
13281328
'animation.bitrate': [-1, validate_int],
13291329
# Controls image format when frames are written to disk
13301330
'animation.frame_format': ['png', validate_movie_frame_fmt],

matplotlibrc.template

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -597,7 +597,7 @@ backend : $TEMPLATE_BACKEND
597597
# the IPython notebook. 'html5' uses
598598
# HTML5 video tag.
599599
#animation.writer : ffmpeg # MovieWriter 'backend' to use
600-
#animation.codec : mpeg4 # Codec to use for writing movie
600+
#animation.codec : h264 # Codec to use for writing movie
601601
#animation.bitrate: -1 # Controls size/quality tradeoff for movie.
602602
# -1 implies let utility auto-determine
603603
#animation.frame_format: 'png' # Controls frame format used by temp files

0 commit comments

Comments
 (0)