def __init__(self, view): self.view = view loader = QtUiTools.QUiLoader() uifile = QtCore.QFile(':/ui/ddScreenGrabber.ui') assert uifile.open(uifile.ReadOnly) self.frameCount = 0 self.widget = loader.load(uifile) self.ui = WidgetDict(self.widget.children()) self.ui.lockViewSizeCheck.connect('clicked()', self.onLockViewSize) self.ui.screenshotOutputBrowseButton.connect( 'clicked()', self.onChooseScreenshotOutputDir) self.ui.movieOutputBrowseButton.connect('clicked()', self.onChooseMovieOutputDir) self.ui.saveScreenshotButton.connect('clicked()', self.onSaveScreenshot) self.ui.recordMovieButton.connect('clicked()', self.onRecordMovie) self.ui.viewSizeCombo.connect('currentIndexChanged(const QString&)', self.updateViewSize) self.ui.viewHeightSpin.connect('valueChanged(int)', self.onViewSizeChanged) self.ui.viewWidthSpin.connect('valueChanged(int)', self.onViewSizeChanged) self.updateViewSize() self.onLockViewSize() self.recordTimer = QtCore.QTimer() self.recordTimer.connect('timeout()', self.onRecordTimer) self.fpsCounter = FPSCounter() self.eventFilter = PythonQt.dd.ddPythonEventFilter() self.ui.scrollArea.installEventFilter(self.eventFilter) self.eventFilter.addFilteredEventType(QtCore.QEvent.Resize) self.eventFilter.connect('handleEvent(QObject*, QEvent*)', self.onEvent)
def __init__(self, view): self.view = view loader = QtUiTools.QUiLoader() uifile = QtCore.QFile(':/ui/ddScreenGrabber.ui') assert uifile.open(uifile.ReadOnly) self.frameCount = 0 self.widget = loader.load(uifile) self.ui = WidgetDict(self.widget.children()) self.ui.lockViewSizeCheck.connect('clicked()', self.onLockViewSize) self.ui.screenshotOutputBrowseButton.connect('clicked()', self.onChooseScreenshotOutputDir) self.ui.movieOutputBrowseButton.connect('clicked()', self.onChooseMovieOutputDir) self.ui.saveScreenshotButton.connect('clicked()', self.onSaveScreenshot) self.ui.recordMovieButton.connect('clicked()', self.onRecordMovie) self.ui.viewSizeCombo.connect('currentIndexChanged(const QString&)', self.updateViewSize) self.ui.viewHeightSpin.connect('valueChanged(int)', self.onViewSizeChanged) self.ui.viewWidthSpin.connect('valueChanged(int)', self.onViewSizeChanged) self.updateViewSize() self.onLockViewSize() self.recordTimer = QtCore.QTimer() self.recordTimer.connect('timeout()', self.onRecordTimer) self.fpsCounter = FPSCounter() self.eventFilter = PythonQt.dd.ddPythonEventFilter() self.ui.scrollArea.installEventFilter(self.eventFilter) self.eventFilter.addFilteredEventType(QtCore.QEvent.Resize) self.eventFilter.connect('handleEvent(QObject*, QEvent*)', self.onEvent)
class ScreenGrabberPanel(object): def __init__(self, view): self.view = view loader = QtUiTools.QUiLoader() uifile = QtCore.QFile(':/ui/ddScreenGrabber.ui') assert uifile.open(uifile.ReadOnly) self.frameCount = 0 self.widget = loader.load(uifile) self.ui = WidgetDict(self.widget.children()) self.ui.lockViewSizeCheck.connect('clicked()', self.onLockViewSize) self.ui.screenshotOutputBrowseButton.connect( 'clicked()', self.onChooseScreenshotOutputDir) self.ui.movieOutputBrowseButton.connect('clicked()', self.onChooseMovieOutputDir) self.ui.saveScreenshotButton.connect('clicked()', self.onSaveScreenshot) self.ui.recordMovieButton.connect('clicked()', self.onRecordMovie) self.ui.viewSizeCombo.connect('currentIndexChanged(const QString&)', self.updateViewSize) self.ui.viewHeightSpin.connect('valueChanged(int)', self.onViewSizeChanged) self.ui.viewWidthSpin.connect('valueChanged(int)', self.onViewSizeChanged) self.updateViewSize() self.onLockViewSize() self.recordTimer = QtCore.QTimer() self.recordTimer.connect('timeout()', self.onRecordTimer) self.fpsCounter = FPSCounter() self.eventFilter = PythonQt.dd.ddPythonEventFilter() self.ui.scrollArea.installEventFilter(self.eventFilter) self.eventFilter.addFilteredEventType(QtCore.QEvent.Resize) self.eventFilter.connect('handleEvent(QObject*, QEvent*)', self.onEvent) def onEvent(self, obj, event): minSize = self.ui.scrollArea.widget().minimumSizeHint.width( ) + self.ui.scrollArea.verticalScrollBar().width self.ui.scrollArea.setMinimumWidth(minSize) def dateTimeString(self): return datetime.datetime.fromtimestamp( time.time()).strftime('%Y-%m-%d_%H:%M:%S') def movieOutputDirectory(self): return os.path.expanduser(self.ui.movieOutputDirectory.text) def screenshotOutputDirectory(self): return os.path.expanduser(self.ui.screenshotOutputDirectory.text) def captureRate(self): return self.ui.captureRateSpin.value def chooseDirectory(self): return QtGui.QFileDialog.getExistingDirectory( app.getMainWindow(), "Choose directory...", self.movieOutputDirectory()) def ensureDirectoryIsWritable(self, dirname): if not os.path.isdir(dirname): try: os.makedirs(dirname) except OSError: app.showErrorMessage('Error creating directory: %s' % dirname) return False if not os.access(dirname, os.W_OK | os.X_OK): app.showErrorMessage('Directory is not writable: %s' % dirname) return False return True def onChooseScreenshotOutputDir(self): newDir = self.chooseDirectory() if newDir: self.ui.screenshotOutputDirectory.text = newDir def onChooseMovieOutputDir(self): newDir = self.chooseDirectory() if newDir: self.ui.movieOutputDirectory.text = newDir def onSaveScreenshot(self): outDir = self.screenshotOutputDirectory() if not self.ensureDirectoryIsWritable(outDir): return filename = os.path.join(outDir, 'Screenshot-' + self.dateTimeString() + '.png') saveScreenshot(self.view, filename) app.getMainWindow().statusBar().showMessage('Saved: ' + filename, 2000) def nextMovieFileName(self): filename = os.path.join(self.movieOutputDirectory(), 'frame_%07d.tiff' % self.frameCount) self.frameCount += 1 return filename def updateRecordingStats(self): isRecordMode = self.ui.recordMovieButton.checked currentRate = 0.0 writeQueue = 0.0 self.ui.currentRateValueLabel.setText('%.1f' % currentRate) self.ui.writeQueueValueLabel.setText('%.1f' % currentRate) def isRecordMode(self): return self.ui.recordMovieButton.checked def updateRecordingButtons(self): isRecordMode = self.isRecordMode() self.ui.movieOutputDirectory.setEnabled(not isRecordMode) self.ui.movieOutputBrowseButton.setEnabled(not isRecordMode) self.ui.captureRateSpin.setEnabled(not isRecordMode) self.ui.captureRateLabel.setEnabled(not isRecordMode) self.ui.moveOutputDirectoryLabel.setEnabled(not isRecordMode) self.ui.currentRateLabel.setEnabled(isRecordMode) self.ui.currentRateValueLabel.setEnabled(isRecordMode) self.ui.writeQueueLabel.setEnabled(isRecordMode) self.ui.writeQueueValueLabel.setEnabled(isRecordMode) self.updateRecordingStats() def onRecordMovie(self): # Enforce even width number, otherwise avconv will fail _width = (self.view.width if self.view.width % 2 == 0 else self.view.width + 1) _height = (self.view.height if self.view.height % 2 == 0 else self.view.height + 1) self.view.setFixedSize(_width, _height) if self.isRecordMode(): self.startRecording() else: self.stopRecording() self.updateRecordingButtons() def startRecording(self): self.frameCount = 0 if not self.ensureDirectoryIsWritable(self.movieOutputDirectory()): self.ui.recordMovieButton.checked = False return existingFiles = glob.glob( os.path.join(self.movieOutputDirectory(), '*.tiff')) if len(existingFiles): choice = QtGui.QMessageBox.question( app.getMainWindow(), 'Continue?', 'There are existing image files in the output directory. They will be deleted prior to recording. Continue?', QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No) if choice == QtGui.QMessageBox.No: self.ui.recordMovieButton.checked = False return for fileToRemove in existingFiles: os.remove(fileToRemove) self.fpsCounter.tick() self.startT = time.time() interval = int(round(1000.0 / self.captureRate())) self.recordTimer.setInterval(interval) self.recordTimer.start() def stopRecording(self): self.recordTimer.stop() if self.frameCount > 0: self.showEncodingDialog() def showEncodingDialog(self): msg = 'Recorded %d frames. For encoding, use this command line:\n\n\n' % self.frameCount msg += ' cd "%s"\n\n' % self.movieOutputDirectory() msg += ' avconv -r %d -i frame_%%07d.tiff \\\n' % self.captureRate() msg += ' -vcodec libx264 \\\n' msg += ' -preset slow \\\n' msg += ' -crf 18 \\\n' msg += ' output.mp4\n\n\n' app.showInfoMessage(msg, title='Recording Stopped') def updateViewSize(self): current = str(self.ui.viewSizeCombo.currentText) useCustom = (current == 'Custom') self.ui.viewWidthSpin.setEnabled(useCustom) self.ui.viewHeightSpin.setEnabled(useCustom) if useCustom: return else: viewSize = [ int(value) for value in current.split(' ')[0].split('x') ] self.ui.viewWidthSpin.value = viewSize[0] self.ui.viewHeightSpin.value = viewSize[1] def onViewSizeChanged(self): self.onLockViewSize() def viewSize(self): return self.ui.viewWidthSpin.value, self.ui.viewHeightSpin.value def lockViewSize(self): self.view.setFixedSize(*self.viewSize()) self.ui.viewSizeFrame.setEnabled(True) def unlockViewSize(self): self.ui.viewSizeFrame.setEnabled(False) qtwidgetMaxViewSize = 16777215 self.view.setFixedSize(qtwidgetMaxViewSize, qtwidgetMaxViewSize) def onLockViewSize(self): if self.ui.lockViewSizeCheck.checked: self.lockViewSize() else: self.unlockViewSize() def onRecordTimer(self): saveScreenshot(self.view, self.nextMovieFileName(), shouldRender=False) self.fpsCounter.tick() tNow = time.time() if tNow - self.startT > 1.0: self.startT = tNow self.ui.currentRateValueLabel.text = '%.1f' % self.fpsCounter.getAverageFPS( )
class ScreenGrabberPanel(object): def __init__(self, view): self.view = view loader = QtUiTools.QUiLoader() uifile = QtCore.QFile(':/ui/ddScreenGrabber.ui') assert uifile.open(uifile.ReadOnly) self.frameCount = 0 self.widget = loader.load(uifile) self.ui = WidgetDict(self.widget.children()) self.ui.lockViewSizeCheck.connect('clicked()', self.onLockViewSize) self.ui.screenshotOutputBrowseButton.connect('clicked()', self.onChooseScreenshotOutputDir) self.ui.movieOutputBrowseButton.connect('clicked()', self.onChooseMovieOutputDir) self.ui.saveScreenshotButton.connect('clicked()', self.onSaveScreenshot) self.ui.recordMovieButton.connect('clicked()', self.onRecordMovie) self.ui.viewSizeCombo.connect('currentIndexChanged(const QString&)', self.updateViewSize) self.ui.viewHeightSpin.connect('valueChanged(int)', self.onViewSizeChanged) self.ui.viewWidthSpin.connect('valueChanged(int)', self.onViewSizeChanged) self.updateViewSize() self.onLockViewSize() self.recordTimer = QtCore.QTimer() self.recordTimer.connect('timeout()', self.onRecordTimer) self.fpsCounter = FPSCounter() self.eventFilter = PythonQt.dd.ddPythonEventFilter() self.ui.scrollArea.installEventFilter(self.eventFilter) self.eventFilter.addFilteredEventType(QtCore.QEvent.Resize) self.eventFilter.connect('handleEvent(QObject*, QEvent*)', self.onEvent) def onEvent(self, obj, event): minSize = self.ui.scrollArea.widget().minimumSizeHint.width() + self.ui.scrollArea.verticalScrollBar().width self.ui.scrollArea.setMinimumWidth(minSize) def dateTimeString(self): return datetime.datetime.fromtimestamp(time.time()).strftime('%Y-%m-%d_%H:%M:%S') def movieOutputDirectory(self): return os.path.expanduser(self.ui.movieOutputDirectory.text) def screenshotOutputDirectory(self): return os.path.expanduser(self.ui.screenshotOutputDirectory.text) def captureRate(self): return self.ui.captureRateSpin.value def chooseDirectory(self): return QtGui.QFileDialog.getExistingDirectory(app.getMainWindow(), "Choose directory...", self.movieOutputDirectory()) def ensureDirectoryIsWritable(self, dirname): if not os.path.isdir(dirname): try: os.makedirs(dirname) except OSError: app.showErrorMessage('Error creating directory: %s' % dirname) return False if not os.access(dirname, os.W_OK | os.X_OK): app.showErrorMessage('Directory is not writable: %s' % dirname) return False return True def onChooseScreenshotOutputDir(self): newDir = self.chooseDirectory() if newDir: self.ui.screenshotOutputDirectory.text = newDir def onChooseMovieOutputDir(self): newDir = self.chooseDirectory() if newDir: self.ui.movieOutputDirectory.text = newDir def onSaveScreenshot(self): outDir = self.screenshotOutputDirectory() if not self.ensureDirectoryIsWritable(outDir): return filename = os.path.join(outDir, 'Screenshot-' + self.dateTimeString() + '.png') saveScreenshot(self.view, filename) app.getMainWindow().statusBar().showMessage('Saved: ' + filename, 2000) def nextMovieFileName(self): filename = os.path.join(self.movieOutputDirectory(), 'frame_%07d.tiff' % self.frameCount) self.frameCount += 1 return filename def updateRecordingStats(self): isRecordMode = self.ui.recordMovieButton.checked currentRate = 0.0 writeQueue = 0.0 self.ui.currentRateValueLabel.setText('%.1f' % currentRate) self.ui.writeQueueValueLabel.setText('%.1f' % currentRate) def isRecordMode(self): return self.ui.recordMovieButton.checked def updateRecordingButtons(self): isRecordMode = self.isRecordMode() self.ui.movieOutputDirectory.setEnabled(not isRecordMode) self.ui.movieOutputBrowseButton.setEnabled(not isRecordMode) self.ui.captureRateSpin.setEnabled(not isRecordMode) self.ui.captureRateLabel.setEnabled(not isRecordMode) self.ui.moveOutputDirectoryLabel.setEnabled(not isRecordMode) self.ui.currentRateLabel.setEnabled(isRecordMode) self.ui.currentRateValueLabel.setEnabled(isRecordMode) self.ui.writeQueueLabel.setEnabled(isRecordMode) self.ui.writeQueueValueLabel.setEnabled(isRecordMode) self.updateRecordingStats() def onRecordMovie(self): # Enforce even width number, otherwise avconv will fail _width = (self.view.width if self.view.width % 2 == 0 else self.view.width + 1) _height = (self.view.height if self.view.height % 2 == 0 else self.view.height + 1) self.view.setFixedSize(_width, _height) if self.isRecordMode(): self.startRecording() else: self.stopRecording() self.updateRecordingButtons() def startRecording(self): self.frameCount = 0 if not self.ensureDirectoryIsWritable(self.movieOutputDirectory()): self.ui.recordMovieButton.checked = False return existingFiles = glob.glob(os.path.join(self.movieOutputDirectory(), '*.tiff')) if len(existingFiles): choice = QtGui.QMessageBox.question(app.getMainWindow(), 'Continue?', 'There are existing image files in the output directory. They will be deleted prior to recording. Continue?', QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No) if choice == QtGui.QMessageBox.No: self.ui.recordMovieButton.checked = False return for fileToRemove in existingFiles: os.remove(fileToRemove) self.fpsCounter.tick() self.startT = time.time() interval = int(round(1000.0 / self.captureRate())) self.recordTimer.setInterval(interval) self.recordTimer.start() def stopRecording(self): self.recordTimer.stop() if self.frameCount > 0: self.showEncodingDialog() def showEncodingDialog(self): msg = 'Recorded %d frames. For encoding, use this command line:\n\n\n' % self.frameCount msg += ' cd "%s"\n\n' % self.movieOutputDirectory() msg += ' avconv -r %d -i frame_%%07d.tiff \\\n' % self.captureRate() msg += ' -vcodec libx264 \\\n' msg += ' -preset slow \\\n' msg += ' -crf 18 \\\n' msg += ' output.mp4\n\n\n' app.showInfoMessage(msg, title='Recording Stopped') def updateViewSize(self): current = str(self.ui.viewSizeCombo.currentText) useCustom = (current == 'Custom') self.ui.viewWidthSpin.setEnabled(useCustom) self.ui.viewHeightSpin.setEnabled(useCustom) if useCustom: return else: viewSize = [int(value) for value in current.split(' ')[0].split('x')] self.ui.viewWidthSpin.value = viewSize[0] self.ui.viewHeightSpin.value = viewSize[1] def onViewSizeChanged(self): self.onLockViewSize() def viewSize(self): return self.ui.viewWidthSpin.value, self.ui.viewHeightSpin.value def lockViewSize(self): self.view.setFixedSize(*self.viewSize()) self.ui.viewSizeFrame.setEnabled(True) def unlockViewSize(self): self.ui.viewSizeFrame.setEnabled(False) qtwidgetMaxViewSize = 16777215 self.view.setFixedSize(qtwidgetMaxViewSize, qtwidgetMaxViewSize) def onLockViewSize(self): if self.ui.lockViewSizeCheck.checked: self.lockViewSize() else: self.unlockViewSize() def onRecordTimer(self): saveScreenshot(self.view, self.nextMovieFileName(), shouldRender=False) self.fpsCounter.tick() tNow = time.time() if tNow - self.startT > 1.0: self.startT = tNow self.ui.currentRateValueLabel.text = '%.1f' % self.fpsCounter.getAverageFPS()