123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194 |
- # Copyright (C) 2012, Almar Klein
- # All rights reserved.
- #
- # This code is subject to the (new) BSD license:
- #
- # Redistribution and use in source and binary forms, with or without
- # modification, are permitted provided that the following conditions are met:
- # * Redistributions of source code must retain the above copyright
- # notice, this list of conditions and the following disclaimer.
- # * Redistributions in binary form must reproduce the above copyright
- # notice, this list of conditions and the following disclaimer in the
- # documentation and/or other materials provided with the distribution.
- # * Neither the name of the <organization> nor the
- # names of its contributors may be used to endorse or promote products
- # derived from this software without specific prior written permission.
- #
- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- # ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
- # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- #
- #
- # changes of this file GRASS (PNG instead of JPG) by Anna Petrasova 2013
- """ Module images2avi
- Uses ffmpeg to read and write AVI files. Requires PIL
- I found these sites useful:
- http://www.catswhocode.com/blog/19-ffmpeg-commands-for-all-needs
- http://linux.die.net/man/1/ffmpeg
- """
- import os
- import time
- import subprocess
- import shutil
- from grass.imaging import images2ims
- import grass.script as gscript
- def _cleanDir(tempDir):
- for i in range(3):
- try:
- shutil.rmtree(tempDir)
- except Exception:
- time.sleep(0.2) # Give OS time to free sources
- else:
- break
- else:
- print("Oops, could not fully clean up temporary files.")
- def writeAvi(filename, images, duration=0.1, encoding='mpeg4',
- inputOptions='', outputOptions='', bg_task=False):
- """Export movie to a AVI file, which is encoded with the given
- encoding. Hint for Windows users: the 'msmpeg4v2' codec is
- natively supported on Windows.
- Images should be a list consisting of PIL images or numpy arrays.
- The latter should be between 0 and 255 for integer types, and
- between 0 and 1 for float types.
- Requires the "ffmpeg" application:
- * Most linux users can install using their package manager
- * There is a windows installer on the visvis website
- :param str filename: output filename
- :param images:
- :param float duration:
- :param str encoding: the encoding type
- :param inputOptions:
- :param outputOptions:
- :param bool bg_task: if thread background task, not raise but
- return error message
- :return str: error message
- """
- # Get fps
- try:
- fps = float(1.0 / duration)
- except Exception:
- raise ValueError(_('Invalid duration parameter for writeAvi.'))
- # Determine temp dir and create images
- tempDir = os.path.join(os.path.expanduser('~'), '.tempIms')
- images2ims.writeIms(os.path.join(tempDir, 'im*.png'), images)
- # Determine formatter
- N = len(images)
- formatter = '%04d'
- if N < 10:
- formatter = '%d'
- elif N < 100:
- formatter = '%02d'
- elif N < 1000:
- formatter = '%03d'
- # Compile command to create avi
- command = "ffmpeg -r %i %s " % (int(fps), inputOptions)
- command += "-i im%s.png " % (formatter,)
- command += "-g 1 -vcodec %s %s " % (encoding, outputOptions)
- command += "output.avi"
- # Run ffmpeg
- S = subprocess.Popen(command, shell=True, cwd=tempDir,
- stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- # Show what ffmpeg has to say
- outPut = S.stdout.read()
- if S.wait():
- # Clean up
- _cleanDir(tempDir)
- if bg_task:
- return gscript.decode(outPut) + '\n' + gscript.decode(
- S.stderr.read()) + '\n' + _('Could not write avi.')
- else:
- # An error occurred, show
- print(gscript.decode(outPut))
- print(gscript.decode(S.stderr.read()))
- raise RuntimeError(_('Could not write avi.'))
- else:
- try:
- # Copy avi
- shutil.copy(os.path.join(tempDir, 'output.avi'), filename)
- except Exception as err:
- # Clean up
- _cleanDir(tempDir)
- if bg_task:
- return str(err)
- else:
- raise
- # Clean up
- _cleanDir(tempDir)
- def readAvi(filename, asNumpy=True):
- """Read images from an AVI (or MPG) movie.
- Requires the "ffmpeg" application:
- * Most linux users can install using their package manager
- * There is a windows installer on the visvis website
- :param str filename: name of input movie file
- :param bool asNumpy:
- """
- # Check whether it exists
- if not os.path.isfile(filename):
- raise IOError('File not found: '+str(filename))
- # Determine temp dir, make sure it exists
- tempDir = os.path.join(os.path.expanduser('~'), '.tempIms')
- if not os.path.isdir(tempDir):
- os.makedirs(tempDir)
- # Copy movie there
- shutil.copy(filename, os.path.join(tempDir, 'input.avi'))
- # Run ffmpeg
- command = "ffmpeg -i input.avi im%d.jpg"
- S = subprocess.Popen(command, shell=True, cwd=tempDir,
- stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- # Show what mencodec has to say
- outPut = S.stdout.read()
- if S.wait():
- # An error occurred, show
- print(outPut)
- print(S.stderr.read())
- # Clean up
- _cleanDir(tempDir)
- raise RuntimeError("Could not read avi.")
- else:
- # Read images
- images = images2ims.readIms(os.path.join(tempDir, 'im*.jpg'), asNumpy)
- # Clean up
- _cleanDir(tempDir)
- # Done
- return images
|