X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fmltdevicecapture.cpp;h=c94f896dd2707840e243a43acfd3037407b0d7d7;hb=56aee6aedeeed3efd10ada8fe3c229eddc01ef05;hp=c92b18c29dd67a3153c69bbf1aaf4556b1a217cd;hpb=ebf3022e8b804b2e6fc1e92e995ac42d3c20f29a;p=kdenlive diff --git a/src/mltdevicecapture.cpp b/src/mltdevicecapture.cpp index c92b18c2..c94f896d 100644 --- a/src/mltdevicecapture.cpp +++ b/src/mltdevicecapture.cpp @@ -19,16 +19,14 @@ #include "mltdevicecapture.h" #include "kdenlivesettings.h" #include "definitions.h" -//#include "recmonitor.h" -//#include "renderer.h" -#include "blackmagic/devices.h" +#include "widgets/videosurface.h" #include #include #include #include -#include +#include #include #include @@ -36,6 +34,7 @@ #include #include #include +#include #include #include @@ -51,12 +50,12 @@ static void consumer_gl_frame_show(mlt_consumer, MltDeviceCapture * self, mlt_fr self->showFrame(frame); } -static void rec_consumer_frame_show(mlt_consumer, MltDeviceCapture * self, mlt_frame frame_ptr) +/*static void rec_consumer_frame_show(mlt_consumer, MltDeviceCapture * self, mlt_frame frame_ptr) { Mlt::Frame frame(frame_ptr); if (!frame.is_valid()) return; self->gotCapturedFrame(frame); -} +}*/ static void rec_consumer_frame_preview(mlt_consumer, MltDeviceCapture * self, mlt_frame frame_ptr) { @@ -71,31 +70,36 @@ static void rec_consumer_frame_preview(mlt_consumer, MltDeviceCapture * self, ml } //TODO: connect record monitor to audio scopes - /* + if (self->analyseAudio) { self->showAudio(frame); } - */ + } -MltDeviceCapture::MltDeviceCapture(QString profile, VideoPreviewContainer *surface, QWidget *parent) : - AbstractRender("capture", parent), +MltDeviceCapture::MltDeviceCapture(QString profile, VideoSurface *surface, QWidget *parent) : + AbstractRender(Kdenlive::RecordMonitor, parent), doCapture(0), sendFrameForAnalysis(false), - analyseAudio(KdenliveSettings::monitor_audio()), processingImage(false), m_mltConsumer(NULL), m_mltProducer(NULL), m_mltProfile(NULL), + m_showFrameEvent(NULL), m_droppedFrames(0), - m_livePreview(KdenliveSettings::recording_preview()), - m_captureDisplayWidget(surface), + m_livePreview(KdenliveSettings::enable_recording_preview()), m_winid((int) surface->winId()) { - if (profile.isEmpty()) profile = KdenliveSettings::current_profile(); + m_captureDisplayWidget = surface; + analyseAudio = KdenliveSettings::monitor_audio(); + if (profile.isEmpty()) + profile = KdenliveSettings::current_profile(); buildConsumer(profile); connect(this, SIGNAL(unblockPreview()), this, SLOT(slotPreparePreview())); + m_droppedFramesTimer.setSingleShot(false); + m_droppedFramesTimer.setInterval(1000); + connect(&m_droppedFramesTimer, SIGNAL(timeout()), this, SLOT(slotCheckDroppedFrames())); } MltDeviceCapture::~MltDeviceCapture() @@ -127,17 +131,18 @@ void MltDeviceCapture::buildConsumer(const QString &profileName) } } setenv("SDL_VIDEO_ALLOW_SCREENSAVER", "1", 1); - + + if (m_winid == 0) { // OpenGL monitor m_mltConsumer = new Mlt::Consumer(*m_mltProfile, "sdl_audio"); m_mltConsumer->set("preview_off", 1); m_mltConsumer->set("preview_format", mlt_image_rgb24); - m_mltConsumer->listen("consumer-frame-show", this, (mlt_listener) consumer_gl_frame_show); + m_showFrameEvent = m_mltConsumer->listen("consumer-frame-show", this, (mlt_listener) consumer_gl_frame_show); } else { m_mltConsumer = new Mlt::Consumer(*m_mltProfile, "sdl_preview"); m_mltConsumer->set("window_id", m_winid); - m_mltConsumer->listen("consumer-frame-show", this, (mlt_listener) rec_consumer_frame_preview); + m_showFrameEvent = m_mltConsumer->listen("consumer-frame-show", this, (mlt_listener) rec_consumer_frame_preview); } //m_mltConsumer->set("resize", 1); //m_mltConsumer->set("terminate_on_pause", 1); @@ -161,15 +166,29 @@ void MltDeviceCapture::buildConsumer(const QString &profileName) //m_mltConsumer->set("real_time", 0); } +void MltDeviceCapture::pause() +{ + if (m_mltConsumer) { + m_mltConsumer->set("refresh", 0); + //m_mltProducer->set_speed(0.0); + m_mltConsumer->purge(); + } +} + void MltDeviceCapture::stop() { + m_droppedFramesTimer.stop(); bool isPlaylist = false; - disconnect(this, SIGNAL(imageReady(QImage)), this, SIGNAL(frameUpdated(QImage))); - m_captureDisplayWidget->stop(); + //disconnect(this, SIGNAL(imageReady(QImage)), this, SIGNAL(frameUpdated(QImage))); + //m_captureDisplayWidget->stop(); + + if (m_showFrameEvent) delete m_showFrameEvent; + m_showFrameEvent = NULL; if (m_mltConsumer) { m_mltConsumer->set("refresh", 0); - m_mltConsumer->stop(); + m_mltConsumer->purge(); + m_mltConsumer->stop(); //if (!m_mltConsumer->is_stopped()) m_mltConsumer->stop(); } if (m_mltProducer) { @@ -209,9 +228,16 @@ void MltDeviceCapture::stop() } -void MltDeviceCapture::doRefresh() +void MltDeviceCapture::slotDoRefresh() { - if (m_mltConsumer) m_mltConsumer->set("refresh", 1); + QMutexLocker locker(&m_mutex); + if (!m_mltProducer) + return; + if (m_mltConsumer) { + if (m_mltConsumer->is_stopped()) m_mltConsumer->start(); + m_mltConsumer->purge(); + m_mltConsumer->set("refresh", 1); + } } @@ -233,9 +259,10 @@ void MltDeviceCapture::emitFrameUpdated(Mlt::Frame& frame) int width = 0; int height = 0; const uchar* image = frame.get_image(format, width, height); - QImage qimage(width, height, QImage::Format_ARGB32); + QImage qimage(width, height, QImage::Format_RGB888); + //QImage qimage(width, height, QImage::Format_ARGB32_Premultiplied); memcpy(qimage.bits(), image, width * height * 3); - emit frameUpdated(qimage.rgbSwapped()); + emit frameUpdated(qimage); } void MltDeviceCapture::showFrame(Mlt::Frame& frame) @@ -272,7 +299,6 @@ void MltDeviceCapture::showAudio(Mlt::Frame& frame) // So the vector is of size samples*channels. QVector sampleVector(samples*num_channels); memcpy(sampleVector.data(), data, samples*num_channels*sizeof(int16_t)); - if (samples > 0) { emit audioSamplesSignal(sampleVector, freq, num_channels, samples); } @@ -302,10 +328,22 @@ bool MltDeviceCapture::slotStartPreview(const QString &producer, bool xmlFormat) m_mltConsumer = NULL; return 0; } - connect(this, SIGNAL(imageReady(QImage)), this, SIGNAL(frameUpdated(QImage))); + m_droppedFramesTimer.start(); + //connect(this, SIGNAL(imageReady(QImage)), this, SIGNAL(frameUpdated(QImage))); return 1; } +void MltDeviceCapture::slotCheckDroppedFrames() +{ + if (m_mltProducer) { + int dropped = m_mltProducer->get_int("dropped"); + if (dropped > m_droppedFrames) { + m_droppedFrames = dropped; + emit droppedFrames(m_droppedFrames); + } + } +} + void MltDeviceCapture::gotCapturedFrame(Mlt::Frame& frame) { if (m_mltProducer) { @@ -316,8 +354,8 @@ void MltDeviceCapture::gotCapturedFrame(Mlt::Frame& frame) } } m_frameCount++; - if (m_livePreview == 2) return; - if (m_livePreview == 0 && (m_frameCount % 10 > 0)) return; + if (!m_livePreview) return; + //if (m_livePreview == 0 && (m_frameCount % 10 > 0)) return; mlt_image_format format = mlt_image_rgb24; int width = 0; int height = 0; @@ -326,7 +364,7 @@ void MltDeviceCapture::gotCapturedFrame(Mlt::Frame& frame) //memcpy(image.bits(), data, width * height * 3); QImage image((uchar *)data, width, height, QImage::Format_RGB888); - m_captureDisplayWidget->setImage(image); + //m_captureDisplayWidget->setImage(image); //TEST: is it better to process frame conversion ouside MLT??? /* @@ -381,7 +419,7 @@ void MltDeviceCapture::captureFrame(const QString &path) doCapture = 5; } -bool MltDeviceCapture::slotStartCapture(const QString ¶ms, const QString &path, const QString &playlist, int livePreview, bool xmlPlaylist) +bool MltDeviceCapture::slotStartCapture(const QString ¶ms, const QString &path, const QString &playlist, bool livePreview, bool xmlPlaylist) { stop(); m_livePreview = livePreview; @@ -391,58 +429,131 @@ bool MltDeviceCapture::slotStartCapture(const QString ¶ms, const QString &pa char *tmp = qstrdup(m_activeProfile.toUtf8().constData()); m_mltProfile = new Mlt::Profile(tmp); delete[] tmp; - m_mltProfile->get_profile()->is_explicit = 1; - kDebug()<<"-- CREATING CAP: "<get_profile()->is_explicit = 1; + + + /*kDebug()<<"-- CREATING CAP: "<set("real_time", -KdenliveSettings::mltthreads()); - delete[] tmp; + delete[] tmp;*/ + + m_mltConsumer = new Mlt::Consumer(*m_mltProfile, "multi"); + if (m_mltConsumer == NULL || !m_mltConsumer->is_valid()) { + if (m_mltConsumer) { + delete m_mltConsumer; + m_mltConsumer = NULL; + } + return false; + } + + m_winid = (int) m_captureDisplayWidget->winId(); + + // Create multi consumer setup + Mlt::Properties *renderProps = new Mlt::Properties; + renderProps->set("mlt_service", "avformat"); + renderProps->set("target", path.toUtf8().constData()); + renderProps->set("real_time", -KdenliveSettings::mltthreads()); + //renderProps->set("terminate_on_pause", 0); + renderProps->set("mlt_profile", m_activeProfile.toUtf8().constData()); + - QStringList paramList = params.split(" ", QString::SkipEmptyParts); + QStringList paramList = params.split(' ', QString::SkipEmptyParts); char *tmp2; - for (int i = 0; i < paramList.count(); i++) { - tmp = qstrdup(paramList.at(i).section("=", 0, 0).toUtf8().constData()); - QString value = paramList.at(i).section("=", 1, 1); + for (int i = 0; i < paramList.count(); ++i) { + tmp = qstrdup(paramList.at(i).section('=', 0, 0).toUtf8().constData()); + QString value = paramList.at(i).section('=', 1, 1); if (value == "%threads") value = QString::number(QThread::idealThreadCount()); tmp2 = qstrdup(value.toUtf8().constData()); - m_mltConsumer->set(tmp, tmp2); + renderProps->set(tmp, tmp2); delete[] tmp; delete[] tmp2; } + mlt_properties consumerProperties = m_mltConsumer->get_properties(); + mlt_properties_set_data(consumerProperties, "0", renderProps->get_properties(), 0, (mlt_destructor) mlt_properties_close, NULL); - if (m_mltConsumer == NULL || !m_mltConsumer->is_valid()) { - if (m_mltConsumer) { - delete m_mltConsumer; - m_mltConsumer = NULL; + if (m_livePreview) + { + // user wants live preview + Mlt::Properties *previewProps = new Mlt::Properties; + QString videoDriver = KdenliveSettings::videodrivername(); + if (!videoDriver.isEmpty()) { + if (videoDriver == "x11_noaccel") { + setenv("SDL_VIDEO_YUV_HWACCEL", "0", 1); + videoDriver = "x11"; + } else { + unsetenv("SDL_VIDEO_YUV_HWACCEL"); + } } - return false; + setenv("SDL_VIDEO_ALLOW_SCREENSAVER", "1", 1); + + if (m_winid == 0) { + // OpenGL monitor + previewProps->set("mlt_service", "sdl_audio"); + previewProps->set("preview_off", 1); + previewProps->set("preview_format", mlt_image_rgb24); + previewProps->set("terminate_on_pause", 0); + m_showFrameEvent = m_mltConsumer->listen("consumer-frame-show", this, (mlt_listener) consumer_gl_frame_show); + } else { + previewProps->set("mlt_service", "sdl_preview"); + previewProps->set("window_id", m_winid); + previewProps->set("terminate_on_pause", 0); + //m_showFrameEvent = m_mltConsumer->listen("consumer-frame-show", this, (mlt_listener) rec_consumer_frame_preview); + } + //m_mltConsumer->set("resize", 1); + previewProps->set("window_background", KdenliveSettings::window_background().name().toUtf8().constData()); + QString audioDevice = KdenliveSettings::audiodevicename(); + if (!audioDevice.isEmpty()) + previewProps->set("audio_device", audioDevice.toUtf8().constData()); + + if (!videoDriver.isEmpty()) + previewProps->set("video_driver", videoDriver.toUtf8().constData()); + + QString audioDriver = KdenliveSettings::audiodrivername(); + + if (!audioDriver.isEmpty()) + previewProps->set("audio_driver", audioDriver.toUtf8().constData()); + + previewProps->set("real_time", "0"); + previewProps->set("mlt_profile", m_activeProfile.toUtf8().constData()); + mlt_properties_set_data(consumerProperties, "1", previewProps->get_properties(), 0, (mlt_destructor) mlt_properties_close, NULL); + //m_showFrameEvent = m_mltConsumer->listen("consumer-frame-render", this, (mlt_listener) rec_consumer_frame_show); + } + else { + } - // FIXME: the event object returned by the listen gets leaked... - if (m_livePreview < 2) m_mltConsumer->listen("consumer-frame-render", this, (mlt_listener) rec_consumer_frame_show); - tmp = qstrdup(playlist.toUtf8().constData()); if (xmlPlaylist) { // create an xml producer - m_mltProducer = new Mlt::Producer(*m_mltProfile, "xml-string", tmp); + m_mltProducer = new Mlt::Producer(*m_mltProfile, "xml-string", playlist.toUtf8().constData()); } else { // create a producer based on mltproducer parameter - m_mltProducer = new Mlt::Producer(*m_mltProfile, tmp); + m_mltProducer = new Mlt::Producer(*m_mltProfile, playlist.toUtf8().constData()); } - delete[] tmp; if (m_mltProducer == NULL || !m_mltProducer->is_valid()) { kDebug()<<"//// ERROR CREATRING PROD"; + if (m_mltConsumer) { + delete m_mltConsumer; + m_mltConsumer = NULL; + } + if (m_mltProducer) { + delete m_mltProducer; + m_mltProducer = NULL; + } return false; } m_mltConsumer->connect(*m_mltProducer); if (m_mltConsumer->start() == -1) { + if (m_showFrameEvent) delete m_showFrameEvent; + m_showFrameEvent = NULL; delete m_mltConsumer; m_mltConsumer = NULL; return 0; } - m_captureDisplayWidget->start(); + m_droppedFramesTimer.start(); return 1; } @@ -504,7 +615,7 @@ void MltDeviceCapture::setOverlay(const QString &path) //delete clip; } -void MltDeviceCapture::setOverlayEffect(const QString &tag, QStringList parameters) +void MltDeviceCapture::setOverlayEffect(const QString &tag, const QStringList ¶meters) { if (m_mltProducer == NULL || !m_mltProducer->is_valid()) return; Mlt::Service service(m_mltProducer->parent().get_service()); @@ -542,7 +653,7 @@ void MltDeviceCapture::setOverlayEffect(const QString &tag, QStringList paramete 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()); + filter->set(parameters.at(j).section('=', 0, 0).toUtf8().constData(), parameters.at(j).section('=', 1, 1).toUtf8().constData()); } trackService.attach(*filter); } @@ -647,7 +758,7 @@ void MltDeviceCapture::uyvy2rgb(unsigned char *yuv_buffer, int width, int height rgb_ptr += 3; } //emit imageReady(image); - m_captureDisplayWidget->setImage(image); + //m_captureDisplayWidget->setImage(image); emit unblockPreview(); //processingImage = false; } @@ -663,3 +774,5 @@ void MltDeviceCapture::slotAllowPreview() } + +#include "mltdevicecapture.moc"