summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndré de la Rocha <andre.rocha@qt.io>2022-08-16 20:33:53 +0200
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2022-08-22 14:36:10 +0000
commit0e3bb5db91184497e71f22861a64113cae2708f7 (patch)
treefde576738666d73f3e41d8d486e923200390d324
parentb310c89e0638a9653f1d0fafa5a44e189e991998 (diff)
downloadqtmultimedia-0e3bb5db91184497e71f22861a64113cae2708f7.tar.gz
Windows: Fix cropping for HEVC-encoded videos
The cropping info associated with HEVC-encoded video files was not being applied and as a result some videos could show garbage on the borders of the actual video contents, since instead of the source frames width and height, the sizes in pixels of the buffers used by the encoding algorithm, which are padded to multiples of some power of two, were used. Root cause seems to be a bug in Media Foundation or incompatibility with the Windows HEVC decoder, as the API is returning buffer sizes where sizes of actual video contents should be returned. It works as expected for other video formats. This patch makes the QtMultimedia decoder enforce the actual video dimensions obtained through the file's metadata. Fixes: QTBUG-105381 Change-Id: I2d67c64f07de489edd1d274060eccd5a4d69bafe Reviewed-by: Piotr Srebrny <piotr.srebrny@qt.io> Reviewed-by: Lars Knoll <lars@knoll.priv.no> (cherry picked from commit 65345a04c67c585c4d38d56cb1416a3033434aaf) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r--src/plugins/multimedia/windows/evr/evrcustompresenter.cpp36
-rw-r--r--src/plugins/multimedia/windows/evr/evrcustompresenter_p.h3
-rw-r--r--src/plugins/multimedia/windows/evr/evrd3dpresentengine.cpp7
-rw-r--r--src/plugins/multimedia/windows/evr/evrd3dpresentengine_p.h3
-rw-r--r--src/plugins/multimedia/windows/player/mfplayersession.cpp6
-rw-r--r--src/plugins/multimedia/windows/player/mfvideorenderercontrol.cpp21
-rw-r--r--src/plugins/multimedia/windows/player/mfvideorenderercontrol_p.h3
7 files changed, 71 insertions, 8 deletions
diff --git a/src/plugins/multimedia/windows/evr/evrcustompresenter.cpp b/src/plugins/multimedia/windows/evr/evrcustompresenter.cpp
index 7d98b0dc1..d520584f7 100644
--- a/src/plugins/multimedia/windows/evr/evrcustompresenter.cpp
+++ b/src/plugins/multimedia/windows/evr/evrcustompresenter.cpp
@@ -1016,6 +1016,13 @@ void EVRCustomPresenter::setSink(QVideoSink *sink)
supportedFormatsChanged();
}
+void EVRCustomPresenter::setCropRect(QRect cropRect)
+{
+ m_mutex.lock();
+ m_cropRect = cropRect;
+ m_mutex.unlock();
+}
+
HRESULT EVRCustomPresenter::configureMixer(IMFTransform *mixer)
{
// Set the zoom rectangle (ie, the source clipping rectangle).
@@ -1306,13 +1313,30 @@ HRESULT EVRCustomPresenter::createOptimalVideoType(IMFMediaType *proposedType, I
hr = proposedType->GetUINT64(MF_MT_FRAME_SIZE, &size);
width = int(HI32(size));
height = int(LO32(size));
- rcOutput.left = 0;
- rcOutput.top = 0;
- rcOutput.right = width;
- rcOutput.bottom = height;
+
+ if (m_cropRect.isValid()) {
+ rcOutput.left = m_cropRect.x();
+ rcOutput.top = m_cropRect.y();
+ rcOutput.right = m_cropRect.x() + m_cropRect.width();
+ rcOutput.bottom = m_cropRect.y() + m_cropRect.height();
+
+ m_sourceRect.left = float(m_cropRect.x()) / width;
+ m_sourceRect.top = float(m_cropRect.y()) / height;
+ m_sourceRect.right = float(m_cropRect.x() + m_cropRect.width()) / width;
+ m_sourceRect.bottom = float(m_cropRect.y() + m_cropRect.height()) / height;
+
+ if (m_mixer)
+ configureMixer(m_mixer);
+ } else {
+ rcOutput.left = 0;
+ rcOutput.top = 0;
+ rcOutput.right = width;
+ rcOutput.bottom = height;
+ }
// Set the geometric aperture, and disable pan/scan.
- displayArea = qt_evr_makeMFArea(0, 0, rcOutput.right, rcOutput.bottom);
+ displayArea = qt_evr_makeMFArea(0, 0, rcOutput.right - rcOutput.left,
+ rcOutput.bottom - rcOutput.top);
hr = mtOptimal->SetUINT32(MF_MT_PAN_SCAN_ENABLED, FALSE);
if (FAILED(hr))
@@ -1378,7 +1402,7 @@ HRESULT EVRCustomPresenter::setMediaType(IMFMediaType *mediaType)
// Initialize the presenter engine with the new media type.
// The presenter engine allocates the samples.
- hr = m_presentEngine->createVideoSamples(mediaType, sampleQueue);
+ hr = m_presentEngine->createVideoSamples(mediaType, sampleQueue, m_cropRect.size());
if (FAILED(hr))
goto done;
diff --git a/src/plugins/multimedia/windows/evr/evrcustompresenter_p.h b/src/plugins/multimedia/windows/evr/evrcustompresenter_p.h
index 55c1658bd..590285be5 100644
--- a/src/plugins/multimedia/windows/evr/evrcustompresenter_p.h
+++ b/src/plugins/multimedia/windows/evr/evrcustompresenter_p.h
@@ -19,6 +19,7 @@
#include <qmutex.h>
#include <qqueue.h>
#include <qevent.h>
+#include <qrect.h>
#include <qvideoframeformat.h>
#include <qvideosink.h>
@@ -237,6 +238,7 @@ public:
void supportedFormatsChanged();
void setSink(QVideoSink *sink);
+ void setCropRect(QRect cropRect);
void startSurface();
void stopSurface();
@@ -348,6 +350,7 @@ private:
QVideoSink *m_videoSink;
bool m_canRenderToSurface;
qint64 m_positionOffset; // Seek position in microseconds.
+ QRect m_cropRect; // Video crop rectangle
};
bool qt_evr_setCustomPresenter(IUnknown *evr, EVRCustomPresenter *presenter);
diff --git a/src/plugins/multimedia/windows/evr/evrd3dpresentengine.cpp b/src/plugins/multimedia/windows/evr/evrd3dpresentengine.cpp
index bfaaed4c2..bffb6e46d 100644
--- a/src/plugins/multimedia/windows/evr/evrd3dpresentengine.cpp
+++ b/src/plugins/multimedia/windows/evr/evrd3dpresentengine.cpp
@@ -515,7 +515,7 @@ HRESULT D3DPresentEngine::checkFormat(D3DFORMAT format)
return ok ? S_OK : D3DERR_NOTAVAILABLE;
}
-HRESULT D3DPresentEngine::createVideoSamples(IMFMediaType *format, QList<IMFSample*> &videoSampleQueue)
+HRESULT D3DPresentEngine::createVideoSamples(IMFMediaType *format, QList<IMFSample*> &videoSampleQueue, QSize frameSize)
{
if (!format || !m_device)
return MF_E_UNEXPECTED;
@@ -528,6 +528,11 @@ HRESULT D3DPresentEngine::createVideoSamples(IMFMediaType *format, QList<IMFSamp
if (FAILED(hr))
return hr;
+ if (frameSize.isValid() && !frameSize.isEmpty()) {
+ width = frameSize.width();
+ height = frameSize.height();
+ }
+
DWORD d3dFormat = 0;
hr = qt_evr_getFourCC(format, &d3dFormat);
if (FAILED(hr))
diff --git a/src/plugins/multimedia/windows/evr/evrd3dpresentengine_p.h b/src/plugins/multimedia/windows/evr/evrd3dpresentengine_p.h
index 18923fc62..c9ad5e9c1 100644
--- a/src/plugins/multimedia/windows/evr/evrd3dpresentengine_p.h
+++ b/src/plugins/multimedia/windows/evr/evrd3dpresentengine_p.h
@@ -16,6 +16,7 @@
//
#include <QMutex>
+#include <QSize>
#include <QVideoFrameFormat>
#include <private/qwindowsiupointer_p.h>
@@ -105,7 +106,7 @@ public:
HRESULT checkFormat(D3DFORMAT format);
UINT refreshRate() const { return m_displayMode.RefreshRate; }
- HRESULT createVideoSamples(IMFMediaType *format, QList<IMFSample*>& videoSampleQueue);
+ HRESULT createVideoSamples(IMFMediaType *format, QList<IMFSample*>& videoSampleQueue, QSize frameSize);
QVideoFrameFormat videoSurfaceFormat() const { return m_surfaceFormat; }
QVideoFrame makeVideoFrame(IMFSample* sample);
diff --git a/src/plugins/multimedia/windows/player/mfplayersession.cpp b/src/plugins/multimedia/windows/player/mfplayersession.cpp
index daed6fbb4..152604f1d 100644
--- a/src/plugins/multimedia/windows/player/mfplayersession.cpp
+++ b/src/plugins/multimedia/windows/player/mfplayersession.cpp
@@ -487,6 +487,12 @@ IMFTopologyNode* MFPlayerSession::addOutputNode(MediaType mediaType, IMFTopology
}
} else if (mediaType == Video) {
activate = m_videoRendererControl->createActivate();
+
+ QSize resolution = m_metaData.value(QMediaMetaData::Resolution).toSize();
+
+ if (resolution.isValid())
+ m_videoRendererControl->setCropRect(QRect(QPoint(), resolution));
+
} else {
// Unknown stream type.
emit error(QMediaPlayer::FormatError, tr("Unknown stream type."), false);
diff --git a/src/plugins/multimedia/windows/player/mfvideorenderercontrol.cpp b/src/plugins/multimedia/windows/player/mfvideorenderercontrol.cpp
index 0c8576e70..05bc7b0f7 100644
--- a/src/plugins/multimedia/windows/player/mfvideorenderercontrol.cpp
+++ b/src/plugins/multimedia/windows/player/mfvideorenderercontrol.cpp
@@ -2100,10 +2100,12 @@ public:
STDMETHODIMP DetachObject() override;
void setSink(QVideoSink *sink);
+ void setCropRect(QRect cropRect);
private:
EVRCustomPresenter *m_presenter;
QVideoSink *m_videoSink;
+ QRect m_cropRect;
QMutex m_mutex;
};
@@ -2156,6 +2158,12 @@ void MFVideoRendererControl::setSink(QVideoSink *sink)
static_cast<VideoRendererActivate*>(m_currentActivate)->setSink(m_sink);
}
+void MFVideoRendererControl::setCropRect(QRect cropRect)
+{
+ if (m_presenterActivate)
+ m_presenterActivate->setCropRect(cropRect);
+}
+
void MFVideoRendererControl::customEvent(QEvent *event)
{
if (m_presenterActivate)
@@ -2225,6 +2233,7 @@ HRESULT EVRCustomPresenterActivate::ActivateObject(REFIID riid, void **ppv)
QMutexLocker locker(&m_mutex);
if (!m_presenter) {
m_presenter = new EVRCustomPresenter(m_videoSink);
+ m_presenter->setCropRect(m_cropRect);
}
return m_presenter->QueryInterface(riid, ppv);
}
@@ -2258,5 +2267,17 @@ void EVRCustomPresenterActivate::setSink(QVideoSink *sink)
m_presenter->setSink(sink);
}
+void EVRCustomPresenterActivate::setCropRect(QRect cropRect)
+{
+ QMutexLocker locker(&m_mutex);
+ if (m_cropRect == cropRect)
+ return;
+
+ m_cropRect = cropRect;
+
+ if (m_presenter)
+ m_presenter->setCropRect(cropRect);
+}
+
#include "moc_mfvideorenderercontrol_p.cpp"
#include "mfvideorenderercontrol.moc"
diff --git a/src/plugins/multimedia/windows/player/mfvideorenderercontrol_p.h b/src/plugins/multimedia/windows/player/mfvideorenderercontrol_p.h
index 93a8e27d6..588768eee 100644
--- a/src/plugins/multimedia/windows/player/mfvideorenderercontrol_p.h
+++ b/src/plugins/multimedia/windows/player/mfvideorenderercontrol_p.h
@@ -16,6 +16,7 @@
//
#include "qobject.h"
+#include <qrect.h>
#include <mfapi.h>
#include <mfidl.h>
@@ -37,6 +38,8 @@ public:
QVideoSink *sink() const;
void setSink(QVideoSink *surface);
+ void setCropRect(QRect cropRect);
+
IMFActivate* createActivate();
void releaseActivate();