Commit 1ac25b2e authored by Nicolas Carion's avatar Nicolas Carion

Port parsing of custom XML effect files

parent 870a07b8
......@@ -12,99 +12,6 @@ frei0r.invert0r
frei0r.3dflippo
frei0r.perspective
# effects with XML UI
frei0r.alpha0ps
frei0r.alphagrad
frei0r.alphaspot
frei0r.balanc0r
frei0r.baltan
frei0r.bw0r
frei0r.brightness
frei0r.cartoon
frei0r.cluster
frei0r.c0rners
frei0r.coloradj_RGB
frei0r.colordistance
frei0r.colortap
frei0r.contrast0r
frei0r.curves
frei0r.defish0r
frei0r.delay0r
frei0r.delaygrab
frei0r.d90stairsteppingfix
frei0r.distort0r
frei0r.edgeglow
frei0r.equaliz0r
frei0r.facedetect
frei0r.facebl0r
frei0r.flippo
frei0r.glow
frei0r.IIRblur
frei0r.keyspillm0pup
frei0r.hqdn3d
frei0r.hueshift0r
frei0r.lenscorrection
frei0r.letterb0xed
frei0r.levels
frei0r.lightgraffiti
frei0r.luminance
frei0r.mask0mate
frei0r.nervous
frei0r.nosync0r
frei0r.pixeliz0r
frei0r.pr0be
frei0r.pr0file
frei0r.primaries
frei0r.rgbparade
frei0r.saturat0r
frei0r.scale0tilt
frei0r.scanline0r
frei0r.select0r
frei0r.sharpness
frei0r.sobel
frei0r.sopsat
frei0r.squareblur
frei0r.tehRoxx0r
frei0r.three_point_balance
frei0r.threelay0r
frei0r.threshold0r
frei0r.tint0r
frei0r.twolay0r
frei0r.vectorscope
frei0r.vertigo
frei0r.vignette
#Movit effects with XML UI
movit.blur
movit.sharpen
movit.diffusion
movit.glow
movit.lift_gamma_gain
movit.mirror
movit.opacity
movit.rect
movit.saturation
movit.unsharp_mask
movit.vignette
movit.white_balance
#MLT effects with XML UI
channelcopy
crop
dust
grain
lines
oldfilm
tcolor
rotoscoping
wave
vignette
volume
lift_gamma_gain
audiowaveform
audiowave
qtblend
#Effects not usable with a simple GUI
sox
ladspa
......@@ -173,11 +80,3 @@ avfilter.vflip
avfilter.vignette
avfilter.volume
avfilter.volumedetect
# Avfilter Effects with XML
avfilter.acompressor
avfilter.aecho
avfilter.agate
avfilter.lut3d
avfilter.selectivecolor
......@@ -115,6 +115,7 @@ add_subdirectory(mltcontroller)
add_subdirectory(bin)
add_subdirectory(qml)
add_subdirectory(profiles)
add_subdirectory(xml)
if (Qt5WebKitWidgets_FOUND)
add_subdirectory(qt-oauth-lib)
......
......@@ -21,8 +21,10 @@
#include "effectsrepository.hpp"
#include "core.h"
#include "xml/xml.hpp"
#include <QScopedPointer>
#include <QFile>
#include <QDir>
#include <QStandardPaths>
#include <QTextStream>
......@@ -55,6 +57,27 @@ EffectsRepository::EffectsRepository()
QString name = filters->get_name(i);
if (!m_blacklist.contains(name) && parseEffectFromMlt(name, info)) {
m_effects[name] = info;
} else {
if (m_blacklist.contains(name)) {
qDebug() << name << "is blacklisted";
} else {
qDebug() << "WARNING : Fails to parse "<<name;
}
}
}
// We now parse custom effect xml
// Set the directories to look into for effects.
QStringList effect_dirs = QStandardPaths::locateAll(QStandardPaths::AppDataLocation, QStringLiteral("effects"), QStandardPaths::LocateDirectory);
for (const auto& dir : effect_dirs) {
QDir current_dir(dir);
QStringList filter;
filter << QStringLiteral("*.xml");
QStringList fileList = current_dir.entryList(filter, QDir::Files);
for (const auto& file : fileList) {
QString path = current_dir.absoluteFilePath(file);
parseCustomEffectsFile(path);
}
}
}
......@@ -88,7 +111,8 @@ bool EffectsRepository::parseEffectFromMlt(const QString& effectId, EffectInfo &
res.description = metadata->get("description");
res.author = metadata->get("creator");
res.version = metadata->get("version");
res.version_str = metadata->get("version");
res.version = metadata->get_double("version");
res.type = EffectType::Video;
......@@ -102,6 +126,98 @@ bool EffectsRepository::parseEffectFromMlt(const QString& effectId, EffectInfo &
return false;
}
void EffectsRepository::parseCustomEffectsFile(const QString& file_name)
{
QFile file(file_name);
QDomDocument doc;
doc.setContent(&file, false);
file.close();
QDomElement base = doc.documentElement();
if (base.tagName() == QLatin1String("effectgroup")) {
//in that case we have a custom effect
EffectInfo info;
info.custom_xml_path = file_name;
info.type = EffectType::Custom;
QString tag = base.attribute(QStringLiteral("tag"), QString());
QString id = base.hasAttribute(QStringLiteral("id")) ? base.attribute(QStringLiteral("id")) : tag;
QString name = base.attribute(QStringLiteral("name"), QString());
info.name = name;
if (m_effects.count(id) > 0) {
qDebug() << "Error: conflicting effect name"<<id;
} else {
m_effects[id] = info;
}
return;
}
QDomNodeList effects = doc.elementsByTagName(QStringLiteral("effect"));
int nbr_effect = effects.count();
if (nbr_effect == 0) {
qDebug() << "+++++++++++++\nEffect broken: " << file_name << "\n+++++++++++";
return;
}
for (int i = 0; i < nbr_effect; ++i) {
QDomNode currentNode = effects.item(i);
if (currentNode.isNull()) {
continue;
}
QDomElement currentEffect = currentNode.toElement();
QLocale locale;
//We first deal with locale
if (currentEffect.hasAttribute(QStringLiteral("LC_NUMERIC"))) {
// set a locale for that effect
locale = QLocale(currentEffect.attribute(QStringLiteral("LC_NUMERIC")));
}
locale.setNumberOptions(QLocale::OmitGroupSeparator);
QString tag = currentEffect.attribute(QStringLiteral("tag"), QString());
QString id = currentEffect.hasAttribute(QStringLiteral("id")) ? currentEffect.attribute(QStringLiteral("id")) : tag;
if (!hasEffect(id)) {
qDebug() << "++++++ Unknown effect : " << id;
continue;
}
//Check if there is a maximal version set
if (currentEffect.hasAttribute(QStringLiteral("version"))) {
// a specific version of the filter is required
if (locale.toDouble(currentEffect.attribute(QStringLiteral("version"))) > m_effects[id].version) {
continue;
}
}
m_effects[id].custom_xml_path = file_name;
//Update description if the xml provide one
QString description = Xml::getSubTagContent(currentEffect, QStringLiteral("description"));
if (!description.isEmpty()) {
m_effects[id].description = description;
}
//Update name if the xml provide one
QString name = Xml::getSubTagContent(currentEffect, QStringLiteral("name"));
if (!name.isEmpty()) {
m_effects[id].name = name;
}
// Parse type information.
QString type = currentEffect.attribute(QStringLiteral("type"), QString());
if (type == QLatin1String("audio")) {
m_effects[id].type = EffectType::Audio;
} else if (type == QLatin1String("custom")) {
m_effects[id].type = EffectType::Custom;
} else {
m_effects[id].type = EffectType::Video;
}
}
}
std::unique_ptr<EffectsRepository> & EffectsRepository::get()
{
std::call_once(m_onceFlag, []{instance.reset(new EffectsRepository());});
......
......@@ -74,7 +74,9 @@ protected:
struct EffectInfo
{
QString name, description, author, version;
QString name, description, author, version_str;
double version;
QString custom_xml_path;
EffectType type;
};
......@@ -87,6 +89,9 @@ protected:
*/
static bool parseEffectFromMlt(const QString& effectId, EffectInfo & res);
/* @brief Retrieves additional info about effects from a custom XML file
*/
void parseCustomEffectsFile(const QString& file_name);
static std::unique_ptr<EffectsRepository> instance;
static std::once_flag m_onceFlag; //flag to create the repository only once;
......
set(kdenlive_SRCS
${kdenlive_SRCS}
xml/xml.cpp
PARENT_SCOPE)
/***************************************************************************
* Copyright (C) 2017 by Nicolas Carion *
* This file is part of Kdenlive. See www.kdenlive.org. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) version 3 or any later version accepted by the *
* membership of KDE e.V. (or its successor approved by the membership *
* of KDE e.V.), which shall act as a proxy defined in Section 14 of *
* version 3 of the license. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#include "xml.hpp"
#include <QDebug>
//static
QString Xml::getSubTagContent(const QDomElement& element, const QString& tagName)
{
QDomNodeList nodeList = element.elementsByTagName(tagName);
if (!nodeList.isEmpty()) {
if (nodeList.count() > 1) {
qDebug() << "Warning: "<<element.tagName()<<"provides several "<<tagName<<". We keep only first one.";
}
QString content = nodeList.item(0).toElement().text();
return content;
}
return QString();
}
/***************************************************************************
* Copyright (C) 2017 by Nicolas Carion *
* This file is part of Kdenlive. See www.kdenlive.org. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) version 3 or any later version accepted by the *
* membership of KDE e.V. (or its successor approved by the membership *
* of KDE e.V.), which shall act as a proxy defined in Section 14 of *
* version 3 of the license. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#ifndef XML_H
#define XML_H
#include <QDomElement>
#include <QString>
/** @brief This static class provides helper functions to manipulate Dom objects easily
*/
class Xml
{
public:
Xml() = delete;
/* @brief Returns the content of a given tag within the current DomElement.
For example, if your @param element looks like <html><title>foo</title><head>bar</head></html>, passing @tagName = "title" will return foo, and @tagName = "head" returns bar
*/
static QString getSubTagContent(const QDomElement& element, const QString& tagName);
};
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment