/***************************************************************************
* Copyright (C) 2018 by Jean-Baptiste Mardelle (jb@kdenlive.org) *
* This file is part of Kdenlive. See www.kdenlive.org. *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; either version 2 of *
* the License or (at your option) version 3 or any later version *
* accepted by the membership of KDE e.V. (or its successor approved *
* by the membership of KDE e.V.), which shall act as a proxy *
* defined in Section 14 of version 3 of the license. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see . *
***************************************************************************/
#include "monitorproxy.h"
#include "core.h"
#include "doc/kthumb.h"
#include "glwidget.h"
#include "kdenlivesettings.h"
#include "monitormanager.h"
#include "profiles/profilemodel.hpp"
#include
#include
#include
#include
MonitorProxy::MonitorProxy(GLWidget *parent)
: QObject(parent)
, q(parent)
, m_position(0)
, m_zoneIn(0)
, m_zoneOut(-1)
, m_hasAV(false)
, m_clipType(0)
, m_clipId(-1)
, m_seekFinished(true)
{
}
int MonitorProxy::getPosition() const
{
return m_position;
}
int MonitorProxy::rulerHeight() const
{
return q->m_rulerHeight;
}
void MonitorProxy::setRulerHeight(int addedHeight)
{
q->updateRulerHeight(addedHeight);
}
void MonitorProxy::seek(int delta, uint modifiers)
{
emit q->mouseSeek(delta, modifiers);
}
int MonitorProxy::overlayType() const
{
return (q->m_id == (int)Kdenlive::ClipMonitor ? KdenliveSettings::clipMonitorOverlayGuides() : KdenliveSettings::projectMonitorOverlayGuides());
}
void MonitorProxy::setOverlayType(int ix)
{
if (q->m_id == (int)Kdenlive::ClipMonitor) {
KdenliveSettings::setClipMonitorOverlayGuides(ix);
} else {
KdenliveSettings::setProjectMonitorOverlayGuides(ix);
}
}
QString MonitorProxy::markerComment() const
{
return m_markerComment;
}
bool MonitorProxy::setPosition(int pos)
{
if (m_position == pos) {
return true;
}
m_position = pos;
emit requestSeek(pos);
if (m_seekFinished) {
m_seekFinished = false;
emit seekFinishedChanged();
}
emit positionChanged(pos);
return false;
}
void MonitorProxy::positionFromConsumer(int pos, bool playing)
{
if (playing) {
m_position = pos;
emit positionChanged(pos);
if (!m_seekFinished) {
m_seekFinished = true;
emit seekFinishedChanged();
}
} else {
if (!m_seekFinished && m_position == pos) {
m_seekFinished = true;
emit seekFinishedChanged();
}
}
}
void MonitorProxy::setMarkerComment(const QString &comment)
{
if (m_markerComment == comment) {
return;
}
m_markerComment = comment;
emit markerCommentChanged();
}
int MonitorProxy::zoneIn() const
{
return m_zoneIn;
}
int MonitorProxy::zoneOut() const
{
return m_zoneOut;
}
void MonitorProxy::setZoneIn(int pos)
{
if (m_zoneIn > 0) {
emit removeSnap(m_zoneIn);
}
m_zoneIn = pos;
if (pos > 0) {
emit addSnap(pos);
}
emit zoneChanged();
emit saveZone(QPoint(m_zoneIn, m_zoneOut));
}
void MonitorProxy::setZoneOut(int pos)
{
if (m_zoneOut > 0) {
emit removeSnap(m_zoneOut - 1);
}
m_zoneOut = pos;
if (pos > 0) {
emit addSnap(m_zoneOut - 1);
}
emit zoneChanged();
emit saveZone(QPoint(m_zoneIn, m_zoneOut));
}
void MonitorProxy::startZoneMove()
{
m_undoZone = QPoint(m_zoneIn, m_zoneOut);
}
void MonitorProxy::endZoneMove()
{
emit saveZoneWithUndo(m_undoZone, QPoint(m_zoneIn, m_zoneOut));
}
void MonitorProxy::setZone(int in, int out, bool sendUpdate)
{
if (m_zoneIn > 0) {
emit removeSnap(m_zoneIn);
}
if (m_zoneOut > 0) {
emit removeSnap(m_zoneOut - 1);
}
m_zoneIn = in;
m_zoneOut = out;
if (m_zoneIn > 0) {
emit addSnap(m_zoneIn);
}
if (m_zoneOut > 0) {
emit addSnap(m_zoneOut - 1);
}
emit zoneChanged();
if (sendUpdate) {
emit saveZone(QPoint(m_zoneIn, m_zoneOut));
}
}
void MonitorProxy::setZone(QPoint zone, bool sendUpdate)
{
setZone(zone.x(), zone.y(), sendUpdate);
}
void MonitorProxy::resetZone()
{
m_zoneIn = 0;
m_zoneOut = -1;
}
double MonitorProxy::fps() const
{
return pCore->getCurrentFps();
}
QPoint MonitorProxy::zone() const
{
return {m_zoneIn, m_zoneOut};
}
QImage MonitorProxy::extractFrame(int frame_position, 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 (!path.isEmpty()) {
QScopedPointer tmpProfile(new Mlt::Profile());
QScopedPointer producer(new Mlt::Producer(*tmpProfile, 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 = frame_position * currentFps / projectFps;
}
QImage img = KThumb::getFrame(producer.data(), frame_position, width, height);
return img;
}
}
if ((q->m_producer == nullptr) || !path.isEmpty()) {
QImage pix(width, height, QImage::Format_RGB32);
pix.fill(Qt::black);
return pix;
}
Mlt::Frame *frame = nullptr;
QImage img;
if (useSourceProfile) {
// Our source clip's resolution is higher than current profile, export at full res
QScopedPointer tmpProfile(new Mlt::Profile());
QString service = q->m_producer->get("mlt_service");
QScopedPointer tmpProd(new Mlt::Producer(*tmpProfile, service.toUtf8().constData(), q->m_producer->get("resource")));
tmpProfile->from_producer(*tmpProd);
width = tmpProfile->width();
height = tmpProfile->height();
if (tmpProd && tmpProd->is_valid()) {
Mlt::Filter scaler(*tmpProfile, "swscale");
Mlt::Filter converter(*tmpProfile, "avcolor_space");
tmpProd->attach(scaler);
tmpProd->attach(converter);
// TODO: paste effects
// Clip(*tmpProd).addEffects(*q->m_producer);
double projectFps = pCore->getCurrentFps();
double currentFps = tmpProfile->fps();
if (qFuzzyCompare(projectFps, currentFps)) {
tmpProd->seek(q->m_producer->position());
} else {
tmpProd->seek(q->m_producer->position() * currentFps / projectFps);
}
frame = tmpProd->get_frame();
img = KThumb::getFrame(frame, width, height);
delete frame;
}
} else if (KdenliveSettings::gpu_accel()) {
QString service = q->m_producer->get("mlt_service");
QScopedPointer tmpProd(
new Mlt::Producer(pCore->getCurrentProfile()->profile(), service.toUtf8().constData(), q->m_producer->get("resource")));
Mlt::Filter scaler(pCore->getCurrentProfile()->profile(), "swscale");
Mlt::Filter converter(pCore->getCurrentProfile()->profile(), "avcolor_space");
tmpProd->attach(scaler);
tmpProd->attach(converter);
tmpProd->seek(q->m_producer->position());
frame = tmpProd->get_frame();
img = KThumb::getFrame(frame, width, height);
delete frame;
} else {
frame = q->m_producer->get_frame();
img = KThumb::getFrame(frame, width, height);
delete frame;
}
return img;
}
void MonitorProxy::activateClipMonitor(bool isClipMonitor)
{
pCore->monitorManager()->activateMonitor(isClipMonitor ? Kdenlive::ClipMonitor : Kdenlive::ProjectMonitor);
}
QString MonitorProxy::toTimecode(int frames) const
{
return KdenliveSettings::frametimecode() ? QString::number(frames) : q->frameToTime(frames);
}
void MonitorProxy::setClipProperties(int clipId, ClipType::ProducerType type, bool hasAV, const QString clipName)
{
if (clipId != m_clipId) {
m_clipId = clipId;
emit clipIdChanged();
}
if (hasAV != m_hasAV) {
m_hasAV = hasAV;
emit clipHasAVChanged();
}
if (type != m_clipType) {
m_clipType = type;
emit clipTypeChanged();
}
if (clipName == m_clipName) {
m_clipName.clear();
emit clipNameChanged();
}
m_clipName = clipName;
emit clipNameChanged();
}
void MonitorProxy::setAudioThumb(const QList streamIndexes, QList channels)
{
m_audioChannels = channels;
m_audioStreams = streamIndexes;
emit audioThumbChanged();
}
void MonitorProxy::setAudioStream(const QString &name)
{
m_clipStream = name;
emit clipStreamChanged();
}
QPoint MonitorProxy::profile()
{
QSize s = pCore->getCurrentFrameSize();
return QPoint(s.width(), s.height());
}
QColor MonitorProxy::thumbColor1() const
{
return KdenliveSettings::thumbColor1();
}
QColor MonitorProxy::thumbColor2() const
{
return KdenliveSettings::thumbColor2();
}
bool MonitorProxy::audioThumbFormat() const
{
return KdenliveSettings::displayallchannels();
}
bool MonitorProxy::audioThumbNormalize() const
{
return KdenliveSettings::normalizechannels();
}
void MonitorProxy::switchAutoKeyframe()
{
KdenliveSettings::setAutoKeyframe(!KdenliveSettings::autoKeyframe());
emit autoKeyframeChanged();
}
bool MonitorProxy::autoKeyframe() const
{
return KdenliveSettings::autoKeyframe();
}