File indexing completed on 2024-05-19 04:29:18

0001 /* This file is part of the KDE project
0002    SPDX-FileCopyrightText: 2022 Emmet O'Neill <emmetoneill.pdx@gmail.com>
0003    SPDX-FileCopyrightText: 2022 Eoin O'Neill <eoinoneill1991@gmail.com>
0004 
0005    SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #ifndef KISPLAYBACKENGINEMLT_H
0009 #define KISPLAYBACKENGINEMLT_H
0010 
0011 #include <QObject>
0012 #include "KoCanvasObserverBase.h"
0013 #include "KisPlaybackEngine.h"
0014 #include <kritaui_export.h>
0015 
0016 #include <QScopedPointer>
0017 #include <QFileInfo>
0018 #include <boost/optional.hpp>
0019 
0020 
0021 enum PlaybackMode {
0022     PLAYBACK_PUSH, // MLT is being pushed to, used during pause and stop state for scrubbing.
0023     PLAYBACK_PULL // MLT is updating itself, we are getting regular updates from it about when we need to show our next frame.
0024 };
0025 
0026 /**
0027  * @brief The KisPlaybackEngineMLT class is an implementation of KisPlaybackEngine
0028  * that uses MLT (Media Lovin' Toolkit) to drive image frame changes and animation audio
0029  * with (hopefully) close to frame-perfect synchronization.
0030  *
0031  * If MLT is unavailable or unwanted, Krita can instead use KisPlaybackEngineQT
0032  * which may be simpler but has different characteristics and is not designed with
0033  * audio-video synchronization in mind.
0034  */
0035 class KRITAUI_EXPORT KisPlaybackEngineMLT : public KisPlaybackEngine
0036 {
0037     Q_OBJECT
0038 public:
0039     explicit KisPlaybackEngineMLT(QObject *parent = nullptr);
0040     ~KisPlaybackEngineMLT();
0041 
0042 Q_SIGNALS:
0043     void sigChangeActiveCanvasFrame(int p_frame);
0044 
0045 public Q_SLOTS:
0046     void seek(int frameIndex, SeekOptionFlags flags = SEEK_FINALIZE | SEEK_PUSH_AUDIO) override;
0047 
0048     void setMute(bool val) override;
0049     bool isMute() override;
0050 
0051     bool supportsAudio() override { return true; }
0052     bool supportsVariablePlaybackSpeed() override { return true; }
0053 
0054     void setDropFramesMode(bool value) override;
0055 
0056     PlaybackStats playbackStatistics() const override;
0057 
0058 protected Q_SLOTS:
0059     void setCanvas(KoCanvasBase* canvas) override;
0060     void unsetCanvas() override;
0061     void canvasDestroyed(QObject *canvas);
0062 
0063     /**
0064      * @brief throttledShowFrame
0065      * @param frame
0066      *
0067      * In order to throttle calls from MLT to respect our
0068      * playback mode, we need to redirect `showFrame` calls
0069      * to this thread and enforce that we only allow MLT to
0070      * show frames when we are in PULL mode.
0071      */
0072     void throttledShowFrame(const int frame);
0073 
0074     /**
0075      * @brief throttledSetSpeed
0076      * @param speed
0077      *
0078      * Because MLT needs to be stopped and restarted to change playback speed
0079      * we use this function to limit the frequency of speed change requests.
0080      */
0081     void throttledSetSpeed(const double speed);
0082 
0083 
0084     /**
0085      * @brief setAudioVolume
0086      * @param volume (normalized)
0087      */
0088     void setAudioVolume(qreal volumeNormalized);
0089 
0090 public:
0091     struct FrameWaitingInterface;
0092     FrameWaitingInterface* frameWaitingInterface();
0093 
0094 private:
0095     /**
0096      * @brief Sets up an MLT::Producer object in response to audio being
0097      * added to a Krita document or when canvas changes.
0098      * @param file: An optional file to be loaded by MLT.
0099      */
0100     void setupProducer(boost::optional<QFileInfo> file);
0101 
0102     struct Private;
0103     struct StopAndResume;
0104     QScopedPointer<Private> m_d;
0105 };
0106 
0107 #endif // KISPLAYBACKENGINEMLT_H