4#include "playbackengine/qffmpegcodeccontext_p.h"
7#include <QtMultimedia/qplaybackoptions.h>
8#include <QtCore/qloggingcategory.h>
12using namespace Qt::StringLiterals;
18CodecContext::Data::Data(AVCodecContextUPtr context, AVStream *avStream,
19 AVFormatContext *avFormatContext,
20 std::unique_ptr<QFFmpeg::HWAccel> hwAccel)
21 : context(std::move(context)),
23 formatContext(avFormatContext),
24 hwAccel(std::move(hwAccel))
26 if (stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
27 pixelAspectRatio = av_guess_sample_aspect_ratio(formatContext, stream,
nullptr);
30q23::expected<CodecContext, QString>
CodecContext::create(AVStream *stream,
31 AVFormatContext *formatContext,
35 return q23::unexpected{ u"Invalid stream"_s };
37 if (stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
38 auto hwCodec = create(stream, formatContext, options, Hw);
42 qCInfo(qLcPlaybackEngineCodec) << hwCodec.error();
45 auto context = create(stream, formatContext, options, Sw);
47 qCWarning(qLcPlaybackEngineCodec) << context.error();
55 return d->pixelAspectRatio.num && d->pixelAspectRatio.den ? d->pixelAspectRatio
56 : frame->sample_aspect_ratio;
59q23::expected<CodecContext, QString>
CodecContext::create(AVStream *stream,
60 AVFormatContext *formatContext,
62 VideoCodecCreationPolicy videoCodecPolicy)
66 if (videoCodecPolicy == Hw && stream->codecpar->codec_type != AVMEDIA_TYPE_VIDEO)
67 Q_ASSERT(!
"Codec::create has been called with Hw policy on a non-video stream");
70 std::unique_ptr<QFFmpeg::HWAccel> hwAccel;
72 if (videoCodecPolicy == Hw)
73 std::tie(decoder, hwAccel) = HWAccel::findDecoderWithHwAccel(stream->codecpar->codec_id);
75 decoder = QFFmpeg::findAVDecoder(stream->codecpar->codec_id);
78 return q23::unexpected{
79 QString(u"No %1 decoder found").arg(videoCodecPolicy == Hw ?
"HW" :
"SW")
82 qCDebug(qLcPlaybackEngineCodec)
83 <<
"found decoder" << decoder->name() <<
"for id" << decoder->id();
85 AVCodecContextUPtr context(avcodec_alloc_context3(decoder->get()));
87 return q23::unexpected{ u"Failed to allocate a FFmpeg codec context"_s };
91 context->hwaccel_flags |= AV_HWACCEL_FLAG_IGNORE_LEVEL;
93 static const bool allowProfileMismatch =
static_cast<
bool>(
94 qEnvironmentVariableIntValue(
"QT_FFMPEG_HW_ALLOW_PROFILE_MISMATCH"));
95 if (allowProfileMismatch) {
98 context->hwaccel_flags |= AV_HWACCEL_FLAG_ALLOW_PROFILE_MISMATCH;
102 context->hw_device_ctx = av_buffer_ref(hwAccel->hwDeviceContextAsBuffer());
104 if (context->codec_type != AVMEDIA_TYPE_AUDIO && context->codec_type != AVMEDIA_TYPE_VIDEO
105 && context->codec_type != AVMEDIA_TYPE_SUBTITLE) {
106 return q23::unexpected{ u"Unknown codec type"_s };
109 int ret = avcodec_parameters_to_context(context.get(), stream->codecpar);
111 return q23::unexpected{
112 QStringLiteral(
"Failed to set FFmpeg codec parameters: %1").arg(err2str(ret))
117 context->get_format = QFFmpeg::getFormat;
120 AVDictionaryHolder opts;
121 if (options.playbackIntent() == QPlaybackOptions::PlaybackIntent::LowLatencyStreaming)
122 av_dict_set(opts,
"flags",
"low_delay", 0);
124 av_dict_set(opts,
"refcounted_frames",
"1", 0);
125 av_dict_set(opts,
"threads",
"auto", 0);
126 applyExperimentalCodecOptions(*decoder, opts);
128 ret = avcodec_open2(context.get(), decoder->get(), opts);
131 return q23::unexpected{
132 QStringLiteral(
"Failed to open FFmpeg codec context: %1").arg(err2str(ret))
135 return CodecContext(
new Data(std::move(context), stream, formatContext, std::move(hwAccel)));
AVRational pixelAspectRatio(AVFrame *frame) const
The QPlaybackOptions class enables low-level control of media playback options.
std::conditional_t< QT_FFMPEG_AVIO_WRITE_CONST, const uint8_t *, uint8_t * > AvioWriteBufferType
Q_STATIC_LOGGING_CATEGORY(lcAccessibilityCore, "qt.accessibility.core")