clipstabilize.cpp 10.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/***************************************************************************
 *   Copyright (C) 2008 by Jean-Baptiste Mardelle (jb@kdenlive.org)        *
 *   Copyright (C) 2011 by Marco Gittler (marco@gitma.de)                  *
 *                                                                         *
 *   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) any later version.                                   *
 *                                                                         *
 *   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, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA          *
 ***************************************************************************/


Vincent Pinon's avatar
Vincent Pinon committed
22
#include "clipstabilize.h"
23
#include "effectstack/widgets/doubleparameterwidget.h"
24
#include "effectstack/effectstackview2.h"
25
#include "effectstack/positionedit.h"
26

Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
27
#include <QDebug>
28 29
#include <mlt++/Mlt.h>
#include "kdenlivesettings.h"
30
#include <QFontDatabase>
31
#include <KMessageBox>
32
#include <klocalizedstring.h>
33

34
ClipStabilize::ClipStabilize(const QStringList &urls, const QString &filterName, int out, QWidget * parent) :
35 36 37
    QDialog(parent),
    m_filtername(filterName),
    m_urls(urls),
38
    vbox(Q_NULLPTR)
39
{
40
    setFont(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont));
41 42
    setupUi(this);
    setWindowTitle(i18n("Stabilize Clip"));
43
    auto_add->setText(i18np("Add clip to project", "Add clips to project", urls.count()));
44
    auto_add->setChecked(KdenliveSettings::add_new_clip());
Marco Gittler's avatar
Marco Gittler committed
45

46
    QString stylesheet = EffectStackView2::getStyleSheet();
47 48 49 50 51 52 53 54 55 56 57 58
    setStyleSheet(stylesheet);

    if (m_urls.count() == 1) {
        QString newFile = m_urls.first();
        newFile.append(".mlt");
        dest_url->setMode(KFile::File);
        dest_url->setUrl(QUrl(newFile));
    } else {
        label_dest->setText(i18n("Destination folder"));
        dest_url->setMode(KFile::Directory | KFile::ExistingOnly);
        dest_url->setUrl(QUrl(m_urls.first()).adjusted(QUrl::RemoveFilename));
    }
Marco Gittler's avatar
Marco Gittler committed
59

60 61 62
    if (m_filtername==QLatin1String("vidstab") || m_filtername==QLatin1String("videostab2")) {
        m_fixedParams.insert(QStringLiteral("algo"), QStringLiteral("1"));
        m_fixedParams.insert(QStringLiteral("relative"), QStringLiteral("1"));
63
        fillParameters(QStringList()
64 65 66 67 68 69 70 71 72 73
            << QStringLiteral("accuracy,type,int,value,8,min,1,max,10,tooltip,Accuracy of Shakiness detection")
            << QStringLiteral("shakiness,type,int,value,4,min,1,max,10,tooltip,How shaky is the Video")
            << QStringLiteral("stepsize,type,int,value,6,min,0,max,100,tooltip,Stepsize of Detection process minimum around")
            << QStringLiteral("mincontrast,type,double,value,0.3,min,0,max,1,factor,1,decimals,2,tooltip,Below this Contrast Field is discarded")
            << QStringLiteral("smoothing,type,int,value,10,min,0,max,100,tooltip,number of frames for lowpass filtering")
            << QStringLiteral("maxshift,type,int,value,-1,min,-1,max,1000,tooltip,max number of pixels to shift")
            << QStringLiteral("maxangle,type,double,value,-1,min,-1,max,3.14,decimals,2,tooltip,max angle to rotate (in rad)")
            << QStringLiteral("crop,type,bool,value,0,min,0,max,1,tooltip,0 = keep border  1 = black background")
            << QStringLiteral("zoom,type,int,value,0,min,-500,max,500,tooltip,additional zoom during transform")
            << QStringLiteral("optzoom,type,bool,value,1,min,0,max,1,tooltip,use optimal zoom (calulated from transforms)")
74 75
            << QStringLiteral("sharpen,type,double,value,0.8,min,0,max,1,decimals,1,tooltip,sharpen transformed image")
            << QStringLiteral("tripod,type,position,value,0,min,0,max,100000,tooltip,reference frame"));
76 77
    } else if (m_filtername==QLatin1String("videostab")) {
        fillParameters(QStringList(QStringLiteral("shutterangle,type,int,value,0,min,0,max,180,tooltip,Angle that Images could be maximum rotated")));
78
    }
Marco Gittler's avatar
Marco Gittler committed
79

80 81 82 83
    connect(buttonBox->button(QDialogButtonBox::Ok), &QPushButton::clicked, this, &ClipStabilize::slotValidate);

    vbox=new QVBoxLayout(optionsbox);
    QHashIterator<QString,QHash<QString,QString> > hi(m_ui_params);
84
    m_tc.setFormat(KdenliveSettings::project_fps());
85 86 87
    while(hi.hasNext()){
        hi.next();
        QHash<QString,QString> val=hi.value();
88
        if (val[QStringLiteral("type")]==QLatin1String("int") || val[QStringLiteral("type")]==QLatin1String("double")){
Vincent Pinon's avatar
Vincent Pinon committed
89 90 91 92 93 94 95 96 97
            DoubleParameterWidget *dbl=new DoubleParameterWidget(hi.key()/*name*/,
                    val[QStringLiteral("value")].toDouble(),
                    val[QStringLiteral("min")].toDouble(),
                    val[QStringLiteral("max")].toDouble(),
                    val[QStringLiteral("value")].toDouble(),/*default*/
                    QLatin1String(""),/*comment*/
                    0/*id*/,
                    QLatin1String(""),/*suffix*/
                    val[QStringLiteral("decimals")] != QLatin1String("") ? val[QStringLiteral("decimals")].toInt() : 0,
98
                    false,/*showRadioBtn*/
Vincent Pinon's avatar
Vincent Pinon committed
99
                    this);
100
            dbl->setObjectName(hi.key());
101
            dbl->setToolTip(val[QStringLiteral("tooltip")]);
102 103
            connect(dbl, &DoubleParameterWidget::valueChanged, this, &ClipStabilize::slotUpdateParams);
            vbox->addWidget(dbl);
104
        }else if (val[QStringLiteral("type")]==QLatin1String("bool")){
105
            QCheckBox *ch=new QCheckBox(hi.key(),this);
106
            ch->setCheckState(val[QStringLiteral("value")] == QLatin1String("0") ? Qt::Unchecked : Qt::Checked);
107 108
            ch->setObjectName(hi.key());
            connect(ch, &QCheckBox::stateChanged, this, &ClipStabilize::slotUpdateParams);
109
            ch->setToolTip(val[QStringLiteral("tooltip")]);
110
            vbox->addWidget(ch);
111 112 113 114 115 116
        } else if (val[QStringLiteral("type")]==QLatin1String("position")){
            PositionEdit *posedit = new PositionEdit(hi.key(), 0, 0, out, m_tc, this);
	    posedit->setToolTip(val[QStringLiteral("tooltip")]);
            posedit->setObjectName(hi.key());
            vbox->addWidget(posedit);
            connect(posedit, &PositionEdit::parameterChanged, this, &ClipStabilize::slotUpdateParams);
117 118 119
        }
    }
    adjustSize();
120 121 122 123
}

ClipStabilize::~ClipStabilize()
{
124
    /*if (m_stabilizeProcess.state() != QProcess::NotRunning) {
125
        m_stabilizeProcess.close();
126
    }*/
127
    KdenliveSettings::setAdd_new_clip(auto_add->isChecked());
128 129
}

130
QMap <QString, QString> ClipStabilize::producerParams()
131
{
132 133 134 135 136 137
    return QMap <QString, QString>();
}

QMap <QString, QString> ClipStabilize::filterParams()
{
    QMap <QString, QString> params;
138
    params.insert(QStringLiteral("filter"), m_filtername);
139

140 141 142 143 144 145
    QMapIterator<QString, QString> i(m_fixedParams);
    while (i.hasNext()) {
	i.next();
	params.insert(i.key(), i.value());
    }

146
    QHashIterator <QString,QHash<QString,QString> > it(m_ui_params);
147
    while (it.hasNext()) {
148
        it.next();
149
	params.insert(it.key(), it.value().value(QStringLiteral("value")));
Marco Gittler's avatar
Marco Gittler committed
150
    }
151 152 153 154 155
    return params;
}

QMap <QString, QString> ClipStabilize::consumerParams()
{
156
    // consumer params
157
    QMap <QString, QString> params;
158 159 160
    params.insert(QStringLiteral("consumer"), QStringLiteral("xml"));
    params.insert(QStringLiteral("all"), QStringLiteral("1"));
    params.insert(QStringLiteral("title"), i18n("Stabilised"));
161 162 163 164 165
    return params;
}

QString ClipStabilize::destination() const
{
166 167 168 169 170
    QString path = dest_url->url().path();
    if (m_urls.count() > 1 && !path.endsWith(QDir::separator())) {
        path.append(QDir::separator());
    }
    return path;
171 172 173 174 175
}

QString ClipStabilize::desc() const
{
    return i18n("Stabilize clip");
176 177
}

178 179
void ClipStabilize::slotUpdateParams()
{
180
    for (int i=0;i<vbox->count();++i){
Marco Gittler's avatar
Marco Gittler committed
181 182
        QWidget* w=vbox->itemAt(i)->widget();
        QString name=w->objectName();
183
        if (!name.isEmpty() && m_ui_params.contains(name)){
184
            if (m_ui_params[name][QStringLiteral("type")]==QLatin1String("int") || m_ui_params[name][QStringLiteral("type")]==QLatin1String("double")){
Vincent Pinon's avatar
Vincent Pinon committed
185
                DoubleParameterWidget *dbl=static_cast<DoubleParameterWidget*>(w);
186
                m_ui_params[name][QStringLiteral("value")]=QString::number((double)(dbl->getValue()));
187
            } else if (m_ui_params[name][QStringLiteral("type")]==QLatin1String("bool")){
Marco Gittler's avatar
Marco Gittler committed
188
                QCheckBox *ch=(QCheckBox*)w;
189
                m_ui_params[name][QStringLiteral("value")]= ch->checkState() == Qt::Checked ? "1" : "0" ;
190 191 192
            } else if (m_ui_params[name][QStringLiteral("type")]==QLatin1String("position")){
                PositionEdit *pos=(PositionEdit *)w;
                m_ui_params[name][QStringLiteral("value")]= QString::number(pos->getPosition());
Marco Gittler's avatar
Marco Gittler committed
193 194 195
            }
        }
    }
196 197
}

198 199 200 201 202
bool ClipStabilize::autoAddClip() const
{
    return auto_add->isChecked();
}

Marco Gittler's avatar
Marco Gittler committed
203
void ClipStabilize::fillParameters(QStringList lst)
204 205
{

Marco Gittler's avatar
Marco Gittler committed
206 207 208
    m_ui_params.clear();
    while (!lst.isEmpty()){
        QString vallist=lst.takeFirst();
209
        QStringList cont=vallist.split(',');
Marco Gittler's avatar
Marco Gittler committed
210 211 212 213 214 215 216 217 218 219
        QString name=cont.takeFirst();
        while (!cont.isEmpty()){
            QString valname=cont.takeFirst();
            QString val;
            if (!cont.isEmpty()){
                val=cont.takeFirst();
            }
            m_ui_params[name][valname]=val;
        }
    }
220 221 222

}

223 224 225
void ClipStabilize::slotValidate()
{
    if (m_urls.count() == 1) {
226 227 228
        if (QFile::exists(dest_url->url().path())) {
            if (KMessageBox::questionYesNo(this, i18n("File %1 already exists.\nDo you want to overwrite it?", dest_url->url().path() )) == KMessageBox::No) return;
        }
229 230
    }
    else {
231
        QDir folder(dest_url->url().toLocalFile());
232 233
        QStringList existingFiles;
        foreach(const QString &path, m_urls) {
234
            if (folder.exists(path + ".mlt")) existingFiles.append(folder.absoluteFilePath(path + ".mlt"));
235 236 237 238
        }
        if (!existingFiles.isEmpty()) {
            if (KMessageBox::warningContinueCancelList(this, i18n("The stabilize job will overwrite the following files:"), existingFiles) ==  KMessageBox::Cancel) return;
        }
239 240 241
    }
    accept();
}
242

243

244 245