diff options
Diffstat (limited to 'src/plugins/multimedia/ffmpeg/playbackengine/qffmpegcodec.cpp')
-rw-r--r-- | src/plugins/multimedia/ffmpeg/playbackengine/qffmpegcodec.cpp | 69 |
1 files changed, 69 insertions, 0 deletions
diff --git a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegcodec.cpp b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegcodec.cpp new file mode 100644 index 000000000..f2d094e5f --- /dev/null +++ b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegcodec.cpp @@ -0,0 +1,69 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "playbackengine/qffmpegcodec_p.h" + +QT_BEGIN_NAMESPACE + +namespace QFFmpeg { + +Codec::Data::Data(AVCodecContextUPtr context, AVStream *stream, + std::unique_ptr<QFFmpeg::HWAccel> hwAccel) + : context(std::move(context)), stream(stream), hwAccel(std::move(hwAccel)) +{ +} + +Codec::Data::~Data() +{ + // TODO: investigate if we can remove avcodec_close + // FFmpeg doc says that avcodec_free_context is enough + avcodec_close(context.get()); +} + +QMaybe<Codec> Codec::create(AVStream *stream) +{ + if (!stream) + return { "Invalid stream" }; + + const AVCodec *decoder = + QFFmpeg::HWAccel::hardwareDecoderForCodecId(stream->codecpar->codec_id); + if (!decoder) + return { "Failed to find a valid FFmpeg decoder" }; + + AVCodecContextUPtr context(avcodec_alloc_context3(decoder)); + if (!context) + return { "Failed to allocate a FFmpeg codec context" }; + + if (context->codec_type != AVMEDIA_TYPE_AUDIO && context->codec_type != AVMEDIA_TYPE_VIDEO + && context->codec_type != AVMEDIA_TYPE_SUBTITLE) { + return { "Unknown codec type" }; + } + + int ret = avcodec_parameters_to_context(context.get(), stream->codecpar); + if (ret < 0) + return { "Failed to set FFmpeg codec parameters" }; + + std::unique_ptr<QFFmpeg::HWAccel> hwAccel; + if (decoder->type == AVMEDIA_TYPE_VIDEO) { + hwAccel = QFFmpeg::HWAccel::create(decoder); + if (hwAccel) + context->hw_device_ctx = av_buffer_ref(hwAccel->hwDeviceContextAsBuffer()); + } + // ### This still gives errors about wrong HW formats (as we accept all of them) + // But it would be good to get so we can filter out pixel format we don't support natively + context->get_format = QFFmpeg::getFormat; + + /* Init the decoder, with reference counting and threading */ + AVDictionary *opts = nullptr; + av_dict_set(&opts, "refcounted_frames", "1", 0); + av_dict_set(&opts, "threads", "auto", 0); + ret = avcodec_open2(context.get(), decoder, &opts); + if (ret < 0) + return "Failed to open FFmpeg codec context " + err2str(ret); + + return Codec(new Data(std::move(context), stream, std::move(hwAccel))); +} + +QT_END_NAMESPACE + +} // namespace QFFmpeg |