Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I properly enable ffmpeg for matplotlib.animation?

I have covered a lot of ground on stack so far trying to get ffmpeg going so I can make a timelapse video.

I am on a CentOS 7 machine, running python3.7.0a0.

python3
>>> import numpy as np
>>> np.__version__
'1.12.0'
>>> import matplotlib as mpl
>>> mpl.__version__
'2.0.0'
>>> import mpl_toolkits.basemap as base
>>> base.__version__
'1.0.7'

I found this github gist on installing ffmpeg. I used the chromium source, and installed without a prefix option (using the default).

I have confirmed that ffmpeg is installed, although I don't know anything about testing whether it works.

which ffmpeg
/usr/local/bin/ffmpeg

ffmpeg -version
ffmpeg version N-83533-gada281d Copyright (c) 2000-2017 the FFmpeg dev elopers
built with gcc 4.8.5 (GCC) 20150623 (Red Hat 4.8.5-11
configuration:
libavutil      55. 47.100 / 55. 47.100
libavcodec     57. 80.100 / 57. 80.100
libavformat    57. 66.102 / 57. 66.102
libavdevice    57.  2.100 / 57.  2.100
libavfilter     6. 73.100 /  6. 73.100
libswscale      4.  3.101 /  4.  3.101
libswresample   2.  4.100 /  2.  4.100

I tried to run a few sample examples I found online:

[1] http://matplotlib.org/examples/animation/basic_example_writer.html

[2] https://stackoverflow.com/a/23098090/3454650

Everything works fine up until I try to save the animation file.

[1]

 anim.save('basic_animation.mp4', writer = FFwriter, fps=30, extra_args=['-vcodec', 'libx264'])

[2]

im_ani.save('im.mp4', writer=writer)

I found here that explictly setting the path to ffmpeg might be necessary so I added this to the top of the test scripts:

plt.rcParams['animation.ffmpeg_path'] = '/usr/local/bin/ffmpeg'

I tried a few more tweaks in the code but always get the same response, which I do not know how to begin deciphering:

Traceback (most recent call last):
  File "testanim.py", line 27, in <module>
    writer.grab_frame()
  File "/usr/local/lib/python3.7/contextlib.py", line 100, in __exit__
    self.gen.throw(type, value, traceback)
  File "/usr/local/lib/python3.7/site-packages/matplotlib/animation.py", line 256, in saving
    self.finish()
  File "/usr/local/lib/python3.7/site-packages/matplotlib/animation.py", line 276, in finish
    self.cleanup()
  File "/usr/local/lib/python3.7/site-packages/matplotlib/animation.py", line 311, in cleanup
    out, err = self._proc.communicate()
  File "/usr/local/lib/python3.7/subprocess.py", line 836, in communicate
    stdout, stderr = self._communicate(input, endtime, timeout)
  File "/usr/local/lib/python3.7/subprocess.py", line 1474, in _communicate
    selector.register(self.stdout, selectors.EVENT_READ)
  File "/usr/local/lib/python3.7/selectors.py", line 351, in register
    key = super().register(fileobj, events, data)
  File "/usr/local/lib/python3.7/selectors.py", line 237, in register
    key = SelectorKey(fileobj, self._fileobj_lookup(fileobj), events, data)
  File "/usr/local/lib/python3.7/selectors.py", line 224, in _fileobj_lookup
    return _fileobj_to_fd(fileobj)
  File "/usr/local/lib/python3.7/selectors.py", line 39, in _fileobj_to_fd
    "{!r}".format(fileobj)) from None
ValueError: Invalid file object: <_io.BufferedReader name=6>

Is there something with my configuration that is malformed? I searched google for this error for some time but never found anything relevant to animations / ffmpeg. Any help would be greatly appreciated.


UPDATE:

@LordNeckBeard pointed me here: https://trac.ffmpeg.org/wiki/CompilationGuide/Centos

I ran into problems with installing the x264 encoding dependency. Some files in libavcodec/*.c (in the make output) were reporting undefined references to several functions. After a wild goose chase found this: https://mailman.videolan.org/pipermail/x264-devel/2015-February/010971.html

To fix the x264 installation, I simply added some configure flags:

./configure --enable-static --enable-shared --extra-ldflags="-lswresample -llzma"

UPDATE:

So everything installed fine after fixing the libx264 problems. I went ahead and copied the ffmpeg binary from the ffmpeg_build folder into /usr/local/bin/ffmpeg.

After running the script I was getting problems where ffmpeg could not find the libx264 shared object. I think I will have to recompile everything using different prefixes. My intuition tells me there are old files laying around after I have messed with everything, using some configuration that is broken.

So I decided maybe I should just try to use NUX: http://linoxide.com/linux-how-to/install-ffmpeg-centos-7/ I installed ffmpeg using the new rpm, but to no avail. I still was not able to run ffmpeg because of a missing shared object.

Finally, instead of usiong files copied into my /usr/local/bin folder, I ran ffmpeg directly from the build bin directory. Turns out that this does work properly!

So in essence, if I want to install ffmpeg system wide, I need to manually compile from sources again but using a nonlocal prefix.

like image 401
spanishgum Avatar asked Mar 06 '17 20:03

spanishgum


People also ask

How do you plot an animation in Python?

Plotting our Animation We start by creating our figure object with three-dimensional axes. We then use FuncAnimation, which takes the figure, our animation function created earlier, an interval value, and a frames value as inputs.

How do I save an animation in Python?

To save an animation, we can use Animation. save() or Animation. to_html5_video().


3 Answers

I had this same issue using Anaconda. Running which ffmpeg showed that it was using the ffmpeg inside the Anaconda path instead of the system's binary. I fixed this by adding

plt.rcParams['animation.ffmpeg_path'] = '/usr/bin/ffmpeg'

immediately after my matplotlib import.

like image 139
crypdick Avatar answered Oct 17 '22 08:10

crypdick


I see no ffmpeg specific info in the output you provided; however you are attempting to use libx264, but your ffmpeg configure is missing --enable-gpl --enable-libx264 which are required to enable encoding with this encoder. You can download a ffmpeg binary for Linux, macOS, or Windows that does support libx264 then point your script to it.

Alternatively, compile ffmpeg using the mentioned configure options.

like image 40
llogan Avatar answered Oct 17 '22 07:10

llogan


I had a similar error and I found a solution in the comments of this matplotlib GitHub Issue:

My code was

WriterClass = animation.writers['ffmpeg']
writer = WriterClass(fps=10, metadata=dict(artist='bww'), bitrate=1800)
anim.save('../../data/media/' + name + '.mp4', writer=writer)

(Here anim is just an animation.FuncAnimation(...) with some settings)

I fixed it by using writer = animation.FFMpegFileWriter(...) instead of WriterClass (same arguments).

like image 26
kilgoretrout Avatar answered Oct 17 '22 06:10

kilgoretrout