FFMPEG和蟒蛇子(FFMPEG and Pythons subprocess)

2019-07-18 19:39发布

我试图写一个GUI FFMPEG 。 我使用蟒蛇子创建每次转换我希望有一个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的方式刷新它。 是否有访问它的方法吗?

Answer 1:

我经常发现有子问题读取标准输出(或甚至标准错误!),由于是很难打败缓冲的问题。 我最喜欢的解决方案,当我需要从子读这样的标准输出/标准错误,是切换到使用,而不是subprocesspexpect (或者,在Windows上, wexpect )。



Answer 2:

Simply add ,universal_newlines=True to your subprocess.Popen line.

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)

For now you got line in cycle like:

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

Use the time= value to determine progress in percentage.



Answer 3:

我认为你不能使用输入行,因为从来没有的ffmpeg打印一行,状态是通过写\ R(carrige回报),然后再次写入行更新。

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和当文件转换完成,即会打印。



Answer 4:

由于ffmpeg的写入未刷新到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()

全例如去这里 。



Answer 5:

FFMPEG:

FFMPEG输出的所有状态文本(你所看到的,当你在命令行上手动运行)标准错误接口上。 为了捕捉ffmpeg的输出,你需要看的标准错误界面 - 或重定向像的例子。

检查的标准错误输出:

这里是另一种尝试和标准错误读取,而不是调用POPEN时重定向它,

该POPEN类 Python中有一个叫做标准错误的文件对象,你会访问它在您访问标准输出相同的方式。 我想你的循环会是这个样子:

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

免责声明:我没有在Python测试这一点,但我做了使用Java应用程序相媲美。



Answer 6:

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'))


文章来源: FFMPEG and Pythons subprocess