From 7da639ea0fd02182a860ff7ddfd40077276fe9a6 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Mardelle Date: Mon, 25 Oct 2010 21:58:06 +0000 Subject: [PATCH] Improved performance for blackmagic picture grab and various usability improvements in stopmotion widget svn path=/trunk/kdenlive/; revision=5052 --- src/blackmagic/capture.cpp | 53 +++++++++++++++++++++------------ src/blackmagic/capture.h | 8 ++++- src/stopmotion/capturehandler.h | 2 +- src/stopmotion/stopmotion.cpp | 38 ++++++++++++++++++----- src/stopmotion/stopmotion.h | 10 ++++++- src/v4l/v4lcapture.cpp | 2 +- src/v4l/v4lcapture.h | 2 +- 7 files changed, 84 insertions(+), 31 deletions(-) diff --git a/src/blackmagic/capture.cpp b/src/blackmagic/capture.cpp index 6aa13cad..8afb4d25 100644 --- a/src/blackmagic/capture.cpp +++ b/src/blackmagic/capture.cpp @@ -315,6 +315,29 @@ ULONG DeckLinkCaptureDelegate::Release(void) return (ULONG)m_refCount; } +void DeckLinkCaptureDelegate::slotProcessFrame() +{ + if (m_framesList.isEmpty()) return; + IDeckLinkVideoInputFrame* videoFrame = m_framesList.takeFirst(); + QString capturePath = m_framePath.takeFirst(); + void *frameBytes; + videoFrame->GetBytes(&frameBytes); + if (capturePath.endsWith("raw")) { + // Save as raw uyvy422 imgage + videoOutputFile = open(capturePath.toUtf8().constData(), O_WRONLY | O_CREAT/*|O_TRUNC*/, 0664); + write(videoOutputFile, frameBytes, videoFrame->GetRowBytes() * videoFrame->GetHeight()); + close(videoOutputFile); + emit frameSaved(capturePath); + } else { + QImage image(videoFrame->GetWidth(), videoFrame->GetHeight(), QImage::Format_ARGB32_Premultiplied); + //convert from uyvy422 to rgba + CaptureHandler::yuv2rgb((uchar *)frameBytes, (uchar *)image.bits(), videoFrame->GetWidth(), videoFrame->GetHeight()); + image.save(capturePath); + emit frameSaved(capturePath); + } + videoFrame->Release(); +} + HRESULT DeckLinkCaptureDelegate::VideoInputFrameArrived(IDeckLinkVideoInputFrame* videoFrame, IDeckLinkAudioInputPacket* audioFrame) { IDeckLinkVideoFrame* rightEyeFrame = NULL; @@ -354,21 +377,11 @@ HRESULT DeckLinkCaptureDelegate::VideoInputFrameArrived(IDeckLinkVideoInputFrame free((void*)timecodeString); if (!doCaptureFrame.isEmpty()) { - videoFrame->GetBytes(&frameBytes); - if (doCaptureFrame.endsWith("raw")) { - // Save as raw uyvy422 imgage - videoOutputFile = open(doCaptureFrame.toUtf8().constData(), O_WRONLY | O_CREAT/*|O_TRUNC*/, 0664); - write(videoOutputFile, frameBytes, videoFrame->GetRowBytes() * videoFrame->GetHeight()); - close(videoOutputFile); - emit frameSaved(doCaptureFrame); - } else { - QImage image(videoFrame->GetWidth(), videoFrame->GetHeight(), QImage::Format_ARGB32_Premultiplied); - //convert from uyvy422 to rgba - CaptureHandler::yuv2rgb((uchar *)frameBytes, (uchar *)image.bits(), videoFrame->GetWidth(), videoFrame->GetHeight()); - image.save(doCaptureFrame); - emit frameSaved(doCaptureFrame); - } + videoFrame->AddRef(); + m_framesList.append(videoFrame); + m_framePath.append(doCaptureFrame); doCaptureFrame.clear(); + QtConcurrent::run(this, &DeckLinkCaptureDelegate::slotProcessFrame); } if (videoOutputFile != -1) { @@ -484,7 +497,7 @@ QString BmdCaptureHandler::getDeviceName(QString) return QString(); } -void BmdCaptureHandler::startPreview(int deviceId, int captureMode) +void BmdCaptureHandler::startPreview(int deviceId, int captureMode, bool audio) { deckLinkIterator = CreateDeckLinkIteratorInstance(); BMDVideoInputFlags inputFlags = 0; @@ -693,10 +706,12 @@ void BmdCaptureHandler::startPreview(int deviceId, int captureMode) return; } - result = deckLinkInput->EnableAudioInput(bmdAudioSampleRate48kHz, g_audioSampleDepth, g_audioChannels); - if (result != S_OK) { - stopCapture(); - return; + if (audio) { + result = deckLinkInput->EnableAudioInput(bmdAudioSampleRate48kHz, g_audioSampleDepth, g_audioChannels); + if (result != S_OK) { + stopCapture(); + return; + } } deckLinkInput->SetScreenPreviewCallback(previewView); result = deckLinkInput->StartStreams(); diff --git a/src/blackmagic/capture.h b/src/blackmagic/capture.h index dcf68f81..b58b40c1 100644 --- a/src/blackmagic/capture.h +++ b/src/blackmagic/capture.h @@ -32,6 +32,12 @@ public: private: ULONG m_refCount; pthread_mutex_t m_mutex; + QList m_framesList; + QStringList m_framePath; + +private slots: + void slotProcessFrame(); + signals: void gotTimeCode(ulong); void gotMessage(const QString &); @@ -45,7 +51,7 @@ public: BmdCaptureHandler(QVBoxLayout *lay, QWidget *parent = 0); ~BmdCaptureHandler(); CDeckLinkGLWidget *previewView; - void startPreview(int deviceId, int captureMode); + void startPreview(int deviceId, int captureMode, bool audio = true); void stopPreview(); void startCapture(const QString &path); void stopCapture(); diff --git a/src/stopmotion/capturehandler.h b/src/stopmotion/capturehandler.h index e8b755ba..c91a5d5f 100644 --- a/src/stopmotion/capturehandler.h +++ b/src/stopmotion/capturehandler.h @@ -30,7 +30,7 @@ class CaptureHandler : public QObject public: CaptureHandler(QVBoxLayout *lay, QWidget *parent = 0); ~CaptureHandler(); - virtual void startPreview(int deviceId, int captureMode) = 0; + virtual void startPreview(int deviceId, int captureMode, bool audio = true) = 0; virtual void stopPreview() = 0; virtual void startCapture(const QString &path) = 0; virtual void stopCapture(); diff --git a/src/stopmotion/stopmotion.cpp b/src/stopmotion/stopmotion.cpp index a3c24133..2094396e 100644 --- a/src/stopmotion/stopmotion.cpp +++ b/src/stopmotion/stopmotion.cpp @@ -61,6 +61,12 @@ void MyLabel::wheelEvent(QWheelEvent * event) else emit seek(false); } +//virtual +void MyLabel::mousePressEvent(QMouseEvent *) +{ + emit switchToLive(); +} + //virtual void MyLabel::paintEvent(QPaintEvent * event) { @@ -153,8 +159,8 @@ StopmotionWidget::StopmotionWidget(KUrl projectFolder, const QList< QAction * > connect(showThumbs, SIGNAL(triggered(bool)), this, SLOT(slotShowThumbs(bool))); QAction *removeCurrent = new QAction(KIcon("edit-delete"), i18n("Delete current frame"), this); - //TODO: implement frame deletion - //connect(removeCurrent, SIGNAL(triggered()), this, SLOT(slotRemoveFrame())); + removeCurrent->setShortcut(Qt::Key_Delete); + connect(removeCurrent, SIGNAL(triggered()), this, SLOT(slotRemoveFrame())); QAction *capInterval = new QAction(KIcon(), i18n("Set capture interval"), this); connect(capInterval, SIGNAL(triggered()), this, SLOT(slotSetCaptureInterval())); @@ -175,6 +181,8 @@ StopmotionWidget::StopmotionWidget(KUrl projectFolder, const QList< QAction * > capture_button->setMenu(capMenu); connect(sequence_name, SIGNAL(textChanged(const QString &)), this, SLOT(sequenceNameChanged(const QString &))); + connect(sequence_name, SIGNAL(currentIndexChanged(int)), live_button, SLOT(setFocus())); + m_layout = new QVBoxLayout; if (BMInterface::getBlackMagicDeviceList(capture_device, NULL)) { // Found a BlackMagic device @@ -190,6 +198,7 @@ StopmotionWidget::StopmotionWidget(KUrl projectFolder, const QList< QAction * > connect(capture_device, SIGNAL(currentIndexChanged(int)), this, SLOT(slotUpdateHandler())); m_frame_preview = new MyLabel(this); connect(m_frame_preview, SIGNAL(seek(bool)), this, SLOT(slotSeekFrame(bool))); + connect(m_frame_preview, SIGNAL(switchToLive()), this, SLOT(slotSwitchLive())); m_layout->addWidget(m_frame_preview); m_frame_preview->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); video_preview->setLayout(m_layout); @@ -199,8 +208,11 @@ StopmotionWidget::StopmotionWidget(KUrl projectFolder, const QList< QAction * > connect(button_addsequence, SIGNAL(clicked(bool)), this, SLOT(slotAddSequence())); connect(preview_button, SIGNAL(clicked(bool)), this, SLOT(slotPlayPreview(bool))); connect(frame_list, SIGNAL(currentRowChanged(int)), this, SLOT(slotShowSelectedFrame())); + connect(frame_list, SIGNAL(itemClicked(QListWidgetItem *)), this, SLOT(slotShowSelectedFrame())); connect(this, SIGNAL(doCreateThumbs(QImage, int)), this, SLOT(slotCreateThumbs(QImage, int))); + frame_list->addAction(removeCurrent); + frame_list->setContextMenuPolicy(Qt::ActionsContextMenu); frame_list->setHidden(!KdenliveSettings::showstopmotionthumbs()); parseExistingSequences(); } @@ -304,7 +316,7 @@ void StopmotionWidget::slotLive(bool isOn) if (isOn) { //m_frame_preview->setImage(QImage()); m_frame_preview->setHidden(true); - m_bmCapture->startPreview(KdenliveSettings::hdmi_capturedevice(), KdenliveSettings::hdmi_capturemode()); + m_bmCapture->startPreview(KdenliveSettings::hdmi_capturedevice(), KdenliveSettings::hdmi_capturemode(), false); capture_button->setEnabled(true); } else { m_bmCapture->stopPreview(); @@ -404,7 +416,6 @@ void StopmotionWidget::slotCaptureFrame() } //capture_button->setEnabled(false); QString currentPath = getPathForFrame(m_sequenceFrame); - kDebug() << "Capture FRame NB: " << m_sequenceFrame; m_bmCapture->captureFrame(currentPath); KNotification::event("FrameCaptured"); m_sequenceFrame++; @@ -450,6 +461,9 @@ void StopmotionWidget::slotCreateThumbs(QImage img, int ix) QListWidgetItem *item = new QListWidgetItem(icon, QString(), frame_list); item->setToolTip(getPathForFrame(ix, sequence_name->currentText())); item->setData(Qt::UserRole, ix); + frame_list->blockSignals(true); + frame_list->setCurrentItem(item); + frame_list->blockSignals(false); m_future = QtConcurrent::run(this, &StopmotionWidget::slotPrepareThumbs); } @@ -509,11 +523,11 @@ void StopmotionWidget::slotAnimate() //TODO: loop if (frame_list->currentRow() < (frame_list->count() - 1)) { frame_list->setCurrentRow(frame_list->currentRow() + 1); - QTimer::singleShot(200, this, SLOT(slotAnimate())); + QTimer::singleShot(100, this, SLOT(slotAnimate())); } else preview_button->setChecked(false); } else if (!m_animationList.isEmpty()) { slotShowFrame(m_animationList.takeFirst()); - QTimer::singleShot(200, this, SLOT(slotAnimate())); + QTimer::singleShot(100, this, SLOT(slotAnimate())); } else preview_button->setChecked(false); } @@ -568,4 +582,14 @@ void StopmotionWidget::slotSeekFrame(bool forward) } else if (ix > 0) frame_list->setCurrentRow(ix - 1); } - +void StopmotionWidget::slotRemoveFrame() +{ + if (frame_list->currentItem() == NULL) return; + QString path = frame_list->currentItem()->toolTip(); + if (KMessageBox::questionYesNo(this, i18n("Delete frame %1 from disk?", path), i18n("Delete Frame")) != KMessageBox::Yes) return; + QFile f(path); + if (f.remove()) { + QListWidgetItem *item = frame_list->takeItem(frame_list->currentRow()); + delete item; + } +} diff --git a/src/stopmotion/stopmotion.h b/src/stopmotion/stopmotion.h index 0f3f27bb..bd74a521 100644 --- a/src/stopmotion/stopmotion.h +++ b/src/stopmotion/stopmotion.h @@ -36,6 +36,7 @@ public: protected: virtual void paintEvent(QPaintEvent * event); virtual void wheelEvent(QWheelEvent * event); + virtual void mousePressEvent(QMouseEvent *); private: QImage m_img; @@ -44,6 +45,9 @@ signals: /** @brief Seek to next or previous frame. * @param forward set to true to go to next frame, fals to go to previous frame */ void seek(bool forward); + + /** @brief Switch to live view. */ + void switchToLive(); }; class StopmotionWidget : public QDialog , public Ui::Stopmotion_UI @@ -185,8 +189,12 @@ private slots: /** @brief Set the effect to be applied to overlay frame. */ void slotUpdateOverlayEffect(QAction *act); - /** @brief Switch between live view / currently selected fram. */ + /** @brief Switch between live view / currently selected frame. */ void slotSwitchLive(); + + /** @brief Delete current frame from disk. */ + void slotRemoveFrame(); + signals: /** @brief Ask to add sequence to current project. */ void addOrUpdateSequence(const QString); diff --git a/src/v4l/v4lcapture.cpp b/src/v4l/v4lcapture.cpp index 51b1993d..8ede6e3f 100644 --- a/src/v4l/v4lcapture.cpp +++ b/src/v4l/v4lcapture.cpp @@ -160,7 +160,7 @@ QString V4lCaptureHandler::getDeviceName(QString input) return deviceName.isEmpty() ? input : deviceName; } -void V4lCaptureHandler::startPreview(int /*deviceId*/, int /*captureMode*/) +void V4lCaptureHandler::startPreview(int /*deviceId*/, int /*captureMode*/, bool) { m_display->setHidden(false); fswebcam_config_t *config; diff --git a/src/v4l/v4lcapture.h b/src/v4l/v4lcapture.h index bbcbf883..a1778b3b 100644 --- a/src/v4l/v4lcapture.h +++ b/src/v4l/v4lcapture.h @@ -36,7 +36,7 @@ class V4lCaptureHandler : public CaptureHandler public: V4lCaptureHandler(QVBoxLayout *lay, QWidget *parent = 0); ~V4lCaptureHandler(); - void startPreview(int deviceId, int captureMode); + void startPreview(int deviceId, int captureMode, bool audio = true); void stopPreview(); void startCapture(const QString &path); void stopCapture(); -- 2.39.2