summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJøger Hansegård <joger.hansegard@qt.io>2024-04-07 18:59:12 +0200
committerJøger Hansegård <joger.hansegard@qt.io>2024-04-08 19:00:37 +0200
commite67b5d7e8d300f602fdae2d17511e9917dd1445d (patch)
treebf337b4d88c33f32738ec9a89d4a8da10054bbc4
parentb61affee2c3bf8cc8c1f1b201a414a5c69080b69 (diff)
Fix corrupt frames when playing AV1 videos on Windows
Over-allocate the number of frames in FFmpeg's frame pool to take into account that we keep frames from FFmpeg decoders alive until they are displayed. This reduces the risk of bumpy playback and corrupt images when playing AV1 videos. Amends: 1e3e0fac0d1c3b0772958bb590be263f7114bd45 Fixes: QTBUG-123967 Task-number: QTBUG-115308 Pick-to: 6.7 6.5 Change-Id: I41c204c10898c6384cc0eaf349ded236cbc73376 Reviewed-by: Artem Dyomin <artem.dyomin@qt.io>
-rw-r--r--src/plugins/multimedia/ffmpeg/playbackengine/qffmpegstreamdecoder.cpp24
-rw-r--r--src/plugins/multimedia/ffmpeg/playbackengine/qffmpegstreamdecoder_p.h3
-rw-r--r--src/plugins/multimedia/ffmpeg/qffmpeghwaccel_d3d11.cpp14
3 files changed, 33 insertions, 8 deletions
diff --git a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegstreamdecoder.cpp b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegstreamdecoder.cpp
index d7f313c04..2f40c53aa 100644
--- a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegstreamdecoder.cpp
+++ b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegstreamdecoder.cpp
@@ -78,6 +78,21 @@ QPlatformMediaPlayer::TrackType StreamDecoder::trackType() const
return m_trackType;
}
+qint32 StreamDecoder::maxQueueSize(QPlatformMediaPlayer::TrackType type)
+{
+ switch (type) {
+
+ case QPlatformMediaPlayer::VideoStream:
+ return 3;
+ case QPlatformMediaPlayer::AudioStream:
+ return 9;
+ case QPlatformMediaPlayer::SubtitleStream:
+ return 6; /*main packet and closing packet*/
+ default:
+ Q_UNREACHABLE_RETURN(-1);
+ }
+}
+
void StreamDecoder::onFrameProcessed(Frame frame)
{
if (frame.sourceId() != id())
@@ -91,14 +106,7 @@ void StreamDecoder::onFrameProcessed(Frame frame)
bool StreamDecoder::canDoNextStep() const
{
- constexpr qint32 maxPendingFramesCount = 3;
- constexpr qint32 maxPendingAudioFramesCount = 9;
-
- const auto maxCount = m_trackType == QPlatformMediaPlayer::AudioStream
- ? maxPendingAudioFramesCount
- : m_trackType == QPlatformMediaPlayer::SubtitleStream
- ? maxPendingFramesCount * 2 /*main packet and closing packet*/
- : maxPendingFramesCount;
+ const qint32 maxCount = maxQueueSize(m_trackType);
return !m_packets.empty() && m_pendingFramesCount < maxCount
&& PlaybackEngineObject::canDoNextStep();
diff --git a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegstreamdecoder_p.h b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegstreamdecoder_p.h
index ba405a3f6..1acc07983 100644
--- a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegstreamdecoder_p.h
+++ b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegstreamdecoder_p.h
@@ -35,6 +35,9 @@ public:
QPlatformMediaPlayer::TrackType trackType() const;
+ // Maximum number of frames that we are allowed to keep in render queue
+ static qint32 maxQueueSize(QPlatformMediaPlayer::TrackType type);
+
public slots:
void setInitialPosition(TimePoint tp, qint64 trackPos);
diff --git a/src/plugins/multimedia/ffmpeg/qffmpeghwaccel_d3d11.cpp b/src/plugins/multimedia/ffmpeg/qffmpeghwaccel_d3d11.cpp
index fbd5593ed..92c2a515c 100644
--- a/src/plugins/multimedia/ffmpeg/qffmpeghwaccel_d3d11.cpp
+++ b/src/plugins/multimedia/ffmpeg/qffmpeghwaccel_d3d11.cpp
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qffmpeghwaccel_d3d11_p.h"
+#include "playbackengine/qffmpegstreamdecoder_p.h"
#include <qvideoframeformat.h>
#include "qffmpegvideobuffer_p.h"
@@ -240,6 +241,19 @@ TextureSet *D3D11TextureConverter::getTextures(AVFrame *frame)
void D3D11TextureConverter::SetupDecoderTextures(AVCodecContext *s)
{
+ // We are holding pool frames alive for quite long, which may cause
+ // codecs to run out of frames because FFmpeg has a fixed size
+ // decoder frame pool. We must therefore add extra frames to the pool
+ // to account for the frames we keep alive. First, we need to account
+ // for the maximum number of queued frames during rendering. In
+ // addition, we add one frame for the RHI rendering pipeline, and one
+ // additional frame because we may hold one in the Qt event loop.
+
+ const qint32 maxRenderQueueSize = StreamDecoder::maxQueueSize(QPlatformMediaPlayer::VideoStream);
+ constexpr qint32 framesHeldByRhi = 1;
+ constexpr qint32 framesHeldByQtEventLoop = 1;
+ s->extra_hw_frames = maxRenderQueueSize + framesHeldByRhi + framesHeldByQtEventLoop;
+
int ret = avcodec_get_hw_frames_parameters(s, s->hw_device_ctx, AV_PIX_FMT_D3D11,
&s->hw_frames_ctx);
if (ret < 0) {