X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fdocclipbase.cpp;h=a299a57d2f27af47e2835224aca60329cafc5d84;hb=548782dfe8b4ec1edc0c15f0062f5a976f1c6ee3;hp=05085a36b8a4f923ebbf3223e3efce873aacdaf9;hpb=08a49ce40071207043020d0d8f3c804703ee7af8;p=kdenlive diff --git a/src/docclipbase.cpp b/src/docclipbase.cpp index 05085a36..a299a57d 100644 --- a/src/docclipbase.cpp +++ b/src/docclipbase.cpp @@ -28,11 +28,14 @@ #include "kdenlivesettings.h" #include "kthumb.h" #include "clipmanager.h" +#include "slideshowclip.h" #include +#include #include #include +#include #include @@ -50,7 +53,8 @@ DocClipBase::DocClipBase(ClipManager *clipManager, QDomElement xml, const QStrin m_audioThumbCreated(false), m_id(id), m_placeHolder(xml.hasAttribute("placeholder")), - m_properties() + m_properties(), + m_abortProxy(false) { int type = xml.attribute("type").toInt(); m_clipType = (CLIPTYPE) type; @@ -58,8 +62,9 @@ DocClipBase::DocClipBase(ClipManager *clipManager, QDomElement xml, const QStrin QDomNamedNodeMap attributes = xml.attributes(); for (int i = 0; i < attributes.count(); i++) { QString name = attributes.item(i).nodeName(); - if (name.startsWith("meta.attr.")) m_metadata.insert(name.section('.', 2, 3), attributes.item(i).nodeValue()); - else m_properties.insert(name, attributes.item(i).nodeValue()); + if (name.startsWith("meta.attr.")) { + m_metadata.insert(name.section('.', 2, 3), attributes.item(i).nodeValue()); + } else m_properties.insert(name, attributes.item(i).nodeValue()); } if (xml.hasAttribute("cutzones")) { @@ -501,6 +506,17 @@ void DocClipBase::setProducer(Mlt::Producer *producer, bool reset) //m_clipProducer->set("transparency", m_properties.value("transparency").toInt()); } +static double getPixelAspect(QMap& props) { + int width = props.value("frame_size").section('x', 0, 0).toInt(); + int height = props.value("frame_size").section('x', 1, 1).toInt(); + int aspectNumerator = props.value("force_aspect_num").toInt(); + int aspectDenominator = props.value("force_aspect_den").toInt(); + if (aspectDenominator != 0 && width != 0) + return double(height) * aspectNumerator / aspectDenominator / width; + else + return 1.0; +} + Mlt::Producer *DocClipBase::audioProducer(int track) { if (m_audioTrackProducers.count() <= track) { @@ -511,15 +527,17 @@ Mlt::Producer *DocClipBase::audioProducer(int track) if (m_audioTrackProducers.at(track) == NULL) { Mlt::Producer *base = producer(); m_audioTrackProducers[track] = new Mlt::Producer(*(base->profile()), base->get("resource")); - if (m_properties.contains("force_aspect_ratio")) m_audioTrackProducers.at(track)->set("force_aspect_ratio", m_properties.value("force_aspect_ratio").toDouble()); + if (m_properties.contains("force_aspect_num") && m_properties.contains("force_aspect_den") && m_properties.contains("frame_size")) + m_audioTrackProducers.at(track)->set("force_aspect_ratio", getPixelAspect(m_properties)); if (m_properties.contains("force_fps")) m_audioTrackProducers.at(track)->set("force_fps", m_properties.value("force_fps").toDouble()); if (m_properties.contains("force_progressive")) m_audioTrackProducers.at(track)->set("force_progressive", m_properties.value("force_progressive").toInt()); + if (m_properties.contains("force_tff")) m_audioTrackProducers.at(track)->set("force_tff", m_properties.value("force_tff").toInt()); if (m_properties.contains("threads")) m_audioTrackProducers.at(track)->set("threads", m_properties.value("threads").toInt()); m_audioTrackProducers.at(track)->set("video_index", -1); if (m_properties.contains("audio_index")) m_audioTrackProducers.at(track)->set("audio_index", m_properties.value("audio_index").toInt()); - char *tmp = (char *) qstrdup(QString(getId() + '_' + QString::number(track) + "_audio").toUtf8().data()); - m_audioTrackProducers.at(track)->set("id", tmp); - delete[] tmp; + m_audioTrackProducers.at(track)->set("id", QString(getId() + '_' + QString::number(track) + "_audio").toUtf8().data()); + if (m_properties.contains("force_colorspace")) m_audioTrackProducers.at(track)->set("force_colorspace", m_properties.value("force_colorspace").toInt()); + if (m_properties.contains("full_luma")) m_audioTrackProducers.at(track)->set("set.force_full_luma", m_properties.value("full_luma").toInt()); } return m_audioTrackProducers.at(track); } @@ -532,15 +550,17 @@ Mlt::Producer *DocClipBase::videoProducer() if (m_baseTrackProducers.at(i) != NULL) break; if (i >= m_baseTrackProducers.count()) return NULL; m_videoOnlyProducer = new Mlt::Producer(*m_baseTrackProducers.at(i)->profile(), m_baseTrackProducers.at(i)->get("resource")); - if (m_properties.contains("force_aspect_ratio")) m_videoOnlyProducer->set("force_aspect_ratio", m_properties.value("force_aspect_ratio").toDouble()); + if (m_properties.contains("force_aspect_num") && m_properties.contains("force_aspect_den") && m_properties.contains("frame_size")) + m_videoOnlyProducer->set("force_aspect_ratio", getPixelAspect(m_properties)); if (m_properties.contains("force_fps")) m_videoOnlyProducer->set("force_fps", m_properties.value("force_fps").toDouble()); if (m_properties.contains("force_progressive")) m_videoOnlyProducer->set("force_progressive", m_properties.value("force_progressive").toInt()); + if (m_properties.contains("force_tff")) m_videoOnlyProducer->set("force_tff", m_properties.value("force_tff").toInt()); if (m_properties.contains("threads")) m_videoOnlyProducer->set("threads", m_properties.value("threads").toInt()); m_videoOnlyProducer->set("audio_index", -1); if (m_properties.contains("video_index")) m_videoOnlyProducer->set("video_index", m_properties.value("video_index").toInt()); - char *tmp = (char *) qstrdup(QString(getId() + "_video").toUtf8().data()); - m_videoOnlyProducer->set("id", tmp); - delete[] tmp; + m_videoOnlyProducer->set("id", QString(getId() + "_video").toUtf8().data()); + if (m_properties.contains("force_colorspace")) m_videoOnlyProducer->set("force_colorspace", m_properties.value("force_colorspace").toInt()); + if (m_properties.contains("full_luma")) m_videoOnlyProducer->set("set.force_full_luma", m_properties.value("full_luma").toInt()); } return m_videoOnlyProducer; } @@ -576,20 +596,18 @@ Mlt::Producer *DocClipBase::producer(int track) m_baseTrackProducers[track] = NULL; return NULL; } - - if (m_properties.contains("force_aspect_ratio")) m_baseTrackProducers[track]->set("force_aspect_ratio", m_properties.value("force_aspect_ratio").toDouble()); + if (m_properties.contains("force_aspect_num") && m_properties.contains("force_aspect_den") && m_properties.contains("frame_size")) + m_baseTrackProducers[track]->set("force_aspect_ratio", getPixelAspect(m_properties)); if (m_properties.contains("force_fps")) m_baseTrackProducers[track]->set("force_fps", m_properties.value("force_fps").toDouble()); if (m_properties.contains("force_progressive")) m_baseTrackProducers[track]->set("force_progressive", m_properties.value("force_progressive").toInt()); + if (m_properties.contains("force_tff")) m_baseTrackProducers[track]->set("force_tff", m_properties.value("force_tff").toInt()); if (m_properties.contains("threads")) m_baseTrackProducers[track]->set("threads", m_properties.value("threads").toInt()); if (m_properties.contains("video_index")) m_baseTrackProducers[track]->set("video_index", m_properties.value("video_index").toInt()); if (m_properties.contains("audio_index")) m_baseTrackProducers[track]->set("audio_index", m_properties.value("audio_index").toInt()); - char *tmp = (char *) qstrdup(QString(getId() + '_' + QString::number(track)).toUtf8().data()); - m_baseTrackProducers[track]->set("id", tmp); - delete[] tmp; - if (KdenliveSettings::dropbframes() && m_baseTrackProducers.at(i)->get("skip_loop_filter") && strcmp(m_baseTrackProducers.at(i)->get("skip_loop_filter"), "all") == 0) { - m_baseTrackProducers[track]->set("skip_loop_filter", "all"); - m_baseTrackProducers[track]->set("skip_frame", "bidir"); - } + m_baseTrackProducers[track]->set("id", QString(getId() + '_' + QString::number(track)).toUtf8().data()); + + if (m_properties.contains("force_colorspace")) m_baseTrackProducers[track]->set("force_colorspace", m_properties.value("force_colorspace").toInt()); + if (m_properties.contains("full_luma")) m_baseTrackProducers[track]->set("set.force_full_luma", m_properties.value("full_luma").toInt()); } return m_baseTrackProducers.at(track); } @@ -640,16 +658,55 @@ const char *DocClipBase::producerProperty(const char *name) const void DocClipBase::slotRefreshProducer() { if (m_baseTrackProducers.count() == 0) return; - kDebug() << "//////////// REFRESH CLIP !!!!!!!!!!!!!!!!"; if (m_clipType == SLIDESHOW) { - /*char *tmp = (char *) qstrdup(getProperty("resource").toUtf8().data()); - Mlt::Producer producer(*(m_clipProducer->profile()), tmp); - delete[] tmp; + /*Mlt::Producer producer(*(m_clipProducer->profile()), getProperty("resource").toUtf8().data()); delete m_clipProducer; m_clipProducer = new Mlt::Producer(producer.get_producer()); if (!getProperty("out").isEmpty()) m_clipProducer->set_in_and_out(getProperty("in").toInt(), getProperty("out").toInt());*/ setProducerProperty("ttl", getProperty("ttl").toInt()); //m_clipProducer->set("id", getProperty("id")); + if (!getProperty("animation").isEmpty()) { + Mlt::Service clipService(m_baseTrackProducers.at(0)->get_service()); + int ct = 0; + Mlt::Filter *filter = clipService.filter(ct); + while (filter) { + if (strcmp(filter->get("mlt_service"), "affine") == 0) { + break; + } else if (strcmp(filter->get("mlt_service"), "boxblur") == 0) { + clipService.detach(*filter); + } else ct++; + filter = clipService.filter(ct); + } + + if (!filter || strcmp(filter->get("mlt_service"), "affine")) { + // filter does not exist, create it. + Mlt::Filter *filter = new Mlt::Filter(*(m_baseTrackProducers.at(0)->profile()), "affine"); + if (filter && filter->is_valid()) { + int cycle = getProperty("ttl").toInt(); + QString geometry = SlideshowClip::animationToGeometry(getProperty("animation"), cycle); + if (!geometry.isEmpty()) { + if (getProperty("animation").contains("low-pass")) { + Mlt::Filter *blur = new Mlt::Filter(*(m_baseTrackProducers.at(0)->profile()), "boxblur"); + if (blur && blur->is_valid()) + clipService.attach(*blur); + } + filter->set("transition.geometry", geometry.toUtf8().data()); + filter->set("transition.cycle", cycle); + clipService.attach(*filter); + } + } + } + } else { + Mlt::Service clipService(m_baseTrackProducers.at(0)->get_service()); + int ct = 0; + Mlt::Filter *filter = clipService.filter(0); + while (filter) { + if (strcmp(filter->get("mlt_service"), "affine") == 0 || strcmp(filter->get("mlt_service"), "boxblur") == 0) { + clipService.detach(*filter); + } else ct++; + filter = clipService.filter(ct); + } + } if (getProperty("fade") == "1") { // we want a fade filter effect kDebug() << "//////////// FADE WANTED"; @@ -665,12 +722,9 @@ void DocClipBase::slotRefreshProducer() } if (filter && strcmp(filter->get("mlt_service"), "luma") == 0) { - filter->set("period", getProperty("ttl").toInt() - 1); - filter->set("luma.out", getProperty("luma_duration").toInt()); - QString resource = getProperty("luma_file"); - char *tmp = (char *) qstrdup(resource.toUtf8().data()); - filter->set("luma.resource", tmp); - delete[] tmp; + filter->set("cycle", getProperty("ttl").toInt()); + filter->set("duration", getProperty("luma_duration").toInt()); + filter->set("luma.resource", getProperty("luma_file").toUtf8().data()); if (!getProperty("softness").isEmpty()) { int soft = getProperty("softness").toInt(); filter->set("luma.softness", (double) soft / 100.0); @@ -678,12 +732,9 @@ void DocClipBase::slotRefreshProducer() } else { // filter does not exist, create it... Mlt::Filter *filter = new Mlt::Filter(*(m_baseTrackProducers.at(0)->profile()), "luma"); - filter->set("period", getProperty("ttl").toInt() - 1); - filter->set("luma.out", getProperty("luma_duration").toInt()); - QString resource = getProperty("luma_file"); - char *tmp = (char *) qstrdup(resource.toUtf8().data()); - filter->set("luma.resource", tmp); - delete[] tmp; + filter->set("cycle", getProperty("ttl").toInt()); + filter->set("duration", getProperty("luma_duration").toInt()); + filter->set("luma.resource", getProperty("luma_file").toUtf8().data()); if (!getProperty("softness").isEmpty()) { int soft = getProperty("softness").toInt(); filter->set("luma.softness", (double) soft / 100.0); @@ -702,6 +753,36 @@ void DocClipBase::slotRefreshProducer() filter = clipService.filter(ct); } } + if (getProperty("crop") == "1") { + // we want a center crop filter effect + Mlt::Service clipService(m_baseTrackProducers.at(0)->get_service()); + int ct = 0; + Mlt::Filter *filter = clipService.filter(ct); + while (filter) { + if (strcmp(filter->get("mlt_service"), "crop") == 0) { + break; + } + ct++; + filter = clipService.filter(ct); + } + + if (!filter || strcmp(filter->get("mlt_service"), "crop")) { + // filter does not exist, create it... + Mlt::Filter *filter = new Mlt::Filter(*(m_baseTrackProducers.at(0)->profile()), "crop"); + filter->set("center", 1); + clipService.attach(*filter); + } + } else { + Mlt::Service clipService(m_baseTrackProducers.at(0)->get_service()); + int ct = 0; + Mlt::Filter *filter = clipService.filter(0); + while (filter) { + if (strcmp(filter->get("mlt_service"), "crop") == 0) { + clipService.detach(*filter); + } else ct++; + filter = clipService.filter(ct); + } + } } } @@ -712,7 +793,7 @@ void DocClipBase::setProperties(QMap properties) QMapIterator i(properties); bool refreshProducer = false; QStringList keys; - keys << "luma_duration" << "luma_file" << "fade" << "ttl" << "softness"; + keys << "luma_duration" << "luma_file" << "fade" << "ttl" << "softness" << "crop" << "animation"; while (i.hasNext()) { i.next(); setProperty(i.key(), i.value()); @@ -726,7 +807,11 @@ void DocClipBase::setMetadata(QMap properties) QMapIterator i(properties); while (i.hasNext()) { i.next(); - m_metadata.insert(i.key(), i.value()); + if (i.value().isEmpty() && m_metadata.contains(i.key())) { + m_metadata.remove(i.key()); + } else { + m_metadata.insert(i.key(), i.value()); + } } } @@ -824,24 +909,23 @@ void DocClipBase::setProperty(const QString &key, const QString &value) } else if (key == "out") setDuration(GenTime(value.toInt(), KdenliveSettings::project_fps())); //else if (key == "transparency") m_clipProducer->set("transparency", value.toInt()); else if (key == "colour") { - char *tmp = (char *) qstrdup(value.toUtf8().data()); - setProducerProperty("colour", tmp); - delete[] tmp; + setProducerProperty("colour", value.toUtf8().data()); } else if (key == "templatetext") { - char *tmp = (char *) qstrdup(value.toUtf8().data()); - setProducerProperty("templatetext", tmp); - delete[] tmp; + setProducerProperty("templatetext", value.toUtf8().data()); setProducerProperty("force_reload", 1); } else if (key == "xmldata") { - char *tmp = (char *) qstrdup(value.toUtf8().data()); - setProducerProperty("xmldata", tmp); - delete[] tmp; + setProducerProperty("xmldata", value.toUtf8().data()); setProducerProperty("force_reload", 1); - } else if (key == "force_aspect_ratio") { + } else if (key == "force_aspect_num") { + if (value.isEmpty()) { + m_properties.remove("force_aspect_num"); + resetProducerProperty("force_aspect_ratio"); + } else setProducerProperty("force_aspect_ratio", getPixelAspect(m_properties)); + } else if (key == "force_aspect_den") { if (value.isEmpty()) { - m_properties.remove("force_aspect_ratio"); + m_properties.remove("force_aspect_den"); resetProducerProperty("force_aspect_ratio"); - } else setProducerProperty("force_aspect_ratio", value.toDouble()); + } else setProducerProperty("force_aspect_ratio", getPixelAspect(m_properties)); } else if (key == "force_fps") { if (value.isEmpty()) { m_properties.remove("force_fps"); @@ -852,6 +936,11 @@ void DocClipBase::setProperty(const QString &key, const QString &value) m_properties.remove("force_progressive"); resetProducerProperty("force_progressive"); } else setProducerProperty("force_progressive", value.toInt()); + } else if (key == "force_tff") { + if (value.isEmpty()) { + m_properties.remove("force_tff"); + resetProducerProperty("force_tff"); + } else setProducerProperty("force_tff", value.toInt()); } else if (key == "threads") { if (value.isEmpty()) { m_properties.remove("threads"); @@ -867,6 +956,16 @@ void DocClipBase::setProperty(const QString &key, const QString &value) m_properties.remove("audio_index"); setProducerProperty("audio_index", m_properties.value("default_audio").toInt()); } else setProducerProperty("audio_index", value.toInt()); + } else if (key == "force_colorspace") { + if (value.isEmpty()) { + m_properties.remove("force_colorspace"); + resetProducerProperty("force_colorspace"); + } else setProducerProperty("force_colorspace", value.toInt()); + } else if (key == "full_luma") { + if (value.isEmpty()) { + m_properties.remove("full_luma"); + resetProducerProperty("set.force_full_luma"); + } else setProducerProperty("set.force_full_luma", value.toInt()); } } @@ -877,7 +976,7 @@ QMap DocClipBase::properties() const bool DocClipBase::slotGetAudioThumbs() { - if (m_thumbProd == NULL) return false; + if (m_thumbProd == NULL || isPlaceHolder()) return false; if (!KdenliveSettings::audiothumbnails() || m_audioTimer == NULL) { if (m_audioTimer != NULL) m_audioTimer->stop(); return false; @@ -982,3 +1081,64 @@ bool DocClipBase::hasAudioCodec(const QString &codec) const return prod->get(property) == codec; } +void DocClipBase::generateProxy(KUrl proxyFolder, QString params) +{ + if (m_proxyThread.isRunning()) return; + QStringList parameters; + parameters << "-i" << m_properties.value("resource"); + foreach(QString s, params.split(' ')) + parameters << s; + // Make sure we don't block when proxy file already exists + parameters << "-y"; + if (m_properties.value("file_hash").isEmpty()) getFileHash(m_properties.value("resource")); + QString proxydir=proxyFolder.path( KUrl::AddTrailingSlash) + "proxy/"; + KStandardDirs::makeDir(proxydir); + QString path = proxydir + m_properties.value("file_hash") + ".avi"; + setProperty("proxy", path.toUtf8().data()); + if (QFile::exists(path)) { + emit proxyReady(m_id, true); + return; + } + parameters << path; + m_proxyThread = QtConcurrent::run(this, &DocClipBase::slotGenerateProxy, parameters); +} + +void DocClipBase::slotGenerateProxy(QStringList parameters) +{ + QProcess myProcess; + myProcess.start("ffmpeg", parameters); + myProcess.waitForStarted(); + int result = -1; + while (myProcess.state() != QProcess::NotRunning) { + // building proxy file + if (m_abortProxy) { + QString path = getProperty("proxy"); + myProcess.close(); + myProcess.waitForFinished(); + QFile::remove(path); + m_abortProxy = false; + result = 1; + } + myProcess.waitForFinished(500); + } + myProcess.waitForFinished(); + if (result == -1) result = myProcess.exitStatus(); + if (result == 0) emit proxyReady(m_id, true); + else { + clearProperty("proxy"); + emit proxyReady(m_id, false); + } +} + +void DocClipBase::abortProxy() +{ + if (m_proxyThread.isRunning()) { + // Proxy is being created, abort + m_abortProxy = true; + } + else { + clearProperty("proxy"); + emit proxyReady(m_id, false); + } +} +