Как я могу получить в режиме реального времени вывод командной строки x265.exe с Python? - PullRequest
2 голосов
/ 29 февраля 2020

Я хотел бы написать GUI для x265.exe, который представляет лучший (более гуманизированный) прогресс в реальном времени.

Вот код, который я использовал для захвата вывода подпроцесса:

import subprocess

cmd = r'ping www.baidu.com -n 4'
popen = subprocess.Popen(cmd, stdout = subprocess.PIPE ,stderr=subprocess.STDOUT ,shell=True)
while True:
    next_line = popen.stdout.readline()
    if next_line == b'' and popen.poll() != None:
        break
    else:
        print(next_line.decode('ascii').replace('\r\n','\n') , end='')

Он отлично работает с 'ping'.

Однако, когда я переключился на команду 'x265', все переходит к проводному.

Например, если я заменил строковую переменную 'cmd' в "x265 --y4m --crf 21 --output output.hevc input.y4m" в предыдущем коде. Теоретически, он должен выдавать следующие выходные данные в строках, упорядоченных по времени:

y4m  [info]: 1920x1080 fps 24000/1001 i420p10 frames 0 - 100 of 101
x265 [info]: Using preset ultrafast & tune none
raw  [info]: output file: C:\temp\output.hevc
x265 [info]: Main 10 profile, Level-4 (Main tier)
x265 [info]: Thread pool created using 16 threads
x265 [info]: Slices                              : 1
x265 [info]: frame threads / pool features       : 4 / wpp(34 rows)
x265 [info]: Coding QT: max CU size, min CU size : 32 / 16
x265 [info]: Residual QT: max TU size, max depth : 32 / 1 inter / 1 intra
x265 [info]: ME / range / subpel / merge         : dia / 57 / 0 / 2
x265 [info]: Keyframe min / max / scenecut / bias: 23 / 250 / 0 / 5.00
x265 [info]: Lookahead / bframes / badapt        : 5 / 3 / 0
x265 [info]: AQ: mode / str / qg-size / cu-tree  : 1 / 0.0 / 32 / 1
x265 [info]: Rate Control / qCompress            : CRF-21.0 / 0.60
x265 [info]: tools: strong-intra-smoothing lslices=6 deblock

[1.0%] 1/101 frames, 6.289 fps, 7217.8 kb/s
[25.7%] 26/101 frames, 59.23 fps, 299.23 kb/s
[45.5%] 46/101 frames, 66.76 fps, 322.81 kb/s  
[69.3%] 70/101 frames, 73.30 fps, 224.53 kb/s
[93.1%] 94/101 frames, 77.05 fps, 173.67 kb/s   

x265 [info]: frame I:      1, Avg QP:23.45  kb/s: 7098.44 
x265 [info]: frame P:     25, Avg QP:25.71  kb/s: 311.24  
x265 [info]: frame B:     75, Avg QP:28.33  kb/s: 23.89   
x265 [info]: consecutive B-frames: 3.8% 0.0% 0.0% 96.2% 

encoded 101 frames in 1.22s (82.58 fps), 165.06 kb/s, Avg QP:27.64

Но правда в том, что эти выходные блоки в средней части, которые указывают прогресс в реальном времени не будет отслеживаться при каждом конкретном обновлении c. Команда popen.stdout.readline() будет заблокирована до тех пор, пока прогресс не достигнет 100%, а затем будет выводиться полностью. Очевидно, что это не то, что я хочу.

(↓ я имею в виду под этой частью)

[1.0%] 1/101 frames, 6.289 fps, 7217.8 kb/s
[25.7%] 26/101 frames, 59.23 fps, 299.23 kb/s
[45.5%] 46/101 frames, 66.76 fps, 322.81 kb/s  
[69.3%] 70/101 frames, 73.30 fps, 224.53 kb/s
[93.1%] 94/101 frames, 77.05 fps, 173.67 kb/s   

Может ли кто-нибудь помочь мне разобраться в том, что происходит и как это исправить для достижения моей цели?

Спасибо большое.

1 Ответ

2 голосов
/ 29 февраля 2020

Я полагаю, что, поскольку выходные данные команды обновляют текст на месте, в конце нет символа новой строки, вместо этого на выходе есть только возврат каретки для возврата курсора в начало той же строки. и перезаписать предыдущую строку. Таким образом, использование readline не приведет к тому, что вы хотите. Вам нужно будет написать свой собственный лог c, чтобы прочитать вывод и разбить вывод на строки.

Ниже приведена моя реализация

import re
import subprocess

cmd = r'ping www.baidu.com -n 4'
popen = subprocess.Popen(cmd, stdout = subprocess.PIPE ,stderr=subprocess.STDOUT ,shell=True)

read_chunk_size = 20
next_lines = ['']
while True:
    # read the stdout upto read_chunk_size bytes
    chunk = popen.stdout.read(read_chunk_size)
    # checking if process has finished
    if not chunk and popen.poll() != None:
        break
    # splitting the read string of charachters by either \n, \r or \n\r
    split_chunk = re.split('\n|\r|\n\r', chunk.decode('utf-8'))
    # combining the first of the split strings to the last of the strings
    # which were read in the last iteration. since we are reading upto only 
    # a fixed length, we may get incomplete lines
    next_lines = [next_lines[-1] + split_chunk[0]] + split_chunk[1:]
    # iterate upto the second last item in next_lines, since the last item may
    # still be incomplete which will be read in the next iteration
    for line in next_lines[:-1]:
        # read your lines here
        print(line)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...