我有一个 PyQt 窗口,其中的小部件会发生变化。我想制作一个视频。我发现this Answer非常有用,但是似乎不可能在 QtGui.QPixmap 的保存方法中使用子进程 PIPE 作为目标。我觉得我应该使用本机 QtProcess 来完成此类工作,但我不知道如何通过管道传输图像,而且我看不到错误,因为我也看不到标准输出/错误。我想做的是这样的:
from PyQt4 import QtGui, QtCore
import random
app = QtGui.QApplication([])
win = QtGui.QWidget()
layout = QtGui.QGridLayout()
win.setLayout(layout)
#picture frame
scene = QtGui.QGraphicsScene()
canvas = QtGui.QGraphicsView(scene)
layout.addWidget(canvas,0,0)
# start button
def run():
# set pen
pen = QtGui.QPen(QtCore.Qt.red)
size = canvas.size()
# start seperate process
process = QtCore.QProcess(app)
process.start('ffmpeg',['-y', '-f', 'image2pipe', '-vcodec', 'mjpeg', '-r', '24', '-i', '-', '-vcodec', 'mpeg4', '-qscale', '5', 'video.avi'])
for i in range(100):
x = random.randint(1, size.width()-1)
y = random.randint(1, size.height()-1)
scene.addLine(x,y,x,y, pen=pen)
QtGui.QPixmap.grabWidget(win).save(process, "jpeg")
but_run = QtGui.QPushButton("Go!")
but_run.clicked.connect(run)
layout.addWidget(but_run,1,0)
win.show()
app.exec_()
所以我自己想出了办法。只需要添加几个命令:
process.setProcessChannelMode(process.ForwardedChannels)
会将子进程的错误和正常输出重定向到主进程。这可以让你看到 ffmpeg 做了什么或没有做什么。
编辑:这实际上是不需要的。
process.setOpenMode(process.WriteOnly)
这将打开进程的输入通道。
我将文件格式更改为 png,因为它看起来更好。 JPG 压缩不适合大的单色区域。
process.closeWriteChannel()
将关闭输入通道。这就是 ffmpeg 知道没有更多数据传入的方式。
最后,调用
process.terminate()
关闭进程。
这是完整功能的代码:
from PyQt4 import QtGui, QtCore
import random
app = QtGui.QApplication([])
win = QtGui.QWidget()
layout = QtGui.QGridLayout()
win.setLayout(layout)
#picture frame
scene = QtGui.QGraphicsScene()
canvas = QtGui.QGraphicsView(scene)
layout.addWidget(canvas,0,0)
# start button
def run():
# set pen
pen = QtGui.QPen(QtCore.Qt.red)
size = canvas.size()
# start seperate process
process = QtCore.QProcess(app)
process.setProcessChannelMode(process.ForwardedChannels)
#process.setOpenMode(process.WriteOnly)
process.start('ffmpeg',['-y', '-vcodec', 'png', '-i', '-', '-vcodec', 'mpeg4', '-qscale', '5', '-r', '24', 'video.avi',"-loglevel", "debug"])
for i in range(100):
x = random.randint(1, size.width()-1)
y = random.randint(1, size.height()-1)
scene.addLine(x,y,x,y, pen=pen)
QtGui.QPixmap.grabWidget(win).save(process, "png")
process.closeWriteChannel()
process.terminate()
but_run = QtGui.QPushButton("Go!")
but_run.clicked.connect(run)
layout.addWidget(but_run,1,0)
win.show()
app.exec_()