# Source code for imaging.images2avi

    #   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

Help Index | Topics Index | Keywords Index | Full Index

© 2003-2023 GRASS Development Team, GRASS GIS 8.3.0dev Reference Manual