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