File indexing completed on 2024-04-21 04:51:49

0001 /*
0002     SPDX-FileCopyrightText: 2007 Jean-Baptiste Mardelle <jb@kdenlive.org>
0003 
0004 SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005 */
0006 
0007 #pragma once
0008 
0009 #include "abstractmonitor.h"
0010 #include "bin/model/markerlistmodel.hpp"
0011 #include "definitions.h"
0012 #include "utils/gentime.h"
0013 #include "scopes/sharedframe.h"
0014 #include "widgets/timecodedisplay.h"
0015 
0016 #include <QTimer>
0017 #include <QToolBar>
0018 #include <QWidgetAction>
0019 
0020 #include <memory>
0021 #include <unordered_set>
0022 
0023 class SnapModel;
0024 class ProjectClip;
0025 class MonitorManager;
0026 class QSlider;
0027 class QToolButton;
0028 class KActionMenu;
0029 class KDualAction;
0030 class KSelectAction;
0031 class KMessageWidget;
0032 class QScrollBar;
0033 class RecManager;
0034 class QmlManager;
0035 class QLabel;
0036 class VideoWidget;
0037 class MonitorAudioLevel;
0038 class MonitorProxy;
0039 class MarkerSortModel;
0040 
0041 namespace Mlt {
0042 class Profile;
0043 class Filter;
0044 } // namespace Mlt
0045 
0046 class VolumeAction : public QWidgetAction
0047 {
0048     Q_OBJECT
0049 public:
0050     explicit VolumeAction(QObject *parent);
0051     QWidget *createWidget(QWidget *parent) override;
0052 
0053 Q_SIGNALS:
0054     void volumeChanged(int volume);
0055 };
0056 
0057 
0058 class Monitor : public AbstractMonitor
0059 {
0060     Q_OBJECT
0061 
0062 public:
0063     friend class MonitorManager;
0064 
0065     Monitor(Kdenlive::MonitorId id, MonitorManager *manager, QWidget *parent = nullptr);
0066     ~Monitor() override;
0067     bool locked{false};
0068     void resetProfile();
0069     /** @brief Rebuild consumers after a property change */
0070     void resetConsumer(bool fullReset);
0071     void setupMenu(QMenu *goMenu, QMenu *overlayMenu, QAction *playZone, QAction *loopZone, QMenu *markerMenu = nullptr, QAction *loopClip = nullptr);
0072     const QString activeClipId();
0073     int position();
0074     void updateTimecodeFormat();
0075     void updateMarkers();
0076     /** @brief Controller for the clip currently displayed (only valid for clip monitor). */
0077     std::shared_ptr<ProjectClip> currentController() const;
0078     void reloadProducer(const QString &id);
0079     /** @brief Reimplemented from QWidget, updates the palette colors. */
0080     void setPalette(const QPalette &p);
0081     /** @brief Returns current project's fps. */
0082     double fps() const;
0083     /** @brief Get url for the clip's thumbnail */
0084     QString getMarkerThumb(GenTime pos);
0085     int getZoneStart();
0086     int getZoneEnd();
0087     /** @brief Get the in and out points selected in the clip monitor.
0088      * @return a QPoint where x() is the in point, and y() is the out point + 1.
0089      * E.g. if the user sets in=100, out=101, then this returns <100, 102>.
0090      */
0091     QPoint getZoneInfo() const;
0092     void setUpEffectGeometry(const QRect &r, const QVariantList &list = QVariantList(), const QVariantList &types = QVariantList());
0093     /** @brief Set a property on the effect scene */
0094     void setEffectSceneProperty(const QString &name, const QVariant &value);
0095     /** @brief Returns effective display size */
0096     QSize profileSize() const;
0097     QRect effectRect() const;
0098     QVariantList effectPolygon() const;
0099     QVariantList effectRoto() const;
0100     void setEffectKeyframe(bool enable);
0101     void sendFrameForAnalysis(bool analyse);
0102     void updateAudioForAnalysis();
0103     void switchMonitorInfo(int code);
0104     void restart();
0105     void mute(bool) override;
0106     /** @brief Returns the action displaying record toolbar */
0107     QAction *recAction();
0108     void refreshIcons();
0109     /** @brief Send audio thumb data to qml for on monitor display */
0110     void prepareAudioThumb();
0111     void connectAudioSpectrum(bool activate);
0112     /** @brief Set a property on the Qml scene **/
0113     void setQmlProperty(const QString &name, const QVariant &value);
0114     void displayAudioMonitor(bool isActive);
0115     /** @brief Set the guides list model to currently active item (bin clip or timeline) **/
0116     void updateGuidesList();
0117     /** @brief Prepare split effect from timeline clip producer **/
0118     void activateSplit();
0119     /** @brief Clear monitor display **/
0120     void clearDisplay();
0121     void setProducer(std::shared_ptr<Mlt::Producer> producer, int pos = -1);
0122     void reconfigure();
0123     /** @brief Saves current monitor frame to an image file, and add it to project if addToProject is set to true **/
0124     void slotExtractCurrentFrame(QString frameName = QString(), bool addToProject = false);
0125     /** @brief Zoom in active monitor */
0126     void slotZoomIn();
0127     /** @brief Zoom out active monitor */
0128     void slotZoomOut();
0129     /** @brief Set a property on the MLT consumer */
0130     void setConsumerProperty(const QString &name, const QString &value);
0131     /** @brief Play or Loop zone sets a fake "out" on the producer. It is necessary to reset this before reloading the producer */
0132     void resetPlayOrLoopZone(const QString &binId);
0133     /** @brief Returns a pointer to monitor proxy, allowing to manage seek and consumer position */
0134     MonitorProxy *getControllerProxy();
0135     /** @brief Update active track in multitrack view */
0136     void updateMultiTrackView(int tid);
0137     /** @brief Returns true if monitor is currently fullscreen */
0138     bool monitorIsFullScreen() const;
0139     void reloadActiveStream();
0140     /** @brief Trigger a refresh of audio thumbs colors */
0141     void refreshAudioThumbs();
0142     /** @brief Trigger a refresh of audio thumbs on notrmalization change */
0143     void normalizeAudioThumbs();
0144     /** @brief Returns true if monitor is playing */
0145     bool isPlaying() const;
0146     /** @brief Enables / disables effect scene*/
0147     void enableEffectScene(bool enable);
0148     /** @brief Update the document's uuid - used for qml thumb cache*/
0149     void updateDocumentUuid();
0150     /** @brief Focus the timecode to allow editing*/
0151     void focusTimecode();
0152     /** @brief Ensure the video widget has focus to make keyboard shortcuts work */
0153     void fixFocus();
0154     /** @brief Show a rec countdown over the monitor **/
0155     void startCountDown();
0156     void stopCountDown();
0157     /** @brief Reset monitor scene to default **/
0158     void resetScene();
0159     /** @brief Set monitor zone **/
0160     void loadZone(int in, int out);
0161     /** @brief Extract current frame to image file with path **/
0162     void extractFrame(const QString &path);
0163     /** @brief Returns some infos about the GPU */
0164     const QStringList getGPUInfo();
0165 
0166 protected:
0167     void mousePressEvent(QMouseEvent *event) override;
0168     void mouseReleaseEvent(QMouseEvent *event) override;
0169     void mouseDoubleClickEvent(QMouseEvent *event) override;
0170     void resizeEvent(QResizeEvent *event) override;
0171     void keyPressEvent(QKeyEvent *event) override;
0172 
0173     /** @brief Move to another position on mouse wheel event.
0174      *
0175      * Moves towards the end of the clip/timeline on mouse wheel down/back, the
0176      * opposite on mouse wheel up/forward.
0177      * Ctrl + wheel moves by a second, without Ctrl it moves by a single frame. */
0178     void wheelEvent(QWheelEvent *event) override;
0179     void updateBgColor();
0180 
0181 private:
0182     std::shared_ptr<ProjectClip> m_controller;
0183     /** @brief The QQuickView that handles our monitor display (video and qml overlay) **/
0184     VideoWidget *m_glMonitor;
0185     /** @brief Container for our QQuickView monitor display (QQuickView needs to be embedded) **/
0186     QWidget *m_glWidget;
0187     /** @brief Scrollbar for our monitor view, used when zooming the monitor **/
0188     QScrollBar *m_verticalScroll;
0189     /** @brief Scrollbar for our monitor view, used when zooming the monitor **/
0190     QScrollBar *m_horizontalScroll;
0191     /** @brief Manager for qml overlay for the QQuickView **/
0192     QmlManager *m_qmlManager;
0193     std::shared_ptr<SnapModel> m_snaps;
0194 
0195     std::shared_ptr<Mlt::Filter> m_splitEffect;
0196     std::shared_ptr<Mlt::Producer> m_splitProducer;
0197     std::shared_ptr<MarkerListModel> m_markerModel{nullptr};
0198     int m_length;
0199     bool m_dragStarted;
0200     RecManager *m_recManager;
0201     /** @brief The widget showing current time position **/
0202     TimecodeDisplay *m_timePos;
0203     KDualAction *m_playAction;
0204     KSelectAction *m_forceSize;
0205     KSelectAction *m_background;
0206     /** Has to be available so we can enable and disable it. */
0207     QAction *m_loopClipAction;
0208     QAction *m_zoomVisibilityAction;
0209     KActionMenu *m_configMenuAction;
0210     QMenu *m_contextMenu;
0211     QMenu *m_playMenu;
0212     KActionMenu *m_markerMenu;
0213     QMenu *m_audioChannels;
0214     QToolButton *m_streamsButton;
0215     QAction *m_streamAction;
0216     QPoint m_DragStartPosition;
0217     /** true if selected clip is transition, false = selected clip is clip.
0218      *  Necessary because sometimes we get two signals, e.g. we get a clip and we get selected transition = nullptr. */
0219     bool m_loopClipTransition;
0220     GenTime getSnapForPos(bool previous);
0221     QToolBar *m_toolbar;
0222     QToolBar *m_trimmingbar;
0223     QAction *m_oneLess;
0224     QAction *m_oneMore;
0225     QAction *m_fiveLess;
0226     QAction *m_fiveMore;
0227     QLabel *m_trimmingOffset;
0228     QAction *m_editMarker;
0229     KMessageWidget *m_infoMessage;
0230     int m_forceSizeFactor;
0231     MonitorSceneType m_lastMonitorSceneType;
0232     bool m_displayingCountdown;
0233     MonitorAudioLevel *m_audioMeterWidget;
0234     QTimer m_droppedTimer;
0235     double m_displayedFps;
0236     int m_speedIndex;
0237     QMetaObject::Connection m_switchConnection;
0238     QMetaObject::Connection m_captureConnection;
0239 
0240     void adjustScrollBars(float horizontal, float vertical);
0241     void loadQmlScene(MonitorSceneType type, const QVariant &sceneData = QVariant());
0242     void updateQmlDisplay(int currentOverlay);
0243     /** @brief Create temporary Mlt::Tractor holding a clip and it's effectless clone */
0244     void buildSplitEffect(Mlt::Producer *original);
0245     /** @brief Returns true if monitor is currently visible (not in a tab or hidden)*/
0246     bool monitorVisible() const;
0247     /** To easily get them when creating the right click menu */
0248     QAction *m_markIn;
0249     QAction *m_markOut;
0250 
0251 private Q_SLOTS:
0252     void slotSetThumbFrame();
0253     void slotSeek();
0254     void updateClipZone(const QPoint zone);
0255     void slotGoToMarker(QAction *action);
0256     void slotSetVolume(int volume);
0257     void slotEditMarker();
0258     void slotExtractCurrentZone();
0259     void onFrameDisplayed(const SharedFrame &frame);
0260     void slotStartDrag();
0261     void setZoom(float zoomRatio);
0262     void slotAdjustEffectCompare();
0263     void slotShowMenu(const QPoint pos);
0264     void slotForceSize(QAction *a);
0265     void buildBackgroundedProducer(int pos);
0266     void slotSeekToKeyFrame();
0267     void slotLockMonitor(bool lock);
0268     void slotSwitchPlay();
0269     void slotEditInlineMarker();
0270     /** @brief Pass keypress event to mainwindow */
0271     void doKeyPressEvent(QKeyEvent *);
0272     /** @brief There was an error initializing Movit */
0273     void gpuError();
0274     void setOffsetX(int x);
0275     void setOffsetY(int y);
0276     /** @brief Pan monitor view */
0277     void panView(QPoint diff);
0278     void slotSeekPosition(int);
0279     void addSnapPoint(int pos);
0280     void removeSnapPoint(int pos);
0281     /** @brief Process seek and optionally pause monitor */
0282     void processSeek(int pos, bool noAudioScrub = false);
0283     /** @brief Check and display dropped frames */
0284     void checkDrops();
0285     /** @brief En/Disable the show record timecode feature in clip monitor */
0286     void slotSwitchRecTimecode(bool enable);
0287 
0288 public Q_SLOTS:
0289     void slotSetScreen(int screenIndex);
0290     void slotPreviewResource(const QString &path, const QString &title);
0291     // void slotSetClipProducer(DocClipBase *clip, QPoint zone = QPoint(), bool forceUpdate = false, int position = -1);
0292     void updateClipProducer(const std::shared_ptr<Mlt::Producer> &prod);
0293     void updateClipProducer(const QString &playlist);
0294     void slotOpenClip(const std::shared_ptr<ProjectClip> &controller, int in = -1, int out = -1);
0295     void slotRefreshMonitor(bool visible);
0296     void slotSeek(int pos);
0297     void stop() override;
0298     void start() override;
0299     void switchPlay(bool play);
0300     void updatePlayAction(bool play);
0301     void slotPlay() override;
0302     void pause();
0303     void slotPlayZone();
0304     void slotLoopZone();
0305     /** @brief Loops the selected item (clip or transition). */
0306     void slotLoopClip(QPoint inOut);
0307     void slotForward(double speed = 0, bool allowNormalPlay = false) override;
0308     void slotRewind(double speed = 0) override;
0309     void slotRewindOneFrame(int diff = 1);
0310     void slotForwardOneFrame(int diff = 1);
0311     /** @brief Display a non blocking error message to user **/
0312     void warningMessage(const QString &text, int timeout = 5000, const QList<QAction *> &actions = QList<QAction *>());
0313     void slotStart();
0314     /** @brief Set position and information for the trimming preview
0315     * @param pos Absolute position in frames
0316     * @param offset Difference in frames beetween @p pos and the current position (to be displayed in the monitor toolbar)
0317     * @param frames1 Position in frames to be displayed in the monitor overlay for preview tile one
0318     * @param frames2 Position in frames to be displayed in the monitor overlay for preview tile two
0319     */
0320     void slotTrimmingPos(int pos, int offset, int frames1, int frames2);
0321     /** @brief Move the position for the trimming preview by the given offset
0322     * @param offset How many frames the position should be moved
0323     * @see slotTrimmingPos
0324     */
0325     void slotTrimmingPos(int offset);
0326     void slotEnd();
0327     void slotSetZoneStart();
0328     void slotSetZoneEnd();
0329     void slotZoneStart();
0330     void slotZoneEnd();
0331     void slotLoadClipZone(const QPoint &zone);
0332     void slotSeekToNextSnap();
0333     void slotSeekToPreviousSnap();
0334     void adjustRulerSize(int length, const std::shared_ptr<MarkerSortModel> &markerModel = nullptr);
0335     void setTimePos(const QString &pos);
0336     /** @brief Display the on monitor effect scene (to adjust geometry over monitor). */
0337     void slotShowEffectScene(MonitorSceneType sceneType, bool temporary = false, const QVariant &sceneData = QVariant());
0338     bool effectSceneDisplayed(MonitorSceneType effectType);
0339     /** @brief split screen to compare clip with and without effect */
0340     void slotSwitchCompare(bool enable);
0341     void slotMouseSeek(int eventDelta, uint modifiers) override;
0342     void slotSwitchFullScreen(bool minimizeOnly = false) override;
0343     /** @brief Display or hide the record toolbar */
0344     void slotSwitchRec(bool enable);
0345     /** @brief Display or hide the trimming toolbar and monitor scene*/
0346     void slotSwitchTrimming(bool enable);
0347     /** @brief Request QImage of current frame */
0348     void slotGetCurrentImage(bool request);
0349     /** @brief Enable/disable display of monitor's audio levels widget */
0350     void slotSwitchAudioMonitor();
0351     /** @brief Request seeking */
0352     void requestSeek(int pos);
0353     /** @brief Request seeking only if monitor is visible*/
0354     void requestSeekIfVisible(int pos);
0355     /** @brief Check current position to show relevant infos in qml view (markers, zone in/out, etc). */
0356     void checkOverlay(int pos = -1);
0357     void refreshMonitorIfActive(bool directUpdate = false) override;
0358     void refreshMonitor(bool directUpdate = false);
0359     void forceMonitorRefresh();
0360     /** @brief Clear read ahead cache, to ensure up to date audio */
0361     void purgeCache();
0362 
0363 Q_SIGNALS:
0364     void screenChanged(int screenIndex);
0365     void seekPosition(int pos);
0366     void seekRemap(int pos);
0367     void updateScene();
0368     void durationChanged(int);
0369     void refreshClipThumbnail(const QString &);
0370     void zoneUpdated(const QPoint &);
0371     void zoneUpdatedWithUndo(const QPoint &, const QPoint &);
0372     /** @brief  Editing transitions / effects over the monitor requires the renderer to send frames as QImage.
0373      *      This causes a major slowdown, so we only enable it if required */
0374     void requestFrameForAnalysis(bool);
0375     void effectChanged(const QRect &);
0376     void effectPointsChanged(const QVariantList &);
0377     void addRemoveKeyframe();
0378     void seekToNextKeyframe();
0379     void seekToPreviousKeyframe();
0380     void seekToKeyframe(int);
0381     void addClipToProject(const QUrl &);
0382     /** @brief Request display of current bin clip. */
0383     void refreshCurrentClip();
0384     void addTimelineEffect(const QStringList &);
0385     void passKeyPress(QKeyEvent *);
0386     /** @brief Enable / disable project monitor multitrack view (split view with one track in each quarter). */
0387     void multitrackView(bool, bool);
0388     void timeCodeUpdated(const QString &);
0389     void addMarker();
0390     void deleteMarker(bool deleteGuide = true);
0391     void seekToPreviousSnap();
0392     void seekToNextSnap();
0393     void createSplitOverlay(std::shared_ptr<Mlt::Filter>);
0394     void removeSplitOverlay();
0395     void activateTrack(int, bool notesMode = false);
0396     void autoKeyframeChanged();
0397     void zoneDurationChanged(int duration);
0398 };