From: Jean-Baptiste Mardelle Date: Thu, 26 May 2011 08:01:46 +0000 (+0000) Subject: Bring back overlay & effects in stopmotion widget, rewrite of decklink capture to... X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=ff42e084bde7be764bb867843d38633c98d6879f;p=kdenlive Bring back overlay & effects in stopmotion widget, rewrite of decklink capture to make use of MLT (Can cause some system freeze, under investigation) svn path=/trunk/kdenlive/; revision=5608 --- diff --git a/src/blackmagic/devices.cpp b/src/blackmagic/devices.cpp index 3be150a2..7277c6c3 100644 --- a/src/blackmagic/devices.cpp +++ b/src/blackmagic/devices.cpp @@ -48,8 +48,6 @@ bool BMInterface::getBlackMagicDeviceList(KComboBox *devicelist, KComboBox *mode while(deckLinkIterator->Next(&deckLink) == S_OK) { char * deviceNameString = NULL; - // Increment the total number of DeckLink cards found - numDevices++; //if (numDevices > 1) kDebug() << "// FOUND a BM device\n\n+++++++++++++++++++++++++++++++++++++"; @@ -119,6 +117,7 @@ bool BMInterface::getBlackMagicDeviceList(KComboBox *devicelist, KComboBox *mode displayMode->Release(); } devicelist->addItem(deviceName, availableModes); + devicelist->setItemData(devicelist->count() - 1, numDevices, Qt::UserRole + 1); found = true; } @@ -133,6 +132,9 @@ bool BMInterface::getBlackMagicDeviceList(KComboBox *devicelist, KComboBox *mode // Release the IDeckLink instance when we've finished with it to prevent leaks deckLink->Release(); + + // Increment the total number of DeckLink cards found + numDevices++; } deckLinkIterator->Release(); diff --git a/src/kdenlivesettings.kcfg b/src/kdenlivesettings.kcfg index a3650443..41720563 100644 --- a/src/kdenlivesettings.kcfg +++ b/src/kdenlivesettings.kcfg @@ -721,7 +721,7 @@ 10 - + 0 diff --git a/src/mltdevicecapture.cpp b/src/mltdevicecapture.cpp index f36fda01..07063312 100644 --- a/src/mltdevicecapture.cpp +++ b/src/mltdevicecapture.cpp @@ -64,9 +64,9 @@ static void rec_consumer_frame_preview(mlt_consumer, MltDeviceCapture * self, ml if (self->sendFrameForAnalysis && frame_ptr->convert_image) { self->emitFrameUpdated(frame); } - if (self->doCapture) { - self->doCapture = false; - self->saveFrame(frame); + if (self->doCapture > 0) { + self->doCapture --; + if (self->doCapture == 0) self->saveFrame(frame); } /* if (self->analyseAudio) { @@ -83,7 +83,7 @@ static void rec_consumer_frame_preview(mlt_consumer, MltDeviceCapture * self, ml MltDeviceCapture::MltDeviceCapture(QString profile, VideoPreviewContainer *surface, QWidget *parent) : AbstractRender(parent), - doCapture(false), + doCapture(0), sendFrameForAnalysis(false), m_mltConsumer(NULL), m_mltProducer(NULL), @@ -162,20 +162,18 @@ void MltDeviceCapture::buildConsumer(const QString &profileName) void MltDeviceCapture::stop() { + bool isPlaylist = false; if (m_mltConsumer) { + m_mltConsumer->set("refresh", 0); m_mltConsumer->stop(); //if (!m_mltConsumer->is_stopped()) m_mltConsumer->stop(); - delete m_mltConsumer; - m_mltConsumer = NULL; } - kDebug()<<"STOPPING cap"; if (m_mltProducer) { QList prods; Mlt::Service service(m_mltProducer->parent().get_service()); mlt_service_lock(service.get_service()); -kDebug()<<"STOPPING cap 2"; if (service.type() == tractor_type) { - kDebug()<<"STOPPING cap 3"; + isPlaylist = true; Mlt::Tractor tractor(service); mlt_tractor_close(tractor.get_tractor()); Mlt::Field *field = tractor.field(); @@ -203,7 +201,7 @@ kDebug()<<"STOPPING cap 2"; // the video4linux device stays open, seems like a bug in MLT that is not cleaning properly mlt_properties props = MLT_PRODUCER_PROPERTIES(trackPlaylist.get_clip(i)->get_parent()); while (mlt_properties_ref_count(props) > 0) mlt_properties_dec_ref(props); - mlt_producer_close(trackPlaylist.get_clip(i)->get_parent()); + if (trackPlaylist.get_clip(i)) mlt_producer_close(trackPlaylist.get_clip(i)->get_parent()); } mlt_playlist_close(trackPlaylist.get_playlist()); //trackPlaylist.clear(); @@ -214,9 +212,11 @@ kDebug()<<"STOPPING cap 2"; } mlt_service_unlock(service.get_service()); delete m_mltProducer; - kDebug()<<"/// STOP REC PROD"; m_mltProducer = NULL; } + // For some reason, the consumer seems to be deleted by previous stuff when in playlist mode + if (!isPlaylist) delete m_mltConsumer; + m_mltConsumer = NULL; } @@ -277,35 +277,14 @@ void MltDeviceCapture::showAudio(Mlt::Frame& frame) } } -bool MltDeviceCapture::slotStartPreview(const QString &producer) +bool MltDeviceCapture::slotStartPreview(const QString &producer, bool xmlFormat) { - //stop(); if (m_mltConsumer == NULL) buildConsumer(); - /*if (m_mltConsumer) delete m_mltConsumer; - if (m_mltProducer) delete m_mltProducer; - if (m_mltProfile) delete m_mltProfile; - - char *tmp = qstrdup(m_activeProfile.toUtf8().constData()); - setenv("MLT_PROFILE", tmp, 1); - m_mltProfile = new Mlt::Profile(tmp); - delete[] tmp; - m_mltProfile->get_profile()->is_explicit = 1; - - m_mltConsumer = new Mlt::Consumer(*m_mltProfile, "sdl_preview"); - - m_mltConsumer->set("window_id", m_winid); - m_mltConsumer->set("real_time", 0); -// m_mltConsumer->set("buffer", 1); - m_mltConsumer->set("resize", 1); - m_mltConsumer->set("progressive", 1); - m_mltConsumer->set("rescale", "nearest");*/ - - //char *tmp = qstrdup(QString("avformat-novalidate:video4linux2:%1?frame_rate:%2&width:%3&height:%4").arg(KdenliveSettings::video4vdevice()).arg(m_mltProfile->fps()).arg(m_mltProfile->width()).arg(m_mltProfile->height()).toUtf8().constData()); - char *tmp = qstrdup(producer.toUtf8().constData()); - - m_mltProducer = new Mlt::Producer(*m_mltProfile, tmp); + if (xmlFormat) m_mltProducer = new Mlt::Producer(*m_mltProfile, "xml-string", tmp); + else m_mltProducer = new Mlt::Producer(*m_mltProfile, tmp); delete[] tmp; + if (m_mltProducer == NULL || !m_mltProducer->is_valid()) { kDebug()<<"//// ERROR CREATRING PROD"; return false; @@ -338,6 +317,13 @@ void MltDeviceCapture::saveFrame(Mlt::Frame& frame) const uchar* image = frame.get_image(format, width, height); QImage qimage(width, height, QImage::Format_ARGB32); memcpy(qimage.bits(), image, width * height * 4); + + // Re-enable overlay + Mlt::Service service(m_mltProducer->parent().get_service()); + Mlt::Tractor tractor(service); + Mlt::Producer trackProducer(tractor.track(0)); + trackProducer.set("hide", 0); + qimage.rgbSwapped().save(m_capturePath); emit frameSaved(m_capturePath); m_capturePath.clear(); @@ -345,8 +331,19 @@ void MltDeviceCapture::saveFrame(Mlt::Frame& frame) void MltDeviceCapture::captureFrame(const QString &path) { + if (m_mltProducer == NULL || !m_mltProducer->is_valid()) return; + + // Hide overlay track before doing the capture + Mlt::Service service(m_mltProducer->parent().get_service()); + Mlt::Tractor tractor(service); + Mlt::Producer trackProducer(tractor.track(0)); + mlt_service_lock(service.get_service()); + trackProducer.set("hide", 1); + m_mltConsumer->purge(); + mlt_service_unlock(service.get_service()); m_capturePath = path; - doCapture = true; + // Wait for 5 frames before capture to make sure overlay is gone + doCapture = 5; } bool MltDeviceCapture::slotStartCapture(const QString ¶ms, const QString &path, const QString &playlist) @@ -383,8 +380,6 @@ bool MltDeviceCapture::slotStartCapture(const QString ¶ms, const QString &pa // FIXME: the event object returned by the listen gets leaked... m_mltConsumer->listen("consumer-frame-show", this, (mlt_listener) rec_consumer_frame_show); - - //tmp = qstrdup(QString("avformat-novalidate:video4linux2:%1?frame_rate:%2&width:%3&height:%4").arg(KdenliveSettings::video4vdevice()).arg(m_mltProfile->fps()).arg(m_mltProfile->width()).arg(m_mltProfile->height()).toUtf8().constData()); tmp = qstrdup(playlist.toUtf8().constData()); m_mltProducer = new Mlt::Producer(*m_mltProfile, "xml-string", tmp); delete[] tmp; @@ -404,3 +399,138 @@ bool MltDeviceCapture::slotStartCapture(const QString ¶ms, const QString &pa } +void MltDeviceCapture::setOverlay(const QString &path) +{ + if (m_mltProducer == NULL || !m_mltProducer->is_valid()) return; + Mlt::Producer parentProd(m_mltProducer->parent()); + if (parentProd.get_producer() == NULL) { + kDebug() << "PLAYLIST BROKEN, CANNOT INSERT CLIP //////"; + return; + } + + Mlt::Service service(parentProd.get_service()); + if (service.type() != tractor_type) { + kWarning() << "// TRACTOR PROBLEM"; + return; + } + Mlt::Tractor tractor(service); + if ( tractor.count() < 2) { + kWarning() << "// TRACTOR PROBLEM"; + return; + } + mlt_service_lock(service.get_service()); + Mlt::Producer trackProducer(tractor.track(0)); + Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service()); + + trackPlaylist.remove(0); + if (path.isEmpty()) { + mlt_service_unlock(service.get_service()); + return; + } + + // Add overlay clip + char *tmp = qstrdup(path.toUtf8().constData()); + Mlt::Producer *clip = new Mlt::Producer (*m_mltProfile, "loader", tmp); + delete[] tmp; + clip->set_in_and_out(0, 99999); + trackPlaylist.insert_at(0, clip, 1); + + // Add transition + mlt_service serv = m_mltProducer->parent().get_service(); + mlt_service nextservice = mlt_service_get_producer(serv); + mlt_properties properties = MLT_SERVICE_PROPERTIES(nextservice); + QString mlt_type = mlt_properties_get(properties, "mlt_type"); + if (mlt_type != "transition") { + // transition does not exist, add it + Mlt::Field *field = tractor.field(); + Mlt::Transition *transition = new Mlt::Transition(*m_mltProfile, "composite"); + transition->set_in_and_out(0, 0); + transition->set("geometry", "0,0:100%x100%:70"); + transition->set("fill", 1); + transition->set("operator", "and"); + transition->set("a_track", 0); + transition->set("b_track", 1); + field->plant_transition(*transition, 0, 1); + } + mlt_service_unlock(service.get_service()); + //delete clip; +} + +void MltDeviceCapture::setOverlayEffect(const QString tag, QStringList parameters) +{ + if (m_mltProducer == NULL || !m_mltProducer->is_valid()) return; + Mlt::Service service(m_mltProducer->parent().get_service()); + Mlt::Tractor tractor(service); + Mlt::Producer trackProducer(tractor.track(0)); + Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service()); + Mlt::Service trackService(trackProducer.get_service()); + + mlt_service_lock(service.get_service()); + + // delete previous effects + Mlt::Filter *filter; + filter = trackService.filter(0); + if (filter && !tag.isEmpty()) { + QString currentService = filter->get("mlt_service"); + if (currentService == tag) { + // Effect is already there + mlt_service_unlock(service.get_service()); + return; + } + } + while (filter) { + trackService.detach(*filter); + delete filter; + filter = trackService.filter(0); + } + + if (tag.isEmpty()) { + mlt_service_unlock(service.get_service()); + return; + } + + char *tmp = qstrdup(tag.toUtf8().constData()); + filter = new Mlt::Filter(*m_mltProfile, tmp); + delete[] tmp; + if (filter && filter->is_valid()) { + for (int j = 0; j < parameters.count(); j++) { + filter->set(parameters.at(j).section("=", 0, 0).toUtf8().constData(), parameters.at(j).section("=", 1, 1).toUtf8().constData()); + } + trackService.attach(*filter); + } + mlt_service_unlock(service.get_service()); +} + +void MltDeviceCapture::mirror(bool activate) +{ + if (m_mltProducer == NULL || !m_mltProducer->is_valid()) return; + Mlt::Service service(m_mltProducer->parent().get_service()); + Mlt::Tractor tractor(service); + Mlt::Producer trackProducer(tractor.track(1)); + Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service()); + Mlt::Service trackService(trackProducer.get_service()); + + mlt_service_lock(service.get_service()); + + // delete previous effects + Mlt::Filter *filter; + filter = trackService.filter(0); + while (filter) { + trackService.detach(*filter); + delete filter; + filter = trackService.filter(0); + } + + if (!activate) { + mlt_service_unlock(service.get_service()); + return; + } + + filter = new Mlt::Filter(*m_mltProfile, "mirror"); + if (filter && filter->is_valid()) { + filter->set("mirror", "flip"); + trackService.attach(*filter); + } + mlt_service_unlock(service.get_service()); +} + diff --git a/src/mltdevicecapture.h b/src/mltdevicecapture.h index 461c8295..da341ebc 100644 --- a/src/mltdevicecapture.h +++ b/src/mltdevicecapture.h @@ -57,7 +57,7 @@ Q_OBJECT public: /** @brief Destroy the MLT Renderer. */ ~MltDeviceCapture(); - bool doCapture; + int doCapture; /** @brief This property is used to decide if the renderer should convert it's frames to QImage for use in other Kdenlive widgets. */ bool sendFrameForAnalysis; @@ -77,12 +77,20 @@ Q_OBJECT public: * @param surface The widget onto which the frame should be painted */ bool slotStartCapture(const QString ¶ms, const QString &path, const QString &playlist); - bool slotStartPreview(const QString &producer); + bool slotStartPreview(const QString &producer, bool xmlFormat = false); /** @brief A frame arrived from the MLT Video4Linux process. */ void gotCapturedFrame(Mlt::Frame& frame); /** @brief Save current frame to file. */ void captureFrame(const QString &path); void doRefresh(); + /** @brief This will add the video clip from path and add it in the overlay track. */ + void setOverlay(const QString &path); + + /** @brief This will add an MLT video effect to the overlay track. */ + void setOverlayEffect(const QString tag, QStringList parameters); + + /** @brief This will add a horizontal flip effect, easier to work when filming yourself. */ + void mirror(bool activate); private: Mlt::Consumer * m_mltConsumer; diff --git a/src/recmonitor.cpp b/src/recmonitor.cpp index ba38afcb..1e239b49 100644 --- a/src/recmonitor.cpp +++ b/src/recmonitor.cpp @@ -211,8 +211,8 @@ void RecMonitor::slotVideoDeviceChanged(int ix) if (m_captureDevice) { // MLT capture still running, abort m_captureDevice->stop(); - //delete m_captureDevice; - //m_captureDevice = NULL; + delete m_captureDevice; + m_captureDevice = NULL; } switch (ix) { case SCREENGRAB: @@ -240,8 +240,8 @@ void RecMonitor::slotVideoDeviceChanged(int ix) checkDeviceAvailability(); break; case BLACKMAGIC: - createBlackmagicDevice(); - m_recAction->setEnabled(false); + //createBlackmagicDevice(); + m_recAction->setEnabled(true); m_stopAction->setEnabled(false); m_playAction->setEnabled(true); @@ -399,10 +399,13 @@ void RecMonitor::slotStopCapture() QTimer::singleShot(1000, m_captureProcess, SLOT(kill())); break; case BLACKMAGIC: - m_bmCapture->stopPreview(); + if (m_captureDevice) { + m_captureDevice->stop(); + } + //m_bmCapture->stopPreview(); m_playAction->setEnabled(true); m_stopAction->setEnabled(false); - m_recAction->setEnabled(false); + m_recAction->setEnabled(true); break; default: break; @@ -434,8 +437,8 @@ void RecMonitor::slotStartCapture(bool play) MltVideoProfile profile; QString producer; QStringList dvargs = KdenliveSettings::dvgrabextra().simplified().split(" ", QString::SkipEmptyParts); - video_capture->setVisible(device_selector->currentIndex() == BLACKMAGIC); - video_frame->setHidden(device_selector->currentIndex() == BLACKMAGIC); + //video_capture->setVisible(device_selector->currentIndex() == BLACKMAGIC); + //video_frame->setHidden(device_selector->currentIndex() == BLACKMAGIC); switch (device_selector->currentIndex()) { case FIREWIRE: @@ -509,7 +512,26 @@ void RecMonitor::slotStartCapture(bool play) m_captureProcess->start("ffmpeg", m_captureArgs);*/ break; case BLACKMAGIC: - m_bmCapture->startPreview(KdenliveSettings::hdmi_capturedevice(), KdenliveSettings::hdmi_capturemode()); + path = KdenliveSettings::current_profile(); + m_manager->activateMonitor("record"); + if (m_captureDevice == NULL) { + m_captureDevice = new MltDeviceCapture(path, m_videoBox, this); + m_captureDevice->sendFrameForAnalysis = m_analyse; + m_manager->updateScopeSource(); + } + profile = ProfilesDialog::getVideoProfile(path); + producer = QString("decklink:%1").arg(KdenliveSettings::hdmi_capturedevice()); + if (!m_captureDevice->slotStartPreview(producer)) { + // v4l capture failed to start + video_frame->setText(i18n("Failed to start Decklink,\ncheck your parameters...")); + m_videoBox->setHidden(true); + + } else { + m_videoBox->setHidden(false); + m_playAction->setEnabled(false); + m_stopAction->setEnabled(true); + } + //m_bmCapture->startPreview(KdenliveSettings::hdmi_capturedevice(), KdenliveSettings::hdmi_capturemode()); m_playAction->setEnabled(false); m_stopAction->setEnabled(true); m_recAction->setEnabled(true); @@ -529,7 +551,7 @@ void RecMonitor::slotStartCapture(bool play) void RecMonitor::slotRecord() { - if (device_selector->currentIndex() == BLACKMAGIC) { + /*if (device_selector->currentIndex() == BLACKMAGIC) { if (m_blackmagicCapturing) { // We are capturing, stop it m_bmCapture->stopCapture(); @@ -543,7 +565,7 @@ void RecMonitor::slotRecord() m_blackmagicCapturing = true; } return; - } + }*/ if (m_captureProcess->state() == QProcess::NotRunning && device_selector->currentIndex() == FIREWIRE) { slotStartCapture(); @@ -651,6 +673,30 @@ void RecMonitor::slotRecord() kDebug() << "Capture: Running ffmpeg " << m_captureArgs.join(" "); m_captureProcess->start("ffmpeg", m_captureArgs);*/ break; + + case BLACKMAGIC: + path = KdenliveSettings::current_profile(); + profile = ProfilesDialog::getVideoProfile(path); + if (m_captureDevice == NULL) { + m_captureDevice = new MltDeviceCapture(path, m_videoBox, this); + m_captureDevice->sendFrameForAnalysis = m_analyse; + m_manager->updateScopeSource(); + } + + playlist = QString("producer100000pause%1decklink").arg(KdenliveSettings::hdmi_capturedevice()); + + if (m_captureDevice->slotStartCapture(KdenliveSettings::v4l_parameters(), m_captureFile.path(), playlist)) { + m_videoBox->setHidden(false); + m_isCapturing = true; + } + else { + video_frame->setText(i18n("Failed to start Decklink,\ncheck your parameters...")); + m_videoBox->setHidden(true); + m_isCapturing = false; + m_recAction->setChecked(false); + } + break; + case SCREENGRAB: switch (KdenliveSettings::rmd_capture_type()) { case 0: diff --git a/src/stopmotion/stopmotion.cpp b/src/stopmotion/stopmotion.cpp index c93a15ac..28ce8a89 100644 --- a/src/stopmotion/stopmotion.cpp +++ b/src/stopmotion/stopmotion.cpp @@ -35,10 +35,6 @@ #include #include -#ifdef QIMAGEBLITZ -#include -#endif - #include #include #include @@ -150,6 +146,12 @@ StopmotionWidget::StopmotionWidget(MonitorManager *manager, KUrl projectFolder, analyse->setCheckable(true); analyse->setChecked(KdenliveSettings::analyse_stopmotion()); connect(analyse, SIGNAL(triggered(bool)), this, SLOT(slotSwitchAnalyse(bool))); + + QAction* mirror = new QAction(i18n("Mirror display"), this); + mirror->setCheckable(true); + //mirror->setChecked(KdenliveSettings::analyse_stopmotion()); + connect(mirror, SIGNAL(triggered(bool)), this, SLOT(slotSwitchMirror(bool))); + addActions(actions); setupUi(this); setWindowTitle(i18n("Stop Motion Capture")); @@ -182,22 +184,21 @@ StopmotionWidget::StopmotionWidget(MonitorManager *manager, KUrl projectFolder, overlay_button->setDefaultAction(m_showOverlay); //confMenu->addAction(m_showOverlay); -#ifdef QIMAGEBLITZ - m_effectIndex = KdenliveSettings::blitzeffect(); + m_effectIndex = KdenliveSettings::stopmotioneffect(); QMenu* effectsMenu = new QMenu(i18n("Overlay effect")); QActionGroup* effectGroup = new QActionGroup(this); QAction* noEffect = new QAction(i18n("No Effect"), effectGroup); - noEffect->setData(1); + noEffect->setData(0); QAction* contrastEffect = new QAction(i18n("Contrast"), effectGroup); - contrastEffect->setData(2); + contrastEffect->setData(1); QAction* edgeEffect = new QAction(i18n("Edge detect"), effectGroup); - edgeEffect->setData(3); + edgeEffect->setData(2); QAction* brightEffect = new QAction(i18n("Brighten"), effectGroup); - brightEffect->setData(4); + brightEffect->setData(3); QAction* invertEffect = new QAction(i18n("Invert"), effectGroup); - invertEffect->setData(5); + invertEffect->setData(4); QAction* thresEffect = new QAction(i18n("Threshold"), effectGroup); - thresEffect->setData(6); + thresEffect->setData(5); effectsMenu->addAction(noEffect); effectsMenu->addAction(contrastEffect); @@ -214,7 +215,6 @@ StopmotionWidget::StopmotionWidget(MonitorManager *manager, KUrl projectFolder, } connect(effectsMenu, SIGNAL(triggered(QAction*)), this, SLOT(slotUpdateOverlayEffect(QAction*))); confMenu->addMenu(effectsMenu); -#endif QAction* showThumbs = new QAction(KIcon("image-x-generic"), i18n("Show sequence thumbnails"), this); showThumbs->setCheckable(true); @@ -231,6 +231,7 @@ StopmotionWidget::StopmotionWidget(MonitorManager *manager, KUrl projectFolder, confMenu->addAction(showThumbs); confMenu->addAction(removeCurrent); confMenu->addAction(analyse); + confMenu->addAction(mirror); confMenu->addAction(conf); config_button->setIcon(KIcon("configure")); config_button->setMenu(confMenu); @@ -252,8 +253,6 @@ StopmotionWidget::StopmotionWidget(MonitorManager *manager, KUrl projectFolder, if (BMInterface::getBlackMagicDeviceList(capture_device, NULL)) { // Found a BlackMagic device - //m_bmCapture = new BmdCaptureHandler(m_layout); - //connect(m_bmCapture, SIGNAL(gotMessage(const QString&)), this, SLOT(slotGotHDMIMessage(const QString&))); } if (QFile::exists(KdenliveSettings::video4vdevice())) { #if !defined(Q_WS_MAC) && !defined(Q_OS_FREEBSD) @@ -270,17 +269,10 @@ StopmotionWidget::StopmotionWidget(MonitorManager *manager, KUrl projectFolder, } } } - - //if (m_bmCapture == NULL) { - - //m_captureDevice->sendFrameForAnalysis = m_analyse; - /*m_bmCapture = new V4lCaptureHandler(m_layout); - m_bmCapture->setDevice(capture_device->itemData(capture_device->currentIndex(), Qt::UserRole + 1).toString(), capture_device->itemData(capture_device->currentIndex(), Qt::UserRole + 2).toString());*/ - //} #endif } - connect(capture_device, SIGNAL(currentIndexChanged(int)), this, SLOT(slotUpdateHandler())); + connect(capture_device, SIGNAL(currentIndexChanged(int)), this, SLOT(slotUpdateDeviceHandler())); /*if (m_bmCapture) { connect(m_bmCapture, SIGNAL(frameSaved(const QString)), this, SLOT(slotNewThumb(const QString))); connect(m_bmCapture, SIGNAL(gotFrame(QImage)), this, SIGNAL(gotFrame(QImage))); @@ -294,9 +286,19 @@ StopmotionWidget::StopmotionWidget(MonitorManager *manager, KUrl projectFolder, video_preview->setLayout(layout); //kDebug()<winId(); + + QString profilePath; + // Create MLT producer data + if (capture_device->itemData(capture_device->currentIndex()) == "v4l") { + // Capture using a video4linux device + profilePath = KStandardDirs::locateLocal("appdata", "profiles/video4linux"); + } + else { + // Decklink capture + profilePath = KdenliveSettings::current_profile(); + } - QString path = KStandardDirs::locateLocal("appdata", "profiles/video4linux"); - m_captureDevice = new MltDeviceCapture(path, m_videoBox, this); + m_captureDevice = new MltDeviceCapture(profilePath, m_videoBox, this); m_captureDevice->sendFrameForAnalysis = KdenliveSettings::analyse_stopmotion(); m_monitor->setRender(m_captureDevice); connect(m_captureDevice, SIGNAL(frameSaved(const QString)), this, SLOT(slotNewThumb(const QString))); @@ -335,11 +337,9 @@ StopmotionWidget::~StopmotionWidget() void StopmotionWidget::slotUpdateOverlayEffect(QAction* act) { -#ifdef QIMAGEBLITZ if (act) m_effectIndex = act->data().toInt(); - KdenliveSettings::setBlitzeffect(m_effectIndex); - if (m_showOverlay->isChecked()) slotUpdateOverlay(); -#endif + KdenliveSettings::setStopmotioneffect(m_effectIndex); + slotUpdateOverlay(); } void StopmotionWidget::closeEvent(QCloseEvent* e) @@ -387,8 +387,11 @@ void StopmotionWidget::slotShowThumbs(bool show) } -void StopmotionWidget::slotUpdateHandler() +void StopmotionWidget::slotUpdateDeviceHandler() { + slotLive(false); + delete m_captureDevice; + m_captureDevice = NULL; /*QString data = capture_device->itemData(capture_device->currentIndex()).toString(); slotLive(false); if (m_bmCapture) { @@ -457,21 +460,42 @@ void StopmotionWidget::slotLive(bool isOn) if (isOn) { m_frame_preview->setHidden(true); m_videoBox->setHidden(false); - QString path = KStandardDirs::locateLocal("appdata", "profiles/video4linux"); - kDebug()<<"SURFACE; "<width()<<"x"<height(); + MltVideoProfile profile; + QString resource; + QString service; + QString profilePath; + // Create MLT producer data + if (capture_device->itemData(capture_device->currentIndex()) == "v4l") { + // Capture using a video4linux device + profilePath = KStandardDirs::locateLocal("appdata", "profiles/video4linux"); + profile = ProfilesDialog::getVideoProfile(profilePath); + service = "avformat-novalidate"; + QString devicePath = capture_device->itemData(capture_device->currentIndex(), Qt::UserRole + 1).toString(); + resource = QString("video4linux2:%1?width:%2&height:%3&frame_rate:%4").arg(devicePath).arg(profile.width).arg(profile.height).arg((double) profile.frame_rate_num / profile.frame_rate_den); + } + else { + // Decklink capture + profilePath = KdenliveSettings::current_profile(); + profile = ProfilesDialog::getVideoProfile(profilePath); + service = "decklink"; + resource = capture_device->itemData(capture_device->currentIndex(), Qt::UserRole + 1).toString(); + } + if (m_captureDevice == NULL) { - m_captureDevice = new MltDeviceCapture(path, m_videoBox, this); + m_captureDevice = new MltDeviceCapture(profilePath, m_videoBox, this); m_captureDevice->sendFrameForAnalysis = KdenliveSettings::analyse_stopmotion(); m_monitor->setRender(m_captureDevice); connect(m_captureDevice, SIGNAL(frameSaved(const QString)), this, SLOT(slotNewThumb(const QString))); } - - MltVideoProfile profile = ProfilesDialog::getVideoProfile(path); + m_manager->activateMonitor("stopmotion"); - QString producer = QString("avformat-novalidate:video4linux2:%1?width:%2&height:%3&frame_rate:%4").arg(KdenliveSettings::video4vdevice()).arg(profile.width).arg(profile.height).arg((double) profile.frame_rate_num / profile.frame_rate_den); - if (m_captureDevice->slotStartPreview(producer)) { - kDebug()<<"// STARt CAPTURE GO"; + QString producer = createProducer(profile, service, resource); + if (m_captureDevice->slotStartPreview(producer, true)) { + if (m_showOverlay->isChecked()) { + reloadOverlay(); + slotUpdateOverlay(); + } capture_button->setEnabled(true); live_button->setChecked(true); log_box->insertItem(-1, i18n("Playing %1x%2 (%3 fps)", profile.width, profile.height, QString::number((double)profile.frame_rate_num/profile.frame_rate_den).rightJustified(2, '0'))); @@ -512,53 +536,62 @@ void StopmotionWidget::slotLive(bool isOn) live_button->blockSignals(false); } -void StopmotionWidget::slotShowOverlay(bool /*isOn*/) +void StopmotionWidget::slotShowOverlay(bool isOn) { -/* if (isOn) { - if (live_button->isChecked() && m_sequenceFrame > 0) { - slotUpdateOverlay(); - } - } else if (m_bmCapture) { - m_bmCapture->hideOverlay(); - }*/ + if (isOn) { + // Overlay last frame of the sequence + reloadOverlay(); + slotUpdateOverlay(); + } + else { + // Remove overlay + m_captureDevice->setOverlay(QString()); + } } -void StopmotionWidget::slotUpdateOverlay() +void StopmotionWidget::reloadOverlay() { - if (m_captureDevice == NULL) return; QString path = getPathForFrame(m_sequenceFrame - 1); - if (!QFile::exists(path)) return; - QImage img(path); - if (img.isNull()) { - QTimer::singleShot(1000, this, SLOT(slotUpdateOverlay())); + if (!QFile::exists(path)) { + log_box->insertItem(-1, i18n("No previous frame found")); + log_box->setCurrentIndex(0); return; } + m_captureDevice->setOverlay(path); +} + +void StopmotionWidget::slotUpdateOverlay() +{ + if (m_captureDevice == NULL) return; + + QString tag; + QStringList params; -#ifdef QIMAGEBLITZ - //img = Blitz::convolveEdge(img, 0, Blitz::Low); switch (m_effectIndex) { + case 1: + tag = "frei0r.contrast0r"; + params << "Contrast=1.2"; + break; case 2: - img = Blitz::contrast(img, true, 6); + tag = "charcoal"; + params << "x_scatter=4" << "y_scatter=4" << "scale=1" << "mix=0"; break; case 3: - img = Blitz::edge(img); + tag = "frei0r.brightness"; + params << "Brightness=0.7"; break; case 4: - img = Blitz::intensity(img, 0.5); + tag = "invert"; break; case 5: - Blitz::invert(img); - break; - case 6: - img = Blitz::threshold(img, 120, Blitz::Grayscale, qRgba(0, 0, 0, 0), qRgba(255, 0, 0, 255)); - //img = Blitz::flatten(img, QColor(255, 0, 0, 255), QColor(0, 0, 0, 0)); + tag = "threshold"; + params << "midpoint=125"; break; default: break; } -#endif - //m_bmCapture->showOverlay(img); + m_captureDevice->setOverlayEffect(tag, params); } void StopmotionWidget::sequenceNameChanged(const QString& name) @@ -633,8 +666,9 @@ void StopmotionWidget::slotNewThumb(const QString path) { if (!KdenliveSettings::showstopmotionthumbs()) return; m_filesList.append(path); - if (m_showOverlay->isChecked()) slotUpdateOverlay(); + if (m_showOverlay->isChecked()) reloadOverlay(); if (!m_future.isRunning()) m_future = QtConcurrent::run(this, &StopmotionWidget::slotPrepareThumbs); + } void StopmotionWidget::slotPrepareThumbs() @@ -839,7 +873,33 @@ void StopmotionWidget::slotSwitchAnalyse(bool isOn) { KdenliveSettings::setAnalyse_stopmotion(isOn); if (m_captureDevice) m_captureDevice->sendFrameForAnalysis = isOn; - //m_bmCapture->setAnalyse(isOn); } +void StopmotionWidget::slotSwitchMirror(bool isOn) +{ + //KdenliveSettings::setAnalyse_stopmotion(isOn); + if (m_captureDevice) m_captureDevice->mirror(isOn); +} + +const QString StopmotionWidget::createProducer(MltVideoProfile profile, const QString service, const QString resource) +{ + + QString playlist = "producer100000pause" + resource + "" + service + ""; + + // overlay track + playlist.append(""); + + // video4linux track + playlist.append(""); + + playlist.append(""); + playlist.append(""); + playlist.append(""); + playlist.append(""); + + + return playlist; +} + + diff --git a/src/stopmotion/stopmotion.h b/src/stopmotion/stopmotion.h index dcdfa39e..98636f36 100644 --- a/src/stopmotion/stopmotion.h +++ b/src/stopmotion/stopmotion.h @@ -31,6 +31,7 @@ class MltDeviceCapture; class MonitorManager; class VideoPreviewContainer; +class MltVideoProfile; class MyLabel : public QLabel { @@ -103,8 +104,6 @@ private: MltDeviceCapture *m_captureDevice; VideoPreviewContainer *m_videoBox; - - //CaptureHandler* m_bmCapture; /** @brief Holds the name of the current sequence. * Files will be saved in project folder with name: sequence001.png */ @@ -150,8 +149,15 @@ private: MonitorManager *m_manager; + /** @brief The monitor is used to control the v4l capture device from the monitormanager class. */ StopmotionMonitor *m_monitor; + /** @brief Create the XML playlist. */ + const QString createProducer(MltVideoProfile profile, const QString service, const QString resource); + + /** @brief A new frame arrived, reload overlay. */ + void reloadOverlay(); + #ifdef QIMAGEBLITZ int m_effectIndex; @@ -212,7 +218,7 @@ private slots: void slotPrepareThumbs(); /** @brief Called when user switches the video capture backend. */ - void slotUpdateHandler(); + void slotUpdateDeviceHandler(); /** @brief Show / hide sequence thumbnails. */ void slotShowThumbs(bool show); @@ -234,6 +240,9 @@ private slots: /** @brief Enable / disable frame analysis (in color scopes). */ void slotSwitchAnalyse(bool isOn); + + /** @brief Enable / disable horizontal mirror effect. */ + void slotSwitchMirror(bool isOn); /** @brief Send a notification a few seconds before capturing. */ void slotPreNotify();