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
5eadcd26
Commit
5eadcd26
authored
May 12, 2020
by
Jean-Baptiste Mardelle
Browse files
Multi stream clips: display all active streams thumbnails in clip monitor
parent
dea6b187
Pipeline
#20051
passed with stage
in 9 minutes and 26 seconds
Changes
6
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
src/monitor/monitor.cpp
View file @
5eadcd26
...
...
@@ -295,13 +295,8 @@ Monitor::Monitor(Kdenlive::MonitorId id, MonitorManager *manager, QWidget *paren
}
if
(
!
enabledStreams
.
isEmpty
())
{
// Only 1 stream wanted, easy
m_glMonitor
->
getControllerProxy
()
->
setAudioStream
(
enabledStreams
.
first
());
QMap
<
QString
,
QString
>
props
;
props
.
insert
(
QStringLiteral
(
"audio_index"
),
QString
::
number
(
enabledStreams
.
firstKey
()));
if
(
enabledStreams
.
count
()
>
1
)
{
// Mix audio channels
}
QList
<
int
>
streams
=
enabledStreams
.
keys
();
QStringList
astreams
;
for
(
const
int
st
:
streams
)
{
...
...
@@ -311,7 +306,6 @@ Monitor::Monitor(Kdenlive::MonitorId id, MonitorManager *manager, QWidget *paren
m_controller
->
setProperties
(
props
,
true
);
}
else
{
// No active stream
m_glMonitor
->
getControllerProxy
()
->
setAudioStream
(
QString
());
QMap
<
QString
,
QString
>
props
;
props
.
insert
(
QStringLiteral
(
"audio_index"
),
QStringLiteral
(
"-1"
));
props
.
insert
(
QStringLiteral
(
"kdenlive:active_streams"
),
QStringLiteral
(
"-1"
));
...
...
@@ -1462,7 +1456,13 @@ void Monitor::slotOpenClip(const std::shared_ptr<ProjectClip> &controller, int i
if
(
audioStreamsInfo
.
size
()
>
1
)
{
// Multi stream clip
QMapIterator
<
int
,
QString
>
i
(
audioStreamsInfo
);
QList
<
int
>
activeStreams
=
m_controller
->
activeStreams
().
keys
();
QMap
<
int
,
QString
>
activeStreams
=
m_controller
->
activeStreams
();
if
(
activeStreams
.
size
()
>
1
)
{
m_glMonitor
->
getControllerProxy
()
->
setAudioStream
(
i18n
(
"%1 audio streams"
,
activeStreams
.
size
()));
// TODO: Mix audio channels
}
else
{
m_glMonitor
->
getControllerProxy
()
->
setAudioStream
(
m_controller
->
activeStreams
().
first
());
}
QAction
*
ac
;
while
(
i
.
hasNext
())
{
i
.
next
();
...
...
@@ -1471,7 +1471,6 @@ void Monitor::slotOpenClip(const std::shared_ptr<ProjectClip> &controller, int i
ac
->
setCheckable
(
true
);
if
(
activeStreams
.
contains
(
i
.
key
()))
{
ac
->
setChecked
(
true
);
m_glMonitor
->
getControllerProxy
()
->
setAudioStream
(
ac
->
text
().
remove
(
QLatin1Char
(
'&'
)));
}
}
ac
=
m_audioChannels
->
addAction
(
i18n
(
"Merge all streams"
));
...
...
@@ -1517,7 +1516,7 @@ void Monitor::slotOpenClip(const std::shared_ptr<ProjectClip> &controller, int i
}
m_audioMeterWidget
->
audioChannels
=
controller
->
audioInfo
()
?
controller
->
audioInfo
()
->
channels
()
:
0
;
if
(
!
m_controller
->
hasVideo
()
||
KdenliveSettings
::
displayClipMonitorInfo
()
&
0x10
)
{
m_glMonitor
->
getControllerProxy
()
->
setAudioThumb
(
m_audioMeterWidget
->
audioChannels
==
0
?
QUrl
()
:
ThumbnailCache
::
get
()
->
getAudioThumbPath
(
m_controller
->
clipId
()));
m_glMonitor
->
getControllerProxy
()
->
setAudioThumb
(
m_audioMeterWidget
->
audioChannels
==
0
?
QList
<
QUrl
>
()
:
ThumbnailCache
::
get
()
->
getAudioThumbPath
(
m_controller
->
clipId
()));
}
m_controller
->
getMarkerModel
()
->
registerSnapModel
(
m_snaps
);
m_glMonitor
->
getControllerProxy
()
->
setClipProperties
(
controller
->
clipId
().
toInt
(),
controller
->
clipType
(),
controller
->
hasAudioAndVideo
(),
controller
->
clipName
());
...
...
@@ -1549,7 +1548,13 @@ void Monitor::reloadActiveStream()
QList
<
int
>
activeStreams
=
m_controller
->
activeStreams
().
keys
();
QMap
<
int
,
QString
>
streams
=
m_controller
->
audioStreams
();
qDebug
()
<<
"==== REFRESHING MONITOR STREAMS: "
<<
activeStreams
;
bool
displayedStream
=
false
;
if
(
activeStreams
.
size
()
>
1
)
{
m_glMonitor
->
getControllerProxy
()
->
setAudioStream
(
i18n
(
"%1 audio streams"
,
activeStreams
.
size
()));
// TODO: Mix audio channels
}
else
{
m_glMonitor
->
getControllerProxy
()
->
setAudioStream
(
m_controller
->
activeStreams
().
first
());
}
prepareAudioThumb
();
for
(
auto
ac
:
acts
)
{
int
val
=
ac
->
data
().
toInt
();
if
(
streams
.
contains
(
val
))
{
...
...
@@ -1558,10 +1563,6 @@ void Monitor::reloadActiveStream()
}
if
(
activeStreams
.
contains
(
val
))
{
ac
->
setChecked
(
true
);
if
(
!
displayedStream
)
{
m_glMonitor
->
getControllerProxy
()
->
setAudioStream
(
ac
->
text
().
remove
(
QLatin1Char
(
'&'
)));
displayedStream
=
true
;
}
}
else
{
ac
->
setChecked
(
false
);
}
...
...
src/monitor/monitorproxy.cpp
View file @
5eadcd26
...
...
@@ -328,7 +328,7 @@ void MonitorProxy::setClipProperties(int clipId, ClipType::ProducerType type, bo
}
}
void
MonitorProxy
::
setAudioThumb
(
const
QUrl
thumbPath
)
void
MonitorProxy
::
setAudioThumb
(
const
QList
<
QUrl
>
thumbPath
)
{
m_audioThumb
=
thumbPath
;
emit
audioThumbChanged
();
...
...
src/monitor/monitorproxy.h
View file @
5eadcd26
...
...
@@ -44,7 +44,7 @@ class MonitorProxy : public QObject
Q_PROPERTY
(
int
zoneOut
READ
zoneOut
WRITE
setZoneOut
NOTIFY
zoneChanged
)
Q_PROPERTY
(
int
rulerHeight
READ
rulerHeight
NOTIFY
rulerHeightChanged
)
Q_PROPERTY
(
QString
markerComment
READ
markerComment
NOTIFY
markerCommentChanged
)
Q_PROPERTY
(
QUrl
audioThumb
MEMBER
m_audioThumb
NOTIFY
audioThumbChanged
)
Q_PROPERTY
(
QList
<
QUrl
>
audioThumb
MEMBER
m_audioThumb
NOTIFY
audioThumbChanged
)
Q_PROPERTY
(
int
overlayType
READ
overlayType
WRITE
setOverlayType
NOTIFY
overlayTypeChanged
)
/** @brief: Returns true if current clip in monitor has Audio and Video
* */
...
...
@@ -91,7 +91,7 @@ public:
Q_INVOKABLE
double
fps
()
const
;
QPoint
profile
();
void
setClipProperties
(
int
clipId
,
ClipType
::
ProducerType
type
,
bool
hasAV
,
const
QString
clipName
);
void
setAudioThumb
(
const
QUrl
thumbPath
=
QUrl
());
void
setAudioThumb
(
const
QList
<
QUrl
>
thumbPath
=
QList
<
QUrl
>
());
void
setAudioStream
(
const
QString
&
name
);
signals:
...
...
@@ -125,7 +125,7 @@ private:
int
m_zoneIn
;
int
m_zoneOut
;
bool
m_hasAV
;
QUrl
m_audioThumb
;
QList
<
QUrl
>
m_audioThumb
;
QString
m_markerComment
;
QString
m_clipName
;
QString
m_clipStream
;
...
...
src/monitor/view/kdenliveclipmonitor.qml
View file @
5eadcd26
...
...
@@ -176,10 +176,28 @@ Item {
width
:
(
controller
.
zoneOut
-
controller
.
zoneIn
)
*
timeScale
visible
:
controller
.
zoneIn
>
0
||
controller
.
zoneOut
<
duration
-
1
}
Image
{
anchors.fill
:
parent
source
:
controller
.
audioThumb
asynchronous
:
true
Repeater
{
id
:
streamThumb
model
:
controller
.
audioThumb
.
length
property
double
streamHeight
:
parent
.
height
/
streamThumb
.
count
Item
{
anchors.fill
:
parent
Image
{
anchors.left
:
parent
.
left
anchors.right
:
parent
.
right
height
:
streamThumb
.
streamHeight
y
:
model
.
index
*
height
source
:
controller
.
audioThumb
[
model
.
index
]
asynchronous
:
true
}
Rectangle
{
width
:
parent
.
width
y
:
(
model
.
index
+
1
)
*
streamThumb
.
streamHeight
height
:
1
visible
:
streamThumb
.
count
>
1
&&
model
.
index
<
streamThumb
.
count
-
1
color
:
'
black
'
}
}
}
Rectangle
{
color
:
"
red
"
...
...
src/utils/thumbnailcache.cpp
View file @
5eadcd26
...
...
@@ -110,7 +110,7 @@ bool ThumbnailCache::hasThumbnail(const QString &binId, int pos, bool volatileOn
{
QMutexLocker
locker
(
&
m_mutex
);
bool
ok
=
false
;
auto
key
=
pos
<
0
?
getAudioKey
(
binId
,
&
ok
)
:
getKey
(
binId
,
pos
,
&
ok
);
auto
key
=
pos
<
0
?
getAudioKey
(
binId
,
&
ok
)
.
first
()
:
getKey
(
binId
,
pos
,
&
ok
);
if
(
ok
&&
m_volatileCache
->
contains
(
key
))
{
return
true
;
}
...
...
@@ -125,7 +125,7 @@ QImage ThumbnailCache::getAudioThumbnail(const QString &binId, bool volatileOnly
{
QMutexLocker
locker
(
&
m_mutex
);
bool
ok
=
false
;
auto
key
=
getAudioKey
(
binId
,
&
ok
);
auto
key
=
getAudioKey
(
binId
,
&
ok
)
.
first
()
;
if
(
ok
&&
m_volatileCache
->
contains
(
key
))
{
return
m_volatileCache
->
get
(
key
);
}
...
...
@@ -140,16 +140,21 @@ QImage ThumbnailCache::getAudioThumbnail(const QString &binId, bool volatileOnly
return
QImage
();
}
const
QUrl
ThumbnailCache
::
getAudioThumbPath
(
const
QString
&
binId
)
const
const
QList
<
QUrl
>
ThumbnailCache
::
getAudioThumbPath
(
const
QString
&
binId
)
const
{
QMutexLocker
locker
(
&
m_mutex
);
bool
ok
=
false
;
auto
key
=
getAudioKey
(
binId
,
&
ok
);
QDir
thumbFolder
=
getDir
(
true
,
&
ok
);
if
(
ok
&&
thumbFolder
.
exists
(
key
))
{
return
QUrl
::
fromLocalFile
(
thumbFolder
.
absoluteFilePath
(
key
));
QList
<
QUrl
>
pathList
;
if
(
ok
)
{
for
(
const
QString
&
p
:
key
)
{
if
(
thumbFolder
.
exists
(
p
))
{
pathList
<<
QUrl
::
fromLocalFile
(
thumbFolder
.
absoluteFilePath
(
p
));
}
}
}
return
QUrl
()
;
return
pathList
;
}
QImage
ThumbnailCache
::
getThumbnail
(
const
QString
&
binId
,
int
pos
,
bool
volatileOnly
)
const
...
...
@@ -242,7 +247,9 @@ void ThumbnailCache::invalidateThumbsForClip(const QString &binId, bool reloadAu
if
(
reloadAudio
)
{
auto
key
=
getAudioKey
(
binId
,
&
ok
);
if
(
ok
)
{
QFile
::
remove
(
audioThumbFolder
.
absoluteFilePath
(
key
));
for
(
const
QString
&
p
:
key
)
{
QFile
::
remove
(
audioThumbFolder
.
absoluteFilePath
(
p
));
}
}
}
}
else
{
...
...
@@ -277,18 +284,38 @@ QString ThumbnailCache::getKey(const QString &binId, int pos, bool *ok)
}
// static
QString
ThumbnailCache
::
getAudioKey
(
const
QString
&
binId
,
bool
*
ok
)
QString
List
ThumbnailCache
::
getAudioKey
(
const
QString
&
binId
,
bool
*
ok
)
{
auto
binClip
=
pCore
->
projectItemModel
()
->
getClipByBinID
(
binId
);
*
ok
=
binClip
!=
nullptr
;
if
(
ok
)
{
int
audio
=
binClip
->
getProducerIntProperty
(
QStringLiteral
(
"audio_index"
));
if
(
audio
>
-
1
)
{
return
binClip
->
hash
()
+
QLatin1Char
(
'_'
)
+
QString
::
number
(
audio
)
+
QStringLiteral
(
".png"
);
QString
streams
=
binClip
->
getProducerProperty
(
QStringLiteral
(
"kdenlive:active_streams"
));
if
(
streams
.
isEmpty
())
{
// activate all audio streams
QList
<
int
>
streamIxes
=
binClip
->
audioStreams
().
keys
();
if
(
streamIxes
.
size
()
>
1
)
{
QStringList
streamsList
;
for
(
const
int
st
:
streamIxes
)
{
streamsList
<<
QString
(
"%1_%2.png"
).
arg
(
binClip
->
hash
()).
arg
(
st
);
}
return
streamsList
;
}
}
if
(
streams
.
size
()
==
1
)
{
int
audio
=
binClip
->
getProducerIntProperty
(
QStringLiteral
(
"audio_index"
));
if
(
audio
>
-
1
)
{
return
{
QString
(
"%1_%2.png"
).
arg
(
binClip
->
hash
()).
arg
(
audio
)};
}
return
{
binClip
->
hash
()
+
QStringLiteral
(
".png"
)};
}
QStringList
streamsList
;
QStringList
streamIndexes
=
streams
.
split
(
QLatin1Char
(
';'
));
for
(
const
QString
st
:
streamIndexes
)
{
streamsList
<<
QString
(
"%1_%2.png"
).
arg
(
binClip
->
hash
()).
arg
(
st
);
}
return
binClip
->
hash
()
+
QStringLiteral
(
".png"
)
;
return
streamsList
;
}
return
QString
()
;
return
{}
;
}
// static
...
...
src/utils/thumbnailcache.hpp
View file @
5eadcd26
...
...
@@ -61,7 +61,7 @@ public:
*/
QImage
getThumbnail
(
const
QString
&
binId
,
int
pos
,
bool
volatileOnly
=
false
)
const
;
QImage
getAudioThumbnail
(
const
QString
&
binId
,
bool
volatileOnly
=
false
)
const
;
const
QUrl
getAudioThumbPath
(
const
QString
&
binId
)
const
;
const
QList
<
QUrl
>
getAudioThumbPath
(
const
QString
&
binId
)
const
;
/* @brief Get a given thumbnail from the cache
@param binId is the id of the queried clip
...
...
@@ -85,7 +85,7 @@ protected:
// Return the key associated to a thumbnail
static
QString
getKey
(
const
QString
&
binId
,
int
pos
,
bool
*
ok
);
static
QString
getAudioKey
(
const
QString
&
binId
,
bool
*
ok
);
static
QString
List
getAudioKey
(
const
QString
&
binId
,
bool
*
ok
);
// Return the dir where the persistent cache lives
static
QDir
getDir
(
bool
audio
,
bool
*
ok
);
...
...
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