Commit 9fa9218c authored by Jean-Baptiste Mardelle's avatar Jean-Baptiste Mardelle
Browse files

Fix 1 frame offset in fade out

CCBUG: 416811
parent c4da384e
......@@ -516,7 +516,7 @@ QVariant AssetParameterModel::parseAttribute(const ObjectId &owner, const QStrin
int width = profile->width();
int height = profile->height();
int in = pCore->getItemIn(owner);
int out = in + pCore->getItemDuration(owner);
int out = in + pCore->getItemDuration(owner) - 1;
int frame_duration = pCore->getDurationFromString(KdenliveSettings::fade_duration());
// replace symbols in the double parameter
content.replace(QLatin1String("%maxWidth"), QString::number(width))
......
......@@ -53,7 +53,7 @@ PositionEditWidget::PositionEditWidget(std::shared_ptr<AssetParameterModel> mode
// emit the signal of the base class when appropriate
connect(this->m_slider, &QAbstractSlider::valueChanged, [this](int val) {
if (m_inverted) {
val = m_model->data(m_index, AssetParameterModel::ParentInRole).toInt() + m_model->data(m_index, AssetParameterModel::ParentDurationRole).toInt() -
val = m_model->data(m_index, AssetParameterModel::ParentInRole).toInt() + m_model->data(m_index, AssetParameterModel::ParentDurationRole).toInt() - 1 -
val;
} else if (!m_model->data(m_index, AssetParameterModel::RelativePosRole).toBool()) {
val += m_model->data(m_index, AssetParameterModel::ParentInRole).toInt();
......@@ -100,7 +100,7 @@ void PositionEditWidget::slotRefresh()
if (value.isNull()) {
val = m_model->data(m_index, AssetParameterModel::DefaultRole).toInt();
if (m_inverted) {
val = -val;
val = -val - 1;
}
} else {
if (value.userType() == QMetaType::QString) {
......@@ -112,7 +112,7 @@ void PositionEditWidget::slotRefresh()
if (val < 0) {
val = -val;
} else {
val = max - val;
val = max - val - 1;
}
}
}
......
......@@ -3099,7 +3099,7 @@ void Bin::reloadAllProducers()
// We need to set a temporary id before all outdated producers are replaced;
int jobId = pCore->jobManager()->startJob<LoadJob>({clip->clipId()}, -1, QString(), xml);
ThumbnailCache::get()->invalidateThumbsForClip(clip->clipId(), true);
pCore->jobManager()->startJob<ThumbJob>({clip->clipId()}, jobId, QString(), 150, -1, true, true);
pCore->jobManager()->startJob<ThumbJob>({clip->clipId()}, jobId, QString(), -1, true, true);
pCore->jobManager()->startJob<AudioThumbJob>({clip->clipId()}, jobId, QString());
}
}
......
......@@ -308,7 +308,7 @@ void ProjectClip::reloadProducer(bool refreshOnly, bool audioStreamChanged, bool
ThumbnailCache::get()->invalidateThumbsForClip(clipId(), false);
pCore->jobManager()->discardJobs(clipId(), AbstractClipJob::THUMBJOB);
m_thumbsProducer.reset();
pCore->jobManager()->startJob<ThumbJob>({clipId()}, loadjobId, QString(), 150, -1, true, true);
pCore->jobManager()->startJob<ThumbJob>({clipId()}, loadjobId, QString(), -1, true, true);
} else {
// If another load job is running?
if (loadjobId > -1) {
......@@ -328,7 +328,7 @@ void ProjectClip::reloadProducer(bool refreshOnly, bool audioStreamChanged, bool
}
ThumbnailCache::get()->invalidateThumbsForClip(clipId(), reloadAudio);
int loadJob = pCore->jobManager()->startJob<LoadJob>({clipId()}, loadjobId, QString(), xml);
pCore->jobManager()->startJob<ThumbJob>({clipId()}, loadJob, QString(), 150, -1, true, true);
pCore->jobManager()->startJob<ThumbJob>({clipId()}, loadJob, QString(), -1, true, true);
if (audioStreamChanged) {
discardAudioThumb();
pCore->jobManager()->startJob<AudioThumbJob>({clipId()}, loadjobId, QString());
......@@ -1452,7 +1452,7 @@ void ProjectClip::getThumbFromPercent(int percent)
int id;
if (pCore->jobManager()->hasPendingJob(m_binId, AbstractClipJob::CACHEJOB, &id)) {
} else {
pCore->jobManager()->startJob<CacheJob>({m_binId}, -1, QString(), 150, 50);
pCore->jobManager()->startJob<CacheJob>({m_binId}, -1, QString(), 50);
}
}
}
......@@ -650,13 +650,13 @@ bool ProjectItemModel::requestAddBinClip(QString &id, const QDomElement &descrip
qDebug() << "/////////// added " << res;
if (res) {
int loadJob = pCore->jobManager()->startJob<LoadJob>({id}, -1, QString(), description, std::bind(readyCallBack, id));
int thumbJob = pCore->jobManager()->startJob<ThumbJob>({id}, loadJob, QString(), 150, 0, true);
int thumbJob = pCore->jobManager()->startJob<ThumbJob>({id}, loadJob, QString(), 0, true);
ClipType::ProducerType type = new_clip->clipType();
if (type == ClipType::AV || type == ClipType::Audio || type == ClipType::Playlist || type == ClipType::Unknown) {
pCore->jobManager()->startJob<AudioThumbJob>({id}, loadJob, QString());
}
if (type == ClipType::AV || type == ClipType::Video || type == ClipType::Playlist || type == ClipType::Unknown) {
pCore->jobManager()->startJob<CacheJob>({id}, thumbJob, QString(), 150);
pCore->jobManager()->startJob<CacheJob>({id}, thumbJob, QString());
}
}
return res;
......@@ -690,7 +690,7 @@ bool ProjectItemModel::requestAddBinClip(QString &id, const std::shared_ptr<Mlt:
new_clip->importEffects(producer);
if (new_clip->sourceExists()) {
int blocking = pCore->jobManager()->getBlockingJobId(id, AbstractClipJob::LOADJOB);
pCore->jobManager()->startJob<ThumbJob>({id}, blocking, QString(), 150, -1, true);
pCore->jobManager()->startJob<ThumbJob>({id}, blocking, QString(), -1, true);
pCore->jobManager()->startJob<AudioThumbJob>({id}, blocking, QString());
}
}
......@@ -716,7 +716,7 @@ bool ProjectItemModel::requestAddBinSubClip(QString &id, int in, int out, const
bool res = addItem(new_clip, subId, undo, redo);
if (res) {
int parentJob = pCore->jobManager()->getBlockingJobId(subId, AbstractClipJob::LOADJOB);
pCore->jobManager()->startJob<ThumbJob>({id}, parentJob, QString(), 150, -1, true);
pCore->jobManager()->startJob<ThumbJob>({id}, parentJob, QString(), -1, true);
}
return res;
}
......
......@@ -200,7 +200,7 @@ void ProjectSubClip::getThumbFromPercent(int percent)
int id;
if (pCore->jobManager()->hasPendingJob(m_parentClipId, AbstractClipJob::CACHEJOB, &id)) {
} else {
pCore->jobManager()->startJob<CacheJob>({m_parentClipId}, -1, QString(), 150, 25, m_inPoint, m_outPoint);
pCore->jobManager()->startJob<CacheJob>({m_parentClipId}, -1, QString(), 25, m_inPoint, m_outPoint);
}
}
}
......@@ -101,20 +101,24 @@ QImage KThumb::getFrame(Mlt::Producer &producer, int framepos, int displayWidth,
}
// static
QImage KThumb::getFrame(Mlt::Frame *frame, int width, int height, bool forceRescale)
QImage KThumb::getFrame(Mlt::Frame *frame, int width, int height, int scaledWidth)
{
if (frame == nullptr || !frame->is_valid()) {
qDebug() << "* * * *INVALID FRAME";
return QImage();
}
int ow = forceRescale ? 0 : width;
int oh = forceRescale ? 0 : height;
int ow = width;
int oh = height;
mlt_image_format format = mlt_image_rgb24a;
const uchar *imagedata = frame->get_image(format, ow, oh);
if (imagedata) {
QImage temp(ow, oh, QImage::Format_ARGB32);
memcpy(temp.scanLine(0), imagedata, (unsigned)(ow * oh * 4));
return temp.rgbSwapped();
if (scaledWidth == 0 || scaledWidth == width) {
return temp.rgbSwapped();
}
return temp.rgbSwapped().scaled(scaledWidth, height);
}
return QImage();
}
......
......@@ -35,7 +35,7 @@ QPixmap getImage(const QUrl &url, int width, int height = -1);
QPixmap getImage(const QUrl &url, int frame, int width, int height = -1);
QImage getFrame(Mlt::Producer *producer, int framepos, int displayWidth, int height);
QImage getFrame(Mlt::Producer &producer, int framepos, int displayWidth, int height);
QImage getFrame(Mlt::Frame *frame, int width = 0, int height = 0, bool forceRescale = false);
QImage getFrame(Mlt::Frame *frame, int width = 0, int height = 0, int scaledWidth = 0);
/** @brief Calculates image variance, useful to know if a thumbnail is interesting.
* @return an integer between 0 and 100. 0 means no variance, eg. black image while bigger values mean contrasted image
* */
......
......@@ -447,7 +447,6 @@ bool EffectStackModel::appendEffect(const QString &effectId, bool makeCurrent)
if (res) {
int inFades = 0;
int outFades = 0;
if (effectId == QLatin1String("fadein") || effectId == QLatin1String("fade_from_black")) {
int duration = effect->filter().get_length() - 1;
int in = pCore->getItemIn(m_ownerId);
......@@ -695,7 +694,7 @@ bool EffectStackModel::adjustFadeLength(int duration, bool fromStart, bool audio
in = ptr->get_int("in");
}
int itemDuration = pCore->getItemDuration(m_ownerId);
int out = in + itemDuration;
int out = in + itemDuration - 1;
int oldDuration = -1;
QList<QModelIndex> indexes;
for (int i = 0; i < rootItem->childCount(); ++i) {
......@@ -704,7 +703,7 @@ bool EffectStackModel::adjustFadeLength(int duration, bool fromStart, bool audio
if (oldDuration == -1) {
oldDuration = effect->filter().get_length();
}
effect->filter().set("out", out - 1);
effect->filter().set("out", out);
duration = qMin(itemDuration, duration);
effect->filter().set("in", out - duration);
indexes << getIndexFromItem(effect);
......
......@@ -34,18 +34,19 @@
#include <set>
CacheJob::CacheJob(const QString &binId, int imageHeight, int thumbsCount, int inPoint, int outPoint)
CacheJob::CacheJob(const QString &binId, int thumbsCount, int inPoint, int outPoint)
: AbstractClipJob(CACHEJOB, binId)
, m_fullWidth(imageHeight * pCore->getCurrentDar() + 0.5)
, m_imageHeight(imageHeight)
, m_imageHeight(pCore->thumbProfile()->height())
, m_imageWidth(pCore->thumbProfile()->width())
, m_fullWidth(m_imageHeight * pCore->getCurrentDar() + 0.5)
, m_done(false)
, m_thumbsCount(thumbsCount)
, m_inPoint(inPoint)
, m_outPoint(outPoint)
{
if (m_fullWidth % 8 > 0) {
m_fullWidth += 8 - m_fullWidth % 8;
if (m_fullWidth % 2 > 0) {
m_fullWidth ++;
}
m_imageHeight += m_imageHeight % 2;
auto item = pCore->projectItemModel()->getItemByBinId(binId);
......@@ -104,7 +105,7 @@ bool CacheJob::startJob()
frame->set("top_field_first", -1);
frame->set("rescale.interp", "nearest");
if (frame != nullptr && frame->is_valid()) {
QImage result = KThumb::getFrame(frame.data());
QImage result = KThumb::getFrame(frame.data(), m_imageWidth, m_imageHeight, m_fullWidth);
ThumbnailCache::get()->storeThumbnail(m_clipId, i, result, true);
}
}
......
......@@ -42,7 +42,7 @@ public:
@param frameNumber is the frame to extract. Leave to -1 for default
@param persistent: if true, we will use the persistent cache (for query and saving)
*/
CacheJob(const QString &binId, int imageHeight, int thumbsCount = 10, int inPoint = 0, int outPoint = 0);
CacheJob(const QString &binId, int thumbsCount = 10, int inPoint = 0, int outPoint = 0);
const QString getDescription() const override;
......@@ -53,8 +53,9 @@ public:
bool commitResult(Fun &undo, Fun &redo) override;
private:
int m_fullWidth;
int m_imageHeight;
int m_imageWidth;
int m_fullWidth;
std::shared_ptr<ProjectClip> m_binClip;
std::shared_ptr<Mlt::Producer> m_prod;
......
......@@ -32,17 +32,18 @@
#include <QScopedPointer>
#include <mlt++/MltProducer.h>
ThumbJob::ThumbJob(const QString &binId, int imageHeight, int frameNumber, bool persistent, bool reloadAllThumbs)
ThumbJob::ThumbJob(const QString &binId, int frameNumber, bool persistent, bool reloadAllThumbs)
: AbstractClipJob(THUMBJOB, binId)
, m_frameNumber(frameNumber)
, m_fullWidth(imageHeight * pCore->getCurrentDar() + 0.5)
, m_imageHeight(imageHeight)
, m_imageHeight(pCore->thumbProfile()->height())
, m_imageWidth(pCore->thumbProfile()->width())
, m_fullWidth(m_imageHeight * pCore->getCurrentDar() + 0.5)
, m_persistent(persistent)
, m_reloadAll(reloadAllThumbs)
{
if (m_fullWidth % 8 > 0) {
m_fullWidth += 8 - m_fullWidth % 8;
if (m_fullWidth % 2 > 0) {
m_fullWidth ++;
}
m_imageHeight += m_imageHeight % 2;
auto item = pCore->projectItemModel()->getItemByBinId(binId);
......@@ -103,7 +104,7 @@ bool ThumbJob::startJob()
frame->set("top_field_first", -1);
frame->set("rescale.interp", "nearest");
if ((frame != nullptr) && frame->is_valid()) {
m_result = KThumb::getFrame(frame.data());
m_result = KThumb::getFrame(frame.data(), m_imageWidth, m_imageHeight, m_fullWidth);
m_done = true;
}
return m_done;
......
......@@ -43,7 +43,7 @@ public:
@param frameNumber is the frame to extract. Leave to -1 for default
@param persistent: if true, we will use the persistent cache (for query and saving)
*/
ThumbJob(const QString &binId, int imageHeight, int frameNumber = -1, bool persistent = false, bool reloadAllThumbs = false);
ThumbJob(const QString &binId, int frameNumber = -1, bool persistent = false, bool reloadAllThumbs = false);
const QString getDescription() const override;
......@@ -55,8 +55,9 @@ public:
private:
int m_frameNumber;
int m_fullWidth;
int m_imageHeight;
int m_imageWidth;
int m_fullWidth;
std::shared_ptr<ProjectClip> m_binClip;
std::shared_ptr<Mlt::Producer> m_prod;
......
......@@ -826,9 +826,6 @@ Rectangle {
root.autoScrolling = timeline.autoScroll
anchors.right = parent.right
var duration = clipRoot.fadeOut
if (duration > 0) {
duration += 1
}
timeline.adjustFade(clipRoot.clipId, 'fadeout', duration, startFadeOut)
bubbleHelp.hide()
}
......@@ -841,7 +838,7 @@ Rectangle {
lastDuration = duration
timeline.adjustFade(clipRoot.clipId, 'fadeout', duration, -1)
// Show fade duration as time in a "bubble" help.
var s = timeline.simplifiedTC(clipRoot.fadeOut + (clipRoot.fadeOut > 0 ? 1 : 0))
var s = timeline.simplifiedTC(clipRoot.fadeOut)
bubbleHelp.show(clipRoot.x + x, parentTrack.y + parentTrack.height, s)
}
}
......
......@@ -21,6 +21,7 @@
#include "bin/projectitemmodel.h"
#include "core.h"
#include "utils/thumbnailcache.hpp"
#include "doc/kthumb.h"
#include <QCryptographicHash>
#include <QDebug>
......@@ -122,19 +123,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);
}*/
mlt_image_format format = mlt_image_rgb24a;
const uchar *image = frame->get_image(format, ow, oh);
if (image) {
QImage temp(ow, oh, QImage::Format_ARGB32);
memcpy(temp.scanLine(0), image, (unsigned)(ow * oh * 4));
return temp.rgbSwapped();
}
return QImage();
int imageHeight = pCore->thumbProfile()->height();
int imageWidth = pCore->thumbProfile()->width();
int fullWidth = imageHeight * pCore->getCurrentDar() + 0.5;
return KThumb::getFrame(frame.data(), imageWidth, imageHeight, fullWidth);
}
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