| 1 | /**************************************************************************** | 
| 2 | ** | 
| 3 | ** Copyright (C) 2016 The Qt Company Ltd. | 
| 4 | ** Contact: https://www.qt.io/licensing/ | 
| 5 | ** | 
| 6 | ** This file is part of the Qt Toolkit. | 
| 7 | ** | 
| 8 | ** $QT_BEGIN_LICENSE:LGPL$ | 
| 9 | ** Commercial License Usage | 
| 10 | ** Licensees holding valid commercial Qt licenses may use this file in | 
| 11 | ** accordance with the commercial license agreement provided with the | 
| 12 | ** Software or, alternatively, in accordance with the terms contained in | 
| 13 | ** a written agreement between you and The Qt Company. For licensing terms | 
| 14 | ** and conditions see https://www.qt.io/terms-conditions. For further | 
| 15 | ** information use the contact form at https://www.qt.io/contact-us. | 
| 16 | ** | 
| 17 | ** GNU Lesser General Public License Usage | 
| 18 | ** Alternatively, this file may be used under the terms of the GNU Lesser | 
| 19 | ** General Public License version 3 as published by the Free Software | 
| 20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the | 
| 21 | ** packaging of this file. Please review the following information to | 
| 22 | ** ensure the GNU Lesser General Public License version 3 requirements | 
| 23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. | 
| 24 | ** | 
| 25 | ** GNU General Public License Usage | 
| 26 | ** Alternatively, this file may be used under the terms of the GNU | 
| 27 | ** General Public License version 2.0 or (at your option) the GNU General | 
| 28 | ** Public license version 3 or any later version approved by the KDE Free | 
| 29 | ** Qt Foundation. The licenses are as published by the Free Software | 
| 30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 | 
| 31 | ** included in the packaging of this file. Please review the following | 
| 32 | ** information to ensure the GNU General Public License requirements will | 
| 33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and | 
| 34 | ** https://www.gnu.org/licenses/gpl-3.0.html. | 
| 35 | ** | 
| 36 | ** $QT_END_LICENSE$ | 
| 37 | ** | 
| 38 | ****************************************************************************/ | 
| 39 |  | 
| 40 | #include "qvideowidget_p.h" | 
| 41 | #include "qpaintervideosurface_p.h" | 
| 42 |  | 
| 43 | #include <qmediaobject.h> | 
| 44 | #include <qmediaservice.h> | 
| 45 | #include <qvideowindowcontrol.h> | 
| 46 | #include <qvideowidgetcontrol.h> | 
| 47 |  | 
| 48 | #include <qvideorenderercontrol.h> | 
| 49 | #include <qvideosurfaceformat.h> | 
| 50 | #include <qpainter.h> | 
| 51 |  | 
| 52 | #include <qapplication.h> | 
| 53 | #include <qevent.h> | 
| 54 | #include <qboxlayout.h> | 
| 55 | #include <qnamespace.h> | 
| 56 |  | 
| 57 | #include <qwindow.h> | 
| 58 | #include <private/qhighdpiscaling_p.h> | 
| 59 |  | 
| 60 | #ifdef Q_OS_WIN | 
| 61 | #include <QtCore/qt_windows.h> | 
| 62 | #endif | 
| 63 |  | 
| 64 | using namespace Qt; | 
| 65 |  | 
| 66 | QT_BEGIN_NAMESPACE | 
| 67 |  | 
| 68 | QVideoWidgetControlBackend::QVideoWidgetControlBackend( | 
| 69 |         QMediaService *service, QVideoWidgetControl *control, QWidget *widget) | 
| 70 |     : m_service(service) | 
| 71 |     , m_widgetControl(control) | 
| 72 | { | 
| 73 |     connect(sender: control, SIGNAL(brightnessChanged(int)), receiver: widget, SLOT(_q_brightnessChanged(int))); | 
| 74 |     connect(sender: control, SIGNAL(contrastChanged(int)), receiver: widget, SLOT(_q_contrastChanged(int))); | 
| 75 |     connect(sender: control, SIGNAL(hueChanged(int)), receiver: widget, SLOT(_q_hueChanged(int))); | 
| 76 |     connect(sender: control, SIGNAL(saturationChanged(int)), receiver: widget, SLOT(_q_saturationChanged(int))); | 
| 77 |     connect(sender: control, SIGNAL(fullScreenChanged(bool)), receiver: widget, SLOT(_q_fullScreenChanged(bool))); | 
| 78 |  | 
| 79 |     QBoxLayout *layout = new QVBoxLayout; | 
| 80 |     layout->setContentsMargins(left: 0, top: 0, right: 0, bottom: 0); | 
| 81 |     layout->setSpacing(0); | 
| 82 |  | 
| 83 |     QWidget *videoWidget = control->videoWidget(); | 
| 84 |     videoWidget->setMouseTracking(widget->hasMouseTracking()); | 
| 85 |     layout->addWidget(videoWidget); | 
| 86 |  | 
| 87 |     widget->setLayout(layout); | 
| 88 | } | 
| 89 |  | 
| 90 | void QVideoWidgetControlBackend::releaseControl() | 
| 91 | { | 
| 92 |     m_service->releaseControl(control: m_widgetControl); | 
| 93 | } | 
| 94 |  | 
| 95 | void QVideoWidgetControlBackend::setBrightness(int brightness) | 
| 96 | { | 
| 97 |     m_widgetControl->setBrightness(brightness); | 
| 98 | } | 
| 99 |  | 
| 100 | void QVideoWidgetControlBackend::setContrast(int contrast) | 
| 101 | { | 
| 102 |     m_widgetControl->setContrast(contrast); | 
| 103 | } | 
| 104 |  | 
| 105 | void QVideoWidgetControlBackend::setHue(int hue) | 
| 106 | { | 
| 107 |     m_widgetControl->setHue(hue); | 
| 108 | } | 
| 109 |  | 
| 110 | void QVideoWidgetControlBackend::setSaturation(int saturation) | 
| 111 | { | 
| 112 |     m_widgetControl->setSaturation(saturation); | 
| 113 | } | 
| 114 |  | 
| 115 | void QVideoWidgetControlBackend::setFullScreen(bool fullScreen) | 
| 116 | { | 
| 117 |     m_widgetControl->setFullScreen(fullScreen); | 
| 118 | } | 
| 119 |  | 
| 120 |  | 
| 121 | Qt::AspectRatioMode QVideoWidgetControlBackend::aspectRatioMode() const | 
| 122 | { | 
| 123 |     return m_widgetControl->aspectRatioMode(); | 
| 124 | } | 
| 125 |  | 
| 126 | void QVideoWidgetControlBackend::setAspectRatioMode(Qt::AspectRatioMode mode) | 
| 127 | { | 
| 128 |     m_widgetControl->setAspectRatioMode(mode); | 
| 129 | } | 
| 130 |  | 
| 131 | QRendererVideoWidgetBackend::QRendererVideoWidgetBackend( | 
| 132 |         QMediaService *service, QVideoRendererControl *control, QWidget *widget) | 
| 133 |     : m_service(service) | 
| 134 |     , m_rendererControl(control) | 
| 135 |     , m_widget(widget) | 
| 136 |     , m_surface(new QPainterVideoSurface) | 
| 137 |     , m_aspectRatioMode(Qt::KeepAspectRatio) | 
| 138 |     , m_updatePaintDevice(true) | 
| 139 | { | 
| 140 |     connect(sender: this, SIGNAL(brightnessChanged(int)), receiver: m_widget, SLOT(_q_brightnessChanged(int))); | 
| 141 |     connect(sender: this, SIGNAL(contrastChanged(int)), receiver: m_widget, SLOT(_q_contrastChanged(int))); | 
| 142 |     connect(sender: this, SIGNAL(hueChanged(int)), receiver: m_widget, SLOT(_q_hueChanged(int))); | 
| 143 |     connect(sender: this, SIGNAL(saturationChanged(int)), receiver: m_widget, SLOT(_q_saturationChanged(int))); | 
| 144 |     connect(sender: m_surface, SIGNAL(frameChanged()), receiver: this, SLOT(frameChanged())); | 
| 145 |     connect(sender: m_surface, SIGNAL(surfaceFormatChanged(QVideoSurfaceFormat)), | 
| 146 |             receiver: this, SLOT(formatChanged(QVideoSurfaceFormat))); | 
| 147 |  | 
| 148 |     if (m_rendererControl) | 
| 149 |         m_rendererControl->setSurface(m_surface); | 
| 150 | } | 
| 151 |  | 
| 152 | QRendererVideoWidgetBackend::~QRendererVideoWidgetBackend() | 
| 153 | { | 
| 154 |     delete m_surface; | 
| 155 | } | 
| 156 |  | 
| 157 | QAbstractVideoSurface *QRendererVideoWidgetBackend::videoSurface() const | 
| 158 | { | 
| 159 |     return m_surface; | 
| 160 | } | 
| 161 |  | 
| 162 | void QRendererVideoWidgetBackend::releaseControl() | 
| 163 | { | 
| 164 |     if (m_service && m_rendererControl) | 
| 165 |         m_service->releaseControl(control: m_rendererControl); | 
| 166 | } | 
| 167 |  | 
| 168 | void QRendererVideoWidgetBackend::clearSurface() | 
| 169 | { | 
| 170 |     if (m_rendererControl) | 
| 171 |         m_rendererControl->setSurface(0); | 
| 172 | } | 
| 173 |  | 
| 174 | void QRendererVideoWidgetBackend::setBrightness(int brightness) | 
| 175 | { | 
| 176 |     m_surface->setBrightness(brightness); | 
| 177 |  | 
| 178 |     emit brightnessChanged(brightness); | 
| 179 | } | 
| 180 |  | 
| 181 | void QRendererVideoWidgetBackend::setContrast(int contrast) | 
| 182 | { | 
| 183 |     m_surface->setContrast(contrast); | 
| 184 |  | 
| 185 |     emit contrastChanged(contrast); | 
| 186 | } | 
| 187 |  | 
| 188 | void QRendererVideoWidgetBackend::setHue(int hue) | 
| 189 | { | 
| 190 |     m_surface->setHue(hue); | 
| 191 |  | 
| 192 |     emit hueChanged(hue); | 
| 193 | } | 
| 194 |  | 
| 195 | void QRendererVideoWidgetBackend::setSaturation(int saturation) | 
| 196 | { | 
| 197 |     m_surface->setSaturation(saturation); | 
| 198 |  | 
| 199 |     emit saturationChanged(saturation); | 
| 200 | } | 
| 201 |  | 
| 202 | Qt::AspectRatioMode QRendererVideoWidgetBackend::aspectRatioMode() const | 
| 203 | { | 
| 204 |     return m_aspectRatioMode; | 
| 205 | } | 
| 206 |  | 
| 207 | void QRendererVideoWidgetBackend::setAspectRatioMode(Qt::AspectRatioMode mode) | 
| 208 | { | 
| 209 |     m_aspectRatioMode = mode; | 
| 210 |  | 
| 211 |     m_widget->updateGeometry(); | 
| 212 | } | 
| 213 |  | 
| 214 | void QRendererVideoWidgetBackend::setFullScreen(bool) | 
| 215 | { | 
| 216 | } | 
| 217 |  | 
| 218 | QSize QRendererVideoWidgetBackend::sizeHint() const | 
| 219 | { | 
| 220 |     return m_surface->surfaceFormat().sizeHint(); | 
| 221 | } | 
| 222 |  | 
| 223 | void QRendererVideoWidgetBackend::showEvent() | 
| 224 | { | 
| 225 | } | 
| 226 |  | 
| 227 | void QRendererVideoWidgetBackend::hideEvent(QHideEvent *) | 
| 228 | { | 
| 229 | #if QT_CONFIG(opengl) | 
| 230 |     m_updatePaintDevice = true; | 
| 231 | #endif | 
| 232 | } | 
| 233 |  | 
| 234 | void QRendererVideoWidgetBackend::resizeEvent(QResizeEvent *) | 
| 235 | { | 
| 236 |     updateRects(); | 
| 237 | } | 
| 238 |  | 
| 239 | void QRendererVideoWidgetBackend::moveEvent(QMoveEvent *) | 
| 240 | { | 
| 241 | } | 
| 242 |  | 
| 243 | void QRendererVideoWidgetBackend::paintEvent(QPaintEvent *event) | 
| 244 | { | 
| 245 |     QPainter painter(m_widget); | 
| 246 |  | 
| 247 |     if (m_widget->testAttribute(attribute: Qt::WA_OpaquePaintEvent)) { | 
| 248 |         QRegion borderRegion = event->region(); | 
| 249 |         borderRegion = borderRegion.subtracted(r: m_boundingRect); | 
| 250 |  | 
| 251 |         QBrush brush = m_widget->palette().window(); | 
| 252 |  | 
| 253 |         for (const QRect &r : borderRegion) | 
| 254 |             painter.fillRect(r, brush); | 
| 255 |     } | 
| 256 |  | 
| 257 |     if (m_surface->isActive() && m_boundingRect.intersects(r: event->rect())) { | 
| 258 |         m_surface->paint(painter: &painter, target: m_boundingRect, source: m_sourceRect); | 
| 259 |  | 
| 260 |         m_surface->setReady(true); | 
| 261 |     } else { | 
| 262 | #if QT_CONFIG(opengl) | 
| 263 |         if (m_updatePaintDevice && (painter.paintEngine()->type() == QPaintEngine::OpenGL | 
| 264 |                 || painter.paintEngine()->type() == QPaintEngine::OpenGL2)) { | 
| 265 |             m_updatePaintDevice = false; | 
| 266 |  | 
| 267 |             m_surface->updateGLContext(); | 
| 268 |             if (m_surface->supportedShaderTypes() & QPainterVideoSurface::GlslShader) { | 
| 269 |                 m_surface->setShaderType(QPainterVideoSurface::GlslShader); | 
| 270 |             } else { | 
| 271 |                 m_surface->setShaderType(QPainterVideoSurface::FragmentProgramShader); | 
| 272 |             } | 
| 273 |         } | 
| 274 | #endif | 
| 275 |     } | 
| 276 |  | 
| 277 | } | 
| 278 |  | 
| 279 | void QRendererVideoWidgetBackend::formatChanged(const QVideoSurfaceFormat &format) | 
| 280 | { | 
| 281 |     m_nativeSize = format.sizeHint(); | 
| 282 |  | 
| 283 |     updateRects(); | 
| 284 |  | 
| 285 |     m_widget->updateGeometry(); | 
| 286 |     m_widget->update(); | 
| 287 | } | 
| 288 |  | 
| 289 | void QRendererVideoWidgetBackend::frameChanged() | 
| 290 | { | 
| 291 |     m_widget->update(m_boundingRect); | 
| 292 | } | 
| 293 |  | 
| 294 | void QRendererVideoWidgetBackend::updateRects() | 
| 295 | { | 
| 296 |     QRect rect = m_widget->rect(); | 
| 297 |  | 
| 298 |     if (m_nativeSize.isEmpty()) { | 
| 299 |         m_boundingRect = QRect(); | 
| 300 |     } else if (m_aspectRatioMode == Qt::IgnoreAspectRatio) { | 
| 301 |         m_boundingRect = rect; | 
| 302 |         m_sourceRect = QRectF(0, 0, 1, 1); | 
| 303 |     } else if (m_aspectRatioMode == Qt::KeepAspectRatio) { | 
| 304 |         QSize size = m_nativeSize; | 
| 305 |         size.scale(s: rect.size(), mode: Qt::KeepAspectRatio); | 
| 306 |  | 
| 307 |         m_boundingRect = QRect(0, 0, size.width(), size.height()); | 
| 308 |         m_boundingRect.moveCenter(p: rect.center()); | 
| 309 |  | 
| 310 |         m_sourceRect = QRectF(0, 0, 1, 1); | 
| 311 |     } else if (m_aspectRatioMode == Qt::KeepAspectRatioByExpanding) { | 
| 312 |         m_boundingRect = rect; | 
| 313 |  | 
| 314 |         QSizeF size = rect.size(); | 
| 315 |         size.scale(s: m_nativeSize, mode: Qt::KeepAspectRatio); | 
| 316 |  | 
| 317 |         m_sourceRect = QRectF( | 
| 318 |                 0, 0, size.width() / m_nativeSize.width(), size.height() / m_nativeSize.height()); | 
| 319 |         m_sourceRect.moveCenter(p: QPointF(0.5, 0.5)); | 
| 320 |     } | 
| 321 | } | 
| 322 |  | 
| 323 | QWindowVideoWidgetBackend::QWindowVideoWidgetBackend( | 
| 324 |         QMediaService *service, QVideoWindowControl *control, QWidget *widget) | 
| 325 |     : m_service(service) | 
| 326 |     , m_windowControl(control) | 
| 327 |     , m_widget(widget) | 
| 328 | { | 
| 329 |     connect(sender: control, SIGNAL(brightnessChanged(int)), receiver: m_widget, SLOT(_q_brightnessChanged(int))); | 
| 330 |     connect(sender: control, SIGNAL(contrastChanged(int)), receiver: m_widget, SLOT(_q_contrastChanged(int))); | 
| 331 |     connect(sender: control, SIGNAL(hueChanged(int)), receiver: m_widget, SLOT(_q_hueChanged(int))); | 
| 332 |     connect(sender: control, SIGNAL(saturationChanged(int)), receiver: m_widget, SLOT(_q_saturationChanged(int))); | 
| 333 |     connect(sender: control, SIGNAL(fullScreenChanged(bool)), receiver: m_widget, SLOT(_q_fullScreenChanged(bool))); | 
| 334 |     connect(sender: control, SIGNAL(nativeSizeChanged()), receiver: m_widget, SLOT(_q_dimensionsChanged())); | 
| 335 |  | 
| 336 |     control->setWinId(widget->winId()); | 
| 337 | #if defined(Q_OS_WIN) | 
| 338 |     // Disable updates to avoid flickering while resizing/moving. | 
| 339 |     m_widget->setUpdatesEnabled(false); | 
| 340 | #endif | 
| 341 | } | 
| 342 |  | 
| 343 | QWindowVideoWidgetBackend::~QWindowVideoWidgetBackend() | 
| 344 | { | 
| 345 | } | 
| 346 |  | 
| 347 | void QWindowVideoWidgetBackend::releaseControl() | 
| 348 | { | 
| 349 |     m_service->releaseControl(control: m_windowControl); | 
| 350 | } | 
| 351 |  | 
| 352 | void QWindowVideoWidgetBackend::setBrightness(int brightness) | 
| 353 | { | 
| 354 |     m_windowControl->setBrightness(brightness); | 
| 355 | } | 
| 356 |  | 
| 357 | void QWindowVideoWidgetBackend::setContrast(int contrast) | 
| 358 | { | 
| 359 |     m_windowControl->setContrast(contrast); | 
| 360 | } | 
| 361 |  | 
| 362 | void QWindowVideoWidgetBackend::setHue(int hue) | 
| 363 | { | 
| 364 |     m_windowControl->setHue(hue); | 
| 365 | } | 
| 366 |  | 
| 367 | void QWindowVideoWidgetBackend::setSaturation(int saturation) | 
| 368 | { | 
| 369 |     m_windowControl->setSaturation(saturation); | 
| 370 | } | 
| 371 |  | 
| 372 | void QWindowVideoWidgetBackend::setFullScreen(bool fullScreen) | 
| 373 | { | 
| 374 |     m_windowControl->setFullScreen(fullScreen); | 
| 375 | } | 
| 376 |  | 
| 377 | Qt::AspectRatioMode QWindowVideoWidgetBackend::aspectRatioMode() const | 
| 378 | { | 
| 379 |     return m_windowControl->aspectRatioMode(); | 
| 380 | } | 
| 381 |  | 
| 382 | void QWindowVideoWidgetBackend::setAspectRatioMode(Qt::AspectRatioMode mode) | 
| 383 | { | 
| 384 |     m_windowControl->setAspectRatioMode(mode); | 
| 385 | } | 
| 386 |  | 
| 387 | QSize QWindowVideoWidgetBackend::sizeHint() const | 
| 388 | { | 
| 389 |     return m_windowControl->nativeSize(); | 
| 390 | } | 
| 391 |  | 
| 392 | void QWindowVideoWidgetBackend::updateDisplayRect() | 
| 393 | { | 
| 394 |     QRect rect = m_widget->rect(); | 
| 395 |     if (QHighDpiScaling::isActive()) { | 
| 396 |         const qreal factor = QHighDpiScaling::factor(context: m_widget->windowHandle()); | 
| 397 |         if (!qFuzzyCompare(p1: factor, p2: qreal(1))) { | 
| 398 |             rect = QRectF(QPointF(rect.topLeft()) * factor, | 
| 399 |                           QSizeF(rect.size()) * factor).toRect(); | 
| 400 |         } | 
| 401 |     } | 
| 402 |     m_windowControl->setDisplayRect(rect); | 
| 403 | } | 
| 404 |  | 
| 405 | void QWindowVideoWidgetBackend::showEvent() | 
| 406 | { | 
| 407 |     m_windowControl->setWinId(m_widget->winId()); | 
| 408 |     updateDisplayRect(); | 
| 409 |  | 
| 410 | #if defined(Q_OS_WIN) | 
| 411 |     m_windowControl->repaint(); | 
| 412 | #endif | 
| 413 | } | 
| 414 |  | 
| 415 | void QWindowVideoWidgetBackend::hideEvent(QHideEvent *) | 
| 416 | { | 
| 417 | } | 
| 418 |  | 
| 419 | void QWindowVideoWidgetBackend::moveEvent(QMoveEvent *) | 
| 420 | { | 
| 421 |     updateDisplayRect(); | 
| 422 | } | 
| 423 |  | 
| 424 | void QWindowVideoWidgetBackend::resizeEvent(QResizeEvent *) | 
| 425 | { | 
| 426 |     updateDisplayRect(); | 
| 427 | } | 
| 428 |  | 
| 429 | void QWindowVideoWidgetBackend::paintEvent(QPaintEvent *event) | 
| 430 | { | 
| 431 |     if (m_widget->testAttribute(attribute: Qt::WA_OpaquePaintEvent)) { | 
| 432 |         QPainter painter(m_widget); | 
| 433 |  | 
| 434 |         painter.fillRect(event->rect(), m_widget->palette().window()); | 
| 435 |     } | 
| 436 |  | 
| 437 |     m_windowControl->repaint(); | 
| 438 |  | 
| 439 |     event->accept(); | 
| 440 | } | 
| 441 |  | 
| 442 | void QVideoWidgetPrivate::setCurrentControl(QVideoWidgetControlInterface *control) | 
| 443 | { | 
| 444 |     if (currentControl != control) { | 
| 445 |         currentControl = control; | 
| 446 |  | 
| 447 |         currentControl->setBrightness(brightness); | 
| 448 |         currentControl->setContrast(contrast); | 
| 449 |         currentControl->setHue(hue); | 
| 450 |         currentControl->setSaturation(saturation); | 
| 451 |         currentControl->setAspectRatioMode(aspectRatioMode); | 
| 452 |     } | 
| 453 | } | 
| 454 |  | 
| 455 | void QVideoWidgetPrivate::clearService() | 
| 456 | { | 
| 457 |     if (service) { | 
| 458 |         QObject::disconnect(sender: service, SIGNAL(destroyed()), receiver: q_func(), SLOT(_q_serviceDestroyed())); | 
| 459 |  | 
| 460 |         if (widgetBackend) { | 
| 461 |             QLayout *layout = q_func()->layout(); | 
| 462 |  | 
| 463 |             for (QLayoutItem *item = layout->takeAt(index: 0); item; item = layout->takeAt(index: 0)) { | 
| 464 |                 item->widget()->setParent(0); | 
| 465 |                 delete item; | 
| 466 |             } | 
| 467 |             delete layout; | 
| 468 |  | 
| 469 |             widgetBackend->releaseControl(); | 
| 470 |  | 
| 471 |             delete widgetBackend; | 
| 472 |             widgetBackend = 0; | 
| 473 |         } else if (rendererBackend) { | 
| 474 |             rendererBackend->clearSurface(); | 
| 475 |             rendererBackend->releaseControl(); | 
| 476 |  | 
| 477 |             delete rendererBackend; | 
| 478 |             rendererBackend = 0; | 
| 479 |         } else if (windowBackend) { | 
| 480 |             windowBackend->releaseControl(); | 
| 481 |  | 
| 482 |             delete windowBackend; | 
| 483 |             windowBackend = 0; | 
| 484 |         } | 
| 485 |  | 
| 486 |         currentBackend = 0; | 
| 487 |         currentControl = 0; | 
| 488 |         service = 0; | 
| 489 |     } | 
| 490 | } | 
| 491 |  | 
| 492 | bool QVideoWidgetPrivate::createWidgetBackend() | 
| 493 | { | 
| 494 |     if (QMediaControl *control = service->requestControl(QVideoWidgetControl_iid)) { | 
| 495 |         if (QVideoWidgetControl *widgetControl = qobject_cast<QVideoWidgetControl *>(object: control)) { | 
| 496 |             widgetBackend = new QVideoWidgetControlBackend(service, widgetControl, q_func()); | 
| 497 |  | 
| 498 |             setCurrentControl(widgetBackend); | 
| 499 |  | 
| 500 |             return true; | 
| 501 |         } | 
| 502 |         service->releaseControl(control); | 
| 503 |     } | 
| 504 |     return false; | 
| 505 | } | 
| 506 |  | 
| 507 | bool QVideoWidgetPrivate::createWindowBackend() | 
| 508 | { | 
| 509 |     if (QMediaControl *control = service->requestControl(QVideoWindowControl_iid)) { | 
| 510 |         if (QVideoWindowControl *windowControl = qobject_cast<QVideoWindowControl *>(object: control)) { | 
| 511 |             windowBackend = new QWindowVideoWidgetBackend(service, windowControl, q_func()); | 
| 512 |             currentBackend = windowBackend; | 
| 513 |  | 
| 514 |             setCurrentControl(windowBackend); | 
| 515 |  | 
| 516 |             return true; | 
| 517 |         } | 
| 518 |         service->releaseControl(control); | 
| 519 |     } | 
| 520 |     return false; | 
| 521 | } | 
| 522 |  | 
| 523 | bool QVideoWidgetPrivate::createRendererBackend() | 
| 524 | { | 
| 525 |     QMediaControl *control = service | 
| 526 |                            ? service->requestControl(QVideoRendererControl_iid) | 
| 527 |                            : nullptr; | 
| 528 |     rendererBackend = new QRendererVideoWidgetBackend(service, | 
| 529 |         qobject_cast<QVideoRendererControl *>(object: control), q_func()); | 
| 530 |     currentBackend = rendererBackend; | 
| 531 |     setCurrentControl(rendererBackend); | 
| 532 |  | 
| 533 |     return !service || (service && control); | 
| 534 | } | 
| 535 |  | 
| 536 | void QVideoWidgetPrivate::_q_serviceDestroyed() | 
| 537 | { | 
| 538 |     if (widgetBackend) | 
| 539 |         delete q_func()->layout(); | 
| 540 |  | 
| 541 |     delete widgetBackend; | 
| 542 |     delete windowBackend; | 
| 543 |     delete rendererBackend; | 
| 544 |  | 
| 545 |     widgetBackend = 0; | 
| 546 |     windowBackend = 0; | 
| 547 |     rendererBackend = 0; | 
| 548 |     currentControl = 0; | 
| 549 |     currentBackend = 0; | 
| 550 |     service = 0; | 
| 551 | } | 
| 552 |  | 
| 553 | void QVideoWidgetPrivate::_q_brightnessChanged(int b) | 
| 554 | { | 
| 555 |     if (b != brightness) | 
| 556 |         emit q_func()->brightnessChanged(brightness: brightness = b); | 
| 557 | } | 
| 558 |  | 
| 559 | void QVideoWidgetPrivate::_q_contrastChanged(int c) | 
| 560 | { | 
| 561 |     if (c != contrast) | 
| 562 |         emit q_func()->contrastChanged(contrast: contrast = c); | 
| 563 | } | 
| 564 |  | 
| 565 | void QVideoWidgetPrivate::_q_hueChanged(int h) | 
| 566 | { | 
| 567 |     if (h != hue) | 
| 568 |         emit q_func()->hueChanged(hue: hue = h); | 
| 569 | } | 
| 570 |  | 
| 571 | void QVideoWidgetPrivate::_q_saturationChanged(int s) | 
| 572 | { | 
| 573 |     if (s != saturation) | 
| 574 |         emit q_func()->saturationChanged(saturation: saturation = s); | 
| 575 | } | 
| 576 |  | 
| 577 |  | 
| 578 | void QVideoWidgetPrivate::_q_fullScreenChanged(bool fullScreen) | 
| 579 | { | 
| 580 |     if (!fullScreen && q_func()->isFullScreen()) | 
| 581 |         q_func()->showNormal(); | 
| 582 | } | 
| 583 |  | 
| 584 | void QVideoWidgetPrivate::_q_dimensionsChanged() | 
| 585 | { | 
| 586 |     q_func()->updateGeometry(); | 
| 587 |     q_func()->update(); | 
| 588 | } | 
| 589 |  | 
| 590 | /*! | 
| 591 |     \class QVideoWidget | 
| 592 |  | 
| 593 |  | 
| 594 |     \brief The QVideoWidget class provides a widget which presents video | 
| 595 |     produced by a media object. | 
| 596 |     \ingroup multimedia | 
| 597 |     \inmodule QtMultimediaWidgets | 
| 598 |  | 
| 599 |     Attaching a QVideoWidget to a QMediaObject allows it to display the | 
| 600 |     video or image output of that media object.  A QVideoWidget is attached | 
| 601 |     to media object by passing a pointer to the QMediaObject in its | 
| 602 |     constructor, and detached by destroying the QVideoWidget. | 
| 603 |  | 
| 604 |     \snippet multimedia-snippets/video.cpp Video widget | 
| 605 |  | 
| 606 |     \b {Note}: Only a single display output can be attached to a media | 
| 607 |     object at one time. | 
| 608 |  | 
| 609 |     \sa QMediaObject, QMediaPlayer, QGraphicsVideoItem | 
| 610 | */ | 
| 611 |  | 
| 612 | /*! | 
| 613 |     Constructs a new video widget. | 
| 614 |  | 
| 615 |     The \a parent is passed to QWidget. | 
| 616 | */ | 
| 617 | QVideoWidget::QVideoWidget(QWidget *parent) | 
| 618 |     : QWidget(parent, {}) | 
| 619 |     , d_ptr(new QVideoWidgetPrivate) | 
| 620 | { | 
| 621 |     d_ptr->q_ptr = this; | 
| 622 | } | 
| 623 |  | 
| 624 | /*! | 
| 625 |   \internal | 
| 626 | */ | 
| 627 | QVideoWidget::QVideoWidget(QVideoWidgetPrivate &dd, QWidget *parent) | 
| 628 |     : QWidget(parent, {}) | 
| 629 |     , d_ptr(&dd) | 
| 630 | { | 
| 631 |     d_ptr->q_ptr = this; | 
| 632 |  | 
| 633 |     QPalette palette = QWidget::palette(); | 
| 634 |     palette.setColor(acr: QPalette::Window, acolor: Qt::black); | 
| 635 |     setPalette(palette); | 
| 636 | } | 
| 637 |  | 
| 638 | /*! | 
| 639 |     Destroys a video widget. | 
| 640 | */ | 
| 641 | QVideoWidget::~QVideoWidget() | 
| 642 | { | 
| 643 |     d_ptr->clearService(); | 
| 644 |  | 
| 645 |     delete d_ptr; | 
| 646 | } | 
| 647 |  | 
| 648 | /*! | 
| 649 |     \property QVideoWidget::mediaObject | 
| 650 |     \brief the media object which provides the video displayed by a widget. | 
| 651 | */ | 
| 652 |  | 
| 653 | QMediaObject *QVideoWidget::mediaObject() const | 
| 654 | { | 
| 655 |     return d_func()->mediaObject; | 
| 656 | } | 
| 657 |  | 
| 658 | /*! | 
| 659 |     \internal | 
| 660 | */ | 
| 661 | bool QVideoWidget::setMediaObject(QMediaObject *object) | 
| 662 | { | 
| 663 |     Q_D(QVideoWidget); | 
| 664 |  | 
| 665 |     if (object == d->mediaObject) | 
| 666 |         return true; | 
| 667 |  | 
| 668 |     d->clearService(); | 
| 669 |  | 
| 670 |     d->mediaObject = object; | 
| 671 |  | 
| 672 |     if (d->mediaObject) | 
| 673 |         d->service = d->mediaObject->service(); | 
| 674 |  | 
| 675 |     if (d->service) { | 
| 676 |         if (d->createWidgetBackend()) { | 
| 677 |             // Nothing to do here. | 
| 678 |         } else if ((!window() || !window()->testAttribute(attribute: Qt::WA_DontShowOnScreen)) | 
| 679 |                 && d->createWindowBackend()) { | 
| 680 |             if (isVisible()) | 
| 681 |                 d->windowBackend->showEvent(); | 
| 682 |         } else if (d->createRendererBackend()) { | 
| 683 |             if (isVisible()) | 
| 684 |                 d->rendererBackend->showEvent(); | 
| 685 |         } else { | 
| 686 |             d->service = 0; | 
| 687 |             d->mediaObject = 0; | 
| 688 |  | 
| 689 |             return false; | 
| 690 |         } | 
| 691 |  | 
| 692 |         connect(asender: d->service, SIGNAL(destroyed()), SLOT(_q_serviceDestroyed())); | 
| 693 |     } else { | 
| 694 |         d->mediaObject = 0; | 
| 695 |  | 
| 696 |         return false; | 
| 697 |     } | 
| 698 |  | 
| 699 |     return true; | 
| 700 | } | 
| 701 |  | 
| 702 | /*! | 
| 703 |     \since 5.15 | 
| 704 |     \property QVideoWidget::videoSurface | 
| 705 |     \brief Returns the underlaying video surface that can render video frames | 
| 706 |     to the current widget. | 
| 707 |     This property is never \c nullptr. | 
| 708 |     Example of how to render video frames to QVideoWidget: | 
| 709 |     \snippet multimedia-snippets/video.cpp Widget Surface | 
| 710 |     \sa QMediaPlayer::setVideoOutput | 
| 711 | */ | 
| 712 |  | 
| 713 | QAbstractVideoSurface *QVideoWidget::videoSurface() const | 
| 714 | { | 
| 715 |     auto d = const_cast<QVideoWidgetPrivate *>(d_func()); | 
| 716 |  | 
| 717 |     if (!d->rendererBackend) { | 
| 718 |         d->clearService(); | 
| 719 |         d->createRendererBackend(); | 
| 720 |     } | 
| 721 |  | 
| 722 |     return d->rendererBackend->videoSurface(); | 
| 723 | } | 
| 724 |  | 
| 725 | /*! | 
| 726 |     \property QVideoWidget::aspectRatioMode | 
| 727 |     \brief how video is scaled with respect to its aspect ratio. | 
| 728 | */ | 
| 729 |  | 
| 730 | Qt::AspectRatioMode QVideoWidget::aspectRatioMode() const | 
| 731 | { | 
| 732 |     return d_func()->aspectRatioMode; | 
| 733 | } | 
| 734 |  | 
| 735 | void QVideoWidget::setAspectRatioMode(Qt::AspectRatioMode mode) | 
| 736 | { | 
| 737 |     Q_D(QVideoWidget); | 
| 738 |  | 
| 739 |     if (d->currentControl) { | 
| 740 |         d->currentControl->setAspectRatioMode(mode); | 
| 741 |         d->aspectRatioMode = d->currentControl->aspectRatioMode(); | 
| 742 |     } else { | 
| 743 |         d->aspectRatioMode = mode; | 
| 744 |     } | 
| 745 | } | 
| 746 |  | 
| 747 | /*! | 
| 748 |     \property QVideoWidget::fullScreen | 
| 749 |     \brief whether video display is confined to a window or is fullScreen. | 
| 750 | */ | 
| 751 |  | 
| 752 | void QVideoWidget::setFullScreen(bool fullScreen) | 
| 753 | { | 
| 754 |     Q_D(QVideoWidget); | 
| 755 |  | 
| 756 |     Qt::WindowFlags flags = windowFlags(); | 
| 757 |  | 
| 758 |     if (fullScreen) { | 
| 759 |         d->nonFullScreenFlags = flags & (Qt::Window | Qt::SubWindow); | 
| 760 |         flags |= Qt::Window; | 
| 761 |         flags &= ~Qt::SubWindow; | 
| 762 |         setWindowFlags(flags); | 
| 763 |  | 
| 764 |         showFullScreen(); | 
| 765 |     } else { | 
| 766 |         flags &= ~(Qt::Window | Qt::SubWindow); //clear the flags... | 
| 767 |         flags |= d->nonFullScreenFlags; //then we reset the flags (window and subwindow) | 
| 768 |         setWindowFlags(flags); | 
| 769 |  | 
| 770 |         showNormal(); | 
| 771 |     } | 
| 772 | } | 
| 773 |  | 
| 774 | /*! | 
| 775 |     \fn QVideoWidget::fullScreenChanged(bool fullScreen) | 
| 776 |  | 
| 777 |     Signals that the \a fullScreen mode of a video widget has changed. | 
| 778 |  | 
| 779 |     \sa isFullScreen() | 
| 780 | */ | 
| 781 |  | 
| 782 | /*! | 
| 783 |     \property QVideoWidget::brightness | 
| 784 |     \brief an adjustment to the brightness of displayed video. | 
| 785 |  | 
| 786 |     Valid brightness values range between -100 and 100, the default is 0. | 
| 787 | */ | 
| 788 |  | 
| 789 | int QVideoWidget::brightness() const | 
| 790 | { | 
| 791 |     return d_func()->brightness; | 
| 792 | } | 
| 793 |  | 
| 794 | void QVideoWidget::setBrightness(int brightness) | 
| 795 | { | 
| 796 |     Q_D(QVideoWidget); | 
| 797 |  | 
| 798 |     int boundedBrightness = qBound(min: -100, val: brightness, max: 100); | 
| 799 |  | 
| 800 |     if (d->currentControl) | 
| 801 |         d->currentControl->setBrightness(boundedBrightness); | 
| 802 |     else if (d->brightness != boundedBrightness) | 
| 803 |         emit brightnessChanged(brightness: d->brightness = boundedBrightness); | 
| 804 | } | 
| 805 |  | 
| 806 | /*! | 
| 807 |     \fn QVideoWidget::brightnessChanged(int brightness) | 
| 808 |  | 
| 809 |     Signals that a video widgets's \a brightness adjustment has changed. | 
| 810 |  | 
| 811 |     \sa brightness() | 
| 812 | */ | 
| 813 |  | 
| 814 | /*! | 
| 815 |     \property QVideoWidget::contrast | 
| 816 |     \brief an adjustment to the contrast of displayed video. | 
| 817 |  | 
| 818 |     Valid contrast values range between -100 and 100, the default is 0. | 
| 819 |  | 
| 820 | */ | 
| 821 |  | 
| 822 | int QVideoWidget::contrast() const | 
| 823 | { | 
| 824 |     return d_func()->contrast; | 
| 825 | } | 
| 826 |  | 
| 827 | void QVideoWidget::setContrast(int contrast) | 
| 828 | { | 
| 829 |     Q_D(QVideoWidget); | 
| 830 |  | 
| 831 |     int boundedContrast = qBound(min: -100, val: contrast, max: 100); | 
| 832 |  | 
| 833 |     if (d->currentControl) | 
| 834 |         d->currentControl->setContrast(boundedContrast); | 
| 835 |     else if (d->contrast != boundedContrast) | 
| 836 |         emit contrastChanged(contrast: d->contrast = boundedContrast); | 
| 837 | } | 
| 838 |  | 
| 839 | /*! | 
| 840 |     \fn QVideoWidget::contrastChanged(int contrast) | 
| 841 |  | 
| 842 |     Signals that a video widgets's \a contrast adjustment has changed. | 
| 843 |  | 
| 844 |     \sa contrast() | 
| 845 | */ | 
| 846 |  | 
| 847 | /*! | 
| 848 |     \property QVideoWidget::hue | 
| 849 |     \brief an adjustment to the hue of displayed video. | 
| 850 |  | 
| 851 |     Valid hue values range between -100 and 100, the default is 0. | 
| 852 | */ | 
| 853 |  | 
| 854 | int QVideoWidget::hue() const | 
| 855 | { | 
| 856 |     return d_func()->hue; | 
| 857 | } | 
| 858 |  | 
| 859 | void QVideoWidget::setHue(int hue) | 
| 860 | { | 
| 861 |     Q_D(QVideoWidget); | 
| 862 |  | 
| 863 |     int boundedHue = qBound(min: -100, val: hue, max: 100); | 
| 864 |  | 
| 865 |     if (d->currentControl) | 
| 866 |         d->currentControl->setHue(boundedHue); | 
| 867 |     else if (d->hue != boundedHue) | 
| 868 |         emit hueChanged(hue: d->hue = boundedHue); | 
| 869 | } | 
| 870 |  | 
| 871 | /*! | 
| 872 |     \fn QVideoWidget::hueChanged(int hue) | 
| 873 |  | 
| 874 |     Signals that a video widgets's \a hue has changed. | 
| 875 |  | 
| 876 |     \sa hue() | 
| 877 | */ | 
| 878 |  | 
| 879 | /*! | 
| 880 |     \property QVideoWidget::saturation | 
| 881 |     \brief an adjustment to the saturation of displayed video. | 
| 882 |  | 
| 883 |     Valid saturation values range between -100 and 100, the default is 0. | 
| 884 | */ | 
| 885 |  | 
| 886 | int QVideoWidget::saturation() const | 
| 887 | { | 
| 888 |     return d_func()->saturation; | 
| 889 | } | 
| 890 |  | 
| 891 | void QVideoWidget::setSaturation(int saturation) | 
| 892 | { | 
| 893 |     Q_D(QVideoWidget); | 
| 894 |  | 
| 895 |     int boundedSaturation = qBound(min: -100, val: saturation, max: 100); | 
| 896 |  | 
| 897 |     if (d->currentControl) | 
| 898 |         d->currentControl->setSaturation(boundedSaturation); | 
| 899 |     else if (d->saturation != boundedSaturation) | 
| 900 |         emit saturationChanged(saturation: d->saturation = boundedSaturation); | 
| 901 |  | 
| 902 | } | 
| 903 |  | 
| 904 | /*! | 
| 905 |     \fn QVideoWidget::saturationChanged(int saturation) | 
| 906 |  | 
| 907 |     Signals that a video widgets's \a saturation has changed. | 
| 908 |  | 
| 909 |     \sa saturation() | 
| 910 | */ | 
| 911 |  | 
| 912 | /*! | 
| 913 |   Returns the size hint for the current back end, | 
| 914 |   if there is one, or else the size hint from QWidget. | 
| 915 |  */ | 
| 916 | QSize QVideoWidget::sizeHint() const | 
| 917 | { | 
| 918 |     Q_D(const QVideoWidget); | 
| 919 |  | 
| 920 |     if (d->currentBackend) | 
| 921 |         return d->currentBackend->sizeHint(); | 
| 922 |     else | 
| 923 |         return QWidget::sizeHint(); | 
| 924 |  | 
| 925 |  | 
| 926 | } | 
| 927 |  | 
| 928 | /*! | 
| 929 |   \reimp | 
| 930 |   Current event \a event. | 
| 931 |   Returns the value of the baseclass QWidget::event(QEvent *event) function. | 
| 932 | */ | 
| 933 | bool QVideoWidget::event(QEvent *event) | 
| 934 | { | 
| 935 |     Q_D(QVideoWidget); | 
| 936 |  | 
| 937 |     if (event->type() == QEvent::WindowStateChange) { | 
| 938 |         if (windowState() & Qt::WindowFullScreen) { | 
| 939 |             if (d->currentControl) | 
| 940 |                 d->currentControl->setFullScreen(true); | 
| 941 |  | 
| 942 |             if (!d->wasFullScreen) | 
| 943 |                 emit fullScreenChanged(fullScreen: d->wasFullScreen = true); | 
| 944 |         } else { | 
| 945 |             if (d->currentControl) | 
| 946 |                 d->currentControl->setFullScreen(false); | 
| 947 |  | 
| 948 |             if (d->wasFullScreen) | 
| 949 |                 emit fullScreenChanged(fullScreen: d->wasFullScreen = false); | 
| 950 |         } | 
| 951 |     } | 
| 952 |     return QWidget::event(event); | 
| 953 | } | 
| 954 |  | 
| 955 | /*! | 
| 956 |   \reimp | 
| 957 |   Handles the show \a event. | 
| 958 |  */ | 
| 959 | void QVideoWidget::showEvent(QShowEvent *event) | 
| 960 | { | 
| 961 |     Q_D(QVideoWidget); | 
| 962 |  | 
| 963 |     QWidget::showEvent(event); | 
| 964 |  | 
| 965 |     // The window backend won't work for re-directed windows so use the renderer backend instead. | 
| 966 |     if (d->windowBackend && window()->testAttribute(attribute: Qt::WA_DontShowOnScreen)) { | 
| 967 |         d->windowBackend->releaseControl(); | 
| 968 |  | 
| 969 |         delete d->windowBackend; | 
| 970 |         d->windowBackend = 0; | 
| 971 |  | 
| 972 |         d->createRendererBackend(); | 
| 973 |     } | 
| 974 |  | 
| 975 |     if (d->currentBackend) | 
| 976 |         d->currentBackend->showEvent(); | 
| 977 | } | 
| 978 |  | 
| 979 | /*! | 
| 980 |   \reimp | 
| 981 |   Handles the hide \a event. | 
| 982 | */ | 
| 983 | void QVideoWidget::hideEvent(QHideEvent *event) | 
| 984 | { | 
| 985 |     Q_D(QVideoWidget); | 
| 986 |  | 
| 987 |     if (d->currentBackend) | 
| 988 |         d->currentBackend->hideEvent(event); | 
| 989 |  | 
| 990 |     QWidget::hideEvent(event); | 
| 991 | } | 
| 992 |  | 
| 993 | /*! | 
| 994 |   \reimp | 
| 995 |   Handles the resize \a event. | 
| 996 |  */ | 
| 997 | void QVideoWidget::resizeEvent(QResizeEvent *event) | 
| 998 | { | 
| 999 |     Q_D(QVideoWidget); | 
| 1000 |  | 
| 1001 |     QWidget::resizeEvent(event); | 
| 1002 |  | 
| 1003 |     if (d->currentBackend) | 
| 1004 |         d->currentBackend->resizeEvent(event); | 
| 1005 | } | 
| 1006 |  | 
| 1007 | /*! | 
| 1008 |   \reimp | 
| 1009 |   Handles the move \a event. | 
| 1010 |  */ | 
| 1011 | void QVideoWidget::moveEvent(QMoveEvent *event) | 
| 1012 | { | 
| 1013 |     Q_D(QVideoWidget); | 
| 1014 |  | 
| 1015 |     if (d->currentBackend) | 
| 1016 |         d->currentBackend->moveEvent(event); | 
| 1017 | } | 
| 1018 |  | 
| 1019 | /*! | 
| 1020 |   \reimp | 
| 1021 |   Handles the paint \a event. | 
| 1022 |  */ | 
| 1023 | void QVideoWidget::paintEvent(QPaintEvent *event) | 
| 1024 | { | 
| 1025 |     Q_D(QVideoWidget); | 
| 1026 |  | 
| 1027 |     if (d->currentBackend) { | 
| 1028 |         d->currentBackend->paintEvent(event); | 
| 1029 |     } else if (testAttribute(attribute: Qt::WA_OpaquePaintEvent)) { | 
| 1030 |         QPainter painter(this); | 
| 1031 |  | 
| 1032 |         painter.fillRect(event->rect(), palette().window()); | 
| 1033 |     } | 
| 1034 | } | 
| 1035 |  | 
| 1036 | #if defined(Q_OS_WIN) | 
| 1037 | #  if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) | 
| 1038 | bool QVideoWidget::nativeEvent(const QByteArray &eventType, void *message, qintptr *result) | 
| 1039 | #  else | 
| 1040 | bool QVideoWidget::nativeEvent(const QByteArray &eventType, void *message, long *result) | 
| 1041 | #  endif | 
| 1042 | { | 
| 1043 |     Q_D(QVideoWidget); | 
| 1044 |     Q_UNUSED(eventType); | 
| 1045 |     Q_UNUSED(result); | 
| 1046 |  | 
| 1047 |     MSG *mes = reinterpret_cast<MSG *>(message); | 
| 1048 |     if (mes->message == WM_PAINT || mes->message == WM_ERASEBKGND) { | 
| 1049 |         if (d->windowBackend) | 
| 1050 |             d->windowBackend->showEvent(); | 
| 1051 |     } | 
| 1052 |  | 
| 1053 |     return false; | 
| 1054 | } | 
| 1055 | #endif | 
| 1056 |  | 
| 1057 | QT_END_NAMESPACE | 
| 1058 |  | 
| 1059 | #include "moc_qvideowidget.cpp" | 
| 1060 | #include "moc_qvideowidget_p.cpp" | 
| 1061 |  |