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
d8fd5e44
Commit
d8fd5e44
authored
Jan 08, 2020
by
Jean-Baptiste Mardelle
Browse files
Keep last known frame as thumbnail when resizing a clip
parent
0a43afd6
Pipeline
#12947
passed with stage
in 13 minutes and 43 seconds
Changes
6
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
src/timeline2/view/qml/Clip.qml
View file @
d8fd5e44
...
...
@@ -208,9 +208,10 @@ Rectangle {
//generateWaveform()
}
*/
property
bool
variable
Thumbs
:
(
isAudio
||
itemType
==
ProducerType
.
Color
||
mltService
===
''
)
property
bool
no
Thumbs
:
(
isAudio
||
itemType
==
ProducerType
.
Color
||
mltService
===
''
)
property
bool
isImage
:
itemType
==
ProducerType
.
Image
property
string
baseThumbPath
:
variableThumbs
?
''
:
'
image://thumbnail/
'
+
binId
+
'
/
'
+
documentId
+
'
/
'
+
(
isImage
?
'
#0
'
:
'
#
'
)
property
string
baseThumbPath
:
noThumbs
?
''
:
'
image://thumbnail/
'
+
binId
+
'
/
'
+
documentId
+
'
/
'
+
(
isImage
?
'
#0
'
:
'
#
'
)
property
string
baseCacheThumbPath
:
noThumbs
?
''
:
'
image://thumbnailCache/
'
+
binId
+
'
/
'
+
(
isImage
?
'
#0
'
:
'
#
'
)
DropArea
{
//Drop area for clips
anchors.fill
:
clipRoot
...
...
@@ -291,21 +292,18 @@ Rectangle {
}
onWheel
:
zoomByWheel
(
wheel
)
Item
{
Loader
{
// Thumbs container
id
:
thumbsLoader
anchors.fill
:
parent
anchors.leftMargin
:
parentTrack
.
isAudio
?
0
:
clipRoot
.
border
.
width
anchors.rightMargin
:
parentTrack
.
isAudio
?
0
:
clipRoot
.
border
.
width
anchors.topMargin
:
clipRoot
.
border
.
width
anchors.bottomMargin
:
clipRoot
.
border
.
width
clip
:
true
Loader
{
id
:
thumbsLoader
asynchronous
:
true
visible
:
status
==
Loader
.
Ready
anchors.fill
:
parent
source
:
clipRoot
.
hideClipViews
?
""
:
parentTrack
.
isAudio
?
(
timeline
.
showAudioThumbnails
?
"
ClipAudioThumbs.qml
"
:
""
)
:
itemType
==
ProducerType
.
Color
?
""
:
timeline
.
showThumbnails
?
"
ClipThumbs.qml
"
:
""
}
asynchronous
:
true
visible
:
status
==
Loader
.
Ready
source
:
clipRoot
.
hideClipViews
?
""
:
parentTrack
.
isAudio
?
(
timeline
.
showAudioThumbnails
?
"
ClipAudioThumbs.qml
"
:
""
)
:
itemType
==
ProducerType
.
Color
?
""
:
timeline
.
showThumbnails
?
"
ClipThumbs.qml
"
:
""
}
Item
{
...
...
src/timeline2/view/qml/ClipThumbs.qml
View file @
d8fd5e44
...
...
@@ -37,9 +37,48 @@ Row {
fillMode
:
Image
.
PreserveAspectFit
asynchronous
:
true
cache
:
enableCache
property
int
currentFrame
:
Math
.
floor
(
clipRoot
.
inPoint
+
Math
.
round
((
index
)
*
width
/
timeline
.
scaleFactor
)
*
clipRoot
.
speed
)
property
int
currentFrame
:
thumbRepeater
.
count
<
3
?
(
index
==
0
?
thumbRepeater
.
thumbStartFrame
:
thumbRepeater
.
thumbEndFrame
)
:
Math
.
floor
(
clipRoot
.
inPoint
+
Math
.
round
((
index
)
*
width
/
timeline
.
scaleFactor
)
*
clipRoot
.
speed
)
property
int
lastFrame
:
-
1
horizontalAlignment
:
thumbRepeater
.
count
<
3
?
(
index
==
0
?
Image
.
AlignLeft
:
Image
.
AlignRight
)
:
Image
.
AlignLeft
source
:
thumbRepeater
.
count
<
3
?
(
index
==
0
?
clipRoot
.
baseThumbPath
+
thumbRepeater
.
thumbStartFrame
:
clipRoot
.
baseThumbPath
+
thumbRepeater
.
thumbEndFrame
)
:
(
index
*
width
<
clipRoot
.
scrollStart
-
width
||
index
*
width
>
clipRoot
.
scrollStart
+
scrollView
.
viewport
.
width
)
?
''
:
clipRoot
.
baseThumbPath
+
currentFrame
source
:
thumbRepeater
.
count
<
3
?
(
clipRoot
.
baseThumbPath
+
currentFrame
)
:
(
index
*
width
<
clipRoot
.
scrollStart
-
width
||
index
*
width
>
clipRoot
.
scrollStart
+
scrollView
.
viewport
.
width
)
?
''
:
clipRoot
.
baseThumbPath
+
currentFrame
onStatusChanged
:
{
if
(
thumbRepeater
.
count
<
3
)
{
if
(
status
===
Image
.
Ready
)
{
lastFrame
=
currentFrame
}
}
}
BusyIndicator
{
running
:
parent
.
status
!=
Image
.
Ready
anchors.left
:
parent
.
left
anchors.leftMargin
:
index
<
thumbRepeater
.
count
-
1
?
0
:
parent
.
width
-
thumbRow
.
thumbWidth
-
1
implicitWidth
:
thumbRepeater
.
imageWidth
implicitHeight
:
container
.
height
contentItem
:
Image
{
id
:
thumbPlaceholder
visible
:
parent
.
running
anchors.fill
:
parent
horizontalAlignment
:
Image
.
AlignLeft
fillMode
:
Image
.
PreserveAspectFit
asynchronous
:
true
}
onRunningChanged
:
{
if
(
!
running
)
{
thumbPlaceholder
.
source
=
clipRoot
.
baseCacheThumbPath
+
parent
.
lastFrame
console
.
log
(
'
Setting image lastframe:
'
,
parent
.
lastFrame
)
}
}
}
Rectangle
{
visible
:
thumbRepeater
.
count
<
3
anchors.left
:
parent
.
left
anchors.leftMargin
:
index
<
thumbRepeater
.
count
-
1
?
thumbRow
.
thumbWidth
:
parent
.
width
-
thumbRow
.
thumbWidth
-
1
color
:
"
#ffffff
"
opacity
:
0.3
width
:
1
height
:
parent
.
height
}
}
}
}
src/timeline2/view/qmltypes/thumbnailprovider.cpp
View file @
d8fd5e44
...
...
@@ -30,7 +30,6 @@
ThumbnailProvider
::
ThumbnailProvider
()
:
QQuickImageProvider
(
QQmlImageProviderBase
::
Image
,
QQmlImageProviderBase
::
ForceAsynchronousImageLoading
)
//, m_profile(pCore->getCurrentProfilePath().toUtf8().constData())
{
}
...
...
@@ -57,40 +56,6 @@ QImage ThumbnailProvider::requestImage(const QString &id, QSize *size, const QSi
ThumbnailCache
::
get
()
->
storeThumbnail
(
binId
,
frameNumber
,
result
,
false
);
}
}
/*if (m_producers.contains(binId.toInt())) {
producer = m_producers.object(binId.toInt());
} else {
m_binClip->thumbProducer();
if (!resource.isEmpty()) {
producer = new Mlt::Producer(m_profile, service.toUtf8().constData(), resource.toUtf8().constData());
} else {
producer = new Mlt::Producer(m_profile, service.toUtf8().constData());
}
std::shared_ptr<ProjectClip> binClip = pCore->projectItemModel()->getClipByBinID(binId);
if (binClip) {
std::shared_ptr<Mlt::Producer> projectProducer = binClip->originalProducer();
Mlt::Properties original(projectProducer->get_properties());
Mlt::Properties cloneProps(producer->get_properties());
cloneProps.pass_list(original, "video_index,force_aspect_num,force_aspect_den,force_aspect_ratio,force_fps,force_progressive,force_tff,"
"force_colorspace,set.force_full_luma,templatetext,autorotate,xmldata");
}
Mlt::Filter scaler(m_profile, "swscale");
Mlt::Filter padder(m_profile, "resize");
Mlt::Filter converter(m_profile, "avcolor_space");
producer->attach(scaler);
producer->attach(padder);
producer->attach(converter);
m_producers.insert(binId.toInt(), producer);
}
if ((producer != nullptr) && producer->is_valid()) {
// result = KThumb::getFrame(producer, frameNumber, 0, 0);
result = makeThumbnail(producer, frameNumber, requestedSize);
ThumbnailCache::get()->storeThumbnail(binId, frameNumber, result, false);
//m_cache->insertImage(key, result);
} else {
qDebug() << "INVALID PRODUCER; " << service << " / " << resource;
}*/
}
if
(
size
)
*
size
=
result
.
size
();
return
result
;
...
...
@@ -122,13 +87,8 @@ QImage ThumbnailProvider::makeThumbnail(const std::shared_ptr<Mlt::Producer> &pr
if
(
frame
==
nullptr
||
!
frame
->
is_valid
())
{
return
QImage
();
}
int
ow
=
0
;
// requestedSize.width();
int
oh
=
0
;
// requestedSize.height();
/*if (ow > 0 && oh > 0) {
frame->set("rescale.interp", "fastest");
frame->set("deinterlace_method", "onefield");
frame->set("top_field_first", -1);
}*/
int
ow
=
0
;
int
oh
=
0
;
mlt_image_format
format
=
mlt_image_rgb24a
;
const
uchar
*
image
=
frame
->
get_image
(
format
,
ow
,
oh
);
if
(
image
)
{
...
...
@@ -138,3 +98,28 @@ QImage ThumbnailProvider::makeThumbnail(const std::shared_ptr<Mlt::Producer> &pr
}
return
QImage
();
}
ThumbnailCacheProvider
::
ThumbnailCacheProvider
()
:
QQuickImageProvider
(
QQmlImageProviderBase
::
Image
,
QQmlImageProviderBase
::
ForceAsynchronousImageLoading
)
{
}
ThumbnailCacheProvider
::~
ThumbnailCacheProvider
()
=
default
;
QImage
ThumbnailCacheProvider
::
requestImage
(
const
QString
&
id
,
QSize
*
size
,
const
QSize
&
requestedSize
)
{
QImage
result
;
// id is binID/#frameNumber
QString
binId
=
id
.
section
(
'/'
,
0
,
0
);
bool
ok
;
int
frameNumber
=
id
.
section
(
'#'
,
-
1
).
toInt
(
&
ok
);
if
(
ok
)
{
if
(
ThumbnailCache
::
get
()
->
hasThumbnail
(
binId
,
frameNumber
,
false
))
{
result
=
ThumbnailCache
::
get
()
->
getThumbnail
(
binId
,
frameNumber
);
*
size
=
result
.
size
();
return
result
;
}
}
if
(
size
)
*
size
=
result
.
size
();
return
result
;
}
src/timeline2/view/qmltypes/thumbnailprovider.h
View file @
d8fd5e44
...
...
@@ -34,9 +34,16 @@ public:
QImage
requestImage
(
const
QString
&
id
,
QSize
*
size
,
const
QSize
&
requestedSize
)
override
;
private:
QString
cacheKey
(
Mlt
::
Properties
&
properties
,
const
QString
&
service
,
const
QString
&
resource
,
const
QString
&
hash
,
int
frameNumber
);
QImage
makeThumbnail
(
const
std
::
shared_ptr
<
Mlt
::
Producer
>
&
producer
,
int
frameNumber
,
const
QSize
&
requestedSize
);
QCache
<
int
,
Mlt
::
Producer
>
m_producers
;
QString
cacheKey
(
Mlt
::
Properties
&
properties
,
const
QString
&
service
,
const
QString
&
resource
,
const
QString
&
hash
,
int
frameNumber
);
};
class
ThumbnailCacheProvider
:
public
QQuickImageProvider
{
public:
explicit
ThumbnailCacheProvider
();
~
ThumbnailCacheProvider
()
override
;
QImage
requestImage
(
const
QString
&
id
,
QSize
*
size
,
const
QSize
&
requestedSize
)
override
;
};
#endif // THUMBNAILPROVIDER_H
src/timeline2/view/timelinewidget.cpp
View file @
d8fd5e44
...
...
@@ -81,8 +81,8 @@ TimelineWidget::TimelineWidget(QWidget *parent)
connect
(
m_proxy
,
&
TimelineController
::
zoneMoved
,
this
,
&
TimelineWidget
::
zoneMoved
);
connect
(
m_proxy
,
&
TimelineController
::
ungrabHack
,
this
,
&
TimelineWidget
::
slotUngrabHack
);
setResizeMode
(
QQuickWidget
::
SizeRootObjectToView
);
m_
thumbnail
er
=
new
ThumbnailProvider
;
engine
()
->
addImageProvider
(
QStringLiteral
(
"thumbnail
"
),
m_thumbnail
er
);
engine
()
->
addImageProvider
(
QStringLiteral
(
"
thumbnail
"
),
new
ThumbnailProvider
)
;
engine
()
->
addImageProvider
(
QStringLiteral
(
"thumbnail
Cache"
),
new
ThumbnailCacheProvid
er
);
setVisible
(
false
);
setFont
(
QFontDatabase
::
systemFont
(
QFontDatabase
::
SmallestReadableFont
));
setFocusPolicy
(
Qt
::
StrongFocus
);
...
...
src/timeline2/view/timelinewidget.h
View file @
d8fd5e44
...
...
@@ -71,7 +71,6 @@ private slots:
void
slotUngrabHack
();
private:
ThumbnailProvider
*
m_thumbnailer
;
TimelineController
*
m_proxy
;
static
const
int
comboScale
[];
std
::
shared_ptr
<
AssetTreeModel
>
m_transitionModel
;
...
...
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