blob: fbd698eeac436d64412da1f2f0bcc43cb4540fea [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2016 Research In Motion
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "mmrenderervideowindowcontrol.h"
#include "mmrendererutil.h"
#include <QtCore/qdebug.h>
#include <QtGui/qguiapplication.h>
#include <QtGui/qpa/qplatformnativeinterface.h>
#include <QtGui/qscreen.h>
#include <QtGui/qwindow.h>
#include <mm/renderer.h>
QT_BEGIN_NAMESPACE
static int winIdCounter = 0;
MmRendererVideoWindowControl::MmRendererVideoWindowControl(QObject *parent)
: QVideoWindowControl(parent),
m_videoId(-1),
m_winId(0),
m_context(0),
m_fullscreen(false),
m_aspectRatioMode(Qt::IgnoreAspectRatio),
m_window(0),
m_hue(0),
m_brightness(0),
m_contrast(0),
m_saturation(0)
{
}
MmRendererVideoWindowControl::~MmRendererVideoWindowControl()
{
}
WId MmRendererVideoWindowControl::winId() const
{
return m_winId;
}
void MmRendererVideoWindowControl::setWinId(WId id)
{
m_winId = id;
}
QRect MmRendererVideoWindowControl::displayRect() const
{
return m_displayRect ;
}
void MmRendererVideoWindowControl::setDisplayRect(const QRect &rect)
{
if (m_displayRect != rect) {
m_displayRect = rect;
updateVideoPosition();
}
}
bool MmRendererVideoWindowControl::isFullScreen() const
{
return m_fullscreen;
}
void MmRendererVideoWindowControl::setFullScreen(bool fullScreen)
{
if (m_fullscreen != fullScreen) {
m_fullscreen = fullScreen;
updateVideoPosition();
emit fullScreenChanged(m_fullscreen);
}
}
void MmRendererVideoWindowControl::repaint()
{
// Nothing we can or should do here
}
QSize MmRendererVideoWindowControl::nativeSize() const
{
return QSize(m_metaData.width(), m_metaData.height());
}
Qt::AspectRatioMode MmRendererVideoWindowControl::aspectRatioMode() const
{
return m_aspectRatioMode;
}
void MmRendererVideoWindowControl::setAspectRatioMode(Qt::AspectRatioMode mode)
{
m_aspectRatioMode = mode;
}
int MmRendererVideoWindowControl::brightness() const
{
return m_brightness;
}
void MmRendererVideoWindowControl::setBrightness(int brightness)
{
if (m_brightness != brightness) {
m_brightness = brightness;
updateBrightness();
emit brightnessChanged(m_brightness);
}
}
int MmRendererVideoWindowControl::contrast() const
{
return m_contrast;
}
void MmRendererVideoWindowControl::setContrast(int contrast)
{
if (m_contrast != contrast) {
m_contrast = contrast;
updateContrast();
emit contrastChanged(m_contrast);
}
}
int MmRendererVideoWindowControl::hue() const
{
return m_hue;
}
void MmRendererVideoWindowControl::setHue(int hue)
{
if (m_hue != hue) {
m_hue = hue;
updateHue();
emit hueChanged(m_hue);
}
}
int MmRendererVideoWindowControl::saturation() const
{
return m_saturation;
}
void MmRendererVideoWindowControl::setSaturation(int saturation)
{
if (m_saturation != saturation) {
m_saturation = saturation;
updateSaturation();
emit saturationChanged(m_saturation);
}
}
void MmRendererVideoWindowControl::attachDisplay(mmr_context_t *context)
{
if (m_videoId != -1) {
qDebug() << "MmRendererVideoWindowControl: Video output already attached!";
return;
}
if (!context) {
qDebug() << "MmRendererVideoWindowControl: No media player context!";
return;
}
QWindow *window = findWindow(m_winId);
if (!window) {
qDebug() << "MmRendererVideoWindowControl: No video window!";
return;
}
QPlatformNativeInterface * const nativeInterface = QGuiApplication::platformNativeInterface();
if (!nativeInterface) {
qDebug() << "MmRendererVideoWindowControl: Unable to get platform native interface";
return;
}
const char * const groupNameData = static_cast<const char *>(
nativeInterface->nativeResourceForWindow("windowGroup", window));
if (!groupNameData) {
qDebug() << "MmRendererVideoWindowControl: Unable to find window group for window"
<< window;
return;
}
const QString groupName = QString::fromLatin1(groupNameData);
m_windowName = QString("MmRendererVideoWindowControl_%1_%2").arg(winIdCounter++)
.arg(QCoreApplication::applicationPid());
nativeInterface->setWindowProperty(window->handle(),
QStringLiteral("mmRendererWindowName"), m_windowName);
// Start with an invisible window. If it would be visible right away, it would be at the wrong
// position, and we can only change the position once we get the window handle.
const QString videoDeviceUrl =
QString("screen:?winid=%1&wingrp=%2&initflags=invisible&nodstviewport=1").arg(m_windowName).arg(groupName);
m_videoId = mmr_output_attach(context, videoDeviceUrl.toLatin1(), "video");
if (m_videoId == -1) {
qDebug() << mmErrorMessage("mmr_output_attach() for video failed", context);
return;
}
m_context = context;
updateVideoPosition();
updateHue();
updateContrast();
updateBrightness();
updateSaturation();
}
void MmRendererVideoWindowControl::updateVideoPosition()
{
QWindow * const window = findWindow(m_winId);
if (m_context && m_videoId != -1 && window) {
QPoint topLeft = m_displayRect.topLeft();
QScreen * const screen = window->screen();
int width = m_fullscreen ?
screen->size().width() :
m_displayRect.width();
int height = m_fullscreen ?
screen->size().height() :
m_displayRect.height();
if (m_metaData.hasVideo() && m_metaData.width() > 0 && m_metaData.height() > 0) {
// We need the source size to do aspect ratio scaling
const qreal sourceRatio = m_metaData.width() / static_cast<float>(m_metaData.height());
const qreal targetRatio = width / static_cast<float>(height);
if (m_aspectRatioMode == Qt::KeepAspectRatio) {
if (targetRatio < sourceRatio) {
// Need to make height smaller
const int newHeight = width / sourceRatio;
const int heightDiff = height - newHeight;
topLeft.ry() += heightDiff / 2;
height = newHeight;
} else {
// Need to make width smaller
const int newWidth = sourceRatio * height;
const int widthDiff = width - newWidth;
topLeft.rx() += widthDiff / 2;
width = newWidth;
}
} else if (m_aspectRatioMode == Qt::KeepAspectRatioByExpanding) {
if (targetRatio < sourceRatio) {
// Need to make width larger
const int newWidth = sourceRatio * height;
const int widthDiff = newWidth - width;
topLeft.rx() -= widthDiff / 2;
width = newWidth;
} else {
// Need to make height larger
const int newHeight = width / sourceRatio;
const int heightDiff = newHeight - height;
topLeft.ry() -= heightDiff / 2;
height = newHeight;
}
}
}
if (m_window != 0) {
const int position[2] = { topLeft.x(), topLeft.y() };
const int size[2] = { width, height };
const int visible = m_displayRect.isValid();
if (screen_set_window_property_iv(m_window, SCREEN_PROPERTY_POSITION, position) != 0)
perror("Setting video position failed");
if (screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SIZE, size) != 0)
perror("Setting video size failed");
if (screen_set_window_property_iv(m_window, SCREEN_PROPERTY_VISIBLE, &visible) != 0)
perror("Setting video visibility failed");
}
}
}
void MmRendererVideoWindowControl::updateBrightness()
{
if (m_window != 0) {
const int backendValue = m_brightness * 2.55f;
if (screen_set_window_property_iv(m_window, SCREEN_PROPERTY_BRIGHTNESS, &backendValue) != 0)
perror("Setting brightness failed");
}
}
void MmRendererVideoWindowControl::updateContrast()
{
if (m_window != 0) {
const int backendValue = m_contrast * 1.27f;
if (screen_set_window_property_iv(m_window, SCREEN_PROPERTY_CONTRAST, &backendValue) != 0)
perror("Setting contrast failed");
}
}
void MmRendererVideoWindowControl::updateHue()
{
if (m_window != 0) {
const int backendValue = m_hue * 1.27f;
if (screen_set_window_property_iv(m_window, SCREEN_PROPERTY_HUE, &backendValue) != 0)
perror("Setting hue failed");
}
}
void MmRendererVideoWindowControl::updateSaturation()
{
if (m_window != 0) {
const int backendValue = m_saturation * 1.27f;
if (screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SATURATION, &backendValue) != 0)
perror("Setting saturation failed");
}
}
void MmRendererVideoWindowControl::detachDisplay()
{
if (m_context && m_videoId != -1)
mmr_output_detach(m_context, m_videoId);
m_context = 0;
m_videoId = -1;
m_metaData.clear();
m_windowName.clear();
m_window = 0;
m_hue = 0;
m_brightness = 0;
m_contrast = 0;
m_saturation = 0;
}
void MmRendererVideoWindowControl::setMetaData(const MmRendererMetaData &metaData)
{
m_metaData = metaData;
emit nativeSizeChanged();
// To handle the updated source size data
updateVideoPosition();
}
void MmRendererVideoWindowControl::screenEventHandler(const screen_event_t &screen_event)
{
int eventType;
if (screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_TYPE, &eventType) != 0) {
perror("MmRendererVideoWindowControl: Failed to query screen event type");
return;
}
if (eventType != SCREEN_EVENT_CREATE)
return;
screen_window_t window = 0;
if (screen_get_event_property_pv(screen_event, SCREEN_PROPERTY_WINDOW, (void**)&window) != 0) {
perror("MmRendererVideoWindowControl: Failed to query window property");
return;
}
const int maxIdStrLength = 128;
char idString[maxIdStrLength];
if (screen_get_window_property_cv(window, SCREEN_PROPERTY_ID_STRING, maxIdStrLength, idString) != 0) {
perror("MmRendererVideoWindowControl: Failed to query window ID string");
return;
}
if (m_windowName == idString) {
m_window = window;
updateVideoPosition();
const int visibleFlag = 1;
if (screen_set_window_property_iv(m_window, SCREEN_PROPERTY_VISIBLE, &visibleFlag) != 0) {
perror("MmRendererVideoWindowControl: Failed to make window visible");
return;
}
}
}
QWindow *MmRendererVideoWindowControl::findWindow(WId id) const
{
const auto allWindows = QGuiApplication::allWindows();
for (QWindow *window : allWindows)
if (window->winId() == id)
return window;
return 0;
}
QT_END_NAMESPACE