FFMPEG и подпроцесс Pythons - PullRequest
       13

FFMPEG и подпроцесс Pythons

8 голосов
/ 21 сентября 2009

Я пытаюсь написать графический интерфейс для FFMPEG. Я использую подпроцесс pythons для создания процесса ffmpeg для каждого преобразования, которое я хочу. Это прекрасно работает, но я также хотел бы получить способ получить прогресс преобразования, независимо от того, провалился он или нет и т. Д. Я подумал, что мог бы сделать это, получив доступ к stdout процесса следующим образом:

Звонок subprocess.Popen()

# Convert - Calls FFMPEG with current settings. (in a seperate
# thread.)
def convert(self):
    # Check if options are valid
    if self.input == "" or self.output == "":
        return False

# Make the command string
ffmpegString = self.makeString()

# Try to open with these settings
try:
    self.ffmpeg = subprocess.Popen(ffmpegString, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
except OSError:
    self.error.append("OSError: ")
except ValueError:
    self.error.append("ValueError: Couldn't call FFMPEG with these parameters")

# Convert process should be running now.

и чтение stdout:

convert = Convert()
convert.input = "test.ogv"
convert.output = "test.mp4"
convert.output_size = (0, 0)

convert.convert()

while 1:
    print convert.ffmpeg.stdout.readline()

Это работает, но статус ffmpeg не отображается. Я предполагаю, что это как-то связано с тем, как ffmpeg обновляет его. Есть ли способ получить к нему доступ?

Ответы [ 6 ]

8 голосов
/ 21 сентября 2009

Я часто замечал проблемы с чтением стандартного вывода (или даже стандартной ошибки!) С подпроцессом из-за проблем буферизации, которые трудно устранить. Мое любимое решение, когда мне нужно прочитать такой stdout / stderr из подпроцесса, это переключиться на использование вместо subprocess, pexpect (или, в Windows, wexpect).

6 голосов
/ 30 июня 2015

Просто добавьте universal_newlines = True для вашего подпроцесса. Откройте строку.

cmd="ffmpeg -i in.mp4 -y out.avi"
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,universal_newlines=True)
for line in process.stdout:
    print(line)

Пока у вас есть строка в цикле, как:

frame= 1900 fps=453 q=18.6 Lsize=    3473kB time=00:01:16.08 bitrate= 373.9kbits/s

Используйте время = значение, чтобы определить прогресс в процентах.

3 голосов
/ 01 марта 2010

Я думаю, что вы не можете использовать readline, потому что ffmpeg никогда не печатает одну строку, статус обновляется записью \ r (возврат каретки) и последующей записью строки.

size=      68kB time=0.39 bitrate=1412.1kbits/s    \rsize=    2786kB time=16.17 bitrate=1411.2kbits/s    \rsize=    5472kB time=31.76 bitrate=1411.2kbits/s    \r\n

Если вы изучите строку выше, вы заметите, что есть только один \ n, и он печатается, когда файл завершает конвертацию.

2 голосов
/ 21 августа 2010

Так как ffmpeg записывает данные в неразблокированном виде в stderr, вы должны установить дескриптор файла stderr на неблокирование с помощью fcntl.

    fcntl.fcntl(
        pipe.stderr.fileno(),
        fcntl.F_SETFL,
        fcntl.fcntl(pipe.stderr.fileno(), fcntl.F_GETFL) | os.O_NONBLOCK,
    )

, а затем зациклите с помощью выбора, чтобы прочитать данные

    while True:
        readx = select.select([pipe.stderr.fileno()], [], [])[0]
        if readx:
            chunk = pipe.stderr.read()

для полного примера перейдите здесь .

0 голосов
/ 13 ноября 2017
ffmpegCommand='''
ffmpeg
-f lavfi
-i anullsrc=channel_layout=1c:sample_rate=11025
-rtsp_transport tcp
-rtsp_transport udp
-rtsp_transport http
-thread_queue_size 32000
-i rtsp://xxx.xxx.xxx.xxx:554/user=admin&password=xxx&channel=1&stream=1.sdp?real_stream
-reconnect 1
-reconnect_at_eof 1
-reconnect_streamed 1
-reconnect_delay_max 4294
-tune zerolatency
-c:v copy
-c:a aac
-bufsize 6000k
-f flv rtmp://a.rtmp.youtube.com/live2/xxx-xxx-xxx-xxx'''
cmd=ffmpegCommand.split()
# "universal newline support" This will cause to interpret \n, \r\n and \r     equally, each as a newline.

p = subprocess.Popen(cmd, stderr=subprocess.PIPE, universal_newlines=True)
while True:    
        print(p.stderr.readline().rstrip('\r\n'))
0 голосов
/ 21 сентября 2009

FFMPEG:

FFMPEG выводит весь текст состояния (что вы видите, когда запускаете его вручную в командной строке) в интерфейсе stderr. Чтобы получить выходные данные из ffmpeg, вам нужно следить за интерфейсом stderr или перенаправлять его, как в примере.

Проверка вывода на stderr:

Вот еще один способ попробовать читать из stderr вместо перенаправления при вызове Popen

Класс Popen в Python имеет файловый объект с именем stderr, вы будете обращаться к нему так же, как и к stdout. Я думаю, что ваш цикл будет выглядеть примерно так:

while 1:
    print convert.ffmpeg.stdout.readline()
    print convert.ffmpeg.stderr.readline()

Отказ от ответственности: я не проверял это в Python, но я сделал сопоставимое приложение, используя Java.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...