]> git.sesse.net Git - kdenlive/blob - src/renderer.cpp
* Clean up profiles handling
[kdenlive] / src / renderer.cpp
1 /***************************************************************************
2                         krender.cpp  -  description
3                            -------------------
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
12   email                : jb@kdenlive.org
13
14 ***************************************************************************/
15
16 /***************************************************************************
17  *                                                                         *
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.                                   *
22  *                                                                         *
23  ***************************************************************************/
24
25 // ffmpeg Header files
26
27 extern "C" {
28 #include <avformat.h>
29 }
30
31 #include <stdlib.h>
32
33 #include <QTimer>
34 #include <QDir>
35 #include <QApplication>
36 #include <QPainter>
37
38 #include <KDebug>
39 #include <KStandardDirs>
40 #include <KMessageBox>
41 #include <KLocale>
42 #include <KTemporaryFile>
43
44 #include "renderer.h"
45 #include "kdenlivesettings.h"
46 #include "kthumb.h"
47 #include "definitions.h"
48
49 #include <mlt++/Mlt.h>
50
51 #if LIBAVCODEC_VERSION_MAJOR > 51 || (LIBAVCODEC_VERSION_MAJOR > 50 && LIBAVCODEC_VERSION_MINOR > 54)
52 // long_name was added in FFmpeg avcodec version 51.55
53 #define ENABLE_FFMPEG_CODEC_DESCRIPTION 1
54 #endif
55
56
57
58 static void consumer_frame_show(mlt_consumer, Render * self, mlt_frame frame_ptr) {
59     // detect if the producer has finished playing. Is there a better way to do it ?
60     if (self->m_isBlocked) return;
61     if (mlt_properties_get_double(MLT_FRAME_PROPERTIES(frame_ptr), "_speed") == 0.0) {
62         self->emitConsumerStopped();
63     } else {
64         self->emitFrameNumber(mlt_frame_get_position(frame_ptr));
65     }
66 }
67
68 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), m_blackClip(NULL), m_isSplitView(false) {
69     kDebug() << "//////////  USING PROFILE: " << (char*)KdenliveSettings::current_profile().toUtf8().data();
70     refreshTimer = new QTimer(this);
71     connect(refreshTimer, SIGNAL(timeout()), this, SLOT(refresh()));
72
73     if (rendererName == "project") m_monitorId = 10000;
74     else m_monitorId = 10001;
75     osdTimer = new QTimer(this);
76     connect(osdTimer, SIGNAL(timeout()), this, SLOT(slotOsdTimeout()));
77
78     m_osdProfile =   KStandardDirs::locate("data", "kdenlive/profiles/metadata.properties");
79     buildConsumer();
80
81     m_externalwinid = extid;
82     m_winid = winid;
83     m_mltConsumer->listen("consumer-frame-show", this, (mlt_listener) consumer_frame_show);
84     Mlt::Producer *producer = new Mlt::Producer(*m_mltProfile , "colour", "black");
85     m_mltProducer = producer;
86     if (m_blackClip) delete m_blackClip;
87     m_blackClip = new Mlt::Producer(*m_mltProfile , "colour", "black");
88     m_blackClip->set("id", "black");
89     m_mltConsumer->connect(*m_mltProducer);
90     m_mltProducer->set_speed(0.0);
91 }
92
93 Render::~Render() {
94     closeMlt();
95 }
96
97
98 void Render::closeMlt() {
99     delete osdTimer;
100     delete refreshTimer;
101     if (m_mltConsumer)
102         delete m_mltConsumer;
103     if (m_mltProducer)
104         delete m_mltProducer;
105     if (m_blackClip) delete m_blackClip;
106     //delete m_osdInfo;
107 }
108
109
110 void Render::buildConsumer() {
111     char *tmp;
112     tmp = decodedString(KdenliveSettings::current_profile());
113     m_mltProfile = new Mlt::Profile(tmp);
114     delete[] tmp;
115     m_mltConsumer = new Mlt::Consumer(*m_mltProfile , "sdl_preview");
116     m_mltConsumer->set("resize", 1);
117     m_mltConsumer->set("window_id", m_winid);
118     m_mltConsumer->set("terminate_on_pause", 1);
119     m_mltConsumer->listen("consumer-frame-show", this, (mlt_listener) consumer_frame_show);
120     m_mltConsumer->set("rescale", "nearest");
121     QString audioDevice = KdenliveSettings::audiodevicename();
122     if (!audioDevice.isEmpty()) {
123         tmp = decodedString(audioDevice);
124         m_mltConsumer->set("audio_device", tmp);
125         delete[] tmp;
126     }
127
128     QString videoDriver = KdenliveSettings::videodrivername();
129     if (!videoDriver.isEmpty()) {
130         if (videoDriver == "x11_noaccel") {
131             setenv("SDL_VIDEO_YUV_HWACCEL", "0", 1);
132             m_mltConsumer->set("video_driver", "x11");
133         } else {
134             unsetenv("SDL_VIDEO_YUV_HWACCEL");
135             tmp = decodedString(videoDriver);
136             m_mltConsumer->set("video_driver", tmp);
137             delete[] tmp;
138         }
139     }
140
141     QString audioDriver = KdenliveSettings::audiodrivername();
142     if (!audioDriver.isEmpty()) {
143         tmp = decodedString(audioDriver);
144         m_mltConsumer->set("audio_driver", tmp);
145         delete[] tmp;
146     }
147
148
149     m_mltConsumer->set("progressive", 1);
150     m_mltConsumer->set("audio_buffer", 1024);
151     m_mltConsumer->set("frequency", 48000);
152 }
153
154 int Render::resetProfile() {
155     if (!m_mltConsumer) return 0;
156     if (m_isSplitView) slotSplitView(false);
157     if (!m_mltConsumer->is_stopped()) m_mltConsumer->stop();
158     m_mltConsumer->purge();
159     delete m_mltConsumer;
160     m_mltConsumer = NULL;
161     QString scene = sceneList();
162     if (m_mltProducer) delete m_mltProducer;
163     m_mltProducer = NULL;
164     if (m_mltProfile) delete m_mltProfile;
165     m_mltProfile = NULL;
166     buildConsumer();
167
168     kDebug() << "//RESET WITHSCENE: " << scene;
169     setSceneList(scene);
170
171     char *tmp = decodedString(scene);
172     Mlt::Producer *producer = new Mlt::Producer(*m_mltProfile , "westley-xml", tmp);
173     delete[] tmp;
174     m_mltProducer = producer;
175     if (m_blackClip) delete m_blackClip;
176     m_blackClip = new Mlt::Producer(*m_mltProfile , "colour", "black");
177     m_mltProducer->optimise();
178     m_mltProducer->set_speed(0);
179     connectPlaylist();
180
181     //delete m_mltProfile;
182     // mlt_properties properties = MLT_CONSUMER_PROPERTIES(m_mltConsumer->get_consumer());
183     //mlt_profile prof = m_mltProfile->get_profile();
184     //mlt_properties_set_data(properties, "_profile", prof, 0, (mlt_destructor)mlt_profile_close, NULL);
185     //mlt_properties_set(properties, "profile", "hdv_1080_50i");
186     //m_mltConsumer->set("profile", (char *) profile.toUtf8().data());
187     //m_mltProfile = new Mlt::Profile((char*) profile.toUtf8().data());
188
189     //apply_profile_properties( m_mltProfile, m_mltConsumer->get_consumer(), properties );
190     //refresh();
191     return 1;
192 }
193
194 /** Wraps the VEML command of the same name; Seeks the renderer clip to the given time. */
195 void Render::seek(GenTime time) {
196     sendSeekCommand(time);
197     //emit positionChanged(time);
198 }
199
200 //static
201 char *Render::decodedString(QString str) {
202     /*QCString fn = QFile::encodeName(str);
203     char *t = new char[fn.length() + 1];
204     strcpy(t, (const char *)fn);*/
205
206     return (char *) qstrdup(str.toUtf8().data());   //toLatin1
207 }
208
209 //static
210 /*QPixmap Render::frameThumbnail(Mlt::Frame *frame, int width, int height, bool border) {
211     QPixmap pix(width, height);
212
213     mlt_image_format format = mlt_image_rgb24a;
214     uint8_t *thumb = frame->get_image(format, width, height);
215     QImage image(thumb, width, height, QImage::Format_ARGB32);
216
217     if (!image.isNull()) {
218         pix = pix.fromImage(image);
219         if (border) {
220             QPainter painter(&pix);
221             painter.drawRect(0, 0, width - 1, height - 1);
222         }
223     } else pix.fill(Qt::black);
224     return pix;
225 }
226 */
227 const int Render::renderWidth() const {
228     return (int)(m_mltProfile->height() * m_mltProfile->dar());
229 }
230
231 const int Render::renderHeight() const {
232     return m_mltProfile->height();
233 }
234
235 QPixmap Render::extractFrame(int frame_position, int width, int height) {
236     if (width == -1) {
237         width = renderWidth();
238         height = renderHeight();
239     }
240     QPixmap pix(width, height);
241     if (!m_mltProducer) {
242         pix.fill(Qt::black);
243         return pix;
244     }
245     return KThumb::getFrame(m_mltProducer, frame_position, width, height);
246 }
247
248 QPixmap Render::getImageThumbnail(KUrl url, int width, int height) {
249     QImage im;
250     QPixmap pixmap;
251     if (url.fileName().startsWith(".all.")) {  //  check for slideshow
252         QString fileType = url.fileName().right(3);
253         QStringList more;
254         QStringList::Iterator it;
255
256         QDir dir(url.directory());
257         QStringList filter;
258         filter << "*." + fileType;
259         filter << "*." + fileType.toUpper();
260         more = dir.entryList(filter, QDir::Files);
261         im.load(url.directory() + "/" + more.at(0));
262     } else im.load(url.path());
263     //pixmap = im.scaled(width, height);
264     return pixmap;
265 }
266 /*
267 //static
268 QPixmap Render::getVideoThumbnail(char *profile, QString file, int frame_position, int width, int height) {
269     QPixmap pix(width, height);
270     char *tmp = decodedString(file);
271     Mlt::Profile *prof = new Mlt::Profile(profile);
272     Mlt::Producer m_producer(*prof, tmp);
273     delete[] tmp;
274     if (m_producer.is_blank()) {
275         pix.fill(Qt::black);
276         return pix;
277     }
278
279     Mlt::Filter m_convert(*prof, "avcolour_space");
280     m_convert.set("forced", mlt_image_rgb24a);
281     m_producer.attach(m_convert);
282     m_producer.seek(frame_position);
283     Mlt::Frame * frame = m_producer.get_frame();
284     if (frame) {
285         pix = frameThumbnail(frame, width, height, true);
286         delete frame;
287     }
288     if (prof) delete prof;
289     return pix;
290 }
291 */
292 /*
293 void Render::getImage(KUrl url, int frame_position, QPoint size)
294 {
295     char *tmp = decodedString(url.path());
296     Mlt::Producer m_producer(tmp);
297     delete[] tmp;
298     if (m_producer.is_blank()) {
299  return;
300     }
301     Mlt::Filter m_convert("avcolour_space");
302     m_convert.set("forced", mlt_image_rgb24a);
303     m_producer.attach(m_convert);
304     m_producer.seek(frame_position);
305
306     Mlt::Frame * frame = m_producer.get_frame();
307
308     if (frame) {
309  QPixmap pix = frameThumbnail(frame, size.x(), size.y(), true);
310  delete frame;
311  emit replyGetImage(url, frame_position, pix, size.x(), size.y());
312     }
313 }*/
314
315 /* Create thumbnail for color */
316 /*void Render::getImage(int id, QString color, QPoint size)
317 {
318     QPixmap pixmap(size.x() - 2, size.y() - 2);
319     color = color.replace(0, 2, "#");
320     color = color.left(7);
321     pixmap.fill(QColor(color));
322     QPixmap result(size.x(), size.y());
323     result.fill(Qt::black);
324     //copyBlt(&result, 1, 1, &pixmap, 0, 0, size.x() - 2, size.y() - 2);
325     emit replyGetImage(id, result, size.x(), size.y());
326
327 }*/
328
329 /* Create thumbnail for image */
330 /*void Render::getImage(KUrl url, QPoint size)
331 {
332     QImage im;
333     QPixmap pixmap;
334     if (url.fileName().startsWith(".all.")) {  //  check for slideshow
335      QString fileType = url.fileName().right(3);
336          QStringList more;
337          QStringList::Iterator it;
338
339             QDir dir( url.directory() );
340             more = dir.entryList( QDir::Files );
341             for ( it = more.begin() ; it != more.end() ; ++it ) {
342                 if ((*it).endsWith("."+fileType, Qt::CaseInsensitive)) {
343    if (!im.load(url.directory() + "/" + *it))
344        kDebug()<<"++ ERROR LOADIN IMAGE: "<<url.directory() + "/" + *it;
345    break;
346   }
347      }
348     }
349     else im.load(url.path());
350
351     //pixmap = im.smoothScale(size.x() - 2, size.y() - 2);
352     QPixmap result(size.x(), size.y());
353     result.fill(Qt::black);
354     //copyBlt(&result, 1, 1, &pixmap, 0, 0, size.x() - 2, size.y() - 2);
355     emit replyGetImage(url, 1, result, size.x(), size.y());
356 }*/
357
358
359 double Render::consumerRatio() const {
360     if (!m_mltConsumer) return 1.0;
361     return (m_mltConsumer->get_double("aspect_ratio_num") / m_mltConsumer->get_double("aspect_ratio_den"));
362 }
363
364
365 int Render::getLength() {
366
367     if (m_mltProducer) {
368         // kDebug()<<"//////  LENGTH: "<<mlt_producer_get_playtime(m_mltProducer->get_producer());
369         return mlt_producer_get_playtime(m_mltProducer->get_producer());
370     }
371     return 0;
372 }
373
374 bool Render::isValid(KUrl url) {
375     char *tmp = decodedString(url.path());
376     Mlt::Producer producer(*m_mltProfile, tmp);
377     delete[] tmp;
378     if (producer.is_blank())
379         return false;
380
381     return true;
382 }
383
384 const double Render::dar() const {
385     return m_mltProfile->dar();
386 }
387
388 void Render::slotSplitView(bool doit) {
389     m_isSplitView = doit;
390     Mlt::Service service(m_mltProducer->parent().get_service());
391     Mlt::Tractor tractor(service);
392     if (service.type() != tractor_type || tractor.count() < 2) return;
393     Mlt::Field *field = tractor.field();
394     if (doit) {
395         int screen = 0;
396         for (int i = 1; i < tractor.count() && screen < 4; i++) {
397             Mlt::Producer trackProducer(tractor.track(i));
398             kDebug() << "// TRACK: " << i << ", HIDE: " << trackProducer.get("hide");
399             if (QString(trackProducer.get("hide")).toInt() != 1) {
400                 kDebug() << "// ADIDNG TRACK: " << i;
401                 Mlt::Transition *transition = new Mlt::Transition(*m_mltProfile, "composite");
402                 transition->set("mlt_service", "composite");
403                 transition->set("a_track", 0);
404                 transition->set("b_track", i);
405                 transition->set("distort", 1);
406                 transition->set("internal_added", "200");
407                 char *tmp;
408                 switch (screen) {
409                 case 0:
410                     tmp = "0,0:50%x50%";
411                     break;
412                 case 1:
413                     tmp = "50%,0:50%x50%";
414                     break;
415                 case 2:
416                     tmp = "0,50%:50%x50%";
417                     break;
418                 case 3:
419                     tmp = "50%,50%:50%x50%";
420                     break;
421                 }
422                 transition->set("geometry", tmp);
423                 transition->set("always_active", "1");
424                 field->plant_transition(*transition, 0, i);
425                 //delete[] tmp;
426                 screen++;
427             }
428         }
429         m_mltConsumer->set("refresh", 1);
430     } else {
431         mlt_service serv = m_mltProducer->parent().get_service();
432         mlt_service nextservice = mlt_service_get_producer(serv);
433         mlt_properties properties = MLT_SERVICE_PROPERTIES(nextservice);
434         QString mlt_type = mlt_properties_get(properties, "mlt_type");
435         QString resource = mlt_properties_get(properties, "mlt_service");
436
437         while (mlt_type == "transition") {
438             QString added = mlt_properties_get(MLT_SERVICE_PROPERTIES(nextservice), "internal_added");
439             if (added == "200") {
440                 mlt_field_disconnect_service(field->get_field(), nextservice);
441             }
442             nextservice = mlt_service_producer(nextservice);
443             if (nextservice == NULL) break;
444             properties = MLT_SERVICE_PROPERTIES(nextservice);
445             mlt_type = mlt_properties_get(properties, "mlt_type");
446             resource = mlt_properties_get(properties, "mlt_service");
447             m_mltConsumer->set("refresh", 1);
448         }
449     }
450 }
451
452 void Render::getFileProperties(const QDomElement &xml, int clipId) {
453     int height = 50;
454     int width = (int)(height  * m_mltProfile->dar());
455     QMap < QString, QString > filePropertyMap;
456     QMap < QString, QString > metadataPropertyMap;
457
458     KUrl url = KUrl(xml.attribute("resource", QString::null));
459     Mlt::Producer *producer;
460     if (xml.attribute("type").toInt() == COLOR) {
461         char *tmp = decodedString("colour:" + xml.attribute("colour"));
462         producer = new Mlt::Producer(*m_mltProfile, "fezzik", tmp);
463         delete[] tmp;
464     } else if (url.isEmpty()) {
465         QDomDocument doc;
466         QDomElement westley = doc.createElement("westley");
467         QDomElement play = doc.createElement("playlist");
468         doc.appendChild(westley);
469         westley.appendChild(play);
470         play.appendChild(doc.importNode(xml, true));
471         kDebug() << "/ / / / /CLIP XML: " << doc.toString();
472         char *tmp = decodedString(doc.toString());
473         producer = new Mlt::Producer(*m_mltProfile, "westley-xml", tmp);
474         delete[] tmp;
475     } else {
476         char *tmp = decodedString(url.path());
477         producer = new Mlt::Producer(*m_mltProfile, tmp);
478         delete[] tmp;
479     }
480     if (xml.hasAttribute("out")) producer->set_in_and_out(xml.attribute("in").toInt(), xml.attribute("out").toInt());
481
482     if (producer->is_blank()) {
483         kDebug() << " / / / / / / / /ERRROR / / / / // CANNOT LOAD PRODUCER: ";
484         emit removeInvalidClip(clipId);
485         return;
486     }
487     producer->set("id", clipId);
488     int frameNumber = xml.attribute("thumbnail", "0").toInt();
489     if (frameNumber != 0) producer->seek(frameNumber);
490     mlt_properties properties = MLT_PRODUCER_PROPERTIES(producer->get_producer());
491
492     filePropertyMap["filename"] = url.path();
493     filePropertyMap["duration"] = QString::number(producer->get_playtime());
494     //kDebug() << "///////  PRODUCER: " << url.path() << " IS: " << producer.get_playtime();
495
496     Mlt::Frame * frame = producer->get_frame();
497
498     if (xml.attribute("type").toInt() == SLIDESHOW) {
499         if (xml.hasAttribute("ttl")) producer->set("ttl", xml.attribute("ttl").toInt());
500         if (xml.attribute("fade") == "1") {
501             // user wants a fade effect to slideshow
502             Mlt::Filter *filter = new Mlt::Filter(*m_mltProfile, "luma");
503             if (xml.hasAttribute("ttl")) filter->set("period", xml.attribute("ttl").toInt() - 1);
504             if (xml.hasAttribute("luma_duration") && !xml.attribute("luma_duration").isEmpty()) filter->set("luma.out", xml.attribute("luma_duration").toInt());
505             if (xml.hasAttribute("luma_file") && !xml.attribute("luma_file").isEmpty()) {
506                 char *tmp = decodedString(xml.attribute("luma_file"));
507                 filter->set("luma.resource", tmp);
508                 delete[] tmp;
509                 if (xml.hasAttribute("softness")) {
510                     int soft = xml.attribute("softness").toInt();
511                     filter->set("luma.softness", (double) soft / 100.0);
512                 }
513             }
514             Mlt::Service clipService(producer->get_service());
515             clipService.attach(*filter);
516         }
517     }
518
519
520     filePropertyMap["fps"] = producer->get("source_fps");
521
522     if (frame && frame->is_valid()) {
523         filePropertyMap["frame_size"] = QString::number(frame->get_int("width")) + "x" + QString::number(frame->get_int("height"));
524         filePropertyMap["frequency"] = QString::number(frame->get_int("frequency"));
525         filePropertyMap["channels"] = QString::number(frame->get_int("channels"));
526         filePropertyMap["aspect_ratio"] = frame->get("aspect_ratio");
527
528         if (frame->get_int("test_image") == 0) {
529             if (url.path().endsWith(".westley") || url.path().endsWith(".kdenlive")) {
530                 filePropertyMap["type"] = "playlist";
531                 metadataPropertyMap["comment"] = QString::fromUtf8(mlt_properties_get(MLT_SERVICE_PROPERTIES(producer->get_service()), "title"));
532             } else if (frame->get_int("test_audio") == 0)
533                 filePropertyMap["type"] = "av";
534             else
535                 filePropertyMap["type"] = "video";
536
537             mlt_image_format format = mlt_image_yuv422;
538             int frame_width = 0;
539             int frame_height = 0;
540             //frame->set("rescale.interp", "hyper");
541             frame->set("normalised_height", height);
542             frame->set("normalised_width", width);
543             QPixmap pix(width, height);
544
545             uint8_t *data = frame->get_image(format, frame_width, frame_height, 0);
546             uint8_t *new_image = (uint8_t *)mlt_pool_alloc(frame_width * (frame_height + 1) * 4);
547             mlt_convert_yuv422_to_rgb24a((uint8_t *)data, new_image, frame_width * frame_height);
548             QImage image((uchar *)new_image, frame_width, frame_height, QImage::Format_ARGB32);
549
550             if (!image.isNull()) {
551                 pix = pix.fromImage(image.rgbSwapped());
552             } else
553                 pix.fill(Qt::black);
554
555             mlt_pool_release(new_image);
556             emit replyGetImage(clipId, 0, pix, width, height);
557
558         } else if (frame->get_int("test_audio") == 0) {
559             QPixmap pixmap = KIcon("audio-x-generic").pixmap(QSize(width, height));
560             emit replyGetImage(clipId, 0, pixmap, width, height);
561             filePropertyMap["type"] = "audio";
562         }
563     }
564
565     // Retrieve audio / video codec name
566
567     // Fetch the video_context
568 #if 1
569
570     AVFormatContext *context = (AVFormatContext *) mlt_properties_get_data(properties, "video_context", NULL);
571     if (context != NULL) {
572         // Get the video_index
573         int index = mlt_properties_get_int(properties, "video_index");
574
575 #if ENABLE_FFMPEG_CODEC_DESCRIPTION
576         if (context->streams && context->streams [index] && context->streams[ index ]->codec && context->streams[ index ]->codec->codec->long_name) {
577             filePropertyMap["videocodec"] = context->streams[ index ]->codec->codec->long_name;
578         } else
579 #endif
580             if (context->streams && context->streams [index] && context->streams[ index ]->codec && context->streams[ index ]->codec->codec->name) {
581                 filePropertyMap["videocodec"] = context->streams[ index ]->codec->codec->name;
582             }
583     } else kDebug() << " / / / / /WARNING, VIDEO CONTEXT IS NULL!!!!!!!!!!!!!!";
584     context = (AVFormatContext *) mlt_properties_get_data(properties, "audio_context", NULL);
585     if (context != NULL) {
586         // Get the audio_index
587         int index = mlt_properties_get_int(properties, "audio_index");
588
589 #if ENABLE_FFMPEG_CODEC_DESCRIPTION
590         if (context->streams && context->streams [index] && context->streams[ index ]->codec && context->streams[ index ]->codec->codec->long_name)
591             filePropertyMap["audiocodec"] = context->streams[ index ]->codec->codec->long_name;
592         else
593 #endif
594             if (context->streams && context->streams [index] && context->streams[ index ]->codec && context->streams[ index ]->codec->codec->name)
595                 filePropertyMap["audiocodec"] = context->streams[ index ]->codec->codec->name;
596     }
597 #endif
598     // metadata
599
600     mlt_properties metadata = mlt_properties_new();
601     mlt_properties_pass(metadata, properties, "meta.attr.");
602     int count = mlt_properties_count(metadata);
603     for (int i = 0; i < count; i ++) {
604         QString name = mlt_properties_get_name(metadata, i);
605         QString value = QString::fromUtf8(mlt_properties_get_value(metadata, i));
606         if (name.endsWith("markup") && !value.isEmpty())
607             metadataPropertyMap[ name.section(".", 0, -2)] = value;
608     }
609
610     emit replyGetFileProperties(clipId, producer, filePropertyMap, metadataPropertyMap);
611     kDebug() << "REquested fuile info for: " << url.path();
612     if (frame) delete frame;
613     //if (producer) delete producer;
614 }
615
616 /** Create the producer from the Westley QDomDocument */
617 #if 0
618 void Render::initSceneList() {
619     kDebug() << "--------  INIT SCENE LIST ------_";
620     QDomDocument doc;
621     QDomElement westley = doc.createElement("westley");
622     doc.appendChild(westley);
623     QDomElement prod = doc.createElement("producer");
624     prod.setAttribute("resource", "colour");
625     prod.setAttribute("colour", "red");
626     prod.setAttribute("id", "black");
627     prod.setAttribute("in", "0");
628     prod.setAttribute("out", "0");
629
630     QDomElement tractor = doc.createElement("tractor");
631     QDomElement multitrack = doc.createElement("multitrack");
632
633     QDomElement playlist1 = doc.createElement("playlist");
634     playlist1.appendChild(prod);
635     multitrack.appendChild(playlist1);
636     QDomElement playlist2 = doc.createElement("playlist");
637     multitrack.appendChild(playlist2);
638     QDomElement playlist3 = doc.createElement("playlist");
639     multitrack.appendChild(playlist3);
640     QDomElement playlist4 = doc.createElement("playlist");
641     multitrack.appendChild(playlist4);
642     QDomElement playlist5 = doc.createElement("playlist");
643     multitrack.appendChild(playlist5);
644     tractor.appendChild(multitrack);
645     westley.appendChild(tractor);
646     // kDebug()<<doc.toString();
647     /*
648        QString tmp = QString("<westley><producer resource=\"colour\" colour=\"red\" id=\"red\" /><tractor><multitrack><playlist></playlist><playlist></playlist><playlist /><playlist /><playlist></playlist></multitrack></tractor></westley>");*/
649     setSceneList(doc, 0);
650 }
651 #endif
652
653
654
655 /** Create the producer from the Westley QDomDocument */
656 void Render::setProducer(Mlt::Producer *producer, int position) {
657     if (m_winid == -1) return;
658     m_generateScenelist = true;
659
660     if (m_mltConsumer) {
661         m_mltConsumer->stop();
662     } else return;
663
664     if (m_mltProducer) {
665         m_mltProducer->set_speed(0);
666         delete m_mltProducer;
667         m_mltProducer = NULL;
668         emit stopped();
669     }
670     if (producer) m_mltProducer = new Mlt::Producer(producer->get_producer());
671     else m_mltProducer = new Mlt::Producer();
672     if (!m_mltProducer || !m_mltProducer->is_valid()) kDebug() << " WARNING - - - - -INVALID PLAYLIST: ";
673
674     m_fps = m_mltProducer->get_fps();
675     connectPlaylist();
676     if (position != -1) {
677         m_mltProducer->seek(position);
678         emit rendererPosition(position);
679     }
680     m_generateScenelist = false;
681 }
682
683
684
685 /** Create the producer from the Westley QDomDocument */
686 void Render::setSceneList(QDomDocument list, int position) {
687     setSceneList(list.toString(), position);
688 }
689
690 /** Create the producer from the Westley QDomDocument */
691 void Render::setSceneList(QString playlist, int position) {
692     if (m_winid == -1) return;
693     m_generateScenelist = true;
694
695     kWarning() << "//////  RENDER, SET SCENE LIST: " << playlist;
696
697
698     /*
699         if (!clip.is_valid()) {
700      kWarning()<<" ++++ WARNING, UNABLE TO CREATE MLT PRODUCER";
701      m_generateScenelist = false;
702      return;
703         }*/
704
705     if (m_mltConsumer) {
706         m_mltConsumer->stop();
707         //m_mltConsumer->set("refresh", 0);
708     } else return;
709
710     if (m_mltProducer) {
711         m_mltProducer->set_speed(0);
712         //if (KdenliveSettings::osdtimecode() && m_osdInfo) m_mltProducer->detach(*m_osdInfo);
713
714         delete m_mltProducer;
715         m_mltProducer = NULL;
716         emit stopped();
717     }
718
719     char *tmp = decodedString(playlist);
720     m_mltProducer = new Mlt::Producer(*m_mltProfile, "westley-xml", tmp);
721     delete[] tmp;
722     if (m_blackClip) delete m_blackClip;
723     m_blackClip = new Mlt::Producer(*m_mltProfile , "colour", "black");
724     m_blackClip->set("id", "black");
725     if (!m_mltProducer || !m_mltProducer->is_valid()) kDebug() << " WARNING - - - - -INVALID PLAYLIST: " << tmp;
726     m_mltProducer->optimise();
727
728     /*if (KdenliveSettings::osdtimecode()) {
729     // Attach filter for on screen display of timecode
730     delete m_osdInfo;
731     QString attr = "attr_check";
732     mlt_filter filter = mlt_factory_filter( "data_feed", (char*) attr.ascii() );
733     mlt_properties_set_int( MLT_FILTER_PROPERTIES( filter ), "_fezzik", 1 );
734     mlt_producer_attach( m_mltProducer->get_producer(), filter );
735     mlt_filter_close( filter );
736
737       m_osdInfo = new Mlt::Filter("data_show");
738     tmp = decodedString(m_osdProfile);
739       m_osdInfo->set("resource", tmp);
740     delete[] tmp;
741     mlt_properties properties = MLT_PRODUCER_PROPERTIES(m_mltProducer->get_producer());
742     mlt_properties_set_int( properties, "meta.attr.timecode", 1);
743     mlt_properties_set( properties, "meta.attr.timecode.markup", "#timecode#");
744     m_osdInfo->set("dynamic", "1");
745
746       if (m_mltProducer->attach(*m_osdInfo) == 1) kDebug()<<"////// error attaching filter";
747     } else {
748     m_osdInfo->set("dynamic", "0");
749     }*/
750
751     m_fps = m_mltProducer->get_fps();
752     kDebug() << "// NEW SCENE LIST DURATION SET TO: " << m_mltProducer->get_playtime();
753     connectPlaylist();
754     if (position != 0) {
755         m_mltProducer->seek(position);
756         emit rendererPosition(position);
757     }
758     m_generateScenelist = false;
759
760 }
761
762 /** Create the producer from the Westley QDomDocument */
763 QString Render::sceneList() {
764     KTemporaryFile temp;
765     QString result;
766
767     if (temp.open()) {
768         saveSceneList(temp.fileName());
769         QFile file(temp.fileName());
770         if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
771             kWarning() << "++++++++++++++++   CANNOT READ TMP SCENELIST FILE";
772             return QString();
773         }
774         QTextStream in(&file);
775         while (!in.atEnd()) {
776             result.append(in.readLine());
777         }
778     }
779     return result;
780 }
781
782 void Render::saveSceneList(QString path, QDomElement kdenliveData) {
783
784     char *tmppath = decodedString("westley:" + path);
785     Mlt::Consumer westleyConsumer(*m_mltProfile , tmppath);
786     m_mltProducer->optimise();
787     delete[] tmppath;
788     westleyConsumer.set("terminate_on_pause", 1);
789     Mlt::Producer prod(m_mltProducer->get_producer());
790     bool split = m_isSplitView;
791     if (split) slotSplitView(false);
792     westleyConsumer.connect(prod);
793     //prod.set("title", "kdenlive document");
794     //westleyConsumer.listen("consumer-frame-show", this, (mlt_listener) consumer_frame_show);
795     westleyConsumer.start();
796     while (!westleyConsumer.is_stopped()) {}
797     if (!kdenliveData.isNull()) {
798         // add Kdenlive specific tags
799         QFile file(path);
800         QDomDocument doc;
801         doc.setContent(&file, false);
802         QDomNode wes = doc.elementsByTagName("westley").at(0);
803         wes.appendChild(doc.importNode(kdenliveData, true));
804         file.close();
805         if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
806             kWarning() << "//////  ERROR writing to file: " << path;
807             return;
808         }
809         QTextStream out(&file);
810         out << doc.toString();
811         file.close();
812     }
813     if (split) slotSplitView(true);
814 }
815
816
817 const double Render::fps() const {
818     return m_fps;
819 }
820
821 void Render::connectPlaylist() {
822     if (!m_mltConsumer) return;
823     //m_mltConsumer->set("refresh", "0");
824     m_mltConsumer->connect(*m_mltProducer);
825     m_mltProducer->set_speed(0);
826     m_mltConsumer->start();
827     emit durationChanged(m_mltProducer->get_playtime());
828     //refresh();
829     /*
830      if (m_mltConsumer->start() == -1) {
831           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."));
832           m_mltConsumer = NULL;
833      }
834      else {
835              refresh();
836      }*/
837 }
838
839 void Render::refreshDisplay() {
840
841     if (!m_mltProducer) return;
842     //m_mltConsumer->set("refresh", 0);
843
844     mlt_properties properties = MLT_PRODUCER_PROPERTIES(m_mltProducer->get_producer());
845     /*if (KdenliveSettings::osdtimecode()) {
846         mlt_properties_set_int( properties, "meta.attr.timecode", 1);
847         mlt_properties_set( properties, "meta.attr.timecode.markup", "#timecode#");
848         m_osdInfo->set("dynamic", "1");
849         m_mltProducer->attach(*m_osdInfo);
850     }
851     else {
852         m_mltProducer->detach(*m_osdInfo);
853         m_osdInfo->set("dynamic", "0");
854     }*/
855     refresh();
856 }
857
858 void Render::setVolume(double volume) {
859     if (!m_mltConsumer || !m_mltProducer) return;
860     /*osdTimer->stop();
861     m_mltConsumer->set("refresh", 0);
862     // Attach filter for on screen display of timecode
863     mlt_properties properties = MLT_PRODUCER_PROPERTIES(m_mltProducer->get_producer());
864     mlt_properties_set_double( properties, "meta.volume", volume );
865     mlt_properties_set_int( properties, "meta.attr.osdvolume", 1);
866     mlt_properties_set( properties, "meta.attr.osdvolume.markup", i18n("Volume: ") + QString::number(volume * 100));
867
868     if (!KdenliveSettings::osdtimecode()) {
869     m_mltProducer->detach(*m_osdInfo);
870     mlt_properties_set_int( properties, "meta.attr.timecode", 0);
871      if (m_mltProducer->attach(*m_osdInfo) == 1) kDebug()<<"////// error attaching filter";
872     }*/
873     refresh();
874     osdTimer->setSingleShot(2500);
875 }
876
877 void Render::slotOsdTimeout() {
878     mlt_properties properties = MLT_PRODUCER_PROPERTIES(m_mltProducer->get_producer());
879     mlt_properties_set_int(properties, "meta.attr.osdvolume", 0);
880     mlt_properties_set(properties, "meta.attr.osdvolume.markup", NULL);
881     //if (!KdenliveSettings::osdtimecode()) m_mltProducer->detach(*m_osdInfo);
882     refresh();
883 }
884
885 void Render::start() {
886     kDebug() << "-----  STARTING MONITOR: " << m_name;
887     if (m_winid == -1) {
888         kDebug() << "-----  BROKEN MONITOR: " << m_name << ", RESTART";
889         return;
890     }
891
892     if (m_mltConsumer->is_stopped()) {
893         kDebug() << "-----  MONITOR: " << m_name << " WAS STOPPED";
894         if (m_mltConsumer->start() == -1) {
895             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."));
896             m_mltConsumer = NULL;
897             return;
898         } else {
899             kDebug() << "-----  MONITOR: " << m_name << " REFRESH";
900             m_isBlocked = false;
901             refresh();
902         }
903     }
904     m_isBlocked = false;
905 }
906
907 void Render::clear() {
908     kDebug() << " *********  RENDER CLEAR";
909     if (m_mltConsumer) {
910         //m_mltConsumer->set("refresh", 0);
911         if (!m_mltConsumer->is_stopped()) m_mltConsumer->stop();
912     }
913
914     if (m_mltProducer) {
915         //if (KdenliveSettings::osdtimecode() && m_osdInfo) m_mltProducer->detach(*m_osdInfo);
916         m_mltProducer->set_speed(0.0);
917         delete m_mltProducer;
918         m_mltProducer = NULL;
919         emit stopped();
920     }
921 }
922
923 void Render::stop() {
924     if (m_mltConsumer && !m_mltConsumer->is_stopped()) {
925         kDebug() << "/////////////   RENDER STOPPED: " << m_name;
926         //m_mltConsumer->set("refresh", 0);
927         m_mltConsumer->stop();
928     }
929     kDebug() << "/////////////   RENDER STOP2-------";
930     m_isBlocked = true;
931
932     if (m_mltProducer) {
933         m_mltProducer->set_speed(0.0);
934         m_mltProducer->set("out", m_mltProducer->get_length() - 1);
935         kDebug() << m_mltProducer->get_length();
936     }
937     kDebug() << "/////////////   RENDER STOP3-------";
938 }
939
940 void Render::stop(const GenTime & startTime) {
941
942     kDebug() << "/////////////   RENDER STOP-------2";
943     if (m_mltProducer) {
944         m_mltProducer->set_speed(0.0);
945         m_mltProducer->seek((int) startTime.frames(m_fps));
946     }
947     m_mltConsumer->purge();
948 }
949
950 void Render::switchPlay() {
951     if (!m_mltProducer)
952         return;
953     if (m_mltProducer->get_speed() == 0.0) {
954         //m_isBlocked = false;
955         m_mltProducer->set_speed(1.0);
956         m_mltConsumer->set("refresh", 1);
957         kDebug() << " *********  RENDER PLAY: " << m_mltProducer->get_speed();
958     } else {
959         //m_isBlocked = true;
960         m_mltConsumer->set("refresh", 0);
961         m_mltProducer->set_speed(0.0);
962         //m_isBlocked = true;
963         m_mltProducer->seek((int) m_framePosition);
964         //kDebug()<<" *********  RENDER PAUSE: "<<m_mltProducer->get_speed();
965         //m_mltConsumer->set("refresh", 0);
966         /*mlt_position position = mlt_producer_position( m_mltProducer->get_producer() );
967         m_mltProducer->set_speed(0);
968         m_mltProducer->seek( position );
969                //m_mltProducer->seek((int) m_framePosition);
970                m_isBlocked = false;*/
971     }
972     /*if (speed == 0.0) {
973     m_mltProducer->seek((int) m_framePosition + 1);
974         m_mltConsumer->purge();
975     }*/
976     //refresh();
977 }
978
979 void Render::play(double speed) {
980     kDebug() << " *********  REDNER PLAY";
981     if (!m_mltProducer)
982         return;
983     // if (speed == 0.0) m_mltProducer->set("out", m_mltProducer->get_length() - 1);
984     m_mltProducer->set_speed(speed);
985     /*if (speed == 0.0) {
986     m_mltProducer->seek((int) m_framePosition + 1);
987         m_mltConsumer->purge();
988     }*/
989     refresh();
990 }
991
992 void Render::play(double speed, const GenTime & startTime) {
993     kDebug() << "/////////////   RENDER PLAY2-------" << speed;
994     if (!m_mltProducer)
995         return;
996     //m_mltProducer->set("out", m_mltProducer->get_length() - 1);
997     //if (speed == 0.0) m_mltConsumer->set("refresh", 0);
998     m_mltProducer->set_speed(speed);
999     m_mltProducer->seek((int)(startTime.frames(m_fps)));
1000     //m_mltConsumer->purge();
1001     //refresh();
1002 }
1003
1004 void Render::play(double speed, const GenTime & startTime,
1005                   const GenTime & stopTime) {
1006     kDebug() << "/////////////   RENDER PLAY3-------" << speed << stopTime.frames(m_fps);
1007     if (!m_mltProducer)
1008         return;
1009     m_mltProducer->set("out", stopTime.frames(m_fps));
1010     m_mltProducer->seek((int)(startTime.frames(m_fps)));
1011     m_mltConsumer->purge();
1012     m_mltProducer->set_speed(speed);
1013     refresh();
1014 }
1015
1016
1017 void Render::sendSeekCommand(GenTime time) {
1018     //kDebug()<<" *********  RENDER SEND SEEK";
1019     if (!m_mltProducer)
1020         return;
1021     //kDebug()<<"//////////  KDENLIVE SEEK: "<<(int) (time.frames(m_fps));
1022     m_mltProducer->seek((int)(time.frames(m_fps)));
1023     refresh();
1024 }
1025
1026 void Render::seekToFrame(int pos) {
1027     //kDebug()<<" *********  RENDER SEEK TO POS";
1028     if (!m_mltProducer)
1029         return;
1030     m_mltProducer->seek(pos);
1031     refresh();
1032 }
1033
1034 void Render::askForRefresh() {
1035     // Use a Timer so that we don't refresh too much
1036     refreshTimer->start(200);
1037 }
1038
1039 void Render::doRefresh() {
1040     // Use a Timer so that we don't refresh too much
1041     m_mltConsumer->set("refresh", 1);
1042 }
1043
1044 void Render::refresh() {
1045     if (!m_mltProducer || m_isBlocked)
1046         return;
1047     refreshTimer->stop();
1048     if (m_mltConsumer) {
1049         m_mltConsumer->set("refresh", 1);
1050     }
1051 }
1052
1053 /** Sets the description of this renderer to desc. */
1054 void Render::setDescription(const QString & description) {
1055     m_description = description;
1056 }
1057
1058 /** Returns the description of this renderer */
1059 QString Render::description() {
1060     return m_description;
1061 }
1062
1063
1064 double Render::playSpeed() {
1065     if (m_mltProducer) return m_mltProducer->get_speed();
1066     return 0.0;
1067 }
1068
1069 GenTime Render::seekPosition() const {
1070     if (m_mltProducer) return GenTime((int) m_mltProducer->position(), m_fps);
1071     else return GenTime();
1072 }
1073
1074
1075 const QString & Render::rendererName() const {
1076     return m_name;
1077 }
1078
1079
1080 void Render::emitFrameNumber(double position) {
1081     if (m_generateScenelist) return;
1082     m_framePosition = position;
1083     emit rendererPosition((int) position);
1084     //if (qApp->activeWindow()) QApplication::postEvent(qApp->activeWindow(), new PositionChangeEvent( GenTime((int) position, m_fps), m_monitorId));
1085 }
1086
1087 void Render::emitConsumerStopped() {
1088     // This is used to know when the playing stopped
1089     if (m_mltProducer && !m_generateScenelist) {
1090         double pos = m_mltProducer->position();
1091         emit rendererStopped((int) pos);
1092         //if (qApp->activeWindow()) QApplication::postEvent(qApp->activeWindow(), new PositionChangeEvent(GenTime((int) pos, m_fps), m_monitorId + 100));
1093         //new QCustomEvent(10002));
1094     }
1095 }
1096
1097
1098
1099 void Render::exportFileToFirewire(QString srcFileName, int port, GenTime startTime, GenTime endTime) {
1100     KMessageBox::sorry(0, i18n("Firewire is not enabled on your system.\n Please install Libiec61883 and recompile Kdenlive"));
1101 }
1102
1103
1104 void Render::exportCurrentFrame(KUrl url, bool notify) {
1105     if (!m_mltProducer) {
1106         KMessageBox::sorry(qApp->activeWindow(), i18n("There is no clip, cannot extract frame."));
1107         return;
1108     }
1109
1110     int height = 1080;//KdenliveSettings::defaultheight();
1111     int width = 1940; //KdenliveSettings::displaywidth();
1112     //TODO: rewrite
1113     QPixmap pix; // = KThumb::getFrame(m_mltProducer, -1, width, height);
1114     /*
1115        QPixmap pix(width, height);
1116        Mlt::Filter m_convert(*m_mltProfile, "avcolour_space");
1117        m_convert.set("forced", mlt_image_rgb24a);
1118        m_mltProducer->attach(m_convert);
1119        Mlt::Frame * frame = m_mltProducer->get_frame();
1120        m_mltProducer->detach(m_convert);
1121        if (frame) {
1122            pix = frameThumbnail(frame, width, height);
1123            delete frame;
1124        }*/
1125     pix.save(url.path(), "PNG");
1126     //if (notify) QApplication::postEvent(qApp->activeWindow(), new UrlEvent(url, 10003));
1127 }
1128
1129 /** MLT PLAYLIST DIRECT MANIPULATON  **/
1130
1131
1132 void Render::mltCheckLength(bool reload) {
1133     //kDebug()<<"checking track length: "<<track<<"..........";
1134
1135     Mlt::Service service(m_mltProducer->get_service());
1136     Mlt::Tractor tractor(service);
1137
1138     int trackNb = tractor.count();
1139     double duration = 0;
1140     double trackDuration;
1141     if (trackNb == 1) {
1142         Mlt::Producer trackProducer(tractor.track(0));
1143         Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
1144         duration = Mlt::Producer(trackPlaylist.get_producer()).get_playtime() - 1;
1145         m_mltProducer->set("out", duration);
1146         emit durationChanged((int) duration);
1147         return;
1148     }
1149     while (trackNb > 1) {
1150         Mlt::Producer trackProducer(tractor.track(trackNb - 1));
1151         Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
1152         trackDuration = Mlt::Producer(trackPlaylist.get_producer()).get_playtime() - 1;
1153
1154         //kDebug() << " / / /DURATON FOR TRACK " << trackNb - 1 << " = " << trackDuration;
1155         if (trackDuration > duration) duration = trackDuration;
1156         trackNb--;
1157     }
1158
1159     Mlt::Producer blackTrackProducer(tractor.track(0));
1160     Mlt::Playlist blackTrackPlaylist((mlt_playlist) blackTrackProducer.get_service());
1161     double blackDuration = Mlt::Producer(blackTrackPlaylist.get_producer()).get_playtime() - 1;
1162
1163     if (blackDuration != duration) {
1164         blackTrackPlaylist.remove_region(0, (int)blackDuration);
1165         int i = 0;
1166         int dur = (int)duration;
1167         QDomDocument doc;
1168         QDomElement black = doc.createElement("producer");
1169         black.setAttribute("mlt_service", "colour");
1170         black.setAttribute("colour", "black");
1171         black.setAttribute("id", "black");
1172         ItemInfo info;
1173         info.track = 0;
1174         while (dur > 14000) {
1175             info.startPos = GenTime(i * 14000, m_fps);
1176             info.endPos = info.startPos + GenTime(13999, m_fps);
1177             mltInsertClip(info, black, m_blackClip);
1178             dur = dur - 14000;
1179             i++;
1180         }
1181         if (dur > 0) {
1182             info.startPos = GenTime(i * 14000, m_fps);
1183             info.endPos = info.startPos + GenTime(dur, m_fps);
1184             mltInsertClip(info, black, m_blackClip);
1185         }
1186         m_mltProducer->set("out", duration);
1187         emit durationChanged((int)duration);
1188     }
1189 }
1190
1191 void Render::mltInsertClip(ItemInfo info, QDomElement element, Mlt::Producer *prod) {
1192     if (!m_mltProducer) {
1193         kDebug() << "PLAYLIST NOT INITIALISED //////";
1194         return;
1195     }
1196     Mlt::Producer parentProd(m_mltProducer->parent());
1197     if (parentProd.get_producer() == NULL) {
1198         kDebug() << "PLAYLIST BROKEN, CANNOT INSERT CLIP //////";
1199         return;
1200     }
1201
1202     Mlt::Service service(parentProd.get_service());
1203     Mlt::Tractor tractor(service);
1204     mlt_service_lock(service.get_service());
1205     Mlt::Producer trackProducer(tractor.track(info.track));
1206     Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
1207
1208     Mlt::Producer *clip = prod->cut(info.cropStart.frames(m_fps), (info.endPos - info.startPos).frames(m_fps) - 1);
1209     int newIndex = trackPlaylist.insert_at((int) info.startPos.frames(m_fps), *clip, 1);
1210
1211     if (QString(prod->get("transparency")).toInt() == 1)
1212         mltAddClipTransparency(info, info.track - 1, QString(prod->get("id")).toInt());
1213
1214     mlt_service_unlock(service.get_service());
1215
1216     if (info.track != 0 && (newIndex + 1 == trackPlaylist.count())) mltCheckLength();
1217     //tractor.multitrack()->refresh();
1218     //tractor.refresh();
1219 }
1220
1221
1222 void Render::mltCutClip(int track, GenTime position) {
1223
1224     m_isBlocked = true;
1225
1226     Mlt::Service service(m_mltProducer->parent().get_service());
1227     if (service.type() != tractor_type) kWarning() << "// TRACTOR PROBLEM";
1228
1229     Mlt::Tractor tractor(service);
1230     Mlt::Producer trackProducer(tractor.track(track));
1231     Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
1232
1233
1234     /* // Display playlist info
1235     kDebug()<<"////////////  BEFORE";
1236     for (int i = 0; i < trackPlaylist.count(); i++) {
1237     int blankStart = trackPlaylist.clip_start(i);
1238     int blankDuration = trackPlaylist.clip_length(i) - 1;
1239     QString blk;
1240     if (trackPlaylist.is_blank(i)) blk = "(blank)";
1241     kDebug()<<"CLIP "<<i<<": ("<<blankStart<<"x"<<blankStart + blankDuration<<")"<<blk;
1242     }*/
1243
1244     int cutPos = (int) position.frames(m_fps);
1245
1246     int clipIndex = trackPlaylist.get_clip_index_at(cutPos);
1247     if (trackPlaylist.is_blank(clipIndex)) {
1248         kDebug() << "// WARMNING, TRYING TO CUT A BLANK";
1249         m_isBlocked = false;
1250         return;
1251     }
1252     mlt_service_lock(service.get_service());
1253     int clipStart = trackPlaylist.clip_start(clipIndex);
1254     trackPlaylist.split(clipIndex, cutPos - clipStart - 1);
1255
1256     // duplicate effects
1257     Mlt::Producer *original = trackPlaylist.get_clip_at(clipStart);
1258     Mlt::Producer *clip = trackPlaylist.get_clip_at(cutPos);
1259
1260     if (original == NULL || clip == NULL) {
1261         kDebug() << "// ERROR GRABBING CLIP AFTER SPLIT";
1262     }
1263     Mlt::Service clipService(original->get_service());
1264     Mlt::Service dupService(clip->get_service());
1265     int ct = 0;
1266     Mlt::Filter *filter = clipService.filter(ct);
1267     while (filter) {
1268         if (filter->get("kdenlive_id") != "") {
1269             kDebug() << "++ ADDING FILTER: " << filter->get("kdenlive_id");
1270             Mlt::Filter *dup = new Mlt::Filter(filter->get_filter());
1271             dup->set("kdenlive_ix", filter->get("kdenlive_ix"));
1272             dup->set("kdenlive_id", filter->get("kdenlive_id"));
1273             dupService.attach(*dup);
1274         }
1275         ct++;
1276         filter = clipService.filter(ct);
1277     }
1278     mlt_service_unlock(service.get_service());
1279
1280     /* // Display playlist info
1281     kDebug()<<"////////////  AFTER";
1282     for (int i = 0; i < trackPlaylist.count(); i++) {
1283     int blankStart = trackPlaylist.clip_start(i);
1284     int blankDuration = trackPlaylist.clip_length(i) - 1;
1285     QString blk;
1286     if (trackPlaylist.is_blank(i)) blk = "(blank)";
1287     kDebug()<<"CLIP "<<i<<": ("<<blankStart<<"x"<<blankStart + blankDuration<<")"<<blk;
1288     }*/
1289
1290     m_isBlocked = false;
1291 }
1292
1293 void Render::mltUpdateClip(ItemInfo info, QDomElement element, Mlt::Producer *prod) {
1294     // TODO: optimize
1295     mltRemoveClip(info.track, info.startPos);
1296     mltInsertClip(info, element, prod);
1297 }
1298
1299
1300 bool Render::mltRemoveClip(int track, GenTime position) {
1301     Mlt::Service service(m_mltProducer->parent().get_service());
1302     if (service.type() != tractor_type) kWarning() << "// TRACTOR PROBLEM";
1303
1304     Mlt::Tractor tractor(service);
1305     Mlt::Producer trackProducer(tractor.track(track));
1306     Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
1307     int clipIndex = trackPlaylist.get_clip_index_at((int) position.frames(m_fps));
1308
1309     /* // Display playlist info
1310     kDebug()<<"////  BEFORE";
1311     for (int i = 0; i < trackPlaylist.count(); i++) {
1312     int blankStart = trackPlaylist.clip_start(i);
1313     int blankDuration = trackPlaylist.clip_length(i) - 1;
1314     QString blk;
1315     if (trackPlaylist.is_blank(i)) blk = "(blank)";
1316     kDebug()<<"CLIP "<<i<<": ("<<blankStart<<"x"<<blankStart + blankDuration<<")"<<blk;
1317     }*/
1318
1319     if (trackPlaylist.is_blank(clipIndex)) {
1320         kDebug() << "// WARMNING, TRYING TO REMOVE A BLANK: " << clipIndex << ", AT: " << position.frames(25);
1321         return false;
1322     }
1323     m_isBlocked = true;
1324     Mlt::Producer clip(trackPlaylist.get_clip(clipIndex));
1325     trackPlaylist.replace_with_blank(clipIndex);
1326     trackPlaylist.consolidate_blanks(0);
1327     if (QString(clip.parent().get("transparency")).toInt() == 1)
1328         mltDeleteTransparency((int) position.frames(m_fps), track, QString(clip.parent().get("id")).toInt());
1329
1330     /* // Display playlist info
1331     kDebug()<<"////  AFTER";
1332     for (int i = 0; i < trackPlaylist.count(); i++) {
1333     int blankStart = trackPlaylist.clip_start(i);
1334     int blankDuration = trackPlaylist.clip_length(i) - 1;
1335     QString blk;
1336     if (trackPlaylist.is_blank(i)) blk = "(blank)";
1337     kDebug()<<"CLIP "<<i<<": ("<<blankStart<<"x"<<blankStart + blankDuration<<")"<<blk;
1338     }*/
1339
1340     if (track != 0 && trackPlaylist.count() > clipIndex) mltCheckLength();
1341     m_isBlocked = false;
1342     return true;
1343 }
1344
1345 int Render::mltChangeClipSpeed(ItemInfo info, double speed, Mlt::Producer *prod) {
1346     m_isBlocked = true;
1347     int newLength = 0;
1348     Mlt::Service service(m_mltProducer->parent().get_service());
1349     if (service.type() != tractor_type) kWarning() << "// TRACTOR PROBLEM";
1350     kDebug() << "Changing clip speed, set in and out: " << info.cropStart.frames(m_fps) << " to " << (info.endPos - info.startPos).frames(m_fps) - 1;
1351     Mlt::Tractor tractor(service);
1352     Mlt::Producer trackProducer(tractor.track(info.track));
1353     Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
1354     int clipIndex = trackPlaylist.get_clip_index_at((int) info.startPos.frames(m_fps));
1355     Mlt::Producer clip(trackPlaylist.get_clip(clipIndex));
1356     QString serv = clip.parent().get("mlt_service");
1357     QString id = clip.parent().get("id");
1358     kDebug() << "CLIP SERVICE: " << clip.parent().get("mlt_service");
1359     if (serv == "avformat" && speed != 1.0) {
1360         mlt_service_lock(service.get_service());
1361         QString url = clip.parent().get("resource");
1362         url.append("?" + QString::number(speed));
1363         Mlt::Producer *slowprod = m_slowmotionProducers.value(url);
1364         if (!slowprod || slowprod->get_producer() == NULL) {
1365             char *tmp = decodedString(url);
1366             slowprod = new Mlt::Producer(*m_mltProfile, "framebuffer", tmp);
1367             delete[] tmp;
1368             QString producerid = "slowmotion:" + id + ":" + QString::number(speed);
1369             tmp = decodedString(producerid);
1370             slowprod->set("id", tmp);
1371             delete[] tmp;
1372             m_slowmotionProducers.insert(url, slowprod);
1373         }
1374         Mlt::Producer *cut = slowprod->cut(info.cropStart.frames(m_fps), (info.endPos - info.startPos).frames(m_fps) - 1);
1375         newLength = cut->get_length();
1376         trackPlaylist.replace_with_blank(clipIndex);
1377         trackPlaylist.consolidate_blanks(0);
1378         trackPlaylist.insert_at((int) info.startPos.frames(m_fps), *cut, 1);
1379         mlt_service_unlock(service.get_service());
1380     } else if (speed == 1.0) {
1381         mlt_service_lock(service.get_service());
1382         Mlt::Producer *cut = prod->cut(info.cropStart.frames(m_fps), (info.endPos - info.startPos).frames(m_fps) - 1);
1383         trackPlaylist.replace_with_blank(clipIndex);
1384         newLength = cut->get_length();
1385         trackPlaylist.consolidate_blanks(0);
1386         trackPlaylist.insert_at((int) info.startPos.frames(m_fps), *cut, 1);
1387         mlt_service_unlock(service.get_service());
1388     } else if (serv == "framebuffer") {
1389         mlt_service_lock(service.get_service());
1390         QString url = clip.parent().get("resource");
1391         url = url.section("?", 0, 0);
1392         url.append("?" + QString::number(speed));
1393         Mlt::Producer *slowprod = m_slowmotionProducers.value(url);
1394         if (!slowprod || slowprod->get_producer() == NULL) {
1395             char *tmp = decodedString(url);
1396             slowprod = new Mlt::Producer(*m_mltProfile, "framebuffer", tmp);
1397             delete[] tmp;
1398             QString producerid = "slowmotion:" + id.section(":", 1, 1) + ":" + QString::number(speed);
1399             tmp = decodedString(producerid);
1400             slowprod->set("id", tmp);
1401             delete[] tmp;
1402             m_slowmotionProducers.insert(url, slowprod);
1403         }
1404         Mlt::Producer *cut = slowprod->cut(info.cropStart.frames(m_fps), (info.endPos - info.startPos).frames(m_fps) - 1);
1405         newLength = cut->get_length();
1406         trackPlaylist.replace_with_blank(clipIndex);
1407         trackPlaylist.consolidate_blanks(0);
1408         trackPlaylist.insert_at((int) info.startPos.frames(m_fps), *cut, 1);
1409         mlt_service_unlock(service.get_service());
1410         kDebug() << "AVFORMAT CLIP!!!:";
1411     }
1412
1413     m_isBlocked = false;
1414     return newLength;
1415 }
1416
1417 bool Render::mltRemoveEffect(int track, GenTime position, QString index, bool doRefresh) {
1418
1419     Mlt::Service service(m_mltProducer->parent().get_service());
1420     bool success = false;
1421     Mlt::Tractor tractor(service);
1422     Mlt::Producer trackProducer(tractor.track(track));
1423     Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
1424     //int clipIndex = trackPlaylist.get_clip_index_at(position.frames(m_fps));
1425     Mlt::Producer *clip = trackPlaylist.get_clip_at((int) position.frames(m_fps));
1426     if (!clip) {
1427         kDebug() << " / / / CANNOT FIND CLIP TO REMOVE EFFECT";
1428         return success;
1429     }
1430     Mlt::Service clipService(clip->get_service());
1431 //    if (tag.startsWith("ladspa")) tag = "ladspa";
1432     m_isBlocked = true;
1433     int ct = 0;
1434     Mlt::Filter *filter = clipService.filter(ct);
1435     while (filter) {
1436         if ((index == "-1" && filter->get("kdenlive_id") != "")  || filter->get("kdenlive_ix") == index) {// && filter->get("kdenlive_id") == id) {
1437             if (clipService.detach(*filter) == 0) success = true;
1438             kDebug() << " / / / DLEETED EFFECT: " << ct;
1439         } else ct++;
1440         filter = clipService.filter(ct);
1441     }
1442     m_isBlocked = false;
1443     if (doRefresh) refresh();
1444     return success;
1445 }
1446
1447
1448 bool Render::mltAddEffect(int track, GenTime position, QMap <QString, QString> args, bool doRefresh) {
1449
1450     Mlt::Service service(m_mltProducer->parent().get_service());
1451
1452     Mlt::Tractor tractor(service);
1453     Mlt::Producer trackProducer(tractor.track(track));
1454     Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
1455
1456     Mlt::Producer *clip = trackPlaylist.get_clip_at((int) position.frames(m_fps));
1457     if (!clip) {
1458         return false;
1459     }
1460     Mlt::Service clipService(clip->get_service());
1461     m_isBlocked = true;
1462     // create filter
1463     QString tag = args.value("tag");
1464     kDebug() << " / / INSERTING EFFECT: " << tag;
1465     if (tag.startsWith("ladspa")) tag = "ladspa";
1466     char *filterTag = decodedString(tag);
1467     char *filterId = decodedString(args.value("id"));
1468     QMap<QString, QString>::Iterator it;
1469     QString kfr = args.value("keyframes");
1470
1471     if (!kfr.isEmpty()) {
1472         QStringList keyFrames = kfr.split(";", QString::SkipEmptyParts);
1473         kDebug() << "// ADDING KEYFRAME EFFECT: " << args.value("keyframes");
1474         char *starttag = decodedString(args.value("starttag", "start"));
1475         char *endtag = decodedString(args.value("endtag", "end"));
1476         kDebug() << "// ADDING KEYFRAME TAGS: " << starttag << ", " << endtag;
1477         int duration = clip->get_playtime();
1478         double max = args.value("max").toDouble();
1479         double min = args.value("min").toDouble();
1480         double factor = args.value("factor", "1").toDouble();
1481         args.remove("starttag");
1482         args.remove("endtag");
1483         args.remove("keyframes");
1484         args.remove("min");
1485         args.remove("max");
1486         args.remove("factor");
1487         int offset = 0;
1488         for (int i = 0; i < keyFrames.size() - 1; ++i) {
1489             Mlt::Filter *filter = new Mlt::Filter(*m_mltProfile, filterTag);
1490             filter->set("kdenlive_id", filterId);
1491             int x1 = keyFrames.at(i).section(":", 0, 0).toInt() + offset;
1492             double y1 = keyFrames.at(i).section(":", 1, 1).toDouble();
1493             int x2 = keyFrames.at(i + 1).section(":", 0, 0).toInt();
1494             double y2 = keyFrames.at(i + 1).section(":", 1, 1).toDouble();
1495             if (x2 == -1) x2 = duration;
1496             for (it = args.begin(); it != args.end(); ++it) {
1497                 char *name = decodedString(it.key());
1498                 char *value = decodedString(it.value());
1499                 filter->set(name, value);
1500                 delete[] name;
1501                 delete[] value;
1502             }
1503
1504             filter->set("in", x1);
1505             filter->set("out", x2);
1506             //kDebug() << "// ADDING KEYFRAME vals: " << min<<" / "<<max<<", "<<y1<<", factor: "<<factor;
1507             filter->set(starttag, QString::number((min + y1) / factor).toUtf8().data());
1508             filter->set(endtag, QString::number((min + y2) / factor).toUtf8().data());
1509             clipService.attach(*filter);
1510             offset = 1;
1511         }
1512         delete[] starttag;
1513         delete[] endtag;
1514     } else {
1515         Mlt::Filter *filter = new Mlt::Filter(*m_mltProfile, filterTag);
1516         if (filter && filter->is_valid())
1517             filter->set("kdenlive_id", filterId);
1518         else {
1519             kDebug() << "filter is NULL";
1520             m_isBlocked = false;
1521             return false;
1522         }
1523
1524         for (it = args.begin(); it != args.end(); ++it) {
1525             char *name = decodedString(it.key());
1526             char *value = decodedString(it.value());
1527             filter->set(name, value);
1528             delete[] name;
1529             delete[] value;
1530         }
1531         // attach filter to the clip
1532         clipService.attach(*filter);
1533     }
1534     delete[] filterId;
1535     delete[] filterTag;
1536     m_isBlocked = false;
1537     if (doRefresh) refresh();
1538     return true;
1539 }
1540
1541 bool Render::mltEditEffect(int track, GenTime position, QMap <QString, QString> args) {
1542     QString index = args.value("kdenlive_ix");
1543     QString tag =  args.value("tag");
1544     QMap<QString, QString>::Iterator it = args.begin();
1545     if (!args.value("keyframes").isEmpty() || /*it.key().startsWith("#") || */tag.startsWith("ladspa") || tag == "sox" || tag == "autotrack_rectangle") {
1546         // This is a keyframe effect, to edit it, we remove it and re-add it.
1547         mltRemoveEffect(track, position, index);
1548         bool success = mltAddEffect(track, position, args);
1549         return success;
1550     }
1551
1552     // create filter
1553     Mlt::Service service(m_mltProducer->parent().get_service());
1554
1555     Mlt::Tractor tractor(service);
1556     Mlt::Producer trackProducer(tractor.track(track));
1557     Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
1558     //int clipIndex = trackPlaylist.get_clip_index_at(position.frames(m_fps));
1559     Mlt::Producer *clip = trackPlaylist.get_clip_at((int) position.frames(m_fps));
1560     if (!clip) {
1561         kDebug() << "WARINIG, CANNOT FIND CLIP ON track: " << track << ", AT POS: " << position.frames(m_fps);
1562         return false;
1563     }
1564     Mlt::Service clipService(clip->get_service());
1565     m_isBlocked = true;
1566     int ct = 0;
1567     Mlt::Filter *filter = clipService.filter(ct);
1568     while (filter) {
1569         if (filter->get("kdenlive_ix") == index) {
1570             break;
1571         }
1572         ct++;
1573         filter = clipService.filter(ct);
1574     }
1575
1576     if (!filter) {
1577         kDebug() << "WARINIG, FILTER FOR EDITING NOT FOUND, ADDING IT!!!!!";
1578         // filter was not found, it was probably a disabled filter, so add it to the correct place...
1579         int ct = 0;
1580         filter = clipService.filter(ct);
1581         QList <Mlt::Filter *> filtersList;
1582         while (filter) {
1583             if (QString(filter->get("kdenlive_ix")).toInt() > index.toInt()) {
1584                 filtersList.append(filter);
1585                 clipService.detach(*filter);
1586             } else ct++;
1587             filter = clipService.filter(ct);
1588         }
1589         bool success = mltAddEffect(track, position, args);
1590
1591         for (int i = 0; i < filtersList.count(); i++) {
1592             clipService.attach(*(filtersList.at(i)));
1593         }
1594
1595         m_isBlocked = false;
1596         return success;
1597     }
1598
1599     for (it = args.begin(); it != args.end(); ++it) {
1600         kDebug() << " / / EDITING EFFECT ARGS: " << it.key() << ": " << it.value();
1601         char *name = decodedString(it.key());
1602         char *value = decodedString(it.value());
1603         filter->set(name, value);
1604         delete[] name;
1605         delete[] value;
1606     }
1607     m_isBlocked = false;
1608     refresh();
1609     return true;
1610 }
1611
1612 void Render::mltMoveEffect(int track, GenTime position, int oldPos, int newPos) {
1613
1614     kDebug() << "MOVING EFFECT FROM " << oldPos << ", TO: " << newPos;
1615     Mlt::Service service(m_mltProducer->parent().get_service());
1616
1617     Mlt::Tractor tractor(service);
1618     Mlt::Producer trackProducer(tractor.track(track));
1619     Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
1620     //int clipIndex = trackPlaylist.get_clip_index_at(position.frames(m_fps));
1621     Mlt::Producer *clip = trackPlaylist.get_clip_at((int) position.frames(m_fps));
1622     if (!clip) {
1623         kDebug() << "WARINIG, CANNOT FIND CLIP ON track: " << track << ", AT POS: " << position.frames(m_fps);
1624         return;
1625     }
1626     Mlt::Service clipService(clip->get_service());
1627     m_isBlocked = true;
1628     int ct = 0;
1629     QList <Mlt::Filter *> filtersList;
1630     Mlt::Filter *filter = clipService.filter(ct);
1631     bool found = false;
1632     if (newPos > oldPos) {
1633         while (filter) {
1634             if (!found && QString(filter->get("kdenlive_ix")).toInt() == oldPos) {
1635                 filter->set("kdenlive_ix", newPos);
1636                 filtersList.append(filter);
1637                 clipService.detach(*filter);
1638                 filter = clipService.filter(ct);
1639                 while (filter && QString(filter->get("kdenlive_ix")).toInt() <= newPos) {
1640                     filter->set("kdenlive_ix", QString(filter->get("kdenlive_ix")).toInt() - 1);
1641                     ct++;
1642                     filter = clipService.filter(ct);
1643                 }
1644                 found = true;
1645             }
1646             if (filter && QString(filter->get("kdenlive_ix")).toInt() > newPos) {
1647                 filtersList.append(filter);
1648                 clipService.detach(*filter);
1649             } else ct++;
1650             filter = clipService.filter(ct);
1651         }
1652     } else {
1653         while (filter) {
1654             if (QString(filter->get("kdenlive_ix")).toInt() == oldPos) {
1655                 filter->set("kdenlive_ix", newPos);
1656                 filtersList.append(filter);
1657                 clipService.detach(*filter);
1658             } else ct++;
1659             filter = clipService.filter(ct);
1660         }
1661
1662         ct = 0;
1663         filter = clipService.filter(ct);
1664         while (filter) {
1665             int pos = QString(filter->get("kdenlive_ix")).toInt();
1666             if (pos >= newPos) {
1667                 if (pos < oldPos) filter->set("kdenlive_ix", QString(filter->get("kdenlive_ix")).toInt() + 1);
1668                 filtersList.append(filter);
1669                 clipService.detach(*filter);
1670             } else ct++;
1671             filter = clipService.filter(ct);
1672         }
1673     }
1674
1675     for (int i = 0; i < filtersList.count(); i++) {
1676         clipService.attach(*(filtersList.at(i)));
1677     }
1678
1679     m_isBlocked = false;
1680     refresh();
1681 }
1682
1683 bool Render::mltResizeClipEnd(ItemInfo info, GenTime clipDuration) {
1684     m_isBlocked = true;
1685
1686     Mlt::Service service(m_mltProducer->parent().get_service());
1687
1688     Mlt::Tractor tractor(service);
1689     Mlt::Producer trackProducer(tractor.track(info.track));
1690     Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
1691
1692     /* // Display playlist info
1693     kDebug()<<"////////////  BEFORE RESIZE";
1694     for (int i = 0; i < trackPlaylist.count(); i++) {
1695     int blankStart = trackPlaylist.clip_start(i);
1696     int blankDuration = trackPlaylist.clip_length(i) - 1;
1697     QString blk;
1698     if (trackPlaylist.is_blank(i)) blk = "(blank)";
1699     kDebug()<<"CLIP "<<i<<": ("<<blankStart<<"x"<<blankStart + blankDuration<<")"<<blk;
1700     }*/
1701
1702     if (trackPlaylist.is_blank_at((int) info.startPos.frames(m_fps))) {
1703         kDebug() << "////////  ERROR RSIZING BLANK CLIP!!!!!!!!!!!";
1704         m_isBlocked = false;
1705         return false;
1706     }
1707     int clipIndex = trackPlaylist.get_clip_index_at((int) info.startPos.frames(m_fps));
1708     kDebug() << "// SELECTED CLIP START: " << trackPlaylist.clip_start(clipIndex);
1709     Mlt::Producer *clip = trackPlaylist.get_clip(clipIndex);
1710     int previousStart = clip->get_in();
1711     int previousDuration = trackPlaylist.clip_length(clipIndex) - 1;
1712     int newDuration = (int) clipDuration.frames(m_fps) - 1;
1713     trackPlaylist.resize_clip(clipIndex, previousStart, newDuration + previousStart);
1714     //trackPlaylist.consolidate_blanks(0);
1715     // skip to next clip
1716     clipIndex++;
1717     int diff = newDuration - previousDuration;
1718     kDebug() << "////////  RESIZE CLIP: " << clipIndex << "( pos: " << info.startPos.frames(25) << "), DIFF: " << diff << ", CURRENT DUR: " << previousDuration << ", NEW DUR: " << newDuration;
1719     if (diff > 0) {
1720         // clip was made longer, trim next blank if there is one.
1721         if (trackPlaylist.is_blank(clipIndex)) {
1722             int blankStart = trackPlaylist.clip_start(clipIndex);
1723             int blankDuration = trackPlaylist.clip_length(clipIndex) - 1;
1724             if (diff - blankDuration == 1) {
1725                 trackPlaylist.remove(clipIndex);
1726             } else trackPlaylist.resize_clip(clipIndex, blankStart, blankStart + blankDuration - diff);
1727         } else {
1728             kDebug() << "/// RESIZE ERROR, NXT CLIP IS NOT BLK: " << clipIndex;
1729         }
1730     } else trackPlaylist.insert_blank(clipIndex, 0 - diff - 1);
1731
1732     trackPlaylist.consolidate_blanks(0);
1733
1734     /* // Display playlist info
1735     kDebug()<<"////////////  AFTER RESIZE";
1736     for (int i = 0; i < trackPlaylist.count(); i++) {
1737     int blankStart = trackPlaylist.clip_start(i);
1738     int blankDuration = trackPlaylist.clip_length(i) - 1;
1739     QString blk;
1740     if (trackPlaylist.is_blank(i)) blk = "(blank)";
1741     kDebug()<<"CLIP "<<i<<": ("<<blankStart<<"x"<<blankStart + blankDuration<<")"<<blk;
1742     }*/
1743
1744     //tractor.multitrack()->refresh();
1745     //tractor.refresh();
1746     if (info.track != 0 && clipIndex == trackPlaylist.count()) mltCheckLength();
1747     if (QString(clip->parent().get("transparency")).toInt() == 1) {
1748         //mltResizeTransparency(previousStart, previousStart, previousStart + newDuration, track, QString(clip->parent().get("id")).toInt());
1749         mltDeleteTransparency(info.startPos.frames(m_fps), info.track, QString(clip->parent().get("id")).toInt());
1750         ItemInfo transpinfo;
1751         transpinfo.startPos = info.startPos;
1752         transpinfo.endPos = info.startPos + clipDuration;
1753         transpinfo.track = info.track;
1754         mltAddClipTransparency(transpinfo, info.track - 1, QString(clip->parent().get("id")).toInt());
1755     }
1756     m_isBlocked = false;
1757     return true;
1758 }
1759
1760 void Render::mltChangeTrackState(int track, bool mute, bool blind) {
1761     Mlt::Service service(m_mltProducer->parent().get_service());
1762     Mlt::Tractor tractor(service);
1763     Mlt::Producer trackProducer(tractor.track(track));
1764     Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
1765     if (mute) {
1766         if (blind) trackProducer.set("hide", 3);
1767         else trackProducer.set("hide", 2);
1768     } else if (blind) {
1769         trackProducer.set("hide", 1);
1770     } else {
1771         trackProducer.set("hide", 0);
1772     }
1773     tractor.multitrack()->refresh();
1774     tractor.refresh();
1775     refresh();
1776 }
1777
1778 bool Render::mltResizeClipStart(ItemInfo info, GenTime diff) {
1779     Mlt::Service service(m_mltProducer->parent().get_service());
1780     int moveFrame = (int) diff.frames(m_fps);
1781     Mlt::Tractor tractor(service);
1782     Mlt::Producer trackProducer(tractor.track(info.track));
1783     Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
1784     if (trackPlaylist.is_blank_at(info.startPos.frames(m_fps))) {
1785         kDebug() << "////////  ERROR RSIZING BLANK CLIP!!!!!!!!!!!";
1786         return false;
1787     }
1788     int clipIndex = trackPlaylist.get_clip_index_at(info.startPos.frames(m_fps));
1789     /*int previousStart = trackPlaylist.clip_start(clipIndex);
1790     int previousDuration = trackPlaylist.clip_length(clipIndex) - 1;*/
1791     //kDebug() << " ** RESIZING CLIP START:" << clipIndex << " on track:" << track << ", mid pos: " << pos.frames(25) << ", moving: " << moveFrame << ", in: " << in.frames(25) << ", out: " << out.frames(25);
1792     Mlt::Producer *clip = trackPlaylist.get_clip(clipIndex);
1793     if (clip == NULL) {
1794         kDebug() << "////////  ERROR RSIZING NULL CLIP!!!!!!!!!!!";
1795         return false;
1796     }
1797     m_mltConsumer->set("refresh", 0);
1798     int previousStart = clip->get_in();
1799     int previousDuration = trackPlaylist.clip_length(clipIndex) - 1;
1800     m_isBlocked = true;
1801     kDebug() << "RESIZE, old start: " << previousStart << ", PREV DUR: " << previousDuration << ", DIFF: " << moveFrame;
1802     trackPlaylist.resize_clip(clipIndex, previousStart + moveFrame, previousStart + previousDuration);
1803     if (moveFrame > 0) trackPlaylist.insert_blank(clipIndex, moveFrame - 1);
1804     else {
1805         //int midpos = info.startPos.frames(m_fps) + moveFrame - 1;
1806         int blankIndex = clipIndex - 1;
1807         int blankLength = trackPlaylist.clip_length(blankIndex);
1808         kDebug() << " + resizing blank length " <<  blankLength << ", SIZE DIFF: " << moveFrame;
1809         if (! trackPlaylist.is_blank(blankIndex)) {
1810             kDebug() << "WARNING, CLIP TO RESIZE IS NOT BLANK";
1811         }
1812         if (blankLength + moveFrame == 0) trackPlaylist.remove(blankIndex);
1813         else trackPlaylist.resize_clip(blankIndex, 0, blankLength + moveFrame - 1);
1814     }
1815     trackPlaylist.consolidate_blanks(0);
1816     if (QString(clip->parent().get("transparency")).toInt() == 1) {
1817         //mltResizeTransparency(previousStart, (int) moveEnd.frames(m_fps), (int) (moveEnd + out - in).frames(m_fps), track, QString(clip->parent().get("id")).toInt());
1818         mltDeleteTransparency(info.startPos.frames(m_fps), info.track, QString(clip->parent().get("id")).toInt());
1819         ItemInfo transpinfo;
1820         transpinfo.startPos = info.startPos + diff;
1821         transpinfo.endPos = info.startPos + diff + (info.endPos - info.startPos);
1822         transpinfo.track = info.track;
1823         mltAddClipTransparency(transpinfo, info.track - 1, QString(clip->parent().get("id")).toInt());
1824     }
1825     m_isBlocked = false;
1826     m_mltConsumer->set("refresh", 1);
1827     return true;
1828 }
1829
1830 bool Render::mltMoveClip(int startTrack, int endTrack, GenTime moveStart, GenTime moveEnd) {
1831     return mltMoveClip(startTrack, endTrack, (int) moveStart.frames(m_fps), (int) moveEnd.frames(m_fps));
1832 }
1833
1834
1835 bool Render::mltMoveClip(int startTrack, int endTrack, int moveStart, int moveEnd) {
1836     m_isBlocked = true;
1837
1838     m_mltConsumer->set("refresh", 0);
1839     mlt_service_lock(m_mltConsumer->get_service());
1840     Mlt::Service service(m_mltProducer->parent().get_service());
1841     if (service.type() != tractor_type) kWarning() << "// TRACTOR PROBLEM";
1842
1843     Mlt::Tractor tractor(service);
1844     Mlt::Producer trackProducer(tractor.track(startTrack));
1845     Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
1846     int clipIndex = trackPlaylist.get_clip_index_at(moveStart + 1);
1847     bool checkLength = false;
1848     if (endTrack == startTrack) {
1849         //mlt_service_lock(service.get_service());
1850         Mlt::Producer clipProducer(trackPlaylist.replace_with_blank(clipIndex));
1851
1852         if (!trackPlaylist.is_blank_at(moveEnd)) {
1853             // error, destination is not empty
1854             //int ix = trackPlaylist.get_clip_index_at(moveEnd);
1855             kDebug() << "// ERROR MOVING CLIP TO : " << moveEnd;
1856             mlt_service_unlock(m_mltConsumer->get_service());
1857             m_isBlocked = false;
1858             return false;
1859         } else {
1860             trackPlaylist.consolidate_blanks(0);
1861             int newIndex = trackPlaylist.insert_at(moveEnd, clipProducer, 1);
1862             if (QString(clipProducer.parent().get("transparency")).toInt() == 1) {
1863                 mltMoveTransparency(moveStart, moveEnd, startTrack, endTrack, QString(clipProducer.parent().get("id")).toInt());
1864             }
1865             if (newIndex + 1 == trackPlaylist.count()) checkLength = true;
1866         }
1867         //mlt_service_unlock(service.get_service());
1868     } else {
1869         Mlt::Producer destTrackProducer(tractor.track(endTrack));
1870         Mlt::Playlist destTrackPlaylist((mlt_playlist) destTrackProducer.get_service());
1871         if (!destTrackPlaylist.is_blank_at(moveEnd)) {
1872             // error, destination is not empty
1873             mlt_service_unlock(m_mltConsumer->get_service());
1874             m_isBlocked = false;
1875             return false;
1876         } else {
1877             Mlt::Producer clipProducer(trackPlaylist.replace_with_blank(clipIndex));
1878             trackPlaylist.consolidate_blanks(0);
1879             destTrackPlaylist.consolidate_blanks(1);
1880             int newIndex = destTrackPlaylist.insert_at(moveEnd, clipProducer, 1);
1881             destTrackPlaylist.consolidate_blanks(0);
1882             if (QString(clipProducer.parent().get("transparency")).toInt() == 1) {
1883                 kDebug() << "//////// moving clip transparency";
1884                 mltMoveTransparency(moveStart, moveEnd, startTrack, endTrack, QString(clipProducer.parent().get("id")).toInt());
1885             }
1886             if (clipIndex > trackPlaylist.count()) checkLength = true;
1887             else if (newIndex + 1 == destTrackPlaylist.count()) checkLength = true;
1888         }
1889     }
1890
1891     if (checkLength) mltCheckLength();
1892     mlt_service_unlock(m_mltConsumer->get_service());
1893     m_isBlocked = false;
1894     m_mltConsumer->set("refresh", 1);
1895     return true;
1896 }
1897
1898 void Render::mltMoveTransition(QString type, int startTrack, int newTrack, int newTransitionTrack, GenTime oldIn, GenTime oldOut, GenTime newIn, GenTime newOut) {
1899
1900     Mlt::Service service(m_mltProducer->parent().get_service());
1901     Mlt::Tractor tractor(service);
1902     Mlt::Field *field = tractor.field();
1903
1904     mlt_service_lock(service.get_service());
1905     m_mltConsumer->set("refresh", 0);
1906     m_isBlocked = true;
1907
1908     mlt_service serv = m_mltProducer->parent().get_service();
1909     mlt_service nextservice = mlt_service_get_producer(serv);
1910     mlt_properties properties = MLT_SERVICE_PROPERTIES(nextservice);
1911     QString mlt_type = mlt_properties_get(properties, "mlt_type");
1912     QString resource = mlt_properties_get(properties, "mlt_service");
1913     int old_pos = (int)(oldIn.frames(m_fps) + oldOut.frames(m_fps)) / 2;
1914
1915     int new_in = (int)newIn.frames(m_fps);
1916     int new_out = (int)newOut.frames(m_fps);
1917
1918     while (mlt_type == "transition") {
1919         mlt_transition tr = (mlt_transition) nextservice;
1920         int currentTrack = mlt_transition_get_b_track(tr);
1921         int currentIn = (int) mlt_transition_get_in(tr);
1922         int currentOut = (int) mlt_transition_get_out(tr);
1923
1924         if (resource == type && startTrack == currentTrack && currentIn <= old_pos && currentOut >= old_pos) {
1925             mlt_transition_set_in_and_out(tr, new_in, new_out);
1926             if (newTrack - startTrack != 0) {
1927                 kDebug() << "///// TRANSITION CHANGE TRACK. CUrrent (b): " << currentTrack << "x" << mlt_transition_get_a_track(tr) << ", NEw: " << newTrack << "x" << newTransitionTrack;
1928
1929                 mlt_properties properties = MLT_TRANSITION_PROPERTIES(tr);
1930                 mlt_properties_set_int(properties, "a_track", newTransitionTrack);
1931                 mlt_properties_set_int(properties, "b_track", newTrack);
1932                 //kDebug() << "set new start & end :" << new_in << new_out<< "TR OFFSET: "<<trackOffset<<", TRACKS: "<<mlt_transition_get_a_track(tr)<<"x"<<mlt_transition_get_b_track(tr);
1933             }
1934             break;
1935         }
1936         nextservice = mlt_service_producer(nextservice);
1937         if (nextservice == NULL) break;
1938         properties = MLT_SERVICE_PROPERTIES(nextservice);
1939         mlt_type = mlt_properties_get(properties, "mlt_type");
1940         resource = mlt_properties_get(properties, "mlt_service");
1941     }
1942     m_isBlocked = false;
1943     mlt_service_unlock(service.get_service());
1944     m_mltConsumer->set("refresh", 1);
1945 }
1946
1947 void Render::mltUpdateTransition(QString oldTag, QString tag, int a_track, int b_track, GenTime in, GenTime out, QDomElement xml) {
1948     // kDebug() << "update transition"  << tag << " at pos " << in.frames(25);
1949     if (oldTag == tag) mltUpdateTransitionParams(tag, a_track, b_track, in, out, xml);
1950     else {
1951         mltDeleteTransition(oldTag, a_track, b_track, in, out, xml, false);
1952         mltAddTransition(tag, a_track, b_track, in, out, xml);
1953     }
1954     //mltSavePlaylist();
1955 }
1956
1957 void Render::mltUpdateTransitionParams(QString type, int a_track, int b_track, GenTime in, GenTime out, QDomElement xml) {
1958     m_isBlocked = true;
1959
1960     Mlt::Service service(m_mltProducer->parent().get_service());
1961     Mlt::Tractor tractor(service);
1962     Mlt::Field *field = tractor.field();
1963
1964     //m_mltConsumer->set("refresh", 0);
1965     mlt_service serv = m_mltProducer->parent().get_service();
1966
1967     mlt_service nextservice = mlt_service_get_producer(serv);
1968     mlt_properties properties = MLT_SERVICE_PROPERTIES(nextservice);
1969     QString mlt_type = mlt_properties_get(properties, "mlt_type");
1970     QString resource = mlt_properties_get(properties, "mlt_service");
1971     int in_pos = (int) in.frames(m_fps);
1972     int out_pos = (int) out.frames(m_fps);
1973
1974     while (mlt_type == "transition") {
1975         mlt_transition tr = (mlt_transition) nextservice;
1976         int currentTrack = mlt_transition_get_b_track(tr);
1977         int currentIn = (int) mlt_transition_get_in(tr);
1978         int currentOut = (int) mlt_transition_get_out(tr);
1979
1980         // kDebug()<<"Looking for transition : " << currentIn <<"x"<<currentOut<< ", OLD oNE: "<<in_pos<<"x"<<out_pos;
1981
1982         if (resource == type && b_track == currentTrack && currentIn == in_pos && currentOut == out_pos) {
1983             QMap<QString, QString> map = mltGetTransitionParamsFromXml(xml);
1984             QMap<QString, QString>::Iterator it;
1985             QString key;
1986             mlt_properties transproperties = MLT_TRANSITION_PROPERTIES(tr);
1987
1988             for (it = map.begin(); it != map.end(); ++it) {
1989                 key = it.key();
1990                 char *name = decodedString(key);
1991                 char *value = decodedString(it.value());
1992                 mlt_properties_set(transproperties, name, value);
1993                 kDebug() << " ------  UPDATING TRANS PARAM: " << name << ": " << value;
1994                 //filter->set("kdenlive_id", id);
1995                 delete[] name;
1996                 delete[] value;
1997             }
1998             break;
1999         }
2000         nextservice = mlt_service_producer(nextservice);
2001         if (nextservice == NULL) break;
2002         properties = MLT_SERVICE_PROPERTIES(nextservice);
2003         mlt_type = mlt_properties_get(properties, "mlt_type");
2004         resource = mlt_properties_get(properties, "mlt_service");
2005     }
2006     m_isBlocked = false;
2007     m_mltConsumer->set("refresh", 1);
2008 }
2009
2010 void Render::mltDeleteTransition(QString tag, int a_track, int b_track, GenTime in, GenTime out, QDomElement xml, bool do_refresh) {
2011     Mlt::Service service(m_mltProducer->parent().get_service());
2012     Mlt::Tractor tractor(service);
2013     Mlt::Field *field = tractor.field();
2014
2015     if (do_refresh) m_mltConsumer->set("refresh", 0);
2016     mlt_service serv = m_mltProducer->parent().get_service();
2017
2018     mlt_service nextservice = mlt_service_get_producer(serv);
2019     mlt_properties properties = MLT_SERVICE_PROPERTIES(nextservice);
2020     QString mlt_type = mlt_properties_get(properties, "mlt_type");
2021     QString resource = mlt_properties_get(properties, "mlt_service");
2022     int old_pos = (int)((in + out).frames(m_fps) / 2);
2023
2024     while (mlt_type == "transition") {
2025         mlt_transition tr = (mlt_transition) nextservice;
2026         int currentTrack = mlt_transition_get_b_track(tr);
2027         int currentIn = (int) mlt_transition_get_in(tr);
2028         int currentOut = (int) mlt_transition_get_out(tr);
2029         kDebug() << "// FOUND EXISTING TRANS, IN: " << currentIn << ", OUT: " << currentOut << ", TRACK: " << currentTrack;
2030
2031         if (resource == tag && b_track == currentTrack && currentIn <= old_pos && currentOut >= old_pos) {
2032             //kDebug() << " / / / / /DELETE TRANS DOOOMNE";
2033             mlt_field_disconnect_service(field->get_field(), nextservice);
2034             break;
2035         }
2036         nextservice = mlt_service_producer(nextservice);
2037         if (nextservice == NULL) break;
2038         properties = MLT_SERVICE_PROPERTIES(nextservice);
2039         mlt_type = mlt_properties_get(properties, "mlt_type");
2040         resource = mlt_properties_get(properties, "mlt_service");
2041     }
2042     if (do_refresh) m_mltConsumer->set("refresh", 1);
2043 }
2044
2045 QMap<QString, QString> Render::mltGetTransitionParamsFromXml(QDomElement xml) {
2046     QDomNodeList attribs = xml.elementsByTagName("parameter");
2047     QMap<QString, QString> map;
2048     for (int i = 0;i < attribs.count();i++) {
2049         QDomElement e = attribs.item(i).toElement();
2050         QString name = e.attribute("name");
2051         //kDebug()<<"-- TRANSITION PARAM: "<<name<<" = "<< e.attribute("name")<<" / " << e.attribute("value");
2052         map[name] = e.attribute("default");
2053         if (!e.attribute("value").isEmpty()) {
2054             map[name] = e.attribute("value");
2055         }
2056         if (!e.attribute("factor").isEmpty() && e.attribute("factor").toDouble() > 0) {
2057             map[name] = QString::number(map[name].toDouble() / e.attribute("factor").toDouble());
2058             //map[name]=map[name].replace(".",","); //FIXME how to solve locale conversion of . ,
2059         }
2060
2061         if (e.attribute("namedesc").contains(";")) {
2062             QString format = e.attribute("format");
2063             QStringList separators = format.split("%d", QString::SkipEmptyParts);
2064             QStringList values = e.attribute("value").split(QRegExp("[,:;x]"));
2065             QString neu;
2066             QTextStream txtNeu(&neu);
2067             if (values.size() > 0)
2068                 txtNeu << (int)values[0].toDouble();
2069             int i = 0;
2070             for (i = 0;i < separators.size() && i + 1 < values.size();i++) {
2071                 txtNeu << separators[i];
2072                 txtNeu << (int)(values[i+1].toDouble());
2073             }
2074             if (i < separators.size())
2075                 txtNeu << separators[i];
2076             map[e.attribute("name")] = neu;
2077         }
2078
2079     }
2080     return map;
2081 }
2082
2083 void Render::mltAddClipTransparency(ItemInfo info, int transitiontrack, int id) {
2084     kDebug() << "/////////  ADDING CLIP TRANSPARENCY AT: " << info.startPos.frames(25);
2085     Mlt::Service service(m_mltProducer->parent().get_service());
2086     Mlt::Tractor tractor(service);
2087     Mlt::Field *field = tractor.field();
2088
2089     Mlt::Transition *transition = new Mlt::Transition(*m_mltProfile, "composite");
2090     transition->set_in_and_out((int) info.startPos.frames(m_fps), (int) info.endPos.frames(m_fps) - 1);
2091     transition->set("transparency", id);
2092     transition->set("fill", 1);
2093     transition->set("internal_added", 237);
2094     field->plant_transition(*transition, transitiontrack, info.track);
2095     refresh();
2096 }
2097
2098 void Render::mltDeleteTransparency(int pos, int track, int id) {
2099     Mlt::Service service(m_mltProducer->parent().get_service());
2100     Mlt::Tractor tractor(service);
2101     Mlt::Field *field = tractor.field();
2102
2103     //if (do_refresh) m_mltConsumer->set("refresh", 0);
2104     mlt_service serv = m_mltProducer->parent().get_service();
2105
2106     mlt_service nextservice = mlt_service_get_producer(serv);
2107     mlt_properties properties = MLT_SERVICE_PROPERTIES(nextservice);
2108     QString mlt_type = mlt_properties_get(properties, "mlt_type");
2109     QString resource = mlt_properties_get(properties, "mlt_service");
2110
2111     while (mlt_type == "transition") {
2112         mlt_transition tr = (mlt_transition) nextservice;
2113         int currentTrack = mlt_transition_get_b_track(tr);
2114         int currentIn = (int) mlt_transition_get_in(tr);
2115         int currentOut = (int) mlt_transition_get_out(tr);
2116         int transitionId = QString(mlt_properties_get(properties, "transparency")).toInt();
2117         kDebug() << "// FOUND EXISTING TRANS, IN: " << currentIn << ", OUT: " << currentOut << ", TRACK: " << currentTrack;
2118
2119         if (resource == "composite" && track == currentTrack && currentIn == pos && transitionId == id) {
2120             //kDebug() << " / / / / /DELETE TRANS DOOOMNE";
2121             mlt_field_disconnect_service(field->get_field(), nextservice);
2122             break;
2123         }
2124         nextservice = mlt_service_producer(nextservice);
2125         if (nextservice == NULL) break;
2126         properties = MLT_SERVICE_PROPERTIES(nextservice);
2127         mlt_type = mlt_properties_get(properties, "mlt_type");
2128         resource = mlt_properties_get(properties, "mlt_service");
2129     }
2130     //if (do_refresh) m_mltConsumer->set("refresh", 1);
2131 }
2132
2133 void Render::mltResizeTransparency(int oldStart, int newStart, int newEnd, int track, int id) {
2134     Mlt::Service service(m_mltProducer->parent().get_service());
2135     Mlt::Tractor tractor(service);
2136     Mlt::Field *field = tractor.field();
2137
2138     mlt_service_lock(service.get_service());
2139     m_mltConsumer->set("refresh", 0);
2140     m_isBlocked = true;
2141
2142     mlt_service serv = m_mltProducer->parent().get_service();
2143     mlt_service nextservice = mlt_service_get_producer(serv);
2144     mlt_properties properties = MLT_SERVICE_PROPERTIES(nextservice);
2145     QString mlt_type = mlt_properties_get(properties, "mlt_type");
2146     QString resource = mlt_properties_get(properties, "mlt_service");
2147     kDebug() << "// resize transpar from: " << oldStart << ", TO: " << newStart << "x" << newEnd << ", " << track << ", " << id;
2148     while (mlt_type == "transition") {
2149         mlt_transition tr = (mlt_transition) nextservice;
2150         int currentTrack = mlt_transition_get_b_track(tr);
2151         int currentIn = (int) mlt_transition_get_in(tr);
2152         //mlt_properties props = MLT_TRANSITION_PROPERTIES(tr);
2153         int transitionId = QString(mlt_properties_get(properties, "transparency")).toInt();
2154         kDebug() << "// resize transpar current in: " << currentIn << ", Track: " << currentTrack << ", id: " << id << "x" << transitionId ;
2155         if (resource == "composite" && track == currentTrack && currentIn == oldStart && transitionId == id) {
2156             kDebug() << " / / / / /RESIZE TRANS TO: " << newStart << "x" << newEnd;
2157             mlt_transition_set_in_and_out(tr, newStart, newEnd);
2158             break;
2159         }
2160         nextservice = mlt_service_producer(nextservice);
2161         if (nextservice == NULL) break;
2162         properties = MLT_SERVICE_PROPERTIES(nextservice);
2163         mlt_type = mlt_properties_get(properties, "mlt_type");
2164         resource = mlt_properties_get(properties, "mlt_service");
2165     }
2166     m_isBlocked = false;
2167     mlt_service_unlock(service.get_service());
2168     m_mltConsumer->set("refresh", 1);
2169
2170 }
2171
2172 void Render::mltMoveTransparency(int startTime, int endTime, int startTrack, int endTrack, int id) {
2173     Mlt::Service service(m_mltProducer->parent().get_service());
2174     Mlt::Tractor tractor(service);
2175     Mlt::Field *field = tractor.field();
2176
2177     mlt_service_lock(service.get_service());
2178     m_mltConsumer->set("refresh", 0);
2179     m_isBlocked = true;
2180
2181     mlt_service serv = m_mltProducer->parent().get_service();
2182     mlt_service nextservice = mlt_service_get_producer(serv);
2183     mlt_properties properties = MLT_SERVICE_PROPERTIES(nextservice);
2184     QString mlt_type = mlt_properties_get(properties, "mlt_type");
2185     QString resource = mlt_properties_get(properties, "mlt_service");
2186
2187     while (mlt_type == "transition") {
2188         mlt_transition tr = (mlt_transition) nextservice;
2189         int currentTrack = mlt_transition_get_b_track(tr);
2190         int currentaTrack = mlt_transition_get_a_track(tr);
2191         int currentIn = (int) mlt_transition_get_in(tr);
2192         int currentOut = (int) mlt_transition_get_out(tr);
2193         //mlt_properties properties = MLT_TRANSITION_PROPERTIES(tr);
2194         int transitionId = QString(mlt_properties_get(properties, "transparency")).toInt();
2195         //kDebug()<<" + TRANSITION "<<id<<" == "<<transitionId<<", START TMIE: "<<currentIn<<", LOOK FR: "<<startTime<<", TRACK: "<<currentTrack<<"x"<<startTrack;
2196         if (resource == "composite" && transitionId == id && startTime == currentIn && startTrack == currentTrack) {
2197             kDebug() << "//////MOVING";
2198             mlt_transition_set_in_and_out(tr, endTime, endTime + currentOut - currentIn);
2199             if (endTrack != startTrack) {
2200                 mlt_properties properties = MLT_TRANSITION_PROPERTIES(tr);
2201                 mlt_properties_set_int(properties, "a_track", currentaTrack + endTrack - currentTrack);
2202                 mlt_properties_set_int(properties, "b_track", endTrack);
2203             }
2204             break;
2205         }
2206         nextservice = mlt_service_producer(nextservice);
2207         if (nextservice == NULL) break;
2208         properties = MLT_SERVICE_PROPERTIES(nextservice);
2209         mlt_type = mlt_properties_get(properties, "mlt_type");
2210         resource = mlt_properties_get(properties, "mlt_service");
2211     }
2212     m_isBlocked = false;
2213     mlt_service_unlock(service.get_service());
2214     m_mltConsumer->set("refresh", 1);
2215 }
2216
2217
2218 void Render::mltAddTransition(QString tag, int a_track, int b_track, GenTime in, GenTime out, QDomElement xml, bool do_refresh) {
2219
2220     QMap<QString, QString> args = mltGetTransitionParamsFromXml(xml);
2221     Mlt::Service service(m_mltProducer->parent().get_service());
2222
2223     Mlt::Tractor tractor(service);
2224     Mlt::Field *field = tractor.field();
2225
2226     char *transId = decodedString(tag);
2227     Mlt::Transition *transition = new Mlt::Transition(*m_mltProfile, transId);
2228     if (out != GenTime())
2229         transition->set_in_and_out((int) in.frames(m_fps), (int) out.frames(m_fps));
2230     QMap<QString, QString>::Iterator it;
2231     QString key;
2232
2233     kDebug() << " ------  ADDING TRANSITION PARAMs: " << args.count();
2234
2235     for (it = args.begin(); it != args.end(); ++it) {
2236         key = it.key();
2237         char *name = decodedString(key);
2238         char *value = decodedString(it.value());
2239         transition->set(name, value);
2240         kDebug() << " ------  ADDING TRANS PARAM: " << name << ": " << value;
2241         //filter->set("kdenlive_id", id);
2242         delete[] name;
2243         delete[] value;
2244     }
2245     // attach filter to the clip
2246     field->plant_transition(*transition, a_track, b_track);
2247     delete[] transId;
2248     refresh();
2249 }
2250
2251 void Render::mltSavePlaylist() {
2252     kWarning() << "// UPDATING PLAYLIST TO DISK++++++++++++++++";
2253     Mlt::Consumer fileConsumer(*m_mltProfile, "westley");
2254     fileConsumer.set("resource", "/tmp/playlist.westley");
2255
2256     Mlt::Service service(m_mltProducer->get_service());
2257
2258     fileConsumer.connect(service);
2259     fileConsumer.start();
2260
2261 }
2262
2263 #include "renderer.moc"
2264