예제 #1
0
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        layout = QVBoxLayout()
        self.setLayout(layout)

        hlayout = QHBoxLayout()
        layout.addLayout(hlayout)

        self.attachTree = QAttachmentTree(self)
        self.attachTree.setMinimumHeight(240)
        hlayout.addWidget(self.attachTree)
        self.previewWidget = QImageView(self)
        self.previewWidget.setMinimumWidth(240)
        self.previewWidget.setMaximumWidth(360)
        self.previewWidget.hide()
        hlayout.addWidget(self.previewWidget)

        btnlayout = QHBoxLayout()
        layout.addLayout(btnlayout)

        self.add1Btn = QPushButton("&Add attachment(s) from file(s)...", self)
        self.add2Btn = QPushButton(
            "&Import existing attachment(s) from input...", self)
        self.removeBtn = QPushButton("&Remove selected attachment(s)", self)
        self.add1Btn.clicked.connect(self.attachTree.addFromFile)
        self.add2Btn.clicked.connect(self.attachTree.addFromInput)
        self.removeBtn.clicked.connect(self.attachTree.askDeleteSelected)

        btnlayout.addWidget(self.add1Btn)
        btnlayout.addWidget(self.add2Btn)
        btnlayout.addWidget(self.removeBtn)
        btnlayout.addStretch()
예제 #2
0
class QVideoPreview(QWidget):
    frameChanged = pyqtSignal(int, QTime)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.imageView = QImageView(self)
        self.frameSelection = QFrameSelect(self)
        self.frameSelection.frameSelectionChanged.connect(self.updateImage)
        layout = QVBoxLayout()
        self.setLayout(layout)
        layout.addWidget(self.imageView)
        layout.addWidget(self.frameSelection)

    def setSource(self, source):
        self._source = source
        self.frameSelection.setPtsTimeArray(source.pts_time)
        self.setFrameIndex(0)
        s, ms = divmod(int(1000 * source.pts_time[0]), 1000)
        m, s = divmod(s, 60)
        h, m = divmod(m, 60)
        self.updateImage(0, QTime(h, m, s, ms))

    def setFrameIndex(self, value):
        self.frameSelection.slider.setValue(value)

    def updateImage(self, n, t):
        try:
            frame = next(self._source.iterFrames(n, whence="framenumber"))

        except Exception:
            return

        self.imageView.setFrame(frame.to_image().convert("RGBA").toqpixmap())
        self.frameChanged.emit(n, t)
예제 #3
0
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        layout = QVBoxLayout()
        self.setLayout(layout)

        hlayout = QHBoxLayout()
        layout.addLayout(hlayout)
        self.selectionTree = AvailableAttachmentsTree(self)
        self.selectionTree.setMinimumHeight(240)
        self.previewWidget = QImageView(self)
        self.previewWidget.setMinimumWidth(240)
        self.previewWidget.setMaximumWidth(360)
        self.previewWidget.hide()
        hlayout.addWidget(self.selectionTree)
        hlayout.addWidget(self.previewWidget)

        hlayout = QHBoxLayout()
        layout.addLayout(hlayout)
        self.okayBtn = QPushButton("&OK", self)
        self.cancelBtn = QPushButton("&Cancel", self)

        hlayout.addStretch()
        hlayout.addWidget(self.okayBtn)
        hlayout.addWidget(self.cancelBtn)

        self.okayBtn.clicked.connect(self.applyAndClose)
        self.cancelBtn.clicked.connect(self.close)
        self.selectedAttachments = None
예제 #4
0
 def __init__(self, *args, **kwargs):
     super().__init__(*args, **kwargs)
     self.imageView = QImageView(self)
     self.frameSelection = QFrameSelect(self)
     self.frameSelection.frameSelectionChanged.connect(self.updateImage)
     layout = QVBoxLayout()
     self.setLayout(layout)
     layout.addWidget(self.imageView)
     layout.addWidget(self.frameSelection)
예제 #5
0
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        layout = QGridLayout()
        self.setLayout(layout)

        self.cropTop = QSpinBox(self)
        self.cropLeft = QSpinBox(self)
        self.cropRight = QSpinBox(self)
        self.cropBottom = QSpinBox(self)

        self.cropTop.setSingleStep(2)
        self.cropTop.setMinimum(0)
        self.cropTop.valueChanged.connect(self.setCropTop)

        self.cropBottom.setSingleStep(2)
        self.cropBottom.setMinimum(0)
        self.cropBottom.valueChanged.connect(self.setCropBottom)

        self.cropLeft.setSingleStep(2)
        self.cropLeft.setMinimum(0)
        self.cropLeft.valueChanged.connect(self.setCropLeft)

        self.cropRight.setSingleStep(2)
        self.cropRight.setMinimum(0)
        self.cropRight.valueChanged.connect(self.setCropRight)

        self.scrollArea = QScrollArea(self)
        self.scrollArea.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        self.scrollArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)

        self.imageView = QImageView(self)
        self.scrollArea.setWidget(self.imageView)
        self.imageView.setPaintHook(self._paintHook)

        tlayout = QHBoxLayout()
        tlayout.addStretch()
        tlayout.addWidget(self.cropTop)
        tlayout.addStretch()

        layout.addLayout(tlayout, 0, 1)
        layout.addWidget(self.cropLeft, 1, 0)
        layout.addWidget(self.scrollArea, 1, 1)
        layout.addWidget(self.cropRight, 1, 2)

        blayout = QHBoxLayout()
        blayout.addStretch()
        blayout.addWidget(self.cropBottom)
        blayout.addStretch()

        layout.addLayout(blayout, 2, 1)

        self.setFrameWidth(1920)
        self.setFrameHeight(720)
예제 #6
0
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setMaximumWidth(960)

        layout = QVBoxLayout()
        layout.setContentsMargins(4, 4, 4, 4)
        layout.setSpacing(4)
        self.setLayout(layout)

        self.imageView = QImageView(self)
        layout.addWidget(self.imageView)

        self.slider = Slider(self)
        self.slider.setOrientation(Qt.Horizontal)
        self.slider.valueChanged.connect(self.handleSliderChange)
        self.slider.setTickInterval(1)
        layout.addWidget(self.slider)

        hlayout = QHBoxLayout()
        layout.addLayout(hlayout)

        self.prevLabel = QLabel(self)
        self.currentIndex = QSpinBox(self)
        self.currentIndex.valueChanged.connect(self.handleIndexChange)
        self.currentTime = QTimeEdit(self)
        self.currentTime.setDisplayFormat("H:mm:ss.zzz")
        self.currentTime.timeChanged.connect(self.handleTimeChange)
        self.nextLabel = QLabel(self)

        hlayout.addWidget(self.prevLabel)
        hlayout.addStretch()
        hlayout.addWidget(QLabel("Frame index:", self))
        hlayout.addWidget(self.currentIndex)
        hlayout.addWidget(QLabel("Timestamp:", self))
        hlayout.addWidget(self.currentTime)
        hlayout.addStretch()
        hlayout.addWidget(self.nextLabel)

        hlayout = QHBoxLayout()
        hlayout.setContentsMargins(0, 0, 0, 0)
        hlayout.setSpacing(4)
        layout.addLayout(hlayout)

        self.okayBtn = QPushButton("&OK", self)
        self.cancelBtn = QPushButton("&Cancel", self)

        hlayout.addStretch()
        hlayout.addWidget(self.okayBtn)
        hlayout.addWidget(self.cancelBtn)
        self.setFrameSource(None, None)
예제 #7
0
    def _createControls(self):
        self.setWindowTitle("Configure Crossfade")

        layout = QVBoxLayout(self)
        self.setLayout(layout)

        self.sourceWidget = QWidget(self)

        self.source1Selection = self.createSourceControl(self.sourceWidget)
        self.source1Selection.setSelectFunc(self.isValidSource1)
        self.source1Selection.currentDataChanged.connect(self.setFilterSource1)
        self.source1Fade = QCheckBox("Fade Out", self)
        self.source1Fade.stateChanged.connect(self.setSource1Fade)

        self.source2Selection = self.createSourceControl(self.sourceWidget)
        self.source2Selection.setSelectFunc(self.isValidSource2)
        self.source2Selection.currentDataChanged.connect(self.setFilterSource2)
        self.source2Fade = QCheckBox("Fade In", self)
        self.source2Fade.stateChanged.connect(self.setSource2Fade)

        srclayout = QVBoxLayout()
        src1layout = QHBoxLayout()
        src2layout = QHBoxLayout()
        srclayout.addLayout(src1layout)
        srclayout.addLayout(src2layout)

        src1layout.addWidget(QLabel("Source 1: ", self.sourceWidget))
        src1layout.addWidget(self.source1Selection)
        src1layout.addWidget(self.source1Fade)

        src2layout.addWidget(QLabel("Source 2: ", self.sourceWidget))
        src2layout.addWidget(self.source2Selection)
        src2layout.addWidget(self.source2Fade)

        self.sourceWidget.setLayout(srclayout)
        layout.addWidget(self.sourceWidget)

        self.imageView = QImageView(self)
        self.frameSelect = QFrameSelect(self)
        self.frameSelect.frameSelectionChanged.connect(
            self.handleFrameSelectionChange)
        layout.addWidget(self.imageView)
        layout.addWidget(self.frameSelect)

        self._prepareDlgButtons()
예제 #8
0
    def _createControls(self):
        self.setWindowTitle("Configure Slice")

        layout = QVBoxLayout(self)
        self.setLayout(layout)

        self.sourceWidget = QWidget(self)
        self.sourceSelection = self.createSourceControl(self.sourceWidget)
        self.sourceSelection.currentDataChanged.connect(self.setFilterSource)

        srclayout = QHBoxLayout()
        srclayout.addWidget(QLabel("Source: ", self.sourceWidget))
        srclayout.addWidget(self.sourceSelection)

        self.sourceWidget.setLayout(srclayout)
        layout.addWidget(self.sourceWidget)

        hlayout = QHBoxLayout()
        layout.addLayout(hlayout)

        vlayout = QVBoxLayout()
        hlayout.addLayout(vlayout)
        self.startImageView = QImageView(self)
        self.startSlider = QTimeSlider(self)
        self.startSlider.timeSelectionChanged.connect(self.setStart)
        vlayout.addWidget(self.startImageView)
        vlayout.addWidget(self.startSlider)

        vlayout = QVBoxLayout()
        hlayout.addLayout(vlayout)
        self.endImageView = QImageView(self)
        self.endSlider = QTimeSlider(self)
        self.endSlider.timeSelectionChanged.connect(self.setEnd)
        vlayout.addWidget(self.endImageView)
        vlayout.addWidget(self.endSlider)

        self._prepareDlgButtons()
예제 #9
0
    def _createControls(self):
        self.setWindowTitle("Configure Hue/Saturation/Luminosity")

        layout = QVBoxLayout(self)
        self.setLayout(layout)

        self.sourceWidget = QWidget(self)
        self.sourceSelection = self.createSourceControl(self.sourceWidget)
        self.sourceSelection.currentDataChanged.connect(self.setFilterSource)

        srclayout = QHBoxLayout()
        srclayout.addWidget(QLabel("Source: ", self.sourceWidget))
        srclayout.addWidget(self.sourceSelection)

        self.sourceWidget.setLayout(srclayout)
        layout.addWidget(self.sourceWidget)

        self.imageView = QImageView(self)
        layout.addWidget(self.imageView)

        self.slider = QFrameSelect(self)
        self.slider.frameSelectionChanged.connect(self.loadFrame)
        layout.addWidget(self.slider)

        hueLabel = QLabel("Hue adjustment:", self)
        self.hueSpinBox = QSpinBox(self)
        self.hueSpinBox.setMinimum(-179)
        self.hueSpinBox.setMaximum(180)
        self.hueSpinBox.valueChanged.connect(
            self._handleHueSpinBoxValueChanged)

        satLabel = QLabel("Saturation factor:", self)
        self.satSpinBox = QDoubleSpinBox(self)
        self.satSpinBox.setDecimals(2)
        self.satSpinBox.setSingleStep(0.1)
        self.satSpinBox.setMinimum(0)
        self.satSpinBox.setMaximum(10)
        self.satSpinBox.valueChanged.connect(
            self._handleSatSpinBoxValueChanged)

        lumLabel = QLabel("Luminosity factor:", self)
        self.lumSpinBox = QDoubleSpinBox(self)
        self.lumSpinBox.setDecimals(2)
        self.lumSpinBox.setMinimum(0)
        self.lumSpinBox.setMaximum(10)
        self.lumSpinBox.valueChanged.connect(
            self._handleLumSpinBoxValueChanged)

        hlayout = QHBoxLayout()

        hlayout.addStretch()
        hlayout.addWidget(hueLabel)
        hlayout.addWidget(self.hueSpinBox)

        hlayout.addStretch()
        hlayout.addWidget(satLabel)
        hlayout.addWidget(self.satSpinBox)

        hlayout.addStretch()
        hlayout.addWidget(lumLabel)
        hlayout.addWidget(self.lumSpinBox)

        hlayout.addStretch()

        layout.addLayout(hlayout)

        self._prepareDlgButtons()
예제 #10
0
class QHSLAdjDlg(QFilterConfig):
    allowedtypes = ("video",)

    def _createControls(self):
        self.setWindowTitle("Configure Hue/Saturation/Luminosity")

        layout = QVBoxLayout(self)
        self.setLayout(layout)

        self.sourceWidget = QWidget(self)
        self.sourceSelection = self.createSourceControl(self.sourceWidget)
        self.sourceSelection.currentDataChanged.connect(self.setFilterSource)

        srclayout = QHBoxLayout()
        srclayout.addWidget(QLabel("Source: ", self.sourceWidget))
        srclayout.addWidget(self.sourceSelection)

        self.sourceWidget.setLayout(srclayout)
        layout.addWidget(self.sourceWidget)

        self.imageView = QImageView(self)
        layout.addWidget(self.imageView)

        self.slider = QFrameSelect(self)
        self.slider.frameSelectionChanged.connect(self.loadFrame)
        layout.addWidget(self.slider)

        hueLabel = QLabel("Hue adjustment:", self)
        self.hueSpinBox = QSpinBox(self)
        self.hueSpinBox.setMinimum(-179)
        self.hueSpinBox.setMaximum(180)
        self.hueSpinBox.valueChanged.connect(
            self._handleHueSpinBoxValueChanged)

        satLabel = QLabel("Saturation factor:", self)
        self.satSpinBox = QDoubleSpinBox(self)
        self.satSpinBox.setDecimals(2)
        self.satSpinBox.setSingleStep(0.1)
        self.satSpinBox.setMinimum(0)
        self.satSpinBox.setMaximum(10)
        self.satSpinBox.valueChanged.connect(
            self._handleSatSpinBoxValueChanged)

        lumLabel = QLabel("Luminosity factor:", self)
        self.lumSpinBox = QDoubleSpinBox(self)
        self.lumSpinBox.setDecimals(2)
        self.lumSpinBox.setMinimum(0)
        self.lumSpinBox.setMaximum(10)
        self.lumSpinBox.valueChanged.connect(
            self._handleLumSpinBoxValueChanged)

        hlayout = QHBoxLayout()

        hlayout.addStretch()
        hlayout.addWidget(hueLabel)
        hlayout.addWidget(self.hueSpinBox)

        hlayout.addStretch()
        hlayout.addWidget(satLabel)
        hlayout.addWidget(self.satSpinBox)

        hlayout.addStretch()
        hlayout.addWidget(lumLabel)
        hlayout.addWidget(self.lumSpinBox)

        hlayout.addStretch()

        layout.addLayout(hlayout)

        self._prepareDlgButtons()

    def createNewFilterInstance(self):
        return HSLAdjust()

    def _resetControls(self):
        self.hueSpinBox.blockSignals(True)
        self.hueSpinBox.setValue(self.filtercopy.dh)
        self.hueSpinBox.blockSignals(False)

        self.satSpinBox.blockSignals(True)
        self.satSpinBox.setValue(self.filtercopy.sfactor)
        self.satSpinBox.blockSignals(False)

        self.lumSpinBox.blockSignals(True)
        self.lumSpinBox.setValue(self.filtercopy.lgamma)
        self.lumSpinBox.blockSignals(False)

        if self.filtercopy.prev is not None:
            self.slider.setPtsTimeArray(self.filtercopy.prev.pts_time)
            self.loadFrame(self.slider.slider.value(), QTime())

    def _handleHueSpinBoxValueChanged(self, value):
        self.filtercopy.dh = value
        self.isModified()
        self.loadFrame(self.slider.slider.value(), None)

    def _handleSatSpinBoxValueChanged(self, value):
        self.filtercopy.sfactor = value
        self.isModified()
        self.loadFrame(self.slider.slider.value(), None)

    def _handleLumSpinBoxValueChanged(self, value):
        self.filtercopy.sfactor = value
        self.isModified()
        self.loadFrame(self.slider.slider.value(), None)

    @pyqtSlot(int, QTime)
    def loadFrame(self, n, t):
        if self.filtercopy.prev is not None:
            frame = next(self.filtercopy.iterFrames(n, whence="framenumber"))
            im = frame.to_image()
            pixmap = im.convert("RGBA").toqpixmap()
            self.imageView.setFrame(pixmap)

    def _prevChanged(self, source):
        self.slider.setPtsTimeArray(source.pts_time)
        self.loadFrame(self.slider.slider.value(),
                       self.slider.currentTime.time())
예제 #11
0
class FrameSelectWidget(QWidget):
    frameSelectionChanged = pyqtSignal(int, QTime)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setMaximumWidth(960)

        layout = QVBoxLayout()
        layout.setContentsMargins(4, 4, 4, 4)
        layout.setSpacing(4)
        self.setLayout(layout)

        self.imageView = QImageView(self)
        layout.addWidget(self.imageView)

        self.slider = Slider(self)
        self.slider.setOrientation(Qt.Horizontal)
        self.slider.valueChanged.connect(self.handleSliderChange)
        self.slider.setTickInterval(1)
        layout.addWidget(self.slider)

        hlayout = QHBoxLayout()
        layout.addLayout(hlayout)

        self.prevLabel = QLabel(self)
        self.currentIndex = QSpinBox(self)
        self.currentIndex.valueChanged.connect(self.handleIndexChange)
        self.currentTime = QTimeEdit(self)
        self.currentTime.setDisplayFormat("H:mm:ss.zzz")
        self.currentTime.timeChanged.connect(self.handleTimeChange)
        self.nextLabel = QLabel(self)

        hlayout.addWidget(self.prevLabel)
        hlayout.addStretch()
        hlayout.addWidget(QLabel("Frame index:", self))
        hlayout.addWidget(self.currentIndex)
        hlayout.addWidget(QLabel("Timestamp:", self))
        hlayout.addWidget(self.currentTime)
        hlayout.addStretch()
        hlayout.addWidget(self.nextLabel)

        hlayout = QHBoxLayout()
        hlayout.setContentsMargins(0, 0, 0, 0)
        hlayout.setSpacing(4)
        layout.addLayout(hlayout)

        self.okayBtn = QPushButton("&OK", self)
        self.cancelBtn = QPushButton("&Cancel", self)

        hlayout.addStretch()
        hlayout.addWidget(self.okayBtn)
        hlayout.addWidget(self.cancelBtn)
        self.setFrameSource(None, None)

    def sizeHint(self):
        widgetHeights = (
            self.slider.height()
            + max([self.okayBtn.height(), self.cancelBtn.height()])
            + max([self.currentIndex.height(), self.currentTime.height()])
        )

        if isinstance(self.filters, BaseFilter):
            w, h = self.filters.width, self.filters.height
            sar = self.filters.sar

        elif isinstance(self.source, (Track, BaseFilter)):
            w, h = self.source.width, self.source.height
            sar = self.source.sar

        else:
            return super().sizeHint()

        dar = w*sar/h
        W, H = min([
            max([(w, h/sar), (w*sar, h)]),
            (960 - 8, (960 - 8)/dar),
            ((720 - 20 - widgetHeights)*dar, 720 - 20 - widgetHeights)
        ])

        return QSize(int(W + 8), int(H + 20 + widgetHeights))

    def setFrameSource(self, source, filters=None):
        self.source = source

        if source is not None:
            self.slider.setMaximum(self.source.framecount - 1)
            self.currentIndex.setMaximum(self.source.framecount - 1)
            self.filters = filters

            if self.filters is not None:
                lastpts = self.filters.pts_time[-1]
                self.slider.setSnapValues(self.filters.keyframes)

            else:
                lastpts = self.source.pts_time[-1]

                if isinstance(self.source, BaseFilter):
                    self.slider.setSnapValues(self.source.keyframes)

                else:
                    self.slider.setSnapValues(None)

            ms = int(lastpts*1000 + 0.5)
            s, ms = divmod(ms, 1000)
            m, s = divmod(s, 60)
            h, m = divmod(m, 60)
            self.currentTime.setMaximumTime(QTime(h, m, s, ms))
            self.slider.setValue(0)
            self._frameChange(0)

        else:
            self.slider.setSnapValues(None)

        self.update()

    def handleIndexChange(self, n):
        self._frameChange(n)

        self.slider.blockSignals(True)
        self.slider.setValue(n)
        self.slider.blockSignals(False)

    def handleSliderChange(self, n):
        self._frameChange(n)

        self.currentIndex.blockSignals(True)
        self.currentIndex.setValue(n)
        self.currentIndex.blockSignals(False)

    def _frameChange(self, n):
        if self.source is not None:
            if self.filters is not None:
                nn = n
                m = -1

                while m < 0 and nn < len(self.filters.indexMap):
                    m = self.filters.indexMap[nn]
                    nn += 1

                try:
                    pts = self.filters.pts_time[m]

                except Exception:
                    pts = None

                try:
                    frame = next(self.filters.iterFrames(
                        m, whence="framenumber"))

                except StopIteration:
                    frame = None

                sar = self.filters.sar

            else:
                try:
                    pts = self.source.pts_time[n]

                except IndexError:
                    pts = None

                try:
                    frame = next(self.source.iterFrames(
                        n, whence="framenumber"))

                except StopIteration:
                    frame = None

                sar = self.source.sar

            if frame is not None:
                im = frame.to_image()
                self.imageView.setFrame(im.toqpixmap())
                self.imageView.setSar(sar)

            if pts is not None:
                ms = int(pts*1000+0.5)
                s, ms = divmod(ms, 1000)
                m, s = divmod(s, 60)
                h, m = divmod(m, 60)

                self.currentTime.blockSignals(True)
                self.currentTime.setTime(QTime(h, m, s, ms))
                self.currentTime.blockSignals(False)

            self.frameSelectionChanged.emit(n, self.currentTime.time())

    def handleTimeChange(self, t):
        if self.source is not None:
            if self.filters is not None:
                pts = t.msecsSinceStartOfDay()/1000
                n = self.filters.frameIndexFromPtsTime(pts, dir="-")

            else:
                pts = t.msecsSinceStartOfDay()/1000
                n = self.source.frameIndexFromPtsTime(pts, dir="-")

            self.slider.blockSignals(True)
            self.slider.setValue(n)
            self.slider.blockSignals(False)

            self.currentIndex.blockSignals(True)
            self.currentIndex.setValue(n)
            self.currentIndex.blockSignals(False)

            self._frameChange(n)
예제 #12
0
class QCrossFade(QFilterConfig):
    allowedtypes = ("video", "audio")

    def _createControls(self):
        self.setWindowTitle("Configure Crossfade")

        layout = QVBoxLayout(self)
        self.setLayout(layout)

        self.sourceWidget = QWidget(self)

        self.source1Selection = self.createSourceControl(self.sourceWidget)
        self.source1Selection.setSelectFunc(self.isValidSource1)
        self.source1Selection.currentDataChanged.connect(self.setFilterSource1)
        self.source1Fade = QCheckBox("Fade Out", self)
        self.source1Fade.stateChanged.connect(self.setSource1Fade)

        self.source2Selection = self.createSourceControl(self.sourceWidget)
        self.source2Selection.setSelectFunc(self.isValidSource2)
        self.source2Selection.currentDataChanged.connect(self.setFilterSource2)
        self.source2Fade = QCheckBox("Fade In", self)
        self.source2Fade.stateChanged.connect(self.setSource2Fade)

        srclayout = QVBoxLayout()
        src1layout = QHBoxLayout()
        src2layout = QHBoxLayout()
        srclayout.addLayout(src1layout)
        srclayout.addLayout(src2layout)

        src1layout.addWidget(QLabel("Source 1: ", self.sourceWidget))
        src1layout.addWidget(self.source1Selection)
        src1layout.addWidget(self.source1Fade)

        src2layout.addWidget(QLabel("Source 2: ", self.sourceWidget))
        src2layout.addWidget(self.source2Selection)
        src2layout.addWidget(self.source2Fade)

        self.sourceWidget.setLayout(srclayout)
        layout.addWidget(self.sourceWidget)

        self.imageView = QImageView(self)
        self.frameSelect = QFrameSelect(self)
        self.frameSelect.frameSelectionChanged.connect(
            self.handleFrameSelectionChange)
        layout.addWidget(self.imageView)
        layout.addWidget(self.frameSelect)

        self._prepareDlgButtons()

    def _resetSourceModels(self):
        self._resetSourceModel(self.source1Selection)
        self._resetSourceModel(self.source2Selection)

    @pyqtSlot(int, QTime)
    def handleFrameSelectionChange(self, n, t):
        self.setFrame(n)

    def setSource1Fade(self, value):
        if value:
            self.filtercopy.flags &= ~1

        else:
            self.filtercopy.flags |= 1

        if (self.filtercopy.prev is not None
                and self.filtercopy.prev.type == "video"):
            self.setFrame(self.frameSelect.slider.value())

        self.isModified()

    def setSource2Fade(self, value):
        if value:
            self.filtercopy.flags &= ~2

        else:
            self.filtercopy.flags |= 2

        if (self.filtercopy.prev is not None
                and self.filtercopy.prev.type == "video"):
            self.setFrame(self.frameSelect.slider.value())

        self.isModified()

    def setFrame(self, n):
        try:
            frame = next(self.filtercopy.iterFrames(n, whence="framenumber"))

        except StopIteration:
            self.imageView.setFrame(
                QPixmap(self.filtercopy.width, self.filtercopy.height))
            return

        im = frame.to_image()
        pixmap = im.convert("RGBA").toqpixmap()
        self.imageView.setFrame(pixmap)

    def createNewFilterInstance(self):
        return CrossFade()

    def _resetSourceControls(self):
        self._showSourceControls(self.inputFiles or self.availableFilters)
        self._setSourceSelection(self.source1Selection,
                                 self.filtercopy.source1)
        self._setSourceSelection(self.source2Selection,
                                 self.filtercopy.source2)

    def _resetControls(self):
        if self.filtercopy is not None:
            self.source1Fade.blockSignals(True)
            self.source1Fade.setCheckState(0 if (
                1 & self.filtercopy.flags) else 2)
            self.source1Fade.blockSignals(False)

            self.source2Fade.blockSignals(True)
            self.source2Fade.setCheckState(0 if (
                2 & self.filtercopy.flags) else 2)
            self.source2Fade.blockSignals(False)

            self.frameSelect.setVisible(self.filtercopy.type == "video")
            self.imageView.setVisible(self.filtercopy.type == "video")

            if self.filtercopy.type == "video":
                self.frameSelect.setPtsTimeArray(self.filtercopy.pts_time)
                self.setFrame(0)

            self.setEnabled(True)

        else:
            self.source1Fade.blockSignals(True)
            self.source1Fade.setCheckState(2)
            self.source1Fade.blockSignals(False)

            self.source2Fade.blockSignals(True)
            self.source2Fade.setCheckState(2)
            self.source2Fade.blockSignals(False)

            self.frameSelect.setVisible(False)
            self.imageView.setVisible(False)
            self.setEnabled(False)

    def setFilterSource1(self, source):
        self.imageView.setVisible(source is not None
                                  and source.type == "video")
        self.filtercopy.source1 = source
        self.isModified()

        if (source is not None and self.filtercopy.source2 is not None
                and source.type == "video"):
            self.frameSelect.setPtsTimeArray(source.pts_time)
            self.setFrame(self.frameSelect.slider.value())

    def setFilterSource2(self, source):
        self.imageView.setVisible(source is not None
                                  and source.type == "video")
        self.filtercopy.source2 = source
        self.isModified()

        if (source is not None and self.filtercopy.source1 is not None
                and source.type == "video"):
            self.frameSelect.setPtsTimeArray(source.pts_time)
            self.setFrame(self.frameSelect.slider.value())

    def isValidSource1(self, other):
        if other is self.filter:
            return False

        if (isinstance(other, BaseFilter)
                and self.filter in other.dependencies):
            return False

        if self.filtercopy.source2 is None:
            return other.type in ("video", "audio")

        if other.type is None:
            return True

        elif self.filtercopy.source2.type == "video":
            return (self.filtercopy.source2.framecount == other.framecount
                    and self.filtercopy.source2.width == other.width
                    and self.filtercopy.source2.height == other.height
                    and (abs(self.filtercopy.source2.pts_time - other.pts_time)
                         < 0.008).all())

        elif self.filtercopy.source2.type == "audio":
            return (self.filtercopy.source2.channels == other.channels
                    and abs(self.filtercopy.source2.duration - other.duration)
                    < 0.00001)

    def isValidSource2(self, other):
        if other is self.filter:
            return False

        if isinstance(other, BaseFilter) and self.filter in other.dependencies:
            return False

        if other.type is None:
            return True

        if self.filtercopy.source1 is None:
            return other.type in ("video", "audio")

        elif self.filtercopy.source1.type == "video":
            return (self.filtercopy.source1.framecount == other.framecount
                    and self.filtercopy.source1.width == other.width
                    and self.filtercopy.source1.height == other.height
                    and (abs(self.filtercopy.source1.pts_time - other.pts_time)
                         < 0.008).all())

        elif self.filtercopy.source1.type == "audio":
            return (self.filtercopy.source1.channels == other.channels
                    and abs(self.filtercopy.source1.duration - other.duration)
                    < 0.00001)
예제 #13
0
class QCrop(QWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        layout = QGridLayout()
        self.setLayout(layout)

        self.cropTop = QSpinBox(self)
        self.cropLeft = QSpinBox(self)
        self.cropRight = QSpinBox(self)
        self.cropBottom = QSpinBox(self)

        self.cropTop.setSingleStep(2)
        self.cropTop.setMinimum(0)
        self.cropTop.valueChanged.connect(self.setCropTop)

        self.cropBottom.setSingleStep(2)
        self.cropBottom.setMinimum(0)
        self.cropBottom.valueChanged.connect(self.setCropBottom)

        self.cropLeft.setSingleStep(2)
        self.cropLeft.setMinimum(0)
        self.cropLeft.valueChanged.connect(self.setCropLeft)

        self.cropRight.setSingleStep(2)
        self.cropRight.setMinimum(0)
        self.cropRight.valueChanged.connect(self.setCropRight)

        self.scrollArea = QScrollArea(self)
        self.scrollArea.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        self.scrollArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)

        self.imageView = QImageView(self)
        self.scrollArea.setWidget(self.imageView)
        self.imageView.setPaintHook(self._paintHook)

        tlayout = QHBoxLayout()
        tlayout.addStretch()
        tlayout.addWidget(self.cropTop)
        tlayout.addStretch()

        layout.addLayout(tlayout, 0, 1)
        layout.addWidget(self.cropLeft, 1, 0)
        layout.addWidget(self.scrollArea, 1, 1)
        layout.addWidget(self.cropRight, 1, 2)

        blayout = QHBoxLayout()
        blayout.addStretch()
        blayout.addWidget(self.cropBottom)
        blayout.addStretch()

        layout.addLayout(blayout, 2, 1)

        self.setFrameWidth(1920)
        self.setFrameHeight(720)

    def setFrameWidth(self, width):
        self._width = width
        self.cropRight.setMaximum(width - self.cropLeft.value() - 2)
        self.cropLeft.setMaximum(width - self.cropRight.value() - 2)

    def setFrameHeight(self, height):
        self._height = height
        self.cropTop.setMaximum(height - self.cropBottom.value() - 2)
        self.cropBottom.setMaximum(height - self.cropTop.value() - 2)

    def frameWidth(self):
        return self._width

    def frameHeight(self):
        return self._height

    @pyqtSlot(int)
    def setCropTop(self, croptop):
        self.cropBottom.setMaximum(self.frameHeight() - croptop - 2)
        self.imageView.update()

    @pyqtSlot(int)
    def setCropBottom(self, cropbottom):
        self.cropTop.setMaximum(self.frameHeight() - cropbottom - 2)
        self.imageView.update()

    @pyqtSlot(int)
    def setCropLeft(self, cropleft):
        self.cropRight.setMaximum(self.frameWidth() - cropleft - 2)
        self.imageView.update()

    @pyqtSlot(int)
    def setCropRight(self, cropright):
        self.cropLeft.setMaximum(self.frameWidth() - cropright - 2)
        self.imageView.update()

    def setFrame(self, frame):
        self.setFrameWidth(max(2, frame.width()))
        self.setFrameHeight(max(2, frame.height()))
        self.imageView.setFrame(frame)
        self.imageView.resize(frame.width(), frame.height())

    def _paintHook(self, widget, event, painter):
        w, h = widget.pixmap().width(), widget.pixmap().height()
        dar = w/h

        W = widget.width()
        H = widget.height()

        WW, HH = min([(W, W/dar), (H*dar, H)])

        if WW < W:
            x0, y0 = ((W - WW)/2, 0)

        else:
            x0, y0 = (0, (H - HH)/2)

        zoom = WW/w

        if widget.pixmap() is not None:
            if zoom >= 8:
                pen = QPen(Qt.gray, 1)
                painter.setPen(pen)

                for j in range(0, w + 1):
                    J = j*zoom
                    painter.drawLine(x0 + J, y0, x0 + J, y0 + H)

                for j in range(0, h + 1):
                    J = j*zoom
                    painter.drawLine(x0, y0 + J, x0 + W, y0 + J)

        pen = QPen(Qt.red, 1)
        painter.setPen(pen)

        j = k = int(zoom < 8)

        painter.drawLine(x0 + self.cropLeft.value()*zoom - j,
                         y0, x0 + self.cropLeft.value()*zoom - j, y0 + H)
        painter.drawLine(x0 + W - self.cropRight.value()*zoom,
                         y0, x0 + W - self.cropRight.value()*zoom, y0 + H)
        painter.drawLine(x0, y0 + self.cropTop.value()*zoom - k,
                         x0 + W, y0 + self.cropTop.value()*zoom - k)
        painter.drawLine(x0, y0 + H - self.cropBottom.value()
                         * zoom, x0 + W, y0 + H - self.cropBottom.value()*zoom)
예제 #14
0
class QSlice(QFilterConfig):
    allowedtypes = ("video", "audio", "subtitle")

    def _createControls(self):
        self.setWindowTitle("Configure Slice")

        layout = QVBoxLayout(self)
        self.setLayout(layout)

        self.sourceWidget = QWidget(self)
        self.sourceSelection = self.createSourceControl(self.sourceWidget)
        self.sourceSelection.currentDataChanged.connect(self.setFilterSource)

        srclayout = QHBoxLayout()
        srclayout.addWidget(QLabel("Source: ", self.sourceWidget))
        srclayout.addWidget(self.sourceSelection)

        self.sourceWidget.setLayout(srclayout)
        layout.addWidget(self.sourceWidget)

        hlayout = QHBoxLayout()
        layout.addLayout(hlayout)

        vlayout = QVBoxLayout()
        hlayout.addLayout(vlayout)
        self.startImageView = QImageView(self)
        self.startSlider = QTimeSlider(self)
        self.startSlider.timeSelectionChanged.connect(self.setStart)
        vlayout.addWidget(self.startImageView)
        vlayout.addWidget(self.startSlider)

        vlayout = QVBoxLayout()
        hlayout.addLayout(vlayout)
        self.endImageView = QImageView(self)
        self.endSlider = QTimeSlider(self)
        self.endSlider.timeSelectionChanged.connect(self.setEnd)
        vlayout.addWidget(self.endImageView)
        vlayout.addWidget(self.endSlider)

        self._prepareDlgButtons()

    @pyqtSlot(int, float)
    def setStart(self, n, t):
        self.filtercopy.startpts = t
        self.updateStartImage()
        self.isModified()

    @pyqtSlot(int, float)
    def setEnd(self, n, t):
        if self.filtercopy.prev is not None:
            if abs(t - self.filtercopy.prev.duration) < 10**-9:
                self.filtercopy.endpts = None

            else:
                self.filtercopy.endpts = t

        else:
            self.filtercopy.endpts = t

        self.updateEndImage()
        self.isModified()

    def updateStartImage(self):
        if (self.filtercopy.prev is not None
                and self.filtercopy.prev.type == "video"):
            n = search(self.filtercopy.prev.pts_time,
                       self.filtercopy.startpts + 0.0005, "-")

            try:
                frame = next(self.filtercopy.prev.iterFrames(
                    n, whence="framenumber"))

            except StopIteration:
                self.startImageView.setFrame(
                    QPixmap(self.filtercopy.prev.width,
                            self.filtercopy.prev.height))
                return

            im = frame.to_image()
            pixmap = im.convert("RGBA").toqpixmap()
            self.startImageView.setFrame(pixmap)

    def updateEndImage(self):
        if (self.filtercopy.prev is not None
                and self.filtercopy.prev.type == "video"):
            if self.filtercopy.endpts is not None:
                n = search(self.filtercopy.prev.pts_time,
                           self.filtercopy.endpts + 0.0005, "-")

                try:
                    frame = next(self.filtercopy.prev.iterFrames(
                        n, whence="framenumber"))

                except StopIteration:
                    self.endImageView.setFrame(
                        QPixmap(self.filtercopy.prev.width,
                                self.filtercopy.prev.height))
                    return

                im = frame.to_image()
                pixmap = im.convert("RGBA").toqpixmap()
                self.endImageView.setFrame(pixmap)

            else:
                self.endImageView.setFrame(
                    QPixmap(self.filtercopy.prev.width,
                            self.filtercopy.prev.height))

    def createNewFilterInstance(self):
        return Slice()

    def _prevChanged(self, source):
        self._resetControlMaximums()

        self.startSlider.spinBox.setVisible(source.type == "video")
        self.startSlider.slider.setVisible(source.type == "video")
        self.startImageView.setVisible(source.type == "video")

        self.endSlider.spinBox.setVisible(source.type == "video")
        self.endSlider.slider.setVisible(source.type == "video")
        self.endImageView.setVisible(source.type == "video")

    def _resetControlMaximums(self):
        if self.filtercopy.prev is not None:
            pts_time = concatenate(
                (self.filtercopy.prev.pts_time,
                 [float(self.filtercopy.prev.duration)]))
            self.startSlider.blockSignals(True)
            self.startSlider.setPtsTimeArray(pts_time)
            self.startSlider.blockSignals(False)

            self.endSlider.blockSignals(True)
            self.endSlider.setPtsTimeArray(pts_time)
            self.endSlider.blockSignals(False)

            if self.filtercopy.prev.type == "subtitle":
                self.startSlider.timeSelect.setMinimum(0)
                self.endSlider.timeSelect.setMinimum(0)
                self.startSlider.timeSelect.setMaximum(24*3600)
                self.endSlider.timeSelect.setMaximum(24*3600)

    def _resetControls(self):
        if self.filtercopy is not None:
            self._resetControlMaximums()

            self.startSlider.blockSignals(True)
            self.startSlider.timeSelect.setValue(self.filtercopy.startpts)
            self.startSlider.blockSignals(False)

            self.endSlider.blockSignals(True)

            if self.filtercopy.endpts is not None:
                self.endSlider.timeSelect.setValue(self.filtercopy.endpts)

            elif self.filtercopy.prev is not None:
                if self.filtercopy.prev.type in ("video", "audio"):
                    self.endSlider.timeSelect.setValue(
                        float(self.filtercopy.prev.duration))

                else:
                    self.endSlider.timeSelect.setValue(24*3600)

            self.endSlider.blockSignals(False)

            self.updateStartImage()
            self.updateEndImage()

        else:
            self.startSlider.setPtsTimeArray(numpy.array([0]))
            self.endSlider.setPtsTimeArray(numpy.array([0]))
예제 #15
0
class QAttachmentsWidget(QWidget):
    contentsModified = pyqtSignal()

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        layout = QVBoxLayout()
        self.setLayout(layout)

        hlayout = QHBoxLayout()
        layout.addLayout(hlayout)

        self.attachTree = QAttachmentTree(self)
        self.attachTree.setMinimumHeight(240)
        hlayout.addWidget(self.attachTree)
        self.previewWidget = QImageView(self)
        self.previewWidget.setMinimumWidth(240)
        self.previewWidget.setMaximumWidth(360)
        self.previewWidget.hide()
        hlayout.addWidget(self.previewWidget)

        btnlayout = QHBoxLayout()
        layout.addLayout(btnlayout)

        self.add1Btn = QPushButton("&Add attachment(s) from file(s)...", self)
        self.add2Btn = QPushButton(
            "&Import existing attachment(s) from input...", self)
        self.removeBtn = QPushButton("&Remove selected attachment(s)", self)
        self.add1Btn.clicked.connect(self.attachTree.addFromFile)
        self.add2Btn.clicked.connect(self.attachTree.addFromInput)
        self.removeBtn.clicked.connect(self.attachTree.askDeleteSelected)

        btnlayout.addWidget(self.add1Btn)
        btnlayout.addWidget(self.add2Btn)
        btnlayout.addWidget(self.removeBtn)
        btnlayout.addStretch()

    def setData(self, tags, attachments):
        self.attachTree.setData(tags, attachments)

        if attachments is not None:
            self.attachTree.model().dataChanged.connect(self.contentsModified)
            self.attachTree.model().rowsInserted.connect(self.contentsModified)
            self.attachTree.model().rowsRemoved.connect(self.contentsModified)
            self.attachTree.model().rowsMoved.connect(self.contentsModified)
            self.attachTree.selectionModel().selectionChanged.connect(
                self.handleSelectionChanged)
            self.handleSelectionChanged()

    def handleSelectionChanged(self):
        self.removeBtn.setEnabled(
            len(self.attachTree.selectionModel().selectedRows()) > 0)

        selected = self.attachTree.currentIndex().data(Qt.UserRole)

        if (isinstance(selected, AttachedFile)
                and selected.mimeType in ("image/jpeg", "image/png")):
            try:
                if isinstance(selected.source, AttachmentRef):
                    with io.BytesIO() as b:
                        b.write(b"".join(selected.source.attachment.fileData))
                        b.seek(0)
                        im = Image.open(b).convert("RGBA")

                else:
                    im = Image.open(selected.source).convert("RGBA")

            except Exception:
                self.previewWidget.hide()
                return

            self.previewWidget.setFrame(im.toqpixmap())
            self.previewWidget.show()

        else:
            self.previewWidget.hide()
예제 #16
0
class AvailableAttachmentsSelection(QDialog):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        layout = QVBoxLayout()
        self.setLayout(layout)

        hlayout = QHBoxLayout()
        layout.addLayout(hlayout)
        self.selectionTree = AvailableAttachmentsTree(self)
        self.selectionTree.setMinimumHeight(240)
        self.previewWidget = QImageView(self)
        self.previewWidget.setMinimumWidth(240)
        self.previewWidget.setMaximumWidth(360)
        self.previewWidget.hide()
        hlayout.addWidget(self.selectionTree)
        hlayout.addWidget(self.previewWidget)

        hlayout = QHBoxLayout()
        layout.addLayout(hlayout)
        self.okayBtn = QPushButton("&OK", self)
        self.cancelBtn = QPushButton("&Cancel", self)

        hlayout.addStretch()
        hlayout.addWidget(self.okayBtn)
        hlayout.addWidget(self.cancelBtn)

        self.okayBtn.clicked.connect(self.applyAndClose)
        self.cancelBtn.clicked.connect(self.close)
        self.selectedAttachments = None

    def handleSelectionChanged(self):
        self.okayBtn.setEnabled(
            len(self.selectionTree.selectionModel().selectedRows()) > 0)

        selected = self.selectionTree.currentIndex().data(Qt.UserRole)

        if selected.mimeType in ("image/jpeg", "image/png"):
            try:
                with io.BytesIO() as b:
                    b.write(b"".join(selected.fileData))
                    b.seek(0)
                    im = Image.open(b).convert("RGBA")

            except Exception:
                self.previewWidget.hide()
                return

            self.previewWidget.setFrame(im.toqpixmap())
            self.previewWidget.show()

        else:
            self.previewWidget.hide()

    def applyAndClose(self):
        self.selectedAttachments = [
            (index.parent().data(Qt.UserRole), index.data(Qt.UserRole))
            for index in self.selectionTree.selectionModel().selectedRows()
        ]
        self.done(1)
        self.close()

    def setInputFiles(self, input_files):
        self.selectionTree.setInputFiles(input_files)
        self.selectionTree.selectionModel().selectionChanged.connect(
            self.handleSelectionChanged)
        self.okayBtn.setEnabled(len(self.selectionTree.selectedIndexes()) > 0)