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