CuteLogger
Fast and simple logging solution for Qt based applications
videowidget.h
1/*
2 * Copyright (c) 2011-2026 Meltytech, LLC
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#ifndef VIDEOWIDGET_H
19#define VIDEOWIDGET_H
20
21#include "mltcontroller.h"
22#include "settings.h"
23#include "sharedframe.h"
24
25enum class HdrTransfer { SDR = 0, HLG = 1, PQ = 2 };
26
27inline HdrTransfer hdrTransferFromTrc(const QString &trc)
28{
29 if (trc == QLatin1String("arib-std-b67"))
30 return HdrTransfer::HLG;
31 if (trc == QLatin1String("smpte2084"))
32 return HdrTransfer::PQ;
33 return HdrTransfer::SDR;
34}
35
36#include <memory>
37#include <QAbstractVideoBuffer>
38#include <QMutex>
39#include <QPointer>
40#include <QQuickWidget>
41#include <QRectF>
42#include <QSemaphore>
43#include <QThread>
44#include <QTimer>
45#include <QVideoFrame>
46#include <QVideoFrameFormat>
47#include <QVideoSink>
48
49class QmlFilter;
50class QmlMetadata;
51class QOpenGLContext;
52class QOffscreenSurface;
53
54namespace Mlt {
55
56class Filter;
57class RenderThread;
58class FrameRenderer;
59
60typedef void *(*thread_function_t)(void *);
61
62class VideoWidget : public QQuickWidget, public Controller
63{
64 Q_OBJECT
65 Q_PROPERTY(QRectF rect READ rect NOTIFY rectChanged)
66 Q_PROPERTY(int grid READ grid NOTIFY gridChanged)
67 Q_PROPERTY(bool snapToGrid READ snapToGrid NOTIFY snapToGridChanged)
68 Q_PROPERTY(float zoom READ zoom NOTIFY zoomChanged)
69 Q_PROPERTY(QPoint offset READ offset NOTIFY offsetChanged)
70 Q_PROPERTY(bool oldVideoOutput READ oldVideoOutput CONSTANT)
71
72public:
73 VideoWidget(QObject *parent = 0);
74 virtual ~VideoWidget();
75
76 int setProducer(Mlt::Producer *, bool isMulti = false) override;
77 void createThread(RenderThread **thread, thread_function_t function, void *data);
78 void startGlsl();
79 void stopGlsl();
80 int reconfigure(bool isMulti) override;
81
82 void play(double speed = 1.0) override
83 {
84 Controller::play(speed);
85 if (speed == 0)
86 emit paused();
87 else
88 emit playing();
89 }
90 void seek(int position) override
91 {
92 Controller::seek(position);
93 if (Settings.playerPauseAfterSeek())
94 emit paused();
95 }
96 void refreshConsumer(bool scrubAudio = false) override;
97 void pause(int position = -1) override
98 {
99 Controller::pause();
100 emit paused();
101 }
102 int displayWidth() const override { return m_rect.width(); }
103 int displayHeight() const override { return m_rect.height(); }
104
105 QObject *videoWidget() override { return this; }
106 QRectF rect() const { return m_rect; }
107 int grid() const { return m_grid; }
108 float zoom() const
109 {
110 return m_zoom * MLT.profile().height() * MLT.profile().dar() / m_rect.width();
111 }
112 QPoint offset() const;
113 QImage image() const;
114 bool imageIsProxy() const;
115 void requestImage();
116 bool snapToGrid() const { return m_snapToGrid; }
117 int maxTextureSize() const { return m_maxTextureSize; }
118 bool oldVideoOutput() const;
119 void toggleVuiDisplay();
120 Q_INVOKABLE void setVideoSink(QVideoSink *sink);
121
122public slots:
123 void setGrid(int grid);
124 void setZoom(float zoom);
125 void setOffsetX(int x);
126 void setOffsetY(int y);
127 void setBlankScene();
128 void setCurrentFilter(QmlFilter *filter, QmlMetadata *meta);
129 void setSnapToGrid(bool snap);
130 virtual void initialize();
131 virtual void beforeRendering() {}
132 virtual void renderVideo();
133 virtual void onFrameDisplayed(const SharedFrame &frame);
134 void showFrame(Mlt::Frame frame, QByteArray p016Buffer = {});
135
136signals:
137 void frameDisplayed(const SharedFrame &frame);
138 void dragStarted();
139 void seekTo(int x);
140 void gpuNotSupported();
141 void started();
142 void paused();
143 void playing();
144 void rectChanged();
145 void gridChanged();
146 void zoomChanged();
147 void offsetChanged(const QPoint &offset = QPoint());
148 void imageReady();
149 void snapToGridChanged();
150 void toggleZoom(bool);
151 void stepZoom(float, float);
152 void videoFrameReady(const QVideoFrame &frame);
153 void hdrTransferChanged(HdrTransfer transfer);
154
155private:
156 QRectF m_rect;
157 int m_grid;
158 QPoint m_dragStart;
159 QSemaphore m_initSem;
160 bool m_isInitialized;
161 std::unique_ptr<Filter> m_glslManager;
162 std::unique_ptr<Event> m_threadStartEvent;
163 std::unique_ptr<Event> m_threadStopEvent;
164 std::unique_ptr<Event> m_threadCreateEvent;
165 std::unique_ptr<Event> m_threadJoinEvent;
166 QSemaphore m_frameSemaphore;
167 bool m_imageRequested;
168 const bool m_oldVideoOutput;
169 float m_zoom;
170 QPoint m_offset;
171 QUrl m_savedQmlSource;
172 bool m_hideVui;
173 bool m_snapToGrid;
174 QTimer m_refreshTimer;
175 bool m_scrubAudio;
176 QPoint m_mousePosition;
177 std::unique_ptr<RenderThread> m_renderThread;
178 QPointer<QVideoSink> m_videoSink;
179 FrameRenderer *m_frameRenderer;
180
181 static void on_frame_show(mlt_consumer, VideoWidget *widget, mlt_event_data);
182 void pushFrameToSink(const SharedFrame &frame, QByteArray p016Buffer = {});
183 struct P016Pool
184 {
185 QMutex mutex;
186 QList<QByteArray> buffers;
187 };
188 std::shared_ptr<P016Pool> m_p016Pool;
189
190private slots:
191 void resizeVideo(int width, int height);
192 void onRefreshTimeout();
193
194protected:
195 void resizeEvent(QResizeEvent *event) override;
196 void mousePressEvent(QMouseEvent *) override;
197 void mouseMoveEvent(QMouseEvent *) override;
198 void wheelEvent(QWheelEvent *event) override;
199 void keyPressEvent(QKeyEvent *event) override;
200 bool event(QEvent *event) override;
201 virtual void createShader() {}
202
203 int m_maxTextureSize;
204 SharedFrame m_sharedFrame;
205 QMutex m_mutex;
206};
207
208class RenderThread : public QThread
209{
210 Q_OBJECT
211public:
212 RenderThread(thread_function_t function, void *data);
213 ~RenderThread();
214
215protected:
216 void run();
217
218private:
219 thread_function_t m_function;
220 void *m_data;
221 std::unique_ptr<QOpenGLContext> m_context;
222 std::unique_ptr<QOffscreenSurface> m_surface;
223};
224
225class FrameRenderer : public QThread
226{
227 Q_OBJECT
228public:
229 FrameRenderer();
230 ~FrameRenderer();
231 QSemaphore *semaphore() { return &m_semaphore; }
232 SharedFrame getDisplayFrame();
233 Q_INVOKABLE void showFrame(Mlt::Frame frame);
234 void requestImage();
235 QImage image() const { return m_image; }
236
237signals:
238 void frameDisplayed(const SharedFrame &frame);
239 void imageReady();
240
241private:
242 QSemaphore m_semaphore;
243 mutable QMutex m_mutex;
244 SharedFrame m_displayFrame;
245 bool m_imageRequested;
246 QImage m_image;
247};
248
249} // namespace Mlt
250
251#endif