diff --git a/NetworkPrinterOutputDevice.py b/NetworkPrinterOutputDevice.py index 2fef90ac86..ecb493d85d 100644 --- a/NetworkPrinterOutputDevice.py +++ b/NetworkPrinterOutputDevice.py @@ -113,6 +113,13 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice): self._camera_timer.setSingleShot(False) self._camera_timer.timeout.connect(self._update_camera) + self._image_request = None + self._image_reply = None + + self._use_stream = True + self._stream_buffer = b"" + self._stream_buffer_start_index = -1 + self._camera_image_id = 0 self._authentication_counter = 0 @@ -192,6 +199,13 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice): def ipAddress(self): return self._address + def _start_camera_stream(self): + ## Request new image + url = QUrl("http://" + self._address + ":8080/?action=stream") + self._image_request = QNetworkRequest(url) + self._image_reply = self._manager.get(self._image_request) + self._image_reply.downloadProgress.connect(self._onStreamDownloadProgress) + def _update_camera(self): if not self._manager.networkAccessible(): return @@ -423,6 +437,12 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice): self._update_timer.stop() self._camera_timer.stop() + if self._image_reply: + self._image_reply.abort() + self._image_reply.downloadProgress.disconnect(self._onStreamDownloadProgress) + self._image_reply = None + self._image_request = None + def requestWrite(self, node, file_name = None, filter_by_machine = False): if self._progress != 0: self._error_message = Message(i18n_catalog.i18nc("@info:status", "Unable to start a new print job because the printer is busy. Please check the printer.")) @@ -531,7 +551,8 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice): self.setConnectionState(ConnectionState.connecting) self._update() # Manually trigger the first update, as we don't want to wait a few secs before it starts. - self._update_camera() + if not self._use_stream: + self._update_camera() Logger.log("d", "Connection with printer %s with ip %s started", self._key, self._address) ## Check if this machine was authenticated before. @@ -539,7 +560,10 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice): self._authentication_key = Application.getInstance().getGlobalContainerStack().getMetaDataEntry("network_authentication_key", None) self._update_timer.start() - self._camera_timer.start() + if self._use_stream: + self._start_camera_stream() + else: + self._camera_timer.start() ## Stop requesting data from printer def disconnect(self): @@ -841,6 +865,25 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice): else: Logger.log("d", "NetworkPrinterOutputDevice got an unhandled operation %s", reply.operation()) + def _onStreamDownloadProgress(self, bytes_received, bytes_total): + # An MJPG stream is (for our purpose) a stream of concatenated JPG images. + # JPG images start with the marker 0xFFD8, and end with 0xFFD9 + self._stream_buffer += self._image_reply.readAll() + + if self._stream_buffer_start_index == -1: + self._stream_buffer_start_index = self._stream_buffer.indexOf(b'\xff\xd8') + stream_buffer_end_index = self._stream_buffer.lastIndexOf(b'\xff\xd9') + # If this happens to be more than a single frame, then so be it; the JPG decoder will + # ignore the extra data. We do it like this in order not to get a buildup of frames + + if self._stream_buffer_start_index != -1 and stream_buffer_end_index != -1: + jpg_data = self._stream_buffer[self._stream_buffer_start_index:stream_buffer_end_index + 2] + self._stream_buffer = self._stream_buffer[stream_buffer_end_index + 2:] + self._stream_buffer_start_index = -1 + + self._camera_image.loadFromData(jpg_data) + self.newImage.emit() + def _onUploadProgress(self, bytes_sent, bytes_total): if bytes_total > 0: new_progress = bytes_sent / bytes_total * 100