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+++++++++++++++++++++++++++++++++++++";
displayMode->Release();
}
devicelist->addItem(deviceName, availableModes);
+ devicelist->setItemData(devicelist->count() - 1, numDevices, Qt::UserRole + 1);
found = true;
}
// 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();
<default>10</default>
</entry>
- <entry name="blitzeffect" type="Int">
+ <entry name="stopmotioneffect" type="Int">
<label>Effect applied to stopmotion frame overlay.</label>
<default>0</default>
</entry>
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) {
MltDeviceCapture::MltDeviceCapture(QString profile, VideoPreviewContainer *surface, QWidget *parent) :
AbstractRender(parent),
- doCapture(false),
+ doCapture(0),
sendFrameForAnalysis(false),
m_mltConsumer(NULL),
m_mltProducer(NULL),
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 <Mlt::Producer *> 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();
// 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();
}
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;
}
}
}
-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;
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();
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)
// 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;
}
+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());
+}
+
/** @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;
* @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;
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:
checkDeviceAvailability();
break;
case BLACKMAGIC:
- createBlackmagicDevice();
- m_recAction->setEnabled(false);
+ //createBlackmagicDevice();
+ m_recAction->setEnabled(true);
m_stopAction->setEnabled(false);
m_playAction->setEnabled(true);
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;
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:
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);
void RecMonitor::slotRecord()
{
- if (device_selector->currentIndex() == BLACKMAGIC) {
+ /*if (device_selector->currentIndex() == BLACKMAGIC) {
if (m_blackmagicCapturing) {
// We are capturing, stop it
m_bmCapture->stopCapture();
m_blackmagicCapturing = true;
}
return;
- }
+ }*/
if (m_captureProcess->state() == QProcess::NotRunning && device_selector->currentIndex() == FIREWIRE) {
slotStartCapture();
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("<producer id=\"producer0\" in=\"0\" out=\"99999\"><property name=\"mlt_type\">producer</property><property name=\"length\">100000</property><property name=\"eof\">pause</property><property name=\"resource\">%1</property><property name=\"mlt_service\">decklink</property></producer>").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:
#include <kdeversion.h>
#include <KNotification>
-#ifdef QIMAGEBLITZ
-#include <qimageblitz/qimageblitz.h>
-#endif
-
#include <QtConcurrentRun>
#include <QInputDialog>
#include <QComboBox>
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"));
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);
}
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);
confMenu->addAction(showThumbs);
confMenu->addAction(removeCurrent);
confMenu->addAction(analyse);
+ confMenu->addAction(mirror);
confMenu->addAction(conf);
config_button->setIcon(KIcon("configure"));
config_button->setMenu(confMenu);
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)
}
}
}
-
- //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)));
video_preview->setLayout(layout);
//kDebug()<<video_preview->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)));
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)
}
-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) {
if (isOn) {
m_frame_preview->setHidden(true);
m_videoBox->setHidden(false);
- QString path = KStandardDirs::locateLocal("appdata", "profiles/video4linux");
- kDebug()<<"SURFACE; "<<m_videoBox->width()<<"x"<<m_videoBox->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')));
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)
{
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()
{
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 = "<mlt title=\"capture\"><producer id=\"producer0\" in=\"0\" out=\"99999\"><property name=\"mlt_type\">producer</property><property name=\"length\">100000</property><property name=\"eof\">pause</property><property name=\"resource\">" + resource + "</property><property name=\"mlt_service\">" + service + "</property></producer>";
+
+ // overlay track
+ playlist.append("<playlist id=\"playlist0\"></playlist>");
+
+ // video4linux track
+ playlist.append("<playlist id=\"playlist1\"><entry producer=\"producer0\" in=\"0\" out=\"99999\"/></playlist>");
+
+ playlist.append("<tractor id=\"tractor0\" title=\"video0\" global_feed=\"1\" in=\"0\" out=\"99999\">");
+ playlist.append("<track producer=\"playlist0\"/>");
+ playlist.append("<track producer=\"playlist1\"/>");
+ playlist.append("</tractor></mlt>");
+
+
+ return playlist;
+}
+
+
class MltDeviceCapture;
class MonitorManager;
class VideoPreviewContainer;
+class MltVideoProfile;
class MyLabel : public QLabel
{
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 */
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;
void slotPrepareThumbs();
/** @brief Called when user switches the video capture backend. */
- void slotUpdateHandler();
+ void slotUpdateDeviceHandler();
/** @brief Show / hide sequence thumbnails. */
void slotShowThumbs(bool show);
/** @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();