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