diff options
author | Artem Dyomin <artem.dyomin@qt.io> | 2023-07-28 18:39:00 +0200 |
---|---|---|
committer | Artem Dyomin <artem.dyomin@qt.io> | 2023-08-01 15:34:56 +0000 |
commit | 49bf21047413fab156345b9f788d2332ba8c61dd (patch) | |
tree | 07d85a2b461f3f76d42dd2d3c7b5ac1f09f1817d /src/plugins/multimedia/ffmpeg/qffmpegvideoframeencoder.cpp | |
parent | 072cfbc82c9121a629f53e16de1cd791d8a291a8 (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.cpp | 59 |
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() |