speedjob.cpp 6.41 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/***************************************************************************
 *   Copyright (C) 2018 by Jean-Baptiste Mardelle (jb@kdenlive.org)        *
 *   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 "speedjob.hpp"
#include "bin/clipcreator.hpp"
#include "bin/projectclip.h"
#include "bin/projectfolder.h"
#include "bin/projectitemmodel.h"
#include "core.h"
#include "jobmanager.h"
#include "kdenlivesettings.h"
#include "project/clipstabilize.h"
#include "ui_scenecutdialog_ui.h"

Nicolas Carion's avatar
Nicolas Carion committed
35
#include <QInputDialog>
36
37
#include <QScopedPointer>

38
#include <KIO/RenameDialog>
39
40
#include <mlt++/Mlt.h>

Nicolas Carion's avatar
Nicolas Carion committed
41
SpeedJob::SpeedJob(const QString &binId, double speed, QString destUrl)
42
43
    : MeltJob(binId, SPEEDJOB, false, -1, -1)
    , m_speed(speed)
Nicolas Carion's avatar
Nicolas Carion committed
44
    , m_destUrl(std::move(destUrl))
45
46
47
48
49
50
51
52
53
54
55
{
    m_requiresFilter = false;
}

const QString SpeedJob::getDescription() const
{
    return i18n("Change clip speed");
}

void SpeedJob::configureConsumer()
{
Nicolas Carion's avatar
Nicolas Carion committed
56
    m_consumer = std::make_unique<Mlt::Consumer>(*m_profile.get(), "xml", m_destUrl.toUtf8().constData());
57
58
59
60
61
62
63
64
    m_consumer->set("terminate_on_pause", 1);
    m_consumer->set("title", "Speed Change");
    m_consumer->set("real_time", -KdenliveSettings::mltthreads());
}

void SpeedJob::configureProducer()
{
    if (!qFuzzyCompare(m_speed, 1.0)) {
65
        QLocale locale;
66
        QString resource = m_producer->get("resource");
67
        m_producer = std::make_unique<Mlt::Producer>(*m_profile.get(), "timewarp", QStringLiteral("%1:%2").arg(locale.toString(m_speed)).arg(resource).toUtf8().constData());
68
69
70
    }
}

Nicolas Carion's avatar
Nicolas Carion committed
71
void SpeedJob::configureFilter() {}
72
73

// static
Nicolas Carion's avatar
Nicolas Carion committed
74
int SpeedJob::prepareJob(const std::shared_ptr<JobManager> &ptr, const std::vector<QString> &binIds, int parentId, QString undoString)
75
76
77
78
79
80
81
82
83
84
85
86
{
    // Show config dialog
    bool ok;
    int speed = QInputDialog::getInt(QApplication::activeWindow(), i18n("Clip Speed"), i18n("Percentage"), 100, -100000, 100000, 1, &ok);
    if (!ok) {
        return -1;
    }
    std::unordered_map<QString, QString> destinations; // keys are binIds, values are path to target files
    for (const auto &binId : binIds) {
        auto binClip = pCore->projectItemModel()->getClipByBinID(binId);
        // Filter several clips, destination points to a folder
        QString mltfile = QFileInfo(binClip->url()).absoluteFilePath() + QStringLiteral(".mlt");
87
88
        if (QFile::exists(mltfile)) {
            KIO::RenameDialog renameDialog(qApp->activeWindow(), QString(), /*i18n("File already exists"), */QUrl::fromLocalFile(mltfile), QUrl::fromLocalFile(mltfile), KIO::RenameDialog_Option::RenameDialog_Overwrite );
89
            if (renameDialog.exec() != QDialog::Rejected) {
90
91
92
93
94
95
96
97
                QUrl final = renameDialog.newDestUrl();
                if (final.isValid()) {
                    mltfile = final.toLocalFile();
                }
            } else {
                return -1;
            }
        }
98
99
        destinations[binId] = mltfile;
    }
100
    // Now we have to create the jobs objects. This is trickier than usual, since the parameters are different for each job (each clip has its own
Nicolas Carion's avatar
Nicolas Carion committed
101
    // destination). We have to construct a lambda that does that.
102

103
    auto createFn = [dest = std::move(destinations), fSpeed = speed / 100.0](const QString &id) { return std::make_shared<SpeedJob>(id, fSpeed, dest.at(id)); };
104

Nicolas Carion's avatar
Nicolas Carion committed
105
106
    // We are now all set to create the job. Note that we pass all the parameters directly through the lambda, hence there are no extra parameters to the
    // function
107
108
109
110
    using local_createFn_t = std::function<std::shared_ptr<SpeedJob>(const QString &)>;
    return ptr->startJob<SpeedJob>(binIds, parentId, std::move(undoString), local_createFn_t(std::move(createFn)));
}

111
bool SpeedJob::commitResult(Fun &undo, Fun &redo)
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
{
    Q_ASSERT(!m_resultConsumed);
    if (!m_done) {
        qDebug() << "ERROR: Trying to consume invalid results";
        return false;
    }
    m_resultConsumed = true;
    if (!m_successful) {
        return false;
    }

    auto binClip = pCore->projectItemModel()->getClipByBinID(m_clipId);

    // We store the stabilized clips in a sub folder with this name
    const QString folderName(i18n("Speed Change"));

    QString folderId = QStringLiteral("-1");
    bool found = false;
    // We first try to see if it exists
    auto containingFolder = std::static_pointer_cast<ProjectFolder>(binClip->parent());
    for (int i = 0; i < containingFolder->childCount(); ++i) {
        auto currentItem = std::static_pointer_cast<AbstractProjectItem>(containingFolder->child(i));
        if (currentItem->itemType() == AbstractProjectItem::FolderItem && currentItem->name() == folderName) {
            found = true;
            folderId = currentItem->clipId();
            break;
        }
    }

    if (!found) {
        // if it was not found, we create it
        pCore->projectItemModel()->requestAddFolder(folderId, folderName, binClip->parent()->clipId(), undo, redo);
    }

    auto id = ClipCreator::createClipFromFile(m_destUrl, folderId, pCore->projectItemModel(), undo, redo);
    return id != QStringLiteral("-1");
}