Switch storing duration to clock instead of frames to ease project fps conversion

Fix crash on thumbnail creation (resetting producer while creating thumbs)
parent 4bb8959e
......@@ -2667,10 +2667,10 @@ void Bin::showTitleWidget(std::shared_ptr<ProjectClip> clip)
newprops.insert(QStringLiteral("xmldata"), dia_ui.xml().toString());
if (dia_ui.duration() != clip->duration().frames(pCore->getCurrentFps()) + 1) {
// duration changed, we need to update duration
newprops.insert(QStringLiteral("out"), QString::number(dia_ui.duration() - 1));
int currentLength = clip->getProducerIntProperty(QStringLiteral("kdenlive:duration"));
newprops.insert(QStringLiteral("out"), clip->framesToTime(dia_ui.duration() - 1));
int currentLength = clip->getProducerDuration();
if (currentLength != dia_ui.duration()) {
newprops.insert(QStringLiteral("kdenlive:duration"), QString::number(dia_ui.duration()));
newprops.insert(QStringLiteral("kdenlive:duration"), clip->framesToTime(dia_ui.duration()));
}
}
// trigger producer reload
......@@ -2811,8 +2811,8 @@ void Bin::showSlideshowWidget(std::shared_ptr<ProjectClip> clip)
if (dia->exec() == QDialog::Accepted) {
// edit clip properties
QMap<QString, QString> properties;
properties.insert(QStringLiteral("out"), QString::number(m_doc->getFramePos(dia->clipDuration()) * dia->imageCount() - 1));
properties.insert(QStringLiteral("kdenlive:duration"), QString::number(m_doc->getFramePos(dia->clipDuration()) * dia->imageCount()));
properties.insert(QStringLiteral("out"), clip->framesToTime(m_doc->getFramePos(dia->clipDuration()) * dia->imageCount() - 1));
properties.insert(QStringLiteral("kdenlive:duration"), clip->framesToTime(m_doc->getFramePos(dia->clipDuration()) * dia->imageCount()));
properties.insert(QStringLiteral("kdenlive:clipname"), dia->clipName());
properties.insert(QStringLiteral("ttl"), QString::number(m_doc->getFramePos(dia->clipDuration())));
properties.insert(QStringLiteral("loop"), QString::number(static_cast<int>(dia->loop())));
......
......@@ -289,12 +289,14 @@ void ProjectClip::reloadProducer(bool refreshOnly)
// we find if there are some loading job on that clip
int loadjobId = -1;
pCore->jobManager()->hasPendingJob(clipId(), AbstractClipJob::LOADJOB, &loadjobId);
QMutexLocker lock(&m_thumbMutex);
if (refreshOnly) {
// In that case, we only want a new thumbnail.
// We thus set up a thumb job. We must make sure that there is no pending LOADJOB
// Clear cache first
m_thumbsProducer.reset();
ThumbnailCache::get()->invalidateThumbsForClip(clipId());
pCore->jobManager()->discardJobs(clipId(), AbstractClipJob::THUMBJOB);
m_thumbsProducer.reset();
pCore->jobManager()->startJob<ThumbJob>({clipId()}, loadjobId, QString(), 150, -1, true, true);
} else {
......@@ -305,6 +307,7 @@ void ProjectClip::reloadProducer(bool refreshOnly)
QDomDocument doc;
QDomElement xml = toXml(doc);
if (!xml.isNull()) {
pCore->jobManager()->discardJobs(clipId(), AbstractClipJob::THUMBJOB);
m_thumbsProducer.reset();
ThumbnailCache::get()->invalidateThumbsForClip(clipId());
int loadJob = pCore->jobManager()->startJob<LoadJob>({clipId()}, loadjobId, QString(), xml);
......@@ -452,6 +455,7 @@ std::shared_ptr<Mlt::Producer> ProjectClip::thumbProducer()
if (clipType() == ClipType::Unknown) {
return nullptr;
}
QMutexLocker lock(&m_thumbMutex);
std::shared_ptr<Mlt::Producer> prod = originalProducer();
if (!prod->is_valid()) {
return nullptr;
......@@ -519,13 +523,17 @@ std::shared_ptr<Mlt::Producer> ProjectClip::getTimelineProducer(int clipId, Play
if (state == PlaylistState::VideoOnly) {
// we return the video producer
// We need to get an audio producer, if none exists
if (m_clipType == ClipType::Color || m_clipType == ClipType::Image) {
int duration = m_masterProducer->time_to_frames(m_masterProducer->get("kdenlive:duration"));
return std::shared_ptr<Mlt::Producer>(m_masterProducer->cut(-1, duration > 0 ? duration: -1));
}
if (m_videoProducers.count(clipId) == 0) {
m_videoProducers[clipId] = cloneProducer(&pCore->getCurrentProfile()->profile(), true);
m_videoProducers[clipId]->set("set.test_audio", 1);
m_videoProducers[clipId]->set("set.test_image", 0);
m_effectStack->addService(m_videoProducers[clipId]);
}
int duration = m_masterProducer->get_int("kdenlive:duration");
int duration = m_masterProducer->time_to_frames(m_masterProducer->get("kdenlive:duration"));
return std::shared_ptr<Mlt::Producer>(m_videoProducers[clipId]->cut(-1, duration > 0 ? duration : -1));
}
if (m_videoProducers.count(clipId) > 0) {
......@@ -534,7 +542,7 @@ std::shared_ptr<Mlt::Producer> ProjectClip::getTimelineProducer(int clipId, Play
}
Q_ASSERT(state == PlaylistState::Disabled);
createDisabledMasterProducer();
int duration = m_masterProducer->get_int("kdenlive:duration");
int duration = m_masterProducer->time_to_frames(m_masterProducer->get("kdenlive:duration"));
return std::shared_ptr<Mlt::Producer>(m_disabledProducer->cut(-1, duration > 0 ? duration : -1));
}
......
......@@ -328,9 +328,13 @@ bool LoadJob::startJob()
if (duration == 0) {
duration = length;
}
m_producer->set("length", length);
int kdenlive_duration = Xml::getXmlProperty(m_xml, QStringLiteral("kdenlive:duration")).toInt();
m_producer->set("kdenlive:duration", kdenlive_duration > 0 ? kdenlive_duration : length);
m_producer->set("length", m_producer->frames_to_time(length, mlt_time_clock));
int kdenlive_duration = m_producer->time_to_frames(Xml::getXmlProperty(m_xml, QStringLiteral("kdenlive:duration")).toUtf8().constData());
if (kdenlive_duration > 0) {
m_producer->set("kdenlive:duration", m_producer->frames_to_time(kdenlive_duration , mlt_time_clock));
} else {
m_producer->set("kdenlive:duration", m_producer->get("length"));
}
}
if (clipOut > 0) {
m_producer->set_in_and_out(m_xml.attribute(QStringLiteral("in")).toInt(), clipOut);
......
......@@ -230,11 +230,11 @@ void ClipController::getInfoForProducer()
}
if (!m_hasLimitedDuration) {
int playtime = m_masterProducer->get_int("kdenlive:duration");
int playtime = m_masterProducer->time_to_frames(m_masterProducer->get("kdenlive:duration"));
if (playtime <= 0) {
// Fix clips having missing kdenlive:duration
m_masterProducer->set("kdenlive:duration", m_masterProducer->get_playtime());
m_masterProducer->set("out", m_masterProducer->get_length() - 1);
m_masterProducer->set("kdenlive:duration", m_masterProducer->frames_to_time(m_masterProducer->get_playtime(), mlt_time_clock));
m_masterProducer->set("out", m_masterProducer->frames_to_time(m_masterProducer->get_length() - 1, mlt_time_clock));
}
}
}
......@@ -335,7 +335,7 @@ void ClipController::updateProducer(const std::shared_ptr<Mlt::Producer> &produc
const QString ClipController::getStringDuration()
{
if (m_masterProducer) {
int playtime = m_masterProducer->get_int("kdenlive:duration");
int playtime = m_masterProducer->time_to_frames(m_masterProducer->get("kdenlive:duration"));
if (playtime > 0) {
return QString(m_properties->frames_to_time(playtime, mlt_time_smpte_df));
}
......@@ -347,7 +347,7 @@ const QString ClipController::getStringDuration()
int ClipController::getProducerDuration() const
{
if (m_masterProducer) {
int playtime = m_masterProducer->get_int("kdenlive:duration");
int playtime = m_masterProducer->time_to_frames(m_masterProducer->get("kdenlive:duration"));
if (playtime <= 0) {
return playtime = m_masterProducer->get_length();
}
......@@ -356,6 +356,14 @@ int ClipController::getProducerDuration() const
return -1;
}
char *ClipController::framesToTime(int frames) const
{
if (m_masterProducer) {
return m_masterProducer->frames_to_time(frames, mlt_time_clock);
}
return nullptr;
}
GenTime ClipController::getPlaytime() const
{
if (!m_masterProducer || !m_masterProducer->is_valid()) {
......@@ -363,7 +371,7 @@ GenTime ClipController::getPlaytime() const
}
double fps = pCore->getCurrentFps();
if (!m_hasLimitedDuration) {
int playtime = m_masterProducer->get_int("kdenlive:duration");
int playtime = m_masterProducer->time_to_frames(m_masterProducer->get("kdenlive:duration"));
return GenTime(playtime == 0 ? m_masterProducer->get_playtime() : playtime, fps);
}
return GenTime(m_masterProducer->get_playtime(), fps);
......@@ -375,7 +383,7 @@ int ClipController::getFramePlaytime() const
return 0;
}
if (!m_hasLimitedDuration) {
int playtime = m_masterProducer->get_int("kdenlive:duration");
int playtime = m_masterProducer->time_to_frames(m_masterProducer->get("kdenlive:duration"));
return playtime == 0 ? m_masterProducer->get_playtime() : playtime;
}
return m_masterProducer->get_playtime();
......
......@@ -131,6 +131,7 @@ public:
/** @brief Returns the clip duration as a string like 00:00:02:01. */
const QString getStringDuration();
int getProducerDuration() const;
char *framesToTime(int frames) const;
/**
* @brief Returns a pixmap created from a frame of the producer.
......
......@@ -255,9 +255,9 @@ ClipPropertiesController::ClipPropertiesController(ClipController *controller, Q
if (m_type == ClipType::Color || m_type == ClipType::Image || m_type == ClipType::AV || m_type == ClipType::Video || m_type == ClipType::TextTemplate) {
// Edit duration widget
m_originalProperties.insert(QStringLiteral("out"), m_properties->get("out"));
int kdenlive_length = m_properties->get_int("kdenlive:duration");
int kdenlive_length = m_properties->time_to_frames(m_properties->get("kdenlive:duration"));
if (kdenlive_length > 0) {
m_originalProperties.insert(QStringLiteral("kdenlive:duration"), QString::number(kdenlive_length));
m_originalProperties.insert(QStringLiteral("kdenlive:duration"), m_properties->get("kdenlive:duration"));
}
m_originalProperties.insert(QStringLiteral("length"), m_properties->get("length"));
auto *hlay = new QHBoxLayout;
......@@ -768,18 +768,18 @@ void ClipPropertiesController::slotDurationChanged(int duration)
{
QMap<QString, QString> properties;
// kdenlive_length is the default duration for image / title clips
int kdenlive_length = m_properties->get_int("kdenlive:duration");
int kdenlive_length = m_properties->time_to_frames(m_properties->get("kdenlive:duration"));
int current_length = m_properties->get_int("length");
if (kdenlive_length > 0) {
// special case, image/title clips store default duration in kdenlive:duration property
properties.insert(QStringLiteral("kdenlive:duration"), QString::number(duration));
properties.insert(QStringLiteral("kdenlive:duration"), m_properties->frames_to_time(duration));
if (duration > current_length) {
properties.insert(QStringLiteral("length"), QString::number(duration));
properties.insert(QStringLiteral("out"), QString::number(duration - 1));
properties.insert(QStringLiteral("length"), m_properties->frames_to_time(duration));
properties.insert(QStringLiteral("out"), m_properties->frames_to_time(duration - 1));
}
} else {
properties.insert(QStringLiteral("length"), QString::number(duration));
properties.insert(QStringLiteral("out"), QString::number(duration - 1));
properties.insert(QStringLiteral("length"), m_properties->frames_to_time(duration));
properties.insert(QStringLiteral("out"), m_properties->frames_to_time(duration - 1));
}
emit updateClipProperties(m_id, m_originalProperties, properties);
m_originalProperties = properties;
......@@ -821,8 +821,8 @@ void ClipPropertiesController::slotEnableForce(int state)
if (param == QLatin1String("force_duration")) {
int original_length = m_properties->get_int("kdenlive:original_length");
if (original_length == 0) {
int kdenlive_duration = m_properties->get_int("kdenlive:duration");
m_properties->set("kdenlive:original_length", kdenlive_duration > 0 ? kdenlive_duration : m_properties->get_int("length"));
int kdenlive_length = m_properties->time_to_frames(m_properties->get("kdenlive:duration"));
m_properties->set("kdenlive:original_length", kdenlive_length > 0 ? m_properties->get("kdenlive:duration") : m_properties->get("length"));
}
} else if (param == QLatin1String("force_fps")) {
QDoubleSpinBox *spin = findChild<QDoubleSpinBox *>(param + QStringLiteral("_value"));
......
......@@ -142,7 +142,9 @@ Rectangle {
onForceReloadThumbChanged: {
// TODO: find a way to force reload of clip thumbs
thumbsLoader.item.reload()
if (thumbsLoader.item) {
thumbsLoader.item.reload()
}
}
onTimeScaleChanged: {
......
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