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

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 KISPLAYBACKENGINE_H
0009 #define KISPLAYBACKENGINE_H
0010 
0011 #include "KoCanvasObserverBase.h"
0012 #include <QObject>
0013 
0014 #include <kritaui_export.h>
0015 
0016 /**
0017  * @brief The SeekOption enum represents additional behaviors associated with seeking to a new frame.
0018  * For example, sometimes you want to push audio when seeking, and other times you might want to reload the image without using the cache.
0019  * Other optional, uncommon or specialized seeking behaviors might make sense to add here.
0020  */
0021 enum SeekOption {
0022     SEEK_NONE = 0,
0023     SEEK_PUSH_AUDIO = 1, // Whether we should be pushing audio or not. Used to prevent double-takes on scrubbing.
0024     SEEK_FINALIZE = 1 << 1 // Force reload of KisImage to specific frame, ignore caching ability.
0025 };
0026 
0027 Q_DECLARE_FLAGS(SeekOptionFlags, SeekOption)
0028 Q_DECLARE_OPERATORS_FOR_FLAGS(SeekOptionFlags)
0029 
0030 
0031 /** @brief Krita's base animation playback engine for producing image frame changes and associated audio.
0032  *
0033  *  Krita stores a main playback engine in KisPart (a singleton) to be used by the active document's canvas.
0034  *  It can be thought of as being just below the GUI layer of Krita's animation system,
0035  *  responding to various GUI events, controlling transport controls (play, stop, next, etc.),
0036  *  and generally driving the playback of animation within Krita.
0037  *
0038  *  It's implemented by KisPlaybackEngineQT and KisPlaybackEngineMLT, one of which is typically selected
0039  *  at compile time depending on available dependencies. Specific implementations may or may not support
0040  *  certain features (audio, speed, dropping frames, etc.) and have other different characteristics.
0041  */
0042 class KRITAUI_EXPORT KisPlaybackEngine : public QObject, public KoCanvasObserverBase
0043 {
0044     Q_OBJECT
0045 public:
0046     KisPlaybackEngine(QObject* parent = nullptr);
0047     ~KisPlaybackEngine();
0048 
0049     struct PlaybackStats {
0050         qreal expectedFps {0.0};
0051         qreal realFps {0.0};
0052         qreal droppedFramesPortion {0.0};
0053     };
0054 
0055 public Q_SLOTS:
0056     // Basic transport controls...
0057     virtual void play();
0058     virtual void pause();
0059     virtual void playPause();
0060     virtual void stop();
0061 
0062     virtual void seek( int frameIndex, SeekOptionFlags options = SEEK_FINALIZE | SEEK_PUSH_AUDIO ) = 0;
0063     virtual void previousFrame();
0064     virtual void nextFrame();
0065     virtual void previousKeyframe();
0066     virtual void nextKeyframe();
0067     virtual void firstFrame();
0068     virtual void lastFrame();
0069 
0070     /**
0071      * @brief previousMatchingKeyframe && nextMatchingKeyframe
0072      * Navigate to the next keyframe that has the same color-label
0073      * as the current keyframe. Useful to quickly navigate to user-specified
0074      * 'similar' keyframes. E.g. Contact points in an animation might have
0075      * a specific color to specify importance and be quickly swapped between.
0076      */
0077     virtual void previousMatchingKeyframe();
0078     virtual void nextMatchingKeyframe();
0079 
0080     /**
0081      * @brief previousUnfilteredKeyframe && nextUnfilteredKeyframe
0082      * Navigate to keyframes based on the current onion skin filtration.
0083      * This lets users easily navigate to the next visible "onion-skinned"
0084      * keyframe on the active layer.
0085      */
0086     virtual void previousUnfilteredKeyframe();
0087     virtual void nextUnfilteredKeyframe();
0088 
0089     // Audio controls...
0090     virtual void setMute(bool val) = 0;
0091     virtual bool isMute() = 0;
0092 
0093     virtual void setDropFramesMode(bool value);
0094     bool dropFrames() const;
0095 
0096     virtual bool supportsAudio() = 0;
0097     virtual bool supportsVariablePlaybackSpeed() = 0;
0098 
0099     virtual PlaybackStats playbackStatistics() const = 0;
0100 
0101 Q_SIGNALS:
0102     void sigDropFramesModeChanged(bool value);
0103 
0104 protected:
0105     class KisCanvas2* activeCanvas() const;
0106     int frameWrap(int frame, int startFrame, int endFrame);
0107 
0108 protected Q_SLOTS:
0109     virtual void setCanvas(KoCanvasBase* p_canvas) override;
0110     virtual void unsetCanvas() override;
0111 
0112 private:
0113     /**
0114      * @brief Move the active frame of the animation player forwards or backwards by some number of frames.
0115      * @param The signed number of frames to move. Negative frames move backwards in time (left on a left-to-right system).
0116      */
0117     void moveActiveFrameBy(int frames);
0118 
0119     // Used by previous/next unfiltered keyframe functions...
0120     void nextKeyframeWithColor(int color);
0121     void nextKeyframeWithColor(const QSet<int> &validColors);
0122     void previousKeyframeWithColor(int color);
0123     void previousKeyframeWithColor(const QSet<int> &validColors);
0124 
0125 private:
0126     struct Private;
0127     QScopedPointer<Private> m_d;
0128 };
0129 
0130 #endif // KISPLAYBACKENGINE_H