Hi,
ich bin momentan dabei ein kleines tool zu basteln, welches mir alle x Minuten einen Ordner scannt und dann gegebenenfalls die Daten weiterverarbeitet.
dazu nutze ich https://github.com/senko/python-video-converter und APscheduler um den Thread zu starten.
allerdings habe ich nun das Problem, dass der video converter Popen nutzt um ffprobe/ffmpeg aufzurufen, das funktioniert auch alles wunderbar, aber sobald ich das ganze per APscheduler aufrufe bleibt der Thread 'hängen' und zwar beim ausfürhren von ffprobe, es sieht so aus als würde der Thread nicht mitbekommen dass der subprocess erfolgreich terminiert/ausgeführt wurde. Sobald der Thread 'hängt' und ich ctr + c drücke, merkt er das auch, springt dann quasi zum ende, und macht mit ffmpeg weiter...
da das ganze ja aber möglichst automatisch laufen würde wäre es natürlich klasse wenn das ganze selbstständig raus finden würde dass der subprocess beendet wurde und Daten zur Verarbeitung vorliegen.
gibt es da vielleicht ne einfache Möglichkeit auf die ich einfach nur nicht komme gerade?
Es kommt mir irgendwie so vor als würde der exit status code von ffprobe/ffmpeg einfach nicht beim thread ankommen...
bin für jede Hilfe dankbar
Subprocess.Popen in threads
ich weis nicht genau was davon ihr sehen wollt/müsst hier mal einige code ausschnitte....
der abschnitt in dem die convertierung aufgerufen wird...
c.converter() ruft dann erst einmal ffprobe auf um die stream infos zu bekommen und im anschluss convert... hier der auszug aus der FFMpeg Klasse:
ich hoffe das waren/sind die relevanten code stellen, ich lass mal nen link zu bitbucket da, dort kann gegebenenfalls der komplette code eingesehen werden.
https://bitbucket.org/raphaelmutschler/pyencoder/src
der abschnitt in dem die convertierung aufgerufen wird...
Code: Alles auswählen
from apscheduler.scheduler import Scheduler
from converter import Converter
#start the scheduler
sched = Scheduler()
sched.start()
c = Converter()
def conversion():
conv_string = {
'format': 'mkv',
'audio': {
'codec': 'ac3',
'bitrate': 448000,
'channels': 6
},
'video': {
'codec': 'copy'
}
}
con = c.converter("/tmp/input.mkv", "/tmp/output.mkv", conv_string)
for timecode in con:
print timecode
sched.add_interval_job(convert, minutes=30, max_instances=2, start_date=datetime.datetime.now() + datetime.timedelta(seconds=2))
Code: Alles auswählen
@staticmethod
def _spawn(cmds):
logger.debug('Spawning ffmpeg with command: ' + ' '.join(cmds))
return Popen(cmds, shell=False, stdin=PIPE, stdout=PIPE, stderr=PIPE,
close_fds=True)
def probe(self, fname, posters_as_video=True):
if not os.path.exists(fname):
return None
info = MediaInfo(posters_as_video)
p = self._spawn([self.ffprobe_path,
'-show_format', '-show_streams', fname])
stdout_data, _ = p.communicate()
info.parse_ffprobe(stdout_data)
if not info.format.format and len(info.streams) == 0:
return None
return info
def convert(self, infile, outfile, opts, timeout=10):
if not os.path.exists(infile):
raise FFMpegError("Input file doesn't exist: " + infile)
cmds = [self.ffmpeg_path, '-i', infile]
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:
raise FFMpegError('Error while calling ffmpeg binary')
yielded = False
buf = ''
total_output = ''
pat = re.compile(r'time=([0-9.:]+) ')
while True:
if timeout:
signal.alarm(timeout)
ret = p.stderr.read(10)
if timeout:
signal.alarm(0)
if not ret:
break
total_output += ret
buf += ret
if '\r' in buf:
line, buf = buf.split('\r', 1)
tmp = pat.findall(line)
if len(tmp) == 1:
timespec = tmp[0]
if ':' in timespec:
timecode = 0
for part in timespec.split(':'):
timecode = 60 * timecode + float(part)
else:
timecode = float(tmp[0])
yielded = True
yield timecode
if timeout:
signal.signal(signal.SIGALRM, signal.SIG_DFL)
p.communicate() # wait for process to exit
if total_output == '':
raise FFMpegError('Error while calling ffmpeg binary')
cmd = ' '.join(cmds)
if '\n' in total_output:
line = total_output.split('\n')[-2]
if line.startswith('Received signal'):
# Received signal 15: terminating.
raise FFMpegConvertError(line.split(':')[0], cmd, total_output)
if line.startswith(infile + ': '):
err = line[len(infile) + 2:]
raise FFMpegConvertError('Encoding error', cmd, total_output,
err)
if line.startswith('Error while '):
raise FFMpegConvertError('Encoding error', cmd, total_output,
line)
if not yielded:
raise FFMpegConvertError('Unknown ffmpeg error', cmd,
total_output, line)
if p.returncode != 0:
raise FFMpegConvertError('Exited with code %d' % p.returncode, cmd,
total_output)
https://bitbucket.org/raphaelmutschler/pyencoder/src
Hast du mal geschaut ob etwas in stderr von dem subprocess ankommt? Vielleicht tritt ja ein Fehler auf und das Programm terminiert gar nicht? Ansonsten könnte das natürlich an dem apscheduler liegen. Fuse lässt auch nur Threads zu, wenn man Multithreading explizit aktiviert.
Warum willst du überhaupt pollen? Reagier doch lieber auf ein auftretendes Ereignis. Mit pyinotify kann man unter Linux problemlos und ressourcenschonend Verzeichnisse auf Änderungen überwachen. In deinem Fall kannst du auf das Erstellen einer Datei mit einer bestimmten Endung reagieren und den entsprechenden Vorgang dafür starten. Das spart dir den scheduler.
Warum willst du überhaupt pollen? Reagier doch lieber auf ein auftretendes Ereignis. Mit pyinotify kann man unter Linux problemlos und ressourcenschonend Verzeichnisse auf Änderungen überwachen. In deinem Fall kannst du auf das Erstellen einer Datei mit einer bestimmten Endung reagieren und den entsprechenden Vorgang dafür starten. Das spart dir den scheduler.