File indexing completed on 2024-04-28 04:52:26

0001 /*
0002     SPDX-FileCopyrightText: 2017 Nicolas Carion
0003     SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0004 */
0005 
0006 #pragma once
0007 
0008 #include "moveableItem.hpp"
0009 #include "undohelper.hpp"
0010 #include <memory>
0011 
0012 namespace Mlt {
0013 class Producer;
0014 }
0015 class EffectStackModel;
0016 class MarkerListModel;
0017 class TimelineModel;
0018 class TrackModel;
0019 class KeyframeModel;
0020 class ClipSnapModel;
0021 
0022 /** @brief This class represents a Clip object, as viewed by the backend.
0023    In general, the Gui associated with it will send modification queries (such as resize or move), and this class authorize them or not depending on the
0024    validity of the modifications
0025 */
0026 class ClipModel : public MoveableItem<Mlt::Producer>
0027 {
0028     ClipModel() = delete;
0029 
0030 protected:
0031     /** @brief This constructor is not meant to be called, call the static construct instead */
0032     ClipModel(const std::shared_ptr<TimelineModel> &parent, std::shared_ptr<Mlt::Producer> prod, const QString &binClipId, int id,
0033               PlaylistState::ClipState state, double speed = 1.);
0034 
0035 public:
0036     ~ClipModel() override;
0037     /** @brief Creates a clip, which references itself to the parent timeline
0038        Returns the (unique) id of the created clip
0039        @param parent is a pointer to the timeline
0040        @param binClip is the id of the bin clip associated
0041        @param id Requested id of the clip. Automatic if -1
0042     */
0043     static int construct(const std::shared_ptr<TimelineModel> &parent, const QString &binClipId, int id, PlaylistState::ClipState state, int audioStream = -1,
0044                          double speed = 1., bool warp_pitch = false);
0045 
0046     /** @brief Creates a clip, which references itself to the parent timeline
0047        Returns the (unique) id of the created clip
0048     This variants assumes a producer is already known, which should typically happen only at loading time.
0049     Note that there is no guarantee that this producer is actually going to be used. It might be discarded.
0050     */
0051     static int construct(const std::shared_ptr<TimelineModel> &parent, const QString &binClipId, const std::shared_ptr<Mlt::Producer> &producer,
0052                          PlaylistState::ClipState state, int tid, const QString &originalDecimalPoint, int playlist = 0);
0053 
0054     /** @brief returns a property of the clip, or from it's parent if it's a cut
0055      */
0056     const QString getProperty(const QString &name) const override;
0057     int getIntProperty(const QString &name) const;
0058     /** @brief returns the bin clip name
0059      */
0060     const QString clipName() const;
0061     const QString clipTag() const;
0062     QSize getFrameSize() const;
0063     bool showKeyframes() const;
0064     void setShowKeyframes(bool show);
0065 
0066     /** @brief Returns true if the clip can be converted to a video clip */
0067     bool canBeVideo() const;
0068     /** @brief Returns true if the clip can be converted to an audio clip */
0069     bool canBeAudio() const;
0070 
0071     /** @brief Returns true if the producer is embedded in a chain (for use with timeremap) */
0072     bool isChain() const;
0073     bool hasTimeRemap() const;
0074     /** @brief Returns the duration of the input map */
0075     int getRemapInputDuration() const;
0076     /** @brief Get the time remap effect parameters */
0077     QMap<QString, QString> getRemapValues() const;
0078     void setRemapValue(const QString &name, const QString &value);
0079 
0080     /** @brief Returns a comma separated list of effect names */
0081     const QString effectNames() const;
0082 
0083     /** @brief Returns true if effect stack is enabled */
0084     bool stackEnabled() const;
0085 
0086     /** @brief Returns a list of external files (e.g. LUTs) used by the effects of the clip */
0087     const QStringList externalFiles() const;
0088 
0089     /** @brief Returns the timeline clip status (video / audio only) */
0090     PlaylistState::ClipState clipState() const;
0091     /** @brief Returns the bin clip type (image, color, AV, ...) */
0092     ClipType::ProducerType clipType() const;
0093     /** @brief Sets the timeline clip status (video / audio only) */
0094     bool setClipState(PlaylistState::ClipState state, Fun &undo, Fun &redo);
0095     /** @brief The fake track is used in insert/overwrite mode.
0096      *  in this case, dragging a clip is always accepted, but the change is not applied to the model.
0097      *  so we use a 'fake' track id to pass to the qml view
0098      */
0099     int getFakeTrackId() const;
0100     void setFakeTrackId(int fid);
0101     void setFakePosition(int fpos);
0102     int getFakePosition() const;
0103     void setMixDuration(int mix, int offset);
0104     void setMixDuration(int mix);
0105     int getMixDuration() const;
0106     int getMixCutPosition() const;
0107     void setGrab(bool grab) override;
0108     void setSelected(bool sel) override;
0109 
0110     /** @brief Returns an XML representation of the clip with its effects */
0111     QDomElement toXml(QDomDocument &document);
0112 
0113     /** @brief Retrieve a list of all snaps for this clip */
0114     void allSnaps(std::vector<int> &snaps, int offset = 0) const;
0115 
0116     /** @brief Replace the bin producer with another bin clip */
0117     void switchBinReference(const QString newId, const QUuid &uuid);
0118 
0119 protected:
0120     /** @brief helper functions that creates the lambda */
0121     Fun setClipState_lambda(PlaylistState::ClipState state);
0122     /** @brief Returns a clip hash, useful for regression testing */
0123     QString clipHash() const;
0124 
0125 public:
0126     /** @brief returns the length of the item on the timeline
0127      */
0128     int getPlaytime() const override;
0129 
0130     /** @brief Returns the bin clip's id */
0131     const QString &binId() const;
0132 
0133     void registerClipToBin(std::shared_ptr<Mlt::Producer> service, bool registerProducer);
0134     void deregisterClipToBin(const QUuid &uuid);
0135 
0136     bool addEffect(const QString &effectId);
0137     bool addEffectWithUndo(const QString &effectId, Fun &undo, Fun &redo);
0138     bool copyEffect(const QUuid &uuid, const std::shared_ptr<EffectStackModel> &stackModel, int rowId);
0139     bool copyEffectWithUndo(const QUuid &uuid, const std::shared_ptr<EffectStackModel> &stackModel, int rowId, Fun &undo, Fun &redo);
0140     /** @brief Import effects from a different stackModel */
0141     bool importEffects(std::shared_ptr<EffectStackModel> stackModel);
0142     /** @brief Import effects from a service that contains some (another clip?) */
0143     bool importEffects(std::weak_ptr<Mlt::Service> service);
0144 
0145     bool removeFade(bool fromStart);
0146     /** @brief Adjust effects duration. Should be called after each resize / cut operation */
0147     bool adjustEffectLength(bool adjustFromEnd, int oldIn, int newIn, int oldDuration, int duration, int offset, Fun &undo, Fun &redo, bool logUndo);
0148     bool adjustEffectLength(const QString &effectName, int duration, int originalDuration, Fun &undo, Fun &redo);
0149     void passTimelineProperties(const std::shared_ptr<ClipModel> &other);
0150     KeyframeModel *getKeyframeModel();
0151 
0152     int fadeIn() const;
0153     int fadeOut() const;
0154 
0155     /** @brief Tracks have two sub playlists to enable same track transitions. This returns the index of the sub-playlist containing this clip */
0156     int getSubPlaylistIndex() const;
0157     void setSubPlaylistIndex(int index, int trackId);
0158     const QString clipThumbPath();
0159 
0160     friend class TrackModel;
0161     friend class TimelineModel;
0162     friend class TimelineItemModel;
0163     friend class TimelineController;
0164     friend struct TimelineFunctions;
0165 
0166 protected:
0167     Mlt::Producer *service() const override;
0168 
0169     /** @brief Performs a resize of the given clip.
0170      *  This method is protected because it shouldn't be called directly. Call the function in the timeline instead.
0171      *  If a snap point is within reach, the operation will be coerced to use it.
0172      *  @param size is the new size of the clip
0173      *  @param right is true if we change the right side of the clip, false otherwise
0174      *  @param undo Lambda function containing the current undo stack. Will be updated with current operation
0175      *  @param redo Lambda function containing the current redo queue. Will be updated with current operation
0176      *  @return Returns true if the operation succeeded, and otherwise nothing is modified
0177      */
0178     bool requestResize(int size, bool right, Fun &undo, Fun &redo, bool logUndo = true, bool hasMix = false) override;
0179 
0180     /** @brief Performs a slip of the given clip
0181      *  This moves the in and out point of the clip without changing its size or position.
0182      *  @param offset How many frames in and out point should be moved
0183      *  @param undo Lambda function containing the current undo stack. Will be updated with current operation
0184      *  @param redo Lambda function containing the current redo queue. Will be updated with current operation
0185      *  @return Returns true if the operation succeeded, and otherwise nothing is modified
0186      */
0187     bool requestSlip(int offset, Fun &undo, Fun &redo, bool logUndo = true);
0188 
0189     void setCurrentTrackId(int tid, bool finalMove = true) override;
0190     void setPosition(int pos) override;
0191     void setInOut(int in, int out) override;
0192 
0193     /** @brief This function change the global (timeline-wise) enabled state of the effects
0194      */
0195     void setTimelineEffectsEnabled(bool enabled);
0196 
0197     /** @brief This functions should be called when the producer of the binClip changes, to allow refresh
0198      * @param state corresponds to the state of the clip we want (audio or video)
0199      * @param speed corresponds to the speed we need. Leave to 0 to keep current speed. Warning: this function doesn't notify the model. Unless you know what
0200      * you are doing, better use useTimewarProducer to change the speed
0201      */
0202     void refreshProducerFromBin(int trackId, PlaylistState::ClipState state, int stream, double speed, bool hasPitch, bool secondPlaylist = false,
0203                                 bool timeremap = false);
0204     void refreshProducerFromBin(int trackId);
0205 
0206     /** @brief This functions replaces the current producer with a slowmotion one
0207        It also resizes the producer so that set of frames contained in the clip is the same
0208     */
0209     bool useTimewarpProducer(double speed, bool pitchCompensate, bool changeDuration, Fun &undo, Fun &redo);
0210     /** @brief Lambda that merely changes the speed (in and out are untouched) */
0211     Fun useTimewarpProducer_lambda(double speed, int stream, bool pitchCompensate);
0212 
0213     bool useTimeRemapProducer(bool enable, Fun &undo, Fun &redo);
0214     /** @brief Lambda that merely changes the speed (in and out are untouched) */
0215     Fun useTimeRemapProducer_lambda(bool enable, int audioStream, const QMap<QString, QString> &remapProperties);
0216 
0217     /** @brief Returns the marker model associated with this clip */
0218     std::shared_ptr<MarkerListModel> getMarkerModel() const;
0219 
0220     /** @brief Returns the number of audio channels for this clip */
0221     int audioChannels() const;
0222     /** @brief Returns the active audio stream for this clip (or -1 if we only have 1 stream */
0223     int audioStream() const;
0224     /** @brief Returns true if we have multiple audio streams in the master clip */
0225     bool audioMultiStream() const;
0226     /** @brief Returns the list of available audio stream indexes for the bin clip */
0227     int audioStreamIndex() const;
0228 
0229     bool audioEnabled() const;
0230     bool isAudioOnly() const;
0231     double getSpeed() const;
0232 
0233     /** @brief Returns the clip offset (calculated in the model between 2 clips from same bin clip */
0234     void setOffset(int offset);
0235     /** @brief Clears the clip offset (calculated in the model between 2 clips from same bin clip */
0236     void clearOffset();
0237     int getOffset() const;
0238     /** @brief Returns the producer's duration, or -1 if it can be resized without limit  */
0239     int getMaxDuration() const;
0240 
0241     /** @brief Returns the clip status (normal, proxied, missing, etc)  */
0242     FileStatus::ClipStatus clipStatus() const;
0243 
0244     /** @brief This is a debug function to ensure the clip is in a valid state */
0245     bool checkConsistency();
0246 
0247     /** @brief Resize remap keyframes */
0248     void requestRemapResize(int inPoint, int outPoint, int oldIn, int oldOut, Fun &undo, Fun &redo);
0249 
0250 protected:
0251     std::shared_ptr<Mlt::Producer> m_producer;
0252     std::shared_ptr<Mlt::Producer> getProducer();
0253 
0254     std::shared_ptr<EffectStackModel> m_effectStack;
0255     std::shared_ptr<ClipSnapModel> m_clipMarkerModel;
0256     /** @brief This is the Id of the bin clip this clip corresponds to. */
0257     QString m_binClipId;
0258 
0259     /** @brief Whether this clip can be freely resized */
0260     bool m_endlessResize;
0261 
0262     /** @brief Used to trigger a forced thumb reload, when producer changes */
0263     bool forceThumbReload;
0264 
0265     PlaylistState::ClipState m_currentState;
0266     ClipType::ProducerType m_clipType;
0267     /** @brief Speed of the clip */
0268     double m_speed = -1;
0269 
0270     bool m_canBeVideo, m_canBeAudio;
0271     /** @brief Fake track id, used when dragging in insert/overwrite mode */
0272     int m_fakeTrack;
0273     int m_fakePosition;
0274     /** @brief Temporary val to store offset between two clips with same bin id. */
0275     int m_positionOffset;
0276     /** @brief Tracks have two sub playlists to enable same track transitions, we store in which one this clip is. */
0277     int m_subPlaylistIndex;
0278 
0279     /** @brief Remember last set track, so that we don't unnecessarily refresh the producer when deleting and re-adding a clip on same track */
0280     int m_lastTrackId = -1;
0281 
0282     /** @brief Duration of a same track mix. */
0283     int m_mixDuration;
0284     /** @brief Position of the original cut, relative to mix right side */
0285     int m_mixCutPos;
0286     /** @brief True if the clip has a timeremap effect */
0287     bool m_hasTimeRemap;
0288 };