mirror of
https://invent.kde.org/multimedia/kdenlive
synced 2025-12-05 15:59:59 +01:00
When copy/paste between 2 kdenlive windows, correctly load bin clip effects
This commit is contained in:
@@ -386,6 +386,28 @@ QDomElement EffectStackModel::rowToXml(int row, QDomDocument &document)
|
|||||||
return container;
|
return container;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool EffectStackModel::fromMltXml(const QDomElement &effectsXml)
|
||||||
|
{
|
||||||
|
QDomNodeList nodeList = effectsXml.elementsByTagName(QStringLiteral("filter"));
|
||||||
|
for (int i = 0; i < nodeList.count(); ++i) {
|
||||||
|
QDomElement node = nodeList.item(i).toElement();
|
||||||
|
if (!Xml::hasXmlProperty(node, QStringLiteral("kdenlive_id")) || Xml::hasXmlProperty(node, QStringLiteral("internal_added"))) {
|
||||||
|
// Internal effect, ignore
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (Xml::hasXmlProperty(node, QStringLiteral("kdenlive:builtin")) && Xml::getXmlProperty(node, QStringLiteral("disable")) == QLatin1String("1")) {
|
||||||
|
// Disabled built-in effect, ignore
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const QString effectId = Xml::getXmlProperty(node, QStringLiteral("kdenlive_id"));
|
||||||
|
Fun undo = []() { return true; };
|
||||||
|
Fun redo = []() { return true; };
|
||||||
|
stringMap params = Xml::getXmlPropertyByWildcard(node, QString());
|
||||||
|
doAppendEffect(effectId, false, params, undo, redo);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool EffectStackModel::fromXml(const QDomElement &effectsXml, Fun &undo, Fun &redo)
|
bool EffectStackModel::fromXml(const QDomElement &effectsXml, Fun &undo, Fun &redo)
|
||||||
{
|
{
|
||||||
QDomNodeList nodeList = effectsXml.elementsByTagName(QStringLiteral("effect"));
|
QDomNodeList nodeList = effectsXml.elementsByTagName(QStringLiteral("effect"));
|
||||||
|
|||||||
@@ -137,6 +137,8 @@ public:
|
|||||||
QDomElement rowToXml(int row, QDomDocument &document);
|
QDomElement rowToXml(int row, QDomDocument &document);
|
||||||
/** @brief Load an effect stack from an XML representation */
|
/** @brief Load an effect stack from an XML representation */
|
||||||
bool fromXml(const QDomElement &effectsXml, Fun &undo, Fun &redo);
|
bool fromXml(const QDomElement &effectsXml, Fun &undo, Fun &redo);
|
||||||
|
/** @brief Load an effect stack from an MLT XML representation */
|
||||||
|
bool fromMltXml(const QDomElement &effectsXml);
|
||||||
/** @brief Delete active effect from stack */
|
/** @brief Delete active effect from stack */
|
||||||
void removeCurrentEffect();
|
void removeCurrentEffect();
|
||||||
|
|
||||||
|
|||||||
@@ -69,6 +69,9 @@ ClipController::ClipController(const QString &clipId, const std::shared_ptr<Mlt:
|
|||||||
} else {
|
} else {
|
||||||
m_controlUuid = QUuid::createUuid();
|
m_controlUuid = QUuid::createUuid();
|
||||||
}
|
}
|
||||||
|
if (description.elementsByTagName(QStringLiteral("filter")).count() > 0) {
|
||||||
|
m_effectsToLoad = description;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,56 +126,61 @@ void ClipController::addMasterProducer(const std::shared_ptr<Mlt::Producer> &pro
|
|||||||
if (!m_masterProducer->is_valid()) {
|
if (!m_masterProducer->is_valid()) {
|
||||||
m_masterProducer = std::shared_ptr<Mlt::Producer>(pCore->mediaUnavailable->cut());
|
m_masterProducer = std::shared_ptr<Mlt::Producer>(pCore->mediaUnavailable->cut());
|
||||||
qCDebug(KDENLIVE_LOG) << "// WARNING, USING INVALID PRODUCER";
|
qCDebug(KDENLIVE_LOG) << "// WARNING, USING INVALID PRODUCER";
|
||||||
} else {
|
connectEffectStack();
|
||||||
setProducerProperty(QStringLiteral("kdenlive:id"), m_controllerBinId);
|
return;
|
||||||
if (!m_properties->property_exists("kdenlive:control_uuid")) {
|
}
|
||||||
m_properties->set("kdenlive:control_uuid", m_controlUuid.toString().toUtf8().constData());
|
setProducerProperty(QStringLiteral("kdenlive:id"), m_controllerBinId);
|
||||||
}
|
if (!m_properties->property_exists("kdenlive:control_uuid")) {
|
||||||
getInfoForProducer();
|
m_properties->set("kdenlive:control_uuid", m_controlUuid.toString().toUtf8().constData());
|
||||||
checkAudioVideo();
|
}
|
||||||
if (!m_hasMultipleVideoStreams && m_service.startsWith(QLatin1String("avformat")) && (m_clipType == ClipType::AV || m_clipType == ClipType::Video)) {
|
getInfoForProducer();
|
||||||
// Check if clip has multiple video streams
|
checkAudioVideo();
|
||||||
QList<int> videoStreams;
|
if (!m_effectsToLoad.isNull()) {
|
||||||
QList<int> audioStreams;
|
m_effectStack->fromMltXml(m_effectsToLoad);
|
||||||
int aStreams = m_properties->get_int("meta.media.nb_streams");
|
m_effectsToLoad.clear();
|
||||||
for (int ix = 0; ix < aStreams; ++ix) {
|
}
|
||||||
char property[200];
|
if (!m_hasMultipleVideoStreams && m_service.startsWith(QLatin1String("avformat")) && (m_clipType == ClipType::AV || m_clipType == ClipType::Video)) {
|
||||||
snprintf(property, sizeof(property), "meta.media.%d.stream.type", ix);
|
// Check if clip has multiple video streams
|
||||||
QString type = m_properties->get(property);
|
QList<int> videoStreams;
|
||||||
if (type == QLatin1String("video")) {
|
QList<int> audioStreams;
|
||||||
QString key = QStringLiteral("meta.media.%1.codec.name").arg(ix);
|
int aStreams = m_properties->get_int("meta.media.nb_streams");
|
||||||
QString codec_name = m_properties->get(key.toLatin1().constData());
|
for (int ix = 0; ix < aStreams; ++ix) {
|
||||||
if (codec_name == QLatin1String("png")) {
|
char property[200];
|
||||||
|
snprintf(property, sizeof(property), "meta.media.%d.stream.type", ix);
|
||||||
|
QString type = m_properties->get(property);
|
||||||
|
if (type == QLatin1String("video")) {
|
||||||
|
QString key = QStringLiteral("meta.media.%1.codec.name").arg(ix);
|
||||||
|
QString codec_name = m_properties->get(key.toLatin1().constData());
|
||||||
|
if (codec_name == QLatin1String("png")) {
|
||||||
|
// This is a cover image, skip
|
||||||
|
qDebug() << "=== FOUND PNG COVER ART STREAM: " << ix;
|
||||||
|
setProducerProperty(QStringLiteral("kdenlive:coverartstream"), ix);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (codec_name == QLatin1String("mjpeg")) {
|
||||||
|
key = QStringLiteral("meta.media.%1.stream.frame_rate").arg(ix);
|
||||||
|
QString fps = m_properties->get(key.toLatin1().constData());
|
||||||
|
if (fps.isEmpty()) {
|
||||||
|
key = QStringLiteral("meta.media.%1.codec.frame_rate").arg(ix);
|
||||||
|
fps = m_properties->get(key.toLatin1().constData());
|
||||||
|
}
|
||||||
|
if (fps == QLatin1String("90000")) {
|
||||||
// This is a cover image, skip
|
// This is a cover image, skip
|
||||||
qDebug() << "=== FOUND PNG COVER ART STREAM: " << ix;
|
qDebug() << "=== FOUND MJPEG COVER ART STREAM: " << ix;
|
||||||
setProducerProperty(QStringLiteral("kdenlive:coverartstream"), ix);
|
setProducerProperty(QStringLiteral("kdenlive:coverartstream"), ix);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (codec_name == QLatin1String("mjpeg")) {
|
|
||||||
key = QStringLiteral("meta.media.%1.stream.frame_rate").arg(ix);
|
|
||||||
QString fps = m_properties->get(key.toLatin1().constData());
|
|
||||||
if (fps.isEmpty()) {
|
|
||||||
key = QStringLiteral("meta.media.%1.codec.frame_rate").arg(ix);
|
|
||||||
fps = m_properties->get(key.toLatin1().constData());
|
|
||||||
}
|
|
||||||
if (fps == QLatin1String("90000")) {
|
|
||||||
// This is a cover image, skip
|
|
||||||
qDebug() << "=== FOUND MJPEG COVER ART STREAM: " << ix;
|
|
||||||
setProducerProperty(QStringLiteral("kdenlive:coverartstream"), ix);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
videoStreams << ix;
|
|
||||||
} else if (type == QLatin1String("audio")) {
|
|
||||||
audioStreams << ix;
|
|
||||||
}
|
}
|
||||||
|
videoStreams << ix;
|
||||||
|
} else if (type == QLatin1String("audio")) {
|
||||||
|
audioStreams << ix;
|
||||||
}
|
}
|
||||||
if (videoStreams.count() > 1) {
|
}
|
||||||
setProducerProperty(QStringLiteral("kdenlive:multistreams"), 1);
|
if (videoStreams.count() > 1) {
|
||||||
m_hasMultipleVideoStreams = true;
|
setProducerProperty(QStringLiteral("kdenlive:multistreams"), 1);
|
||||||
QMetaObject::invokeMethod(pCore->bin(), "processMultiStream", Qt::QueuedConnection, Q_ARG(QString, m_controllerBinId),
|
m_hasMultipleVideoStreams = true;
|
||||||
Q_ARG(QList<int>, videoStreams), Q_ARG(QList<int>, audioStreams));
|
QMetaObject::invokeMethod(pCore->bin(), "processMultiStream", Qt::QueuedConnection, Q_ARG(QString, m_controllerBinId),
|
||||||
}
|
Q_ARG(QList<int>, videoStreams), Q_ARG(QList<int>, audioStreams));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
connectEffectStack();
|
connectEffectStack();
|
||||||
|
|||||||
@@ -251,6 +251,7 @@ private:
|
|||||||
/** @brief Temporarily store clip properties until producer is available */
|
/** @brief Temporarily store clip properties until producer is available */
|
||||||
QMap <QString, QVariant> m_tempProps;
|
QMap <QString, QVariant> m_tempProps;
|
||||||
QString m_controllerBinId;
|
QString m_controllerBinId;
|
||||||
|
QDomElement m_effectsToLoad;
|
||||||
/** @brief Build the audio info object */
|
/** @brief Build the audio info object */
|
||||||
void buildAudioInfo(int audioIndex);
|
void buildAudioInfo(int audioIndex);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -218,7 +218,7 @@ QMap<QString, QString> Xml::getXmlPropertyByWildcard(const QDomElement &element,
|
|||||||
QDomNodeList params = element.elementsByTagName(QStringLiteral("property"));
|
QDomNodeList params = element.elementsByTagName(QStringLiteral("property"));
|
||||||
for (int i = 0; i < params.count(); ++i) {
|
for (int i = 0; i < params.count(); ++i) {
|
||||||
QDomElement e = params.item(i).toElement();
|
QDomElement e = params.item(i).toElement();
|
||||||
if (e.attribute(QStringLiteral("name")).startsWith(propertyName)) {
|
if (propertyName.isEmpty() || e.attribute(QStringLiteral("name")).startsWith(propertyName)) {
|
||||||
props.insert(e.attribute(QStringLiteral("name")), e.text());
|
props.insert(e.attribute(QStringLiteral("name")), e.text());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user