2012-05-14 4 views
0

Я пытаюсь выполнить системную команду с подпроцессом и считывать вывод.Killing python ffmpeg subprocess breaks cli output

Но если команда занимает более 10 секунд, я хочу убить подпроцесс.

Я пробовал делать это несколькими способами.

Моя последняя попытка была вдохновлена ​​этой должности: https://stackoverflow.com/a/3326559/969208

Пример:

import os 
import signal 
from subprocess import Popen, PIPE 

class Alarm(Exception): 
    pass 

def alarm_handler(signum, frame): 
    raise Alarm 

def pexec(args): 

    p = Popen(args, stdout=PIPE, stderr=PIPE) 

    signal.signal(signal.SIGALRM, alarm_handler) 
    signal.alarm(10) 

    stdout = stderr = '' 
    try: 
     stdout, stderr = p.communicate() 
     signal.alarm(0) 
    except Alarm: 
     try: 
      os.kill(p.pid, signal.SIGKILL) 
     except: 
      pass 

    return (stdout, stderr) 

Проблема заключается в том: После того, как выходит из программы не символы не отображаются в кли, пока я не достиг возвращения. И удар по возвращению не даст мне новой линии.

Я полагаю, что это имеет какое-то отношение к трубе stdout и stderr.

Я попытался гиперемией и чтением из трубы (p.stdout.flush())

Я также попытался с различными POPEN аргументов, но, возможно, что-то пропустил. Просто подумал, что я останусь здесь просто.

Я запускаю это на сервере Debian.

Я что-то упустил?

EDIT:

Это кажется, что это только в том случае, когда убийство продолжающийся процесс FFmpeg. Если процесс ffmpeg выходит нормально до 10 секунд, проблем нет.

Я попытался выполнить несколько разных команд, которые занимают больше 10 секунд, тот, кто печатает вывод, тот, кто этого не делает, и команду ffmpeg для проверки целостности файла.

args = ['sleep', '12s'] # Works fine 
args = ['ls', '-R', '/var'] # Works fine, prints lots for a long time 
args = ['ffmpeg', '-v', '1', '-i', 'large_file.mov','-f', 'null', '-'] # Breaks cli output 

Я считаю, что ffmpeg печатает с использованием \ r и печатает все на трубе strerr. Это может быть причиной? Есть идеи, как это исправить?

ответ

1

Ну. ваш код, безусловно, отлично работает на моем сервере Ubuntu.

(который является близким родственником или братом Debian я полагаю)

Я добавил несколько строк, так что я могу проверить свой код.

import os 
import signal 
from subprocess import Popen, PIPE 

class Alarm(Exception): 
    pass 

def alarm_handler(signum, frame): 
    raise Alarm 
def pexec(args): 
    p = Popen(args, stdout=PIPE, stderr=PIPE) 

    signal.signal(signal.SIGALRM, alarm_handler) 
    signal.alarm(1) 

    stderr = '' 
    try: 
     stdout, stderr = p.communicate() 
     signal.alarm(0) 
    except Alarm: 
    print "Done!" 
     try: 
      os.kill(p.pid, signal.SIGKILL) 
     except: 
      pass 

    return (stdout, stderr) 

args = ('find', '/', '-name','*') 
stdout = pexec(args) 
print "----------------------result--------------------------" 
print stdout 
print "----------------------result--------------------------" 

Работает как очарование.

Если этот код работает на сервере, я предполагаю, что проблема на самом деле лежит на

командной строки приложения, которые вы пытаетесь восстановить данные.

+0

Thx Ryan, вы правы, он отлично работает. Кажется, это только в случае убийства текущих процессов ffmpeg. См. Мое редактирование. – JayLev

0

У меня такая же проблема. Я не могу запустить FFmpeg, чтобы закончить из подпроцесса python, поэтому я использую <process>.kill().Однако я думаю, что это означает, что FFmpeg не восстанавливает режим TTY правильно (как описано здесь: https://askubuntu.com/a/172747)

Вы можете получить раковину назад, запустив reset на Баш строке, но это очищает экран, так что вы не можете как вы продолжаете работать.

Лучше всего запустить stty echo, который снова включится для сеанса вашей оболочки.

Вы даже можете запустить это в своем скрипте после того, как вы нажмете FFmpeg. Я делаю:

ffmpeg_popen.kill() 
ffmpeg_popen.wait() 
subprocess.call(["stty", "echo"]) 

Это работает для меня на Ubuntu с bash как моя оболочка. YMMV, но я надеюсь, что это поможет. Он пахнет хаккой, но это лучшее решение, которое я нашел.

0

Я столкнулся с аналогичной проблемой с ffmpeg. Кажется, что если ffmpeg убит с помощью Popen.kill(), он не закрывается должным образом и не восстанавливает эхо на вашем терминале.

Мы можем решить эту проблему с помощью трубы для стандартного ввода, и писать д закрыть FFmpeg, как мы бы в Cli сессии:

p = Popen(args, stdin=PIPE stdout=PIPE, stderr=PIPE) 
p.stdin.write(b"q") 

Это, вероятно, предпочтительнее использовать Popen.communicate для того, чтобы избежать тупика. Ниже будет также работать:

p = Popen(args, stdin=PIPE stdout=PIPE, stderr=PIPE) 
p.communicate(b'q') 

Но, похоже, даже в следующих работах:

p = Popen(args, stdin=PIPE stdout=PIPE, stderr=PIPE) 
p.kill() 

Я не уверен, что причины этого FFmpeg закрыть чисто, если он имеет входной трубы. Возможно, это имеет какое-то отношение к тому, что вызывает эту ошибку в первую очередь?