1 /***************************************************************************
2 krender.cpp - description
4 begin : Fri Nov 22 2002
5 copyright : (C) 2002 by Jason Wood
6 email : jasonwood@blueyonder.co.uk
7 copyright : (C) 2005 Lucio Flavio Correa
8 email : lucio.correa@gmail.com
9 copyright : (C) Marco Gittler
10 email : g.marco@freenet.de
11 copyright : (C) 2006 Jean-Baptiste Mardelle
14 ***************************************************************************/
16 /***************************************************************************
18 * This program is free software; you can redistribute it and/or modify *
19 * it under the terms of the GNU General Public License as published by *
20 * the Free Software Foundation; either version 2 of the License, or *
21 * (at your option) any later version. *
23 ***************************************************************************/
25 // ffmpeg Header files
28 #include <libavformat/avformat.h>
32 #include <QApplication>
36 #include <KStandardDirs>
37 #include <KMessageBox>
39 #include <KTemporaryFile>
42 #include "kdenlivesettings.h"
45 static void consumer_frame_show(mlt_consumer, Render * self, mlt_frame frame_ptr) {
46 // detect if the producer has finished playing. Is there a better way to do it ?
47 //if (self->isBlocked) return;
48 if (mlt_properties_get_double(MLT_FRAME_PROPERTIES(frame_ptr), "_speed") == 0.0) {
49 self->emitConsumerStopped();
51 self->emitFrameNumber(mlt_frame_get_position(frame_ptr));
55 Render::Render(const QString & rendererName, int winid, int extid, QWidget *parent): QObject(parent), m_name(rendererName), m_mltConsumer(NULL), m_mltProducer(NULL), m_mltTextProducer(NULL), m_winid(-1), m_framePosition(0), m_generateScenelist(false), m_isBlocked(true) {
56 kDebug() << "////////// USING PROFILE: " << (char *)KdenliveSettings::current_profile().toUtf8().data();
57 m_mltProfile = new Mlt::Profile((char*) KdenliveSettings::current_profile().data());
58 refreshTimer = new QTimer(this);
59 connect(refreshTimer, SIGNAL(timeout()), this, SLOT(refresh()));
61 m_connectTimer = new QTimer(this);
62 connect(m_connectTimer, SIGNAL(timeout()), this, SLOT(connectPlaylist()));
64 if (rendererName == "project") m_monitorId = 10000;
65 else m_monitorId = 10001;
66 osdTimer = new QTimer(this);
67 connect(osdTimer, SIGNAL(timeout()), this, SLOT(slotOsdTimeout()));
69 m_osdProfile = KStandardDirs::locate("data", "kdenlive/profiles/metadata.properties");
70 //if (rendererName == "clip")
72 //Mlt::Consumer *consumer = new Mlt::Consumer( profile , "sdl_preview");
73 m_mltConsumer = new Mlt::Consumer(*m_mltProfile , "sdl_preview"); //consumer;
74 m_mltConsumer->set("resize", 1);
75 m_mltConsumer->set("window_id", winid);
76 m_mltConsumer->set("terminate_on_pause", 1);
77 m_externalwinid = extid;
79 m_mltConsumer->listen("consumer-frame-show", this, (mlt_listener) consumer_frame_show);
80 Mlt::Producer *producer = new Mlt::Producer(*m_mltProfile , "westley-xml", "<westley><playlist><producer mlt_service=\"colour\" colour=\"blue\" in=\"0\" out=\"25\" /></playlist></westley>");
81 m_mltProducer = producer;
82 m_mltConsumer->connect(*m_mltProducer);
83 m_mltProducer->set_speed(0.0);
84 //m_mltConsumer->start();
88 /*m_osdInfo = new Mlt::Filter("data_show");
89 char *tmp = decodedString(m_osdProfile);
90 m_osdInfo->set("resource", tmp);
92 // Does it do anything usefull? I mean, RenderThread doesn't do anything useful at the moment
93 // (except being cpu hungry :)
95 /* if(!s_renderThread) {
96 s_renderThread = new RenderThread;
97 s_renderThread->start();
106 void Render::closeMlt() {
107 delete m_connectTimer;
111 delete m_mltConsumer;
113 delete m_mltProducer;
119 int Render::resetProfile(QString profile) {
120 if (!m_mltConsumer) return 0;
121 if (!m_mltConsumer->is_stopped()) m_mltConsumer->stop();
122 m_mltConsumer->set("refresh", 0);
123 m_mltConsumer->purge();
124 delete m_mltConsumer;
125 m_mltConsumer = NULL;
126 QString scene = sceneList();
127 if (m_mltProducer) delete m_mltProducer;
128 m_mltProducer = NULL;
129 if (m_mltProfile) delete m_mltProfile;
132 m_mltProfile = new Mlt::Profile((char*) profile.toUtf8().data());
133 m_mltConsumer = new Mlt::Consumer(*m_mltProfile , "sdl_preview"); //consumer;
134 m_mltConsumer->set("resize", 1);
135 m_mltConsumer->set("window_id", m_winid);
136 m_mltConsumer->set("terminate_on_pause", 1);
137 m_mltConsumer->listen("consumer-frame-show", this, (mlt_listener) consumer_frame_show);
139 Mlt::Producer *producer = new Mlt::Producer(*m_mltProfile , "westley-xml", (char *) scene.toUtf8().data());
140 m_mltProducer = producer;
141 m_mltConsumer->connect(*m_mltProducer);
142 m_mltProducer->set_speed(0.0);
144 //delete m_mltProfile;
145 // mlt_properties properties = MLT_CONSUMER_PROPERTIES(m_mltConsumer->get_consumer());
146 //mlt_profile prof = m_mltProfile->get_profile();
147 //mlt_properties_set_data(properties, "_profile", prof, 0, (mlt_destructor)mlt_profile_close, NULL);
148 //mlt_properties_set(properties, "profile", "hdv_1080_50i");
149 //m_mltConsumer->set("profile", (char *) profile.toUtf8().data());
150 //m_mltProfile = new Mlt::Profile((char*) profile.toUtf8().data());
151 kDebug() << " ++++++++++ RESET CONSUMER WITH PROFILE: " << profile << ", WIDTH: " << m_mltProfile->width();
153 //apply_profile_properties( m_mltProfile, m_mltConsumer->get_consumer(), properties );
158 /** Wraps the VEML command of the same name; Seeks the renderer clip to the given time. */
159 void Render::seek(GenTime time) {
160 sendSeekCommand(time);
161 //emit positionChanged(time);
165 char *Render::decodedString(QString str) {
166 /*QCString fn = QFile::encodeName(str);
167 char *t = new char[fn.length() + 1];
168 strcpy(t, (const char *)fn);*/
170 return (char *) qstrdup(str.toUtf8().data()); //toLatin1
174 QPixmap Render::frameThumbnail(Mlt::Frame *frame, int width, int height, bool border) {
175 QPixmap pix(width, height);
177 mlt_image_format format = mlt_image_rgb24a;
178 uint8_t *thumb = frame->get_image(format, width, height);
179 QImage image(thumb, width, height, QImage::Format_ARGB32);
181 if (!image.isNull()) {
182 pix = pix.fromImage(image);
184 QPainter painter(&pix);
185 painter.drawRect(0, 0, width - 1, height - 1);
187 } else pix.fill(Qt::black);
192 QPixmap Render::extractFrame(int frame_position, int width, int height) {
193 QPixmap pix(width, height);
194 if (!m_mltProducer) {
198 Mlt::Producer *mlt_producer = m_mltProducer->cut(frame_position, frame_position + 1);
199 Mlt::Filter m_convert(*m_mltProfile, "avcolour_space");
200 m_convert.set("forced", mlt_image_rgb24a);
201 mlt_producer->attach(m_convert);
202 Mlt::Frame *frame = mlt_producer->get_frame();
205 pix = frameThumbnail(frame, width, height);
207 } else pix.fill(Qt::black);
212 QPixmap Render::getImageThumbnail(KUrl url, int width, int height) {
215 if (url.fileName().startsWith(".all.")) { // check for slideshow
216 QString fileType = url.fileName().right(3);
218 QStringList::Iterator it;
220 QDir dir(url.directory());
221 more = dir.entryList(QDir::Files);
223 for (it = more.begin() ; it != more.end() ; ++it) {
224 if ((*it).endsWith("." + fileType, Qt::CaseInsensitive)) {
225 im.load(url.directory() + "/" + *it);
229 } else im.load(url.path());
230 //pixmap = im.scaled(width, height);
235 QPixmap Render::getVideoThumbnail(char *profile, QString file, int frame_position, int width, int height) {
236 QPixmap pix(width, height);
237 char *tmp = decodedString(file);
238 Mlt::Profile *prof = new Mlt::Profile(profile);
239 Mlt::Producer m_producer(*prof, tmp);
241 if (m_producer.is_blank()) {
246 Mlt::Filter m_convert(*prof, "avcolour_space");
247 m_convert.set("forced", mlt_image_rgb24a);
248 m_producer.attach(m_convert);
249 m_producer.seek(frame_position);
250 Mlt::Frame * frame = m_producer.get_frame();
252 pix = frameThumbnail(frame, width, height, true);
255 if (prof) delete prof;
260 void Render::getImage(KUrl url, int frame_position, QPoint size)
262 char *tmp = decodedString(url.path());
263 Mlt::Producer m_producer(tmp);
265 if (m_producer.is_blank()) {
268 Mlt::Filter m_convert("avcolour_space");
269 m_convert.set("forced", mlt_image_rgb24a);
270 m_producer.attach(m_convert);
271 m_producer.seek(frame_position);
273 Mlt::Frame * frame = m_producer.get_frame();
276 QPixmap pix = frameThumbnail(frame, size.x(), size.y(), true);
278 emit replyGetImage(url, frame_position, pix, size.x(), size.y());
282 /* Create thumbnail for color */
283 /*void Render::getImage(int id, QString color, QPoint size)
285 QPixmap pixmap(size.x() - 2, size.y() - 2);
286 color = color.replace(0, 2, "#");
287 color = color.left(7);
288 pixmap.fill(QColor(color));
289 QPixmap result(size.x(), size.y());
290 result.fill(Qt::black);
291 //copyBlt(&result, 1, 1, &pixmap, 0, 0, size.x() - 2, size.y() - 2);
292 emit replyGetImage(id, result, size.x(), size.y());
296 /* Create thumbnail for image */
297 /*void Render::getImage(KUrl url, QPoint size)
301 if (url.fileName().startsWith(".all.")) { // check for slideshow
302 QString fileType = url.fileName().right(3);
304 QStringList::Iterator it;
306 QDir dir( url.directory() );
307 more = dir.entryList( QDir::Files );
308 for ( it = more.begin() ; it != more.end() ; ++it ) {
309 if ((*it).endsWith("."+fileType, Qt::CaseInsensitive)) {
310 if (!im.load(url.directory() + "/" + *it))
311 kDebug()<<"++ ERROR LOADIN IMAGE: "<<url.directory() + "/" + *it;
316 else im.load(url.path());
318 //pixmap = im.smoothScale(size.x() - 2, size.y() - 2);
319 QPixmap result(size.x(), size.y());
320 result.fill(Qt::black);
321 //copyBlt(&result, 1, 1, &pixmap, 0, 0, size.x() - 2, size.y() - 2);
322 emit replyGetImage(url, 1, result, size.x(), size.y());
326 double Render::consumerRatio() const {
327 if (!m_mltConsumer) return 1.0;
328 return (m_mltConsumer->get_double("aspect_ratio_num") / m_mltConsumer->get_double("aspect_ratio_den"));
332 int Render::getLength() {
335 // kDebug()<<"////// LENGTH: "<<mlt_producer_get_playtime(m_mltProducer->get_producer());
336 return mlt_producer_get_playtime(m_mltProducer->get_producer());
341 bool Render::isValid(KUrl url) {
342 char *tmp = decodedString(url.path());
343 Mlt::Producer producer(*m_mltProfile, tmp);
345 if (producer.is_blank())
351 void Render::getFileProperties(const QDomElement &xml, int clipId) {
353 int width = height * 16 / 9.0; //KdenliveSettings::displayratio();
355 QDomElement westley = doc.createElement("westley");
356 doc.appendChild(westley);
357 westley.appendChild(doc.importNode(xml, true));
358 kDebug() << "////////////\n" << doc.toString() << "////////////////\n";
359 char *tmp = decodedString(doc.toString());
361 Mlt::Producer producer(*m_mltProfile, "westley-xml", tmp);
364 if (producer.is_blank()) {
367 int frameNumber = xml.attribute("frame_thumbnail", 0).toInt();
368 if (frameNumber != 0) producer.seek(frameNumber);
369 mlt_properties properties = MLT_PRODUCER_PROPERTIES(producer.get_producer());
371 QMap < QString, QString > filePropertyMap;
372 QMap < QString, QString > metadataPropertyMap;
374 KUrl url = xml.attribute("resource", QString::null);
375 filePropertyMap["filename"] = url.path();
376 filePropertyMap["duration"] = QString::number(producer.get_playtime());
377 kDebug() << "/////// PRODUCER: " << url.path() << " IS: " << producer.get_playtime();
378 Mlt::Filter m_convert(*m_mltProfile, "avcolour_space");
379 m_convert.set("forced", mlt_image_rgb24a);
380 producer.attach(m_convert);
381 Mlt::Frame * frame = producer.get_frame();
383 filePropertyMap["fps"] =
384 QString::number(mlt_producer_get_fps(producer.get_producer()));
386 if (frame && frame->is_valid()) {
387 filePropertyMap["width"] =
388 QString::number(frame->get_int("width"));
389 filePropertyMap["height"] =
390 QString::number(frame->get_int("height"));
391 filePropertyMap["frequency"] =
392 QString::number(frame->get_int("frequency"));
393 filePropertyMap["channels"] =
394 QString::number(frame->get_int("channels"));
396 if (frame->get_int("test_image") == 0) {
397 if (url.path().endsWith(".westley") || url.path().endsWith(".kdenlive")) {
398 filePropertyMap["type"] = "playlist";
399 metadataPropertyMap["comment"] = QString::fromUtf8(mlt_properties_get(MLT_SERVICE_PROPERTIES(producer.get_service()), "title"));
400 } else if (frame->get_int("test_audio") == 0)
401 filePropertyMap["type"] = "av";
403 filePropertyMap["type"] = "video";
405 // Generate thumbnail for this frame
406 QPixmap pixmap = KThumb::getImage(url, 0, width, height);
408 emit replyGetImage(clipId, 0, pixmap, width, height);
410 } else if (frame->get_int("test_audio") == 0) {
411 QPixmap pixmap(KStandardDirs::locate("appdata", "graphics/music.png"));
412 emit replyGetImage(clipId, 0, pixmap, width, height);
413 filePropertyMap["type"] = "audio";
417 // Retrieve audio / video codec name
419 // Fetch the video_context
420 #if 0 //until the reason for the chrashs is found
421 AVFormatContext *context = (AVFormatContext *) mlt_properties_get_data(properties, "video_context", NULL);
422 if (context != NULL) {
423 // Get the video_index
424 int index = mlt_properties_get_int(properties, "video_index");
425 if (context->streams && context->streams [index] && context->streams[ index ]->codec && context->streams[ index ]->codec->codec->name)
426 filePropertyMap["videocodec"] = context->streams[ index ]->codec->codec->name;
428 context = (AVFormatContext *) mlt_properties_get_data(properties, "audio_context", NULL);
429 if (context != NULL) {
430 // Get the video_index
431 int index = mlt_properties_get_int(properties, "audio_index");
432 if (context->streams && context->streams [index] && context->streams[ index ]->codec && context->streams[ index ]->codec->codec->name)
433 filePropertyMap["audiocodec"] = context->streams[ index ]->codec->codec->name;
440 mlt_properties metadata = mlt_properties_new();
441 mlt_properties_pass(metadata, properties, "meta.attr.");
442 int count = mlt_properties_count(metadata);
443 for (int i = 0; i < count; i ++) {
444 QString name = mlt_properties_get_name(metadata, i);
445 QString value = QString::fromUtf8(mlt_properties_get_value(metadata, i));
446 if (name.endsWith("markup") && !value.isEmpty())
447 metadataPropertyMap[ name.section(".", 0, -2)] = value;
450 emit replyGetFileProperties(clipId, filePropertyMap, metadataPropertyMap);
451 kDebug() << "REquested fuile info for: " << url.path();
452 if (frame) delete frame;
455 /** Create the producer from the Westley QDomDocument */
456 void Render::initSceneList() {
457 kDebug() << "-------- INIT SCENE LIST ------_";
459 QDomElement westley = doc.createElement("westley");
460 doc.appendChild(westley);
461 QDomElement prod = doc.createElement("producer");
462 prod.setAttribute("resource", "colour");
463 prod.setAttribute("colour", "red");
464 prod.setAttribute("id", "black");
465 prod.setAttribute("in", "0");
466 prod.setAttribute("out", "0");
468 QDomElement tractor = doc.createElement("tractor");
469 QDomElement multitrack = doc.createElement("multitrack");
471 QDomElement playlist1 = doc.createElement("playlist");
472 playlist1.appendChild(prod);
473 multitrack.appendChild(playlist1);
474 QDomElement playlist2 = doc.createElement("playlist");
475 multitrack.appendChild(playlist2);
476 QDomElement playlist3 = doc.createElement("playlist");
477 multitrack.appendChild(playlist3);
478 QDomElement playlist4 = doc.createElement("playlist");
479 multitrack.appendChild(playlist4);
480 QDomElement playlist5 = doc.createElement("playlist");
481 multitrack.appendChild(playlist5);
482 tractor.appendChild(multitrack);
483 westley.appendChild(tractor);
484 // kDebug()<<doc.toString();
486 QString tmp = QString("<westley><producer resource=\"colour\" colour=\"red\" id=\"red\" /><tractor><multitrack><playlist></playlist><playlist></playlist><playlist /><playlist /><playlist></playlist></multitrack></tractor></westley>");*/
487 setSceneList(doc, 0);
490 /** Create the producer from the Westley QDomDocument */
491 void Render::setSceneList(QDomDocument list, int position) {
492 setSceneList(list.toString(), position);
495 /** Create the producer from the Westley QDomDocument */
496 void Render::setSceneList(QString playlist, int position) {
497 if (m_winid == -1) return;
498 m_generateScenelist = true;
500 kWarning() << "////// RENDER, SET SCENE LIST: " << playlist;
504 if (!clip.is_valid()) {
505 kWarning()<<" ++++ WARNING, UNABLE TO CREATE MLT PRODUCER";
506 m_generateScenelist = false;
511 m_mltConsumer->set("refresh", 0);
514 m_mltProducer->set_speed(0.0);
515 //if (KdenliveSettings::osdtimecode() && m_osdInfo) m_mltProducer->detach(*m_osdInfo);
517 delete m_mltProducer;
518 m_mltProducer = NULL;
522 char *tmp = decodedString(playlist);
523 m_mltProducer = new Mlt::Producer(*m_mltProfile, "westley-xml", tmp);
525 if (!m_mltProducer || !m_mltProducer->is_valid()) kDebug() << " WARNING - - - - -INVALID PLAYLIST: " << tmp;
526 //m_mltProducer->optimise();
527 if (position != 0) m_mltProducer->seek(position);
529 /*if (KdenliveSettings::osdtimecode()) {
530 // Attach filter for on screen display of timecode
532 QString attr = "attr_check";
533 mlt_filter filter = mlt_factory_filter( "data_feed", (char*) attr.ascii() );
534 mlt_properties_set_int( MLT_FILTER_PROPERTIES( filter ), "_fezzik", 1 );
535 mlt_producer_attach( m_mltProducer->get_producer(), filter );
536 mlt_filter_close( filter );
538 m_osdInfo = new Mlt::Filter("data_show");
539 tmp = decodedString(m_osdProfile);
540 m_osdInfo->set("resource", tmp);
542 mlt_properties properties = MLT_PRODUCER_PROPERTIES(m_mltProducer->get_producer());
543 mlt_properties_set_int( properties, "meta.attr.timecode", 1);
544 mlt_properties_set( properties, "meta.attr.timecode.markup", "#timecode#");
545 m_osdInfo->set("dynamic", "1");
547 if (m_mltProducer->attach(*m_osdInfo) == 1) kDebug()<<"////// error attaching filter";
549 m_osdInfo->set("dynamic", "0");
552 m_fps = m_mltProducer->get_fps();
553 emit durationChanged(m_mltProducer->get_playtime());
554 //m_connectTimer->start( 1000 );
556 m_generateScenelist = false;
560 /** Create the producer from the Westley QDomDocument */
561 QString Render::sceneList() {
566 saveSceneList(temp.fileName());
567 QFile file(temp.fileName());
568 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
569 kWarning() << "++++++++++++++++ CANNOT READ TMP SCENELIST FILE";
572 QTextStream in(&file);
573 while (!in.atEnd()) {
574 result.append(in.readLine());
580 void Render::saveSceneList(QString path, QDomElement addedXml) {
581 char *tmppath = decodedString("westley:" + path);
582 Mlt::Consumer westleyConsumer(*m_mltProfile , tmppath);
584 westleyConsumer.set("terminate_on_pause", 1);
585 Mlt::Producer prod(m_mltProducer->get_producer());
586 westleyConsumer.connect(prod);
587 westleyConsumer.start();
588 if (!addedXml.isNull()) {
589 // add Kdenlive specific tags
592 doc.setContent(&file, false);
593 doc.documentElement().appendChild(doc.importNode(addedXml, true));
595 if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
596 kWarning() << "////// ERROR writing to file: " << path;
599 QTextStream out(&file);
600 out << doc.toString();
606 const double Render::fps() const {
610 void Render::connectPlaylist() {
611 if (!m_mltConsumer) return;
612 m_connectTimer->stop();
613 m_mltConsumer->set("refresh", "0");
614 m_mltConsumer->connect(*m_mltProducer);
615 m_mltProducer->set_speed(0.0);
616 m_mltConsumer->start();
619 if (m_mltConsumer->start() == -1) {
620 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."));
621 m_mltConsumer = NULL;
628 void Render::refreshDisplay() {
630 if (!m_mltProducer) return;
631 m_mltConsumer->set("refresh", 0);
633 mlt_properties properties = MLT_PRODUCER_PROPERTIES(m_mltProducer->get_producer());
634 /*if (KdenliveSettings::osdtimecode()) {
635 mlt_properties_set_int( properties, "meta.attr.timecode", 1);
636 mlt_properties_set( properties, "meta.attr.timecode.markup", "#timecode#");
637 m_osdInfo->set("dynamic", "1");
638 m_mltProducer->attach(*m_osdInfo);
641 m_mltProducer->detach(*m_osdInfo);
642 m_osdInfo->set("dynamic", "0");
647 void Render::setVolume(double volume) {
648 if (!m_mltConsumer || !m_mltProducer) return;
650 m_mltConsumer->set("refresh", 0);
651 // Attach filter for on screen display of timecode
652 mlt_properties properties = MLT_PRODUCER_PROPERTIES(m_mltProducer->get_producer());
653 mlt_properties_set_double( properties, "meta.volume", volume );
654 mlt_properties_set_int( properties, "meta.attr.osdvolume", 1);
655 mlt_properties_set( properties, "meta.attr.osdvolume.markup", i18n("Volume: ") + QString::number(volume * 100));
657 if (!KdenliveSettings::osdtimecode()) {
658 m_mltProducer->detach(*m_osdInfo);
659 mlt_properties_set_int( properties, "meta.attr.timecode", 0);
660 if (m_mltProducer->attach(*m_osdInfo) == 1) kDebug()<<"////// error attaching filter";
663 osdTimer->setSingleShot(2500);
666 void Render::slotOsdTimeout() {
667 mlt_properties properties = MLT_PRODUCER_PROPERTIES(m_mltProducer->get_producer());
668 mlt_properties_set_int(properties, "meta.attr.osdvolume", 0);
669 mlt_properties_set(properties, "meta.attr.osdvolume.markup", NULL);
670 //if (!KdenliveSettings::osdtimecode()) m_mltProducer->detach(*m_osdInfo);
674 void Render::start() {
675 kDebug() << "----- STARTING MONITOR: " << m_name;
677 kDebug() << "----- BROKEN MONITOR: " << m_name << ", RESTART";
681 if (m_mltConsumer->is_stopped()) {
682 kDebug() << "----- MONITOR: " << m_name << " WAS STOPPED";
683 if (m_mltConsumer->start() == -1) {
684 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."));
685 m_mltConsumer = NULL;
688 kDebug() << "----- MONITOR: " << m_name << " REFRESH";
695 void Render::clear() {
697 m_mltConsumer->set("refresh", 0);
698 if (!m_mltConsumer->is_stopped()) m_mltConsumer->stop();
702 //if (KdenliveSettings::osdtimecode() && m_osdInfo) m_mltProducer->detach(*m_osdInfo);
703 m_mltProducer->set_speed(0.0);
704 delete m_mltProducer;
705 m_mltProducer = NULL;
710 void Render::stop() {
711 if (m_mltConsumer && !m_mltConsumer->is_stopped()) {
712 kDebug() << "///////////// RENDER STOPPED: " << m_name;
713 m_mltConsumer->set("refresh", 0);
714 m_mltConsumer->stop();
716 kDebug() << "///////////// RENDER STOP2-------";
720 m_mltProducer->set_speed(0.0);
721 m_mltProducer->set("out", m_mltProducer->get_length() - 1);
723 kDebug() << "///////////// RENDER STOP3-------";
726 void Render::stop(const GenTime & startTime) {
727 kDebug() << "///////////// RENDER STOP-------2";
729 m_mltProducer->set_speed(0.0);
730 m_mltProducer->seek((int) startTime.frames(m_fps));
732 m_mltConsumer->purge();
735 void Render::switchPlay() {
738 if (m_mltProducer->get_speed() == 0.0) m_mltProducer->set_speed(1.0);
740 m_mltProducer->set_speed(0.0);
741 kDebug() << "// POSITON: " << m_framePosition;
742 m_mltProducer->seek((int) m_framePosition);
745 /*if (speed == 0.0) {
746 m_mltProducer->seek((int) m_framePosition + 1);
747 m_mltConsumer->purge();
752 void Render::play(double speed) {
755 if (speed == 0.0) m_mltProducer->set("out", m_mltProducer->get_length() - 1);
756 m_mltProducer->set_speed(speed);
757 /*if (speed == 0.0) {
758 m_mltProducer->seek((int) m_framePosition + 1);
759 m_mltConsumer->purge();
764 void Render::play(double speed, const GenTime & startTime) {
765 kDebug() << "///////////// RENDER PLAY2-------" << speed;
768 //m_mltProducer->set("out", m_mltProducer->get_length() - 1);
769 //if (speed == 0.0) m_mltConsumer->set("refresh", 0);
770 m_mltProducer->set_speed(speed);
771 m_mltProducer->seek((int)(startTime.frames(m_fps)));
772 //m_mltConsumer->purge();
776 void Render::play(double speed, const GenTime & startTime,
777 const GenTime & stopTime) {
778 kDebug() << "///////////// RENDER PLAY3-------" << speed;
781 m_mltProducer->set("out", stopTime.frames(m_fps));
782 m_mltProducer->seek((int)(startTime.frames(m_fps)));
783 m_mltConsumer->purge();
784 m_mltProducer->set_speed(speed);
789 void Render::sendSeekCommand(GenTime time) {
792 //kDebug()<<"////////// KDENLIVE SEEK: "<<(int) (time.frames(m_fps));
793 m_mltProducer->seek((int)(time.frames(m_fps)));
797 void Render::seekToFrame(int pos) {
800 //kDebug()<<"////////// KDENLIVE SEEK: "<<(int) (time.frames(m_fps));
801 m_mltProducer->seek(pos);
805 void Render::askForRefresh() {
806 // Use a Timer so that we don't refresh too much
807 refreshTimer->start(200);
810 void Render::doRefresh() {
811 // Use a Timer so that we don't refresh too much
815 void Render::refresh() {
816 if (!m_mltProducer || m_isBlocked)
818 refreshTimer->stop();
820 m_mltConsumer->set("refresh", 1);
824 /** Sets the description of this renderer to desc. */
825 void Render::setDescription(const QString & description) {
826 m_description = description;
829 /** Returns the description of this renderer */
830 QString Render::description() {
831 return m_description;
835 double Render::playSpeed() {
836 if (m_mltProducer) return m_mltProducer->get_speed();
840 const GenTime & Render::seekPosition() const {
841 if (m_mltProducer) return GenTime((int) m_mltProducer->position(), m_fps);
842 else return GenTime();
846 const QString & Render::rendererName() const {
851 void Render::emitFrameNumber(double position) {
852 //kDebug()<<"// POSITON: "<<m_framePosition;
853 if (m_generateScenelist) return;
854 m_framePosition = position;
855 emit rendererPosition((int) position);
856 //if (qApp->activeWindow()) QApplication::postEvent(qApp->activeWindow(), new PositionChangeEvent( GenTime((int) position, m_fps), m_monitorId));
859 void Render::emitConsumerStopped() {
860 // This is used to know when the playing stopped
861 if (m_mltProducer && !m_generateScenelist) {
862 double pos = m_mltProducer->position();
863 emit rendererStopped((int) pos);
864 //if (qApp->activeWindow()) QApplication::postEvent(qApp->activeWindow(), new PositionChangeEvent(GenTime((int) pos, m_fps), m_monitorId + 100));
865 //new QCustomEvent(10002));
871 void Render::exportFileToFirewire(QString srcFileName, int port, GenTime startTime, GenTime endTime) {
872 KMessageBox::sorry(0, i18n("Firewire is not enabled on your system.\n Please install Libiec61883 and recompile Kdenlive"));
876 void Render::exportCurrentFrame(KUrl url, bool notify) {
877 if (!m_mltProducer) {
878 KMessageBox::sorry(qApp->activeWindow(), i18n("There is no clip, cannot extract frame."));
882 int height = 1080;//KdenliveSettings::defaultheight();
883 int width = 1940; //KdenliveSettings::displaywidth();
885 QPixmap pix(width, height);
886 Mlt::Filter m_convert(*m_mltProfile, "avcolour_space");
887 m_convert.set("forced", mlt_image_rgb24a);
888 m_mltProducer->attach(m_convert);
889 Mlt::Frame * frame = m_mltProducer->get_frame();
890 m_mltProducer->detach(m_convert);
892 pix = frameThumbnail(frame, width, height);
895 pix.save(url.path(), "PNG");
896 //if (notify) QApplication::postEvent(qApp->activeWindow(), new UrlEvent(url, 10003));
899 /** MLT PLAYLIST DIRECT MANIPULATON **/
902 void Render::mltCheckLength() {
903 //kDebug()<<"checking track length: "<<track<<"..........";
904 Mlt::Service service(m_mltProducer->get_service());
905 Mlt::Tractor tractor(service);
907 int trackNb = tractor.count();
909 double trackDuration;
911 Mlt::Producer trackProducer(tractor.track(0));
912 Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
913 duration = Mlt::Producer(trackPlaylist.get_producer()).get_playtime() - 1;
914 m_mltProducer->set("out", duration);
915 emit durationChanged(duration);
918 while (trackNb > 1) {
919 Mlt::Producer trackProducer(tractor.track(trackNb - 1));
920 Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
921 trackDuration = Mlt::Producer(trackPlaylist.get_producer()).get_playtime() - 1;
923 kDebug() << " / / /DURATON FOR TRACK " << trackNb - 1 << " = " << trackDuration;
924 if (trackDuration > duration) duration = trackDuration;
928 Mlt::Producer blackTrackProducer(tractor.track(0));
929 Mlt::Playlist blackTrackPlaylist((mlt_playlist) blackTrackProducer.get_service());
930 double blackDuration = Mlt::Producer(blackTrackPlaylist.get_producer()).get_playtime() - 1;
931 kDebug() << " / / /DURATON FOR TRACK 0 = " << blackDuration;
932 if (blackDuration != duration) {
933 blackTrackPlaylist.remove_region(0, blackDuration);
937 QDomElement black = doc.createElement("producer");
938 black.setAttribute("mlt_service", "colour");
939 black.setAttribute("colour", "black");
940 black.setAttribute("in", "0");
941 black.setAttribute("out", "13999");
942 while (dur > 14000) { // <producer mlt_service=\"colour\" colour=\"black\" in=\"0\" out=\"13999\" />
943 mltInsertClip(0, GenTime(i * 14000, m_fps), black);
947 black.setAttribute("out", QString::number(dur));
948 mltInsertClip(0, GenTime(), black);
950 m_mltProducer->set("out", duration);
951 emit durationChanged(duration);
956 void Render::mltInsertClip(int track, GenTime position, QDomElement element) {
957 if (!m_mltProducer) {
958 kDebug() << "PLAYLIST NOT INITIALISED //////";
961 Mlt::Producer parentProd(m_mltProducer->parent());
962 if (parentProd.get_producer() == NULL) {
963 kDebug() << "PLAYLIST BROKEN, CANNOT INSERT CLIP //////";
967 Mlt::Service service(parentProd.get_service());
968 Mlt::Tractor tractor(service);
971 doc.appendChild(doc.importNode(element, true));
972 QString resource = doc.toString();
973 kDebug() << "/////// ADDING CLIP TMLNE: " << resource << " ON TRACK: " << track;
974 Mlt::Producer trackProducer(tractor.track(track));
975 Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
976 char *tmp = decodedString(resource);
977 Mlt::Producer clip(*m_mltProfile, "westley-xml", tmp);
978 //clip.set_in_and_out(in.frames(m_fps), out.frames(m_fps));
981 trackPlaylist.insert_at(position.frames(m_fps), clip, 1);
982 tractor.multitrack()->refresh();
984 if (track != 0) mltCheckLength();
988 void Render::mltCutClip(int track, GenTime position) {
990 Mlt::Service service(m_mltProducer->parent().get_service());
991 Mlt::Tractor tractor(service);
992 Mlt::Producer trackProducer(tractor.track(track));
993 Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
994 trackPlaylist.split_at(position.frames(m_fps));
995 trackPlaylist.consolidate_blanks(0);
996 kDebug() << "/ / / /CUTTING CLIP AT: " << position.frames(m_fps);
1001 void Render::mltRemoveClip(int track, GenTime position) {
1003 Mlt::Service service(m_mltProducer->parent().get_service());
1004 Mlt::Tractor tractor(service);
1005 Mlt::Producer trackProducer(tractor.track(track));
1006 Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
1007 int clipIndex = trackPlaylist.get_clip_index_at(position.frames(m_fps));
1008 //trackPlaylist.remove(clipIndex);
1009 trackPlaylist.replace_with_blank(clipIndex);
1010 trackPlaylist.consolidate_blanks(0);
1011 if (track != 0) mltCheckLength();
1012 //emit durationChanged();
1013 m_isBlocked = false;
1016 void Render::mltRemoveEffect(int track, GenTime position, QString index, bool doRefresh) {
1018 Mlt::Service service(m_mltProducer->parent().get_service());
1020 Mlt::Tractor tractor(service);
1021 Mlt::Producer trackProducer(tractor.track(track));
1022 Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
1023 //int clipIndex = trackPlaylist.get_clip_index_at(position.frames(m_fps));
1024 Mlt::Producer *clip = trackPlaylist.get_clip_at(position.frames(m_fps));
1026 kDebug() << " / / / CANNOT FIND CLIP TO REMOVE EFFECT";
1030 Mlt::Service clipService(clip->get_service());
1032 // if (tag.startsWith("ladspa")) tag = "ladspa";
1035 Mlt::Filter *filter = clipService.filter(ct);
1037 if (index == "-1" || filter->get("kdenlive_ix") == index) {// && filter->get("kdenlive_id") == id) {
1038 clipService.detach(*filter);
1039 kDebug() << " / / / DLEETED EFFECT: " << ct;
1041 filter = clipService.filter(ct);
1043 m_isBlocked = false;
1044 if (doRefresh) refresh();
1048 void Render::mltAddEffect(int track, GenTime position, QMap <QString, QString> args, bool doRefresh) {
1049 Mlt::Service service(m_mltProducer->parent().get_service());
1050 Mlt::Tractor tractor(service);
1051 Mlt::Producer trackProducer(tractor.track(track));
1052 Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
1054 Mlt::Producer *clip = trackPlaylist.get_clip_at(position.frames(m_fps));
1057 kDebug() << "********** CANNOT FIND CLIP TO APPLY EFFECT-----------";
1060 Mlt::Service clipService(clip->get_service());
1063 QString tag = args.value("tag");
1064 //kDebug()<<" / / INSERTING EFFECT: "<<id;
1065 if (tag.startsWith("ladspa")) tag = "ladspa";
1066 char *filterId = decodedString(tag);
1067 Mlt::Filter *filter = new Mlt::Filter(*m_mltProfile, filterId);
1068 if (filter && filter->is_valid())
1069 filter->set("kdenlive_id", filterId);
1071 kDebug() << "filter is NULL";
1075 QMap<QString, QString>::Iterator it;
1076 QString keyFrameNumber = "#0";
1078 for (it = args.begin(); it != args.end(); ++it) {
1079 //kDebug()<<" / / INSERTING EFFECT ARGS: "<<it.key()<<": "<<it.data();
1081 QString currentKeyFrameNumber;
1082 if (it.key().startsWith("#")) {
1083 currentKeyFrameNumber = it.key().section(":", 0, 0);
1084 if (currentKeyFrameNumber != keyFrameNumber) {
1085 // attach filter to the clip
1086 clipService.attach(*filter);
1087 filter = new Mlt::Filter(*m_mltProfile, filterId);
1088 filter->set("kdenlive_id", filterId);
1089 keyFrameNumber = currentKeyFrameNumber;
1091 key = it.key().section(":", 1);
1092 } else key = it.key();
1093 char *name = decodedString(key);
1094 char *value = decodedString(it.value());
1095 filter->set(name, value);
1099 // attach filter to the clip
1100 clipService.attach(*filter);
1102 m_isBlocked = false;
1103 if (doRefresh) refresh();
1107 void Render::mltEditEffect(int track, GenTime position, QMap <QString, QString> args) {
1108 QString index = args.value("kdenlive_ix");
1109 QString tag = args.value("tag");
1110 QMap<QString, QString>::Iterator it = args.begin();
1111 if (it.key().startsWith("#") || tag.startsWith("ladspa") || tag == "sox" || tag == "autotrack_rectangle") {
1112 // This is a keyframe effect, to edit it, we remove it and re-add it.
1113 mltRemoveEffect(track, position, index);
1114 mltAddEffect(track, position, args);
1119 Mlt::Service service(m_mltProducer->parent().get_service());
1121 Mlt::Tractor tractor(service);
1122 Mlt::Producer trackProducer(tractor.track(track));
1123 Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
1124 //int clipIndex = trackPlaylist.get_clip_index_at(position.frames(m_fps));
1125 Mlt::Producer *clip = trackPlaylist.get_clip_at(position.frames(m_fps));
1127 kDebug() << "WARINIG, CANNOT FIND CLIP ON track: " << track << ", AT POS: " << position.frames(m_fps);
1128 m_isBlocked = false;
1132 Mlt::Service clipService(clip->get_service());
1134 // if (tag.startsWith("ladspa")) tag = "ladspa";
1137 Mlt::Filter *filter = clipService.filter(ct);
1139 if (filter->get("kdenlive_ix") == index) {
1143 filter = clipService.filter(ct);
1148 kDebug() << "WARINIG, FILTER FOR EDITING NOT FOUND, ADDING IT!!!!!";
1149 mltAddEffect(track, position, args);
1150 m_isBlocked = false;
1154 for (it = args.begin(); it != args.end(); ++it) {
1155 kDebug() << " / / EDITING EFFECT ARGS: " << it.key() << ": " << it.value();
1156 char *name = decodedString(it.key());
1157 char *value = decodedString(it.value());
1158 filter->set(name, value);
1162 m_isBlocked = false;
1166 void Render::mltResizeClipEnd(int track, GenTime pos, GenTime in, GenTime out) {
1168 Mlt::Service service(m_mltProducer->parent().get_service());
1170 Mlt::Tractor tractor(service);
1171 Mlt::Producer trackProducer(tractor.track(track));
1172 Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
1173 if (trackPlaylist.is_blank_at(pos.frames(m_fps) + 1))
1174 kDebug() << "//////// ERROR RSIZING BLANK CLIP!!!!!!!!!!!";
1175 int clipIndex = trackPlaylist.get_clip_index_at(pos.frames(m_fps) + 1);
1177 int previousDuration = trackPlaylist.clip_length(clipIndex) - 1;
1178 int newDuration = out.frames(m_fps) - 1;
1180 kDebug() << " ** RESIZING CLIP END:" << clipIndex << " on track:" << track << ", mid pos: " << pos.frames(25) << ", in: " << in.frames(25) << ", out: " << out.frames(25) << ", PREVIOUS duration: " << previousDuration;
1181 trackPlaylist.resize_clip(clipIndex, in.frames(m_fps), newDuration);
1182 trackPlaylist.consolidate_blanks(0);
1183 if (previousDuration < newDuration) {
1184 // clip was made longer, trim next blank if there is one.
1185 if (trackPlaylist.is_blank(clipIndex + 1)) {
1186 trackPlaylist.split(clipIndex + 1, newDuration - previousDuration);
1187 trackPlaylist.remove(clipIndex + 1);
1189 } else trackPlaylist.insert_blank(clipIndex + 1, previousDuration - newDuration - 1);
1191 trackPlaylist.consolidate_blanks(0);
1192 tractor.multitrack()->refresh();
1194 if (track != 0) mltCheckLength();
1195 m_isBlocked = false;
1198 void Render::mltChangeTrackState(int track, bool mute, bool blind) {
1199 Mlt::Service service(m_mltProducer->parent().get_service());
1201 Mlt::Tractor tractor(service);
1202 Mlt::Producer trackProducer(tractor.track(track));
1203 Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
1205 if (blind) trackProducer.set("hide", 3);
1206 else trackProducer.set("hide", 2);
1208 trackProducer.set("hide", 1);
1210 trackProducer.set("hide", 0);
1212 tractor.multitrack()->refresh();
1217 void Render::mltResizeClipStart(int track, GenTime pos, GenTime moveEnd, GenTime moveStart, GenTime in, GenTime out) {
1219 Mlt::Service service(m_mltProducer->parent().get_service());
1220 int moveFrame = (moveEnd - moveStart).frames(m_fps);
1222 Mlt::Tractor tractor(service);
1223 Mlt::Producer trackProducer(tractor.track(track));
1224 Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
1225 if (trackPlaylist.is_blank_at(pos.frames(m_fps) - 1))
1226 kDebug() << "//////// ERROR RSIZING BLANK CLIP!!!!!!!!!!!";
1227 int clipIndex = trackPlaylist.get_clip_index_at(pos.frames(m_fps) - 1);
1228 kDebug() << " ** RESIZING CLIP START:" << clipIndex << " on track:" << track << ", mid pos: " << pos.frames(25) << ", moving: " << moveFrame << ", in: " << in.frames(25) << ", out: " << out.frames(25);
1230 trackPlaylist.resize_clip(clipIndex, in.frames(m_fps), out.frames(m_fps));
1231 if (moveFrame > 0) trackPlaylist.insert_blank(clipIndex, moveFrame - 1);
1233 int midpos = moveStart.frames(m_fps) - 1; //+ (moveFrame / 2)
1234 int blankIndex = trackPlaylist.get_clip_index_at(midpos);
1235 int blankLength = trackPlaylist.clip_length(blankIndex);
1237 kDebug() << " + resizing blank: " << blankIndex << ", Mid: " << midpos << ", Length: " << blankLength << ", SIZE DIFF: " << moveFrame;
1240 if (blankLength + moveFrame == 0) trackPlaylist.remove(blankIndex);
1241 else trackPlaylist.resize_clip(blankIndex, 0, blankLength + moveFrame - 1);
1243 trackPlaylist.consolidate_blanks(0);
1244 m_isBlocked = false;
1245 kDebug() << "-----------------\n" << "CLIP 0: " << trackPlaylist.clip_start(0) << ", LENGT: " << trackPlaylist.clip_length(0);
1246 kDebug() << "CLIP 1: " << trackPlaylist.clip_start(1) << ", LENGT: " << trackPlaylist.clip_length(1);
1247 kDebug() << "CLIP 2: " << trackPlaylist.clip_start(2) << ", LENGT: " << trackPlaylist.clip_length(2);
1248 kDebug() << "CLIP 3: " << trackPlaylist.clip_start(3) << ", LENGT: " << trackPlaylist.clip_length(3);
1249 kDebug() << "CLIP 4: " << trackPlaylist.clip_start(4) << ", LENGT: " << trackPlaylist.clip_length(4);
1252 void Render::mltMoveClip(int startTrack, int endTrack, GenTime moveStart, GenTime moveEnd) {
1253 mltMoveClip(startTrack, endTrack, (int) moveStart.frames(m_fps), (int) moveEnd.frames(m_fps));
1257 void Render::mltMoveClip(int startTrack, int endTrack, int moveStart, int moveEnd) {
1259 //m_mltConsumer->set("refresh", 0);
1260 Mlt::Service service(m_mltProducer->parent().get_service());
1262 Mlt::Tractor tractor(service);
1263 Mlt::Producer trackProducer(tractor.track(startTrack));
1264 Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
1265 int clipIndex = trackPlaylist.get_clip_index_at(moveStart + 1);
1266 mlt_field field = mlt_tractor_field(tractor.get_tractor());
1267 mlt_multitrack multitrack = mlt_field_multitrack(field); //mlt_tractor_multitrack(tractor.get_tractor());
1268 kDebug() << " -- CURRENT MULTIOTRACK HAS: " << mlt_multitrack_count(multitrack) << " tracks";;
1269 mlt_service multiprod = mlt_multitrack_service(multitrack);
1271 Mlt::Producer clipProducer(trackPlaylist.replace_with_blank(clipIndex));
1272 trackPlaylist.consolidate_blanks(0);
1273 mlt_events_block(MLT_PRODUCER_PROPERTIES(trackProducer.get_producer()), NULL);
1275 if (endTrack == startTrack) {
1276 if (!trackPlaylist.is_blank_at(moveEnd)) {
1277 kWarning() << "// ERROR, CLIP COLLISION----------";
1278 int ix = trackPlaylist.get_clip_index_at(moveEnd);
1279 kDebug() << "BAD CLIP STARTS AT: " << trackPlaylist.clip_start(ix) << ", LENGT: " << trackPlaylist.clip_length(ix);
1281 trackPlaylist.insert_at(moveEnd, clipProducer, 1);
1282 trackPlaylist.consolidate_blanks(0);
1284 trackPlaylist.consolidate_blanks(0);
1285 Mlt::Producer destTrackProducer(tractor.track(endTrack));
1286 Mlt::Playlist destTrackPlaylist((mlt_playlist) destTrackProducer.get_service());
1287 destTrackPlaylist.consolidate_blanks(1);
1288 destTrackPlaylist.insert_at(moveEnd, clipProducer, 1);
1289 destTrackPlaylist.consolidate_blanks(0);
1293 mlt_events_unblock(MLT_PRODUCER_PROPERTIES(trackProducer.get_producer()), NULL);
1294 m_isBlocked = false;
1295 m_mltConsumer->set("refresh", 1);
1298 void Render::mltMoveTransition(QString type, int startTrack, int trackOffset, GenTime oldIn, GenTime oldOut, GenTime newIn, GenTime newOut) {
1300 m_mltConsumer->set("refresh", 0);
1301 mlt_service serv = m_mltProducer->parent().get_service();
1303 mlt_service nextservice = mlt_service_get_producer(serv);
1304 mlt_properties properties = MLT_SERVICE_PROPERTIES(nextservice);
1305 QString mlt_type = mlt_properties_get(properties, "mlt_type");
1306 QString resource = mlt_properties_get(properties, "mlt_service");
1307 int old_pos = (oldIn.frames(m_fps) + oldOut.frames(m_fps)) / 2;
1309 int new_in = newIn.frames(m_fps);
1310 int new_out = newOut.frames(m_fps) - 1;
1311 while (mlt_type == "transition") {
1312 mlt_transition tr = (mlt_transition) nextservice;
1313 int currentTrack = mlt_transition_get_b_track(tr);
1314 int currentIn = (int) mlt_transition_get_in(tr);
1315 int currentOut = (int) mlt_transition_get_out(tr);
1316 kDebug() << "// FOUND EXISTING TRANS, IN: " << currentIn << ", OUT: " << currentOut << ", TRACK: " << currentTrack;
1317 //kDebug()<<"// LOOKING FOR IN: "<<old_in<<", OUT: "<<old_out;
1318 kDebug() << "// OLD IN: " << oldIn.frames(m_fps) << " // OLD OUT: " << oldOut.frames(m_fps) << ", TRACK: " << startTrack << ", MID POS: " << old_pos;
1319 if (resource == type && startTrack == currentTrack && currentIn <= old_pos && currentOut >= old_pos) {
1320 mlt_transition_set_in_and_out(tr, new_in, new_out);
1321 if (trackOffset != 0) {
1322 mlt_properties properties = MLT_TRANSITION_PROPERTIES(tr);
1323 mlt_properties_set_int(properties, "a_track", mlt_transition_get_a_track(tr) + trackOffset);
1324 mlt_properties_set_int(properties, "b_track", mlt_transition_get_b_track(tr) + trackOffset);
1328 nextservice = mlt_service_producer(nextservice);
1329 properties = MLT_SERVICE_PROPERTIES(nextservice);
1330 mlt_type = mlt_properties_get(properties, "mlt_type");
1331 resource = mlt_properties_get(properties, "mlt_service");
1333 m_isBlocked = false;
1336 void Render::mltAddTransition(QString tag, int a_track, int b_track, GenTime in, GenTime out, QMap <QString, QString> args) {
1338 Mlt::Service service(m_mltProducer->parent().get_service());
1340 Mlt::Tractor tractor(service);
1341 Mlt::Field *field = tractor.field();
1342 char *transId = decodedString(tag);
1343 Mlt::Transition *transition = new Mlt::Transition(*m_mltProfile, transId);
1344 transition->set_in_and_out((int) in.frames(m_fps), (int) out.frames(m_fps));
1345 QMap<QString, QString>::Iterator it;
1348 kDebug() << " ------ ADDING TRANSITION PARAMs: " << args.count();
1350 for (it = args.begin(); it != args.end(); ++it) {
1352 char *name = decodedString(key);
1353 char *value = decodedString(it.value());
1354 transition->set(name, value);
1355 kDebug() << " ------ ADDING TRANS PARAM: " << name << ": " << value;
1356 //filter->set("kdenlive_id", id);
1360 // attach filter to the clip
1361 field->plant_transition(*transition, a_track, b_track);
1363 m_isBlocked = false;
1368 void Render::mltSavePlaylist() {
1369 kWarning() << "// UPDATING PLAYLIST TO DISK++++++++++++++++";
1370 Mlt::Consumer *fileConsumer = new Mlt::Consumer(*m_mltProfile, "westley");
1371 fileConsumer->set("resource", "/home/one/playlist.xml");
1373 Mlt::Service service(m_mltProducer->get_service());
1374 Mlt::Tractor tractor(service);
1376 fileConsumer->connect(service);
1377 fileConsumer->start();
1381 #include "renderer.moc"