Fix crash on exit, continue move away from render

parent 6fb533e5
......@@ -730,6 +730,7 @@ Bin::~Bin()
m_proxyModel->selectionModel()->blockSignals(true);
setEnabled(false);
abortOperations();
m_itemModel->clean();
}
QDockWidget *Bin::clipPropertiesDock()
......
......@@ -54,10 +54,9 @@ Core::Core()
Core::~Core()
{
if (m_monitorManager) {
m_monitorManager->stopActiveMonitor();
delete m_monitorManager;
}
delete m_producerQueue;
//delete m_producerQueue;
// delete m_binWidget;
delete m_projectManager;
}
......@@ -97,7 +96,7 @@ void Core::build(const QString &MltPath)
m_self->profileChanged();
// Init producer shown for unavailable media
// TODO make it a more proper image, it currently causes a crash on exit
// TODO make it a more proper image
ClipController::mediaUnavailable = std::make_shared<Mlt::Producer>(ProfileRepository::get()->getProfile(m_self->m_profile)->profile(), "color:blue");
ClipController::mediaUnavailable->set("length", 99999999);
}
......
......@@ -726,6 +726,7 @@ void MainWindow::slotReloadTheme()
MainWindow::~MainWindow()
{
ClipController::mediaUnavailable.reset();
delete m_audioSpectrum;
if (m_projectMonitor) {
m_projectMonitor->stop();
......
......@@ -34,6 +34,7 @@ BinController::BinController(const QString &profileName)
BinController::~BinController()
{
qDebug() << "/// delete bincontroller";
qDebug()<<"REMAINING CLIPS: "<<m_clipList.keys();
destroyBin();
}
......
......@@ -88,6 +88,7 @@ public slots:
virtual void stop() = 0;
virtual void start() = 0;
virtual void slotPlay() = 0;
virtual void refreshMonitorIfActive() = 0;
virtual void slotMouseSeek(int eventDelta, int modifiers) = 0;
bool slotActivateMonitor(bool forceRefresh = false);
virtual void slotSwitchFullScreen(bool minimizeOnly = false) = 0;
......@@ -95,6 +96,14 @@ public slots:
protected:
Kdenlive::MonitorId m_id;
MonitorManager *m_monitorManager;
signals:
/** @brief Send a frame for analysis or title background display. */
void frameUpdated(const QImage &);
/** @brief This signal contains the audio of the current frame. */
void audioSamplesSignal(const audioShortVector &, int, int, int);
/** @brief Scopes are ready to receive a new frame. */
void scopesClear();
};
#endif
......@@ -30,6 +30,7 @@
#include "core.h"
#include "glwidget.h"
#include "doc/kthumb.h"
#include "kdenlivesettings.h"
#include "mltcontroller/bincontroller.h"
#include "profiles/profilemodel.hpp"
......@@ -1793,6 +1794,9 @@ int GLWidget::rulerHeight() const
void GLWidget::startConsumer()
{
if (m_consumer == nullptr) {
return;
}
if (m_consumer->is_stopped() && m_consumer->start() == -1) {
// ARGH CONSUMER BROKEN!!!!
KMessageBox::error(
......@@ -1827,3 +1831,101 @@ void GLWidget::stop()
}
}
}
QImage GLWidget::extractFrame(int frame_position, const QString &path, int width, int height)
{
if (width == -1) {
width = m_monitorProfile->width();
height = m_monitorProfile->height();
} else if (width % 2 == 1) {
width++;
}
if (!path.isEmpty()) {
Mlt::Producer *producer = new Mlt::Producer(*m_monitorProfile, path.toUtf8().constData());
if (producer) {
if (producer->is_valid()) {
QImage img = KThumb::getFrame(producer, frame_position, width, height);
delete producer;
return img;
}
delete producer;
}
}
if (m_producer == nullptr) {
QImage pix(width, height, QImage::Format_RGB32);
pix.fill(Qt::black);
return pix;
}
Mlt::Frame *frame = nullptr;
if (KdenliveSettings::gpu_accel()) {
QString service = m_producer->get("mlt_service");
// TODO: create duplicate prod from xml data
Mlt::Producer *tmpProd = new Mlt::Producer(*m_monitorProfile, service.toUtf8().constData(), path.toUtf8().constData());
Mlt::Filter scaler(*m_monitorProfile, "swscale");
Mlt::Filter converter(*m_monitorProfile, "avcolor_space");
tmpProd->attach(scaler);
tmpProd->attach(converter);
tmpProd->seek(m_producer->position());
frame = tmpProd->get_frame();
delete tmpProd;
} else {
frame = m_producer->get_frame();
}
QImage img = KThumb::getFrame(frame, width, height);
delete frame;
return img;
}
double GLWidget::playSpeed() const
{
if (m_producer) {
return m_producer->get_speed();
}
return 0.0;
}
void GLWidget::setDropFrames(bool drop)
{
QMutexLocker locker(&m_mutex);
if (m_consumer) {
int dropFrames = realTime();
if (!drop) {
dropFrames = -dropFrames;
}
m_consumer->stop();
m_consumer->set("real_time", dropFrames);
if (m_consumer->start() == -1) {
qCWarning(KDENLIVE_LOG) << "ERROR, Cannot start monitor";
}
}
}
int GLWidget::volume() const
{
if ((m_consumer == nullptr) || (m_producer == nullptr)) {
return -1;
}
if (m_consumer->get("mlt_service") == QStringLiteral("multi")) {
return ((int)100 * m_consumer->get_double("0.volume"));
}
return ((int)100 * m_consumer->get_double("volume"));
}
void GLWidget::setVolume(double volume)
{
if (m_consumer) {
if (m_consumer->get("mlt_service") == QStringLiteral("multi")) {
m_consumer->set("0.volume", volume);
} else {
m_consumer->set("volume", volume);
}
}
}
int GLWidget::duration() const
{
if (m_producer == nullptr) {
return 0;
}
return m_producer->get_playtime();
}
......@@ -115,6 +115,17 @@ public:
void startConsumer();
void stop();
int rulerHeight() const;
QImage extractFrame(int frame_position, const QString &path = QString(), int width = -1, int height = -1);
/** @brief return current play producer's playing speed */
double playSpeed() const;
/** @brief Turn drop frame feature on/off */
void setDropFrames(bool drop);
/** @brief Returns current audio volume */
int volume() const;
/** @brief Set audio volume on consumer */
void setVolume(double volume);
/** @brief Returns current producer's duration in frames */
int duration() const;
protected:
void mouseReleaseEvent(QMouseEvent *event) override;
......
......@@ -288,11 +288,11 @@ Monitor::Monitor(Kdenlive::MonitorId id, MonitorManager *manager, QWidget *paren
setLayout(layout);
setMinimumHeight(200);
render = new Render(m_id, m_monitorManager->binController(), m_glMonitor, this);
//render = new Render(m_id, m_monitorManager->binController(), m_glMonitor, this);
connect(render, &AbstractRender::scopesClear, m_glMonitor, &GLWidget::releaseAnalyse, Qt::DirectConnection);
connect(m_glMonitor, SIGNAL(analyseFrame(QImage)), this, SIGNAL(frameUpdated(QImage)));
connect(m_glMonitor, &GLWidget::audioSamplesSignal, render, &AbstractRender::audioSamplesSignal);
connect(this, &Monitor::scopesClear, m_glMonitor, &GLWidget::releaseAnalyse, Qt::DirectConnection);
connect(m_glMonitor, &GLWidget::analyseFrame, this, &Monitor::frameUpdated);
connect(m_glMonitor, &GLWidget::audioSamplesSignal, this, &Monitor::audioSamplesSignal);
if (id != Kdenlive::ClipMonitor) {
// TODO: reimplement
......@@ -359,7 +359,6 @@ Monitor::Monitor(Kdenlive::MonitorId id, MonitorManager *manager, QWidget *paren
Monitor::~Monitor()
{
render->stop();
delete m_audioMeterWidget;
delete m_glMonitor;
delete m_videoWidget;
......@@ -956,7 +955,7 @@ void Monitor::slotSetThumbFrame()
if (m_controller == nullptr) {
return;
}
m_controller->setProducerProperty(QStringLiteral("kdenlive:thumbnailFrame"), (int)render->seekFramePosition());
m_controller->setProducerProperty(QStringLiteral("kdenlive:thumbnailFrame"), m_glMonitor->getCurrentPos());
emit refreshClipThumbnail(m_controller->AbstractProjectItem::clipId());
}
......@@ -992,7 +991,7 @@ void Monitor::slotExtractCurrentFrame(QString frameName, bool addToProject)
? currentController()->clipName()
: pCore->projectManager()->current()->url().isValid() ? pCore->projectManager()->current()->url().fileName() : i18n("untitled"))
.completeBaseName() +
QStringLiteral("-f") + QString::number(render->seekFramePosition()) + QStringLiteral(".png");
QStringLiteral("-f") + QString::number(m_glMonitor->getCurrentPos()) + QStringLiteral(".png");
frameName = QFileInfo(frameName, suggestedImageName).fileName();
}
......@@ -1019,9 +1018,9 @@ void Monitor::slotExtractCurrentFrame(QString frameName, bool addToProject)
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 = render->extractFrame(render->seekFramePosition(), m_controller->getProducerProperty(QStringLiteral("kdenlive:originalurl")));
frame = m_glMonitor->extractFrame(m_glMonitor->getCurrentPos(), m_controller->getProducerProperty(QStringLiteral("kdenlive:originalurl")));
} else {
frame = render->extractFrame(render->seekFramePosition());
frame = m_glMonitor->extractFrame(m_glMonitor->getCurrentPos());
}
frame.save(savePath.toLocalFile());
KRecentDirs::add(QStringLiteral(":KdenliveFramesFolder"), savePath.adjusted(QUrl::RemoveFilename).toLocalFile());
......@@ -1094,20 +1093,6 @@ void Monitor::checkOverlay(int pos)
// m_qmlManager->setProperty(QLatin1String("markerText"), overlayText);
}
void Monitor::slotStart()
{
slotActivateMonitor();
render->play(0);
render->seekToFrame(0);
}
void Monitor::slotEnd()
{
slotActivateMonitor();
render->play(0);
render->seekToFrame(render->getLength() - 1);
}
int Monitor::getZoneStart()
{
return m_glMonitor->getControllerProxy()->zoneIn();
......@@ -1160,7 +1145,7 @@ void Monitor::slotForward(double speed)
{
slotActivateMonitor();
if (speed == 0) {
double currentspeed = render->playSpeed();
double currentspeed = m_glMonitor->playSpeed();
if (currentspeed <= 0) {
speed = 1;
} else
......@@ -1231,6 +1216,7 @@ void Monitor::stop()
void Monitor::mute(bool mute, bool updateIconOnly)
{
//TODO
if (render) {
// TODO: we should set the "audio_off" property to 1 to mute the consumer instead of changing volume
QIcon icon;
......@@ -1332,6 +1318,7 @@ void Monitor::updateClipProducer(Mlt::Producer *prod)
void Monitor::updateClipProducer(const QString &playlist)
{
//TODO
Mlt::Producer *prod = new Mlt::Producer(*m_glMonitor->profile(), playlist.toUtf8().constData());
m_glMonitor->setProducer(prod, render->seekFramePosition(), true);
render->play(1.0);
......@@ -1391,6 +1378,7 @@ const QString Monitor::activeClipId()
void Monitor::slotOpenDvdFile(const QString &file)
{
//TODO
if (render == nullptr) {
return;
}
......@@ -1406,6 +1394,7 @@ void Monitor::slotSaveZone()
void Monitor::setCustomProfile(const QString &profile, const Timecode &tc)
{
//TODO or deprecate
m_timePos->updateTimeCode(tc);
if (render == nullptr) {
return;
......@@ -1423,14 +1412,10 @@ void Monitor::setCustomProfile(const QString &profile, const Timecode &tc)
void Monitor::resetProfile()
{
m_timePos->updateTimeCode(m_monitorManager->timecode());
if (render == nullptr) {
return;
}
render->prepareProfileReset(m_monitorManager->timecode().fps());
m_glMonitor->reloadProfile();
m_glMonitor->rootObject()->setProperty("framesize", QRect(0, 0, m_glMonitor->profileSize().width(), m_glMonitor->profileSize().height()));
double fps = m_monitorManager->timecode().fps();
// Update dro pframe info
// Update drop frame info
m_qmlManager->setProperty(QStringLiteral("dropped"), false);
m_qmlManager->setProperty(QStringLiteral("fps"), QString::number(fps, 'g', 2));
}
......@@ -1461,7 +1446,7 @@ void Monitor::updateTimelineClipZone()
void Monitor::switchDropFrames(bool drop)
{
render->setDropFrames(drop);
m_glMonitor->setDropFrames(drop);
}
void Monitor::switchMonitorInfo(int code)
......@@ -1659,8 +1644,8 @@ void Monitor::slotSetVolume(int volume)
{
KdenliveSettings::setVolume(volume);
QIcon icon;
double renderVolume = render->volume();
render->setVolume((double)volume / 100.0);
double renderVolume = m_glMonitor->volume();
m_glMonitor->setVolume((double)volume / 100.0);
if (renderVolume > 0 && volume > 0) {
return;
}
......@@ -1842,6 +1827,7 @@ void Monitor::slotSwitchCompare(bool enable, int pos)
}
buildSplitEffect(m_controller->masterProducer(), pos);
} else if (m_splitEffect) {
//TODO
render->setProducer(m_controller->masterProducer(), pos, isActive());
delete m_splitEffect;
m_splitProducer = nullptr;
......@@ -1853,6 +1839,7 @@ void Monitor::slotSwitchCompare(bool enable, int pos)
void Monitor::buildSplitEffect(Mlt::Producer *original, int pos)
{
//TODO
m_splitEffect = new Mlt::Filter(*profile(), "frei0r.alphagrad");
if ((m_splitEffect != nullptr) && m_splitEffect->is_valid()) {
m_splitEffect->set("0", 0.5); // 0 is the Clip left parameter
......@@ -1902,7 +1889,8 @@ void Monitor::loadQmlScene(MonitorSceneType type)
// User doesn't want effect scenes
type = MonitorSceneDefault;
}
m_qmlManager->setScene(m_id, type, m_glMonitor->profileSize(), (double)render->renderWidth() / render->frameRenderWidth(), m_glMonitor->displayRect(),
double ratio = (double) m_glMonitor->profileSize().width() / (int) (m_glMonitor->profileSize().height() * m_glMonitor->profile()->dar() + 0.5);
m_qmlManager->setScene(m_id, type, m_glMonitor->profileSize(), ratio, m_glMonitor->displayRect(),
m_glMonitor->zoom());
QQuickItem *root = m_glMonitor->rootObject();
root->setProperty("showToolbar", m_zoomVisibilityAction->isChecked());
......@@ -2003,14 +1991,14 @@ void Monitor::slotAdjustEffectCompare()
if (m_splitEffect) {
m_splitEffect->set("0", percent);
}
render->doRefresh();
//render->doRefresh();
}
ProfileInfo Monitor::profileInfo() const
{
ProfileInfo info;
info.profileSize = QSize(render->frameRenderWidth(), render->renderHeight());
info.profileFps = render->fps();
info.profileSize = m_glMonitor->profileSize();
info.profileFps = m_glMonitor->profile()->fps();
return info;
}
......@@ -2036,6 +2024,7 @@ void Monitor::slotSwitchRec(bool enable)
bool Monitor::startCapture(const QString &params, const QString &path, Mlt::Producer *p)
{
//TODO
m_controller = nullptr;
if (render->updateProducer(p)) {
m_glMonitor->reconfigureMulti(params, path, p->profile());
......@@ -2180,3 +2169,17 @@ void Monitor::slotSeekPosition(int pos)
m_timePos->setValue(pos);
checkOverlay();
}
void Monitor::slotStart()
{
slotActivateMonitor();
m_glMonitor->switchPlay(false);
m_glMonitor->seek(0);
}
void Monitor::slotEnd()
{
slotActivateMonitor();
m_glMonitor->switchPlay(false);
m_glMonitor->seek(m_glMonitor->duration());
}
......@@ -143,7 +143,6 @@ public:
void refreshIcons();
/** @brief Send audio thumb data to qml for on monitor display */
void prepareAudioThumb(int channels, QVariantList &audioCache);
void refreshMonitorIfActive();
void connectAudioSpectrum(bool activate);
/** @brief Set a property on the Qml scene **/
void setQmlProperty(const QString &name, const QVariant &value);
......@@ -333,6 +332,7 @@ public slots:
void requestSeek(int pos);
/** @brief Check current position to show relevant infos in qml view (markers, zone in/out, etc). */
void checkOverlay(int pos = -1);
void refreshMonitorIfActive() override;
signals:
void seekPosition(int);
......@@ -373,8 +373,6 @@ signals:
void removeSplitOverlay();
void acceptRipple(bool);
void switchTrimMode(int);
/** @brief Send a frame for analysis of title background display. */
void frameUpdated(const QImage &);
};
#endif
......@@ -338,10 +338,10 @@ void MonitorManager::updateScopeSource()
emit checkColorScopes();
}
AbstractRender *MonitorManager::activeRenderer()
AbstractMonitor *MonitorManager::activeMonitor()
{
if (m_activeMonitor) {
return m_activeMonitor->abstractRender();
return m_activeMonitor;
}
return nullptr;
}
......
......@@ -46,7 +46,7 @@ public:
void resetProfiles(const Timecode &tc);
void stopActiveMonitor();
void pauseActiveMonitor();
AbstractRender *activeRenderer();
AbstractMonitor *activeMonitor();
/** Searches for a monitor with the given name.
@return nullptr, if no monitor could be found, or the monitor otherwise.
*/
......
......@@ -96,7 +96,7 @@ QVector<QPair<QString, QString>> ProfileRepository::getAllProfiles()
std::unique_ptr<ProfileModel> &ProfileRepository::getProfile(const QString &path)
{
QReadLocker locker(&m_mutex);
qDebug()<<"// GET PROFILE: "<<path;
if (m_profiles.count(path) == 0) {
qCWarning(KDENLIVE_LOG) << "//// WARNING: profile not found: " << path << ". Returning default profile instead.";
QString default_profile = KdenliveSettings::default_profile();
......
......@@ -32,13 +32,13 @@ NotesPlugin::NotesPlugin(ProjectManager *projectManager)
void NotesPlugin::setProject(KdenliveDoc *document)
{
connect(m_widget, &NotesWidget::seekProject, pCore->monitorManager()->projectMonitor()->render, &Render::seekToFrame);
connect(m_widget, &NotesWidget::seekProject, pCore->monitorManager()->projectMonitor(), &Monitor::requestSeek);
connect(m_widget, SIGNAL(textChanged()), document, SLOT(setModified()));
}
void NotesPlugin::slotInsertTimecode()
{
int frames = pCore->monitorManager()->projectMonitor()->render->seekPosition().frames(pCore->getCurrentFps());
int frames = pCore->monitorManager()->projectMonitor()->position();
QString position = pCore->projectManager()->current()->timecode().getTimecodeFromFrames(frames);
m_widget->insertHtml(QStringLiteral("<a href=\"") + QString::number(frames) + QStringLiteral("\">") + position + QStringLiteral("</a> "));
}
......
......@@ -185,7 +185,9 @@ void ScopeManager::slotRequestFrame(const QString &widgetName)
}
}
if (m_lastConnectedRenderer) {
m_lastConnectedRenderer->sendFrameUpdate();
//TODO: trigger refresh?
m_lastConnectedRenderer->refreshMonitorIfActive();
//m_lastConnectedRenderer->sendFrameUpdate();
}
}
......@@ -204,7 +206,7 @@ void ScopeManager::slotUpdateActiveRenderer()
m_lastConnectedRenderer->disconnect(this);
}
m_lastConnectedRenderer = pCore->monitorManager()->activeRenderer();
m_lastConnectedRenderer = pCore->monitorManager()->activeMonitor();
// DVD monitor shouldn't be monitored or will cause crash on deletion
if (pCore->monitorManager()->isActive(Kdenlive::DvdMonitor)) {
m_lastConnectedRenderer = nullptr;
......@@ -212,8 +214,8 @@ void ScopeManager::slotUpdateActiveRenderer()
// Connect new renderer
if (m_lastConnectedRenderer != nullptr) {
connect(m_lastConnectedRenderer, &AbstractRender::frameUpdated, this, &ScopeManager::slotDistributeFrame, Qt::UniqueConnection);
connect(m_lastConnectedRenderer, &AbstractRender::audioSamplesSignal, this, &ScopeManager::slotDistributeAudio, Qt::UniqueConnection);
connect(m_lastConnectedRenderer, &Monitor::frameUpdated, this, &ScopeManager::slotDistributeFrame, Qt::UniqueConnection);
connect(m_lastConnectedRenderer, &Monitor::audioSamplesSignal, this, &ScopeManager::slotDistributeAudio, Qt::UniqueConnection);
#ifdef DEBUG_SM
qCDebug(KDENLIVE_LOG) << "Renderer connected to ScopeManager: " << m_lastConnectedRenderer->id();
......@@ -223,7 +225,7 @@ void ScopeManager::slotUpdateActiveRenderer()
#ifdef DEBUG_SM
qCDebug(KDENLIVE_LOG) << "Some scopes accept images, triggering frame update.";
#endif
m_lastConnectedRenderer->sendFrameUpdate();
m_lastConnectedRenderer->refreshMonitorIfActive();
}
}
}
......
......@@ -17,7 +17,7 @@
#include <QList>
class QDockWidget;
class AbstractRender;
class AbstractMonitor;
/**
\brief Manages communication between Scopes and Renderer
......@@ -71,7 +71,7 @@ private:
QList<AudioScopeData> m_audioScopes;
QList<GfxScopeData> m_colorScopes;
AbstractRender *m_lastConnectedRenderer;
AbstractMonitor *m_lastConnectedRenderer;
QSignalMapper *m_signalMapper;
......
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