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

0001 /*
0002     SPDX-FileCopyrightText: 2011-2014 Meltytech LLC
0003     SPDX-FileCopyrightText: 2011-2014 Dan Dennedy <dan@dennedy.org>
0004 
0005     SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0006 */
0007 
0008 #pragma once
0009 
0010 #include <QFont>
0011 #include <QMutex>
0012 #include <QOffscreenSurface>
0013 #include <QOpenGLContext>
0014 
0015 #include <QQuickWidget>
0016 #include <QRect>
0017 #include <QSemaphore>
0018 #include <QThread>
0019 #include <QTimer>
0020 
0021 #include "bin/model/markerlistmodel.hpp"
0022 #include "definitions.h"
0023 #include "kdenlivesettings.h"
0024 #include "scopes/sharedframe.h"
0025 
0026 #include <mlt++/MltEvent.h>
0027 #include <mlt++/MltFilter.h>
0028 #include <mlt++/MltProfile.h>
0029 
0030 namespace Mlt {
0031 class Filter;
0032 class Producer;
0033 class Consumer;
0034 } // namespace Mlt
0035 
0036 class RenderThread;
0037 class FrameRenderer;
0038 class MonitorProxy;
0039 class MarkerSortModel;
0040 
0041 typedef void *(*thread_function_t)(void *);
0042 
0043 /** @class VideoWidget
0044  *  @brief QQuickView that renders an .
0045  *
0046  * Creates an MLT consumer and renders a GL view from the consumer. This pipeline is one of:
0047  *
0048  *    A. YUV gl texture w/o GPU filter acceleration
0049  *    B. YUV gl texture multithreaded w/o GPU filter acceleration
0050  *    C. RGB gl texture multithreaded w/ GPU filter acceleration and no sync
0051  *    D. RGB gl texture multithreaded w/ GPU filter acceleration and sync
0052  */
0053 class VideoWidget : public QQuickWidget
0054 {
0055     Q_OBJECT
0056     Q_PROPERTY(QRect rect READ rect NOTIFY rectChanged)
0057     Q_PROPERTY(float zoom READ zoom NOTIFY zoomChanged)
0058 
0059 public:
0060     friend class MonitorController;
0061     friend class Monitor;
0062     friend class MonitorProxy;
0063 
0064     VideoWidget(int id, QObject *parent = nullptr);
0065     virtual ~VideoWidget();
0066 
0067     int requestedSeekPosition;
0068     void createThread(RenderThread **thread, thread_function_t function, void *data);
0069     void startGlsl();
0070     void stopGlsl();
0071     void clear();
0072     void stopCapture();
0073 
0074     int displayWidth() const { return m_rect.width(); }
0075     void updateAudioForAnalysis();
0076     int displayHeight() const { return m_rect.height(); }
0077 
0078     QObject *videoWidget() { return this; }
0079     QRect rect() const { return m_rect; }
0080     QRect effectRect() const { return m_effectRect; }
0081     float zoom() const;
0082     QPoint offset() const;
0083     std::shared_ptr<Mlt::Consumer> consumer();
0084     Mlt::Producer *producer();
0085     QSize profileSize() const;
0086     QRect displayRect() const;
0087     /** @brief set to true if we want to emit a QImage of the frame for analysis */
0088     bool sendFrameForAnalysis;
0089     /** @brief delete and rebuild consumer, for example when external display is switched */
0090     void resetConsumer(bool fullReset);
0091     void lockMonitor();
0092     void releaseMonitor();
0093     int droppedFrames() const;
0094     void resetDrops();
0095     bool checkFrameNumber(int pos, bool isPlaying);
0096     /** @brief Return current timeline position */
0097     int getCurrentPos() const;
0098     /** @brief Requests a monitor refresh */
0099     void requestRefresh();
0100     void setRulerInfo(int duration, const std::shared_ptr<MarkerSortModel> &model = nullptr);
0101     MonitorProxy *getControllerProxy();
0102     bool playZone(bool loop = false);
0103     bool loopClip(QPoint inOut);
0104     void startConsumer();
0105     void stop();
0106     int rulerHeight() const;
0107     /** @brief return current play producer's playing speed */
0108     double playSpeed() const;
0109     /** @brief Purge and restart consumer */
0110     void restart();
0111     /** @brief Returns current audio volume */
0112     int volume() const;
0113     /** @brief Set audio volume on consumer */
0114     void setVolume(double volume);
0115     /** @brief Returns current producer's duration in frames */
0116     int duration() const;
0117     /** @brief Set a property on the MLT consumer */
0118     void setConsumerProperty(const QString &name, const QString &value);
0119     /** @brief Clear consumer cache */
0120     void purgeCache();
0121     /** @brief Show / hide monitor ruler */
0122     void switchRuler(bool show);
0123     /** @brief Returns true if consumer is initialized */
0124     bool isReady() const;
0125     virtual const QStringList getGPUInfo();
0126 
0127 protected:
0128     void mouseReleaseEvent(QMouseEvent *event) override;
0129     void mouseDoubleClickEvent(QMouseEvent *event) override;
0130     /** @brief Update producer, should ONLY be called from monitor
0131      * @param producer
0132      * @param isActive
0133      * @param position If == 0 producer position will be used.
0134      * If == -1 consumer position will be used if possible.
0135      * If == -2 position will not be set.
0136      */
0137     int setProducer(const std::shared_ptr<Mlt::Producer> &producer, bool isActive, int position);
0138     int setProducer(const QString &file);
0139     QString frameToTime(int frames) const;
0140 
0141 public Q_SLOTS:
0142     virtual void initialize();
0143     virtual void beforeRendering(){};
0144     virtual void renderVideo();
0145     virtual void onFrameDisplayed(const SharedFrame &frame);
0146     void requestSeek(int position, bool noAudioScrub = false);
0147     void setZoom(float zoom, bool force = false);
0148     void setOffsetX(int x, int max);
0149     void setOffsetY(int y, int max);
0150     void slotZoom(bool zoomIn);
0151     void releaseAnalyse();
0152     bool switchPlay(bool play, double speed = 1.0);
0153     void reloadProfile();
0154     /** @brief Update MLT's consumer scaling
0155      *  @returns true is scaling was changed
0156      */
0157     bool updateScaling();
0158 
0159 Q_SIGNALS:
0160     void frameDisplayed(const SharedFrame &frame);
0161     void frameRendered(int pos);
0162     void imageReady();
0163     void dragStarted();
0164     void seekTo(int x);
0165     void gpuNotSupported();
0166     void started();
0167     void paused();
0168     void playing();
0169     void rectChanged();
0170     void zoomChanged(float zoomRatio);
0171     void monitorPlay();
0172     void switchFullScreen(bool minimizeOnly = false);
0173     void mouseSeek(int eventDelta, uint modifiers);
0174     void startDrag();
0175     void analyseFrame(const QImage &);
0176     void showContextMenu(const QPoint &);
0177     void lockMonitor(bool);
0178     void passKeyEvent(QKeyEvent *);
0179     void panView(const QPoint &diff);
0180     void reconnectWindow();
0181 
0182 protected:
0183     // TODO: MTL has lock/unlock of individual nodes. Use those.
0184     // keeping this for refactoring ease.
0185     QMutex m_mltMutex;
0186     std::shared_ptr<Mlt::Consumer> m_consumer;
0187     std::shared_ptr<Mlt::Producer> m_producer;
0188     int m_id;
0189     /** @brief The height of the qml ruler */
0190     int m_rulerHeight;
0191     /** @brief The height of the qml ruler and audio thumbs */
0192     int m_displayRulerHeight;
0193     int m_maxTextureSize;
0194     /** @brief For some reason on Qt6 fullscreen switch, image position is not correctly updated, so use this to track state */
0195     bool refreshZoom{false};
0196     SharedFrame m_sharedFrame;
0197     bool m_sendFrame;
0198     QSemaphore m_analyseSem;
0199     float m_zoom;
0200     QSize m_profileSize;
0201     QMutex m_mutex;
0202     bool m_isInitialized;
0203 
0204     /** @brief adjust monitor ruler size (for example if we want to display audio thumbs permanently) */
0205     virtual void updateRulerHeight(int addedHeight);
0206 
0207 private:
0208     QRect m_rect;
0209     QRect m_effectRect;
0210     QPoint m_panStart;
0211     QPoint m_dragStart;
0212     QSemaphore m_initSem;
0213     bool m_qmlEvent;
0214     bool m_swallowDrop{false};
0215     int m_maxProducerPosition;
0216     int m_bckpMax;
0217     std::unique_ptr<Mlt::Filter> m_glslManager;
0218     std::unique_ptr<Mlt::Event> m_threadStartEvent;
0219     std::unique_ptr<Mlt::Event> m_threadStopEvent;
0220     std::unique_ptr<Mlt::Event> m_threadCreateEvent;
0221     std::unique_ptr<Mlt::Event> m_threadJoinEvent;
0222     std::unique_ptr<Mlt::Event> m_displayEvent;
0223     FrameRenderer *m_frameRenderer;
0224     QTimer m_refreshTimer;
0225     int m_colorSpace;
0226     double m_dar;
0227     bool m_isZoneMode;
0228     bool m_isLoopMode;
0229     int m_loopIn;
0230     int m_loopOut;
0231     QPoint m_offset;
0232     MonitorProxy *m_proxy;
0233     std::unique_ptr<RenderThread> m_renderThread;
0234     std::shared_ptr<Mlt::Producer> m_blackClip;
0235     static void on_frame_show(mlt_consumer, VideoWidget *widget, mlt_event_data);
0236     static void on_frame_render(mlt_consumer, VideoWidget *widget, mlt_frame frame);
0237     /*static void on_gl_frame_show(mlt_consumer, VideoWidget *widget, mlt_event_data data);
0238     static void on_gl_nosync_frame_show(mlt_consumer, VideoWidget *widget, mlt_event_data data);*/
0239 
0240     void refreshSceneLayout();
0241     void resetZoneMode();
0242     bool initGPUAccel();
0243     void disableGPUAccel();
0244     /** @brief Restart consumer, keeping preview scaling settings */
0245     bool restartConsumer();
0246 
0247     /* OpenGL context management. Interfaces to MLT according to the configured render pipeline.
0248      */
0249 private Q_SLOTS:
0250     void resizeVideo(int width, int height);
0251     int reconfigure();
0252     void refresh();
0253     void switchRecordState(bool on);
0254 
0255 protected:
0256     void resizeEvent(QResizeEvent *event) override;
0257     void mousePressEvent(QMouseEvent *) override;
0258     void mouseMoveEvent(QMouseEvent *) override;
0259     void keyPressEvent(QKeyEvent *event) override;
0260 };
0261 
0262 class RenderThread : public QThread
0263 {
0264     Q_OBJECT
0265 public:
0266     RenderThread(thread_function_t function, void *data);
0267     ~RenderThread();
0268 
0269 protected:
0270     void run() override;
0271 
0272 private:
0273     thread_function_t m_function;
0274     void *m_data;
0275     std::unique_ptr<QOpenGLContext> m_context;
0276     std::unique_ptr<QOffscreenSurface> m_surface;
0277 };
0278 
0279 class FrameRenderer : public QThread
0280 {
0281     Q_OBJECT
0282 public:
0283     explicit FrameRenderer();
0284     ~FrameRenderer();
0285     QSemaphore *semaphore() { return &m_semaphore; }
0286     SharedFrame getDisplayFrame();
0287     Q_INVOKABLE void showFrame(Mlt::Frame frame);
0288     void requestImage();
0289     QImage image() const { return m_image; }
0290 
0291 Q_SIGNALS:
0292     void frameDisplayed(const SharedFrame &frame);
0293     void imageReady();
0294 
0295 private:
0296     QSemaphore m_semaphore;
0297     SharedFrame m_displayFrame;
0298     bool m_imageRequested;
0299     QImage m_image;
0300 };