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

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 #include <QOpenGLFramebufferObject>
0015 #include <QOpenGLFunctions>
0016 #include <QOpenGLShaderProgram>
0017 #include <QQuickWidget>
0018 #include <QRect>
0019 #include <QSemaphore>
0020 #include <QThread>
0021 #include <QTimer>
0022 
0023 #include "bin/model/markerlistmodel.hpp"
0024 #include "definitions.h"
0025 #include "kdenlivesettings.h"
0026 #include "scopes/sharedframe.h"
0027 
0028 #include <mlt++/MltProfile.h>
0029 
0030 class QOpenGLFunctions_3_2_Core;
0031 
0032 namespace Mlt {
0033 class Filter;
0034 class Producer;
0035 class Consumer;
0036 } // namespace Mlt
0037 
0038 class RenderThread;
0039 class FrameRenderer;
0040 class MonitorProxy;
0041 class MarkerSortModel;
0042 
0043 using thread_function_t = void *(*)(void *);
0044 
0045 /** @class VideoWidget
0046  *  @brief QQuickView that renders an .
0047  *
0048  * Creates an MLT consumer and renders a GL view from the consumer. This pipeline is one of:
0049  *
0050  *    A. YUV gl texture w/o GPU filter acceleration
0051  *    B. YUV gl texture multithreaded w/o GPU filter acceleration
0052  *    C. RGB gl texture multithreaded w/ GPU filter acceleration and no sync
0053  *    D. RGB gl texture multithreaded w/ GPU filter acceleration and sync
0054  */
0055 class VideoWidget : public QQuickWidget, protected QOpenGLFunctions
0056 {
0057     Q_OBJECT
0058     Q_PROPERTY(QRect rect READ rect NOTIFY rectChanged)
0059     Q_PROPERTY(float zoom READ zoom NOTIFY zoomChanged)
0060 
0061 public:
0062     friend class MonitorController;
0063     friend class Monitor;
0064     friend class MonitorProxy;
0065     using ClientWaitSync_fp = GLenum (*)(GLsync, GLbitfield, GLuint64);
0066 
0067     VideoWidget(int id, QWidget *parent = nullptr);
0068     ~VideoWidget() override;
0069 
0070     int requestedSeekPosition;
0071     void createThread(RenderThread **thread, thread_function_t function, void *data);
0072     void startGlsl();
0073     void stopGlsl();
0074     void clear();
0075     void stopCapture();
0076 
0077     int displayWidth() const { return m_rect.width(); }
0078     void updateAudioForAnalysis();
0079     int displayHeight() const { return m_rect.height(); }
0080 
0081     QObject *videoWidget() { return this; }
0082     Mlt::Filter *glslManager() const { return m_glslManager; }
0083     QRect rect() const { return m_rect; }
0084     QRect effectRect() const { return m_effectRect; }
0085     float zoom() const;
0086     QPoint offset() const;
0087     std::shared_ptr<Mlt::Consumer> consumer();
0088     Mlt::Producer *producer();
0089     QSize profileSize() const;
0090     QRect displayRect() const;
0091     /** @brief set to true if we want to emit a QImage of the frame for analysis */
0092     bool sendFrameForAnalysis;
0093     /** @brief delete and rebuild consumer, for example when external display is switched */
0094     void resetConsumer(bool fullReset);
0095     void lockMonitor();
0096     void releaseMonitor();
0097     int droppedFrames() const;
0098     void resetDrops();
0099     bool checkFrameNumber(int pos, bool isPlaying);
0100     /** @brief Return current timeline position */
0101     int getCurrentPos() const;
0102     /** @brief Requests a monitor refresh */
0103     void requestRefresh();
0104     void setRulerInfo(int duration, const std::shared_ptr<MarkerSortModel> &model = nullptr);
0105     MonitorProxy *getControllerProxy();
0106     bool playZone(bool loop = false);
0107     bool loopClip(QPoint inOut);
0108     void startConsumer();
0109     void stop();
0110     int rulerHeight() const;
0111     /** @brief return current play producer's playing speed */
0112     double playSpeed() const;
0113     /** @brief Purge and restart consumer */
0114     void restart();
0115     /** @brief Returns current audio volume */
0116     int volume() const;
0117     /** @brief Set audio volume on consumer */
0118     void setVolume(double volume);
0119     /** @brief Returns current producer's duration in frames */
0120     int duration() const;
0121     /** @brief Set a property on the MLT consumer */
0122     void setConsumerProperty(const QString &name, const QString &value);
0123     /** @brief Clear consumer cache */
0124     void purgeCache();
0125     /** @brief Show / hide monitor ruler */
0126     void switchRuler(bool show);
0127     /** @brief Returns true if consumer is initialized */
0128     bool isReady() const;
0129     /** @brief Returns some infos about the GPU */
0130     virtual const QStringList getGPUInfo();
0131 
0132 protected:
0133     void mouseReleaseEvent(QMouseEvent *event) override;
0134     void mouseDoubleClickEvent(QMouseEvent *event) override;
0135     /** @brief Update producer, should ONLY be called from monitor
0136     * @param producer
0137     * @param isActive
0138     * @param position If == 0 producer position will be used.
0139     * If == -1 consumer position will be used if possible.
0140     * If == -2 position will not be set.
0141     */
0142     int setProducer(const std::shared_ptr<Mlt::Producer> &producer, bool isActive, int position);
0143     int setProducer(const QString &file);
0144     QString frameToTime(int frames) const;
0145 
0146 public Q_SLOTS:
0147     void requestSeek(int position, bool noAudioScrub = false);
0148     void setZoom(float zoom, bool force = false);
0149     void setOffsetX(int x, int max);
0150     void setOffsetY(int y, int max);
0151     void slotZoom(bool zoomIn);
0152     void initializeGL();
0153     void releaseAnalyse();
0154     bool switchPlay(bool play, double speed = 1.0);
0155     void reloadProfile();
0156     /** @brief Update MLT's consumer scaling 
0157      *  @returns true is scaling was changed
0158      */
0159     bool updateScaling();
0160 
0161 Q_SIGNALS:
0162     void frameDisplayed(const SharedFrame &frame);
0163     void frameRendered(int pos);
0164     void dragStarted();
0165     void seekTo(int x);
0166     void gpuNotSupported();
0167     void started();
0168     void paused();
0169     void playing();
0170     void rectChanged();
0171     void zoomChanged(float zoomRatio);
0172     void monitorPlay();
0173     void switchFullScreen(bool minimizeOnly = false);
0174     void mouseSeek(int eventDelta, uint modifiers);
0175     void startDrag();
0176     void analyseFrame(const QImage &);
0177     void showContextMenu(const QPoint &);
0178     void lockMonitor(bool);
0179     void passKeyEvent(QKeyEvent *);
0180     void panView(const QPoint &diff);
0181 
0182 protected:
0183     Mlt::Filter *m_glslManager;
0184     // TODO: MTL has lock/unlock of individual nodes. Use those.
0185     // keeping this for refactoring ease.
0186     QMutex m_mltMutex;
0187     std::shared_ptr<Mlt::Consumer> m_consumer;
0188     std::shared_ptr<Mlt::Producer> m_producer;
0189     int m_id;
0190     /** @brief The height of the qml ruler */
0191     int m_rulerHeight;
0192     /** @brief The height of the qml ruler and audio thumbs */
0193     int m_displayRulerHeight;
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     QColor m_bgColor;
0197 
0198 private:
0199     QRect m_rect;
0200     QRect m_effectRect;
0201     GLuint m_texture[3];
0202     QOpenGLShaderProgram *m_shader;
0203     QPoint m_panStart;
0204     QPoint m_dragStart;
0205     QSemaphore m_initSem;
0206     QSemaphore m_analyseSem;
0207     bool m_isInitialized;
0208     int m_maxProducerPosition;
0209     int m_bckpMax;
0210     Mlt::Event *m_threadStartEvent;
0211     Mlt::Event *m_threadStopEvent;
0212     Mlt::Event *m_threadCreateEvent;
0213     Mlt::Event *m_threadJoinEvent;
0214     Mlt::Event *m_displayEvent;
0215     Mlt::Event *m_renderEvent;
0216     FrameRenderer *m_frameRenderer;
0217     int m_projectionLocation;
0218     int m_modelViewLocation;
0219     int m_vertexLocation;
0220     int m_texCoordLocation;
0221     int m_colorspaceLocation;
0222     int m_textureLocation[3];
0223     QTimer m_refreshTimer;
0224     float m_zoom;
0225     QSize m_profileSize;
0226     int m_colorSpace;
0227     double m_dar;
0228     bool m_sendFrame;
0229     bool m_isZoneMode;
0230     bool m_isLoopMode;
0231     int m_loopIn;
0232     int m_loopOut;
0233     QPoint m_offset;
0234     MonitorProxy *m_proxy;
0235     std::shared_ptr<Mlt::Producer> m_blackClip;
0236     static void on_frame_show(mlt_consumer, VideoWidget *widget, mlt_event_data);
0237     static void on_frame_render(mlt_consumer, VideoWidget *widget, mlt_frame frame);
0238     static void on_gl_frame_show(mlt_consumer, VideoWidget *widget, mlt_event_data data);
0239     static void on_gl_nosync_frame_show(mlt_consumer, VideoWidget *widget, mlt_event_data data);
0240     QOpenGLFramebufferObject *m_fbo;
0241     void refreshSceneLayout();
0242     void resetZoneMode();
0243     /** @brief Restart consumer, keeping preview scaling settings */
0244     bool restartConsumer();
0245 
0246     /* OpenGL context management. Interfaces to MLT according to the configured render pipeline.
0247      */
0248 private Q_SLOTS:
0249     void resizeGL(int width, int height);
0250     void updateTexture(GLuint yName, GLuint uName, GLuint vName);
0251     void paintGL();
0252     void onFrameDisplayed(const SharedFrame &frame);
0253     int reconfigure();
0254     void refresh();
0255     void switchRecordState(bool on);
0256 
0257 protected:
0258     QMutex m_contextSharedAccess;
0259     QOffscreenSurface m_offscreenSurface;
0260     SharedFrame m_sharedFrame;
0261     QOpenGLContext *m_shareContext;
0262 
0263     /** @brief adjust monitor ruler size (for example if we want to display audio thumbs permanently) */
0264     void updateRulerHeight(int addedHeight);
0265     bool acquireSharedFrameTextures();
0266     void bindShaderProgram();
0267     void createGPUAccelFragmentProg();
0268     void createShader();
0269     void createYUVTextureProjectFragmentProg();
0270     void disableGPUAccel();
0271     void releaseSharedFrameTextures();
0272 
0273     // pipeline A - YUV gl texture w/o GPU filter acceleration
0274     // pipeline B - YUV gl texture multithreaded w/o GPU filter acceleration
0275     // pipeline C - RGB gl texture multithreaded w/ GPU filter acceleration and no sync
0276     // pipeline D - RGB gl texture multithreaded w/ GPU filter acceleration and sync
0277     bool m_openGLSync;
0278     bool initGPUAccelSync();
0279 
0280     // pipeline C & D
0281     bool initGPUAccel();
0282     bool onlyGLESGPUAccel() const;
0283 
0284     // pipeline A & B & C & D
0285     // not null iff D
0286     ClientWaitSync_fp m_ClientWaitSync;
0287 
0288 protected:
0289     void resizeEvent(QResizeEvent *event) override;
0290     void mousePressEvent(QMouseEvent *) override;
0291     void mouseMoveEvent(QMouseEvent *) override;
0292     void keyPressEvent(QKeyEvent *event) override;
0293 };
0294 
0295 class RenderThread : public QThread
0296 {
0297     Q_OBJECT
0298 public:
0299     RenderThread(thread_function_t function, void *data, QOpenGLContext *context, QSurface *surface);
0300     ~RenderThread() override;
0301 
0302 protected:
0303     void run() override;
0304 
0305 private:
0306     thread_function_t m_function;
0307     void *m_data;
0308     QOpenGLContext *m_context;
0309     QSurface *m_surface;
0310 };
0311 
0312 class FrameRenderer : public QThread
0313 {
0314     Q_OBJECT
0315 public:
0316     explicit FrameRenderer(QOpenGLContext *shareContext, QSurface *surface, VideoWidget::ClientWaitSync_fp clientWaitSync);
0317     ~FrameRenderer() override;
0318     QSemaphore *semaphore() { return &m_semaphore; }
0319     QOpenGLContext *context() const { return m_context; }
0320     Q_INVOKABLE void showFrame(Mlt::Frame frame);
0321     Q_INVOKABLE void showGLFrame(Mlt::Frame frame);
0322     Q_INVOKABLE void showGLNoSyncFrame(Mlt::Frame frame);
0323 
0324 public Q_SLOTS:
0325     void cleanup();
0326 
0327 Q_SIGNALS:
0328     void textureReady(GLuint yName, GLuint uName = 0, GLuint vName = 0);
0329     void frameDisplayed(const SharedFrame &frame);
0330 
0331 private:
0332     QSemaphore m_semaphore;
0333     SharedFrame m_displayFrame;
0334     QOpenGLContext *m_context;
0335     QSurface *m_surface;
0336     VideoWidget::ClientWaitSync_fp m_ClientWaitSync;
0337 
0338     void pipelineSyncToFrame(Mlt::Frame &);
0339 
0340 public:
0341     GLuint m_renderTexture[3];
0342     GLuint m_displayTexture[3];
0343     QOpenGLFunctions_3_2_Core *m_gl32;
0344     bool sendAudioForAnalysis;
0345 };