/***************************************************************************
                        krender.cpp  -  description
                           -------------------
  begin                : Fri Nov 22 2002
  copyright            : (C) 2002 by Jason Wood
  email                : jasonwood@blueyonder.co.uk
  copyright            : (C) 2005 Lucio Flavio Correa
  email                : lucio.correa@gmail.com
  copyright            : (C) Marco Gittler
  email                : g.marco@freenet.de
  copyright            : (C) 2006 Jean-Baptiste Mardelle
  email                : jb@ader.ch

***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

// ffmpeg Header files

extern "C" {
#include <avformat.h>
}

#include <iostream>

#include <qcolor.h>
#include <qpixmap.h>
#include <qxml.h>
#include <qapplication.h>
#include <qimage.h>
#include <qmutex.h>
#include <qevent.h>
#include <qtextstream.h>
#include <qstringlist.h>
#include <qdir.h>
#include <qcstring.h>

#include <kio/netaccess.h>
#include <kdebug.h>
#include <kmessagebox.h>
#include <klocale.h>
#include <kstandarddirs.h>



#include "kdenlive.h"
#include "krender.h"

#include "effectparamdesc.h"
#include "initeffects.h"

static QMutex mutex (true);

static void consumer_frame_show(mlt_consumer, KRender * self, mlt_frame frame_ptr)
{
    // detect if the producer has finished playing. Is there a better way to do it ?
    if (self->isBlocked) return;
    if (mlt_properties_get_double( MLT_FRAME_PROPERTIES( frame_ptr ), "_speed" ) == 0.0) {
        self->emitConsumerStopped();
    }
    else {
	self->emitFrameNumber(mlt_frame_get_position(frame_ptr));
    }
}

KRender::KRender(const QString & rendererName, QWidget *parent, const char *name, int wid, int extwid):QObject(parent, name), m_name(rendererName), m_mltConsumer(NULL), m_mltProducer(NULL), m_mltTextProducer(NULL), m_sceneList(QDomDocument()), m_winid(wid), m_externalwinid(extwid), m_framePosition(0), m_generateScenelist(false), isBlocked(true)
{
    m_mltProfile = new Mlt::Profile((char*) KdenliveSettings::videoprofile().ascii());
    refreshTimer = new QTimer( this );
    connect( refreshTimer, SIGNAL(timeout()), this, SLOT(refresh()) );

    m_connectTimer = new QTimer( this );
    connect( m_connectTimer, SIGNAL(timeout()), this, SLOT(connectPlaylist()) );

    if (rendererName == "Document") m_monitorId = 10000;
    else m_monitorId = 10001;
    osdTimer = new QTimer( this );
    connect( osdTimer, SIGNAL(timeout()), this, SLOT(slotOsdTimeout()) );

    m_osdProfile = locate("data", "kdenlive/profiles/metadata.properties");
    m_osdInfo = new Mlt::Filter(*m_mltProfile, "data_show");
    char *tmp = decodedString(m_osdProfile);
    m_osdInfo->set("resource", tmp);
    delete[] tmp;

    m_mltConsumer = new Mlt::Consumer(*m_mltProfile, "sdl_preview");
    //m_mltConsumer = consumer;

    if (!m_mltConsumer || !m_mltConsumer->is_valid()) {
	KMessageBox::error(qApp->mainWidget(), i18n("Could not create the video preview window.\nThere is something wrong with your Kdenlive install.\n Exiting now..."));
	kdError()<<"Sorry, cannot create MLT consumer, check your MLT install you miss SDL libraries support in MLT"<<endl;
	qApp->quit();
    }

    if (KdenliveSettings::useexternalmonitor()) {
	m_mltConsumer->set("output_display", QString(":0." + QString::number(KdenliveSettings::externalmonitor())).ascii());
	m_mltConsumer->set("window_id", m_externalwinid);
    }
    else m_mltConsumer->set("window_id", m_winid);
    m_mltConsumer->set("resize", 1);
    m_mltConsumer->set("rescale", KdenliveSettings::previewquality().ascii());

    m_mltConsumer->set("terminate_on_pause", 1);
    QString aDevice = KdenliveSettings::audiodevice();
    if (!KdenliveSettings::videodriver().isEmpty()) m_mltConsumer->set("video_driver", KdenliveSettings::videodriver().ascii());
    if (!KdenliveSettings::audiodriver().isEmpty()) m_mltConsumer->set("audio_driver", KdenliveSettings::audiodriver().ascii());
    m_mltConsumer->set("audio_device", aDevice.section(";", 1).ascii());
    m_mltConsumer->set("progressive", 1);
    m_mltConsumer->set("audio_buffer", 1024);
    m_mltConsumer->set("frequency", 48000);

    m_mltConsumer->listen("consumer-frame-show", this, (mlt_listener) consumer_frame_show);
    //m_mltConsumer->start();
    initSceneList();

    kdDebug()<<"//// CREATING RENDERER.. DONE "<<rendererName<<endl;
    //      Does it do anything usefull? I mean, KRenderThread doesn't do anything useful at the moment
    //      (except being cpu hungry :)

    /*      if(!s_renderThread) {
    s_renderThread = new KRenderThread;
    s_renderThread->start();
    } */
}

KRender::~KRender()
{
    closeMlt();
}

void KRender::setWid(int wid)
{
    if (wid == m_winid) return;
    if (!m_mltConsumer->is_stopped()) m_mltConsumer->stop();
    m_winid = wid;
    m_mltConsumer->set("window_id", m_winid);
    m_mltConsumer->stop();
}

int KRender::renderWidgetId()
{
    return m_winid;
}

int KRender::renderExtWidgetId()
{
    return m_externalwinid;
}

void KRender::closeMlt()
{
    delete m_connectTimer;
    delete osdTimer;
    delete refreshTimer;
    if (m_mltConsumer)
        delete m_mltConsumer;
    if (m_mltProducer)
	delete m_mltProducer;
    delete m_osdInfo;
}

 

static void consumer_stopped(mlt_consumer, KRender * self, mlt_frame )
{
    //self->emitConsumerStopped();
}

void my_lock()
{
    //mutex.lock();
}
void my_unlock()
{
    //mutex.unlock();
}



int KRender::resetRendererProfile(char * profile)
{
    if (!m_mltConsumer) return 0;
    if (!m_mltConsumer->is_stopped()) m_mltConsumer->stop();
    m_mltConsumer->set("refresh", 0);

    if (m_mltProducer) delete m_mltProducer;
    m_mltProducer = NULL;

    delete m_mltConsumer;
    m_mltConsumer = NULL;

    delete m_mltProfile;
    m_mltProfile = new Mlt::Profile(qstrdup(profile));
    kdDebug()<<" + + RESET CONSUMER WITH PROFILE: "<<m_mltProfile->width()<<endl;
    m_mltConsumer = new Mlt::Consumer(*m_mltProfile, "sdl_preview");
    //m_mltConsumer = consumer;

    if (!m_mltConsumer || !m_mltConsumer->is_valid()) {
	KMessageBox::error(qApp->mainWidget(), i18n("Could not create the video preview window.\nThere is something wrong with your Kdenlive install.\n Exiting now..."));
	kdError()<<"Sorry, cannot create MLT consumer, check your MLT install you miss SDL libraries support in MLT"<<endl;
	qApp->quit();
    }

    if (KdenliveSettings::useexternalmonitor()) {
	m_mltConsumer->set("output_display", QString(":0." + QString::number(KdenliveSettings::externalmonitor())).ascii());
	m_mltConsumer->set("window_id", m_externalwinid);
    }
    else m_mltConsumer->set("window_id", m_winid);
    m_mltConsumer->set("resize", 1);
    m_mltConsumer->set("rescale", KdenliveSettings::previewquality().ascii());

    m_mltConsumer->set("terminate_on_pause", 1);
    QString aDevice = KdenliveSettings::audiodevice();
    if (!KdenliveSettings::videodriver().isEmpty()) m_mltConsumer->set("video_driver", KdenliveSettings::videodriver().ascii());
    if (!KdenliveSettings::audiodriver().isEmpty()) m_mltConsumer->set("audio_driver", KdenliveSettings::audiodriver().ascii());
    m_mltConsumer->set("audio_device", aDevice.section(";", 1).ascii());
    m_mltConsumer->set("progressive", 1);
    m_mltConsumer->set("audio_buffer", 1024);
    m_mltConsumer->set("frequency", 48000);

    m_mltConsumer->listen("consumer-frame-show", this, (mlt_listener) consumer_frame_show);
    initSceneList();
    //mlt_properties properties = MLT_CONSUMER_PROPERTIES( m_mltConsumer->get_consumer() );


    //mlt_properties_set_data(properties, "profile", m_mltProfile->get_profile(), 0, NULL, NULL);

    //m_mltConsumer->set("profile", profile);
    
    //m_fps = KdenliveSettings::defaultfps();
    //m_mltConsumer->set("fps", m_fps);
    
    //delete m_mltProfile;
    //m_mltProfile = new Mlt::Profile(profile);
    //m_mltConsumer->start();
    //mlt_properties properties = MLT_CONSUMER_PROPERTIES( m_mltConsumer->get_consumer() );
    //apply_profile_properties( m_mltConsumer->get_consumer(), prof.get_profile(), properties );
    //int result = mlt_consumer_profile( properties, profile );
    //refresh();*/
    return 1; //result;
}


/** Wraps the VEML command of the same name; Seeks the renderer clip to the given time. */
void KRender::seek(GenTime time)
{
    sendSeekCommand(time);
    //emit positionChanged(time);
}

//static
char *KRender::decodedString(QString str)
{
    QCString fn = QFile::encodeName(str);
    char *t = new char[fn.length() + 1];
    strcpy(t, (const char *)fn);
    return t;
}

QPixmap KRender::frameThumbnail(Mlt::Frame *frame, int width, int height, bool border)
{
    QPixmap pix(width, height);

    mlt_image_format format = mlt_image_rgb24a;
    if (border) {
	width = width -2;
	height = height -2;
    }
    kdDebug()<<"/// GTE TMB, "<<width<<", "<<height<<", FRAME SIZE: "<<frame->get("width")<<", "<<frame->get("height")<<endl;
    uint8_t *thumb = frame->get_image(format, width, height);
    QImage image(thumb, width, height, 32, NULL, 0, QImage::IgnoreEndian);
    image.setAlphaBuffer( true );
    if (!image.isNull()) {
	if (!border) bitBlt(&pix, 0, 0, &image, 0, 0, width, height);
	else {
		pix.fill(black);
		bitBlt(&pix, 1, 1, &image, 0, 0, width, height);
	}
    }
    else pix.fill(black);
    return pix;
}


QPixmap KRender::extractFrame(int frame_position, int width, int height)
{
    QPixmap pix(width, height);
    if (!m_mltProducer) {
	pix.fill(black);
	return pix;
    }
    Mlt::Producer *mlt_producer = m_mltProducer->cut(frame_position, frame_position + 1);
    Mlt::Filter m_convert(*m_mltProfile, "avcolour_space");
    m_convert.set("forced", mlt_image_rgb24a);
    mlt_producer->attach(m_convert);
    Mlt::Frame *frame = mlt_producer->get_frame();

    if (frame) {
	pix = frameThumbnail(frame, width, height);
	delete frame;
    }
    else pix.fill(black);
    delete mlt_producer;
    return pix;
}

QPixmap KRender::getImageThumbnail(KURL url, int width, int height)
{
    QImage im;
    QPixmap pixmap;
    if (url.filename().startsWith(".all.")) {  //  check for slideshow
	    QString fileType = url.filename().right(3);
    	    QStringList more;
    	    QStringList::Iterator it;

            QDir dir( url.directory() );
            more = dir.entryList( QDir::Files );
 
            for ( it = more.begin() ; it != more.end() ; ++it ) {
                if ((*it).endsWith("."+fileType, FALSE)) {
			im.load(url.directory() + "/" + *it);
			break;
		}
	    }
    }
    else im.load(url.path());
    pixmap = im.smoothScale(width, height);
    return pixmap;
}

QPixmap KRender::getVideoThumbnail(QString file, int frame_position, int width, int height)
{
    QPixmap pix(width, height);
    char *tmp = decodedString(file);
    Mlt::Producer m_producer(*m_mltProfile, tmp);
    delete[] tmp;
    if (m_producer.is_blank()) {
	pix.fill(black);
	return pix;
    }

    Mlt::Filter m_convert(*m_mltProfile, "avcolour_space");
    m_convert.set("forced", mlt_image_rgb24a);
    m_producer.attach(m_convert);
    m_producer.seek(frame_position);
    Mlt::Frame * frame = m_producer.get_frame();
    if (frame) {
	pix = frameThumbnail(frame, width, height, true);
	delete frame;
    }
    return pix;
}


void KRender::getImage(KURL url, int frame_position, QPoint size)
{
    char *tmp = decodedString(url.path());
    Mlt::Producer m_producer(*m_mltProfile, tmp);
    delete[] tmp;
    if (m_producer.is_blank()) {
	return;
    }
    Mlt::Filter m_convert(*m_mltProfile, "avcolour_space");
    m_convert.set("forced", mlt_image_rgb24a);
    m_producer.attach(m_convert);
    m_producer.seek(frame_position);

    Mlt::Frame * frame = m_producer.get_frame();

    if (frame) {
	QPixmap pix = frameThumbnail(frame, size.x(), size.y(), true);
	delete frame;
	emit replyGetImage(url, frame_position, pix, size.x(), size.y());
    }
}

/* Create thumbnail for color */
void KRender::getImage(int id, QString color, QPoint size)
{
    QPixmap pixmap(size.x() - 2, size.y() - 2);
    color = color.replace(0, 2, "#");
    color = color.left(7);
    pixmap.fill(QColor(color));
    QPixmap result(size.x(), size.y());
    result.fill(Qt::black);
    copyBlt(&result, 1, 1, &pixmap, 0, 0, size.x() - 2, size.y() - 2);
    emit replyGetImage(id, result, size.x(), size.y());

}

/* Create thumbnail for image */
void KRender::getImage(KURL url, QPoint size)
{
    QImage im;
    QPixmap pixmap;
    if (url.filename().startsWith(".all.")) {  //  check for slideshow
	    QString fileType = url.filename().right(3);
    	    QStringList more;
    	    QStringList::Iterator it;

            QDir dir( url.directory() );
            more = dir.entryList( QDir::Files );
            for ( it = more.begin() ; it != more.end() ; ++it ) {
                if ((*it).endsWith("."+fileType, FALSE)) {
			if (!im.load(url.directory() + "/" + *it))
			    kdDebug()<<"++ ERROR LOADIN IMAGE: "<<url.directory() + "/" + *it<<endl;
			break;
		}
	    }
    }
    else im.load(url.path());

    pixmap = im.smoothScale(size.x() - 2, size.y() - 2);
    QPixmap result(size.x(), size.y());
    result.fill(Qt::black);
    copyBlt(&result, 1, 1, &pixmap, 0, 0, size.x() - 2, size.y() - 2);
    emit replyGetImage(url, 1, result, size.x(), size.y());
}


double KRender::consumerRatio() const
{
    if (!m_mltConsumer) return 1.0;
    return (m_mltConsumer->get_double("aspect_ratio_num")/m_mltConsumer->get_double("aspect_ratio_den"));
}


int KRender::getLength()
{

    if (m_mltProducer) 
    {
	kdDebug()<<"//////  LENGTH: "<<mlt_producer_get_playtime(m_mltProducer->get_producer())<<", V2: "<<m_mltProducer->get_playtime()<<endl;
	return mlt_producer_get_playtime(m_mltProducer->get_producer());
    }
    return 0;
}

bool KRender::isValid(KURL url)
{
    char *tmp = decodedString(url.path());
    Mlt::Producer producer(*m_mltProfile, tmp);
    delete[] tmp;
    if (producer.is_blank())
	return false;

    return true;
}


void KRender::getFileProperties(KURL url, uint framenb)
{
        int height = 40;
        int width = height * KdenliveSettings::displayratio();
	char *tmp = decodedString(url.path());

	Mlt::Producer producer(*m_mltProfile, tmp);
	delete[] tmp;
    	if (producer.is_blank()) {
	    return;
    	}
	producer.seek( framenb );
	mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer.get_producer() );

	QMap < QString, QString > filePropertyMap;
        QMap < QString, QString > metadataPropertyMap;

	kdDebug()<<"Getting file PROPS: "<<url.path()<<", DURATON: "<<QString::number(producer.get_playtime())<<endl;
	filePropertyMap["filename"] = url.path();
	filePropertyMap["duration"] = QString::number(producer.get_playtime());
        
        Mlt::Filter m_convert(*m_mltProfile, "avcolour_space");
        m_convert.set("forced", mlt_image_rgb24a);
        producer.attach(m_convert);

	Mlt::Frame * frame = producer.get_frame();

	if (frame->is_valid()) {
	    filePropertyMap["fps"] =
		QString::number(mlt_producer_get_fps( producer.get_producer() ));
	    filePropertyMap["width"] =
		QString::number(frame->get_int("width"));
	    filePropertyMap["height"] =
		QString::number(frame->get_int("height"));
	    filePropertyMap["frequency"] =
		QString::number(frame->get_int("frequency"));
	    filePropertyMap["channels"] =
		QString::number(frame->get_int("channels"));

	// Retrieve audio / video codec name

	// Fetch the video_context
	AVFormatContext *context = (AVFormatContext *) mlt_properties_get_data( properties, "video_context", NULL );
	if (context != NULL) {
		// Get the video_index
		int index = mlt_properties_get_int( properties, "video_index" );
		if (context->streams && 
		    context->streams [index] && 
		    context->streams[ index ]->codec && 
		    context->streams[ index ]->codec->codec && 
		    context->streams[ index ]->codec->codec->name )
			 filePropertyMap["videocodec"] = context->streams[ index ]->codec->codec->name;
	}
	context = (AVFormatContext *) mlt_properties_get_data( properties, "audio_context", NULL );
	if (context != NULL) {
		// Get the video_index
		int index = mlt_properties_get_int( properties, "audio_index" );
		if (context->streams && 
		    context->streams [index] &&
		    context->streams[ index ]->codec && 
		    context->streams[ index ]->codec->codec && 
		    context->streams[ index ]->codec->codec->name )
			filePropertyMap["audiocodec"] = context->streams[ index ]->codec->codec->name;
	}



	    // metadata

	    mlt_properties metadata = mlt_properties_new( );
	    mlt_properties_pass( metadata, properties, "meta.attr." );
	    int count = mlt_properties_count( metadata );
	    for ( int i = 0; i < count; i ++ )
	    {
		QString name = mlt_properties_get_name( metadata, i );
		QString value = QString::fromUtf8(mlt_properties_get_value( metadata, i ));
		if (name.endsWith("markup") && !value.isEmpty())
			metadataPropertyMap[ name.section(".", 0, -2) ] = value;
	    }

	    if (frame->get_int("test_image") == 0) {
		if (url.path().endsWith(".westley") || url.path().endsWith(".kdenlive")) {
		    filePropertyMap["type"] = "playlist";
		    metadataPropertyMap["comment"] = QString::fromUtf8(mlt_properties_get( MLT_SERVICE_PROPERTIES( producer.get_service() ), "title"));
		}
		else if (frame->get_int("test_audio") == 0)
		    filePropertyMap["type"] = "av";
		else
		    filePropertyMap["type"] = "video";

                // Generate thumbnail for this frame
		QPixmap pixmap = frameThumbnail(frame, width, height, true);

                emit replyGetImage(url, 0, pixmap, width, height);

	    } else if (frame->get_int("test_audio") == 0) {
                QPixmap pixmap(locate("appdata", "graphics/music.png"));
                emit replyGetImage(url, 0, pixmap, width, height);
		filePropertyMap["type"] = "audio";
            }
	}
	emit replyGetFileProperties(filePropertyMap, metadataPropertyMap);
	if (frame) delete frame;
	//if (producer) delete producer;
}

QDomDocument KRender::sceneList() const
{
    return m_sceneList;
}

/** Create the producer from the Westley QDomDocument */
void KRender::initSceneList()
{
    kdDebug()<<"--------  INIT SCENE LIST ------_"<<endl;
    QDomDocument doc;
    QDomElement westley = doc.createElement("westley");
    doc.appendChild(westley);
    QDomElement prod = doc.createElement("producer");
    prod.setAttribute("resource", "colour");
    prod.setAttribute("colour", "black");
    prod.setAttribute("id", "black");
    prod.setAttribute("in", "0");
    prod.setAttribute("out", "0");

    QDomElement tractor = doc.createElement("tractor");
    QDomElement multitrack = doc.createElement("multitrack"); 

    QDomElement playlist1 = doc.createElement("playlist");
    playlist1.appendChild(prod);
    multitrack.appendChild(playlist1);
    QDomElement playlist2 = doc.createElement("playlist");
    multitrack.appendChild(playlist2);
    QDomElement playlist3 = doc.createElement("playlist");
    multitrack.appendChild(playlist3);
    QDomElement playlist4 = doc.createElement("playlist");
    multitrack.appendChild(playlist4);
    QDomElement playlist5 = doc.createElement("playlist");
    multitrack.appendChild(playlist5);
    tractor.appendChild(multitrack);
    westley.appendChild(tractor);
    kdDebug()<<doc.toString()<<endl;
/*
   QString tmp = QString("<westley><producer resource=\"colour\" colour=\"red\" id=\"red\" /><tractor><multitrack><playlist></playlist><playlist></playlist><playlist /><playlist /><playlist></playlist></multitrack></tractor></westley>");*/
    setSceneList(doc, 0);
}


/** Create the producer from the Westley QDomDocument */
void KRender::setSceneList(QDomDocument list, int position)
{
    if (!m_winid == -1) return;
    m_generateScenelist = true;

    kdWarning()<<"//////  RENDER, SET SCENE LIST\n"<<list.toString()<<"\n---------------"<<endl;

    char *tmp = decodedString(list.toString());
    Mlt::Producer clip(*m_mltProfile, "westley-xml", tmp);
    delete[] tmp;

    if (clip.is_valid())
    	kdWarning()<<"//////  CLIP DURATION REND: "<<clip.get_playtime()<<endl;
    else {
	kdWarning()<<" ++++ WARNING, UNABLE TO CREATE MLT PRODUCER"<<endl;
	m_generateScenelist = false;
	return;
    }

    kdWarning()<<"//////  RENDER, SET SCENE LIST 1"<<endl;
    if (m_mltConsumer) {
	//m_mltConsumer->set("refresh", 0);
	if (!m_mltConsumer->is_stopped()) {
	    kdWarning()<<"//////  RENDER, SET SCENE LIST 2"<<endl;
	  //emitConsumerStopped();
	  m_mltConsumer->stop();
	}
    }
    kdWarning()<<"//////  RENDER, SET SCENE LIST 3"<<endl;
    if (m_mltProducer) {
	m_mltProducer->set_speed(0.0);

	if (KdenliveSettings::osdtimecode() && m_osdInfo) m_mltProducer->detach(*m_osdInfo);
	//mlt_producer_clear(m_mltProducer->get_producer());
	delete m_mltProducer;
	m_mltProducer = NULL;
	emit stopped();
    }

    m_mltProducer = new Mlt::Producer(clip); //track.current();
    m_mltProducer->optimise();
    if (position != 0) m_mltProducer->seek(position);

    if (KdenliveSettings::osdtimecode()) {
		// Attach filter for on screen display of timecode
		delete m_osdInfo;
		QString attr = "attr_check";
		mlt_filter filter = mlt_factory_filter(m_mltProfile->get_profile(), "data_feed", (char*) attr.ascii() );
		mlt_properties_set_int( MLT_FILTER_PROPERTIES( filter ), "_fezzik", 1 );
		mlt_producer_attach( m_mltProducer->get_producer(), filter );
		mlt_filter_close( filter );

    		m_osdInfo = new Mlt::Filter(*m_mltProfile, "data_show");
		tmp = decodedString(m_osdProfile);
    		m_osdInfo->set("resource", tmp);
		delete[] tmp;
		mlt_properties properties = MLT_PRODUCER_PROPERTIES(m_mltProducer->get_producer());
		mlt_properties_set_int( properties, "meta.attr.timecode", 1);
		mlt_properties_set( properties, "meta.attr.timecode.markup", "#timecode#");
		m_osdInfo->set("dynamic", "1");

    		if (m_mltProducer->attach(*m_osdInfo) == 1) kdDebug()<<"////// error attaching filter"<<endl;
	} else {
		m_osdInfo->set("dynamic", "0");
	}
	m_fps = m_mltProducer->get_fps();
    kdWarning()<<"//////  RENDER, SET SCENE LIST, FPS: "<<m_fps<<endl;
	//connectPlaylist();
	m_connectTimer->start( 500, TRUE);
	m_generateScenelist = false;
  
}


void KRender::connectPlaylist() {
	if (m_winid == -1 || !m_mltProducer) {
		m_connectTimer->start( 500, TRUE);
		return;
	}
	m_connectTimer->stop();
	kdDebug()<<" / / /CONNECTING PLAYLIST: - - -"<<m_winid<<endl;
	m_mltConsumer->connect(*m_mltProducer);
    	//refresh();
	m_mltProducer->set_speed(0.0);
	if (m_mltConsumer->start() == -1) {
	    	KMessageBox::error(qApp->mainWidget(), i18n("Could not create the video preview window.\nThere is something wrong with your Kdenlive install or your driver settings, please fix it."));
	    	m_mltConsumer = NULL;
	}
	else {
	    refresh();
	    m_mltConsumer->start();
	kdDebug()<<" / / /CONNECTING PLAYLIST: - - - 2"<<endl;
	}
}

void KRender::refreshDisplay() {

	if (!m_mltProducer) return;
	//m_mltConsumer->set("refresh", 0);

	mlt_properties properties = MLT_PRODUCER_PROPERTIES(m_mltProducer->get_producer());
	if (KdenliveSettings::osdtimecode()) {
	    mlt_properties_set_int( properties, "meta.attr.timecode", 1);
	    mlt_properties_set( properties, "meta.attr.timecode.markup", "#timecode#");
	    m_osdInfo->set("dynamic", "1");
	    m_mltProducer->attach(*m_osdInfo);
	}
	else {
	    m_mltProducer->detach(*m_osdInfo);
	    m_osdInfo->set("dynamic", "0");
	}
	refresh();
}

void KRender::setVolume(double volume)
{
    if (!m_mltConsumer || !m_mltProducer) return;
    osdTimer->stop();
	//m_mltConsumer->set("refresh", 0);
    // Attach filter for on screen display of timecode
    mlt_properties properties = MLT_PRODUCER_PROPERTIES(m_mltProducer->get_producer());
    mlt_properties_set_double( properties, "meta.volume", volume );
    mlt_properties_set_int( properties, "meta.attr.osdvolume", 1);
    mlt_properties_set( properties, "meta.attr.osdvolume.markup", i18n("Volume: ") + QString::number(volume * 100));

    if (!KdenliveSettings::osdtimecode()) {
	m_mltProducer->detach(*m_osdInfo);
	mlt_properties_set_int( properties, "meta.attr.timecode", 0);
    	if (m_mltProducer->attach(*m_osdInfo) == 1) kdDebug()<<"////// error attaching filter"<<endl;
    }
    refresh();
    osdTimer->start(2500, TRUE);
}

void KRender::slotOsdTimeout()
{
    mlt_properties properties = MLT_PRODUCER_PROPERTIES(m_mltProducer->get_producer());
    mlt_properties_set_int(properties, "meta.attr.osdvolume", 0);
    mlt_properties_set(properties, "meta.attr.osdvolume.markup", NULL);
    if (!KdenliveSettings::osdtimecode()) m_mltProducer->detach(*m_osdInfo);
    refresh();
}

void KRender::start()
{
    if (m_mltConsumer->is_stopped()) {
	if (m_mltConsumer->start() == -1) {
	    KMessageBox::error(qApp->mainWidget(), i18n("Could not create the video preview window.\nThere is something wrong with your Kdenlive install or your driver settings, please fix it."));
	    m_mltConsumer = NULL;
	    return;
	}
    	else {
		refresh();
	}
    }
    isBlocked = false;
}

void KRender::clear()
{
    if (m_mltConsumer) {
	m_mltConsumer->set("refresh", 0);
	if (!m_mltConsumer->is_stopped()) m_mltConsumer->stop();
    }

    if (m_mltProducer) {
	if (KdenliveSettings::osdtimecode() && m_osdInfo) m_mltProducer->detach(*m_osdInfo);
	m_mltProducer->set_speed(0.0);
	delete m_mltProducer;
	m_mltProducer = NULL;
	emit stopped();
    }
}

void KRender::stop()
{
    kdDebug()<<"/////////////   RENDER STOP-------"<<endl;
    if (m_mltConsumer && !m_mltConsumer->is_stopped()) {
	m_mltConsumer->set("refresh", 0);
	m_mltConsumer->stop();
    }

    isBlocked = true;

    if (m_mltProducer) {
	m_mltProducer->set_speed(0.0);
	m_mltProducer->set("out", m_mltProducer->get_length() - 1);
    }
}

void KRender::stop(const GenTime & startTime)
{
    kdDebug()<<"/////////////   RENDER STOP-------2"<<endl;
    if (m_mltProducer) {
	m_mltProducer->set_speed(0.0);
	m_mltProducer->seek((int) startTime.frames(m_fps));
    }
    m_mltConsumer->purge();
}


void KRender::play(double speed)
{
    kdDebug()<<"/////////////   RENDER PLAY-------"<<speed<<endl;
    if (!m_mltProducer)
	return;
    if (speed == 0.0) m_mltProducer->set("out", m_mltProducer->get_length() - 1);
    m_mltProducer->set_speed(speed);
    /*if (speed == 0.0) {
	m_mltProducer->seek((int) m_framePosition + 1);
        m_mltConsumer->purge();
    }*/
    refresh();
}

void KRender::play(double speed, const GenTime & startTime)
{
    kdDebug()<<"/////////////   RENDER PLAY2-------"<<speed<<endl;
    if (!m_mltProducer)
	return;
    //m_mltProducer->set("out", m_mltProducer->get_length() - 1);
    //if (speed == 0.0) m_mltConsumer->set("refresh", 0);
    m_mltProducer->set_speed(speed);
    m_mltProducer->seek((int) (startTime.frames(m_fps)));
    //m_mltConsumer->purge();
    refresh();
}

void KRender::play(double speed, const GenTime & startTime,
    const GenTime & stopTime)
{
    kdDebug()<<"/////////////   RENDER PLAY3-------"<<speed<<endl;
    if (!m_mltProducer)
	return;
    m_mltProducer->set("out", stopTime.frames(m_fps));
    m_mltProducer->seek((int) (startTime.frames(m_fps)));
    m_mltConsumer->purge();
    m_mltProducer->set_speed(speed);
    refresh();
}

void KRender::render(const KURL & url)
{
    QDomDocument doc;
    QDomElement elem = doc.createElement("render");
    elem.setAttribute("filename", url.path());
    doc.appendChild(elem);
}

void KRender::sendSeekCommand(GenTime time)
{
    if (!m_mltProducer)
	return;
    m_mltProducer->seek((int) (time.frames(m_fps)));
    refresh();
}

void KRender::askForRefresh()
{
    // Use a Timer so that we don't refresh too much
    refreshTimer->start(200, TRUE);
}

void KRender::refresh()
{
    if (!m_mltProducer)
	return;
    refreshTimer->stop();
    if (m_mltConsumer) {
	m_mltConsumer->set("refresh", 1);
    }
}

/** Sets the description of this renderer to desc. */
void KRender::setDescription(const QString & description)
{
    m_description = description;
}

/** Returns the description of this renderer */
QString KRender::description()
{
    return m_description;
}


double KRender::playSpeed()
{
    if (m_mltProducer) return m_mltProducer->get_speed();
    return 0.0;
}

const GenTime & KRender::seekPosition() const
{
    if (m_mltProducer) return GenTime((int) m_mltProducer->position(), m_fps);
    else return GenTime();
}


const QString & KRender::rendererName() const
{
    return m_name;
}


void KRender::emitFrameNumber(double position)
{
	if (m_generateScenelist) return;
	m_framePosition = position;
        if (qApp->mainWidget()) QApplication::postEvent(qApp->mainWidget(), new PositionChangeEvent( GenTime((int) position, m_fps), m_monitorId));
}

void KRender::emitConsumerStopped()
{
    // This is used to know when the playing stopped
    if (m_mltProducer && !m_generateScenelist) {
	double pos = m_mltProducer->position();
        if (qApp->mainWidget()) QApplication::postEvent(qApp->mainWidget(), new PositionChangeEvent(GenTime((int) pos, m_fps), m_monitorId + 100));
	//new QCustomEvent(10002));
    }
}



void KRender::exportFileToFirewire(QString srcFileName, int port, GenTime startTime, GenTime endTime)
{
KMessageBox::sorry(0, i18n("Firewire is not enabled on your system.\n Please install Libiec61883 and recompile Kdenlive"));
}


void KRender::exportCurrentFrame(KURL url, bool notify) {
    if (!m_mltProducer) {
	KMessageBox::sorry(qApp->mainWidget(), i18n("There is no clip, cannot extract frame."));
	return;
    }

    int height = KdenliveSettings::defaultheight();
    int width = KdenliveSettings::displaywidth();

    QPixmap pix(width, height);
    Mlt::Filter m_convert(*m_mltProfile, "avcolour_space");
    m_convert.set("forced", mlt_image_rgb24a);
    m_mltProducer->attach(m_convert);
    Mlt::Frame * frame = m_mltProducer->get_frame();
    m_mltProducer->detach(m_convert);
    if (frame) {
	pix = frameThumbnail(frame, width, height);
	delete frame;
    }
    pix.save(url.path(), "PNG");
    if (notify) QApplication::postEvent(qApp->mainWidget(), new UrlEvent(url, 10003));
}

/**	MLT PLAYLIST DIRECT MANIPULATON		**/


void KRender::mltCheckLength()
{
    //kdDebug()<<"checking track length: "<<track<<".........."<<endl;
    Mlt::Service service(m_mltProducer->get_service());
    Mlt::Tractor tractor(service);

    int trackNb = tractor.count( );
    double duration = 0;
    double trackDuration;
    if (trackNb == 1) {
        Mlt::Producer trackProducer(tractor.track(0));
        Mlt::Playlist trackPlaylist(( mlt_playlist ) trackProducer.get_service());
        duration = Mlt::Producer(trackPlaylist.get_producer()).get_playtime() - 1;
	m_mltProducer->set("out", duration);
	emit durationChanged();
	return;
    }
    while (trackNb > 1) {
        Mlt::Producer trackProducer(tractor.track(trackNb - 1));
        Mlt::Playlist trackPlaylist(( mlt_playlist ) trackProducer.get_service());
        trackDuration = Mlt::Producer(trackPlaylist.get_producer()).get_playtime() - 1;

	kdDebug()<<" / / /DURATON FOR TRACK "<<trackNb - 1<<" = "<<trackDuration<<endl;
	if (trackDuration > duration) duration = trackDuration;
	trackNb--;
    }

    Mlt::Producer blackTrackProducer(tractor.track(0));
    Mlt::Playlist blackTrackPlaylist(( mlt_playlist ) blackTrackProducer.get_service());
    double blackDuration = Mlt::Producer(blackTrackPlaylist.get_producer()).get_playtime() - 1;
	kdDebug()<<" / / /DURATON FOR TRACK 0 = "<<blackDuration<<endl;
    if (blackDuration != duration) {
	blackTrackPlaylist.remove_region( 0, blackDuration );
	int i = 0;
	int dur = duration;
	
        while (dur > 14000) { // <producer mlt_service=\"colour\" colour=\"black\" in=\"0\" out=\"13999\" />
	    mltInsertClip(0, GenTime(i * 14000, m_fps), QString("<westley><producer mlt_service=\"colour\" colour=\"black\" in=\"0\" out=\"13999\" /></westley>"));
	    dur = dur - 14000;
	    i++;
        }

	mltInsertClip(0, GenTime(), QString("<westley><producer mlt_service=\"colour\" colour=\"black\" in=\"0\" out=\"" + QString::number(dur) + "\" /></westley>"));

	m_mltProducer->set("out", duration);
	emit durationChanged();
    }
}


void KRender::mltInsertClip(int track, GenTime position, QString resource)
{
    if (!m_mltProducer) {
	kdDebug()<<"PLAYLIST NOT INITIALISED //////"<<endl;
	return;
    }
    Mlt::Producer parentProd(m_mltProducer->parent());
    if (parentProd.get_producer() == NULL) {
	kdDebug()<<"PLAYLIST BROKEN, CANNOT INSERT CLIP //////"<<endl;
	return;
    }
    Mlt::Service service(parentProd.get_service());
    Mlt::Tractor tractor(service);

    Mlt::Producer trackProducer(tractor.track(track));
    Mlt::Playlist trackPlaylist(( mlt_playlist ) trackProducer.get_service());
    char *tmp = decodedString(resource);
    Mlt::Producer clip(*m_mltProfile, "westley-xml", tmp);
    //clip.set_in_and_out(in.frames(m_fps), out.frames(m_fps));
    delete[] tmp;

    trackPlaylist.insert_at(position.frames(m_fps), clip, 1);
    tractor.multitrack()->refresh();
    tractor.refresh();
    if (track != 0) mltCheckLength();
    double duration = Mlt::Producer(trackPlaylist.get_producer()).get_playtime();
    kdDebug()<<"// +  +INSERTING CLIP: "<<resource<<" AT: "<<position.frames(m_fps)<<" on track: "<<track<<", DURATION: "<<duration<<endl;


}

void KRender::mltCutClip(int track, GenTime position)
{
    Mlt::Service service(m_mltProducer->parent().get_service());
    if (service.type() != tractor_type) kdWarning()<<"// TRACOR PROBLEM"<<endl;

    Mlt::Tractor tractor(service);
    Mlt::Producer trackProducer(tractor.track(track));
    Mlt::Playlist trackPlaylist(( mlt_playlist ) trackProducer.get_service());
    trackPlaylist.split_at(position.frames(m_fps));
    trackPlaylist.consolidate_blanks(0);
    kdWarning()<<"/ / / /CUTTING CLIP ON TRACK "<<track<<" AT: "<<position.frames(m_fps)<<endl;
}


void KRender::mltRemoveClip(int track, GenTime position)
{
    Mlt::Service service(m_mltProducer->parent().get_service());
    if (service.type() != tractor_type) kdWarning()<<"// TRACOR PROBLEM"<<endl;

    Mlt::Tractor tractor(service);
    Mlt::Producer trackProducer(tractor.track(track));
    Mlt::Playlist trackPlaylist(( mlt_playlist ) trackProducer.get_service());
    int clipIndex = trackPlaylist.get_clip_index_at(position.frames(m_fps));
    //trackPlaylist.remove(clipIndex);
    trackPlaylist.replace_with_blank(clipIndex);
    trackPlaylist.consolidate_blanks(0);
    if (track != 0) mltCheckLength();
    //emit durationChanged();
}

void KRender::mltRemoveEffect(int track, GenTime position, QString id, QString tag, int index)
{
    Mlt::Service service(m_mltProducer->parent().get_service());

    Mlt::Tractor tractor(service);
    Mlt::Producer trackProducer(tractor.track(track));
    Mlt::Playlist trackPlaylist(( mlt_playlist ) trackProducer.get_service());
    //int clipIndex = trackPlaylist.get_clip_index_at(position.frames(m_fps));
    Mlt::Producer *clip = trackPlaylist.get_clip_at(position.frames(m_fps));
    if (!clip) {
	kdDebug()<<" / / / CANNOT FIND CLIP TO REMOVE EFFECT"<<endl;
	return;
    }
    Mlt::Service clipService(clip->get_service());

    if (tag.startsWith("ladspa")) tag = "ladspa";

    if (index == -1) {
	int ct = 0;
	Mlt::Filter *filter = clipService.filter( ct );
	while (filter) {
	    if (filter->get("mlt_service") == tag && filter->get("kdenlive_id") == id) {
		clipService.detach(*filter);
		kdDebug()<<" / / / DLEETED EFFECT: "<<ct<<endl;
	    }
	    else ct++;
	    filter = clipService.filter( ct );
	}
    }
    else {
        Mlt::Filter *filter = clipService.filter( index );
        if (filter && filter->get("mlt_service") == tag && filter->get("kdenlive_id") == id) clipService.detach(*filter);
        else {
	    kdDebug()<<"WARINIG, FILTER "<<id<<" NOT FOUND!!!!!"<<endl;
        }
    }
    refresh();
}


void KRender::mltAddEffect(int track, GenTime position, QString id, QString tag, QMap <QString, QString> args)
{
    Mlt::Service service(m_mltProducer->parent().get_service());

    Mlt::Tractor tractor(service);
    Mlt::Producer trackProducer(tractor.track(track));
    Mlt::Playlist trackPlaylist(( mlt_playlist ) trackProducer.get_service());

    Mlt::Producer *clip = trackPlaylist.get_clip_at(position.frames(m_fps));

    if (!clip) {
	kdDebug()<<"**********  CANNOT FIND CLIP TO APPLY EFFECT-----------"<<endl;
	return;
    }
    Mlt::Service clipService(clip->get_service());

    // create filter
    kdDebug()<<" / / INSERTING EFFECT: "<<id<<endl;
    if (tag.startsWith("ladspa")) tag = "ladspa";
    char *filterId = decodedString(id);
    Mlt::Filter *filter = new Mlt::Filter(*m_mltProfile, filterId);
    filter->set("kdenlive_id", id);

    QMap<QString, QString>::Iterator it;
    QString keyFrameNumber = "#0";

    for ( it = args.begin(); it != args.end(); ++it ) {
    kdDebug()<<" / / INSERTING EFFECT ARGS: "<<it.key()<<": "<<it.data()<<endl;
	QString key;
	QString currentKeyFrameNumber;
	if (it.key().startsWith("#")) {
	    currentKeyFrameNumber = it.key().section(":", 0, 0);
	    if (currentKeyFrameNumber != keyFrameNumber) {
    		// attach filter to the clip
		clipService.attach(*filter);
	        filter = new Mlt::Filter(*m_mltProfile, filterId);
		filter->set("kdenlive_id", id);
		keyFrameNumber = currentKeyFrameNumber;
	    }
	    key = it.key().section(":", 1);
	}
	else key = it.key();
        char *name = decodedString(key);
        char *value = decodedString(it.data());
        filter->set(name, value);
	delete[] name;
	delete[] value;
    }
    // attach filter to the clip
    clipService.attach(*filter);
    delete[] filterId;
    refresh();

}

void KRender::mltEditEffect(int track, GenTime position, int index, QString id, QString tag, QMap <QString, QString> args)
{
    QMap<QString, QString>::Iterator it = args.begin();
    if (it.key().startsWith("#") || tag.startsWith("ladspa") || tag == "sox" || tag == "autotrack_rectangle") {
	// This is a keyframe effect, to edit it, we remove it and re-add it.
	mltRemoveEffect(track, position, id, tag, -1);
	mltAddEffect(track, position, id, tag, args);
	return;
    }

    // create filter
    Mlt::Service service(m_mltProducer->parent().get_service());

    Mlt::Tractor tractor(service);
    Mlt::Producer trackProducer(tractor.track(track));
    Mlt::Playlist trackPlaylist(( mlt_playlist ) trackProducer.get_service());
    //int clipIndex = trackPlaylist.get_clip_index_at(position.frames(m_fps));
    Mlt::Producer *clip = trackPlaylist.get_clip_at(position.frames(m_fps));
    if (!clip) {
      kdDebug()<<"WARINIG, CANNOT FIND CLIP ON track: "<<track<<", AT POS: "<<position.frames(m_fps);
      return;
    }
    Mlt::Service clipService(clip->get_service());
    Mlt::Filter *filter = clipService.filter( index );


    if (!filter || filter->get("mlt_service") != tag) {
	kdDebug()<<"WARINIG, FILTER NOT FOUND!!!!!"<<endl;
	int index = 0;
	filter = clipService.filter( index );
	while (filter) {
	    if (filter->get("mlt_service") == tag && filter->get("kdenlive_id") == id) break;
	    index++;
	    filter = clipService.filter( index );
	}
    }
    if (!filter) {
	kdDebug()<<"WARINIG, FILTER "<<id<<" NOT FOUND!!!!!"<<endl;
	return;
    }

    for ( it = args.begin(); it != args.end(); ++it ) {
    kdDebug()<<" / / INSERTING EFFECT ARGS: "<<it.key()<<": "<<it.data()<<endl;
        char *name = decodedString(it.key());
        char *value = decodedString(it.data());
        filter->set(name, value);
	delete[] name;
	delete[] value;
    }
    refresh();
}

void KRender::mltResizeClipEnd(int track, GenTime pos, GenTime in, GenTime out)
{
    Mlt::Service service(m_mltProducer->parent().get_service());

    Mlt::Tractor tractor(service);
    Mlt::Producer trackProducer(tractor.track(track));
    Mlt::Playlist trackPlaylist(( mlt_playlist ) trackProducer.get_service());
    if (trackPlaylist.is_blank_at(pos.frames(m_fps) + 1)) 
	kdDebug()<<"////////  ERROR RSIZING BLANK CLIP!!!!!!!!!!!"<<endl;
    int clipIndex = trackPlaylist.get_clip_index_at(pos.frames(m_fps) + 1);

    int previousDuration = trackPlaylist.clip_length(clipIndex) - 1;
    int newDuration = out.frames(m_fps) - 1;

    kdDebug()<<" ** RESIZING CLIP END:" << clipIndex << " on track:"<< track <<", mid pos: "<<pos.frames(25)<<", in: "<<in.frames(25)<<", out: "<<out.frames(25)<<", PREVIOUS duration: "<<previousDuration<<endl;
    trackPlaylist.resize_clip(clipIndex, in.frames(m_fps), newDuration);
    trackPlaylist.consolidate_blanks(0);
    if (previousDuration < newDuration) {
	// clip was made longer, trim next blank if there is one.
	if (trackPlaylist.is_blank(clipIndex + 1)) {
	    trackPlaylist.split(clipIndex + 1, newDuration - previousDuration);
	    trackPlaylist.remove(clipIndex + 1);
	}
    }
    else trackPlaylist.insert_blank(clipIndex + 1, previousDuration - newDuration - 1);

    trackPlaylist.consolidate_blanks(0);
    tractor.multitrack()->refresh();
    tractor.refresh();
    if (track != 0) mltCheckLength();

}

void KRender::mltChangeTrackState(int track, bool mute, bool blind)
{
    Mlt::Service service(m_mltProducer->parent().get_service());

    Mlt::Tractor tractor(service);
    Mlt::Producer trackProducer(tractor.track(track));
    Mlt::Playlist trackPlaylist(( mlt_playlist ) trackProducer.get_service());
    if (mute) {
	if (blind) trackProducer.set("hide", 3);
	else trackProducer.set("hide", 2);
    }
    else if (blind) {
	trackProducer.set("hide", 1);
    }
    else {
	trackProducer.set("hide", 0);
    }
    tractor.multitrack()->refresh();
    tractor.refresh();
    refresh();
}

void KRender::mltResizeClipStart(int track, GenTime pos, GenTime moveEnd, GenTime moveStart, GenTime in, GenTime out)
{
    Mlt::Service service(m_mltProducer->parent().get_service());
    if (service.type() == playlist_type) kdDebug()<<"// PLAYLIST TYPE"<<endl;
    if (service.type() == tractor_type) kdDebug()<<"// TRACOT TYPE"<<endl;
    if (service.type() == multitrack_type) kdDebug()<<"// MULTITRACK TYPE"<<endl;
    if (service.type() == producer_type) kdDebug()<<"// PROD TYPE"<<endl;

    int moveFrame = (moveEnd - moveStart).frames(m_fps);

    Mlt::Tractor tractor(service);
    Mlt::Producer trackProducer(tractor.track(track));
    Mlt::Playlist trackPlaylist(( mlt_playlist ) trackProducer.get_service());
    if (trackPlaylist.is_blank_at(pos.frames(m_fps) - 1)) 
	kdDebug()<<"////////  ERROR RSIZING BLANK CLIP!!!!!!!!!!!"<<endl;
    int clipIndex = trackPlaylist.get_clip_index_at(pos.frames(m_fps) - 1);
    kdDebug()<<" ** RESIZING CLIP START:" << clipIndex << " on track:"<< track <<", mid pos: "<<pos.frames(25)<<", moving: "<<moveFrame<<", in: "<<in.frames(25)<<", out: "<<out.frames(25)<<endl;

    trackPlaylist.resize_clip(clipIndex, in.frames(m_fps), out.frames(m_fps));
    if (moveFrame > 0) trackPlaylist.insert_blank(clipIndex, moveFrame - 1);
    else {
	int midpos = moveStart.frames(m_fps) - 1; //+ (moveFrame / 2)
	int blankIndex = trackPlaylist.get_clip_index_at(midpos);
	int blankLength = trackPlaylist.clip_length(blankIndex);

	kdDebug()<<" + resizing blank: "<<blankIndex<<", Mid: "<<midpos<<", Length: "<<blankLength<< ", SIZE DIFF: "<<moveFrame<<endl;

	
	if (blankLength + moveFrame == 0) trackPlaylist.remove(blankIndex);
	else trackPlaylist.resize_clip(blankIndex, 0, blankLength + moveFrame -1);
    }
    trackPlaylist.consolidate_blanks(0);

    kdDebug()<<"-----------------\n"<<"CLIP 0: "<<trackPlaylist.clip_start(0)<<", LENGT: "<<trackPlaylist.clip_length(0)<<endl;
    kdDebug()<<"CLIP 1: "<<trackPlaylist.clip_start(1)<<", LENGT: "<<trackPlaylist.clip_length(1)<<endl;
    kdDebug()<<"CLIP 2: "<<trackPlaylist.clip_start(2)<<", LENGT: "<<trackPlaylist.clip_length(2)<<endl;
    kdDebug()<<"CLIP 3: "<<trackPlaylist.clip_start(3)<<", LENGT: "<<trackPlaylist.clip_length(3)<<endl;
   kdDebug()<<"CLIP 4: "<<trackPlaylist.clip_start(4)<<", LENGT: "<<trackPlaylist.clip_length(4)<<endl;
}

void KRender::mltMoveClip(int startTrack, int endTrack, GenTime moveStart, GenTime moveEnd)
{
    mltMoveClip(startTrack, endTrack, (int) moveStart.frames(m_fps), (int) moveEnd.frames(m_fps));
}


void KRender::mltMoveClip(int startTrack, int endTrack, int moveStart, int moveEnd)
{
    m_mltConsumer->set("refresh", 0);
    Mlt::Service service(m_mltProducer->parent().get_service());

    Mlt::Tractor tractor(service);
    Mlt::Producer trackProducer(tractor.track(startTrack));
    Mlt::Playlist trackPlaylist(( mlt_playlist ) trackProducer.get_service());
    int clipIndex = trackPlaylist.get_clip_index_at(moveStart + 1);


    mlt_field field = mlt_tractor_field(tractor.get_tractor());

    mlt_multitrack multitrack = mlt_field_multitrack(field); //mlt_tractor_multitrack(tractor.get_tractor());
    kdDebug()<<" --  CURRENT MULTIOTRACK HAS: "<<mlt_multitrack_count(multitrack)<<" tracks"<<endl;;
    mlt_service multiprod = mlt_multitrack_service( multitrack );

    Mlt::Producer clipProducer(trackPlaylist.replace_with_blank(clipIndex));
    trackPlaylist.consolidate_blanks(0);
    mlt_events_block( MLT_PRODUCER_PROPERTIES(clipProducer.get_producer()), NULL );

    if (endTrack == startTrack) {
	if (!trackPlaylist.is_blank_at(moveEnd)) {
	    kdWarning()<<"// ERROR, CLIP COLLISION----------"<<endl;
	    int ix = trackPlaylist.get_clip_index_at(moveEnd);
		kdDebug()<<"BAD CLIP STARTS AT: "<<trackPlaylist.clip_start(ix)<<", LENGT: "<<trackPlaylist.clip_length(ix)<<endl;
	}
	trackPlaylist.insert_at(moveEnd, clipProducer, 1);
	trackPlaylist.consolidate_blanks(0);
    }
    else {
    	trackPlaylist.consolidate_blanks(0);
	Mlt::Producer destTrackProducer(tractor.track(endTrack));
	Mlt::Playlist destTrackPlaylist(( mlt_playlist ) destTrackProducer.get_service());
	destTrackPlaylist.consolidate_blanks(1);
	destTrackPlaylist.insert_at(moveEnd, clipProducer, 1);
	destTrackPlaylist.consolidate_blanks(0);
    }

    mltCheckLength();
    mlt_events_unblock( MLT_PRODUCER_PROPERTIES(clipProducer.get_producer()), NULL );
}

void KRender::mltMoveTransition(QString type, int startTrack, int trackOffset, GenTime oldIn, GenTime oldOut, GenTime newIn, GenTime newOut)
{
    m_mltConsumer->set("refresh", 0);
    mlt_service serv = m_mltProducer->parent().get_service();

    mlt_service nextservice = mlt_service_get_producer(serv);
    mlt_properties properties = MLT_SERVICE_PROPERTIES( nextservice );
    QString mlt_type = mlt_properties_get( properties, "mlt_type" );
    QString resource = mlt_properties_get( properties, "mlt_service");
    int old_pos = (oldIn.frames(m_fps) + oldOut.frames(m_fps)) / 2;

    int new_in = newIn.frames(m_fps);
    int new_out = newOut.frames(m_fps) - 1;
    while (mlt_type == "transition") {
	mlt_transition tr = (mlt_transition) nextservice;
	int currentTrack = mlt_transition_get_b_track(tr);
	int currentIn = (int) mlt_transition_get_in(tr);
        int currentOut = (int) mlt_transition_get_out(tr);
	kdDebug()<<"// FOUND EXISTING TRANS, IN: "<<currentIn<<", OUT: "<<currentOut<<", TRACK: "<<currentTrack<<endl;
	//kdDebug()<<"// LOOKING FOR IN: "<<old_in<<", OUT: "<<old_out<<endl;
	kdDebug()<<"// OLD IN: "<<oldIn.frames(m_fps)<<" // OLD OUT: "<<oldOut.frames(m_fps)<<", TRACK: "<<startTrack<<", MID POS: "<<old_pos<<endl;
	if (resource == type && startTrack == currentTrack && currentIn <= old_pos && currentOut >= old_pos) {
            mlt_transition_set_in_and_out(tr, new_in, new_out);
            if (trackOffset != 0) {
		mlt_properties properties = MLT_TRANSITION_PROPERTIES( tr );
		mlt_properties_set_int( properties, "a_track", mlt_transition_get_a_track(tr) + trackOffset );
		mlt_properties_set_int( properties, "b_track", mlt_transition_get_b_track(tr) + trackOffset );
            }
            break;
        }
	nextservice = mlt_service_producer(nextservice);
	properties = MLT_SERVICE_PROPERTIES( nextservice );
	mlt_type = mlt_properties_get( properties, "mlt_type" );
	resource = mlt_properties_get( properties, "mlt_service" );
    }
}

void KRender::mltAddTransition(QString tag, int a_track, int b_track, GenTime in, GenTime out, QMap <QString, QString> args)
{
    Mlt::Service service(m_mltProducer->parent().get_service());

    Mlt::Tractor tractor(service);
    Mlt::Field *field = tractor.field();

    char *transId = decodedString(tag);
    Mlt::Transition *transition = new Mlt::Transition(*m_mltProfile, transId);
    transition->set_in_and_out((int) in.frames(m_fps), (int) out.frames(m_fps));
    QMap<QString, QString>::Iterator it;
    QString key;

    kdDebug()<<" ------  ADDING TRANSITION PARAMs: "<<args.count()<<endl;

    for ( it = args.begin(); it != args.end(); ++it ) {
	key = it.key();
        char *name = decodedString(key);
        char *value = decodedString(it.data());
        transition->set(name, value);
	kdDebug()<<" ------  ADDING TRANS PARAM: "<<name<<": "<<value<<endl;
	//filter->set("kdenlive_id", id);
	delete[] name;
	delete[] value;
    }
    // attach filter to the clip
    field->plant_transition(*transition, a_track, b_track);
    delete[] transId;
    refresh();

}

void KRender::mltSavePlaylist()
{
    kdWarning()<<"// UPDATING PLAYLIST TO DISK++++++++++++++++"<<endl;
    Mlt::Consumer *fileConsumer = new Mlt::Consumer(*m_mltProfile, "westley");
    fileConsumer->set("resource", "/home/one/playlist.xml");

    Mlt::Service service(m_mltProducer->get_service());
    Mlt::Tractor tractor(service);

    fileConsumer->connect(service);
    fileConsumer->start();

}

