1 | // Copyright (C) 2016 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #include "qgraphicsvideoitem.h" |
5 | #include "qvideosink.h" |
6 | |
7 | #include <qobject.h> |
8 | #include <qvideoframe.h> |
9 | #include <qvideoframeformat.h> |
10 | |
11 | #include <QtCore/qcoreevent.h> |
12 | #include <QtCore/qpointer.h> |
13 | |
14 | QT_BEGIN_NAMESPACE |
15 | |
16 | class QGraphicsVideoItemPrivate |
17 | { |
18 | public: |
19 | QGraphicsVideoItemPrivate() |
20 | : rect(0.0, 0.0, 320, 240) |
21 | { |
22 | } |
23 | |
24 | QGraphicsVideoItem *q_ptr = nullptr; |
25 | |
26 | QVideoSink *sink = nullptr; |
27 | QRectF rect; |
28 | QRectF boundingRect; |
29 | QSizeF nativeSize; |
30 | QVideoFrame m_frame; |
31 | Qt::AspectRatioMode m_aspectRatioMode = Qt::KeepAspectRatio; |
32 | |
33 | void updateRects(); |
34 | |
35 | void _q_present(const QVideoFrame &); |
36 | }; |
37 | |
38 | void QGraphicsVideoItemPrivate::updateRects() |
39 | { |
40 | q_ptr->prepareGeometryChange(); |
41 | |
42 | boundingRect = rect; |
43 | if (nativeSize.isEmpty()) |
44 | return; |
45 | |
46 | if (m_aspectRatioMode == Qt::KeepAspectRatio) { |
47 | QSizeF size = nativeSize; |
48 | size.scale(s: rect.size(), mode: Qt::KeepAspectRatio); |
49 | |
50 | boundingRect = QRectF(0, 0, size.width(), size.height()); |
51 | boundingRect.moveCenter(p: rect.center()); |
52 | } |
53 | } |
54 | |
55 | void QGraphicsVideoItemPrivate::_q_present(const QVideoFrame &frame) |
56 | { |
57 | m_frame = frame; |
58 | q_ptr->update(rect: boundingRect); |
59 | |
60 | if (frame.isValid()) { |
61 | const QSize &size = frame.surfaceFormat().viewport().size(); |
62 | if (nativeSize != size) { |
63 | nativeSize = size; |
64 | |
65 | updateRects(); |
66 | emit q_ptr->nativeSizeChanged(size: nativeSize); |
67 | } |
68 | } |
69 | } |
70 | |
71 | /*! |
72 | \class QGraphicsVideoItem |
73 | |
74 | \brief The QGraphicsVideoItem class provides a graphics item which display video produced by a QMediaPlayer or QCamera. |
75 | |
76 | \inmodule QtMultimediaWidgets |
77 | \ingroup multimedia |
78 | |
79 | Attaching a QGraphicsVideoItem to a QMediaPlayer or QCamera allows it to display |
80 | the video or image output of that media object. |
81 | |
82 | \snippet multimedia-snippets/video.cpp Video graphics item |
83 | |
84 | \b {Note}: Only a single display output can be attached to a media |
85 | object at one time. |
86 | |
87 | \sa QMediaPlayer, QVideoWidget, QCamera |
88 | */ |
89 | |
90 | /*! |
91 | Constructs a graphics item that displays video. |
92 | |
93 | The \a parent is passed to QGraphicsItem. |
94 | */ |
95 | QGraphicsVideoItem::QGraphicsVideoItem(QGraphicsItem *parent) |
96 | : QGraphicsObject(parent) |
97 | , d_ptr(new QGraphicsVideoItemPrivate) |
98 | { |
99 | d_ptr->q_ptr = this; |
100 | d_ptr->sink = new QVideoSink(this); |
101 | |
102 | connect(sender: d_ptr->sink, SIGNAL(videoFrameChanged(const QVideoFrame &)), receiver: this, SLOT(_q_present(const QVideoFrame &))); |
103 | } |
104 | |
105 | /*! |
106 | Destroys a video graphics item. |
107 | */ |
108 | QGraphicsVideoItem::~QGraphicsVideoItem() |
109 | { |
110 | delete d_ptr; |
111 | } |
112 | |
113 | /*! |
114 | \since 6.0 |
115 | \property QGraphicsVideoItem::videoSink |
116 | \brief Returns the underlying video sink that can render video frames |
117 | to the current item. |
118 | This property is never \c nullptr. |
119 | Example of how to render video frames to QGraphicsVideoItem: |
120 | \snippet multimedia-snippets/video.cpp GraphicsVideoItem Surface |
121 | \sa QMediaPlayer::setVideoOutput |
122 | */ |
123 | |
124 | QVideoSink *QGraphicsVideoItem::videoSink() const |
125 | { |
126 | return d_func()->sink; |
127 | } |
128 | |
129 | /*! |
130 | \property QGraphicsVideoItem::aspectRatioMode |
131 | \brief how a video is scaled to fit the graphics item's size. |
132 | */ |
133 | |
134 | Qt::AspectRatioMode QGraphicsVideoItem::aspectRatioMode() const |
135 | { |
136 | return d_func()->m_aspectRatioMode; |
137 | } |
138 | |
139 | void QGraphicsVideoItem::setAspectRatioMode(Qt::AspectRatioMode mode) |
140 | { |
141 | Q_D(QGraphicsVideoItem); |
142 | if (d->m_aspectRatioMode == mode) |
143 | return; |
144 | |
145 | d->m_aspectRatioMode = mode; |
146 | d->updateRects(); |
147 | } |
148 | |
149 | /*! |
150 | \property QGraphicsVideoItem::offset |
151 | \brief the video item's offset. |
152 | |
153 | QGraphicsVideoItem will draw video using the offset for its top left |
154 | corner. |
155 | */ |
156 | |
157 | QPointF QGraphicsVideoItem::offset() const |
158 | { |
159 | return d_func()->rect.topLeft(); |
160 | } |
161 | |
162 | void QGraphicsVideoItem::setOffset(const QPointF &offset) |
163 | { |
164 | Q_D(QGraphicsVideoItem); |
165 | |
166 | d->rect.moveTo(p: offset); |
167 | d->updateRects(); |
168 | } |
169 | |
170 | /*! |
171 | \property QGraphicsVideoItem::size |
172 | \brief the video item's size. |
173 | |
174 | QGraphicsVideoItem will draw video scaled to fit size according to its |
175 | fillMode. |
176 | */ |
177 | |
178 | QSizeF QGraphicsVideoItem::size() const |
179 | { |
180 | return d_func()->rect.size(); |
181 | } |
182 | |
183 | void QGraphicsVideoItem::setSize(const QSizeF &size) |
184 | { |
185 | Q_D(QGraphicsVideoItem); |
186 | |
187 | d->rect.setSize(size.isValid() ? size : QSizeF(0, 0)); |
188 | d->updateRects(); |
189 | } |
190 | |
191 | /*! |
192 | \property QGraphicsVideoItem::nativeSize |
193 | \brief the native size of the video. |
194 | */ |
195 | |
196 | QSizeF QGraphicsVideoItem::nativeSize() const |
197 | { |
198 | return d_func()->nativeSize; |
199 | } |
200 | |
201 | /*! |
202 | \reimp |
203 | */ |
204 | QRectF QGraphicsVideoItem::boundingRect() const |
205 | { |
206 | return d_func()->boundingRect; |
207 | } |
208 | |
209 | /*! |
210 | \reimp |
211 | */ |
212 | void QGraphicsVideoItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) |
213 | { |
214 | Q_D(QGraphicsVideoItem); |
215 | |
216 | Q_UNUSED(option); |
217 | Q_UNUSED(widget); |
218 | |
219 | d->m_frame.paint(painter, rect: d->rect, options: { .backgroundColor: Qt::transparent, .aspectRatioMode: d->m_aspectRatioMode }); |
220 | } |
221 | |
222 | /*! |
223 | \fn int QGraphicsVideoItem::type() const |
224 | \reimp |
225 | |
226 | Returns an int representing the type of the video item. |
227 | */ |
228 | /*! |
229 | \variable QGraphicsVideoItem::d_ptr |
230 | \internal |
231 | */ |
232 | /*! |
233 | \enum QGraphicsVideoItem::anonymous |
234 | \internal |
235 | |
236 | \omitvalue Type |
237 | */ |
238 | /*! |
239 | \reimp |
240 | |
241 | \internal |
242 | */ |
243 | QVariant QGraphicsVideoItem::itemChange(GraphicsItemChange change, const QVariant &value) |
244 | { |
245 | return QGraphicsItem::itemChange(change, value); |
246 | } |
247 | |
248 | /*! |
249 | \internal |
250 | */ |
251 | void QGraphicsVideoItem::timerEvent(QTimerEvent *event) |
252 | { |
253 | QGraphicsObject::timerEvent(event); |
254 | } |
255 | |
256 | QT_END_NAMESPACE |
257 | |
258 | #include "moc_qgraphicsvideoitem.cpp" |
259 | |
260 | |
261 | |