summaryrefslogtreecommitdiffstats
path: root/src/plugins/multimedia/ffmpeg/qffmpegvideoframeencoder.cpp
diff options
context:
space:
mode:
authorArtem Dyomin <artem.dyomin@qt.io>2023-07-28 18:39:00 +0200
committerArtem Dyomin <artem.dyomin@qt.io>2023-08-01 15:34:56 +0000
commit49bf21047413fab156345b9f788d2332ba8c61dd (patch)
tree07d85a2b461f3f76d42dd2d3c7b5ac1f09f1817d /src/plugins/multimedia/ffmpeg/qffmpegvideoframeencoder.cpp
parent072cfbc82c9121a629f53e16de1cd791d8a291a8 (diff)
Implement a workaround for cases packet.pts < packet.dts
Some ffmpeg video encoders create packets where dts (decoding time) overtakes pts (presentation time). Muxer doesn't accept such packets. Shifting dts down fixes the problem. Pick-to: 6.6 6.5 Change-Id: Ia27d15650a0d9a8c273229dc4516e18551264676 Reviewed-by: Jøger Hansegård <joger.hansegard@qt.io> Reviewed-by: Artem Dyomin <artem.dyomin@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Diffstat (limited to 'src/plugins/multimedia/ffmpeg/qffmpegvideoframeencoder.cpp')
-rw-r--r--src/plugins/multimedia/ffmpeg/qffmpegvideoframeencoder.cpp59
1 files changed, 45 insertions, 14 deletions
diff --git a/src/plugins/multimedia/ffmpeg/qffmpegvideoframeencoder.cpp b/src/plugins/multimedia/ffmpeg/qffmpegvideoframeencoder.cpp
index 700d3c2cd..fa596e276 100644
--- a/src/plugins/multimedia/ffmpeg/qffmpegvideoframeencoder.cpp
+++ b/src/plugins/multimedia/ffmpeg/qffmpegvideoframeencoder.cpp
@@ -309,24 +309,55 @@ AVPacketUPtr VideoFrameEncoder::retrievePacket()
{
if (!d || !d->codecContext)
return nullptr;
- AVPacketUPtr packet(av_packet_alloc());
- int ret = avcodec_receive_packet(d->codecContext.get(), packet.get());
- if (ret < 0) {
- if (ret != AVERROR(EOF) && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF)
- qCDebug(qLcVideoFrameEncoder) << "Error receiving packet" << ret << err2str(ret);
- return nullptr;
- }
- auto ts = timeStampMs(packet->pts, d->stream->time_base);
- qCDebug(qLcVideoFrameEncoder) << "got a packet" << packet->pts << packet->dts << (ts ? *ts : 0);
+ auto getPacket = [&]() {
+ AVPacketUPtr packet(av_packet_alloc());
+ const int ret = avcodec_receive_packet(d->codecContext.get(), packet.get());
+ if (ret < 0) {
+ if (ret != AVERROR(EOF) && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF)
+ qCDebug(qLcVideoFrameEncoder) << "Error receiving packet" << ret << err2str(ret);
+ return AVPacketUPtr{};
+ }
+ auto ts = timeStampMs(packet->pts, d->stream->time_base);
+
+ qCDebug(qLcVideoFrameEncoder)
+ << "got a packet" << packet->pts << packet->dts << (ts ? *ts : 0);
+
+ packet->stream_index = d->stream->id;
+ return packet;
+ };
+
+ auto fixPacketDts = [&](AVPacket &packet) {
+ // Workaround for some ffmpeg codecs bugs (e.g. nvenc)
+ // Ideally, packet->pts < packet->dts is not expected
+
+ if (packet.dts == AV_NOPTS_VALUE)
+ return true;
+
+ packet.dts -= m_packetDtsOffset;
+
+ if (packet.pts != AV_NOPTS_VALUE && packet.pts < packet.dts) {
+ m_packetDtsOffset += packet.dts - packet.pts;
+ packet.dts = packet.pts;
+
+ if (m_prevPacketDts != AV_NOPTS_VALUE && packet.dts < m_prevPacketDts) {
+ qCWarning(qLcVideoFrameEncoder)
+ << "Skip packet; failed to fix dts:" << packet.dts << m_prevPacketDts;
+ return false;
+ }
+ }
+
+ m_prevPacketDts = packet.dts;
+
+ return true;
+ };
- if (packet->dts != AV_NOPTS_VALUE && packet->pts < packet->dts) {
- // the case seems to be an ffmpeg bug
- packet->dts = AV_NOPTS_VALUE;
+ while (auto packet = getPacket()) {
+ if (fixPacketDts(*packet))
+ return packet;
}
- packet->stream_index = d->stream->id;
- return packet;
+ return nullptr;
}
void VideoFrameEncoder::updateConversions()