这是一个我从C
++版本转换为Python的工作示例,该问题可用:如何使用QMediaPlayer保存框架?
import sysimport uuidimport PyQt5from PyQt5 import QtCore, QtWidgetsfrom PyQt5.QtCore import Qt, QObject, QUrl, QRect, pyqtSignal, QPointfrom PyQt5.QtGui import QPainter, QImagefrom PyQt5.QtWidgets import QWidget, QApplication, QMainWindow, QGridLayout, QToolBar, QActionfrom PyQt5.QtMultimedia import QMediaPlayer, QMediaContent, QAbstractVideoBuffer, QVideoframe, QVideoSurfaceFormat, QAbstractVideoSurfacefrom PyQt5.QtMultimediaWidgets import QVideoWidgetclass VideoframeGrabber(QAbstractVideoSurface): frameAvailable = pyqtSignal(QImage) def __init__(self, widget: QWidget, parent: QObject): super().__init__(parent) self.widget = widget def supportedPixelFormats(self, handleType): return [QVideoframe.Format_ARGB32, QVideoframe.Format_ARGB32_Premultiplied, QVideoframe.Format_RGB32, QVideoframe.Format_RGB24, QVideoframe.Format_RGB565, QVideoframe.Format_RGB555, QVideoframe.Format_ARGB8565_Premultiplied, QVideoframe.Format_BGRA32, QVideoframe.Format_BGRA32_Premultiplied, QVideoframe.Format_BGR32, QVideoframe.Format_BGR24, QVideoframe.Format_BGR565, QVideoframe.Format_BGR555, QVideoframe.Format_BGRA5658_Premultiplied, QVideoframe.Format_AYUV444, QVideoframe.Format_AYUV444_Premultiplied, QVideoframe.Format_YUV444, QVideoframe.Format_YUV420P, QVideoframe.Format_YV12, QVideoframe.Format_UYVY, QVideoframe.Format_YUYV, QVideoframe.Format_NV12, QVideoframe.Format_NV21, QVideoframe.Format_IMC1, QVideoframe.Format_IMC2, QVideoframe.Format_IMC3, QVideoframe.Format_IMC4, QVideoframe.Format_Y8, QVideoframe.Format_Y16, QVideoframe.Format_Jpeg, QVideoframe.Format_CameraRaw, QVideoframe.Format_AdobeDng] def isFormatSupported(self, format): imageFormat = QVideoframe.imageFormatFromPixelFormat(format.pixelFormat()) size = format.frameSize() return imageFormat != QImage.Format_Invalid and not size.isEmpty() and format.handleType() == QAbstractVideoBuffer.NoHandle def start(self, format: QVideoSurfaceFormat): imageFormat = QVideoframe.imageFormatFromPixelFormat(format.pixelFormat()) size = format.frameSize() if imageFormat != QImage.Format_Invalid and not size.isEmpty(): self.imageFormat = imageFormat self.imageSize = size self.sourceRect = format.viewport() super().start(format) self.widget.updateGeometry() self.updateVideoRect() return True else: return False def stop(self): self.currentframe = QVideoframe() self.targetRect = QRect() super().stop() self.widget.update() def present(self, frame): if frame.isValid(): cloneframe = QVideoframe(frame) cloneframe.map(QAbstractVideoBuffer.ReadOnly) image = QImage(cloneframe.bits(), cloneframe.width(), cloneframe.height(), QVideoframe.imageFormatFromPixelFormat(cloneframe.pixelFormat())) self.frameAvailable.emit(image) # this is very important cloneframe.unmap() if self.surfaceFormat().pixelFormat() != frame.pixelFormat() or self.surfaceFormat().frameSize() != frame.size(): self.setError(QAbstractVideoSurface.IncorrectFormatError) self.stop() return False else: self.currentframe = frame self.widget.repaint(self.targetRect) return True def updateVideoRect(self): size = self.surfaceFormat().sizeHint() size.scale(self.widget.size().boundedTo(size), Qt.KeepAspectRatio) self.targetRect = QRect(QPoint(0, 0), size) self.targetRect.moveCenter(self.widget.rect().center()) def paint(self, painter): if self.currentframe.map(QAbstractVideoBuffer.ReadOnly): oldTransform = self.painter.transform() if self.surfaceFormat().scanLineDirection() == QVideoSurfaceFormat.BottomToTop: self.painter.scale(1, -1) self.painter.translate(0, -self.widget.height()) image = QImage(self.currentframe.bits(), self.currentframe.width(), self.currentframe.height(), self.currentframe.bytesPerLine(), self.imageFormat) self.painter.drawImage(self.targetRect, image, self.sourceRect) self.painter.setTransform(oldTransform) self.currentframe.unmap()class App(QApplication): def __init__(self, sys_argv): super().__init__(sys_argv) # Show main window self.view = QMainWindow() self.centralWidget = QWidget(self.view) self.gridLayout = QGridLayout(self.centralWidget) self.gridLayout.setContentsMargins(0, 0, 0, 0) self.gridLayout.setSpacing(0) self.video_item = QVideoWidget() self.gridLayout.addWidget(self.video_item) self.view.setCentralWidget(self.centralWidget) self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface) self.grabber = VideoframeGrabber(self.video_item, self) self.mediaPlayer.setVideoOutput(self.grabber) self.grabber.frameAvailable.connect(self.process_frame) self.mediaPlayer.durationChanged.connect(self.update_duration) self.mediaPlayer.positionChanged.connect(self.update_slider_position) local = QUrl.fromLocalFile('c:/temp/lorem.mp4') media = QMediaContent(local) self.mediaPlayer.setMedia(media) self.mediaPlayer.play() self.view.show() def process_frame(self, image): # Save image here image.save('c:/temp/{}.jpg'.format(str(uuid.uuid4()))) def update_duration(self): pass def update_slider_position(self): passif __name__ == '__main__': def except_hook(cls, exception, traceback): sys.__excepthook__(cls, exception, traceback) if hasattr(QtCore.Qt, 'AA_EnableHighDpiScaling'): PyQt5.QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling, True) if hasattr(QtCore.Qt, 'AA_UseHighDpiPixmaps'): PyQt5.QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps, True) app = App(sys.argv) app.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling) sys.excepthook = except_hook sys.exit(app.exec_())


