Keep last known frame as thumbnail when resizing a clip

parent 0a43afd6
Pipeline #12947 passed with stage
in 13 minutes and 43 seconds
......@@ -208,9 +208,10 @@ Rectangle {
//generateWaveform()
}
*/
property bool variableThumbs: (isAudio || itemType == ProducerType.Color || mltService === '')
property bool noThumbs: (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 {
......
......@@ -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
}
}
}
}
......@@ -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;
}
......@@ -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
......@@ -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_thumbnailer = new ThumbnailProvider;
engine()->addImageProvider(QStringLiteral("thumbnail"), m_thumbnailer);
engine()->addImageProvider(QStringLiteral("thumbnail"), new ThumbnailProvider);
engine()->addImageProvider(QStringLiteral("thumbnailCache"), new ThumbnailCacheProvider);
setVisible(false);
setFont(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont));
setFocusPolicy(Qt::StrongFocus);
......
......@@ -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;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment