Commit 5cf61ff0 authored by Julius Künzel's avatar Julius Künzel
Browse files

Scene split job: Bring back to UI entry after mlt7 switch, cleanup files

parent 8ecff03b
Pipeline #68194 passed with stage
in 8 minutes and 23 seconds
/***************************************************************************
* Copyright (C) 2011 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 "scenesplitjob.hpp"
#include "bin/clipcreator.hpp"
#include "bin/model/markerlistmodel.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"
#include <QScopedPointer>
#include <mlt++/Mlt.h>
SceneSplitJob::SceneSplitJob(const QString &binId, bool subClips, int markersType, int minInterval)
: MeltJob(binId, {ObjectType::BinClip, binId.toInt()}, STABILIZEJOB, true, -1, -1)
, m_subClips(subClips)
, m_markersType(markersType)
, m_minInterval(minInterval)
{
}
const QString SceneSplitJob::getDescription() const
{
return i18n("Scene split");
}
void SceneSplitJob::configureConsumer()
{
m_consumer = std::make_unique<Mlt::Consumer>(*m_profile.get(), "null");
m_consumer->set("all", 1);
m_consumer->set("terminate_on_pause", 1);
m_consumer->set("real_time", -1);
// We just want to find scene change, set all methods to the fastests
m_consumer->set("rescale", "nearest");
m_consumer->set("deinterlace_method", "onefield");
m_consumer->set("top_field_first", -1);
}
void SceneSplitJob::configureFilter()
{
m_filter = std::make_unique<Mlt::Filter>(*m_profile.get(), "motion_est");
if ((m_filter == nullptr) || !m_filter->is_valid()) {
m_errorMessage.append(i18n("Cannot create filter motion_est. Cannot split scenes"));
return;
}
m_filter->set("shot_change_list", 0);
m_filter->set("denoise", 0);
m_filter->set_in_and_out(0, length - 1);
}
void SceneSplitJob::configureProfile()
{
m_profile->set_height(160);
m_profile->set_width(int(m_profile->height() * m_profile->sar()));
}
// static
int SceneSplitJob::prepareJob(const std::shared_ptr<JobManager> &ptr, const std::vector<QString> &binIds, int parentId, QString undoString)
{
// Show config dialog
QScopedPointer<QDialog> d(new QDialog(QApplication::activeWindow()));
Ui::SceneCutDialog_UI ui;
ui.setupUi(d.data());
// Set up categories
for (size_t i = 0; i < MarkerListModel::markerTypes.size(); ++i) {
ui.marker_type->insertItem(int(i), i18n("Category %1", i));
ui.marker_type->setItemData(int(i), MarkerListModel::markerTypes[i], Qt::DecorationRole);
}
ui.marker_type->setCurrentIndex(KdenliveSettings::default_marker_type());
ui.zone_only->setEnabled(false); // TODO not implemented
ui.store_data->setEnabled(false); // TODO not implemented
if (d->exec() != QDialog::Accepted) {
return -1;
}
int markersType = ui.add_markers->isChecked() ? ui.marker_type->currentIndex() : -1;
bool subclips = ui.cut_scenes->isChecked();
int minInterval = ui.minDuration->value();
return emit ptr->startJob_noprepare<SceneSplitJob>(binIds, parentId, std::move(undoString), subclips, markersType, minInterval);
}
bool SceneSplitJob::commitResult(Fun &undo, Fun &redo)
{
Q_UNUSED(undo)
Q_UNUSED(redo)
Q_ASSERT(!m_resultConsumed);
if (!m_done) {
qDebug() << "ERROR: Trying to consume invalid results";
return false;
}
m_resultConsumed = true;
if (!m_successful) {
return false;
}
QString result = QString::fromLatin1(m_filter->get("shot_change_list"));
if (result.isEmpty()) {
m_errorMessage.append(i18n("No data returned from clip analysis"));
return false;
}
auto binClip = pCore->projectItemModel()->getClipByBinID(m_clipId);
QStringList markerData = result.split(QLatin1Char(';'));
if (m_markersType >= 0) {
// Build json data for markers
QJsonArray list;
int ix = 1;
int lastCut = 0;
for (const QString &marker : qAsConst(markerData)) {
int pos = marker.section(QLatin1Char('='), 0, 0).toInt();
if (m_minInterval > 0 && ix > 1 && pos - lastCut < m_minInterval) {
continue;
}
lastCut = pos;
QJsonObject currentMarker;
currentMarker.insert(QLatin1String("pos"), QJsonValue(pos));
currentMarker.insert(QLatin1String("comment"), QJsonValue(i18n("Scene %1", ix)));
currentMarker.insert(QLatin1String("type"), QJsonValue(m_markersType));
list.push_back(currentMarker);
ix++;
}
QJsonDocument json(list);
binClip->getMarkerModel()->importFromJson(QString(json.toJson()), true, undo, redo);
}
if (m_subClips) {
// Create zones
int ix = 1;
int lastCut = 0;
QJsonArray list;
QJsonDocument json;
for (const QString &marker : qAsConst(markerData)) {
int pos = marker.section(QLatin1Char('='), 0, 0).toInt();
if (pos <= lastCut + 1 || pos - lastCut < m_minInterval) {
continue;
}
QJsonObject currentZone;
currentZone.insert(QLatin1String("name"), QJsonValue(i18n("Scene %1", ix)));
currentZone.insert(QLatin1String("in"), QJsonValue(lastCut));
currentZone.insert(QLatin1String("out"), QJsonValue(pos - 1));
list.push_back(currentZone);
lastCut = pos;
ix++;
}
json.setArray(list);
QString dataMap(json.toJson());
if (!json.isEmpty()) {
pCore->projectItemModel()->loadSubClips(m_clipId, dataMap, undo, redo);
binClip->updateZones();
}
}
qDebug() << "RESULT of the SCENESPLIT filter:" << result;
// TODO refac: reimplement add markers and subclips
return true;
}
/***************************************************************************
* Copyright (C) 2011 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/>. *
***************************************************************************/
#pragma once
#include "meltjob.h"
#include <unordered_map>
#include <unordered_set>
class JobManager;
/** @class SceneSplitJob
@brief Detects the scenes of a clip using a mlt filter
*/
class SceneSplitJob : public MeltJob
{
Q_OBJECT
public:
/** @brief Creates a scenesplit job for the given bin clip
* @param subClips if true, we create a subclip per found scene
* @param markersType The type of markers that will be created to denote scene. Leave -1 for no markers
*/
SceneSplitJob(const QString &binId, bool subClips, int markersType = -1, int minInterval = 0);
// This is a special function that prepares the stabilize job for a given list of clips.
// Namely, it displays the required UI to configure the job and call startJob with the right set of parameters
// Then the job is automatically put in queue. Its id is returned
static int prepareJob(const std::shared_ptr<JobManager> &ptr, const std::vector<QString> &binIds, int parentId, QString undoString);
bool commitResult(Fun &undo, Fun &redo) override;
const QString getDescription() const override;
protected:
/** @brief create and configure consumer */
void configureConsumer() override;
/** @brief create and configure filter */
void configureFilter() override;
/** @brief extra configuration of the profile (eg: resize the profile) */
void configureProfile() override;
bool m_subClips;
int m_markersType;
/** @brief minimum scene duration. */
int m_minInterval;
};
......@@ -3541,16 +3541,13 @@ void MainWindow::buildDynamicActions()
StabilizeTask::start(this);
});
}
filter = std::make_unique<Mlt::Filter>(profile, "motion_est");
if (filter) {
if (filter->is_valid()) {
QAction *action = new QAction(i18n("Automatic scene split"), m_extraFactory->actionCollection());
ts->addAction(action->text(), action);
connect(action, &QAction::triggered, [&]() {
SceneSplitTask::start(this);
});
}
}
QAction *action = new QAction(i18n("Automatic scene split"), m_extraFactory->actionCollection());
ts->addAction(action->text(), action);
connect(action, &QAction::triggered, [&]() {
SceneSplitTask::start(this);
});
if (true /* TODO: check if timewarp producer is available */) {
QAction *action = new QAction(i18n("Duplicate clip with speed change"), m_extraFactory->actionCollection());
ts->addAction(action->text(), action);
......
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