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