From c563eb81a3df662061b9631ba98a78210c7b246d Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Mon, 18 Mar 2019 10:30:37 +0100 Subject: [PATCH] lib/ffmpeg/Filter: C+++ wrapper for several libavfilter objects --- src/lib/ffmpeg/Filter.hxx | 180 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 180 insertions(+) create mode 100644 src/lib/ffmpeg/Filter.hxx diff --git a/src/lib/ffmpeg/Filter.hxx b/src/lib/ffmpeg/Filter.hxx new file mode 100644 index 000000000..b2ab70e82 --- /dev/null +++ b/src/lib/ffmpeg/Filter.hxx @@ -0,0 +1,180 @@ +/* + * 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_FILTER_HXX +#define MPD_FFMPEG_FILTER_HXX + +#include "Error.hxx" + +extern "C" { +#include +} + +namespace Ffmpeg { + +class FilterInOut { + friend class FilterGraph; + + AVFilterInOut *io = nullptr; + + explicit FilterInOut(AVFilterInOut *_io) noexcept + :io(_io) {} + +public: + FilterInOut() = default; + + FilterInOut(const char *name, AVFilterContext &context) + :io(avfilter_inout_alloc()) { + if (io == nullptr) + throw std::bad_alloc(); + + io->name = av_strdup(name); + io->filter_ctx = &context; + io->pad_idx = 0; + io->next = nullptr; + } + + FilterInOut(FilterInOut &&src) noexcept + :io(std::exchange(src.io, nullptr)) {} + + ~FilterInOut() noexcept { + if (io != nullptr) + avfilter_inout_free(&io); + } + + FilterInOut &operator=(FilterInOut &&src) noexcept { + using std::swap; + swap(io, src.io); + return *this; + } + + auto *get() noexcept { + return io; + } +}; + +class FilterContext { + AVFilterContext *context = nullptr; + +public: + FilterContext() = default; + + FilterContext(const AVFilter &filt, + const char *name, const char *args, void *opaque, + AVFilterGraph &graph_ctx) { + int err = avfilter_graph_create_filter(&context, &filt, + name, args, opaque, + &graph_ctx); + if (err < 0) + throw MakeFfmpegError(err, "avfilter_graph_create_filter() failed"); + } + + FilterContext(const AVFilter &filt, + const char *name, + AVFilterGraph &graph_ctx) + :FilterContext(filt, name, nullptr, nullptr, graph_ctx) {} + + FilterContext(FilterContext &&src) noexcept + :context(std::exchange(src.context, nullptr)) {} + + ~FilterContext() noexcept { + if (context != nullptr) + avfilter_free(context); + } + + FilterContext &operator=(FilterContext &&src) noexcept { + using std::swap; + swap(context, src.context); + return *this; + } + + auto &operator*() noexcept { + return *context; + } + + auto *get() noexcept { + return context; + } +}; + +class FilterGraph { + AVFilterGraph *graph = nullptr; + +public: + FilterGraph(std::nullptr_t) noexcept {} + + FilterGraph():graph(avfilter_graph_alloc()) { + if (graph == nullptr) + throw std::bad_alloc(); + } + + FilterGraph(FilterGraph &&src) noexcept + :graph(std::exchange(src.graph, nullptr)) {} + + ~FilterGraph() noexcept { + if (graph != nullptr) + avfilter_graph_free(&graph); + } + + FilterGraph &operator=(FilterGraph &&src) noexcept { + using std::swap; + swap(graph, src.graph); + return *this; + } + + auto &operator*() noexcept { + return *graph; + } + + auto *operator->() noexcept { + return graph; + } + + std::pair Parse(const char *filters, + FilterInOut &&inputs, + FilterInOut &&outputs) { + int err = avfilter_graph_parse_ptr(graph, filters, + &inputs.io, &outputs.io, + nullptr); + if (err < 0) + throw MakeFfmpegError(err, "avfilter_graph_parse_ptr() failed"); + + return std::make_pair(std::move(inputs), std::move(outputs)); + } + + std::pair Parse(const char *filters) { + AVFilterInOut *inputs, *outputs; + int err = avfilter_graph_parse2(graph, filters, + &inputs, &outputs); + if (err < 0) + throw MakeFfmpegError(err, "avfilter_graph_parse2() failed"); + + return std::make_pair(FilterInOut{inputs}, FilterInOut{outputs}); + } + + void CheckAndConfigure() { + int err = avfilter_graph_config(graph, nullptr); + if (err < 0) + throw MakeFfmpegError(err, "avfilter_graph_config() failed"); + } +}; + +} + +#endif