Merge pull request #4669 from Ultimaker/CURA-5821_fix_camera_memory_leak

Cura 5821 fix camera memory leak
This commit is contained in:
Remco Burema 2018-10-26 15:00:03 +02:00 committed by GitHub
commit de680f4aac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 75 additions and 26 deletions

View File

@ -959,6 +959,9 @@ class CuraApplication(QtApplication):
qmlRegisterType(QualityManagementModel, "Cura", 1, 0, "QualityManagementModel") qmlRegisterType(QualityManagementModel, "Cura", 1, 0, "QualityManagementModel")
qmlRegisterType(MachineManagementModel, "Cura", 1, 0, "MachineManagementModel") qmlRegisterType(MachineManagementModel, "Cura", 1, 0, "MachineManagementModel")
from cura.PrinterOutput.CameraView import CameraView
qmlRegisterType(CameraView, "Cura", 1, 0, "CameraView")
qmlRegisterSingletonType(QualityProfilesDropDownMenuModel, "Cura", 1, 0, qmlRegisterSingletonType(QualityProfilesDropDownMenuModel, "Cura", 1, 0,
"QualityProfilesDropDownMenuModel", self.getQualityProfilesDropDownMenuModel) "QualityProfilesDropDownMenuModel", self.getQualityProfilesDropDownMenuModel)
qmlRegisterSingletonType(CustomQualityProfilesDropDownMenuModel, "Cura", 1, 0, qmlRegisterSingletonType(CustomQualityProfilesDropDownMenuModel, "Cura", 1, 0,

View File

@ -0,0 +1,41 @@
# Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
from PyQt5.QtCore import pyqtProperty, pyqtSignal
from PyQt5.QtGui import QImage
from PyQt5.QtQuick import QQuickPaintedItem
#
# A custom camera view that uses QQuickPaintedItem to present (or "paint") the image frames from a printer's
# network camera feed.
#
class CameraView(QQuickPaintedItem):
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
self._image = QImage()
imageChanged = pyqtSignal()
def setImage(self, image: "QImage") -> None:
self._image = image
self.imageChanged.emit()
self.update()
def getImage(self) -> "QImage":
return self._image
image = pyqtProperty(QImage, fget = getImage, fset = setImage, notify = imageChanged)
@pyqtProperty(int, notify = imageChanged)
def imageWidth(self) -> int:
return self._image.width()
@pyqtProperty(int, notify = imageChanged)
def imageHeight(self) -> int:
return self._image.height()
def paint(self, painter):
painter.drawImage(self.contentsBoundingRect(), self._image)

View File

@ -16,7 +16,6 @@ class NetworkCamera(QObject):
self._image_request = None self._image_request = None
self._image_reply = None self._image_reply = None
self._image = QImage() self._image = QImage()
self._image_id = 0
self._target = target self._target = target
self._started = False self._started = False
@ -33,15 +32,9 @@ class NetworkCamera(QObject):
if restart_required: if restart_required:
self.start() self.start()
@pyqtProperty(QUrl, notify=newImage) @pyqtProperty(QImage, notify=newImage)
def latestImage(self): def latestImage(self):
self._image_id += 1 return self._image
# There is an image provider that is called "camera". In order to ensure that the image qml object, that
# requires a QUrl to function, updates correctly we add an increasing number. This causes to see the QUrl
# as new (instead of relying on cached version and thus forces an update.
temp = "image://camera/" + str(self._image_id)
return QUrl(temp, QUrl.TolerantMode)
@pyqtSlot() @pyqtSlot()
def start(self): def start(self):
@ -116,4 +109,4 @@ class NetworkCamera(QObject):
self._stream_buffer_start_index = -1 self._stream_buffer_start_index = -1
self._image.loadFromData(jpg_data) self._image.loadFromData(jpg_data)
self.newImage.emit() self.newImage.emit()

View File

@ -10,7 +10,7 @@ Component {
height: maximumHeight; height: maximumHeight;
width: maximumWidth; width: maximumWidth;
Image { Cura.CameraView {
id: cameraImage; id: cameraImage;
anchors { anchors {
horizontalCenter: parent.horizontalCenter; horizontalCenter: parent.horizontalCenter;
@ -21,7 +21,7 @@ Component {
OutputDevice.activePrinter.camera.start(); OutputDevice.activePrinter.camera.start();
} }
} }
height: Math.floor((sourceSize.height === 0 ? 600 * screenScaleFactor : sourceSize.height) * width / sourceSize.width); height: Math.floor((imageHeight === 0 ? 600 * screenScaleFactor : imageHeight) * width / imageWidth);
onVisibleChanged: { onVisibleChanged: {
if (visible) { if (visible) {
if (OutputDevice.activePrinter != null && OutputDevice.activePrinter.camera != null) { if (OutputDevice.activePrinter != null && OutputDevice.activePrinter.camera != null) {
@ -33,14 +33,20 @@ Component {
} }
} }
} }
source: { width: Math.min(imageWidth === 0 ? 800 * screenScaleFactor : imageWidth, maximumWidth);
if (OutputDevice.activePrinter != null && OutputDevice.activePrinter.camera != null && OutputDevice.activePrinter.camera.latestImage) {
return OutputDevice.activePrinter.camera.latestImage;
}
return "";
}
width: Math.min(sourceSize.width === 0 ? 800 * screenScaleFactor : sourceSize.width, maximumWidth);
z: 1; z: 1;
Connections
{
target: OutputDevice.activePrinter.camera;
onNewImage:
{
if (cameraImage.visible) {
cameraImage.image = OutputDevice.activePrinter.camera.latestImage;
cameraImage.update();
}
}
}
} }
} }
} }

View File

@ -5,6 +5,7 @@ import QtQuick 2.2
import QtQuick.Controls 1.4 import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4 import QtQuick.Controls.Styles 1.4
import UM 1.3 as UM import UM 1.3 as UM
import Cura 1.0 as Cura
Item { Item {
property var camera: null; property var camera: null;
@ -33,11 +34,11 @@ Item {
z: 999; z: 999;
} }
Image { Cura.CameraView {
id: cameraImage id: cameraImage
anchors.horizontalCenter: parent.horizontalCenter; anchors.horizontalCenter: parent.horizontalCenter;
anchors.verticalCenter: parent.verticalCenter; anchors.verticalCenter: parent.verticalCenter;
height: Math.round((sourceSize.height === 0 ? 600 * screenScaleFactor : sourceSize.height) * width / sourceSize.width); height: Math.round((imageHeight === 0 ? 600 * screenScaleFactor : imageHeight) * width / imageWidth);
onVisibleChanged: { onVisibleChanged: {
if (visible) { if (visible) {
if (camera != null) { if (camera != null) {
@ -49,13 +50,18 @@ Item {
} }
} }
} }
source: {
if (camera != null && camera.latestImage != null) { Connections
return camera.latestImage; {
target: camera
onNewImage: {
if (cameraImage.visible) {
cameraImage.image = camera.latestImage;
cameraImage.update();
}
} }
return "";
} }
width: Math.min(sourceSize.width === 0 ? 800 * screenScaleFactor : sourceSize.width, maximumWidth); width: Math.min(imageWidth === 0 ? 800 * screenScaleFactor : imageWidth, maximumWidth);
z: 1 z: 1
} }