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
a538fcd9
Commit
a538fcd9
authored
Jul 22, 2022
by
Jean-Baptiste Mardelle
Browse files
Extract frame: process in another frame so we don't block the UI, make sure effects are applied
Related to
#1491
parent
d5ed0a48
Changes
5
Hide whitespace changes
Inline
Side-by-side
src/bin/projectclip.cpp
View file @
a538fcd9
...
...
@@ -1115,6 +1115,41 @@ std::pair<std::shared_ptr<Mlt::Producer>, bool> ProjectClip::giveMasterAndGetTim
return
{
std
::
shared_ptr
<
Mlt
::
Producer
>
(
ClipController
::
mediaUnavailable
->
cut
()),
false
};
}
void
ProjectClip
::
cloneProducerToFile
(
const
QString
&
path
)
{
Mlt
::
Consumer
c
(
pCore
->
getCurrentProfile
()
->
profile
(),
"xml"
,
path
.
toUtf8
().
constData
());
Mlt
::
Service
s
(
m_masterProducer
->
get_service
());
int
ignore
=
s
.
get_int
(
"ignore_points"
);
if
(
ignore
)
{
s
.
set
(
"ignore_points"
,
0
);
}
c
.
connect
(
s
);
c
.
set
(
"time_format"
,
"frames"
);
c
.
set
(
"no_meta"
,
1
);
c
.
set
(
"no_root"
,
1
);
c
.
set
(
"no_profile"
,
1
);
c
.
set
(
"root"
,
"/"
);
c
.
set
(
"store"
,
"kdenlive"
);
c
.
run
();
if
(
ignore
)
{
s
.
set
(
"ignore_points"
,
ignore
);
}
if
(
m_usesProxy
)
{
QFile
file
(
path
);
if
(
file
.
open
(
QIODevice
::
ReadOnly
))
{
QTextStream
in
(
&
file
);
QString
content
=
in
.
readAll
();
file
.
close
();
content
.
replace
(
getProducerProperty
(
QStringLiteral
(
"resource"
)),
getProducerProperty
(
QStringLiteral
(
"kdenlive:originalurl"
)));
if
(
file
.
open
(
QIODevice
::
WriteOnly
))
{
QTextStream
out
(
&
file
);
out
<<
content
;
file
.
close
();
}
}
}
}
std
::
shared_ptr
<
Mlt
::
Producer
>
ProjectClip
::
cloneProducer
(
bool
removeEffects
)
{
Mlt
::
Consumer
c
(
pCore
->
getCurrentProfile
()
->
profile
(),
"xml"
,
"string"
);
...
...
src/bin/projectclip.h
View file @
a538fcd9
...
...
@@ -200,6 +200,7 @@ public:
std
::
pair
<
std
::
shared_ptr
<
Mlt
::
Producer
>
,
bool
>
giveMasterAndGetTimelineProducer
(
int
clipId
,
std
::
shared_ptr
<
Mlt
::
Producer
>
master
,
PlaylistState
::
ClipState
state
,
int
tid
,
bool
secondPlaylist
=
false
);
std
::
shared_ptr
<
Mlt
::
Producer
>
cloneProducer
(
bool
removeEffects
=
false
);
void
cloneProducerToFile
(
const
QString
&
path
);
static
std
::
shared_ptr
<
Mlt
::
Producer
>
cloneProducer
(
const
std
::
shared_ptr
<
Mlt
::
Producer
>
&
producer
);
std
::
shared_ptr
<
Mlt
::
Producer
>
softClone
(
const
char
*
list
);
/** @brief Returns a clone of the producer, useful for movit clip jobs
...
...
src/monitor/monitor.cpp
View file @
a538fcd9
...
...
@@ -58,6 +58,7 @@ SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
#include
<QSlider>
#include
<QToolButton>
#include
<QVBoxLayout>
#include
<QtConcurrent>
#include
<utility>
...
...
@@ -1162,27 +1163,33 @@ void Monitor::slotExtractCurrentFrame(QString frameName, bool addToProject)
if
(
dlg
->
exec
()
==
QDialog
::
Accepted
)
{
QString
selectedFile
=
fileWidget
->
selectedFile
();
if
(
!
selectedFile
.
isEmpty
())
{
// Disable monitor preview scaling if any
int
previewScale
=
KdenliveSettings
::
previewScaling
();
if
(
previewScale
>
0
)
{
KdenliveSettings
::
setPreviewScaling
(
0
);
m_glMonitor
->
updateScaling
();
if
(
b
!=
nullptr
)
{
KdenliveSettings
::
setExportframe_usingsourceres
(
b
->
isChecked
());
}
// Create QImage with frame
QImage
frame
;
KRecentDirs
::
add
(
QStringLiteral
(
":KdenliveFramesFolder"
),
QUrl
::
fromLocalFile
(
selectedFile
).
adjusted
(
QUrl
::
RemoveFilename
).
toLocalFile
());
// check if we are using a proxy
if
((
m_controller
!=
nullptr
)
&&
!
m_controller
->
getProducerProperty
(
QStringLiteral
(
"kdenlive:proxy"
)).
isEmpty
()
&&
m_controller
->
getProducerProperty
(
QStringLiteral
(
"kdenlive:proxy"
))
!=
QLatin1String
(
"-"
))
{
// using proxy, use original clip url to get frame
frame
=
m_glMonitor
->
getControllerProxy
()
->
extractFrame
(
m_glMonitor
->
getCurrentPos
(),
m_controller
->
getProducerProperty
(
QStringLiteral
(
"kdenlive:originalurl"
)),
-
1
,
-
1
,
b
!=
nullptr
?
b
->
isChecked
()
:
false
);
if
(
previewScale
>
0
)
{
KdenliveSettings
::
setPreviewScaling
(
previewScale
);
m_glMonitor
->
updateScaling
();
QTemporaryFile
src
(
QDir
::
temp
().
absoluteFilePath
(
QString
(
"XXXXXX.mlt"
)));
if
(
src
.
open
())
{
src
.
setAutoRemove
(
false
);
m_controller
->
cloneProducerToFile
(
src
.
fileName
());
const
QStringList
pathInfo
=
{
src
.
fileName
(),
selectedFile
,
pCore
->
bin
()
->
getCurrentFolder
()};
QtConcurrent
::
run
(
m_glMonitor
->
getControllerProxy
(),
&
MonitorProxy
::
extractFrameToFile
,
m_glMonitor
->
getCurrentPos
(),
pathInfo
,
addToProject
,
b
!=
nullptr
?
b
->
isChecked
()
:
false
);
}
return
;
}
else
{
if
(
m_id
==
Kdenlive
::
ProjectMonitor
)
{
// Create QImage with frame
QImage
frame
;
// Disable monitor preview scaling if any
int
previewScale
=
KdenliveSettings
::
previewScaling
();
if
(
previewScale
>
0
)
{
KdenliveSettings
::
setPreviewScaling
(
0
);
m_glMonitor
->
updateScaling
();
}
// Check if we have proxied clips at position
QStringList
proxiedClips
=
pCore
->
window
()
->
getCurrentTimeline
()
->
model
()
->
getProxiesAt
(
m_glMonitor
->
getCurrentPos
());
// Temporarily disable proxy on those clips
...
...
@@ -1226,24 +1233,17 @@ void Monitor::slotExtractCurrentFrame(QString frameName, bool addToProject)
}
return
;
}
else
{
frame
=
m_glMonitor
->
getControllerProxy
()
->
extractFrame
(
m_glMonitor
->
getCurrentPos
(),
QString
(),
-
1
,
-
1
,
b
!=
nullptr
?
b
->
isChecked
()
:
false
);
if
(
previewScale
>
0
)
{
KdenliveSettings
::
setPreviewScaling
(
previewScale
);
m_glMonitor
->
updateScaling
();
QTemporaryFile
src
(
QDir
::
temp
().
absoluteFilePath
(
QString
(
"XXXXXX.mlt"
)));
if
(
src
.
open
())
{
src
.
setAutoRemove
(
false
);
m_controller
->
cloneProducerToFile
(
src
.
fileName
());
const
QStringList
pathInfo
=
{
src
.
fileName
(),
selectedFile
,
pCore
->
bin
()
->
getCurrentFolder
()};
QtConcurrent
::
run
(
m_glMonitor
->
getControllerProxy
(),
&
MonitorProxy
::
extractFrameToFile
,
m_glMonitor
->
getCurrentPos
(),
pathInfo
,
addToProject
,
b
!=
nullptr
?
b
->
isChecked
()
:
false
);
}
return
;
}
}
frame
.
save
(
selectedFile
);
if
(
b
!=
nullptr
)
{
KdenliveSettings
::
setExportframe_usingsourceres
(
b
->
isChecked
());
}
KRecentDirs
::
add
(
QStringLiteral
(
":KdenliveFramesFolder"
),
QUrl
::
fromLocalFile
(
selectedFile
).
adjusted
(
QUrl
::
RemoveFilename
).
toLocalFile
());
if
(
addToProject
)
{
QString
folderInfo
=
pCore
->
bin
()
->
getCurrentFolder
();
pCore
->
bin
()
->
droppedUrls
(
QList
<
QUrl
>
{
QUrl
::
fromLocalFile
(
selectedFile
)},
folderInfo
);
}
}
}
}
...
...
src/monitor/monitorproxy.cpp
View file @
a538fcd9
...
...
@@ -217,30 +217,70 @@ QPoint MonitorProxy::zone() const
return
{
m_zoneIn
,
m_zoneOut
};
}
QImage
MonitorProxy
::
extractFrame
(
int
frame_position
,
const
QString
&
path
,
int
width
,
int
heigh
t
,
bool
useSourceProfile
)
void
MonitorProxy
::
extractFrame
ToFile
(
int
frame_position
,
const
QString
List
&
path
Info
,
bool
addToProjec
t
,
bool
useSourceProfile
)
{
if
(
width
==
-
1
)
{
width
=
pCore
->
getCurrentProfile
()
->
width
();
height
=
pCore
->
getCurrentProfile
()
->
height
();
}
else
if
(
width
%
2
==
1
)
{
width
++
;
const
QString
path
=
pathInfo
.
at
(
0
);
const
QString
destPath
=
pathInfo
.
at
(
1
);
const
QString
folderInfo
=
pathInfo
.
at
(
2
);
QSize
size
=
pCore
->
getCurrentFrameSize
();
QImage
img
;
int
height
=
size
.
height
();
int
width
=
size
.
width
();
if
(
!
useSourceProfile
)
{
Mlt
::
Frame
*
frame
=
q
->
m_producer
->
get_frame
();
QImage
img
=
KThumb
::
getFrame
(
frame
,
width
,
height
);
delete
frame
;
img
.
save
(
destPath
);
if
(
addToProject
)
{
QMetaObject
::
invokeMethod
(
pCore
->
bin
(),
"droppedUrls"
,
Q_ARG
(
const
QList
<
QUrl
>
&
,
{
QUrl
::
fromLocalFile
(
destPath
)}),
Q_ARG
(
const
QString
&
,
folderInfo
));
}
return
;
}
if
(
!
path
.
isEmpty
())
{
QScopedPointer
<
Mlt
::
Profile
>
tmpProfile
(
new
Mlt
::
Profile
());
QScopedPointer
<
Mlt
::
Producer
>
producer
(
new
Mlt
::
Producer
(
*
tmpProfile
,
path
.
toUtf8
().
constData
()));
QScopedPointer
<
Mlt
::
Producer
>
producer
;
QScopedPointer
<
Mlt
::
Profile
>
tmpProfile
;
if
(
useSourceProfile
)
{
tmpProfile
.
reset
(
new
Mlt
::
Profile
());
producer
.
reset
(
new
Mlt
::
Producer
(
*
tmpProfile
,
path
.
toUtf8
().
constData
()));
}
else
{
producer
.
reset
(
new
Mlt
::
Producer
(
pCore
->
getCurrentProfile
()
->
profile
(),
path
.
toUtf8
().
constData
()));
}
if
(
producer
&&
producer
->
is_valid
())
{
tmpProfile
->
from_producer
(
*
producer
);
width
=
tmpProfile
->
width
();
height
=
tmpProfile
->
height
();
double
projectFps
=
pCore
->
getCurrentFps
();
double
currentFps
=
tmpProfile
->
fps
();
if
(
!
qFuzzyCompare
(
projectFps
,
currentFps
))
{
frame_position
=
int
(
frame_position
*
currentFps
/
projectFps
);
if
(
useSourceProfile
)
{
tmpProfile
->
from_producer
(
*
producer
);
width
=
tmpProfile
->
width
();
height
=
tmpProfile
->
height
();
double
projectFps
=
pCore
->
getCurrentFps
();
double
currentFps
=
tmpProfile
->
fps
();
if
(
!
qFuzzyCompare
(
projectFps
,
currentFps
))
{
frame_position
=
int
(
frame_position
*
currentFps
/
projectFps
);
}
}
QImage
img
=
KThumb
::
getFrame
(
producer
.
data
(),
frame_position
,
width
,
height
);
return
img
;
img
.
save
(
destPath
);
if
(
addToProject
)
{
QMetaObject
::
invokeMethod
(
pCore
->
bin
(),
"droppedUrls"
,
Q_ARG
(
const
QList
<
QUrl
>
&
,
{
QUrl
::
fromLocalFile
(
destPath
)}),
Q_ARG
(
const
QString
&
,
folderInfo
));
}
}
else
{
qDebug
()
<<
"::: INVALID PRODUCER: "
<<
path
;
}
if
(
QDir
::
temp
().
exists
(
path
))
{
// This was a temporary playlist file, remove
QFile
::
remove
(
path
);
}
}
}
QImage
MonitorProxy
::
extractFrame
(
const
QString
&
path
,
int
width
,
int
height
,
bool
useSourceProfile
)
{
if
(
width
==
-
1
)
{
width
=
pCore
->
getCurrentProfile
()
->
width
();
height
=
pCore
->
getCurrentProfile
()
->
height
();
}
else
if
(
width
%
2
==
1
)
{
width
++
;
}
if
((
q
->
m_producer
==
nullptr
)
||
!
path
.
isEmpty
())
{
QImage
pix
(
width
,
height
,
QImage
::
Format_RGB32
);
...
...
src/monitor/monitorproxy.h
View file @
a538fcd9
...
...
@@ -94,7 +94,6 @@ public:
void
setZone
(
QPoint
zone
,
bool
sendUpdate
=
true
);
void
resetZone
();
QPoint
zone
()
const
;
QImage
extractFrame
(
int
frame_position
,
const
QString
&
path
=
QString
(),
int
width
=
-
1
,
int
height
=
-
1
,
bool
useSourceProfile
=
false
);
Q_INVOKABLE
QString
toTimecode
(
int
frames
)
const
;
Q_INVOKABLE
void
startZoneMove
();
Q_INVOKABLE
void
endZoneMove
();
...
...
@@ -105,6 +104,7 @@ public:
Q_INVOKABLE
bool
seekOnDrop
()
const
;
Q_INVOKABLE
void
addEffect
(
const
QString
&
effectData
,
const
QString
&
effectSource
);
QPoint
profile
();
QImage
extractFrame
(
const
QString
&
path
=
QString
(),
int
width
=
-
1
,
int
height
=
-
1
,
bool
useSourceProfile
=
false
);
void
setClipProperties
(
int
clipId
,
ClipType
::
ProducerType
type
,
bool
hasAV
,
const
QString
&
clipName
);
void
setAudioThumb
(
const
QList
<
int
>
&
streamIndexes
=
QList
<
int
>
(),
const
QList
<
int
>
&
channels
=
QList
<
int
>
());
void
setAudioStream
(
const
QString
&
name
);
...
...
@@ -185,4 +185,5 @@ private:
public
slots
:
void
updateClipBounds
(
const
QVector
<
QPoint
>&
bounds
);
void
extractFrameToFile
(
int
frame_position
,
const
QStringList
&
pathInfo
,
bool
addToProject
=
false
,
bool
useSourceProfile
=
false
);
};
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