monitorproxy.cpp 10.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/***************************************************************************
 *   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 <http://www.gnu.org/licenses/>. *
 ***************************************************************************/

#include "monitorproxy.h"
23
#include "core.h"
24
#include "doc/kthumb.h"
25 26 27
#include "glwidget.h"
#include "kdenlivesettings.h"
#include "monitormanager.h"
28
#include "profiles/profilemodel.hpp"
29 30

#include <mlt++/MltConsumer.h>
31
#include <mlt++/MltFilter.h>
32 33 34
#include <mlt++/MltProducer.h>
#include <mlt++/MltProfile.h>

35 36 37 38 39 40
MonitorProxy::MonitorProxy(GLWidget *parent)
    : QObject(parent)
    , q(parent)
    , m_position(0)
    , m_zoneIn(0)
    , m_zoneOut(-1)
41
    , m_hasAV(false)
42
    , m_clipType(0)
43
    , m_clipId(-1)
44
    , m_seekFinished(true)
45 46 47
{
}

48
int MonitorProxy::getPosition() const
49 50 51 52 53 54 55 56
{
    return m_position;
}

int MonitorProxy::rulerHeight() const
{
    return q->m_rulerHeight;
}
57

58 59 60 61 62
void MonitorProxy::setRulerHeight(int addedHeight)
{
    q->updateRulerHeight(addedHeight);
}

63 64
void MonitorProxy::seek(int delta, uint modifiers)
{
Vincent Pinon's avatar
Vincent Pinon committed
65
    emit q->mouseSeek(delta, modifiers);
66
}
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86

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;
}

87
bool MonitorProxy::setPosition(int pos)
88
{
89
    if (m_position == pos) {
90
        return true;
91
    }
92 93
    m_position = pos;
    emit requestSeek(pos);
94 95 96 97 98
    if (m_seekFinished) {
        m_seekFinished = false;
        emit seekFinishedChanged();
    }
    emit positionChanged(pos);
99
    return false;
100 101
}

102
void MonitorProxy::positionFromConsumer(int pos, bool playing)
103
{
104 105 106 107 108 109 110 111 112 113 114 115 116
    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();
        }
    }
117 118
}

119 120 121 122 123 124 125 126 127
void MonitorProxy::setMarkerComment(const QString &comment)
{
    if (m_markerComment == comment) {
        return;
    }
    m_markerComment = comment;
    emit markerCommentChanged();
}

128
int MonitorProxy::zoneIn() const
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
{
    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();
148
    emit saveZone(QPoint(m_zoneIn, m_zoneOut));
149 150 151 152 153
}

void MonitorProxy::setZoneOut(int pos)
{
    if (m_zoneOut > 0) {
154
        emit removeSnap(m_zoneOut - 1);
155 156 157
    }
    m_zoneOut = pos;
    if (pos > 0) {
158
        emit addSnap(m_zoneOut - 1);
159 160
    }
    emit zoneChanged();
161
    emit saveZone(QPoint(m_zoneIn, m_zoneOut));
162 163
}

164 165 166 167 168 169 170 171 172 173
void MonitorProxy::startZoneMove()
{
    m_undoZone = QPoint(m_zoneIn, m_zoneOut);
}

void MonitorProxy::endZoneMove()
{
    emit saveZoneWithUndo(m_undoZone, QPoint(m_zoneIn, m_zoneOut));
}

174
void MonitorProxy::setZone(int in, int out, bool sendUpdate)
175 176 177 178 179
{
    if (m_zoneIn > 0) {
        emit removeSnap(m_zoneIn);
    }
    if (m_zoneOut > 0) {
180
        emit removeSnap(m_zoneOut - 1);
181 182 183 184 185 186 187
    }
    m_zoneIn = in;
    m_zoneOut = out;
    if (m_zoneIn > 0) {
        emit addSnap(m_zoneIn);
    }
    if (m_zoneOut > 0) {
188
        emit addSnap(m_zoneOut - 1);
189 190
    }
    emit zoneChanged();
191
    if (sendUpdate) {
192
        emit saveZone(QPoint(m_zoneIn, m_zoneOut));
193
    }
194 195
}

196
void MonitorProxy::setZone(QPoint zone, bool sendUpdate)
197
{
198
    setZone(zone.x(), zone.y(), sendUpdate);
199 200 201 202 203 204 205 206
}

void MonitorProxy::resetZone()
{
    m_zoneIn = 0;
    m_zoneOut = -1;
}

207 208 209 210 211
double MonitorProxy::fps() const
{
    return pCore->getCurrentFps();
}

212 213
QPoint MonitorProxy::zone() const
{
Nicolas Carion's avatar
Nicolas Carion committed
214
    return {m_zoneIn, m_zoneOut};
215 216 217 218 219
}

QImage MonitorProxy::extractFrame(int frame_position, const QString &path, int width, int height, bool useSourceProfile)
{
    if (width == -1) {
220 221
        width = pCore->getCurrentProfile()->width();
        height = pCore->getCurrentProfile()->height();
222 223 224 225
    } else if (width % 2 == 1) {
        width++;
    }
    if (!path.isEmpty()) {
226 227
        QScopedPointer<Mlt::Profile> tmpProfile(new Mlt::Profile());
        QScopedPointer<Mlt::Producer> producer(new Mlt::Producer(*tmpProfile, path.toUtf8().constData()));
228
        if (producer && producer->is_valid()) {
229 230 231 232 233 234 235 236
            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;
            }
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
            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<Mlt::Profile> tmpProfile(new Mlt::Profile());
        QString service = q->m_producer->get("mlt_service");
        QScopedPointer<Mlt::Producer> 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);
264 265 266 267 268 269 270
            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);
            }
271 272 273 274 275 276
            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");
277 278 279 280
        QScopedPointer<Mlt::Producer> 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");
281 282 283 284 285 286 287 288 289 290 291 292 293
        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;
}
294 295 296 297 298 299

void MonitorProxy::activateClipMonitor(bool isClipMonitor)
{
    pCore->monitorManager()->activateMonitor(isClipMonitor ? Kdenlive::ClipMonitor : Kdenlive::ProjectMonitor);
}

300 301 302 303
QString MonitorProxy::toTimecode(int frames) const
{
    return KdenliveSettings::frametimecode() ? QString::number(frames) : q->frameToTime(frames);
}
304

305
void MonitorProxy::setClipProperties(int clipId, ClipType::ProducerType type, bool hasAV, const QString clipName)
306
{
307 308 309 310
    if (clipId != m_clipId) {
        m_clipId = clipId;
        emit clipIdChanged();
    }
311
    if (hasAV != m_hasAV) {
312 313 314
        m_hasAV = hasAV;
        emit clipHasAVChanged();
    }
315 316 317 318
    if (type != m_clipType) {
        m_clipType = type;
        emit clipTypeChanged();
    }
319
    if (clipName == m_clipName) {
320 321 322 323 324
        m_clipName.clear();
        emit clipNameChanged();
    }
    m_clipName = clipName;
    emit clipNameChanged();
325
}
326

327
void MonitorProxy::setAudioThumb(const QList <int> streamIndexes, QList <int> channels)
328
{
329 330
    m_audioChannels = channels;
    m_audioStreams = streamIndexes;
331 332
    emit audioThumbChanged();
}
333

334 335 336 337 338 339 340
void MonitorProxy::setAudioStream(const QString &name)
{
    m_clipStream = name;
    emit clipStreamChanged();
}


341 342 343 344 345
QPoint MonitorProxy::profile()
{
    QSize s = pCore->getCurrentFrameSize();
    return QPoint(s.width(), s.height());
}
346 347 348 349 350 351 352 353 354 355 356 357 358 359 360

QColor MonitorProxy::thumbColor1() const
{
    return KdenliveSettings::thumbColor1();
}

QColor MonitorProxy::thumbColor2() const
{
    return KdenliveSettings::thumbColor2();
}

bool MonitorProxy::audioThumbFormat() const
{
    return KdenliveSettings::displayallchannels();
}
361

362 363 364 365 366
bool MonitorProxy::audioThumbNormalize() const
{
    return KdenliveSettings::normalizechannels();
}

367 368 369 370 371 372 373 374 375 376
void MonitorProxy::switchAutoKeyframe()
{
    KdenliveSettings::setAutoKeyframe(!KdenliveSettings::autoKeyframe());
    emit autoKeyframeChanged();
}

bool MonitorProxy::autoKeyframe() const
{
    return KdenliveSettings::autoKeyframe();
}