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
daa2c64c
Commit
daa2c64c
authored
May 07, 2021
by
Jean-Baptiste Mardelle
Browse files
Fixes and improvements for clips load / audio thumb jobs
parent
00f0c3a5
Changes
27
Hide whitespace changes
Inline
Side-by-side
src/abstractmodel/abstracttreemodel.cpp
View file @
daa2c64c
...
...
@@ -281,6 +281,9 @@ bool AbstractTreeModel::checkConsistency()
Fun
AbstractTreeModel
::
addItem_lambda
(
const
std
::
shared_ptr
<
TreeItem
>
&
new_item
,
int
parentId
)
{
return
[
this
,
new_item
,
parentId
]()
{
if
(
new_item
->
m_isInvalid
)
{
return
true
;
}
/* Insertion is simply setting the parent of the item.*/
std
::
shared_ptr
<
TreeItem
>
parent
;
if
(
parentId
!=
-
1
)
{
...
...
@@ -302,6 +305,10 @@ Fun AbstractTreeModel::removeItem_lambda(int id)
is captured by the reverse operation.
Actual deletions occurs when the undo object is destroyed.
*/
if
(
m_allItems
.
count
(
id
)
==
0
)
{
// Invalid item, might have been deleted on insert
return
true
;
}
auto
item
=
m_allItems
[
id
].
lock
();
Q_ASSERT
(
item
);
if
(
!
item
)
{
...
...
src/abstractmodel/treeitem.cpp
View file @
daa2c64c
...
...
@@ -32,6 +32,7 @@ TreeItem::TreeItem(QList<QVariant> data, const std::shared_ptr<AbstractTreeModel
,
m_id
(
id
==
-
1
?
AbstractTreeModel
::
getNextId
()
:
id
)
,
m_isInModel
(
false
)
,
m_isRoot
(
isRoot
)
,
m_isInvalid
(
false
)
{
}
...
...
src/abstractmodel/treeitem.hpp
View file @
daa2c64c
...
...
@@ -167,9 +167,9 @@ protected:
std
::
weak_ptr
<
AbstractTreeModel
>
m_model
;
int
m_depth
;
int
m_id
;
bool
m_isInModel
;
bool
m_isRoot
;
bool
m_isInvalid
;
};
template
<
class
T
,
class
BinaryOperation
>
T
TreeItem
::
accumulate
(
T
init
,
BinaryOperation
op
)
...
...
src/assets/model/assetparametermodel.cpp
View file @
daa2c64c
...
...
@@ -42,6 +42,7 @@ AssetParameterModel::AssetParameterModel(std::unique_ptr<Mlt::Properties> asset,
,
m_active
(
false
)
,
m_asset
(
std
::
move
(
asset
))
,
m_keyframes
(
nullptr
)
,
m_filterProgress
(
0
)
{
Q_ASSERT
(
m_asset
->
is_valid
());
QDomNodeList
parameterNodes
=
assetXml
.
elementsByTagName
(
QStringLiteral
(
"parameter"
));
...
...
@@ -469,6 +470,8 @@ QVariant AssetParameterModel::data(const QModelIndex &index, int role) const
return
parseAttribute
(
m_ownerId
,
QStringLiteral
(
"consumerparams"
),
element
);
case
FilterJobParamsRole
:
return
parseSubAttributes
(
QStringLiteral
(
"jobparam"
),
element
);
case
FilterProgressRole
:
return
m_filterProgress
;
case
AlternateNameRole
:
{
QDomNode
child
=
element
.
firstChildElement
(
QStringLiteral
(
"name"
));
if
(
child
.
toElement
().
hasAttribute
(
QStringLiteral
(
"conditional"
)))
{
...
...
@@ -542,7 +545,7 @@ QVariant AssetParameterModel::data(const QModelIndex &index, int role) const
int
AssetParameterModel
::
rowCount
(
const
QModelIndex
&
parent
)
const
{
qDebug
()
<<
"===================================================== Requested rowCount"
<<
parent
<<
m_rows
.
size
();
//
qDebug() << "===================================================== Requested rowCount" << parent << m_rows.size();
if
(
parent
.
isValid
())
return
0
;
return
m_rows
.
size
();
}
...
...
@@ -990,7 +993,7 @@ const QVector<QPair<QString, QVariant>> AssetParameterModel::loadPreset(const QS
return
params
;
}
void
AssetParameterModel
::
setParameters
(
const
Q
Vector
<
QPair
<
QString
,
QVariant
>>
&
params
,
bool
update
)
void
AssetParameterModel
::
setParameters
(
const
param
Vector
&
params
,
bool
update
)
{
ObjectType
itemId
;
if
(
!
update
)
{
...
...
@@ -1053,6 +1056,12 @@ void AssetParameterModel::passProperties(Mlt::Properties &target)
target
.
set_lcnumeric
(
m_asset
->
get_lcnumeric
());
}
void
AssetParameterModel
::
setProgress
(
int
progress
)
{
m_filterProgress
=
progress
;
emit
dataChanged
(
index
(
0
,
0
),
index
(
m_rows
.
count
()
-
1
,
0
),
{
AssetParameterModel
::
FilterProgressRole
});
}
Mlt
::
Properties
*
AssetParameterModel
::
getAsset
()
{
return
m_asset
.
get
();
...
...
src/assets/model/assetparametermodel.hpp
View file @
daa2c64c
...
...
@@ -34,6 +34,8 @@
class
KeyframeModelList
;
typedef
QVector
<
QPair
<
QString
,
QVariant
>>
paramVector
;
enum
class
ParamType
{
Double
,
List
,
// Value can be chosen from a list of pre-defined ones
...
...
@@ -109,6 +111,7 @@ public:
FactorRole
,
FilterRole
,
FilterJobParamsRole
,
FilterProgressRole
,
FilterParamsRole
,
FilterConsumerParamsRole
,
ScaleRole
,
...
...
@@ -162,11 +165,6 @@ public:
const
QStringList
getPresetList
(
const
QString
&
presetFile
)
const
;
const
QVector
<
QPair
<
QString
,
QVariant
>>
loadPreset
(
const
QString
&
presetFile
,
const
QString
&
presetName
);
/** @brief Sets the value of a list of parameters
@param params contains the pairs (parameter name, parameter value)
*/
void
setParameters
(
const
QVector
<
QPair
<
QString
,
QVariant
>>
&
params
,
bool
update
=
true
);
/* Which monitor is attached to this asset (clip/project)
*/
Kdenlive
::
MonitorId
monitorId
;
...
...
@@ -194,10 +192,17 @@ public:
/** @brief Returns the current value of an effect parameter */
const
QString
getParam
(
const
QString
&
paramName
);
/** @brief Returns the current asset */
Mlt
::
Properties
*
getAsset
();
public
slots
:
/** @brief Sets the value of a list of parameters
@param params contains the pairs (parameter name, parameter value)
*/
void
setParameters
(
const
paramVector
&
params
,
bool
update
=
true
);
/** @brief Set a filter job's progress */
void
setProgress
(
int
progress
);
protected:
/** @brief Helper function to retrieve the type of a parameter given the string corresponding to it*/
static
ParamType
paramTypeFromStr
(
const
QString
&
type
);
...
...
@@ -244,6 +249,8 @@ protected:
bool
m_hideKeyframesByDefault
;
/** @brief true if this is an audio effect, used to prevent unnecessary monitor refresh / timeline invalidate */
bool
m_isAudio
;
/** @brief Store a filter's job progress */
int
m_filterProgress
;
/** @brief Set the parameter with given name to the given value. This should be called when first
* building an effect in the constructor, so that we don't call shared_from_this
...
...
src/assets/view/widgets/buttonparamwidget.cpp
View file @
daa2c64c
...
...
@@ -21,7 +21,7 @@
#include "buttonparamwidget.hpp"
#include "assets/model/assetparametermodel.hpp"
#include "jobs/filter
clipjob
.h"
#include "jobs/filter
task
.h"
#include "jobs/jobmanager.h"
#include "assets/model/assetcommand.hpp"
#include "core.h"
...
...
@@ -30,6 +30,7 @@
#include <KMessageWidget>
#include <QPushButton>
#include <QVBoxLayout>
#include <QProgressBar>
ButtonParamWidget
::
ButtonParamWidget
(
std
::
shared_ptr
<
AssetParameterModel
>
model
,
QModelIndex
index
,
QWidget
*
parent
)
:
AbstractParamWidget
(
std
::
move
(
model
),
index
,
parent
)
...
...
@@ -86,6 +87,11 @@ ButtonParamWidget::ButtonParamWidget(std::shared_ptr<AssetParameterModel> model,
layout
->
setSpacing
(
0
);
m_button
=
new
QPushButton
(
m_displayConditional
?
m_buttonName
:
m_alternatebuttonName
,
this
);
layout
->
addWidget
(
m_button
);
m_progress
=
new
QProgressBar
(
this
);
m_progress
->
setMaximumHeight
(
m_button
->
height
()
/
5
);
m_progress
->
setTextVisible
(
false
);
layout
->
addWidget
(
m_progress
);
m_progress
->
setVisible
(
false
);
setMinimumHeight
(
m_button
->
sizeHint
().
height
()
+
(
m_label
!=
nullptr
?
m_label
->
sizeHint
().
height
()
:
0
));
// emit the signal of the base class when appropriate
...
...
@@ -134,11 +140,16 @@ ButtonParamWidget::ButtonParamWidget(std::shared_ptr<AssetParameterModel> model,
fParams
.
insert
({
fparam
.
section
(
QLatin1Char
(
'='
),
0
,
0
),
fparam
.
section
(
QLatin1Char
(
'='
),
1
)});
}
}
emit
pCore
->
jobManager
()
->
startJob
<
FilterClipJob
>
({
binId
},
-
1
,
QString
(),
owner
,
m_model
,
assetId
,
in
,
out
,
assetId
,
fParams
,
fData
,
consumerParams
);
if
(
m_label
)
{
m_label
->
setVisible
(
false
);
if
(
m_progress
->
value
()
>
0
&&
m_progress
->
value
()
<
100
)
{
// The task is in progress, abort it
pCore
->
taskManager
.
discardJobs
(
owner
,
AbstractTask
::
FILTERCLIPJOB
);
}
else
{
FilterTask
::
start
(
owner
,
binId
,
m_model
,
assetId
,
in
,
out
,
assetId
,
fParams
,
fData
,
consumerParams
,
this
);
if
(
m_label
)
{
m_label
->
setVisible
(
false
);
}
m_button
->
setEnabled
(
false
);
}
m_button
->
setEnabled
(
false
);
});
}
...
...
@@ -163,8 +174,21 @@ void ButtonParamWidget::slotRefresh()
if
(
m_label
)
{
m_label
->
setVisible
(
m_displayConditional
);
}
m_button
->
setText
(
m_displayConditional
?
m_buttonName
:
m_alternatebuttonName
);
m_button
->
setEnabled
(
true
);
// Check running job percentage
int
progress
=
m_model
->
data
(
m_index
,
AssetParameterModel
::
FilterProgressRole
).
toInt
();
if
(
progress
>
0
&&
progress
<
100
)
{
m_progress
->
setValue
(
progress
);
if
(
!
m_progress
->
isVisible
())
{
m_button
->
setText
(
i18n
(
"Abort processing"
));
m_progress
->
setVisible
(
true
);
}
}
else
{
m_button
->
setText
(
m_displayConditional
?
m_buttonName
:
m_alternatebuttonName
);
m_progress
->
setValue
(
0
);
m_progress
->
setVisible
(
false
);
}
updateGeometry
();
}
...
...
@@ -172,3 +196,4 @@ bool ButtonParamWidget::getValue()
{
return
true
;
}
src/assets/view/widgets/buttonparamwidget.hpp
View file @
daa2c64c
...
...
@@ -26,6 +26,7 @@
#include <QWidget>
class
QPushButton
;
class
QProgressBar
;
class
KMessageWidget
;
/** @brief This class represents a parameter that requires
...
...
@@ -58,6 +59,7 @@ public slots:
private:
QPushButton
*
m_button
;
QProgressBar
*
m_progress
;
KMessageWidget
*
m_label
;
QString
m_keyParam
;
QString
m_buttonName
;
...
...
src/assets/view/widgets/clickablelabelwidget.cpp
View file @
daa2c64c
...
...
@@ -21,8 +21,6 @@
#include "clickablelabelwidget.hpp"
#include "assets/model/assetparametermodel.hpp"
#include "jobs/filterclipjob.h"
#include "jobs/jobmanager.h"
#include "core.h"
#include <QPushButton>
...
...
src/bin/abstractprojectitem.cpp
View file @
daa2c64c
...
...
@@ -289,7 +289,6 @@ std::shared_ptr<AbstractProjectItem> AbstractProjectItem::getEnclosingFolder(boo
bool
AbstractProjectItem
::
selfSoftDelete
(
Fun
&
undo
,
Fun
&
redo
)
{
pCore
->
jobManager
()
->
slotDiscardClipJobs
(
clipId
());
Fun
local_undo
=
[]()
{
return
true
;
};
Fun
local_redo
=
[]()
{
return
true
;
};
for
(
const
auto
&
child
:
m_childItems
)
{
...
...
@@ -339,3 +338,11 @@ void AbstractProjectItem::setRating(uint rating)
{
m_rating
=
rating
;
}
Fun
AbstractProjectItem
::
getAudio_lambda
()
{
return
[]()
{
qDebug
()
<<
"============
\n\n
ABSTRACT AUDIO CHECK
\n\n
==========="
;
return
true
;
};
}
src/bin/abstractprojectitem.h
View file @
daa2c64c
...
...
@@ -86,7 +86,7 @@ public:
@param Undo,Redo are the lambdas accumulating the update.
*/
virtual
bool
selfSoftDelete
(
Fun
&
undo
,
Fun
&
redo
);
virtual
Fun
getAudio_lambda
();
/** @brief Returns the clip's id. */
const
QString
&
clipId
()
const
;
virtual
QPoint
zone
()
const
;
...
...
src/bin/projectclip.cpp
View file @
daa2c64c
...
...
@@ -45,6 +45,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "projectsubclip.h"
#include "timecode.h"
#include "timeline2/model/snapmodel.hpp"
#include "macros.hpp"
#include "utils/thumbnailcache.hpp"
#include "xml/xml.hpp"
...
...
@@ -123,7 +124,7 @@ ProjectClip::ProjectClip(const QString &id, const QIcon &thumb, const std::share
if
(
m_clipStatus
==
FileStatus
::
StatusProxy
||
m_clipStatus
==
FileStatus
::
StatusReady
||
m_clipStatus
==
FileStatus
::
StatusProxyOnly
)
{
// Generate clip thumbnail
ClipLoadTask
::
start
({
ObjectType
::
BinClip
,
m_binId
.
toInt
()},
QDomElement
(),
true
,
this
);
// Generate audio
levels
// Generate audio
thumbnail
AudioLevelsTask
::
start
({
ObjectType
::
BinClip
,
m_binId
.
toInt
()},
this
,
false
);
}
}
...
...
@@ -179,11 +180,6 @@ std::shared_ptr<ProjectClip> ProjectClip::construct(const QString &id, const QDo
ProjectClip
::~
ProjectClip
()
{
// controller is deleted in bincontroller
m_thumbMutex
.
lock
();
m_requestedThumbs
.
clear
();
m_thumbMutex
.
unlock
();
m_thumbThread
.
waitForFinished
();
}
void
ProjectClip
::
connectEffectStack
()
...
...
@@ -1672,6 +1668,18 @@ QList<int> ProjectClip::timelineInstances() const
bool
ProjectClip
::
selfSoftDelete
(
Fun
&
undo
,
Fun
&
redo
)
{
Fun
operation
=
[
this
]()
{
// Free audio thumb data and timeline producers
pCore
->
taskManager
.
discardJobs
({
ObjectType
::
BinClip
,
m_binId
.
toInt
()});
m_audioLevels
.
clear
();
m_disabledProducer
.
reset
();
m_audioProducers
.
clear
();
m_videoProducers
.
clear
();
m_timewarpProducers
.
clear
();
return
true
;
};
operation
();
auto
toDelete
=
m_registeredClips
;
// we cannot use m_registeredClips directly, because it will be modified during loop
for
(
const
auto
&
clip
:
toDelete
)
{
if
(
m_registeredClips
.
count
(
clip
.
first
)
==
0
)
{
...
...
@@ -1687,9 +1695,22 @@ bool ProjectClip::selfSoftDelete(Fun &undo, Fun &redo)
return
false
;
}
}
PUSH_LAMBDA
(
operation
,
redo
);
qDebug
()
<<
"===== REMOVING MASTER PRODUCER; CURRENT COUNT: "
<<
m_masterProducer
.
use_count
()
<<
"
\n
:::::::::::::::::::::::::::"
;
return
AbstractProjectItem
::
selfSoftDelete
(
undo
,
redo
);
}
Fun
ProjectClip
::
getAudio_lambda
()
{
return
[
this
]()
{
if
(
KdenliveSettings
::
audiothumbnails
()
&&
(
m_clipType
==
ClipType
::
AV
||
m_clipType
==
ClipType
::
Audio
||
m_clipType
==
ClipType
::
Playlist
)
&&
m_audioLevels
.
isEmpty
())
{
// Generate audio levels
AudioLevelsTask
::
start
({
ObjectType
::
BinClip
,
m_binId
.
toInt
()},
this
,
false
);
}
return
true
;
};
}
bool
ProjectClip
::
isIncludedInTimeline
()
{
return
m_registeredClips
.
size
()
>
0
;
...
...
@@ -2035,3 +2056,8 @@ void ProjectClip::updateJobProgress()
std
::
static_pointer_cast
<
ProjectItemModel
>
(
ptr
)
->
onItemUpdated
(
m_binId
,
AbstractProjectItem
::
JobProgress
);
}
}
void
ProjectClip
::
setInvalid
()
{
m_isInvalid
=
true
;
}
src/bin/projectclip.h
View file @
daa2c64c
...
...
@@ -103,6 +103,8 @@ public:
bool
selfSoftDelete
(
Fun
&
undo
,
Fun
&
redo
)
override
;
Fun
getAudio_lambda
()
override
;
/** @brief Returns true if item has both audio and video enabled. */
bool
hasAudioAndVideo
()
const
override
;
...
...
@@ -240,6 +242,8 @@ public:
static
const
QByteArray
getFolderHash
(
QDir
dir
,
QString
fileName
);
/** @brief Check if the clip is included in timeline and reset its occurrences on producer reload. */
void
updateTimelineOnReload
();
/** @brief If a clip is invalid on load, mark it as such so we don't try to re-insert it on undo/redo. */
void
setInvalid
();
int
getRecordTime
();
protected:
...
...
@@ -295,8 +299,6 @@ private:
const
QString
getFileHash
();
QMutex
m_producerMutex
;
QMutex
m_thumbMutex
;
QFuture
<
void
>
m_thumbThread
;
QList
<
int
>
m_requestedThumbs
;
const
QString
geometryWithOffset
(
const
QString
&
data
,
int
offset
);
QMap
<
QString
,
QByteArray
>
m_audioLevels
;
/** @brief If true, all timeline occurrences of this clip will be replaced from a fresh producer on reload. */
...
...
src/bin/projectitemmodel.cpp
View file @
daa2c64c
...
...
@@ -604,9 +604,6 @@ bool ProjectItemModel::requestBinClipDeletion(const std::shared_ptr<AbstractProj
binId
=
ptr
->
clipId
();
}
bool
isSubClip
=
clip
->
itemType
()
==
AbstractProjectItem
::
SubClipItem
;
if
(
!
isSubClip
)
{
pCore
->
taskManager
.
discardJobs
({
ObjectType
::
BinClip
,
clip
->
clipId
().
toInt
()});
}
clip
->
selfSoftDelete
(
undo
,
redo
);
int
id
=
clip
->
getId
();
Fun
operation
=
removeItem_lambda
(
id
);
...
...
@@ -625,6 +622,9 @@ bool ProjectItemModel::requestBinClipDeletion(const std::shared_ptr<AbstractProj
update_doc
();
PUSH_LAMBDA
(
update_doc
,
operation
);
PUSH_LAMBDA
(
update_doc
,
reverse
);
}
else
{
Fun
checkAudio
=
clip
->
getAudio_lambda
();
PUSH_LAMBDA
(
checkAudio
,
reverse
);
}
UPDATE_UNDO_REDO
(
operation
,
reverse
,
undo
,
redo
);
}
...
...
@@ -692,6 +692,9 @@ bool ProjectItemModel::addItem(const std::shared_ptr<AbstractProjectItem> &item,
bool
res
=
operation
();
Q_ASSERT
(
item
->
isInModel
());
if
(
res
)
{
Fun
checkAudio
=
item
->
getAudio_lambda
();
checkAudio
();
PUSH_LAMBDA
(
checkAudio
,
operation
);
UPDATE_UNDO_REDO
(
operation
,
reverse
,
undo
,
redo
);
}
return
res
;
...
...
src/core.cpp
View file @
daa2c64c
...
...
@@ -91,6 +91,7 @@ bool Core::build(bool testMode)
qRegisterMetaType
<
QVector
<
int
>>
();
qRegisterMetaType
<
QDomElement
>
(
"QDomElement"
);
qRegisterMetaType
<
requestClipInfo
>
(
"requestClipInfo"
);
qRegisterMetaType
<
QVector
<
QPair
<
QString
,
QVariant
>>>
(
"paramVector"
);
if
(
!
testMode
)
{
// Check if we had a crash
...
...
src/jobs/CMakeLists.txt
View file @
daa2c64c
...
...
@@ -8,6 +8,7 @@ set(kdenlive_SRCS
jobs/cliploadtask.cpp
jobs/proxytask.cpp
jobs/transcodetask.cpp
jobs/filtertask.cpp
jobs/jobmanager.cpp
jobs/cachejob.cpp
jobs/loadjob.cpp
...
...
src/jobs/abstracttask.cpp
View file @
daa2c64c
...
...
@@ -66,7 +66,8 @@ AbstractTask::AbstractTask(const ObjectId &owner, JOBTYPE type, QObject* object)
void
AbstractTask
::
cancelJob
()
{
m_isCanceled
=
true
;
m_isCanceled
.
testAndSetAcquire
(
0
,
1
);
qDebug
()
<<
"====== SETTING TACK CANCELED: "
<<
m_isCanceled
;
emit
jobCanceled
();
}
...
...
src/jobs/abstracttask.h
View file @
daa2c64c
...
...
@@ -22,6 +22,7 @@
#include "definitions.h"
#include <QRunnable>
#include <QAtomicInt>
#include <QMutex>
#include <QObject>
...
...
@@ -56,11 +57,10 @@ protected:
QObject
*
m_object
;
int
m_progress
;
bool
m_successful
;
bool
m_isCanceled
;
QAtomicInt
m_isCanceled
;
bool
m_isForce
;
bool
m_running
;
void
run
()
override
;
QMutex
m_runMutex
;
void
cleanup
();
private:
...
...
src/jobs/audiolevelstask.cpp
View file @
daa2c64c
...
...
@@ -63,7 +63,6 @@ void AudioLevelsTask::start(const ObjectId &owner, QObject* object, bool force)
void
AudioLevelsTask
::
run
()
{
QMutexLocker
lk
(
&
m_runMutex
);
m_running
=
true
;
// 2 channels interleaved of uchar values
if
(
m_isCanceled
)
{
...
...
@@ -210,38 +209,40 @@ void AudioLevelsTask::run()
m_audioLevels << uchar(255 * v / maxLevel);
}*/
m_progress
=
100
;
if
(
m_isCanceled
)
{
mltLevels
.
clear
();
}
QMetaObject
::
invokeMethod
(
m_object
,
"updateJobProgress"
);
if
(
!
m_isCanceled
)
{
if
(
mltLevels
.
size
()
>
0
&&
!
m_isCanceled
)
{
QVector
<
uint8_t
>*
levelsCopy
=
new
QVector
<
uint8_t
>
(
mltLevels
);
producer
->
lock
();
QString
key
=
QString
(
"_kdenlive:audio%1"
).
arg
(
stream
);
producer
->
set
(
key
.
toUtf8
().
constData
(),
levelsCopy
,
0
,
(
mlt_destructor
)
deleteQVariantList
);
producer
->
unlock
();
qDebug
()
<<
"=== FINISHED PRODUCING AUDIO FOR: "
<<
key
<<
", SIZE: "
<<
levelsCopy
->
size
();
QMetaObject
::
invokeMethod
(
m_object
,
"updateAudioThumbnail"
);
// Put into an image for caching.
int
count
=
mltLevels
.
size
();
QImage
image
((
count
+
3
)
/
4
/
channels
,
channels
,
QImage
::
Format_ARGB32
);
int
n
=
image
.
width
()
*
image
.
height
();
for
(
int
i
=
0
;
i
<
n
;
i
++
)
{
QRgb
p
;
if
((
4
*
i
+
3
)
<
count
)
{
p
=
qRgba
(
mltLevels
.
at
(
4
*
i
),
mltLevels
.
at
(
4
*
i
+
1
),
mltLevels
.
at
(
4
*
i
+
2
),
mltLevels
.
at
(
4
*
i
+
3
));
}
else
{
int
last
=
mltLevels
.
last
();
int
r
=
(
4
*
i
+
0
)
<
count
?
mltLevels
.
at
(
4
*
i
+
0
)
:
last
;
int
g
=
(
4
*
i
+
1
)
<
count
?
mltLevels
.
at
(
4
*
i
+
1
)
:
last
;
int
b
=
(
4
*
i
+
2
)
<
count
?
mltLevels
.
at
(
4
*
i
+
2
)
:
last
;
int
a
=
last
;
p
=
qRgba
(
r
,
g
,
b
,
a
);
}
image
.
setPixel
(
i
/
2
,
i
%
channels
,
p
);
if
(
mltLevels
.
size
()
>
0
)
{
QVector
<
uint8_t
>*
levelsCopy
=
new
QVector
<
uint8_t
>
(
mltLevels
);
producer
->
lock
();
QString
key
=
QString
(
"_kdenlive:audio%1"
).
arg
(
stream
);
producer
->
set
(
key
.
toUtf8
().
constData
(),
levelsCopy
,
0
,
(
mlt_destructor
)
deleteQVariantList
);
producer
->
unlock
();
qDebug
()
<<
"=== FINISHED PRODUCING AUDIO FOR: "
<<
key
<<
", SIZE: "
<<
levelsCopy
->
size
();
QMetaObject
::
invokeMethod
(
m_object
,
"updateAudioThumbnail"
);
// Put into an image for caching.
int
count
=
mltLevels
.
size
();
QImage
image
((
count
+
3
)
/
4
/
channels
,
channels
,
QImage
::
Format_ARGB32
);
int
n
=
image
.
width
()
*
image
.
height
();
for
(
int
i
=
0
;
i
<
n
;
i
++
)
{
QRgb
p
;
if
((
4
*
i
+
3
)
<
count
)
{
p
=
qRgba
(
mltLevels
.
at
(
4
*
i
),
mltLevels
.
at
(
4
*
i
+
1
),
mltLevels
.
at
(
4
*
i
+
2
),
mltLevels
.
at
(
4
*
i
+
3
));
}
else
{
int
last
=
mltLevels
.
last
();
int
r
=
(
4
*
i
+
0
)
<
count
?
mltLevels
.
at
(
4
*
i
+
0
)
:
last
;
int
g
=
(
4
*
i
+
1
)
<
count
?
mltLevels
.
at
(
4
*
i
+
1
)
:
last
;
int
b
=
(
4
*
i
+
2
)
<
count
?
mltLevels
.
at
(
4
*
i
+
2
)
:
last
;
int
a
=
last
;
p
=
qRgba
(
r
,
g
,
b
,
a
);
}
image
.
s
ave
(
cachePath
);
image
.
s
etPixel
(
i
/
2
,
i
%
channels
,
p
);
}
image
.
save
(
cachePath
);
}
}
qDebug
()
<<
"============= TASK WAS CANCELED: "
<<
m_isCanceled
<<
"
\n\n
==================="
;
pCore
->
taskManager
.
taskDone
(
m_owner
.
second
,
this
);
QMetaObject
::
invokeMethod
(
m_object
,
"updateJobProgress"
);
}
src/jobs/cliploadtask.cpp
View file @
daa2c64c
...
...
@@ -109,7 +109,7 @@ std::shared_ptr<Mlt::Producer> ClipLoadTask::loadResource(QString resource, cons
if
(
!
resource
.
startsWith
(
type
))
{
resource
.
prepend
(
type
);
}
return
std
::
make_shared
<
Mlt
::
Producer
>
(
pCore
->
get
CurrentProfile
()
->
p
rofile
(),
nullptr
,
resource
.
toUtf8
().
constData
());
return
std
::
make_shared
<
Mlt
::
Producer
>
(
*
pCore
->
get
ProjectP
rofile
(),
nullptr
,
resource
.
toUtf8
().
constData
());
}
std
::
shared_ptr
<
Mlt
::
Producer
>
ClipLoadTask
::
loadPlaylist
(
QString
&
resource
)
...
...
@@ -133,15 +133,13 @@ std::shared_ptr<Mlt::Producer> ClipLoadTask::loadPlaylist(QString &resource)
m_errorMessage
.
append
(
i18n
(
"Playlist has a different framerate (%1/%2fps), not recommended."
,
xmlProfile
->
frame_rate_num
(),
xmlProfile
->
frame_rate_den
()));
QString
loader
=
resource
;
loader
.
prepend
(
QStringLiteral
(
"consumer:"
));
pCore
->
getCurrentProfile
()
->
set_explicit
(
1
);
return
std
::
make_shared
<
Mlt
::
Producer
>
(
pCore
->
getCurrentProfile
()
->
profile
(),
loader
.
toUtf8
().
constData
());
return
std
::
make_shared
<
Mlt
::
Producer
>
(
*
pCore
->
getProjectProfile
(),
loader
.
toUtf8
().
constData
());
}
else
{
m_errorMessage
.
append
(
i18n
(
"No matching profile"
));
return
nullptr
;
}
}
pCore
->
getCurrentProfile
()
->
set_explicit
(
1
);
return
std
::
make_shared
<
Mlt
::
Producer
>
(
pCore
->
getCurrentProfile
()
->
profile
(),
"xml"
,
resource
.
toUtf8
().
constData
());
return
std
::
make_shared
<
Mlt
::
Producer
>
(
*
pCore
->
getProjectProfile
(),
"xml"
,
resource
.
toUtf8
().
constData
());
}
// Read the properties of the xml and pass them to the producer. Note that some properties like resource are ignored
...
...
@@ -180,13 +178,13 @@ void ClipLoadTask::processSlideShow(std::shared_ptr<Mlt::Producer> producer)
int
ttl
=
Xml
::
getXmlProperty
(
m_xml
,
QStringLiteral
(
"ttl"
)).
toInt
();
QString
anim
=
Xml
::
getXmlProperty
(
m_xml
,
QStringLiteral
(
"animation"
));
if
(
!
anim
.
isEmpty
())
{
auto
*
filter
=
new
Mlt
::
Filter
(
pCore
->
get
CurrentProfile
()
->
p
rofile
(),
"affine"
);
auto
*
filter
=
new
Mlt
::
Filter
(
*
pCore
->
get
ProjectP
rofile
(),
"affine"
);
if
((
filter
!=
nullptr
)
&&
filter
->
is_valid
())
{
int
cycle
=
ttl
;
QString
geometry
=
SlideshowClip
::
animationToGeometry
(
anim
,
cycle
);
if
(
!
geometry
.
isEmpty
())
{
if
(
anim
.
contains
(
QStringLiteral
(
"low-pass"
)))
{
auto
*
blur
=
new
Mlt
::
Filter
(
pCore
->
get
CurrentProfile
()
->
p
rofile
(),
"boxblur"
);
auto
*
blur
=
new
Mlt
::
Filter
(
*
pCore
->
get
ProjectP
rofile
(),
"boxblur"
);
if
((
blur
!=
nullptr
)
&&
blur
->
is_valid
())
{
producer
->
attach
(
*
blur
);
}
...
...
@@ -200,7 +198,7 @@ void ClipLoadTask::processSlideShow(std::shared_ptr<Mlt::Producer> producer)
QString
fade
=
Xml
::
getXmlProperty
(
m_xml
,
QStringLiteral
(
"fade"
));
if
(
fade
==
QLatin1String
(
"1"
))
{
// user wants a fade effect to slideshow
auto
*
filter
=
new
Mlt
::
Filter
(
pCore
->
get
CurrentProfile
()
->
p
rofile
(),
"luma"
);
auto
*
filter
=
new
Mlt
::
Filter
(
*
pCore
->
get
ProjectP
rofile
(),
"luma"
);
if
((
filter
!=
nullptr
)
&&
filter
->
is_valid
())
{
if
(
ttl
!=
0
)
{
filter
->
set
(
"cycle"
,
ttl
);
...
...
@@ -224,7 +222,7 @@ void ClipLoadTask::processSlideShow(std::shared_ptr<Mlt::Producer> producer)
QString
crop
=
Xml
::
getXmlProperty
(
m_xml
,
QStringLiteral
(
"crop"
));
if
(
crop
==
QLatin1String
(
"1"
))
{
// user wants to center crop the slides
auto
*
filter
=
new
Mlt
::
Filter
(
pCore
->
get
CurrentProfile
()
->
p
rofile
(),
"crop"
);
auto
*
filter
=
new
Mlt
::
Filter
(
*
pCore
->
get
ProjectP
rofile
(),
"crop"
);
if
((
filter
!=
nullptr
)
&&
filter
->
is_valid
())
{
filter
->
set
(
"center"
,
1
);
producer
->
attach
(
*
filter
);
...
...
@@ -244,21 +242,26 @@ void ClipLoadTask::generateThumbnail(std::shared_ptr<ProjectClip>binClip, std::s
qDebug
()
<<
"=== FOUND THUMB IN CACHe"
;
QMetaObject
::
invokeMethod
(
binClip
.
get
(),
"setThumbnail"
,
Qt
::
QueuedConnection
,
Q_ARG
(
QImage
,
result
));