]> git.sesse.net Git - kdenlive/commitdiff
Workaround MLT not giving rgb images to fix thumbnails
authorJean-Baptiste Mardelle <jb@kdenlive.org>
Tue, 17 Jun 2008 21:04:00 +0000 (21:04 +0000)
committerJean-Baptiste Mardelle <jb@kdenlive.org>
Tue, 17 Jun 2008 21:04:00 +0000 (21:04 +0000)
svn path=/branches/KDE4/; revision=2251

src/kthumb.cpp
src/kthumb.h
src/renderer.cpp
src/renderer.h

index 0f16a1cce8bac3487683deb1b4fba929406e0c10..a1bd47adb282390286dee2a2d32568fae5e4cdf8 100644 (file)
@@ -121,10 +121,8 @@ void MyThread::run() {
     m_isWorking = false;
     if (stop_me) {
         f.remove();
-        QApplication::postEvent(m_parent, new ProgressEvent(-1, (QEvent::Type)10005));
-
     }
-    QApplication::postEvent(m_parent, new ProgressEvent(0, (QEvent::Type)10005));
+    QApplication::postEvent(m_parent, new ProgressEvent(-1, (QEvent::Type)10005));
 
 }
 
@@ -155,68 +153,44 @@ void KThumb::updateClipUrl(KUrl url) {
 //static
 QPixmap KThumb::getImage(KUrl url, int width, int height) {
     if (url.isEmpty()) return QPixmap();
-    /*QPixmap pix(width, height);
-    kDebug() << "+++++++++++  GET THMB IMG FOR: " << url;
-    char *tmp = Render::decodedString(url.path());
-    Mlt::Profile prof((char*) KdenliveSettings::current_profile().data());
-    Mlt::Producer m_producer(prof, tmp);
-    delete[] tmp;
-
-    if (m_producer.is_blank()) {
-        pix.fill(Qt::black);
-        return pix;
-    }
-    Mlt::Frame * m_frame;
-    mlt_image_format format = mlt_image_rgb24a;
-    Mlt::Filter m_convert(prof, "avcolour_space");
-    m_convert.set("forced", mlt_image_rgb24a);
-    m_producer.attach(m_convert);
-    //m_producer.seek(frame);
-    m_frame = m_producer.get_frame();
-    if (m_frame && m_frame->is_valid()) {
-        uint8_t *thumb = m_frame->get_image(format, width, height);
-        QImage image(thumb, width, height, QImage::Format_ARGB32);
-        if (!image.isNull()) {
-            pix = pix.fromImage(image);
-        } else pix.fill(Qt::black);
-    }
-    if (m_frame) delete m_frame;
-    return pix;*/
     return getImage(url, 0, width, height);
 }
 
 void KThumb::extractImage(int frame, int frame2) {
     if (m_url.isEmpty()) return;
-
-    char *tmp = Render::decodedString(m_url.path());
-    Mlt::Producer m_producer(*m_profile, tmp);
+    char *tmp = Render::decodedString("<westley><playlist><producer resource=\"" + m_url.path() + "\" /></playlist></westley>");
+    Mlt::Producer producer(*m_profile, "westley-xml", tmp);
     delete[] tmp;
+
     int twidth = (int)(KdenliveSettings::trackheight() * KdenliveSettings::project_display_ratio());
-    if (m_producer.is_blank()) {
+    if (producer.is_blank()) {
         QPixmap pix(twidth, KdenliveSettings::trackheight());
         pix.fill(Qt::black);
         emit thumbReady(frame, pix);
         return;
     }
     if (frame != -1) {
-        QPixmap pix = getFrame(&m_producer, frame, twidth, KdenliveSettings::trackheight());
+        QPixmap pix = getFrame(&producer, frame, twidth, KdenliveSettings::trackheight());
         emit thumbReady(frame, pix);
     }
     if (frame2 != -1) {
-        QPixmap pix = getFrame(&m_producer, frame2, twidth , KdenliveSettings::trackheight());
+        QPixmap pix = getFrame(&producer, frame2, twidth , KdenliveSettings::trackheight());
         emit thumbReady(frame2, pix);
     }
 
 }
 
+//static
 QPixmap KThumb::getImage(KUrl url, int frame, int width, int height) {
     Mlt::Profile profile((char*) KdenliveSettings::current_profile().data());
     QPixmap pix(width, height);
     if (url.isEmpty()) return pix;
-    char *tmp = Render::decodedString(url.path());
-    Mlt::Producer producer(profile, tmp);
+
+    char *tmp = Render::decodedString("<westley><playlist><producer resource=\"" + url.path() + "\" /></playlist></westley>");
+    Mlt::Producer producer(profile, "westley-xml", tmp);
     delete[] tmp;
 
+
     if (producer.is_blank()) {
 
         pix.fill(Qt::black);
@@ -225,15 +199,17 @@ QPixmap KThumb::getImage(KUrl url, int frame, int width, int height) {
     return getFrame(&producer, frame, width, height);
 }
 
+//static
 QPixmap KThumb::getImage(QDomElement xml, int frame, int width, int height) {
     Mlt::Profile profile((char*) KdenliveSettings::current_profile().data());
     QPixmap pix(width, height);
     QDomDocument doc;
     QDomElement westley = doc.createElement("westley");
+    QDomElement play = doc.createElement("playlist");
     doc.appendChild(westley);
-    westley.appendChild(doc.importNode(xml, true));
+    westley.appendChild(play);
+    play.appendChild(doc.importNode(xml, true));
     char *tmp = Render::decodedString(doc.toString());
-    kDebug() << " - - - UPDATING THMB, XML: " << doc.toString();
     Mlt::Producer producer(profile, "westley-xml", tmp);
     delete[] tmp;
 
@@ -244,26 +220,28 @@ QPixmap KThumb::getImage(QDomElement xml, int frame, int width, int height) {
     return getFrame(&producer, frame, width, height);
 }
 
-QPixmap KThumb::getFrame(Mlt::Producer* producer, int frame, int width, int height) {
-    Mlt::Profile profile((char*) KdenliveSettings::current_profile().data());
-    Mlt::Filter m_convert(profile, "avcolour_space");
-    m_convert.set("forced", mlt_image_rgb24a);
-    producer->attach(m_convert);
-    if (frame > -1)
-        producer->seek(frame);
-    Mlt::Frame * m_frame = producer->get_frame();
-    mlt_image_format format = mlt_image_rgb24a;
+//static
+QPixmap KThumb::getFrame(Mlt::Producer* producer, int framepos, int width, int height) {
+    if (framepos > 0)
+        producer->seek(framepos);
+    Mlt::Frame *frame = producer->get_frame();
+
+    mlt_image_format format = mlt_image_yuv422;
+    uint8_t* data;
+    int frame_width = 0;
+    int frame_height = 0;
+    mlt_frame_get_image(frame->get_frame(), &data, &format, &frame_width, &frame_height, 0);
     QPixmap pix(width, height);
-    if (m_frame && m_frame->is_valid()) {
-        uint8_t *thumb = m_frame->get_image(format, width, height);
-        QImage image(thumb, width, height, QImage::Format_ARGB32);
-        if (!image.isNull()) {
-            pix = pix.fromImage(image);
-        } else pix.fill(Qt::black);
-    }
-    if (m_frame) delete m_frame;
+    uint8_t *new_image = (uint8_t *)mlt_pool_alloc(frame_width * (frame_height + 1) * 4);
+    mlt_convert_yuv422_to_rgb24a((uint8_t *)data, new_image, frame_width * frame_height);
+    QImage image((uchar *)new_image, frame_width, frame_height, QImage::Format_ARGB32);
+
+    if (!image.isNull()) {
+        QImage scale = image.scaled(width, height, Qt::KeepAspectRatio, Qt::SmoothTransformation).rgbSwapped();
+        pix = pix.fromImage(scale);
+    } else pix.fill(Qt::black);
+    if (frame) delete frame;
     return pix;
-
 }
 /*
 void KThumb::getImage(KUrl url, int frame, int width, int height)
index 43fa366d410a2a536987c0a12eded92168e94790..1c4628c2c861c71d424af48e3cc878e3d2010c28 100644 (file)
@@ -86,7 +86,7 @@ public slots:
     void removeAudioThumb();
     void getAudioThumbs(int channel, double frame, double frameLength, int arrayWidth);
     static QPixmap getImage(KUrl url, int frame, int width, int height);
-    static QPixmap getFrame(Mlt::Producer* producer, int frame, int width, int height);
+    static QPixmap getFrame(Mlt::Producer* producer, int framepos, int width, int height);
 
 protected:
     virtual void customEvent(QEvent * event);
index d5806531b655737b92a418b03ce5cd5be4472daf..75750708c1a6c5cab06b568c6b6c82c0ba3528ce 100644 (file)
@@ -42,6 +42,7 @@ extern "C" {
 #include "renderer.h"
 #include "kdenlivesettings.h"
 #include "kthumb.h"
+#include "definitions.h"
 
 #include <mlt++/Mlt.h>
 
@@ -52,7 +53,7 @@ extern "C" {
 
 static void consumer_frame_show(mlt_consumer, Render * 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 (self->m_isBlocked) return;
     if (mlt_properties_get_double(MLT_FRAME_PROPERTIES(frame_ptr), "_speed") == 0.0) {
         self->emitConsumerStopped();
     } else {
@@ -223,8 +224,8 @@ QPixmap Render::extractFrame(int frame_position, int width, int height) {
         pix.fill(Qt::black);
         return pix;
     }
-    //Mlt::Producer *mlt_producer = m_mltProducer->cut(frame_position, frame_position + 1);
-    return KThumb::getFrame(m_mltProducer, frame_position, width, height);
+    //TODO: rewrite
+    return pix; //KThumb::getFrame(m_mltProducer, frame_position, width, height);
     /*Mlt::Filter m_convert(*m_mltProfile, "avcolour_space");
     m_convert.set("forced", mlt_image_rgb24a);
     mlt_producer->attach(m_convert);
@@ -378,8 +379,11 @@ bool Render::isValid(KUrl url) {
 }
 
 void Render::getFileProperties(const QDomElement &xml, int clipId) {
-    int height = 40;
+    int height = 50;
     int width = (int)(height  * m_mltProfile->dar());
+    QMap < QString, QString > filePropertyMap;
+    QMap < QString, QString > metadataPropertyMap;
+
     QDomDocument doc;
     QDomElement westley = doc.createElement("westley");
     QDomElement play = doc.createElement("playlist");
@@ -387,29 +391,24 @@ void Render::getFileProperties(const QDomElement &xml, int clipId) {
     westley.appendChild(play);
     play.appendChild(doc.importNode(xml, true));
     char *tmp = decodedString(doc.toString());
-
     Mlt::Producer producer(*m_mltProfile, "westley-xml", tmp);
     delete[] tmp;
 
     if (producer.is_blank()) {
         return;
     }
+
     int frameNumber = xml.attribute("frame_thumbnail", "0").toInt();
     if (frameNumber != 0) producer.seek(frameNumber);
     mlt_properties properties = MLT_PRODUCER_PROPERTIES(producer.get_producer());
 
-    QMap < QString, QString > filePropertyMap;
-    QMap < QString, QString > metadataPropertyMap;
-
     KUrl url = xml.attribute("resource", QString::null);
     filePropertyMap["filename"] = url.path();
     filePropertyMap["duration"] = QString::number(producer.get_playtime());
-    kDebug() << "///////  PRODUCER: " << url.path() << " IS: " << 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();
+    //kDebug() << "///////  PRODUCER: " << url.path() << " IS: " << producer.get_playtime();
 
+    Mlt::Frame * frame = producer.get_frame();
+    //frame->set("rescale", "nearest");
     //filePropertyMap["fps"] = QString::number(mlt_producer_get_fps(producer.get_producer()));
     filePropertyMap["fps"] = producer.get("source_fps");
 
@@ -428,18 +427,21 @@ void Render::getFileProperties(const QDomElement &xml, int clipId) {
             else
                 filePropertyMap["type"] = "video";
 
+            mlt_image_format format = mlt_image_yuv422;
+            uint8_t* data;
+            int frame_width = 0;
+            int frame_height = 0;
+            mlt_frame_get_image(frame->get_frame(), &data, &format, &frame_width, &frame_height, 0);
+
             QPixmap pix(width, height);
-                       //uchar *data = frame->fetch_image( mlt_image_rgb24, width, height, 1 );
-                       mlt_image_format format = mlt_image_rgb24a;
-            uint8_t* data = frame->get_image(format, width, height);
-            QImage image(data, width, height, QImage::Format_ARGB32);
+            uint8_t *new_image = (uint8_t *)mlt_pool_alloc(frame_width * (frame_height + 1) * 4);
+            mlt_convert_yuv422_to_rgb24a((uint8_t *)data, new_image, frame_width * frame_height);
+            QImage image((uchar *)new_image, frame_width, frame_height, QImage::Format_ARGB32);
 
             if (!image.isNull()) {
-                pix = pix.fromImage(image);
+                QImage scale = image.scaled(width, height, Qt::KeepAspectRatio, Qt::SmoothTransformation).rgbSwapped();
+                pix = pix.fromImage(scale);
             } else pix.fill(Qt::black);
-            QPixmap copy = pix;
-            copy.detach();
-            pix = copy;
 
             emit replyGetImage(clipId, 0, pix, width, height);
 
@@ -544,7 +546,7 @@ void Render::setSceneList(QString playlist, int position) {
     if (m_winid == -1) return;
     m_generateScenelist = true;
 
-    // kWarning() << "//////  RENDER, SET SCENE LIST: " << playlist;
+    kWarning() << "//////  RENDER, SET SCENE LIST: " << playlist;
 
 
     /*
@@ -597,12 +599,13 @@ void Render::setSceneList(QString playlist, int position) {
     }*/
 
     m_fps = m_mltProducer->get_fps();
+    kDebug() << "// NEW SCENE LIST DURATION SET TO: " << m_mltProducer->get_playtime();
     emit durationChanged(m_mltProducer->get_playtime());
     //m_connectTimer->start( 1000 );
     connectPlaylist();
     if (position != 0) {
         m_mltProducer->seek(position);
-        emit rendererPosition((int) position);
+        emit rendererPosition(position);
     }
     m_generateScenelist = false;
 
@@ -742,6 +745,7 @@ void Render::start() {
             return;
         } else {
             kDebug() << "-----  MONITOR: " << m_name << " REFRESH";
+            m_isBlocked = false;
             refresh();
         }
     }
@@ -794,9 +798,11 @@ void Render::switchPlay() {
         return;
     if (m_mltProducer->get_speed() == 0.0) m_mltProducer->set_speed(1.0);
     else {
+        m_isBlocked = true;
         m_mltProducer->set_speed(0.0);
-        kDebug() << "// POSITON: " << m_framePosition;
+        m_mltConsumer->set("refresh", 0);
         m_mltProducer->seek((int) m_framePosition);
+        m_isBlocked = false;
     }
 
     /*if (speed == 0.0) {
@@ -809,7 +815,7 @@ void Render::switchPlay() {
 void Render::play(double speed) {
     if (!m_mltProducer)
         return;
-    if (speed == 0.0) m_mltProducer->set("out", m_mltProducer->get_length() - 1);
+    // 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);
@@ -906,7 +912,6 @@ const QString & Render::rendererName() const {
 
 
 void Render::emitFrameNumber(double position) {
-    //kDebug()<<"// POSITON: "<<m_framePosition;
     if (m_generateScenelist) return;
     m_framePosition = position;
     emit rendererPosition((int) position);
@@ -938,7 +943,8 @@ void Render::exportCurrentFrame(KUrl url, bool notify) {
 
     int height = 1080;//KdenliveSettings::defaultheight();
     int width = 1940; //KdenliveSettings::displaywidth();
-    QPixmap pix = KThumb::getFrame(m_mltProducer, -1, width, height);
+    //TODO: rewrite
+    QPixmap pix; // = KThumb::getFrame(m_mltProducer, -1, width, height);
     /*
        QPixmap pix(width, height);
        Mlt::Filter m_convert(*m_mltProfile, "avcolour_space");
@@ -1008,7 +1014,7 @@ void Render::mltCheckLength(bool reload) {
             black.setAttribute("out", QString::number(dur));
             mltInsertClip(0, GenTime(i * 14000, m_fps), black);
         }
-        //m_mltProducer->set("out", duration);
+        m_mltProducer->set("out", duration);
         emit durationChanged((int)duration);
     }
 }
@@ -1121,7 +1127,6 @@ void Render::mltAddEffect(int track, GenTime position, QMap <QString, QString> a
     Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
 
     Mlt::Producer *clip = trackPlaylist.get_clip_at((int) position.frames(m_fps));
-
     if (!clip) {
         kDebug() << "**********  CANNOT FIND CLIP TO APPLY EFFECT-----------";
         return;
@@ -1130,45 +1135,70 @@ void Render::mltAddEffect(int track, GenTime position, QMap <QString, QString> a
     m_isBlocked = true;
     // create filter
     QString tag = args.value("tag");
-    //kDebug()<<" / / INSERTING EFFECT: "<<id;
+    kDebug() << " / / INSERTING EFFECT: " << tag;
     if (tag.startsWith("ladspa")) tag = "ladspa";
     char *filterTag = decodedString(tag);
     char *filterId = decodedString(args.value("id"));
-    Mlt::Filter *filter = new Mlt::Filter(*m_mltProfile, filterTag);
-    if (filter && filter->is_valid())
-        filter->set("kdenlive_id", filterId);
-    else {
-        kDebug() << "filter is NULL";
-        m_isBlocked = false;
-        return;
-    }
-
     QMap<QString, QString>::Iterator it;
-    QString keyFrameNumber = "#0";
-
-    for (it = args.begin(); it != args.end(); ++it) {
-        //kDebug()<<" / / INSERTING EFFECT ARGS: "<<it.key()<<": "<<it.data();
-        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, filterTag);
-                filter->set("kdenlive_id", filterId);
-                keyFrameNumber = currentKeyFrameNumber;
+    kDebug() << "KFR: " << args.value("keyframes");
+    QStringList keyFrames = args.value("keyframes").split(";");
+    if (!keyFrames.isEmpty()) {
+        kDebug() << "// ADDING KEYFRAME EFFECT: " << args.value("keyframes");
+        char *starttag = decodedString(args.value("starttag"));
+        char *endtag = decodedString(args.value("endtag", "end"));
+        int duration = clip->get_playtime();
+        int max = args.value("max").toInt();
+        int min = args.value("min").toInt();
+        int factor = args.value("factor").toInt();
+        args.remove("starttag");
+        args.remove("endtag");
+        args.remove("keyframes");
+        for (int i = 0; i < keyFrames.size() - 1; ++i) {
+            Mlt::Filter *filter = new Mlt::Filter(*m_mltProfile, filterTag);
+            filter->set("kdenlive_id", filterId);
+            int x1 = keyFrames.at(i).section(":", 0, 0).toInt();
+            int y1 = keyFrames.at(i).section(":", 1, 1).toInt();
+            int x2 = keyFrames.at(i + 1).section(":", 0, 0).toInt();
+            int y2 = keyFrames.at(i + 1).section(":", 1, 1).toInt();
+
+            for (it = args.begin(); it != args.end(); ++it) {
+                char *name = decodedString(it.key());
+                char *value = decodedString(it.value());
+                filter->set(name, value);
+                delete[] name;
+                delete[] value;
             }
-            key = it.key().section(":", 1);
-        } else key = it.key();
-        char *name = decodedString(key);
-        char *value = decodedString(it.value());
-        filter->set(name, value);
-        delete[] name;
-        delete[] value;
+
+            filter->set("in", duration / 100 * x1);
+            filter->set("out", duration / 100 * x2);
+            filter->set(starttag, (min + y1 * 100 / (max - min)) / factor);
+            filter->set(endtag, (min + y2 * 100 / (max - min)) / factor);
+            kDebug() << "// SETTING FILT VALS: " << duration / 100 * x1 << " to " << duration / 100 * x2 << ", STAT:" << (min + y1 * 100 / (max - min)) / factor << "end: " << (min + y2 * 100 / (max - min)) / factor;
+            clipService.attach(*filter);
+
+        }
+        delete[] starttag;
+        delete[] endtag;
+    } else {
+        Mlt::Filter *filter = new Mlt::Filter(*m_mltProfile, filterTag);
+        if (filter && filter->is_valid())
+            filter->set("kdenlive_id", filterId);
+        else {
+            kDebug() << "filter is NULL";
+            m_isBlocked = false;
+            return;
+        }
+
+        for (it = args.begin(); it != args.end(); ++it) {
+            char *name = decodedString(it.key());
+            char *value = decodedString(it.value());
+            filter->set(name, value);
+            delete[] name;
+            delete[] value;
+        }
+        // attach filter to the clip
+        clipService.attach(*filter);
     }
-    // attach filter to the clip
-    clipService.attach(*filter);
     delete[] filterId;
     delete[] filterTag;
     m_isBlocked = false;
@@ -1179,7 +1209,7 @@ void Render::mltEditEffect(int track, GenTime position, QMap <QString, QString>
     QString index = args.value("kdenlive_ix");
     QString tag =  args.value("tag");
     QMap<QString, QString>::Iterator it = args.begin();
-    if (it.key().startsWith("#") || tag.startsWith("ladspa") || tag == "sox" || tag == "autotrack_rectangle") {
+    if (!args.value("keyframes").isEmpty() || /*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, index);
         mltAddEffect(track, position, args);
@@ -1408,7 +1438,7 @@ void Render::mltMoveClip(int startTrack, int endTrack, int moveStart, int moveEn
     m_isBlocked = true;
 
     m_mltConsumer->set("refresh", 0);
-       mlt_service_lock(m_mltConsumer->get_service());
+    mlt_service_lock(m_mltConsumer->get_service());
     Mlt::Service service(m_mltProducer->parent().get_service());
     if (service.type() != tractor_type) kWarning() << "// TRACTOR PROBLEM";
 
@@ -1440,7 +1470,7 @@ void Render::mltMoveClip(int startTrack, int endTrack, int moveStart, int moveEn
         destTrackPlaylist.consolidate_blanks(0);
     }
     mltCheckLength();
-       mlt_service_unlock(m_mltConsumer->get_service());
+    mlt_service_unlock(m_mltConsumer->get_service());
     m_isBlocked = false;
     m_mltConsumer->set("refresh", 1);
 }
index 1bdcba40c0352459fa358b334849dbe6089b3a43..8696fc6589e08e6d88b83a2aa7f4f8f44e7e086d 100644 (file)
@@ -69,6 +69,7 @@ Q_OBJECT public:
     /** Seeks the renderer clip to the given time. */
     void seek(GenTime time);
     void seekToFrame(int pos);
+    bool m_isBlocked;
 
     //static QPixmap getVideoThumbnail(char *profile, QString file, int frame, int width, int height);
     QPixmap getImageThumbnail(KUrl url, int width, int height);
@@ -178,7 +179,6 @@ private:   // Private attributes & methods
     double m_fps;
     uint m_monitorId;
     bool m_generateScenelist;
-    bool m_isBlocked;
 
     /** Holds the path to on screen display profile */
     QString m_osdProfile;