Skip to content
This repository has been archived by the owner on Mar 9, 2024. It is now read-only.

Commit

Permalink
Port to ffmpeg
Browse files Browse the repository at this point in the history
Improve error messages
  • Loading branch information
mre committed Jan 9, 2018
1 parent dc7247c commit 0b43515
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 59 deletions.
64 changes: 15 additions & 49 deletions encoder.py
Original file line number Diff line number Diff line change
@@ -1,75 +1,41 @@
import datetime # Filename
from threading import Thread # Encoder is a thread
import subprocess # System call
import os
import subprocess

not_found_msg = """
The ffmpeg command was not found;
ffmpeg is used by this script to make an avi file from a set of pngs.
ffmpeg is used by this script to make a video file from a set of pngs.
It is typically not installed by default distros , but it is widely available.
On macOS, try running `brew install ffmpeg`.
"""


class Encoder(Thread):
"""Create a video file from images"""

def __init__(self, output_dir):
def __init__(self, input_dir, output_dir):
# Initialize the thread
Thread.__init__(self)

# Set config options
self.output_dir = output_dir
self.input = "{}/*.png".format(input_dir)
self.output = "{}/output.mp4".format(output_dir)

self.checkLibrary()
print("Encoder started")

def join(self, timeout=None):
""" Hard shutdown """
Thread.join(self)

def run(self):
""" Render video """

def checkLibrary(self):
try:
subprocess.check_call(['ffmpeg'])
except subprocess.CalledProcessError:
print "ffmpeg command was found"
pass # ffmpeg is found, but returns non-zero exit as expected
# This is a quick and dirty check; it leaves some spurious output
# for the user to puzzle over.
except OSError:
print not_found_msg

# Now that we have graphed images of the dataset, we will stitch them
# together using Mencoder to create a movie. Each image will become
# a single frame in the movie.
#
# We want to use Python to make what would normally be a command line
# call to Mencoder. Specifically, the command line call we want to
# emulate is (without the initial '#'):
# mencoder mf://*.png -mf type=png:w=800:h=600:fps=25 -ovc lavc -lavcopts vcodec=mpeg4 -oac copy -o output.avi
# See the MPlayer and Mencoder documentation for details.
#

command = ('mencoder',
'mf://*.png',
'-mf',
'type=png:w=800:h=600:fps=25',
'-ovc',
'lavc',
'-lavcopts',
'vcodec=mpeg4',
'-oac',
'copy',
'-o',
'output.avi')

# os.spawnvp(os.P_WAIT, 'mencoder', command)
"""
Now that we have graphed images of the dataset, we will stitch them
together using ffmpeg to create a movie. Each image will become
a single frame in the movie.
"""
command = (
"ffmpeg", "-framerate", "30", "-pattern_type", "glob", "-i", self.input, self.output
)

print "\n\nabout to execute:\n%s\n\n" % ' '.join(command)
subprocess.check_call(command)

print "\n\n The movie was written to 'output.avi'"

print "\n\n You may want to delete *.png now.\n\n"
print "\n\n The movie was saved to `{}`".format(self.output)
38 changes: 28 additions & 10 deletions timelapse.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import os # For directory traversing
import time # To create subdirectories
import os
import time
import subprocess

from PyObjCTools import AppHelper
from AppKit import *

from encoder import Encoder # Creates timelapse video
from recorder import Recorder # Takes screenshots
Expand Down Expand Up @@ -32,13 +34,17 @@ class Timelapse(NSObject):
""" Creates a timelapse video """

def applicationDidFinishLaunching_(self, notification):
self.check_dependencies()

# Initialize recording
self.recording = start_recording

# Set correct output paths
self.recorder_output_basedir = os.path.join(dir_base, dir_pictures, dir_app)
self.encoder_output_basedir = os.path.join(dir_base, dir_movies)

self.image_dir = self.create_dir(self.recorder_output_basedir)

# Create a reference to the statusbar (menubar)
self.statusbar = NSStatusBar.systemStatusBar()

Expand Down Expand Up @@ -86,33 +92,34 @@ def startStopRecording_(self, notification):
self.recorder.join()
# Create timelapse after recording?
if encode:
self.encoder = Encoder(self.encoder_output_basedir)
self.encoder = Encoder(self.image_dir, self.encoder_output_basedir)
self.encoder.start()
else:
output_dir = self.createDir(self.recorder_output_basedir)
self.recorder = Recorder(output_dir, screenshot_interval)
self.recorder = Recorder(self.image_dir, screenshot_interval)
self.recorder.start()
self.recording = not self.recording
self.setStatus()

def createDir(self, base_dir):
@objc.python_method
def create_dir(self, base_dir):
""" Creates a specified directory and the path to it if necessary """
if create_session_subdir:
# Create a new subdirectory
output_dir = os.path.join(base_dir, self.getSubDir(base_dir))
output_dir = os.path.join(base_dir, self.get_sub_dir(base_dir))
else:
# Don't create a subdirectory. Use base directory for output
output_dir = base_dir
# Create path if it doesn't exist
try:
print(output_dir)
os.makedirs(output_dir)
except OSError:
print("oops")
except OSError, e:
print("Error while creating directory:", e)
exit()
return output_dir

def getSubDir(self, base_dir):
@objc.python_method
def get_sub_dir(self, base_dir):
""" Returns the next nonexistend subdirectory to base_dir """
subdir_base = os.path.join(base_dir, subdir_suffix)
# Check if we can use subdir without any session id
Expand All @@ -125,6 +132,17 @@ def getSubDir(self, base_dir):
subdir = subdir_base + "-" + str(session_number)
return subdir

def check_dependencies(self):
try:
subprocess.check_call(['ffmpeg'])
except subprocess.CalledProcessError:
print "ffmpeg command was found"
pass # ffmpeg is found, but returns non-zero exit as expected
# This is a quick and dirty check; it leaves some spurious output
# for the user to puzzle over.
except OSError:
print not_found_msg


if __name__ == "__main__":
app = NSApplication.sharedApplication()
Expand Down

0 comments on commit 0b43515

Please sign in to comment.