X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Frenderer.cpp;h=880a9653b21d3171ae16d3946057bb17a3fae283;hb=234d7fe2828b8e82253548e32081576fc56cbb80;hp=08a011f6bb12ca56ab0fbaf42ee43454446950c0;hpb=365e5880d7235999249df283930359533a3fcf1b;p=kdenlive diff --git a/src/renderer.cpp b/src/renderer.cpp index 08a011f6..880a9653 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -22,7 +22,6 @@ * * ***************************************************************************/ - #include "renderer.h" #include "kdenlivesettings.h" #include "kthumb.h" @@ -35,7 +34,7 @@ #include #include #include -#include +#include #include #include @@ -43,11 +42,13 @@ #include #include #include +#include #include #include #include +#include #define SEEK_INACTIVE (-1) @@ -81,6 +82,32 @@ void Render::consumer_frame_show(mlt_consumer, Render * self, mlt_frame frame_pt } } +void Render::consumer_thread_started(mlt_consumer, Render * self, mlt_frame) +{ + pthread_t thr = pthread_self(); + if (self->m_renderThreadGLContexts.count(thr) == 0) { + QGLWidget *ctx = new QGLWidget(0, self->m_mainGLContext); + ctx->resize(0, 0); + self->m_renderThreadGLContexts.insert(thr, ctx); + } + self->m_renderThreadGLContexts[thr]->makeCurrent(); + self->m_glslManager->fire_event("init glsl"); + if (!self->m_glslManager->get_int("glsl_supported")) { + QMessageBox::critical(NULL, i18n("Movit failed initialization"), + i18n("Initialization of OpenGL filters failed. Exiting.")); + qApp->quit(); + } +} + +void Render::consumer_thread_stopped(mlt_consumer, Render * self, mlt_frame) +{ + pthread_t thr = pthread_self(); + assert(self->m_renderThreadGLContexts.count(thr) != 0); + self->m_renderThreadGLContexts[thr]->makeCurrent(); + delete self->m_renderThreadGLContexts[thr]; + self->m_renderThreadGLContexts.remove(thr); +} + /* static void consumer_paused(mlt_consumer, Render * self, mlt_frame frame_ptr) { @@ -111,7 +138,7 @@ void Render::consumer_gl_frame_show(mlt_consumer consumer, Render * self, mlt_fr emit self->mltFrameReceived(new Mlt::Frame(frame_ptr)); } -Render::Render(Kdenlive::MONITORID rendererName, int winid, QString profile, QWidget *parent) : +Render::Render(Kdenlive::MonitorId rendererName, int winid, QString profile, QWidget *parent, QGLWidget *mainGLContext) : AbstractRender(rendererName, parent), requestedSeekPosition(SEEK_INACTIVE), showFrameSemaphore(1), @@ -121,6 +148,8 @@ Render::Render(Kdenlive::MONITORID rendererName, int winid, QString profile, QWi m_mltProducer(NULL), m_mltProfile(NULL), m_showFrameEvent(NULL), + m_consumerThreadStartedEvent(NULL), + m_consumerThreadStoppedEvent(NULL), m_pauseEvent(NULL), m_isZoneMode(false), m_isLoopMode(false), @@ -128,7 +157,9 @@ Render::Render(Kdenlive::MONITORID rendererName, int winid, QString profile, QWi m_blackClip(NULL), m_winid(winid), m_paused(true), - m_isActive(false) + m_isActive(false), + m_mainGLContext(mainGLContext), + m_GLContext(NULL) { qRegisterMetaType ("stringMap"); analyseAudio = KdenliveSettings::monitor_audio(); @@ -140,16 +171,21 @@ Render::Render(Kdenlive::MONITORID rendererName, int winid, QString profile, QWi m_mltProducer->set_speed(0.0); m_refreshTimer.setSingleShot(true); m_refreshTimer.setInterval(100); + m_glslManager = new Mlt::Filter(*m_mltProfile, "glsl.manager"); connect(&m_refreshTimer, SIGNAL(timeout()), this, SLOT(refresh())); connect(this, SIGNAL(multiStreamFound(QString,QList,QList,stringMap)), this, SLOT(slotMultiStreamProducerFound(QString,QList,QList,stringMap))); connect(this, SIGNAL(checkSeeking()), this, SLOT(slotCheckSeeking())); connect(this, SIGNAL(mltFrameReceived(Mlt::Frame*)), this, SLOT(showFrame(Mlt::Frame*)), Qt::UniqueConnection); + + m_GLContext = new QGLWidget(0, m_mainGLContext); + m_GLContext->resize(0, 0); } Render::~Render() { closeMlt(); delete m_mltProfile; + delete m_GLContext; } @@ -159,6 +195,8 @@ void Render::closeMlt() m_requestList.clear(); m_infoThread.waitForFinished(); delete m_showFrameEvent; + delete m_consumerThreadStartedEvent; + delete m_consumerThreadStoppedEvent; delete m_pauseEvent; delete m_mltConsumer; delete m_mltProducer; @@ -227,7 +265,7 @@ void Render::buildConsumer(const QString &profileName) m_blackClip = new Mlt::Producer(*m_mltProfile, "colour:black"); m_blackClip->set("id", "black"); m_blackClip->set("mlt_type", "producer"); - if (KdenliveSettings::external_display() && m_name != Kdenlive::clipMonitor && m_winid != 0) { + if (KdenliveSettings::external_display() && m_name != Kdenlive::ClipMonitor && m_winid != 0) { // Use blackmagic card for video output int device = KdenliveSettings::blackmagic_output_device(); if (device >= 0) { @@ -267,7 +305,7 @@ void Render::buildConsumer(const QString &profileName) if (m_winid == 0) { // OpenGL monitor if (!m_mltConsumer) { - if (KdenliveSettings::external_display() && m_name != Kdenlive::clipMonitor) { + if (KdenliveSettings::external_display() && m_name != Kdenlive::ClipMonitor) { int device = KdenliveSettings::blackmagic_output_device(); if (device >= 0) { QString decklink = "decklink:" + QString::number(KdenliveSettings::blackmagic_output_device()); @@ -285,7 +323,9 @@ void Render::buildConsumer(const QString &profileName) m_mltConsumer->set("scrub_audio", 1); m_mltConsumer->set("preview_off", 1); m_mltConsumer->set("audio_buffer", 512); - m_mltConsumer->set("preview_format", mlt_image_rgb24a); + m_mltConsumer->set("mlt_image_format", "glsl"); + m_consumerThreadStartedEvent = m_mltConsumer->listen("consumer-thread-started", this, (mlt_listener) consumer_thread_started); + m_consumerThreadStoppedEvent = m_mltConsumer->listen("consumer-thread-stopped", this, (mlt_listener) consumer_thread_stopped); } m_mltConsumer->set("buffer", "1"); m_showFrameEvent = m_mltConsumer->listen("consumer-frame-show", this, (mlt_listener) consumer_gl_frame_show); @@ -704,6 +744,10 @@ bool Render::isProcessing(const QString &id) void Render::processFileProperties() { + // We are in a new thread, so we need a new OpenGL context for the remainder of the function. + QGLWidget ctx(0, m_mainGLContext); + ctx.makeCurrent(); + requestClipInfo info; QLocale locale; while (!m_requestList.isEmpty()) { @@ -731,10 +775,10 @@ void Render::processFileProperties() } KUrl url(path); Mlt::Producer *producer = NULL; - CLIPTYPE type = (CLIPTYPE)info.xml.attribute("type").toInt(); - if (type == COLOR) { + ClipType type = (ClipType)info.xml.attribute("type").toInt(); + if (type == Color) { producer = new Mlt::Producer(*m_mltProfile, 0, ("colour:" + info.xml.attribute("colour")).toUtf8().constData()); - } else if (type == TEXT) { + } else if (type == Text) { producer = new Mlt::Producer(*m_mltProfile, 0, ("kdenlivetitle:" + info.xml.attribute("resource")).toUtf8().constData()); if (producer && producer->is_valid() && info.xml.hasAttribute("xmldata")) producer->set("xmldata", info.xml.attribute("xmldata").toUtf8().constData()); @@ -837,7 +881,7 @@ void Render::processFileProperties() if (info.xml.hasAttribute("out")) clipOut = info.xml.attribute("out").toInt(); // setup length here as otherwise default length (currently 15000 frames in MLT) will be taken even if outpoint is larger - if (type == COLOR || type == TEXT || type == IMAGE || type == SLIDESHOW) { + if (type == Color || type == Text || type == Image || type == SlideShow) { int length; if (info.xml.hasAttribute("length")) { length = info.xml.attribute("length").toInt(); @@ -892,7 +936,7 @@ void Render::processFileProperties() filePropertyMap["duration"] = QString::number(duration); //kDebug() << "/////// PRODUCER: " << url.path() << " IS: " << producer->get_playtime(); - if (type == SLIDESHOW) { + if (type == SlideShow) { int ttl = info.xml.hasAttribute("ttl") ? info.xml.attribute("ttl").toInt() : 0; if (ttl) producer->set("ttl", ttl); if (!info.xml.attribute("animation").isEmpty()) { @@ -1249,6 +1293,10 @@ void Render::startConsumer() { KMessageBox::error(qApp->activeWindow(), i18n("Could not create the video preview window.\nThere is something wrong with your Kdenlive install or your driver settings, please fix it.")); if (m_showFrameEvent) delete m_showFrameEvent; m_showFrameEvent = NULL; + if (m_consumerThreadStartedEvent) delete m_consumerThreadStartedEvent; + m_consumerThreadStartedEvent = NULL; + if (m_consumerThreadStoppedEvent) delete m_consumerThreadStoppedEvent; + m_consumerThreadStoppedEvent = NULL; if (m_pauseEvent) delete m_pauseEvent; m_pauseEvent = NULL; delete m_mltConsumer; @@ -1413,6 +1461,7 @@ void Render::checkMaxThreads() const QString Render::sceneList() { + if (!m_mltProducer) return QString(); QString playlist; Mlt::Profile profile((mlt_profile) 0); Mlt::Consumer xmlConsumer(profile, "xml:kdenlive_playlist"); @@ -1459,7 +1508,7 @@ void Render::saveZone(KUrl url, QString desc, QPoint zone) Mlt::Consumer xmlConsumer(*m_mltProfile, ("xml:" + url.path()).toUtf8().constData()); m_mltProducer->optimise(); xmlConsumer.set("terminate_on_pause", 1); - if (m_name == Kdenlive::clipMonitor) { + if (m_name == Kdenlive::ClipMonitor) { Mlt::Producer *prod = m_mltProducer->cut(zone.x(), zone.y()); Mlt::Playlist list; list.insert_at(0, prod, 0); @@ -1524,7 +1573,7 @@ void Render::slotSetVolume(int volume) { if (!m_mltConsumer || !m_mltProducer) return; m_mltProducer->set("meta.volume", (double)volume / 100.0); - return; + //return; /*osdTimer->stop(); m_mltConsumer->set("refresh", 0); // Attach filter for on screen display of timecode @@ -1538,7 +1587,7 @@ void Render::slotSetVolume(int volume) mlt_properties_set_int( properties, "meta.attr.timecode", 0); if (m_mltProducer->attach(*m_osdInfo) == 1) kDebug()<<"////// error attaching filter"; }*/ - refresh(); + //refresh(); //m_osdTimer->setSingleShot(2500); } @@ -1632,7 +1681,7 @@ void Render::switchPlay(bool play) return; if (m_isZoneMode) resetZoneMode(); if (play && m_paused) { - if (m_name == Kdenlive::clipMonitor && m_mltConsumer->position() == m_mltProducer->get_out()) m_mltProducer->seek(0); + if (m_name == Kdenlive::ClipMonitor && m_mltConsumer->position() == m_mltProducer->get_out()) m_mltProducer->seek(0); m_paused = false; m_mltProducer->set_speed(1.0); if (m_mltConsumer->is_stopped()) { @@ -1813,12 +1862,12 @@ int Render::seekFramePosition() const void Render::emitFrameUpdated(Mlt::Frame& frame) { - mlt_image_format format = mlt_image_rgb24; + mlt_image_format format = mlt_image_rgb24a; int width = 0; int height = 0; const uchar* image = frame.get_image(format, width, height); - QImage qimage(width, height, QImage::Format_RGB888); //Format_ARGB32_Premultiplied); - memcpy(qimage.scanLine(0), image, width * height * 3); + QImage qimage(width, height, QImage::Format_ARGB32_Premultiplied); + memcpy(qimage.scanLine(0), image, width * height * 4); emit frameUpdated(qimage); } @@ -1896,18 +1945,25 @@ void Render::showFrame(Mlt::Frame* frame) if (currentPos == requestedSeekPosition) requestedSeekPosition = SEEK_INACTIVE; emit rendererPosition(currentPos); if (frame->is_valid()) { - mlt_image_format format = mlt_image_rgb24; + mlt_image_format format = mlt_image_glsl_texture; int width = 0; int height = 0; - const uchar* image = frame->get_image(format, width, height); - QImage qimage(width, height, QImage::Format_RGB888); //Format_ARGB32_Premultiplied); - memcpy(qimage.scanLine(0), image, width * height * 3); - if (analyseAudio) showAudio(*frame); - delete frame; - emit showImageSignal(qimage); - if (sendFrameForAnalysis) { - emit frameUpdated(qimage); - } + m_GLContext->makeCurrent(); + frame->set("movit.convert.use_texture", 1); + const uint8_t* image = frame->get_image(format, width, height); + const GLuint* texnum = (GLuint *)image; + if (format == mlt_image_glsl_texture) { + emit showImageSignal(frame, *texnum); + } else { + QImage qimage(width, height, QImage::Format_ARGB32_Premultiplied); + memcpy(qimage.scanLine(0), image, width * height * 4); + if (analyseAudio) showAudio(*frame); + delete frame; + emit showImageSignal(qimage); + if (sendFrameForAnalysis) { + emit frameUpdated(qimage); + } + } } else delete frame; showFrameSemaphore.release(); emit checkSeeking(); @@ -3037,7 +3093,7 @@ bool Render::mltEditTrackEffect(int track, EffectsParameterList params) return true; } -bool Render::mltEditEffect(int track, GenTime position, EffectsParameterList params) +bool Render::mltEditEffect(int track, const GenTime &position, EffectsParameterList params) { int index = params.paramValue("kdenlive_ix").toInt(); QString tag = params.paramValue("tag"); @@ -3117,7 +3173,8 @@ bool Render::mltEditEffect(int track, GenTime position, EffectsParameterList par delete clip; service.unlock(); - if (doRefresh) refresh(); + if (doRefresh) + refresh(); return true; } if (params.hasParam("_sync_in_out")) { @@ -3126,22 +3183,23 @@ bool Render::mltEditEffect(int track, GenTime position, EffectsParameterList par filter->set_in_and_out(clip->get_in(), clip->get_out()); } - for (int j = 0; j < params.count(); j++) { + for (int j = 0; j < params.count(); ++j) { filter->set(params.at(j).name().toUtf8().constData(), params.at(j).value().toUtf8().constData()); } - for (int j = 0; j < filtersList.count(); j++) { + for (int j = 0; j < filtersList.count(); ++j) { clip->attach(*(filtersList.at(j))); } delete clip; service.unlock(); - if (doRefresh) refresh(); + if (doRefresh) + refresh(); return true; } -bool Render::mltEnableEffects(int track, GenTime position, QList effectIndexes, bool disable) +bool Render::mltEnableEffects(int track, const GenTime &position, const QList &effectIndexes, bool disable) { if (position < GenTime()) { return mltEnableTrackEffects(track, effectIndexes, disable); @@ -3168,6 +3226,7 @@ bool Render::mltEnableEffects(int track, GenTime position, QList effectInd int ct = 0; Mlt::Filter *filter = clip->filter(ct); + service.lock(); while (filter) { if (effectIndexes.contains(filter->get_int("kdenlive_ix"))) { filter->set("disable", (int) disable); @@ -3183,7 +3242,7 @@ bool Render::mltEnableEffects(int track, GenTime position, QList effectInd return true; } -bool Render::mltEnableTrackEffects(int track, QList effectIndexes, bool disable) +bool Render::mltEnableTrackEffects(int track, const QList &effectIndexes, bool disable) { Mlt::Service service(m_mltProducer->parent().get_service()); Mlt::Tractor tractor(service); @@ -3193,6 +3252,7 @@ bool Render::mltEnableTrackEffects(int track, QList effectIndexes, bool di int ct = 0; Mlt::Filter *filter = clipService.filter(ct); + service.lock(); while (filter) { if (effectIndexes.contains(filter->get_int("kdenlive_ix"))) { filter->set("disable", (int) disable); @@ -3206,7 +3266,7 @@ bool Render::mltEnableTrackEffects(int track, QList effectIndexes, bool di return true; } -void Render::mltUpdateEffectPosition(int track, GenTime position, int oldPos, int newPos) +void Render::mltUpdateEffectPosition(int track, const GenTime &position, int oldPos, int newPos) { Mlt::Service service(m_mltProducer->parent().get_service()); Mlt::Tractor tractor(service); @@ -3240,7 +3300,7 @@ void Render::mltUpdateEffectPosition(int track, GenTime position, int oldPos, in if (doRefresh) refresh(); } -void Render::mltMoveEffect(int track, GenTime position, int oldPos, int newPos) +void Render::mltMoveEffect(int track, const GenTime &position, int oldPos, int newPos) { if (position < GenTime()) { mltMoveTrackEffect(track, oldPos, newPos); @@ -4088,7 +4148,7 @@ void Render::mltDeleteTransition(QString tag, int /*a_track*/, int b_track, GenT //if (m_isBlocked == 0) m_mltConsumer->set("refresh", 1); } -QMap Render::mltGetTransitionParamsFromXml(QDomElement xml) +QMap Render::mltGetTransitionParamsFromXml(const QDomElement &xml) { QDomNodeList attribs = xml.elementsByTagName("parameter"); QMap map; @@ -4564,7 +4624,7 @@ void Render::updatePreviewSettings() } -QString Render::updateSceneListFps(double current_fps, double new_fps, QString scene) +QString Render::updateSceneListFps(double current_fps, double new_fps, const QString &scene) { // Update all frame positions to the new fps value //WARNING: there are probably some effects or other that hold a frame value @@ -4731,7 +4791,7 @@ bool Render::getBlackMagicOutputDeviceList(KComboBox *devicelist, bool force) return true; } -void Render::slotMultiStreamProducerFound(const QString path, QList audio_list, QList video_list, stringMap data) +void Render::slotMultiStreamProducerFound(const QString &path, QList audio_list, QList video_list, stringMap data) { if (KdenliveSettings::automultistreams()) { for (int i = 1; i < video_list.count(); ++i) {