From 05f7a6d1ffc1be13be5e7e8dec2aed33556b64f0 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 13 Mar 2019 00:16:28 +0100 Subject: [PATCH] decoder/ffmpeg: add AVFormatContext wrapper class --- src/decoder/plugins/FfmpegDecoderPlugin.cxx | 25 ++----- src/lib/ffmpeg/Format.hxx | 81 +++++++++++++++++++++ 2 files changed, 87 insertions(+), 19 deletions(-) create mode 100644 src/lib/ffmpeg/Format.hxx diff --git a/src/decoder/plugins/FfmpegDecoderPlugin.cxx b/src/decoder/plugins/FfmpegDecoderPlugin.cxx index b15aab225..109e86b97 100644 --- a/src/decoder/plugins/FfmpegDecoderPlugin.cxx +++ b/src/decoder/plugins/FfmpegDecoderPlugin.cxx @@ -28,6 +28,7 @@ #include "lib/ffmpeg/Init.hxx" #include "lib/ffmpeg/Buffer.hxx" #include "lib/ffmpeg/Frame.hxx" +#include "lib/ffmpeg/Format.hxx" #include "../DecoderAPI.hxx" #include "FfmpegMetaData.hxx" #include "FfmpegIo.hxx" @@ -58,24 +59,18 @@ extern "C" { */ static AVDictionary *avformat_options = nullptr; -static AVFormatContext * +static Ffmpeg::FormatContext FfmpegOpenInput(AVIOContext *pb, const char *filename, AVInputFormat *fmt) { - AVFormatContext *context = avformat_alloc_context(); - if (context == nullptr) - throw std::runtime_error("avformat_alloc_context() failed"); - - context->pb = pb; + Ffmpeg::FormatContext context(pb); AVDictionary *options = nullptr; AtScopeExit(&options) { av_dict_free(&options); }; av_dict_copy(&options, avformat_options, 0); - int err = avformat_open_input(&context, filename, fmt, &options); - if (err < 0) - throw MakeFfmpegError(err, "avformat_open_input() failed"); + context.OpenInput(filename, fmt, &options); return context; } @@ -628,13 +623,9 @@ ffmpeg_decode(DecoderClient &client, InputStream &input) return; } - AVFormatContext *format_context = + auto format_context = FfmpegOpenInput(stream.io, input.GetURI(), nullptr); - AtScopeExit(&format_context) { - avformat_close_input(&format_context); - }; - const auto *input_format = format_context->iformat; FormatDebug(ffmpeg_domain, "detected input format '%s' (%s)", input_format->name, input_format->long_name); @@ -683,11 +674,7 @@ try { if (!stream.Open()) return false; - AVFormatContext *f = FfmpegOpenInput(stream.io, is.GetURI(), nullptr); - AtScopeExit(&f) { - avformat_close_input(&f); - }; - + auto f = FfmpegOpenInput(stream.io, is.GetURI(), nullptr); return FfmpegScanStream(*f, handler); } catch (...) { return false; diff --git a/src/lib/ffmpeg/Format.hxx b/src/lib/ffmpeg/Format.hxx new file mode 100644 index 000000000..511f15464 --- /dev/null +++ b/src/lib/ffmpeg/Format.hxx @@ -0,0 +1,81 @@ +/* + * 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_FORMAT_HXX +#define MPD_FFMPEG_FORMAT_HXX + +#include "Error.hxx" + +extern "C" { +#include +} + +#include + +namespace Ffmpeg { + +class FormatContext { + AVFormatContext *format_context = nullptr; + +public: + FormatContext() = default; + + explicit FormatContext(AVIOContext *pb) + :format_context(avformat_alloc_context()) + { + if (format_context == nullptr) + throw std::bad_alloc(); + + format_context->pb = pb; + } + + ~FormatContext() noexcept { + if (format_context != nullptr) + avformat_close_input(&format_context); + } + + FormatContext(FormatContext &&src) noexcept + :format_context(std::exchange(src.format_context, nullptr)) {} + + FormatContext &operator=(FormatContext &&src) noexcept { + using std::swap; + swap(format_context, src.format_context); + return *this; + } + + void OpenInput(const char *url, AVInputFormat *fmt, + AVDictionary **options) { + int err = avformat_open_input(&format_context, url, fmt, + options); + if (err < 0) + throw MakeFfmpegError(err, "avformat_open_input() failed"); + } + + AVFormatContext &operator*() noexcept { + return *format_context; + } + + AVFormatContext *operator->() noexcept { + return format_context; + } +}; + +} // namespace Ffmpeg + +#endif