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
a5c00441
Commit
a5c00441
authored
May 10, 2020
by
Jean-Baptiste Mardelle
Browse files
WIP: improved multistream audio workflow
- Allow selecting multiple streams - Allow renaming streams from clip properties panel
parent
425cce14
Pipeline
#19962
passed with stage
in 9 minutes and 30 seconds
Changes
13
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
src/bin/bin.cpp
View file @
a5c00441
...
...
@@ -2373,7 +2373,7 @@ void Bin::showClipProperties(const std::shared_ptr<ProjectClip> &clip, bool forc
}
m_propertiesPanel
->
setProperty
(
"clipId"
,
clip
->
AbstractProjectItem
::
clipId
());
// Setup timeline targets
emit
setupTargets
(
clip
->
hasVideo
(),
clip
->
a
udio
Streams
());
emit
setupTargets
(
clip
->
hasVideo
(),
clip
->
a
ctive
Streams
());
auto
*
lay
=
static_cast
<
QVBoxLayout
*>
(
m_propertiesPanel
->
layout
());
if
(
lay
==
nullptr
)
{
lay
=
new
QVBoxLayout
(
m_propertiesPanel
);
...
...
@@ -2420,6 +2420,17 @@ void Bin::reloadMonitorStreamIfActive(const QString &id)
}
}
void
Bin
::
updateTargets
(
const
QString
&
id
)
{
if
(
m_monitor
->
activeClipId
()
!=
id
)
{
return
;
}
std
::
shared_ptr
<
ProjectClip
>
clip
=
m_itemModel
->
getClipByBinID
(
id
);
if
(
clip
)
{
emit
setupTargets
(
clip
->
hasVideo
(),
clip
->
activeStreams
());
}
}
QStringList
Bin
::
getBinFolderClipIds
(
const
QString
&
id
)
const
{
QStringList
ids
;
...
...
src/bin/bin.h
View file @
a5c00441
...
...
@@ -221,6 +221,8 @@ public:
void
reloadMonitorIfActive
(
const
QString
&
id
);
/** @brief refresh monitor stream selector */
void
reloadMonitorStreamIfActive
(
const
QString
&
id
);
/** @brief Update timeline targets according to selected audio streams */
void
updateTargets
(
const
QString
&
id
);
void
doMoveClip
(
const
QString
&
id
,
const
QString
&
newParentId
);
void
doMoveFolder
(
const
QString
&
id
,
const
QString
&
newParentId
);
...
...
src/bin/projectclip.cpp
View file @
a5c00441
...
...
@@ -983,7 +983,7 @@ void ProjectClip::setProperties(const QMap<QString, QString> &properties, bool r
QStringLiteral
(
"force_colorspace"
),
QStringLiteral
(
"force_tff"
),
QStringLiteral
(
"force_progressive"
),
QStringLiteral
(
"video_delay"
)
};
QStringList
forceReloadProperties
{
QStringLiteral
(
"autorotate"
),
QStringLiteral
(
"templatetext"
),
QStringLiteral
(
"resource"
),
QStringLiteral
(
"force_fps"
),
QStringLiteral
(
"set.test_image"
),
QStringLiteral
(
"set.test_audio"
),
QStringLiteral
(
"force_fps"
),
QStringLiteral
(
"set.test_image"
),
QStringLiteral
(
"video_index"
)};
QStringList
keys
{
QStringLiteral
(
"luma_duration"
),
QStringLiteral
(
"luma_file"
),
QStringLiteral
(
"fade"
),
QStringLiteral
(
"ttl"
),
QStringLiteral
(
"softness"
),
QStringLiteral
(
"crop"
),
QStringLiteral
(
"animation"
)};
...
...
@@ -1102,6 +1102,15 @@ void ProjectClip::setProperties(const QMap<QString, QString> &properties, bool r
updateTimelineClips
(
updateRoles
);
}
}
else
{
if
(
properties
.
contains
(
QStringLiteral
(
"kdenlive:active_streams"
))
&&
m_audioInfo
)
{
// Clip is a multi audio stream and currently in clip monitor, update target tracks
m_audioInfo
->
updateActiveStreams
(
properties
.
value
(
QStringLiteral
(
"kdenlive:active_streams"
)));
pCore
->
bin
()
->
updateTargets
(
clipId
());
if
(
!
audioStreamChanged
)
{
pCore
->
bin
()
->
reloadMonitorStreamIfActive
(
clipId
());
refreshPanel
=
true
;
}
}
if
(
audioStreamChanged
)
{
refreshAudioInfo
();
audioThumbReady
();
...
...
@@ -1564,3 +1573,16 @@ void ProjectClip::setClipStatus(AbstractProjectItem::CLIPSTATUS status)
AbstractProjectItem
::
IconOverlay
);
}
}
void
ProjectClip
::
renameAudioStream
(
int
id
,
QString
name
)
{
if
(
m_audioInfo
)
{
m_audioInfo
->
renameStream
(
id
,
name
);
QString
prop
=
QString
(
"kdenlive:streamname.%1"
).
arg
(
id
);
m_masterProducer
->
set
(
prop
.
toUtf8
().
constData
(),
name
.
toUtf8
().
constData
());
if
(
m_audioInfo
->
activeStreams
().
keys
().
contains
(
id
))
{
pCore
->
bin
()
->
updateTargets
(
clipId
());
}
pCore
->
bin
()
->
reloadMonitorStreamIfActive
(
clipId
());
}
}
src/bin/projectclip.h
View file @
a5c00441
...
...
@@ -230,6 +230,9 @@ public:
*/
int
getAudioStreamFfmpegIndex
(
int
mltStream
);
void
setClipStatus
(
AbstractProjectItem
::
CLIPSTATUS
status
)
override
;
/** @brief Rename an audio stream for this clip
*/
void
renameAudioStream
(
int
id
,
QString
name
)
override
;
protected:
friend
class
ClipModel
;
...
...
src/lib/audio/audioStreamInfo.cpp
View file @
a5c00441
...
...
@@ -33,35 +33,45 @@ AudioStreamInfo::AudioStreamInfo(const std::shared_ptr<Mlt::Producer> &producer,
memset
(
property
,
0
,
200
);
snprintf
(
property
,
sizeof
(
property
),
"meta.media.%d.codec.channels"
,
ix
);
int
chan
=
producer
->
get_int
(
property
);
QString
channelDescription
=
QString
(
"%1|"
).
arg
(
streamIndex
++
);
switch
(
chan
)
{
case
1
:
channelDescription
.
append
(
i18n
(
"Mono "
));
break
;
case
2
:
channelDescription
.
append
(
i18n
(
"Stereo "
));
break
;
default:
channelDescription
.
append
(
i18n
(
"%1 channels "
,
chan
));
break
;
}
// Frequency
memset
(
property
,
0
,
200
);
snprintf
(
property
,
sizeof
(
property
),
"meta.media.%d.codec.sample_rate"
,
ix
);
QString
frequency
(
producer
->
get
(
property
));
if
(
frequency
.
endsWith
(
QLatin1String
(
"000"
)))
{
frequency
.
chop
(
3
);
frequency
.
append
(
i18n
(
"kHz "
));
snprintf
(
property
,
sizeof
(
property
),
"kdenlive:streamname.%d"
,
ix
);
QString
channelDescription
=
producer
->
get
(
property
);
if
(
channelDescription
.
isEmpty
())
{
channelDescription
=
QString
(
"%1|"
).
arg
(
streamIndex
++
);
switch
(
chan
)
{
case
1
:
channelDescription
.
append
(
i18n
(
"Mono "
));
break
;
case
2
:
channelDescription
.
append
(
i18n
(
"Stereo "
));
break
;
default:
channelDescription
.
append
(
i18n
(
"%1 channels "
,
chan
));
break
;
}
// Frequency
memset
(
property
,
0
,
200
);
snprintf
(
property
,
sizeof
(
property
),
"meta.media.%d.codec.sample_rate"
,
ix
);
QString
frequency
(
producer
->
get
(
property
));
if
(
frequency
.
endsWith
(
QLatin1String
(
"000"
)))
{
frequency
.
chop
(
3
);
frequency
.
append
(
i18n
(
"kHz "
));
}
else
{
frequency
.
append
(
i18n
(
"Hz "
));
}
channelDescription
.
append
(
frequency
);
memset
(
property
,
0
,
200
);
snprintf
(
property
,
sizeof
(
property
),
"meta.media.%d.codec.name"
,
ix
);
channelDescription
.
append
(
producer
->
get
(
property
));
}
else
{
frequency
.
append
(
i18n
(
"Hz "
))
;
streamIndex
++
;
}
channelDescription
.
append
(
frequency
);
memset
(
property
,
0
,
200
);
snprintf
(
property
,
sizeof
(
property
),
"meta.media.%d.codec.name"
,
ix
);
channelDescription
.
append
(
producer
->
get
(
property
));
m_audioStreams
.
insert
(
ix
,
channelDescription
);
}
}
QString
active
=
producer
->
get
(
"kdenlive:active_streams"
);
updateActiveStreams
(
active
);
if
(
audioStreamIndex
>
-
1
)
{
QByteArray
key
;
key
=
QStringLiteral
(
"meta.media.%1.codec.sample_fmt"
).
arg
(
audioStreamIndex
).
toLocal8Bit
();
...
...
@@ -75,7 +85,6 @@ AudioStreamInfo::AudioStreamInfo(const std::shared_ptr<Mlt::Producer> &producer,
key
=
QStringLiteral
(
"meta.media.%1.codec.channels"
).
arg
(
audioStreamIndex
).
toLocal8Bit
();
m_channels
=
producer
->
get_int
(
key
.
data
());
setAudioIndex
(
producer
,
m_audioStreamIndex
);
}
}
...
...
@@ -97,6 +106,19 @@ QMap <int, QString> AudioStreamInfo::streams() const
return
m_audioStreams
;
}
QMap
<
int
,
QString
>
AudioStreamInfo
::
activeStreams
()
const
{
QMap
<
int
,
QString
>
active
;
QMapIterator
<
int
,
QString
>
i
(
m_audioStreams
);
while
(
i
.
hasNext
())
{
i
.
next
();
if
(
m_activeStreams
.
contains
(
i
.
key
()))
{
active
.
insert
(
i
.
key
(),
i
.
value
());
}
}
return
active
;
}
int
AudioStreamInfo
::
bitrate
()
const
{
return
m_bitRate
;
...
...
@@ -137,3 +159,25 @@ void AudioStreamInfo::setAudioIndex(const std::shared_ptr<Mlt::Producer> &produc
}
}
void
AudioStreamInfo
::
updateActiveStreams
(
const
QString
&
activeStreams
)
{
// -1 = disable all audio
// empty = enable all audio
m_activeStreams
.
clear
();
if
(
activeStreams
.
isEmpty
())
{
m_activeStreams
=
m_audioStreams
.
keys
();
return
;
}
QStringList
st
=
activeStreams
.
split
(
QLatin1Char
(
';'
));
for
(
const
QString
&
s
:
st
)
{
m_activeStreams
<<
s
.
toInt
();
}
}
void
AudioStreamInfo
::
renameStream
(
int
ix
,
const
QString
streamName
)
{
if
(
m_audioStreams
.
contains
(
ix
))
{
m_audioStreams
.
insert
(
ix
,
streamName
);
}
}
src/lib/audio/audioStreamInfo.h
View file @
a5c00441
...
...
@@ -29,6 +29,7 @@ public:
int
samplingRate
()
const
;
int
channels
()
const
;
QMap
<
int
,
QString
>
streams
()
const
;
QMap
<
int
,
QString
>
activeStreams
()
const
;
int
bitrate
()
const
;
const
QString
&
samplingFormat
()
const
;
int
audio_index
()
const
;
...
...
@@ -36,10 +37,13 @@ public:
void
dumpInfo
()
const
;
void
setAudioIndex
(
const
std
::
shared_ptr
<
Mlt
::
Producer
>
&
producer
,
int
ix
);
QMap
<
int
,
QString
>
streamInfo
(
Mlt
::
Properties
sourceProperties
);
void
updateActiveStreams
(
const
QString
&
activeStreams
);
void
renameStream
(
int
ix
,
const
QString
streamName
);
private:
int
m_audioStreamIndex
;
QMap
<
int
,
QString
>
m_audioStreams
;
QList
<
int
>
m_activeStreams
;
int
m_ffmpegAudioIndex
;
int
m_samplingRate
;
int
m_channels
;
...
...
src/mltcontroller/clipcontroller.cpp
View file @
a5c00441
...
...
@@ -1047,6 +1047,14 @@ QMap <int, QString> ClipController::audioStreams() const
return
{};
}
QMap
<
int
,
QString
>
ClipController
::
activeStreams
()
const
{
if
(
m_audioInfo
)
{
return
m_audioInfo
->
activeStreams
();
}
return
{};
}
int
ClipController
::
audioStreamsCount
()
const
{
if
(
m_audioInfo
)
{
...
...
@@ -1054,3 +1062,4 @@ int ClipController::audioStreamsCount() const
}
return
0
;
}
src/mltcontroller/clipcontroller.h
View file @
a5c00441
...
...
@@ -97,6 +97,9 @@ public:
/** @brief Returns this clip's producer. */
virtual
std
::
shared_ptr
<
Mlt
::
Producer
>
thumbProducer
()
=
0
;
/** @brief Rename an audio stream. */
virtual
void
renameAudioStream
(
int
id
,
QString
name
)
=
0
;
/** @brief Returns the clip's duration */
GenTime
getPlaytime
()
const
;
...
...
@@ -207,8 +210,10 @@ public:
/** @brief Append an effect to this producer's effect list */
bool
addEffect
(
const
QString
&
effectId
);
/** @brief Returns the list of audio streams indexes for this clip */
/** @brief Returns the list of
all
audio streams indexes for this clip */
QMap
<
int
,
QString
>
audioStreams
()
const
;
/** @brief Returns the list of active audio streams indexes for this clip */
QMap
<
int
,
QString
>
activeStreams
()
const
;
/** @brief Returns the count of audio streams for this clip */
int
audioStreamsCount
()
const
;
...
...
src/mltcontroller/clippropertiescontroller.cpp
View file @
a5c00441
...
...
@@ -64,6 +64,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <QTextEdit>
#include <QToolBar>
#include <QUrl>
#include <QListWidgetItem>
#include <QVBoxLayout>
AnalysisTree
::
AnalysisTree
(
QWidget
*
parent
)
...
...
@@ -168,6 +169,7 @@ ClipPropertiesController::ClipPropertiesController(ClipController *controller, Q
,
m_properties
(
new
Mlt
::
Properties
(
controller
->
properties
()))
,
m_audioStream
(
nullptr
)
,
m_textEdit
(
nullptr
)
,
m_audioStreamsView
(
nullptr
)
{
m_controller
->
mirrorOriginalProperties
(
m_sourceProperties
);
setFont
(
QFontDatabase
::
systemFont
(
QFontDatabase
::
SmallestReadableFont
));
...
...
@@ -182,6 +184,7 @@ ClipPropertiesController::ClipPropertiesController(ClipController *controller, Q
m_tabWidget
->
setDocumentMode
(
true
);
m_tabWidget
->
setTabPosition
(
QTabWidget
::
East
);
auto
*
forcePage
=
new
QScrollArea
(
this
);
auto
*
forceAudioPage
=
new
QScrollArea
(
this
);
m_propertiesPage
=
new
QWidget
(
this
);
m_markersPage
=
new
QWidget
(
this
);
m_metaPage
=
new
QWidget
(
this
);
...
...
@@ -248,6 +251,11 @@ ClipPropertiesController::ClipPropertiesController(ClipController *controller, Q
// Force properties
auto
*
vbox
=
new
QVBoxLayout
;
vbox
->
setSpacing
(
0
);
// Force Audio properties
auto
*
audioVbox
=
new
QVBoxLayout
;
audioVbox
->
setSpacing
(
0
);
if
(
m_type
==
ClipType
::
Text
||
m_type
==
ClipType
::
SlideShow
||
m_type
==
ClipType
::
TextTemplate
)
{
QPushButton
*
editButton
=
new
QPushButton
(
i18n
(
"Edit Clip"
),
this
);
connect
(
editButton
,
&
QAbstractButton
::
clicked
,
this
,
&
ClipPropertiesController
::
editClip
);
...
...
@@ -598,8 +606,10 @@ ClipPropertiesController::ClipPropertiesController(ClipController *controller, Q
// Audio index
QMap
<
int
,
QString
>
audioStreamsInfo
=
m_controller
->
audioStreams
();
if
(
!
audioStreamsInfo
.
isEmpty
())
{
QList
<
int
>
enabledStreams
=
m_controller
->
activeStreams
().
keys
();
QString
vix
=
m_sourceProperties
.
get
(
"audio_index"
);
m_originalProperties
.
insert
(
QStringLiteral
(
"audio_index"
),
vix
);
m_originalProperties
.
insert
(
QStringLiteral
(
"kdenlive:active_streams"
),
m_sourceProperties
.
get
(
"kdenlive:active_streams"
));
hlay
=
new
QHBoxLayout
;
KDualAction
*
ac
=
new
KDualAction
(
i18n
(
"Disable audio"
),
i18n
(
"Enable audio"
),
this
);
...
...
@@ -610,44 +620,94 @@ ClipPropertiesController::ClipPropertiesController(ClipController *controller, Q
tbv
->
setDefaultAction
(
ac
);
tbv
->
setAutoRaise
(
true
);
hlay
->
addWidget
(
tbv
);
hlay
->
addWidget
(
new
QLabel
(
i18n
(
"Audio stream"
)));
m_audioStream
=
new
QComboBox
(
this
);
hlay
->
addWidget
(
new
QLabel
(
i18n
(
"Audio streams"
)));
audioVbox
->
addLayout
(
hlay
);
m_audioStreamsView
=
new
QListWidget
(
this
);
m_audioStreamsView
->
setSizePolicy
(
QSizePolicy
::
Preferred
,
QSizePolicy
::
MinimumExpanding
);
audioVbox
->
addWidget
(
m_audioStreamsView
);
//m_audioStream = new QComboBox(this);
QMapIterator
<
int
,
QString
>
i
(
audioStreamsInfo
);
while
(
i
.
hasNext
())
{
i
.
next
();
m_audioStream
->
addItem
(
i
.
value
(),
i
.
key
());
}
if
(
m_audioStream
->
count
()
>
1
)
{
m_audioStream
->
addItem
(
i18n
(
"Merge all streams"
),
INT_MAX
);
QListWidgetItem
*
item
=
new
QListWidgetItem
(
i
.
value
(),
m_audioStreamsView
);
item
->
setData
(
Qt
::
UserRole
,
i
.
key
());
// Store oringinal name
item
->
setData
(
Qt
::
UserRole
+
1
,
i
.
value
());
item
->
setFlags
(
Qt
::
ItemIsUserCheckable
|
Qt
::
ItemIsEnabled
|
Qt
::
ItemIsSelectable
|
Qt
::
ItemIsEditable
);
if
(
enabledStreams
.
contains
(
i
.
key
()))
{
item
->
setCheckState
(
Qt
::
Checked
);
}
else
{
item
->
setCheckState
(
Qt
::
Unchecked
);
}
}
if
(
!
vix
.
isEmpty
()
&&
vix
.
toInt
()
!=
-
1
)
{
m_audioStream
->
setCurrentIndex
(
m_audioStream
->
findData
(
QVariant
(
vix
)));
if
(
audioStreamsInfo
.
count
()
>
1
)
{
QListWidgetItem
*
item
=
new
QListWidgetItem
(
i18n
(
"Merge all streams"
),
m_audioStreamsView
);
item
->
setData
(
Qt
::
UserRole
,
INT_MAX
);
item
->
setData
(
Qt
::
UserRole
+
1
,
item
->
text
());
item
->
setFlags
(
Qt
::
ItemIsUserCheckable
|
Qt
::
ItemIsEnabled
|
Qt
::
ItemIsSelectable
);
if
(
enabledStreams
.
contains
(
INT_MAX
))
{
item
->
setCheckState
(
Qt
::
Checked
);
}
else
{
item
->
setCheckState
(
Qt
::
Unchecked
);
}
}
connect
(
m_audioStreamsView
,
&
QListWidget
::
itemChanged
,
[
this
]
(
QListWidgetItem
*
item
)
{
if
(
!
item
)
{
return
;
}
bool
checked
=
item
->
checkState
()
==
Qt
::
Checked
;
int
streamId
=
item
->
data
(
Qt
::
UserRole
).
toInt
();
bool
streamModified
=
false
;
QString
currentStreams
=
m_originalProperties
.
value
(
QStringLiteral
(
"kdenlive:active_streams"
));
QStringList
activeStreams
=
currentStreams
.
split
(
QLatin1Char
(
';'
));
if
(
activeStreams
.
contains
(
QString
::
number
(
streamId
)))
{
if
(
!
checked
)
{
// Stream was unselected
activeStreams
.
removeAll
(
QString
::
number
(
streamId
));
streamModified
=
true
;
}
}
else
if
(
checked
)
{
// Stream was selected
activeStreams
<<
QString
::
number
(
streamId
);
activeStreams
.
sort
();
streamModified
=
true
;
}
if
(
streamModified
)
{
if
(
activeStreams
.
isEmpty
())
{
activeStreams
<<
QStringLiteral
(
"-1"
);
}
QMap
<
QString
,
QString
>
properties
;
properties
.
insert
(
QStringLiteral
(
"kdenlive:active_streams"
),
activeStreams
.
join
(
QLatin1Char
(
';'
)));
emit
updateClipProperties
(
m_id
,
m_originalProperties
,
properties
);
m_originalProperties
=
properties
;
}
else
if
(
item
->
text
()
!=
item
->
data
(
Qt
::
UserRole
+
1
).
toString
())
{
// Rename event
QString
txt
=
item
->
text
();
int
row
=
m_audioStreamsView
->
row
(
item
)
+
1
;
if
(
!
txt
.
startsWith
(
QString
(
"%1|"
).
arg
(
row
)))
{
txt
.
prepend
(
QString
(
"%1|"
).
arg
(
row
));
}
m_controller
->
renameAudioStream
(
streamId
,
txt
);
QSignalBlocker
bk
(
m_audioStreamsView
);
item
->
setText
(
txt
);
item
->
setData
(
Qt
::
UserRole
+
1
,
txt
);
}
});
ac
->
setActive
(
vix
.
toInt
()
==
-
1
);
m_audioStream
->
setEnabled
(
vix
.
toInt
()
>
-
1
);
m_audioStream
->
setVisible
(
audioStreamsInfo
.
size
()
>
0
);
connect
(
ac
,
&
KDualAction
::
activeChanged
,
[
this
](
bool
activated
)
{
connect
(
ac
,
&
KDualAction
::
activeChanged
,
[
this
,
audioStreamsInfo
](
bool
activated
)
{
QMap
<
QString
,
QString
>
properties
;
int
vindx
=
-
1
;
if
(
activated
)
{
m_audioStream
->
setEnabled
(
false
);
properties
.
insert
(
QStringLiteral
(
"kdenlive:active_streams"
),
QStringLiteral
(
"-1"
)
);
}
else
{
m_audioStream
->
setEnabled
(
true
);
vindx
=
m_
audioStream
->
currentData
().
toInt
();
properties
.
insert
(
QStringLiteral
(
"kdenlive:active_streams"
),
QString
()
);
vindx
=
audioStream
sInfo
.
firstKey
();
}
properties
.
insert
(
QStringLiteral
(
"audio_index"
),
QString
::
number
(
vindx
));
properties
.
insert
(
QStringLiteral
(
"set.test_audio"
),
vindx
>
-
1
?
QStringLiteral
(
"0"
)
:
QStringLiteral
(
"1"
));
emit
updateClipProperties
(
m_id
,
m_originalProperties
,
properties
);
m_originalProperties
=
properties
;
});
QObject
::
connect
(
m_audioStream
,
static_cast
<
void
(
QComboBox
::*
)(
int
)
>
(
&
QComboBox
::
currentIndexChanged
),
[
this
]()
{
QMap
<
QString
,
QString
>
properties
;
properties
.
insert
(
QStringLiteral
(
"audio_index"
),
QString
::
number
(
m_audioStream
->
currentData
().
toInt
()));
emit
updateClipProperties
(
m_id
,
m_originalProperties
,
properties
);
m_originalProperties
=
properties
;
});
hlay
->
addWidget
(
m_audioStream
);
vbox
->
addLayout
(
hlay
);
// Audio sync
hlay
=
new
QHBoxLayout
;
...
...
@@ -668,7 +728,7 @@ ClipPropertiesController::ClipPropertiesController(ClipController *controller, Q
m_originalProperties
=
properties
;
});
hlay
->
addWidget
(
spinSync
);
v
box
->
addLayout
(
hlay
);
audioV
box
->
addLayout
(
hlay
);
}
// Colorspace
...
...
@@ -712,13 +772,21 @@ ClipPropertiesController::ClipPropertiesController(ClipController *controller, Q
vbox
->
addLayout
(
hlay
);
hlay
->
addStretch
(
10
);
}
// Force properties page
QWidget
*
forceProp
=
new
QWidget
(
this
);
forceProp
->
setLayout
(
vbox
);
forcePage
->
setWidget
(
forceProp
);
forcePage
->
setWidgetResizable
(
true
);
// Force audio properties page
QWidget
*
forceAudioProp
=
new
QWidget
(
this
);
forceAudioProp
->
setLayout
(
audioVbox
);
forceAudioPage
->
setWidget
(
forceAudioProp
);
forceAudioPage
->
setWidgetResizable
(
true
);
vbox
->
addStretch
(
10
);
m_tabWidget
->
addTab
(
m_propertiesPage
,
QString
());
m_tabWidget
->
addTab
(
forcePage
,
QString
());
m_tabWidget
->
addTab
(
forceAudioPage
,
QString
());
m_tabWidget
->
addTab
(
m_markersPage
,
QString
());
m_tabWidget
->
addTab
(
m_metaPage
,
QString
());
m_tabWidget
->
addTab
(
m_analysisPage
,
QString
());
...
...
@@ -726,12 +794,14 @@ ClipPropertiesController::ClipPropertiesController(ClipController *controller, Q
m_tabWidget
->
setTabToolTip
(
0
,
i18n
(
"File info"
));
m_tabWidget
->
setTabIcon
(
1
,
QIcon
::
fromTheme
(
QStringLiteral
(
"document-edit"
)));
m_tabWidget
->
setTabToolTip
(
1
,
i18n
(
"Properties"
));
m_tabWidget
->
setTabIcon
(
2
,
QIcon
::
fromTheme
(
QStringLiteral
(
"bookmark-new"
)));
m_tabWidget
->
setTabToolTip
(
2
,
i18n
(
"Markers"
));
m_tabWidget
->
setTabIcon
(
3
,
QIcon
::
fromTheme
(
QStringLiteral
(
"view-grid"
)));
m_tabWidget
->
setTabToolTip
(
3
,
i18n
(
"Metadata"
));
m_tabWidget
->
setTabIcon
(
4
,
QIcon
::
fromTheme
(
QStringLiteral
(
"visibility"
)));
m_tabWidget
->
setTabToolTip
(
4
,
i18n
(
"Analysis"
));
m_tabWidget
->
setTabIcon
(
2
,
QIcon
::
fromTheme
(
QStringLiteral
(
"audio-volume-high"
)));
m_tabWidget
->
setTabToolTip
(
2
,
i18n
(
"Audio Properties"
));
m_tabWidget
->
setTabIcon
(
3
,
QIcon
::
fromTheme
(
QStringLiteral
(
"bookmark-new"
)));
m_tabWidget
->
setTabToolTip
(
3
,
i18n
(
"Markers"
));
m_tabWidget
->
setTabIcon
(
4
,
QIcon
::
fromTheme
(
QStringLiteral
(
"view-grid"
)));
m_tabWidget
->
setTabToolTip
(
4
,
i18n
(
"Metadata"
));
m_tabWidget
->
setTabIcon
(
5
,
QIcon
::
fromTheme
(
QStringLiteral
(
"visibility"
)));
m_tabWidget
->
setTabToolTip
(
5
,
i18n
(
"Analysis"
));
m_tabWidget
->
setCurrentIndex
(
KdenliveSettings
::
properties_panel_page
());
if
(
m_type
==
ClipType
::
Color
)
{
m_tabWidget
->
setTabEnabled
(
0
,
false
);
...
...
@@ -776,13 +846,21 @@ void ClipPropertiesController::slotReloadProperties()
m_originalProperties
.
insert
(
QStringLiteral
(
"kdenlive:proxy"
),
proxy
);
emit
proxyModified
(
proxy
);
}
if
(
m_audioStream
&&
m_audioStream
->
isEnabled
()
)
{
if
(
m_audioStream
sView
&&
m_audioStream
sView
->
count
()
>
0
)
{
int
audio_ix
=
m_properties
->
get_int
(
"audio_index"
);
m_originalProperties
.
insert
(
QStringLiteral
(
"kdenlive:active_streams"
),
m_properties
->
get
(
"kdenlive:active_streams"
));
if
(
audio_ix
!=
m_originalProperties
.
value
(
QStringLiteral
(
"audio_index"
)).
toInt
())
{
QSignalBlocker
bk
(
m_audioStream
);
m_originalProperties
.
insert
(
QStringLiteral
(
"audio_index"
),
QString
::
number
(
audio_ix
));
// update combo
m_audioStream
->
setCurrentIndex
(
m_audioStream
->
findData
(
audio_ix
));
//m_audioStream->setCurrentIndex(m_audioStream->findData(audio_ix));
}
QList
<
int
>
enabledStreams
=
m_controller
->
activeStreams
().
keys
();
QSignalBlocker
bk
(
m_audioStreamsView
);
for
(
int
ix
=
0
;
ix
<
m_audioStreamsView
->
count
();
ix
++
)
{
QListWidgetItem
*
item
=
m_audioStreamsView
->
item
(
ix
);
int
stream
=
item
->
data
(
Qt
::
UserRole
).
toInt
();
item
->
setCheckState
(
enabledStreams
.
contains
(
stream
)
?
Qt
::
Checked
:
Qt
::
Unchecked
);
}
}
break
;
...
...
@@ -1390,14 +1468,14 @@ void ClipPropertiesController::slotTextChanged()
void
ClipPropertiesController
::
slotDeleteSelectedMarkers
()
{
if
(
m_tabWidget
->
currentIndex
()
==
2
)
{
if
(
m_tabWidget
->
currentIndex
()
==
3
)
{
slotDeleteMarker
();
}
}
void
ClipPropertiesController
::
slotSelectAllMarkers
()
{
if
(
m_tabWidget
->
currentIndex
()
==
2
)
{
if
(
m_tabWidget
->
currentIndex
()
==
3
)
{
m_markerTree
->
selectAll
();
}
}
src/mltcontroller/clippropertiescontroller.h
View file @
a5c00441
...
...
@@ -35,6 +35,7 @@ class QMimeData;
class
QTextEdit
;
class
QLabel
;
class
QComboBox
;
class
QListWidget
;
class
AnalysisTree
:
public
QTreeWidget
{
...
...
@@ -114,6 +115,7 @@ private:
QTreeView
*
m_markerTree
;
AnalysisTree
*
m_analysisTree
;
QTextEdit
*
m_textEdit
;
QListWidget
*
m_audioStreamsView
;
void
fillProperties
();
signals:
...
...
src/monitor/monitor.cpp
View file @
a5c00441
...
...
@@ -141,7 +141,6 @@ Monitor::Monitor(Kdenlive::MonitorId id, MonitorManager *manager, QWidget *paren
,
m_contextMenu
(
nullptr
)
,
m_markerMenu
(
nullptr
)
,
m_audioChannels
(
nullptr
)
,
m_audioChannelsGroup
(
nullptr
)
,
m_loopClipTransition
(
true
)
,
m_editMarker
(
nullptr
)
,
m_forceSizeFactor
(
0
)
...
...
@@ -277,10 +276,48 @@ Monitor::Monitor(Kdenlive::MonitorId id, MonitorManager *manager, QWidget *paren
m_toolbar
->
addAction
(
manager
->
getAction
(
QStringLiteral
(
"insert_project_tree"
)));
m_toolbar
->
setToolTip
(
i18n
(
"Insert Zone to Project Bin"
));
m_toolbar
->
addSeparator
();
m_streamsButton
=
new
QToolButton
(
this
);
m_streamsButton
->
setPopupMode
(
QToolButton
::
InstantPopup
);
m_streamsButton
->
setIcon
(
QIcon
::
fromTheme
(
QStringLiteral
(
"speaker"
)));
m_streamAction
=
m_toolbar
->
addWidget
(
m_streamsButton
);
m_audioChannels
=
new
QMenu
(
this
);
m_audioChannels
->
setIcon
(
QIcon
::
fromTheme
(
QStringLiteral
(
"speaker"
)));
m_toolbar
->
addAction
(
m_audioChannels
->
menuAction
());
m_audioChannels
->
menuAction
()
->
setVisible
(
false
);
m_streamsButton
->
setMenu
(
m_audioChannels
);
m_streamAction
->
setVisible
(
false
);
connect
(
m_audioChannels
,
&
QMenu
::
triggered
,
[
this
]
()
{
m_audioChannels
->
show
();
QList
<
QAction
*>
actions
=
m_audioChannels
->
actions
();
QMap
<
int
,
QString
>
enabledStreams
;
for
(
const
auto
act
:
actions
)
{
if
(
act
->
isChecked
())
{
// Audio stream is selected
enabledStreams
.
insert
(
act
->
data
().
toInt
(),
act
->
text
().
remove
(
QLatin1Char
(
'&'
)));
}
}
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
}