Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Multimedia
Kdenlive
Commits
75feb1d7
Commit
75feb1d7
authored
May 23, 2021
by
Jean-Baptiste Mardelle
Browse files
Scene split: allow selecting markers category and create subclips
parent
383b454c
Pipeline
#62860
passed with stage
in 8 minutes and 14 seconds
Changes
4
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
src/jobs/scenesplittask.cpp
View file @
75feb1d7
...
...
@@ -41,10 +41,13 @@
#include <klocalizedstring.h>
#include <project/projectmanager.h>
SceneSplitTask
::
SceneSplitTask
(
const
ObjectId
&
owner
,
double
threshold
,
QObject
*
object
)
SceneSplitTask
::
SceneSplitTask
(
const
ObjectId
&
owner
,
double
threshold
,
int
markersCategory
,
bool
addSubclips
,
int
minDuration
,
QObject
*
object
)
:
AbstractTask
(
owner
,
AbstractTask
::
ANALYSECLIPJOB
,
object
)
,
m_jobDuration
(
0
)
,
m_threshold
(
threshold
)
,
m_markersType
(
markersCategory
)
,
m_subClips
(
addSubclips
)
,
m_minInterval
(
minDuration
)
,
m_jobProcess
(
nullptr
)
{
}
...
...
@@ -55,6 +58,8 @@ void SceneSplitTask::start(QObject* object, bool force)
Ui
::
SceneCutDialog_UI
view
;
view
.
setupUi
(
d
);
view
.
threshold
->
setValue
(
KdenliveSettings
::
scenesplitthreshold
());
view
.
add_markers
->
setChecked
(
KdenliveSettings
::
scenesplitmarkers
());
view
.
cut_scenes
->
setChecked
(
KdenliveSettings
::
scenesplitsubclips
());
// Set up categories
static
std
::
array
<
QColor
,
9
>
markerTypes
=
pCore
->
projectManager
()
->
getGuideModel
()
->
markerTypes
;
QPixmap
pixmap
(
32
,
32
);
...
...
@@ -68,7 +73,14 @@ void SceneSplitTask::start(QObject* object, bool force)
return
;
}
int
threshold
=
view
.
threshold
->
value
();
bool
addMarkers
=
view
.
add_markers
->
isChecked
();
bool
addSubclips
=
view
.
cut_scenes
->
isChecked
();
int
markersCategory
=
addMarkers
?
view
.
marker_type
->
currentIndex
()
:
-
1
;
int
minDuration
=
view
.
minDuration
->
value
();
KdenliveSettings
::
setScenesplitthreshold
(
threshold
);
KdenliveSettings
::
setScenesplitmarkers
(
view
.
add_markers
->
isChecked
());
KdenliveSettings
::
setScenesplitsubclips
(
view
.
cut_scenes
->
isChecked
());
std
::
vector
<
QString
>
binIds
=
pCore
->
bin
()
->
selectedClipsIds
(
true
);
for
(
auto
&
id
:
binIds
)
{
SceneSplitTask
*
task
=
nullptr
;
...
...
@@ -82,12 +94,12 @@ void SceneSplitTask::start(QObject* object, bool force)
}
owner
=
ObjectId
(
ObjectType
::
BinClip
,
binData
.
first
().
toInt
());
auto
binClip
=
pCore
->
projectItemModel
()
->
getClipByBinID
(
binData
.
first
());
task
=
new
SceneSplitTask
(
owner
,
threshold
/
100.
,
binClip
.
get
());
task
=
new
SceneSplitTask
(
owner
,
threshold
/
100.
,
markersCategory
,
addSubclips
,
minDuration
,
binClip
.
get
());
}
else
{
owner
=
ObjectId
(
ObjectType
::
BinClip
,
id
.
toInt
());
auto
binClip
=
pCore
->
projectItemModel
()
->
getClipByBinID
(
id
);
task
=
new
SceneSplitTask
(
owner
,
threshold
/
100.
,
binClip
.
get
());
task
=
new
SceneSplitTask
(
owner
,
threshold
/
100.
,
markersCategory
,
addSubclips
,
minDuration
,
binClip
.
get
());
}
// See if there is already a task for this MLT service and resource.
if
(
task
&&
pCore
->
taskManager
.
hasPendingJob
(
owner
,
AbstractTask
::
ANALYSECLIPJOB
))
{
...
...
@@ -128,6 +140,7 @@ void SceneSplitTask::run()
return
;
}
m_jobDuration
=
int
(
binClip
->
duration
().
seconds
());
int
producerDuration
=
binClip
->
frameDuration
();
//QStringList parameters = {QStringLiteral("-loglevel"),QStringLiteral("info"),QStringLiteral("-i"),source,QStringLiteral("-filter:v"),QString("scdet"),QStringLiteral("-f"),QStringLiteral("null"),QStringLiteral("-")};
QStringList
parameters
=
{
QStringLiteral
(
"-y"
),
QStringLiteral
(
"-loglevel"
),
QStringLiteral
(
"info"
),
QStringLiteral
(
"-i"
),
source
,
QStringLiteral
(
"-filter:v"
),
QString
(
"select='gt(scene,0.1)',showinfo"
),
QStringLiteral
(
"-vsync"
),
QStringLiteral
(
"vfr"
),
QStringLiteral
(
"-r"
),
QStringLiteral
(
"50"
)};
#ifdef Q_OS_WIN
...
...
@@ -162,56 +175,59 @@ void SceneSplitTask::run()
if
(
result
&&
!
m_isCanceled
)
{
qDebug
()
<<
"========================
\n\n
GOR RESULTS: "
<<
m_results
<<
"
\n\n
========="
;
auto
binClip
=
pCore
->
projectItemModel
()
->
getClipByBinID
(
QString
::
number
(
m_owner
.
second
));
//if (m_markersType >= 0) {
// Build json data for markers
QJsonArray
list
;
int
ix
=
1
;
int
lastCut
=
0
;
for
(
auto
&
marker
:
m_results
)
{
int
pos
=
GenTime
(
marker
).
frames
(
pCore
->
getCurrentFps
());
/*
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
(
0
));
//m_markersType));
list
.
push_back
(
currentMarker
);
ix
++
;
if
(
m_markersType
>=
0
)
{
// Build json data for markers
QJsonArray
list
;
int
ix
=
1
;
int
lastCut
=
0
;
for
(
auto
&
marker
:
m_results
)
{
int
pos
=
GenTime
(
marker
).
frames
(
pCore
->
getCurrentFps
());
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
);
QMetaObject
::
invokeMethod
(
m_object
,
"importJsonMarkers"
,
Q_ARG
(
const
QString
&
,
QString
(
json
.
toJson
())));
}
QJsonDocument
json
(
list
);
QMetaObject
::
invokeMethod
(
m_object
,
"importJsonMarkers"
,
Q_ARG
(
const
QString
&
,
QString
(
json
.
toJson
())));
//binClip->getMarkerModel()->importFromJson(QString(json.toJson()), true, undo, redo);
//}
/*if (QFileInfo(destUrl).size() == 0) {
QFile::remove(destUrl);
// File was not created
m_errorMessage.append(i18n("Failed to create file."));
} else {
QString id = QString::number(m_owner.second);
auto binClip = pCore->projectItemModel()->getClipByBinID(id);
if (m_replaceProducer && binClip) {
QMap <QString, QString> sourceProps;
QMap <QString, QString> newProps;
sourceProps.insert(QStringLiteral("resource"), binClip->url());
sourceProps.insert(QStringLiteral("kdenlive:clipname"), binClip->clipName());
newProps.insert(QStringLiteral("resource"), destUrl);
newProps.insert(QStringLiteral("kdenlive:clipname"), QFileInfo(destUrl).fileName());
pCore->bin()->slotEditClipCommand(id, sourceProps, newProps);
} else {
QString folder = QStringLiteral("-1");
if (binClip) {
auto containingFolder = std::static_pointer_cast<ProjectFolder>(binClip->parent());
if (containingFolder) {
folder = containingFolder->clipId();
}
if
(
m_subClips
)
{
// Create zones
int
ix
=
1
;
int
lastCut
=
0
;
QJsonArray
list
;
QJsonDocument
json
;
for
(
double
&
marker
:
m_results
)
{
int
pos
=
GenTime
(
marker
).
frames
(
pCore
->
getCurrentFps
());
if
(
pos
<=
lastCut
+
1
||
pos
-
lastCut
<
m_minInterval
)
{
continue
;
}
QMetaObject::invokeMethod(pCore->window(), "addProjectClip", Qt::QueuedConnection, Q_ARG(const QString&,destUrl), Q_ARG(const QString&,folder));
//id = ClipCreator::createClipFromFile(destUrl, folderId, pCore->projectItemModel());
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
++
;
}
if
(
lastCut
<
producerDuration
)
{
QJsonObject
currentZone
;
currentZone
.
insert
(
QLatin1String
(
"name"
),
QJsonValue
(
i18n
(
"Scene %1"
,
ix
)));
currentZone
.
insert
(
QLatin1String
(
"in"
),
QJsonValue
(
lastCut
));
currentZone
.
insert
(
QLatin1String
(
"out"
),
QJsonValue
(
producerDuration
));
list
.
push_back
(
currentZone
);
}
}*/
json
.
setArray
(
list
);
if
(
!
json
.
isEmpty
())
{
QString
dataMap
(
json
.
toJson
());
QMetaObject
::
invokeMethod
(
pCore
->
projectItemModel
().
get
(),
"loadSubClips"
,
Q_ARG
(
const
QString
&
,
QString
::
number
(
m_owner
.
second
)),
Q_ARG
(
const
QString
&
,
dataMap
));
}
}
}
else
{
// Proxy process crashed
m_errorMessage
.
append
(
QString
::
fromUtf8
(
m_jobProcess
->
readAll
()));
...
...
src/jobs/scenesplittask.h
View file @
75feb1d7
...
...
@@ -28,7 +28,7 @@ class QProcess;
class
SceneSplitTask
:
public
AbstractTask
{
public:
SceneSplitTask
(
const
ObjectId
&
owner
,
double
threshold
,
QObject
*
object
);
SceneSplitTask
(
const
ObjectId
&
owner
,
double
threshold
,
int
markersCategory
,
bool
addSubclips
,
int
minDuration
,
QObject
*
object
);
static
void
start
(
QObject
*
object
,
bool
force
=
false
);
protected:
...
...
@@ -41,6 +41,9 @@ private slots:
private:
int
m_jobDuration
;
double
m_threshold
;
int
m_markersType
;
bool
m_subClips
;
int
m_minInterval
;
std
::
unique_ptr
<
QProcess
>
m_jobProcess
;
QString
m_errorMessage
;
QString
m_logDetails
;
...
...
src/kdenlivesettings.kcfg
View file @
75feb1d7
...
...
@@ -33,7 +33,15 @@
<group
name=
"jobs"
>
<entry
name=
"scenesplitthreshold"
type=
"Int"
>
<label>
Scene split detection threshold.
</label>
<default>
30
</default>
<default>
30
</default>
</entry>
<entry
name=
"scenesplitmarkers"
type=
"Bool"
>
<label>
Add markers on Scene split.
</label>
<default>
true
</default>
</entry>
<entry
name=
"scenesplitsubclips"
type=
"Bool"
>
<label>
Add subclips on Scene split.
</label>
<default>
false
</default>
</entry>
</group>
<group
name=
"misc"
>
...
...
src/ui/scenecutdialog_ui.ui
View file @
75feb1d7
...
...
@@ -6,38 +6,31 @@
<rect>
<x>
0
</x>
<y>
0
</y>
<width>
36
8
</width>
<height>
250
</height>
<width>
36
6
</width>
<height>
194
</height>
</rect>
</property>
<property
name=
"windowTitle"
>
<string>
Scene Cut
</string>
</property>
<layout
class=
"QGridLayout"
name=
"gridLayout"
>
<item
row=
"
0
"
column=
"0"
>
<widget
class=
"QLabel"
name=
"label
_2
"
>
<item
row=
"
4
"
column=
"0"
colspan=
"2"
>
<widget
class=
"QLabel"
name=
"label"
>
<property
name=
"text"
>
<string>
Change threshold
</string>
</property>
</widget>
</item>
<item
row=
"8"
column=
"0"
colspan=
"5"
>
<widget
class=
"QDialogButtonBox"
name=
"buttonBox"
>
<property
name=
"orientation"
>
<enum>
Qt::Horizontal
</enum>
</property>
<property
name=
"standardButtons"
>
<set>
QDialogButtonBox::Cancel|QDialogButtonBox::Ok
</set>
<string>
Minimum scene length
</string>
</property>
</widget>
</item>
<item
row=
"
2
"
column=
"0"
colspan=
"5"
>
<widget
class=
"Q
CheckBox"
name=
"cut_scenes
"
>
<item
row=
"
0
"
column=
"0"
>
<widget
class=
"Q
Label"
name=
"label_2
"
>
<property
name=
"text"
>
<string>
C
ut scenes
</string>
<string>
C
hange threshold
</string>
</property>
</widget>
</item>
<item
row=
"0"
column=
"3"
>
<widget
class=
"QSpinBox"
name=
"threshold"
/>
</item>
<item
row=
"1"
column=
"2"
colspan=
"3"
>
<widget
class=
"QComboBox"
name=
"marker_type"
>
<property
name=
"sizePolicy"
>
...
...
@@ -48,20 +41,7 @@
</property>
</widget>
</item>
<item
row=
"0"
column=
"1"
colspan=
"2"
>
<widget
class=
"QSlider"
name=
"horizontalSlider"
>
<property
name=
"minimum"
>
<number>
1
</number>
</property>
<property
name=
"value"
>
<number>
30
</number>
</property>
<property
name=
"orientation"
>
<enum>
Qt::Horizontal
</enum>
</property>
</widget>
</item>
<item
row=
"7"
column=
"0"
>
<item
row=
"5"
column=
"0"
>
<spacer
name=
"verticalSpacer"
>
<property
name=
"orientation"
>
<enum>
Qt::Vertical
</enum>
...
...
@@ -74,38 +54,37 @@
</property>
</spacer>
</item>
<item
row=
"
1
"
column=
"0"
colspan=
"
2
"
>
<widget
class=
"Q
CheckBox"
name=
"add_markers
"
>
<property
name=
"
text
"
>
<
string>
Add clip markers
</string
>
<item
row=
"
6
"
column=
"0"
colspan=
"
5
"
>
<widget
class=
"Q
DialogButtonBox"
name=
"buttonBox
"
>
<property
name=
"
orientation
"
>
<
enum>
Qt::Horizontal
</enum
>
</property>
<property
name=
"
checked
"
>
<
bool>
true
</bool
>
<property
name=
"
standardButtons
"
>
<
set>
QDialogButtonBox::Cancel|QDialogButtonBox::Ok
</set
>
</property>
</widget>
</item>
<item
row=
"
6
"
column=
"0"
colspan=
"
2
"
>
<widget
class=
"Q
Label"
name=
"label
"
>
<item
row=
"
2
"
column=
"0"
colspan=
"
5
"
>
<widget
class=
"Q
CheckBox"
name=
"cut_scenes
"
>
<property
name=
"text"
>
<string>
Minimum scene length
</string>
<string>
Cut scenes
</string>
</property>
</widget>
</item>
<item
row=
"
4
"
column=
"
0
"
colspan=
"
5
"
>
<widget
class=
"Q
CheckBox"
name=
"zone_only
"
>
<property
name=
"
text
"
>
<
string>
Analyze only selected zone
</string
>
<item
row=
"
0
"
column=
"
1
"
colspan=
"
2
"
>
<widget
class=
"Q
Slider"
name=
"horizontalSlider
"
>
<property
name=
"
minimum
"
>
<
number>
1
</number
>
</property>
</widget>
</item>
<item
row=
"3"
column=
"0"
colspan=
"5"
>
<widget
class=
"QCheckBox"
name=
"store_data"
>
<property
name=
"text"
>
<string>
Save result in clip metadata
</string>
<property
name=
"value"
>
<number>
30
</number>
</property>
<property
name=
"orientation"
>
<enum>
Qt::Horizontal
</enum>
</property>
</widget>
</item>
<item
row=
"
6
"
column=
"2"
>
<item
row=
"
4
"
column=
"2"
>
<widget
class=
"QSpinBox"
name=
"minDuration"
>
<property
name=
"suffix"
>
<string>
frames
</string>
...
...
@@ -115,8 +94,15 @@
</property>
</widget>
</item>
<item
row=
"0"
column=
"3"
>
<widget
class=
"QSpinBox"
name=
"threshold"
/>
<item
row=
"1"
column=
"0"
colspan=
"2"
>
<widget
class=
"QCheckBox"
name=
"add_markers"
>
<property
name=
"text"
>
<string>
Add clip markers
</string>
</property>
<property
name=
"checked"
>
<bool>
true
</bool>
</property>
</widget>
</item>
</layout>
</widget>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment