+ if (reset) {
+ QMutexLocker locker(&m_producerMutex);
+ m_replaceMutex.lock();
+ deleteProducers();
+ }
+ QString id = producer->get("id");
+ if (m_placeHolder || !producer->is_valid()) {
+ char *tmp = qstrdup(i18n("Missing clip").toUtf8().constData());
+ producer->set("markup", tmp);
+ producer->set("bgcolour", "0xff0000ff");
+ producer->set("pad", "10");
+ delete[] tmp;
+ }
+ else if (m_thumbProd && !m_thumbProd->hasProducer()) {
+ if (m_clipType != AUDIO) {
+ if (!id.endsWith("_audio"))
+ m_thumbProd->setProducer(producer);
+ }
+ else m_thumbProd->setProducer(producer);
+ getAudioThumbs();
+ }
+ bool updated = false;
+ if (id.contains('_')) {
+ // this is a subtrack producer, insert it at correct place
+ id = id.section('_', 1);
+ if (id.endsWith("audio")) {
+ int pos = id.section('_', 0, 0).toInt();
+ if (pos >= m_audioTrackProducers.count()) {
+ while (m_audioTrackProducers.count() - 1 < pos) {
+ m_audioTrackProducers.append(NULL);
+ }
+ }
+ if (m_audioTrackProducers.at(pos) == NULL) {
+ m_audioTrackProducers[pos] = producer;
+ updated = true;
+ }
+ else delete producer;
+ return;
+ } else if (id.endsWith("video")) {
+ 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;
+ return;
+ }
+ int pos = id.toInt();
+ if (pos >= m_baseTrackProducers.count()) {
+ while (m_baseTrackProducers.count() - 1 < pos) {
+ m_baseTrackProducers.append(NULL);
+ }
+ }
+ if (m_baseTrackProducers.at(pos) == NULL) {
+ m_baseTrackProducers[pos] = producer;
+ updated = true;
+ }
+ else delete producer;
+ } else {
+ if (m_baseTrackProducers.isEmpty()) {
+ m_baseTrackProducers.append(producer);
+ updated = true;
+ }
+ else if (m_baseTrackProducers.at(0) == NULL) {
+ m_baseTrackProducers[0] = producer;
+ updated = true;
+ }
+ else delete producer;
+ }
+ if (updated && readPropertiesFromProducer && (m_clipType != COLOR && m_clipType != IMAGE && m_clipType != TEXT))
+ setDuration(GenTime(producer->get_length(), KdenliveSettings::project_fps()));
+}
+
+static double getPixelAspect(QMap<QString, QString>& 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)
+{
+ QMutexLocker locker(&m_producerMutex);
+ if (m_audioTrackProducers.count() <= track) {
+ while (m_audioTrackProducers.count() - 1 < track) {
+ m_audioTrackProducers.append(NULL);
+ }
+ }
+ if (m_audioTrackProducers.at(track) == NULL) {
+ int i;
+ for (i = 0; i < m_audioTrackProducers.count(); ++i)
+ if (m_audioTrackProducers.at(i) != NULL) break;
+ Mlt::Producer *base;
+ if (i >= m_audioTrackProducers.count()) {
+ // Could not find a valid producer for that clip
+ locker.unlock();
+ base = getProducer();
+ if (base == NULL) {
+ return NULL;
+ }
+ locker.relock();
+ }
+ else base = m_audioTrackProducers.at(i);
+ m_audioTrackProducers[track] = cloneProducer(base);
+ adjustProducerProperties(m_audioTrackProducers.at(track), QString(getId() + '_' + QString::number(track) + "_audio"), false, true);
+ }
+ return m_audioTrackProducers.at(track);
+}
+
+
+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());
+ }
+
+}
+
+Mlt::Producer *DocClipBase::videoProducer(int track)
+{
+ QMutexLocker locker(&m_producerMutex);
+ 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_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_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 (track == -1 || (m_clipType != AUDIO && m_clipType != AV && m_clipType != PLAYLIST)) {
+ if (m_baseTrackProducers.count() == 0) {
+ return NULL;
+ }
+ for (int i = 0; i < m_baseTrackProducers.count(); ++i) {
+ if (m_baseTrackProducers.at(i) != NULL) {
+ return m_baseTrackProducers.at(i);
+ }
+ }
+ return NULL;
+ }
+ if (track >= m_baseTrackProducers.count()) {
+ while (m_baseTrackProducers.count() - 1 < track) {
+ m_baseTrackProducers.append(NULL);
+ }
+ }
+ if (m_baseTrackProducers.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()) {
+ // Could not find a valid producer for that clip, check in
+ return NULL;
+ }
+ 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 *DocClipBase::cloneProducer(Mlt::Producer *source)
+{
+ Mlt::Producer *result = NULL;
+ QString url = QString::fromUtf8(source->get("resource"));
+ 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()) {
+ // placeholder clip
+ QString txt = "+" + i18n("Missing clip") + ".txt";
+ char *tmp = qstrdup(txt.toUtf8().constData());
+ result = new Mlt::Producer(*source->profile(), tmp);
+ delete[] tmp;
+ if (result == NULL || !result->is_valid())
+ result = new Mlt::Producer(*(source->profile()), "colour:red");
+ else {
+ result->set("bgcolour", "0xff0000ff");
+ result->set("pad", "10");
+ }
+ return result;
+ }
+ /*Mlt::Properties src_props(source->get_properties());
+ Mlt::Properties props(result->get_properties());
+ props.inherit(src_props);*/
+ return result;
+}
+
+void DocClipBase::setProducerProperty(const char *name, int data)
+{
+ QMutexLocker locker(&m_producerMutex);
+ 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) {
+ 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) {
+ 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) {
+ if (m_baseTrackProducers.at(i) != NULL)
+ m_baseTrackProducers[i]->set(name, (const char*) NULL);
+ }