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