#!/usr/bin/env python
"""
Python script (C) 2011 by Laxap
(http://www.instructables.com/member/laxap/)

Takes one or more movies as argument, and converts each one to a
panorama picture. The movies are meant to be shot using a slowly
rotating mount (approx 2 minutes / round) shot in portrait
orientation. Works for MJPEG encoding.

See:
http://www.instructables.com/id/No-Stitch-Panorama-Picture/
"""
import subprocess
import tempfile
import shutil
import os
import glob
import sys

ROTATE = 90    # 0: landscape, 90: portrait -- acc. to camera orientation. 
RATIO  = "80%" # acc. to lense aperture and rotation speed
MIRROR = True  # 0 or 1 -- acc. to camera and rotation direction

def execute(cmd, comment=None):
    if comment:
        print comment,
        sys.stdout.flush()
    #print "==>", cmd
    retcode = subprocess.call(cmd) #, shell=True)
    if retcode==0:
        return
    else:
        print >>sys.stderr, "Child returned", retcode
        raise RuntimeError

def movie_to_pic(tmpdir, src, dest, rotation, ratio, mirror):
    # movie to frames
    execute(["ffmpeg", "-i", src, "-vcodec", "copy", "-vbsf", "mjpeg2jpeg",
             os.path.join(tmpdir, "frame_%06d.png")],
            "= %s: Extracting frames from movie =\n" % src)
    print 

    # extract a 1 pixel thin strip of each slice
    print "= %s: Slicing frames in strips, resizing to %s =" % (src, ratio)
    for frame in sorted(glob.glob(os.path.join(tmpdir, "frame_*.png"))):
        execute(["convert", frame, "-crop", "0x1+0+0",
                 "-rotate", str(rotation), "-resize", "100%%x%s" % ratio,
                 os.path.join(tmpdir, "strip_"+os.path.split(frame)[-1])],
                "Slicing frame %s\r" % frame)
    print; print

    # stitch strips into bands of 200 pixels
    print "= %s: Stitching =" % (src)
    strips = sorted(glob.glob(os.path.join(tmpdir, "strip_*.png")))
    nb = 0
    while strips:
        nb += 1
        band, strips = strips[:200], strips[200:]
        cmd = ["convert"] + band + ["+append"]
        cmd += [os.path.join(tmpdir, "band_%06d.png" % nb)]
        execute(cmd, "Making band %d\r" % nb)
    print

    # stitch bands into final pic
    bands = sorted(glob.glob(os.path.join(tmpdir, "band_*.png")))
    cmd = ["convert"] + bands + ["+append"]
    if mirror:
        cmd += ["-flop"]
    cmd += [dest]
    execute(cmd, "Stitching bands together\n")
    print "Done: ", dest

tmpdir = tempfile.mkdtemp()
try:
    for src in sys.argv[1:]:
        dst = os.path.splitext(src)[0] + "-panorama.png"
        movie_to_pic(tmpdir, src, dst, ROTATE, RATIO, MIRROR)
except RuntimeError:
    pass
finally:
    print "(Cleanup %s)" % tmpdir
    shutil.rmtree(tmpdir)

#end
