Skip to content
GitLab
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
89b7f9ee
Commit
89b7f9ee
authored
Mar 04, 2020
by
Jean-Baptiste Mardelle
Browse files
Allow filter job effects on tracks and master stack, fix crash
Related to
#570
parent
74a16575
Pipeline
#15977
passed with stage
in 13 minutes and 54 seconds
Changes
9
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
data/effects/loudness.xml
View file @
89b7f9ee
...
...
@@ -6,7 +6,7 @@
<parameter
type=
"double"
name=
"program"
max=
"-10"
min=
"-50"
default=
"-23.00"
decimals=
"2"
suffix=
"LUFS"
>
<name>
Target Program Loudness
</name>
</parameter>
<parameter
type=
"filterjob"
filtertag=
"loudness"
filterparams=
"%params"
consumer=
"
xm
l"
consumerparams=
"video_off=1 no_meta=1 all=1 terminate_on_pause=1"
>
<parameter
type=
"filterjob"
filtertag=
"loudness"
filterparams=
"%params"
consumer=
"
nul
l"
consumerparams=
"video_off=1 no_meta=1 all=1 terminate_on_pause=1"
>
<name>
Analyse
</name>
<jobparam
name=
"key"
>
results
</jobparam>
<jobparam
name=
"finalfilter"
>
loudness
</jobparam>
...
...
src/assets/view/widgets/buttonparamwidget.cpp
View file @
89b7f9ee
...
...
@@ -41,7 +41,7 @@ ButtonParamWidget::ButtonParamWidget(std::shared_ptr<AssetParameterModel> model,
//QString name = m_model->data(m_index, AssetParameterModel::NameRole).toString();
QString
comment
=
m_model
->
data
(
m_index
,
AssetParameterModel
::
CommentRole
).
toString
();
setToolTip
(
comment
);
setEnabled
(
m_model
->
getOwnerId
().
first
!=
ObjectType
::
TimelineTrack
);
//
setEnabled(m_model->getOwnerId().first != ObjectType::TimelineTrack);
auto
*
layout
=
new
QVBoxLayout
(
this
);
QVariantList
filterData
=
m_model
->
data
(
m_index
,
AssetParameterModel
::
FilterJobParamsRole
).
toList
();
QStringList
filterAddedParams
=
m_model
->
data
(
m_index
,
AssetParameterModel
::
FilterParamsRole
).
toString
().
split
(
QLatin1Char
(
' '
),
QString
::
SkipEmptyParts
);
...
...
@@ -102,6 +102,9 @@ ButtonParamWidget::ButtonParamWidget(std::shared_ptr<AssetParameterModel> model,
binId
=
pCore
->
getTimelineClipBinId
(
cid
);
in
=
pCore
->
getItemIn
(
owner
);
out
=
in
+
pCore
->
getItemDuration
(
owner
);
}
else
if
(
owner
.
first
==
ObjectType
::
TimelineTrack
||
owner
.
first
==
ObjectType
::
Master
)
{
in
=
0
;
out
=
pCore
->
getItemDuration
(
owner
);
}
std
::
unordered_map
<
QString
,
QVariant
>
fParams
;
std
::
unordered_map
<
QString
,
QString
>
fData
;
...
...
@@ -118,7 +121,7 @@ ButtonParamWidget::ButtonParamWidget(std::shared_ptr<AssetParameterModel> model,
fParams
.
insert
({
fparam
.
section
(
QLatin1Char
(
'='
),
0
,
0
),
fparam
.
section
(
QLatin1Char
(
'='
),
1
)});
}
}
pCore
->
jobManager
()
->
startJob
<
FilterClipJob
>
({
binId
},
-
1
,
QString
(),
cid
,
m_model
,
assetId
,
in
,
out
,
assetId
,
fParams
,
fData
);
pCore
->
jobManager
()
->
startJob
<
FilterClipJob
>
({
binId
},
-
1
,
QString
(),
owner
,
m_model
,
assetId
,
in
,
out
,
assetId
,
fParams
,
fData
);
if
(
m_label
)
{
m_label
->
setVisible
(
false
);
}
...
...
src/core.cpp
View file @
89b7f9ee
...
...
@@ -879,3 +879,21 @@ void Core::updateProjectTags(QMap <QString, QString> tags)
i
++
;
}
}
std
::
unique_ptr
<
Mlt
::
Producer
>
Core
::
getMasterProducerInstance
()
{
if
(
m_guiConstructed
&&
m_mainWindow
->
getCurrentTimeline
())
{
std
::
unique_ptr
<
Mlt
::
Producer
>
producer
(
m_mainWindow
->
getCurrentTimeline
()
->
controller
()
->
tractor
()
->
cut
(
0
,
m_mainWindow
->
getCurrentTimeline
()
->
controller
()
->
duration
()
-
1
));
return
producer
;
}
return
nullptr
;
}
std
::
unique_ptr
<
Mlt
::
Producer
>
Core
::
getTrackProducerInstance
(
int
tid
)
{
if
(
m_guiConstructed
&&
m_mainWindow
->
getCurrentTimeline
())
{
std
::
unique_ptr
<
Mlt
::
Producer
>
producer
(
new
Mlt
::
Producer
(
m_mainWindow
->
getCurrentTimeline
()
->
controller
()
->
trackProducer
(
tid
)));
return
producer
;
}
return
nullptr
;
}
src/core.h
View file @
89b7f9ee
...
...
@@ -38,6 +38,7 @@ class ProjectManager;
namespace
Mlt
{
class
Repository
;
class
Producer
;
class
Profile
;
}
// namespace Mlt
...
...
@@ -212,6 +213,10 @@ public:
/** @brief Returns the consumer profile, that will be scaled
* according to preview settings. Should only be used on the consumer */
Mlt
::
Profile
*
getProjectProfile
();
/** @brief Returns a copy of current timeline's master playlist */
std
::
unique_ptr
<
Mlt
::
Producer
>
getMasterProducerInstance
();
/** @brief Returns a copy of a track's playlist */
std
::
unique_ptr
<
Mlt
::
Producer
>
getTrackProducerInstance
(
int
tid
);
private:
explicit
Core
();
...
...
src/jobs/filterclipjob.cpp
View file @
89b7f9ee
...
...
@@ -22,6 +22,7 @@
#include
"assets/model/assetparametermodel.hpp"
#include
"bin/projectclip.h"
#include
"bin/projectitemmodel.h"
#include
"profiles/profilemodel.hpp"
#include
"core.h"
#include
"kdenlivesettings.h"
#include
"macros.hpp"
...
...
@@ -30,15 +31,35 @@
#include
<klocalizedstring.h>
FilterClipJob
::
FilterClipJob
(
const
QString
&
binId
,
int
cid
,
std
::
weak_ptr
<
AssetParameterModel
>
model
,
const
QString
&
assetId
,
int
in
,
int
out
,
const
QString
&
filterName
,
std
::
unordered_map
<
QString
,
QVariant
>
filterParams
,
std
::
unordered_map
<
QString
,
QString
>
filterData
)
FilterClipJob
::
FilterClipJob
(
const
QString
&
binId
,
const
ObjectId
&
owner
,
std
::
weak_ptr
<
AssetParameterModel
>
model
,
const
QString
&
assetId
,
int
in
,
int
out
,
const
QString
&
filterName
,
std
::
unordered_map
<
QString
,
QVariant
>
filterParams
,
std
::
unordered_map
<
QString
,
QString
>
filterData
)
:
MeltJob
(
binId
,
FILTERCLIPJOB
,
false
,
in
,
out
)
,
m_model
(
model
)
,
m_filterName
(
filterName
)
,
m_timelineClipId
(
cid
)
,
m_assetId
(
assetId
)
,
m_filterParams
(
std
::
move
(
filterParams
))
,
m_filterData
(
std
::
move
(
filterData
))
,
m_owner
(
owner
)
{
m_timelineClipId
=
-
1
;
if
(
owner
.
first
==
ObjectType
::
TimelineClip
)
{
m_timelineClipId
=
owner
.
second
;
}
}
void
FilterClipJob
::
configureProducer
()
{
if
(
m_producer
!=
nullptr
)
{
// producer already configured, abort
return
;
}
// We are on master or track, configure producer accordingly
if
(
m_owner
.
first
==
ObjectType
::
Master
)
{
m_profile
.
reset
(
&
pCore
->
getCurrentProfile
()
->
profile
());
m_producer
=
std
::
move
(
pCore
->
getMasterProducerInstance
());
}
else
if
(
m_owner
.
first
==
ObjectType
::
TimelineTrack
)
{
m_profile
.
reset
(
&
pCore
->
getCurrentProfile
()
->
profile
());
m_producer
=
std
::
move
(
pCore
->
getTrackProducerInstance
(
m_owner
.
second
));
}
}
const
QString
FilterClipJob
::
getDescription
()
const
...
...
@@ -83,7 +104,11 @@ bool FilterClipJob::commitResult(Fun &undo, Fun &redo)
return
false
;
}
m_resultConsumed
=
true
;
m_producer
->
detach
(
*
m_filter
.
get
());
if
(
!
m_successful
)
{
m_filter
.
reset
();
m_producer
.
reset
();
m_wholeProducer
.
reset
();
return
false
;
}
QVector
<
QPair
<
QString
,
QVariant
>>
params
;
...
...
@@ -102,8 +127,10 @@ bool FilterClipJob::commitResult(Fun &undo, Fun &redo)
}
auto
operation
=
[
assetModel
=
m_model
,
filterParams
=
std
::
move
(
params
)]()
{
if
(
auto
ptr
=
assetModel
.
lock
())
{
qDebug
()
<<
"===== SETTING FILTER PARAM: "
<<
filterParams
;
ptr
->
setParameters
(
filterParams
);
}
pCore
->
setDocumentModified
();
return
true
;
};
auto
reverse
=
[
assetModel
=
m_model
,
keyName
=
key
]()
{
...
...
@@ -112,9 +139,13 @@ bool FilterClipJob::commitResult(Fun &undo, Fun &redo)
if
(
auto
ptr
=
assetModel
.
lock
())
{
ptr
->
setParameters
(
fParams
);
}
pCore
->
setDocumentModified
();
return
true
;
};
bool
ok
=
operation
();
m_filter
.
reset
();
m_producer
.
reset
();
m_wholeProducer
.
reset
();
if
(
ok
)
{
UPDATE_UNDO_REDO_NOLOCK
(
operation
,
reverse
,
undo
,
redo
);
}
...
...
src/jobs/filterclipjob.h
View file @
89b7f9ee
...
...
@@ -33,7 +33,7 @@ class FilterClipJob : public MeltJob
Q_OBJECT
public:
FilterClipJob
(
const
QString
&
binId
,
int
cid
,
std
::
weak_ptr
<
AssetParameterModel
>
model
,
const
QString
&
assetId
,
int
in
,
int
out
,
const
QString
&
filterName
,
std
::
unordered_map
<
QString
,
QVariant
>
filterParams
,
std
::
unordered_map
<
QString
,
QString
>
filterData
);
FilterClipJob
(
const
QString
&
binId
,
const
ObjectId
&
owner
,
std
::
weak_ptr
<
AssetParameterModel
>
model
,
const
QString
&
assetId
,
int
in
,
int
out
,
const
QString
&
filterName
,
std
::
unordered_map
<
QString
,
QVariant
>
filterParams
,
std
::
unordered_map
<
QString
,
QString
>
filterData
);
const
QString
getDescription
()
const
override
;
/** @brief This is to be called after the job finished.
By design, the job should store the result of the computation but not share it with the rest of the code. This happens when we call commitResult */
...
...
@@ -43,6 +43,9 @@ protected:
// @brief create and configure consumer
void
configureConsumer
()
override
;
// @brief create and configure producer
void
configureProducer
()
override
;
// @brief create and configure filter
void
configureFilter
()
override
;
...
...
@@ -53,6 +56,7 @@ protected:
QString
m_assetId
;
std
::
unordered_map
<
QString
,
QVariant
>
m_filterParams
;
std
::
unordered_map
<
QString
,
QString
>
m_filterData
;
ObjectId
m_owner
;
};
#endif
src/jobs/meltjob.cpp
View file @
89b7f9ee
...
...
@@ -55,101 +55,65 @@ MeltJob::MeltJob(const QString &binId, JOBTYPE type, bool useProducerProfile, in
bool
MeltJob
::
startJob
()
{
auto
binClip
=
pCore
->
projectItemModel
()
->
getClipByBinID
(
m_clipId
);
m_url
=
binClip
->
url
();
if
(
m_url
.
isEmpty
())
{
m_errorMessage
.
append
(
i18n
(
"No producer for this clip."
));
m_successful
=
false
;
m_done
=
true
;
return
false
;
}
/*
QString consumerName = m_consumerParams.value(QStringLiteral("consumer"));
// safety check, make sure we don't overwrite a source clip
if (!m_dest.isEmpty() && !m_dest.endsWith(QStringLiteral(".mlt"))) {
m_errorMessage.append(i18n("Invalid destination: %1.", consumerName));
setStatus(JobCrashed);
return;
}
int in = m_producerParams.value(QStringLiteral("in")).toInt();
if (in > 0 && !m_extra.contains(QStringLiteral("offset"))) {
m_extra.insert(QStringLiteral("offset"), QString::number(in));
}
int out = m_producerParams.value(QStringLiteral("out")).toInt();
QString filterName = m_filterParams.value(QStringLiteral("filter"));
// optional params
int startPos = -1;
int track = -1;
// used when triggering a job from an effect
if (m_extra.contains(QStringLiteral("clipStartPos"))) {
startPos = m_extra.value(QStringLiteral("clipStartPos")).toInt();
}
if (m_extra.contains(QStringLiteral("clipTrack"))) {
track = m_extra.value(QStringLiteral("clipTrack")).toInt();
}
if (!m_extra.contains(QStringLiteral("finalfilter"))) {
m_extra.insert(QStringLiteral("finalfilter"), filterName);
}
if
(
binClip
)
{
// Filter applied on a timeline or bin clip
m_url
=
binClip
->
url
();
if
(
m_url
.
isEmpty
())
{
m_errorMessage
.
append
(
i18n
(
"No producer for this clip."
));
m_successful
=
false
;
m_done
=
true
;
return
false
;
}
if (out != -1 && out <= in) {
m_errorMessage.append(i18n("Clip zone undefined (%1 - %2).", in, out));
setStatus(JobCrashed);
return;
}
*/
auto
&
projectProfile
=
pCore
->
getCurrentProfile
();
// bool producerProfile = m_extra.contains(QStringLiteral("producer_profile"));
if
(
m_useProducerProfile
)
{
m_profile
.
reset
(
new
Mlt
::
Profile
());
m_profile
->
set_explicit
(
0
);
}
else
{
m_profile
.
reset
(
&
projectProfile
->
profile
());
}
double
fps
=
projectProfile
->
fps
();
int
fps_num
=
projectProfile
->
frame_rate_num
();
int
fps_den
=
projectProfile
->
frame_rate_den
();
if
(
KdenliveSettings
::
gpu_accel
())
{
m_producer
=
binClip
->
getClone
();
Mlt
::
Filter
converter
(
*
m_profile
.
get
(),
"avcolor_space"
);
m_producer
->
attach
(
converter
);
}
else
{
m_producer
=
std
::
make_unique
<
Mlt
::
Producer
>
(
*
m_profile
.
get
(),
m_url
.
toUtf8
().
constData
());
}
if
(
m_producer
&&
m_useProducerProfile
)
{
m_profile
->
from_producer
(
*
m_producer
.
get
());
m_profile
->
set_explicit
(
1
);
configureProfile
();
if
(
!
qFuzzyCompare
(
m_profile
->
fps
(),
fps
))
{
// Reload producer
// Force same fps as projec profile or the resulting .mlt will not load in our project
qDebug
()
<<
"/// FORCING FRAME RATE TO: "
<<
fps_num
<<
"
\n
-------------------"
;
m_profile
->
set_frame_rate
(
fps_num
,
fps_den
);
auto
&
projectProfile
=
pCore
->
getCurrentProfile
();
if
(
m_useProducerProfile
)
{
m_profile
.
reset
(
new
Mlt
::
Profile
());
m_profile
->
set_explicit
(
0
);
}
else
{
m_profile
.
reset
(
&
projectProfile
->
profile
());
}
double
fps
=
projectProfile
->
fps
();
int
fps_num
=
projectProfile
->
frame_rate_num
();
int
fps_den
=
projectProfile
->
frame_rate_den
();
if
(
KdenliveSettings
::
gpu_accel
())
{
m_producer
=
binClip
->
getClone
();
Mlt
::
Filter
converter
(
*
m_profile
.
get
(),
"avcolor_space"
);
m_producer
->
attach
(
converter
);
}
else
{
m_producer
=
std
::
make_unique
<
Mlt
::
Producer
>
(
*
m_profile
.
get
(),
m_url
.
toUtf8
().
constData
());
}
}
if
((
m_producer
==
nullptr
)
||
!
m_producer
->
is_valid
())
{
// Clip was removed or something went wrong, Notify user?
m_errorMessage
.
append
(
i18n
(
"Invalid clip"
));
m_successful
=
false
;
m_done
=
true
;
return
false
;
}
/*
// Process producer params
QMapIterator<QString, QString> i(m_producerParams);
QStringList ignoredProps;
ignoredProps << QStringLiteral("producer") << QStringLiteral("in") << QStringLiteral("out");
while (i.hasNext()) {
i.next();
QString key = i.key();
if (!ignoredProps.contains(key)) {
producer->set(i.key().toUtf8().constData(), i.value().toUtf8().constData());
if
(
m_producer
&&
m_useProducerProfile
)
{
m_profile
->
from_producer
(
*
m_producer
.
get
());
m_profile
->
set_explicit
(
1
);
configureProfile
();
if
(
!
qFuzzyCompare
(
m_profile
->
fps
(),
fps
))
{
// Reload producer
// Force same fps as projec profile or the resulting .mlt will not load in our project
qDebug
()
<<
"/// FORCING FRAME RATE TO: "
<<
fps_num
<<
"
\n
-------------------"
;
m_profile
->
set_frame_rate
(
fps_num
,
fps_den
);
m_producer
=
std
::
make_unique
<
Mlt
::
Producer
>
(
*
m_profile
.
get
(),
m_url
.
toUtf8
().
constData
());
}
}
if
((
m_producer
==
nullptr
)
||
!
m_producer
->
is_valid
())
{
// Clip was removed or something went wrong, Notify user?
m_errorMessage
.
append
(
i18n
(
"Invalid clip"
));
m_successful
=
false
;
m_done
=
true
;
return
false
;
}
if
(
m_out
==
-
1
)
{
m_out
=
m_producer
->
get_length
()
-
1
;
}
if
(
m_in
==
-
1
)
{
m_in
=
0
;
}
if
(
m_out
!=
m_producer
->
get_length
()
-
1
||
m_in
!=
0
)
{
std
::
swap
(
m_wholeProducer
,
m_producer
);
m_producer
.
reset
(
m_wholeProducer
->
cut
(
m_in
,
m_out
));
}
}
else
{
// Filter applied on a track of master producer, leave config to source job
}
*/
configureProducer
();
if
((
m_producer
==
nullptr
)
||
!
m_producer
->
is_valid
())
{
...
...
@@ -159,16 +123,6 @@ bool MeltJob::startJob()
m_done
=
true
;
return
false
;
}
if
(
m_out
==
-
1
)
{
m_out
=
m_producer
->
get_length
()
-
1
;
}
if
(
m_in
==
-
1
)
{
m_in
=
0
;
}
if
(
m_out
!=
m_producer
->
get_length
()
-
1
||
m_in
!=
0
)
{
std
::
swap
(
m_wholeProducer
,
m_producer
);
m_producer
.
reset
(
m_wholeProducer
->
cut
(
m_in
,
m_out
));
}
// Build consumer
configureConsumer
();
...
...
@@ -252,6 +206,7 @@ bool MeltJob::startJob()
length
=
m_producer
->
get_length
();
}
if
(
m_filter
)
{
m_filter
->
set_in_and_out
(
0
,
length
-
1
);
m_producer
->
attach
(
*
m_filter
.
get
());
}
m_showFrameEvent
.
reset
(
m_consumer
->
listen
(
"consumer-frame-show"
,
this
,
(
mlt_listener
)
consumer_frame_render
));
...
...
@@ -261,20 +216,7 @@ bool MeltJob::startJob()
return
false
;
});
m_consumer
->
run
();
/*
QMap<QString, QString> jobResults;
if (m_jobStatus != JobAborted && m_extra.contains(QStringLiteral("key"))) {
QString result = QString::fromLatin1(m_filter->get(m_extra.value(QStringLiteral("key")).toUtf8().constData()));
jobResults.insert(m_extra.value(QStringLiteral("key")), result);
}
if (!jobResults.isEmpty() && m_jobStatus != JobAborted) {
emit gotFilterJobResults(m_clipId, startPos, track, jobResults, m_extra);
}
if (m_jobStatus == JobWorking) {
m_jobStatus = JobDone;
}
*/
qDebug
()
<<
"===============FILTER PROCESSED
\n\n
==============0"
;
m_successful
=
m_done
=
true
;
return
true
;
}
src/timeline2/view/timelinecontroller.cpp
View file @
89b7f9ee
...
...
@@ -162,6 +162,11 @@ Mlt::Tractor *TimelineController::tractor()
return
m_model
->
tractor
();
}
Mlt
::
Producer
TimelineController
::
trackProducer
(
int
tid
)
{
return
*
(
m_model
->
getTrackById
(
tid
).
get
());
}
double
TimelineController
::
scaleFactor
()
const
{
return
m_scale
;
...
...
src/timeline2/view/timelinecontroller.h
View file @
89b7f9ee
...
...
@@ -319,6 +319,9 @@ public:
/* @brief Return the project's tractor
*/
Mlt
::
Tractor
*
tractor
();
/* @brief Return a track's producer
*/
Mlt
::
Producer
trackProducer
(
int
tid
);
/* @brief Get the list of currently selected clip id's
*/
QList
<
int
>
selection
()
const
;
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new 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