bool EffectManager::editEffect(EffectsParameterList params, int duration, bool replaceEffect) { int index = params.paramValue(QStringLiteral("kdenlive_ix")).toInt(); QString tag = params.paramValue(QStringLiteral("tag")); if (!params.paramValue(QStringLiteral("keyframes")).isEmpty() || replaceEffect || tag.startsWith(QLatin1String("ladspa")) || tag == QLatin1String("sox") || tag == QLatin1String("autotrack_rectangle")) { // This is a keyframe effect, to edit it, we remove it and re-add it. if (removeEffect(index, false)) { return addEffect(params, duration); } } // find filter int ct = 0; Mlt::Filter *filter = m_producer.filter(ct); while (filter) { if (filter->get_int("kdenlive_ix") == index) { break; } delete filter; ct++; filter = m_producer.filter(ct); } if (!filter) { qDebug() << "WARINIG, FILTER FOR EDITING NOT FOUND, ADDING IT! " << index << ", " << tag; // filter was not found, it was probably a disabled filter, so add it to the correct place... bool success = addEffect(params, duration); return success; } ct = 0; QString ser = filter->get("mlt_service"); QList <Mlt::Filter *> filtersList; m_producer.lock(); if (ser != tag) { // Effect service changes, delete effect and re-add it m_producer.detach(*filter); delete filter; // Delete all effects after deleted one filter = m_producer.filter(ct); while (filter) { if (filter->get_int("kdenlive_ix") > index) { filtersList.append(filter); m_producer.detach(*filter); } else ct++; delete filter; filter = m_producer.filter(ct); } // re-add filter doAddFilter(params, duration); m_producer.unlock(); return true; } if (params.hasParam(QStringLiteral("kdenlive:sync_in_out"))) { if (params.paramValue(QStringLiteral("kdenlive:sync_in_out")) == QLatin1String("1")) { // This effect must sync in / out with parent clip //params.removeParam(QStringLiteral("sync_in_out")); Mlt::Producer prod(m_producer); filter->set_in_and_out(prod.get_in(), prod.get_out()); } else { // Reset in/out properties filter->set("in", (char*)NULL); filter->set("out", (char*)NULL); } } for (int j = 0; j < params.count(); ++j) { filter->set(params.at(j).name().toUtf8().constData(), params.at(j).value().toUtf8().constData()); } for (int j = 0; j < filtersList.count(); ++j) { m_producer.attach(*(filtersList.at(j))); } qDeleteAll(filtersList); m_producer.unlock(); delete filter; return true; }
bool EffectManager::doAddFilter(EffectsParameterList params, int duration) { // create filter QString tag = params.paramValue(QStringLiteral("tag")); QLocale locale; ////qDebug() << " / / INSERTING EFFECT: " << tag << ", REGI: " << region; QString kfr = params.paramValue(QStringLiteral("keyframes")); if (!kfr.isEmpty()) { QStringList keyFrames = kfr.split(';', QString::SkipEmptyParts); char *starttag = qstrdup(params.paramValue(QStringLiteral("starttag"), QStringLiteral("start")).toUtf8().constData()); char *endtag = qstrdup(params.paramValue(QStringLiteral("endtag"), QStringLiteral("end")).toUtf8().constData()); ////qDebug() << "// ADDING KEYFRAME TAGS: " << starttag << ", " << endtag; //double max = params.paramValue("max").toDouble(); double min = params.paramValue(QStringLiteral("min")).toDouble(); double factor = params.paramValue(QStringLiteral("factor"), QStringLiteral("1")).toDouble(); double paramOffset = params.paramValue(QStringLiteral("offset"), QStringLiteral("0")).toDouble(); params.removeParam(QStringLiteral("starttag")); params.removeParam(QStringLiteral("endtag")); params.removeParam(QStringLiteral("keyframes")); params.removeParam(QStringLiteral("min")); params.removeParam(QStringLiteral("max")); params.removeParam(QStringLiteral("factor")); params.removeParam(QStringLiteral("offset")); // Special case, only one keyframe, means we want a constant value if (keyFrames.count() == 1) { Mlt::Filter *filter = new Mlt::Filter(*m_producer.profile(), qstrdup(tag.toUtf8().constData())); if (filter && filter->is_valid()) { filter->set("kdenlive_id", qstrdup(params.paramValue(QStringLiteral("id")).toUtf8().constData())); int x1 = keyFrames.at(0).section('=', 0, 0).toInt(); double y1 = keyFrames.at(0).section('=', 1, 1).toDouble(); for (int j = 0; j < params.count(); ++j) { filter->set(params.at(j).name().toUtf8().constData(), params.at(j).value().toUtf8().constData()); } filter->set("in", x1); ////qDebug() << "// ADDING KEYFRAME vals: " << min<<" / "<<max<<", "<<y1<<", factor: "<<factor; filter->set(starttag, locale.toString(((min + y1) - paramOffset) / factor).toUtf8().data()); m_producer.attach(*filter); delete filter; } else { delete[] starttag; delete[] endtag; //qDebug() << "filter is NULL"; m_producer.unlock(); return false; } } else for (int i = 0; i < keyFrames.size() - 1; ++i) { Mlt::Filter *filter = new Mlt::Filter(*m_producer.profile(), qstrdup(tag.toUtf8().constData())); if (filter && filter->is_valid()) { filter->set("kdenlive_id", qstrdup(params.paramValue(QStringLiteral("id")).toUtf8().constData())); int x1 = keyFrames.at(i).section('=', 0, 0).toInt(); double y1 = keyFrames.at(i).section('=', 1, 1).toDouble(); int x2 = keyFrames.at(i + 1).section('=', 0, 0).toInt(); double y2 = keyFrames.at(i + 1).section('=', 1, 1).toDouble(); if (x2 == -1) x2 = duration; // non-overlapping sections if (i > 0) { y1 += (y2 - y1) / (x2 - x1); ++x1; } for (int j = 0; j < params.count(); ++j) { filter->set(params.at(j).name().toUtf8().constData(), params.at(j).value().toUtf8().constData()); } filter->set("in", x1); filter->set("out", x2); ////qDebug() << "// ADDING KEYFRAME vals: " << min<<" / "<<max<<", "<<y1<<", factor: "<<factor; filter->set(starttag, locale.toString(((min + y1) - paramOffset) / factor).toUtf8().data()); filter->set(endtag, locale.toString(((min + y2) - paramOffset) / factor).toUtf8().data()); m_producer.attach(*filter); delete filter; } else { delete[] starttag; delete[] endtag; //qDebug() << "filter is NULL"; m_producer.unlock(); return false; } } delete[] starttag; delete[] endtag; } else { Mlt::Filter *filter; QString prefix; filter = new Mlt::Filter(*m_producer.profile(), qstrdup(tag.toUtf8().constData())); if (filter && filter->is_valid()) { filter->set("kdenlive_id", qstrdup(params.paramValue(QStringLiteral("id")).toUtf8().constData())); } else { //qDebug() << "filter is NULL"; m_producer.unlock(); return false; } params.removeParam(QStringLiteral("kdenlive_id")); if (params.paramValue(QStringLiteral("kdenlive:sync_in_out")) == QLatin1String("1")) { // This effect must sync in / out with parent clip //params.removeParam(QStringLiteral("_sync_in_out")); filter->set_in_and_out(m_producer.get_int("in"), m_producer.get_int("out")); } for (int j = 0; j < params.count(); ++j) { filter->set((prefix + params.at(j).name()).toUtf8().constData(), params.at(j).value().toUtf8().constData()); } if (tag == QLatin1String("sox")) { QString effectArgs = params.paramValue(QStringLiteral("id")).section('_', 1); params.removeParam(QStringLiteral("id")); params.removeParam(QStringLiteral("kdenlive_ix")); params.removeParam(QStringLiteral("tag")); params.removeParam(QStringLiteral("disable")); params.removeParam(QStringLiteral("region")); for (int j = 0; j < params.count(); ++j) { effectArgs.append(' ' + params.at(j).value()); } ////qDebug() << "SOX EFFECTS: " << effectArgs.simplified(); filter->set("effect", effectArgs.simplified().toUtf8().constData()); } // attach filter to the clip m_producer.attach(*filter); delete filter; } return true; }