#include <KIO/NetAccess>
#include <KStandardDirs>
+#include <KApplication>
#include <KDebug>
#include <QCryptographicHash>
#include <QtConcurrentRun>
#include <cstdio>
+#include <kmessagebox.h>
DocClipBase::DocClipBase(ClipManager *clipManager, QDomElement xml, const QString &id) :
- QObject(),
- m_audioFrameCache(),
- m_refcount(0),
- m_baseTrackProducers(),
- m_audioTrackProducers(),
- m_videoOnlyProducer(NULL),
- m_snapMarkers(QList < CommentedTime >()),
- m_duration(),
- m_audioTimer(NULL),
- m_thumbProd(NULL),
- m_audioThumbCreated(false),
- m_id(id),
- m_placeHolder(xml.hasAttribute("placeholder")),
- m_properties()
+ QObject(),
+ lastSeekPosition(0),
+ audioFrameCache(),
+ m_refcount(0),
+ m_baseTrackProducers(),
+ m_videoTrackProducers(),
+ m_audioTrackProducers(),
+ m_snapMarkers(QList < CommentedTime >()),
+ m_duration(),
+ m_thumbProd(NULL),
+ m_audioThumbCreated(false),
+ m_id(id),
+ m_placeHolder(xml.hasAttribute("placeholder")),
+ m_properties()
{
int type = xml.attribute("type").toInt();
m_clipType = (CLIPTYPE) type;
if (m_placeHolder) xml.removeAttribute("placeholder");
QDomNamedNodeMap attributes = xml.attributes();
- for (int i = 0; i < attributes.count(); i++) {
+ 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());
+ m_metadata.insert(name.section('.', 2), QStringList() << attributes.item(i).nodeValue());
} else m_properties.insert(name, attributes.item(i).nodeValue());
}
-
+ QDomNodeList metas = xml.elementsByTagName("metaproperty");
+ for (int i = 0; i < metas.count(); ++i) {
+ QDomElement e = metas.item(i).toElement();
+ if (!e.isNull()) {
+ m_metadata.insert(e.attribute("name").section('.', 2), QStringList() << e.firstChild().nodeValue() << e.attribute("tool"));
+ }
+ }
if (xml.hasAttribute("cutzones")) {
- QStringList cuts = xml.attribute("cutzones").split(";", QString::SkipEmptyParts);
- for (int i = 0; i < cuts.count(); i++) {
+ QStringList cuts = xml.attribute("cutzones").split(';', QString::SkipEmptyParts);
+ for (int i = 0; i < cuts.count(); ++i) {
QString z = cuts.at(i);
addCutZone(z.section('-', 0, 0).toInt(), z.section('-', 1, 1).toInt(), z.section('-', 2, 2));
}
}
+ if (xml.hasAttribute("analysisdata")) {
+ QStringList adata = xml.attribute("analysisdata").split('#', QString::SkipEmptyParts);
+ for (int i = 0; i < adata.count(); ++i)
+ m_analysisdata.insert(adata.at(i).section('?', 0, 0), adata.at(i).section('?', 1, 1));
+ }
+
KUrl url = KUrl(xml.attribute("resource"));
if (!m_properties.contains("file_hash") && !url.isEmpty()) getFileHash(url.path());
} else {
int out = xml.attribute("out").toInt();
int in = xml.attribute("in").toInt();
- setDuration(GenTime(out - in, KdenliveSettings::project_fps()));
+ if (out > in) setDuration(GenTime(out - in + 1, KdenliveSettings::project_fps()));
}
if (!m_properties.contains("name")) m_properties.insert("name", url.fileName());
m_thumbProd = new KThumb(clipManager, url, m_id, m_properties.value("file_hash"));
- if (m_clipType == AV || m_clipType == AUDIO || m_clipType == PLAYLIST) slotCreateAudioTimer();
+
+ // Setup timer to trigger audio thumbs creation
+ m_audioTimer.setSingleShot(true);
+ m_audioTimer.setInterval(800);
+ connect(&m_audioTimer, SIGNAL(timeout()), m_thumbProd, SLOT(slotCreateAudioThumbs()));
+
}
DocClipBase::~DocClipBase()
{
+ m_audioTimer.stop();
delete m_thumbProd;
- if (m_audioTimer) {
- m_audioTimer->stop();
- delete m_audioTimer;
- }
+ m_thumbProd = NULL;
+ qDeleteAll(m_toDeleteProducers);
+ m_toDeleteProducers.clear();
qDeleteAll(m_baseTrackProducers);
m_baseTrackProducers.clear();
qDeleteAll(m_audioTrackProducers);
m_audioTrackProducers.clear();
- delete m_videoOnlyProducer;
- m_videoOnlyProducer = NULL;
+ qDeleteAll(m_videoTrackProducers);
+ m_videoTrackProducers.clear();
}
-void DocClipBase::setZone(QPoint zone)
+void DocClipBase::setZone(const QPoint &zone)
{
m_properties.insert("zone_in", QString::number(zone.x()));
m_properties.insert("zone_out", QString::number(zone.y()));
return zone;
}
-void DocClipBase::slotCreateAudioTimer()
-{
- connect(m_thumbProd, SIGNAL(audioThumbReady(const audioByteArray&)), this , SLOT(updateAudioThumbnail(const audioByteArray&)));
- m_audioTimer = new QTimer(this);
- connect(m_audioTimer, SIGNAL(timeout()), this, SLOT(slotGetAudioThumbs()));
-}
-void DocClipBase::askForAudioThumbs()
+bool DocClipBase::hasAudioThumb() const
{
- if (m_thumbProd && m_audioTimer) m_thumbProd->askForAudioThumbs(getId());
+ if (m_clipType == AUDIO || m_clipType == AV || m_clipType == PLAYLIST) return true;
+ return false;
}
void DocClipBase::slotClearAudioCache()
{
- if (m_thumbProd) m_thumbProd->stopAudioThumbs();
- if (m_audioTimer != NULL) m_audioTimer->stop();
- m_audioFrameCache.clear();
+ audioFrameCache.clear();
m_audioThumbCreated = false;
}
return m_id;
}
-void DocClipBase::setId(const QString &newId)
-{
- m_id = newId;
-}
-
const CLIPTYPE & DocClipBase::clipType() const
{
return m_clipType;
void DocClipBase::setClipType(CLIPTYPE type)
{
m_clipType = type;
-
m_properties.insert("type", QString::number((int) type));
- if (m_thumbProd && m_audioTimer == NULL && (m_clipType == AV || m_clipType == AUDIO || m_clipType == PLAYLIST))
- slotCreateAudioTimer();
}
KUrl DocClipBase::fileURL() const
return m_properties.value(prop);
}
-void DocClipBase::setDuration(GenTime dur)
+void DocClipBase::setDuration(const GenTime &dur)
{
m_duration = dur;
m_properties.insert("duration", QString::number((int) dur.frames(KdenliveSettings::project_fps())));
}
// virtual
-QDomElement DocClipBase::toXML() const
+QDomElement DocClipBase::toXML(bool hideTemporaryProperties) const
{
QDomDocument doc;
QDomElement clip = doc.createElement("producer");
QMapIterator<QString, QString> i(m_properties);
while (i.hasNext()) {
i.next();
+ if (hideTemporaryProperties && i.key().startsWith('_')) continue;
if (!i.value().isEmpty()) clip.setAttribute(i.key(), i.value());
}
+
+ QMapIterator<QString, QStringList> j(m_metadata);
+ // Metadata name can have special chars so we cannot pass it as simple attribute
+ while (j.hasNext()) {
+ j.next();
+ if (!j.value().isEmpty()) {
+ QDomElement property = doc.createElement("metaproperty");
+ property.setAttribute("name", "meta.attr." + j.key());
+ QStringList values = j.value();
+ QDomText value = doc.createTextNode(values.at(0));
+ if (values.count() > 1) property.setAttribute("tool", values.at(1));
+ property.appendChild(value);
+ clip.appendChild(property);
+ }
+ }
doc.appendChild(clip);
if (!m_cutZones.isEmpty()) {
QStringList cuts;
- for (int i = 0; i < m_cutZones.size(); i++) {
+ for (int i = 0; i < m_cutZones.size(); ++i) {
CutZoneInfo info = m_cutZones.at(i);
cuts << QString::number(info.zone.x()) + "-" + QString::number(info.zone.y()) + "-" + info.description;
}
clip.setAttribute("cutzones", cuts.join(";"));
}
+ QString adata;
+ if (!m_analysisdata.isEmpty()) {
+ QMapIterator<QString, QString> i(m_analysisdata);
+ while (i.hasNext()) {
+ i.next();
+ //WARNING: a ? and # separator is not a good idea
+ adata.append(i.key() + "?" + i.value() + "#");
+ }
+ }
+ clip.setAttribute("analysisdata", adata);
//kDebug() << "/// CLIP XML: " << doc.toString();
return doc.documentElement();
}
-
-void DocClipBase::setAudioThumbCreated(bool isDone)
+const QString DocClipBase::shortInfo() const
{
- m_audioThumbCreated = isDone;
-}
-
-void DocClipBase::setThumbnail(const QPixmap & pixmap)
-{
- m_thumbnail = pixmap;
+ QString info;
+ if (m_clipType == AV || m_clipType == VIDEO || m_clipType == IMAGE || m_clipType == PLAYLIST) {
+ info = m_properties.value("frame_size") + " ";
+ if (m_properties.contains("fps")) {
+ info.append(i18n("%1 fps", m_properties.value("fps").left(5)));
+ }
+ if (!info.simplified().isEmpty()) info.prepend(" - ");
+ }
+ else if (m_clipType == AUDIO) {
+ info = " - " + m_properties.value("frequency") + i18n("Hz");
+ }
+ QString tip = "<b>";
+ switch (m_clipType) {
+ case AUDIO:
+ tip.append(i18n("Audio clip") + "</b>" + info + "<br />" + fileURL().path());
+ break;
+ case VIDEO:
+ tip.append(i18n("Mute video clip") + "</b>" + info + "<br />" + fileURL().path());
+ break;
+ case AV:
+ tip.append(i18n("Video clip") + "</b>" + info + "<br />" + fileURL().path());
+ break;
+ case COLOR:
+ tip.append(i18n("Color clip"));
+ break;
+ case IMAGE:
+ tip.append(i18n("Image clip") + "</b>" + info + "<br />" + fileURL().path());
+ break;
+ case TEXT:
+ if (!fileURL().isEmpty() && getProperty("xmldata").isEmpty()) tip.append(i18n("Template text clip") + "</b><br />" + fileURL().path());
+ else tip.append(i18n("Text clip") + "</b><br />" + fileURL().path());
+ break;
+ case SLIDESHOW:
+ tip.append(i18n("Slideshow clip") + "</b><br />" + fileURL().directory());
+ break;
+ case VIRTUAL:
+ tip.append(i18n("Virtual clip"));
+ break;
+ case PLAYLIST:
+ tip.append(i18n("Playlist clip") + "</b>" + info + "<br />" + fileURL().path());
+ break;
+ default:
+ tip.append(i18n("Unknown clip"));
+ break;
+ }
+ return tip;
}
-const QPixmap & DocClipBase::thumbnail() const
+
+void DocClipBase::setAudioThumbCreated(bool isDone)
{
- return m_thumbnail;
+ m_audioThumbCreated = isDone;
}
void DocClipBase::updateAudioThumbnail(const audioByteArray& data)
{
//kDebug() << "CLIPBASE RECIEDVED AUDIO DATA*********************************************";
- m_audioFrameCache = data;
+ audioFrameCache = data;
m_audioThumbCreated = true;
emit gotAudioData();
}
QList < GenTime > DocClipBase::snapMarkers() const
{
QList < GenTime > markers;
-
for (int count = 0; count < m_snapMarkers.count(); ++count) {
markers.append(m_snapMarkers.at(count).time());
}
}
-void DocClipBase::addSnapMarker(const GenTime & time, QString comment)
+void DocClipBase::addSnapMarker(const CommentedTime &marker)
{
QList < CommentedTime >::Iterator it = m_snapMarkers.begin();
for (it = m_snapMarkers.begin(); it != m_snapMarkers.end(); ++it) {
- if ((*it).time() >= time)
+ if ((*it).time() >= marker.time())
break;
}
- if ((it != m_snapMarkers.end()) && ((*it).time() == time)) {
- (*it).setComment(comment);
+ if ((it != m_snapMarkers.end()) && ((*it).time() == marker.time())) {
+ (*it).setComment(marker.comment());
+ (*it).setMarkerType(marker.markerType());
//kError() << "trying to add Snap Marker that already exists, this will cause inconsistancies with undo/redo";
} else {
- CommentedTime t(time, comment);
- m_snapMarkers.insert(it, t);
+ m_snapMarkers.insert(it, marker);
}
-
}
-void DocClipBase::editSnapMarker(const GenTime & time, QString comment)
+void DocClipBase::editSnapMarker(const GenTime & time, const QString &comment)
{
QList < CommentedTime >::Iterator it;
for (it = m_snapMarkers.begin(); it != m_snapMarkers.end(); ++it) {
return duration();
}
-QString DocClipBase::markerComment(GenTime t)
+QString DocClipBase::markerComment(const GenTime &t) const
{
- QList < CommentedTime >::Iterator itt = m_snapMarkers.begin();
-
+ QList < CommentedTime >::ConstIterator itt = m_snapMarkers.begin();
while (itt != m_snapMarkers.end()) {
if ((*itt).time() == t)
return (*itt).comment();
return QString();
}
+CommentedTime DocClipBase::markerAt(const GenTime &t) const
+{
+ QList < CommentedTime >::ConstIterator itt = m_snapMarkers.begin();
+ while (itt != m_snapMarkers.end()) {
+ if ((*itt).time() == t)
+ return (*itt);
+ ++itt;
+ }
+ return CommentedTime();
+}
+
void DocClipBase::clearThumbProducer()
{
if (m_thumbProd) m_thumbProd->clearProducer();
}
+void DocClipBase::reloadThumbProducer()
+{
+ if (m_thumbProd && !m_thumbProd->hasProducer())
+ m_thumbProd->setProducer(getProducer());
+}
+
void DocClipBase::deleteProducers()
{
- m_thumbProd->clearProducer();
+ if (m_thumbProd) m_thumbProd->clearProducer();
- if (numReferences() > 0) {
+ if (numReferences() > 0 && (!m_baseTrackProducers.isEmpty() || !m_videoTrackProducers.isEmpty() || !m_audioTrackProducers.isEmpty())) {
// Clip is used in timeline, delay producers deletion
- if (m_videoOnlyProducer) m_toDeleteProducers.append(m_videoOnlyProducer);
- for (int i = 0; i < m_baseTrackProducers.count(); i++) {
+ for (int i = 0; i < m_baseTrackProducers.count(); ++i) {
m_toDeleteProducers.append(m_baseTrackProducers.at(i));
}
- for (int i = 0; i < m_audioTrackProducers.count(); i++) {
+ for (int i = 0; i < m_videoTrackProducers.count(); ++i) {
+ m_toDeleteProducers.append(m_videoTrackProducers.at(i));
+ }
+ for (int i = 0; i < m_audioTrackProducers.count(); ++i) {
m_toDeleteProducers.append(m_audioTrackProducers.at(i));
}
}
else {
- delete m_videoOnlyProducer;
qDeleteAll(m_baseTrackProducers);
+ qDeleteAll(m_videoTrackProducers);
qDeleteAll(m_audioTrackProducers);
m_replaceMutex.unlock();
}
- m_videoOnlyProducer = NULL;
m_baseTrackProducers.clear();
+ m_videoTrackProducers.clear();
m_audioTrackProducers.clear();
}
/*
int ct = 0;
kDebug()<<"----------------------------------------------------------------------------------";
- for (int i = 0; i < m_toDeleteProducers.count(); i++) {
+ for (int i = 0; i < m_toDeleteProducers.count(); ++i) {
if (m_toDeleteProducers.at(i) != NULL) {
Mlt::Properties props(m_toDeleteProducers.at(i)->get_properties());
if (props.ref_count() > 2) {
}
}*/
- qDeleteAll(m_toDeleteProducers);
- m_toDeleteProducers.clear();
- m_replaceMutex.unlock();
+ if (!isClean()) {
+ qDeleteAll(m_toDeleteProducers);
+ m_toDeleteProducers.clear();
+ m_replaceMutex.unlock();
+ }
}
bool DocClipBase::isClean() const
m_thumbProd->setProducer(producer);
}
else m_thumbProd->setProducer(producer);
+ getAudioThumbs();
}
bool updated = false;
if (id.contains('_')) {
else delete producer;
return;
} else if (id.endsWith("video")) {
- if (m_videoOnlyProducer == NULL) {
- m_videoOnlyProducer = producer;
+ int pos = 0;
+ // Keep compatibility with older projects where video only producers were not track specific
+ if (id.contains('_')) pos = id.section('_', 0, 0).toInt();
+ if (pos >= m_videoTrackProducers.count()) {
+ while (m_videoTrackProducers.count() - 1 < pos) {
+ m_videoTrackProducers.append(NULL);
+ }
+ }
+ if (m_videoTrackProducers.at(pos) == NULL) {
+ m_videoTrackProducers[pos] = producer;
updated = true;
}
else delete producer;
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;
+ return double(height) * aspectNumerator / aspectDenominator / width;
else
return 1.0;
}
}
if (m_audioTrackProducers.at(track) == NULL) {
int i;
- for (i = 0; i < m_audioTrackProducers.count(); i++)
+ for (i = 0; i < m_audioTrackProducers.count(); ++i)
if (m_audioTrackProducers.at(i) != NULL) break;
Mlt::Producer *base;
if (i >= m_audioTrackProducers.count()) {
void DocClipBase::adjustProducerProperties(Mlt::Producer *prod, const QString &id, bool mute, bool blind)
{
- if (m_properties.contains("force_aspect_num") && m_properties.contains("force_aspect_den") && m_properties.contains("frame_size"))
- prod->set("force_aspect_ratio", getPixelAspect(m_properties));
- if (m_properties.contains("force_fps")) prod->set("force_fps", m_properties.value("force_fps").toDouble());
- if (m_properties.contains("force_progressive")) prod->set("force_progressive", m_properties.value("force_progressive").toInt());
- if (m_properties.contains("force_tff")) prod->set("force_tff", m_properties.value("force_tff").toInt());
- if (m_properties.contains("threads")) prod->set("threads", m_properties.value("threads").toInt());
- if (mute) prod->set("audio_index", -1);
- else if (m_properties.contains("audio_index")) prod->set("audio_index", m_properties.value("audio_index").toInt());
- if (blind) prod->set("video_index", -1);
- else if (m_properties.contains("video_index")) prod->set("video_index", m_properties.value("video_index").toInt());
- prod->set("id", id.toUtf8().constData());
- if (m_properties.contains("force_colorspace")) prod->set("force_colorspace", m_properties.value("force_colorspace").toInt());
- if (m_properties.contains("full_luma")) prod->set("set.force_full_luma", m_properties.value("full_luma").toInt());
- if (m_properties.contains("proxy_out")) {
- // We have a proxy clip, make sure the proxy has same duration as original
- prod->set("length", m_properties.value("duration").toInt());
- prod->set("out", m_properties.value("proxy_out").toInt());
- }
+ if (m_properties.contains("force_aspect_num") && m_properties.contains("force_aspect_den") && m_properties.contains("frame_size"))
+ prod->set("force_aspect_ratio", getPixelAspect(m_properties));
+ if (m_properties.contains("force_fps")) prod->set("force_fps", m_properties.value("force_fps").toDouble());
+ if (m_properties.contains("force_progressive")) prod->set("force_progressive", m_properties.value("force_progressive").toInt());
+ if (m_properties.contains("force_tff")) prod->set("force_tff", m_properties.value("force_tff").toInt());
+ if (m_properties.contains("threads")) prod->set("threads", m_properties.value("threads").toInt());
+ if (mute) prod->set("audio_index", -1);
+ else if (m_properties.contains("audio_index")) prod->set("audio_index", m_properties.value("audio_index").toInt());
+ if (blind) prod->set("video_index", -1);
+ else if (m_properties.contains("video_index")) prod->set("video_index", m_properties.value("video_index").toInt());
+ prod->set("id", id.toUtf8().constData());
+ if (m_properties.contains("force_colorspace")) prod->set("force_colorspace", m_properties.value("force_colorspace").toInt());
+ if (m_properties.contains("full_luma")) prod->set("set.force_full_luma", m_properties.value("full_luma").toInt());
+ if (m_properties.contains("proxy_out")) {
+ // We have a proxy clip, make sure the proxy has same duration as original
+ prod->set("length", m_properties.value("duration").toInt());
+ prod->set("out", m_properties.value("proxy_out").toInt());
+ }
}
-Mlt::Producer *DocClipBase::videoProducer()
+Mlt::Producer *DocClipBase::videoProducer(int track)
{
QMutexLocker locker(&m_producerMutex);
- if (m_videoOnlyProducer == NULL) {
+ if (m_videoTrackProducers.count() <= track) {
+ while (m_videoTrackProducers.count() - 1 < track) {
+ m_videoTrackProducers.append(NULL);
+ }
+ }
+ if (m_videoTrackProducers.at(track) == NULL) {
int i;
- for (i = 0; i < m_baseTrackProducers.count(); i++)
- if (m_baseTrackProducers.at(i) != NULL) break;
- if (i >= m_baseTrackProducers.count()) return NULL;
- m_videoOnlyProducer = cloneProducer(m_baseTrackProducers.at(i));
- adjustProducerProperties(m_videoOnlyProducer, QString(getId() + "_video"), true, false);
+ for (i = 0; i < m_videoTrackProducers.count(); ++i)
+ if (m_videoTrackProducers.at(i) != NULL) break;
+ Mlt::Producer *base;
+ if (i >= m_videoTrackProducers.count()) {
+ // Could not find a valid producer for that clip
+ locker.unlock();
+ base = getProducer();
+ if (base == NULL) {
+ return NULL;
+ }
+ locker.relock();
+ }
+ else base = m_videoTrackProducers.at(i);
+ m_videoTrackProducers[track] = cloneProducer(base);
+ adjustProducerProperties(m_videoTrackProducers.at(track), QString(getId() + '_' + QString::number(track) + "_video"), true, false);
}
- return m_videoOnlyProducer;
+ return m_videoTrackProducers.at(track);
}
+Mlt::Producer *DocClipBase::getCloneProducer()
+{
+ Mlt::Producer *source = NULL;
+ Mlt::Producer *prod = NULL;
+ if (m_clipType != AUDIO && m_clipType != AV && m_clipType != PLAYLIST) {
+ source = getProducer();
+ if (!source) return NULL;
+ }
+ if (m_clipType == COLOR) {
+ prod = new Mlt::Producer(*(source->profile()), 0, QString("colour:" + QString(source->get("resource"))).toUtf8().constData());
+ } else if (m_clipType == TEXT) {
+ prod = new Mlt::Producer(*(source->profile()), 0, QString("kdenlivetitle:" + QString(source->get("resource"))).toUtf8().constData());
+ if (prod && prod->is_valid() && m_properties.contains("xmldata"))
+ prod->set("xmldata", m_properties.value("xmldata").toUtf8().constData());
+ }
+ if (!prod) {
+ if (!source) {
+ QMutexLocker locker(&m_producerMutex);
+ for (int i = 0; i < m_baseTrackProducers.count(); ++i) {
+ if (m_baseTrackProducers.at(i) != NULL) {
+ source = m_baseTrackProducers.at(i);
+ break;
+ }
+ }
+ if (!source) return NULL;
+ }
+ prod = cloneProducer(source);
+ }
+ if (prod) {
+ adjustProducerProperties(prod, getId() + "_", false, false);
+ if (!m_properties.contains("proxy_out")) {
+ // Adjust length in case...
+ if (m_properties.contains("duration")) prod->set("length", m_properties.value("duration").toInt());
+ if (m_properties.contains("out"))prod->set("out", m_properties.value("out").toInt());
+ }
+ if (m_clipType == AUDIO) {
+ prod->set("_audioclip", 1);
+ }
+ }
+ return prod;
+}
+
+
Mlt::Producer *DocClipBase::getProducer(int track)
{
QMutexLocker locker(&m_producerMutex);
if (m_baseTrackProducers.count() == 0) {
return NULL;
}
- for (int i = 0; i < m_baseTrackProducers.count(); i++) {
+ for (int i = 0; i < m_baseTrackProducers.count(); ++i) {
if (m_baseTrackProducers.at(i) != NULL) {
return m_baseTrackProducers.at(i);
}
}
if (m_baseTrackProducers.at(track) == NULL) {
int i;
- for (i = 0; i < m_baseTrackProducers.count(); i++)
+ for (i = 0; i < m_baseTrackProducers.count(); ++i)
if (m_baseTrackProducers.at(i) != NULL) break;
if (i >= m_baseTrackProducers.count()) {
- // Could not find a valid producer for that clip, check in
+ // Could not find a valid producer for that clip, check in
return NULL;
}
- m_baseTrackProducers[track] = cloneProducer(m_baseTrackProducers.at(i));
- adjustProducerProperties(m_baseTrackProducers.at(track), QString(getId() + '_' + QString::number(track)), false, false);
+ Mlt::Producer *prod = cloneProducer(m_baseTrackProducers.at(i));
+ adjustProducerProperties(prod, QString(getId() + '_' + QString::number(track)), false, false);
+ m_baseTrackProducers[track] = prod;
}
return m_baseTrackProducers.at(track);
}
{
Mlt::Producer *result = NULL;
QString url = QString::fromUtf8(source->get("resource"));
- if (KIO::NetAccess::exists(KUrl(url), KIO::NetAccess::SourceSide, 0)) {
+ if (url == "<playlist>" || url == "<tractor>" || url == "<producer>") {
+ // Xml producer sometimes loses the correct url
+ url = m_properties.value("resource");
+ }
+ if (m_clipType == SLIDESHOW || KIO::NetAccess::exists(KUrl(url), KIO::NetAccess::SourceSide, 0)) {
result = new Mlt::Producer(*(source->profile()), url.toUtf8().constData());
}
if (result == NULL || !result->is_valid()) {
void DocClipBase::setProducerProperty(const char *name, int data)
{
QMutexLocker locker(&m_producerMutex);
- for (int i = 0; i < m_baseTrackProducers.count(); i++) {
+ for (int i = 0; i < m_baseTrackProducers.count(); ++i) {
if (m_baseTrackProducers.at(i) != NULL)
m_baseTrackProducers[i]->set(name, data);
}
void DocClipBase::setProducerProperty(const char *name, double data)
{
QMutexLocker locker(&m_producerMutex);
- for (int i = 0; i < m_baseTrackProducers.count(); i++) {
+ for (int i = 0; i < m_baseTrackProducers.count(); ++i) {
if (m_baseTrackProducers.at(i) != NULL)
m_baseTrackProducers[i]->set(name, data);
}
void DocClipBase::setProducerProperty(const char *name, const char *data)
{
QMutexLocker locker(&m_producerMutex);
- for (int i = 0; i < m_baseTrackProducers.count(); i++) {
+ for (int i = 0; i < m_baseTrackProducers.count(); ++i) {
if (m_baseTrackProducers.at(i) != NULL)
m_baseTrackProducers[i]->set(name, data);
}
void DocClipBase::resetProducerProperty(const char *name)
{
QMutexLocker locker(&m_producerMutex);
- for (int i = 0; i < m_baseTrackProducers.count(); i++) {
+ for (int i = 0; i < m_baseTrackProducers.count(); ++i) {
if (m_baseTrackProducers.at(i) != NULL)
m_baseTrackProducers[i]->set(name, (const char*) NULL);
}
const char *DocClipBase::producerProperty(const char *name) const
{
- for (int i = 0; i < m_baseTrackProducers.count(); i++) {
+ for (int i = 0; i < m_baseTrackProducers.count(); ++i) {
if (m_baseTrackProducers.at(i) != NULL) {
return m_baseTrackProducers.at(i)->get(name);
}
if (refreshProducer) slotRefreshProducer();
}
-void DocClipBase::setMetadata(QMap <QString, QString> properties)
+void DocClipBase::setMetadata(const QMap <QString, QString> &properties, const QString &tool)
{
QMapIterator<QString, QString> i(properties);
while (i.hasNext()) {
if (i.value().isEmpty() && m_metadata.contains(i.key())) {
m_metadata.remove(i.key());
} else {
- m_metadata.insert(i.key(), i.value());
+ m_metadata.insert(i.key(), QStringList() << i.value() << tool);
}
}
}
-QMap <QString, QString> DocClipBase::metadata() const
+QMap <QString, QStringList> DocClipBase::metadata() const
{
return m_metadata;
}
if (key == "resource") {
getFileHash(value);
if (m_thumbProd) m_thumbProd->updateClipUrl(KUrl(value), m_properties.value("file_hash"));
- } else if (key == "out") setDuration(GenTime(value.toInt(), KdenliveSettings::project_fps()));
- //else if (key == "transparency") m_clipProducer->set("transparency", value.toInt());
+ //else if (key == "transparency") m_clipProducer->set("transparency", value.toInt());
+ } else if (key == "out") {
+ setDuration(GenTime(value.toInt() + 1, KdenliveSettings::project_fps()));
+ }
else if (key == "colour") {
setProducerProperty("colour", value.toUtf8().data());
} else if (key == "templatetext") {
return m_properties;
}
-bool DocClipBase::slotGetAudioThumbs()
+QMap <QString, QString> DocClipBase::currentProperties(const QMap <QString, QString> &props)
{
- if (m_thumbProd == NULL || isPlaceHolder()) return false;
- if (!KdenliveSettings::audiothumbnails() || m_audioTimer == NULL) {
- if (m_audioTimer != NULL) m_audioTimer->stop();
- return false;
+ QMap <QString, QString> currentProps;
+ QMap<QString, QString>::const_iterator i = props.constBegin();
+ while (i != props.constEnd()) {
+ currentProps.insert(i.key(), m_properties.value(i.key()));
+ ++i;
}
+ return currentProps;
+}
+
+bool DocClipBase::getAudioThumbs()
+{
+ if (m_thumbProd == NULL || isPlaceHolder() || !KdenliveSettings::audiothumbnails()) return false;
if (m_audioThumbCreated) {
- m_audioTimer->stop();
return false;
}
- m_audioTimer->start(1500);
- double lengthInFrames = duration().frames(KdenliveSettings::project_fps());
- m_thumbProd->getAudioThumbs(2, 0, lengthInFrames /*must be number of frames*/, 20);
+ m_audioTimer.start();
return true;
}
return m_placeHolder;
}
-void DocClipBase::addCutZone(int in, int out, QString desc)
+void DocClipBase::addCutZone(int in, int out, const QString &desc)
{
CutZoneInfo info;
info.zone = QPoint(in, out);
info.description = desc;
- for (int i = 0; i < m_cutZones.count(); i++)
+ for (int i = 0; i < m_cutZones.count(); ++i) {
if (m_cutZones.at(i).zone == info.zone) {
return;
}
+ }
m_cutZones.append(info);
}
-bool DocClipBase::hasCutZone(QPoint p) const
+bool DocClipBase::hasCutZone(const QPoint &p) const
{
- for (int i = 0; i < m_cutZones.count(); i++)
- if (m_cutZones.at(i).zone == p) return true;
+ for (int i = 0; i < m_cutZones.count(); ++i)
+ if (m_cutZones.at(i).zone == p)
+ return true;
return false;
}
void DocClipBase::removeCutZone(int in, int out)
{
QPoint p(in, out);
- for (int i = 0; i < m_cutZones.count(); i++) {
+ for (int i = 0; i < m_cutZones.count(); ++i) {
if (m_cutZones.at(i).zone == p) {
m_cutZones.removeAt(i);
- i--;
+ --i;
}
}
}
-void DocClipBase::updateCutZone(int oldin, int oldout, int in, int out, QString desc)
+void DocClipBase::updateCutZone(int oldin, int oldout, int in, int out, const QString &desc)
{
QPoint old(oldin, oldout);
for (int i = 0; i < m_cutZones.size(); ++i) {
{
Mlt::Producer *prod = NULL;
if (m_baseTrackProducers.count() == 0) return false;
- for (int i = 0; i < m_baseTrackProducers.count(); i++) {
+ for (int i = 0; i < m_baseTrackProducers.count(); ++i) {
if (m_baseTrackProducers.at(i) != NULL) {
prod = m_baseTrackProducers.at(i);
break;
{
Mlt::Producer *prod = NULL;
if (m_baseTrackProducers.count() == 0) return false;
- for (int i = 0; i < m_baseTrackProducers.count(); i++) {
+ for (int i = 0; i < m_baseTrackProducers.count(); ++i) {
if (m_baseTrackProducers.at(i) != NULL) {
prod = m_baseTrackProducers.at(i);
break;
}
-void DocClipBase::slotExtractImage(int frame, int frame2)
+void DocClipBase::slotExtractImage(const QList <int> &frames)
{
if (m_thumbProd == NULL) return;
- m_thumbProd->extractImage(frame, frame2);
+ m_thumbProd->extractImage(frames);
}
-QPixmap DocClipBase::extractImage(int frame, int width, int height)
+QImage DocClipBase::extractImage(int frame, int width, int height)
{
- if (m_thumbProd == NULL) return QPixmap(width, height);
+ if (m_thumbProd == NULL) return QImage();
QMutexLocker locker(&m_producerMutex);
- QPixmap p = m_thumbProd->extractImage(frame, width, height);
- return p;
+ return m_thumbProd->extractImage(frame, width, height);
+}
+
+void DocClipBase::setAnalysisData(const QString &name, const QString &data, int offset)
+{
+ if (data.isEmpty()) m_analysisdata.remove(name);
+ else {
+ if (m_analysisdata.contains(name)) {
+ if (KMessageBox::questionYesNo(kapp->activeWindow(), i18n("Clip already contains analysis data %1", name), QString(), KGuiItem(i18n("Merge")), KGuiItem(i18n("Add"))) == KMessageBox::Yes) {
+ // Merge data
+ Mlt::Profile *profile = m_baseTrackProducers.at(0)->profile();
+ Mlt::Geometry geometry(m_analysisdata.value(name).toUtf8().data(), m_properties.value("duration").toInt(), profile->width(), profile->height());
+ Mlt::Geometry newGeometry(data.toUtf8().data(), m_properties.value("duration").toInt(), profile->width(), profile->height());
+ Mlt::GeometryItem item;
+ int pos = 0;
+ while (!newGeometry.next_key(&item, pos)) {
+ pos = item.frame();
+ item.frame(pos + offset);
+ pos++;
+ geometry.insert(item);
+ }
+ m_analysisdata.insert(name, geometry.serialise());
+ }
+ else {
+ // Add data with another name
+ int i = 1;
+ QString newname = name + " " + QString::number(i);
+ while (m_analysisdata.contains(newname)) {
+ ++i;
+ newname = name + " " + QString::number(i);
+ }
+ m_analysisdata.insert(newname, geometryWithOffset(data, offset));
+ }
+ }
+ else m_analysisdata.insert(name, geometryWithOffset(data, offset));
+ }
+}
+
+const QString DocClipBase::geometryWithOffset(const QString &data, int offset)
+{
+ if (offset == 0) return data;
+ Mlt::Profile *profile = m_baseTrackProducers.at(0)->profile();
+ Mlt::Geometry geometry(data.toUtf8().data(), m_properties.value("duration").toInt(), profile->width(), profile->height());
+ Mlt::Geometry newgeometry(NULL, m_properties.value("duration").toInt(), profile->width(), profile->height());
+ Mlt::GeometryItem item;
+ int pos = 0;
+ while (!geometry.next_key(&item, pos)) {
+ pos = item.frame();
+ item.frame(pos + offset);
+ pos++;
+ newgeometry.insert(item);
+ }
+ return newgeometry.serialise();
+}
+
+QMap <QString, QString> DocClipBase::analysisData() const
+{
+ return m_analysisdata;
}
+#include "docclipbase.moc"