From 0009d53b3f24068604a6c323243427c0b5a3d2b4 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 13 Mar 2019 09:41:52 +0100 Subject: [PATCH] decoder/ffmpeg: add AVCodecContext wrapper class --- src/decoder/plugins/FfmpegDecoderPlugin.cxx | 23 ++---- src/lib/ffmpeg/Codec.hxx | 87 +++++++++++++++++++++ 2 files changed, 92 insertions(+), 18 deletions(-) create mode 100644 src/lib/ffmpeg/Codec.hxx diff --git a/src/decoder/plugins/FfmpegDecoderPlugin.cxx b/src/decoder/plugins/FfmpegDecoderPlugin.cxx index 109e86b97..41ed4bb16 100644 --- a/src/decoder/plugins/FfmpegDecoderPlugin.cxx +++ b/src/decoder/plugins/FfmpegDecoderPlugin.cxx @@ -29,6 +29,7 @@ #include "lib/ffmpeg/Buffer.hxx" #include "lib/ffmpeg/Frame.hxx" #include "lib/ffmpeg/Format.hxx" +#include "lib/ffmpeg/Codec.hxx" #include "../DecoderAPI.hxx" #include "FfmpegMetaData.hxx" #include "FfmpegIo.hxx" @@ -524,23 +525,9 @@ FfmpegDecode(DecoderClient &client, InputStream &input, return; } - AVCodecContext *codec_context = avcodec_alloc_context3(codec); - if (codec_context == nullptr) { - LogError(ffmpeg_domain, "avcodec_alloc_context3() failed"); - return; - } - - AtScopeExit(&codec_context) { - avcodec_free_context(&codec_context); - }; - - avcodec_parameters_to_context(codec_context, av_stream.codecpar); - - const int open_result = avcodec_open2(codec_context, codec, nullptr); - if (open_result < 0) { - LogError(ffmpeg_domain, "Could not open codec"); - return; - } + Ffmpeg::CodecContext codec_context(*codec); + codec_context.FillFromParameters(*av_stream.codecpar); + codec_context.Open(*codec, nullptr); const SampleFormat sample_format = ffmpeg_sample_format(codec_context->sample_fmt); @@ -583,7 +570,7 @@ FfmpegDecode(DecoderClient &client, InputStream &input, AVSEEK_FLAG_ANY|AVSEEK_FLAG_BACKWARD) < 0) client.SeekError(); else { - avcodec_flush_buffers(codec_context); + codec_context.FlushBuffers(); min_frame = client.GetSeekFrame(); client.CommandFinished(); } diff --git a/src/lib/ffmpeg/Codec.hxx b/src/lib/ffmpeg/Codec.hxx new file mode 100644 index 000000000..adf3fc9ba --- /dev/null +++ b/src/lib/ffmpeg/Codec.hxx @@ -0,0 +1,87 @@ +/* + * Copyright 2003-2019 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_FFMPEG_CODEC_HXX +#define MPD_FFMPEG_CODEC_HXX + +#include "Error.hxx" + +extern "C" { +#include +} + +#include + +namespace Ffmpeg { + +class CodecContext { + AVCodecContext *codec_context = nullptr; + +public: + CodecContext() = default; + + explicit CodecContext(AVCodec &codec) + :codec_context(avcodec_alloc_context3(&codec)) + { + if (codec_context == nullptr) + throw std::bad_alloc(); + } + + ~CodecContext() noexcept { + if (codec_context != nullptr) + avcodec_free_context(&codec_context); + } + + CodecContext(CodecContext &&src) noexcept + :codec_context(std::exchange(src.codec_context, nullptr)) {} + + CodecContext &operator=(CodecContext &&src) noexcept { + using std::swap; + swap(codec_context, src.codec_context); + return *this; + } + + AVCodecContext &operator*() noexcept { + return *codec_context; + } + + AVCodecContext *operator->() noexcept { + return codec_context; + } + + void FillFromParameters(const AVCodecParameters &par) { + int err = avcodec_parameters_to_context(codec_context, &par); + if (err < 0) + throw MakeFfmpegError(err, "avcodec_parameters_to_context() failed"); + } + + void Open(const AVCodec &codec, AVDictionary **options) { + int err = avcodec_open2(codec_context, &codec, options); + if (err < 0) + throw MakeFfmpegError(err, "avcodec_open2() failed"); + } + + void FlushBuffers() noexcept { + avcodec_flush_buffers(codec_context); + } +}; + +} // namespace Ffmpeg + +#endif