Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

set close_fds to false for windows #59

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 44 additions & 13 deletions converter/ffmpeg.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
import os.path
import os
import re
import signal
from subprocess import Popen, PIPE
from threading import Event, Lock, Thread
from time import monotonic # use time.time or monotonic.monotonic on Python 2
import logging
import locale

Expand All @@ -13,6 +14,39 @@
console_encoding = locale.getdefaultlocale()[1] or 'UTF-8'


class WatchdogTimer(Thread):
"""Run *callback* in *timeout* seconds unless the timer is restarted.

http://stackoverflow.com/a/34115590
"""

def __init__(self, timeout, callback, *args, timer=monotonic, **kwargs):
super().__init__(**kwargs)
self.timeout = timeout
self.callback = callback
self.args = args
self.timer = timer
self.cancelled = Event()
self.blocked = Lock()

def run(self):
self.restart() # don't start timer until `.start()` is called
# wait until timeout happens or the timer is canceled
while not self.cancelled.wait(self.deadline - self.timer()):
# don't test the timeout while something else holds the lock
# allow the timer to be restarted while blocked
with self.blocked:
if self.deadline <= self.timer(): # timeout
return self.callback(*self.args)

def restart(self):
"""Restart the watchdog timer."""
self.deadline = self.timer() + self.timeout

def cancel(self):
self.cancelled.set()


class FFMpegError(Exception):
pass

Expand Down Expand Up @@ -350,8 +384,9 @@ def which(name):
@staticmethod
def _spawn(cmds):
logger.debug('Spawning ffmpeg with command: ' + ' '.join(cmds))
close_fds = False if os.name == 'nt' else True
return Popen(cmds, shell=False, stdin=PIPE, stdout=PIPE, stderr=PIPE,
close_fds=True)
close_fds=close_fds)

def probe(self, fname, posters_as_video=True):
"""
Expand Down Expand Up @@ -422,13 +457,6 @@ def convert(self, infile, outfile, opts, timeout=10):
cmds.extend(opts)
cmds.extend(['-y', outfile])

if timeout:
def on_sigalrm(*_):
signal.signal(signal.SIGALRM, signal.SIG_DFL)
raise Exception('timed out while waiting for ffmpeg')

signal.signal(signal.SIGALRM, on_sigalrm)

try:
p = self._spawn(cmds)
except OSError:
Expand All @@ -438,14 +466,17 @@ def on_sigalrm(*_):
buf = ''
total_output = ''
pat = re.compile(r'time=([0-9.:]+) ')

watchdog = WatchdogTimer(timeout, callback=p.kill, daemon=True)
if timeout:
watchdog.start()

while True:
if timeout:
signal.alarm(timeout)

ret = p.stderr.read(10)

if timeout:
signal.alarm(0)
watchdog.restart()

if not ret:
break
Expand All @@ -469,7 +500,7 @@ def on_sigalrm(*_):
yield timecode

if timeout:
signal.signal(signal.SIGALRM, signal.SIG_DFL)
watchdog.cancel()

p.communicate() # wait for process to exit

Expand Down