* *
***************************************************************************/
-
#include "renderer.h"
#include "kdenlivesettings.h"
#include "kthumb.h"
#include <KDebug>
#include <KStandardDirs>
#include <KMessageBox>
-#include <KLocale>
+#include <KLocalizedString>
#include <KTemporaryFile>
#include <QTimer>
#include <QString>
#include <QApplication>
#include <QtConcurrentRun>
+#include <QGLWidget>
#include <cstdlib>
#include <cstdarg>
#include <QDebug>
+#include <assert.h>
#define SEEK_INACTIVE (-1)
}
}
+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)
{
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),
m_mltProducer(NULL),
m_mltProfile(NULL),
m_showFrameEvent(NULL),
+ m_consumerThreadStartedEvent(NULL),
+ m_consumerThreadStoppedEvent(NULL),
m_pauseEvent(NULL),
m_isZoneMode(false),
m_isLoopMode(false),
m_blackClip(NULL),
m_winid(winid),
m_paused(true),
- m_isActive(false)
+ m_isActive(false),
+ m_mainGLContext(mainGLContext),
+ m_GLContext(NULL)
{
qRegisterMetaType<stringMap> ("stringMap");
analyseAudio = KdenliveSettings::monitor_audio();
- if (profile.isEmpty()) profile = KdenliveSettings::current_profile();
+ if (profile.isEmpty())
+ profile = KdenliveSettings::current_profile();
buildConsumer(profile);
m_mltProducer = m_blackClip->cut(0, 1);
m_mltConsumer->connect(*m_mltProducer);
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<int>,QList<int>,stringMap)), this, SLOT(slotMultiStreamProducerFound(QString,QList<int>,QList<int>,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;
}
//delete m_osdTimer;
m_requestList.clear();
m_infoThread.waitForFinished();
- if (m_showFrameEvent) delete m_showFrameEvent;
- if (m_pauseEvent) delete m_pauseEvent;
- if (m_mltConsumer) delete m_mltConsumer;
- if (m_mltProducer) delete m_mltProducer;
+ delete m_showFrameEvent;
+ delete m_consumerThreadStartedEvent;
+ delete m_consumerThreadStoppedEvent;
+ delete m_pauseEvent;
+ delete m_mltConsumer;
+ delete m_mltProducer;
/*if (m_mltProducer) {
Mlt::Service service(m_mltProducer->parent().get_service());
service.lock();
}*/
//kDebug() << "// // // CLOSE RENDERER " << m_name;
- if (m_blackClip) delete m_blackClip;
+ delete m_blackClip;
//delete m_osdInfo;
}
void Render::slotSwitchFullscreen()
{
- if (m_mltConsumer) m_mltConsumer->set("full_screen", 1);
+ if (m_mltConsumer)
+ m_mltConsumer->set("full_screen", 1);
}
void Render::buildConsumer(const QString &profileName)
m_mltProfile->set_sample_aspect(tmpProfile.sample_aspect_num(), tmpProfile.sample_aspect_den());
m_mltProfile->get_profile()->display_aspect_num = tmpProfile.display_aspect_num();
m_mltProfile->get_profile()->display_aspect_den = tmpProfile.display_aspect_den();
- }
- else {
+ } else {
m_mltProfile = new Mlt::Profile(m_activeProfile.toUtf8().constData());
}
setenv("MLT_PROFILE", m_activeProfile.toUtf8().constData(), 1);
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) {
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());
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);
char *tmp = qstrdup(txt.toUtf8().constData());
clip = new Mlt::Producer(*m_mltProfile, tmp);
delete[] tmp;
- if (clip == NULL) clip = new Mlt::Producer(*m_mltProfile, "colour", "red");
- else {
+ if (clip == NULL) {
+ clip = new Mlt::Producer(*m_mltProfile, "colour", "red");
+ } else {
clip->set("bgcolour", "0xff0000ff");
clip->set("pad", "10");
}
}
}
- if (m_isSplitView) slotSplitView(false);
- if (!m_mltConsumer->is_stopped()) m_mltConsumer->stop();
+ if (m_isSplitView)
+ slotSplitView(false);
+ if (!m_mltConsumer->is_stopped())
+ m_mltConsumer->stop();
m_mltConsumer->purge();
}
QString scene;
- if (!dropSceneList) scene = sceneList();
+ if (!dropSceneList)
+ scene = sceneList();
int pos = 0;
double current_fps = m_mltProfile->fps();
double current_dar = m_mltProfile->dar();
return m_mltProfile->height();
}
-QImage Render::extractFrame(int frame_position, QString path, int width, int height)
+QImage Render::extractFrame(int frame_position, const QString &path, int width, int height)
{
if (width == -1) {
width = frameRenderWidth();
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()) {
}
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());
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();
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()) {
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;
const QString Render::sceneList()
{
+ if (!m_mltProducer) return QString();
QString playlist;
Mlt::Profile profile((mlt_profile) 0);
Mlt::Consumer xmlConsumer(profile, "xml:kdenlive_playlist");
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);
{
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
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);
}
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()) {
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);
}
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();
Mlt::Filter *filter = new Mlt::Filter(*m_mltProfile, qstrdup(tag.toUtf8().constData()));
if (filter && filter->is_valid()) {
filter->set("kdenlive_id", qstrdup(params.paramValue("id").toUtf8().constData()));
- int x1 = keyFrames.at(0).section(':', 0, 0).toInt();
- double y1 = keyFrames.at(0).section(':', 1, 1).toDouble();
+ int x1 = keyFrames.at(0).section('=', 0, 0).toInt();
+ double y1 = keyFrames.at(0).section('=', 1, 1).toDouble();
for (int j = 0; j < params.count(); j++) {
filter->set(params.at(j).name().toUtf8().constData(), params.at(j).value().toUtf8().constData());
}
Mlt::Filter *filter = new Mlt::Filter(*m_mltProfile, qstrdup(tag.toUtf8().constData()));
if (filter && filter->is_valid()) {
filter->set("kdenlive_id", qstrdup(params.paramValue("id").toUtf8().constData()));
- int x1 = keyFrames.at(i).section(':', 0, 0).toInt() + offset;
- double y1 = keyFrames.at(i).section(':', 1, 1).toDouble();
- int x2 = keyFrames.at(i + 1).section(':', 0, 0).toInt();
- double y2 = keyFrames.at(i + 1).section(':', 1, 1).toDouble();
+ int x1 = keyFrames.at(i).section('=', 0, 0).toInt() + offset;
+ double y1 = keyFrames.at(i).section('=', 1, 1).toDouble();
+ int x2 = keyFrames.at(i + 1).section('=', 0, 0).toInt();
+ double y2 = keyFrames.at(i + 1).section('=', 1, 1).toDouble();
if (x2 == -1) x2 = duration;
for (int j = 0; j < params.count(); j++) {
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");
delete clip;
service.unlock();
- if (doRefresh) refresh();
+ if (doRefresh)
+ refresh();
return true;
}
if (params.hasParam("_sync_in_out")) {
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 <int> effectIndexes, bool disable)
+bool Render::mltEnableEffects(int track, const GenTime &position, const QList <int> &effectIndexes, bool disable)
{
if (position < GenTime()) {
return mltEnableTrackEffects(track, effectIndexes, disable);
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);
return true;
}
-bool Render::mltEnableTrackEffects(int track, QList <int> effectIndexes, bool disable)
+bool Render::mltEnableTrackEffects(int track, const QList <int> &effectIndexes, bool disable)
{
Mlt::Service service(m_mltProducer->parent().get_service());
Mlt::Tractor tractor(service);
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);
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);
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);
//if (m_isBlocked == 0) m_mltConsumer->set("refresh", 1);
}
-QMap<QString, QString> Render::mltGetTransitionParamsFromXml(QDomElement xml)
+QMap<QString, QString> Render::mltGetTransitionParamsFromXml(const QDomElement &xml)
{
QDomNodeList attribs = xml.elementsByTagName("parameter");
QMap<QString, QString> map;
}
-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
return true;
}
-void Render::slotMultiStreamProducerFound(const QString path, QList<int> audio_list, QList<int> video_list, stringMap data)
+void Render::slotMultiStreamProducerFound(const QString &path, QList<int> audio_list, QList<int> video_list, stringMap data)
{
if (KdenliveSettings::automultistreams()) {
for (int i = 1; i < video_list.count(); ++i) {