media_filter.h 4.98 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
/*
 *  Copyright (C) 2018 Savoir-faire Linux Inc.
 *
 *  Author: Philippe Gorley <philippe.gorley@savoirfairelinux.com>
 *
 *  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 3 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.
 */

#pragma once

#include "config.h"
#include "media_stream.h"
#include "noncopyable.h"

#include <map>
#include <string>
#include <vector>

class AVFilterContext;
class AVFilterGraph;
class AVFilterInOut;

namespace ring {

/**
 * Provides access to libavfilter.
 *
 * Can be used for simple filters (1 input, 1 output), or complex filters (multiple inputs, 1 output).
 * Multiple outputs are not supported. They add complexity for little gain.
 *
 * For information on how to write a filter graph description, see:
 * https://ffmpeg.org/ffmpeg-filters.html
 * http://trac.ffmpeg.org/wiki/FilteringGuide
 *
 * For complex filters, it is required to name each filter graph input. These names are used to feed the correct input.
 * It is the same name that will be passed as second argument to feedInput(AVFrame*, std::string). This is not required
 * for simple filters, as there is only one input.
 *
 * Simple filter: "scale=320:240"
 * Scales the input to 320x240. No need to specify input names.
 *
 * Complex filter: "[in1] scale=iw/4:ih/4 [mid]; [in2] [mid] overlay=main_w-overlay_w-10:main_h-overlay_h-10"
 * in1 will be scaled to 1/16th its size and placed over in2 in the bottom right corner. When feeding frames to
 * the filter, you need to specify whether the frame is destined for in1 or in2.
 */
class MediaFilter {
    public:
        MediaFilter();
        ~MediaFilter();

        /**
         * Returns the current filter graph string.
         */
        std::string getFilterDesc() const;

        /**
         * Initializes the filter graph with 1 input.
         *
         * NOTE This method will fail if @filterDesc has more than 1 input.
         * NOTE Wraps @msp in a vector and calls initialize.
         */
        int initialize(const std::string& filterDesc, MediaStream msp);

        /**
         * Initializes the filter graph with one or more inputs and one output. Returns a negative code on error.
         */
        int initialize(const std::string& filterDesc, std::vector<MediaStream> msps);

        /**
         * Give the filter graph an input frame. Caller is responsible for freeing the frame.
         *
         * NOTE This is a wrapper for feedInput(AVFrame*, std::string)
         * NOTE This is for filters with 1 input.
         */
        int feedInput(AVFrame* frame);

        /**
         * Give the specified source filter an input frame. Caller is responsible for freeing the frame.
         *
         * NOTE Will fail if @inputName is not found in the graph.
         */
        int feedInput(AVFrame* frame, std::string inputName);

        /**
         * Pull a frame from the filter graph. Caller owns the frame reference.
         *
         * Returns AVERROR(EAGAIN) if filter graph requires more input.
         */
        AVFrame* readOutput(); // frame reference belongs to caller

    private:
        NON_COPYABLE(MediaFilter);

        /**
         * Initializes output of filter graph.
         */
        int initOutputFilter(AVFilterInOut* out);

        /**
         * Initializes an input of filter graph.
         */
        int initInputFilter(AVFilterInOut* in, MediaStream msp, bool simple);

        /**
         * Convenience method that prints @msg and returns err.
         *
         * NOTE @msg should not be null.
         */
        int fail(std::string msg, int err);

        /**
         * Frees resources used by MediaFilter.
         */
        void clean();

        /**
         * Filter graph pointer.
         */
        AVFilterGraph* graph_ = nullptr;

        /**
         * Filter graph output. Corresponds to a buffersink/abuffersink filter.
         */
        AVFilterContext* output_ = nullptr;

        /**
         * List of filter graph inputs. Each corresponds to a buffer/abuffer filter.
         */
        std::vector<AVFilterContext*> inputs_;

        /**
         * List of filter graph input names. Same order as @inputs_.
         */
        std::vector<std::string> inputNames_;

        /**
         * Filter graph string.
         */
        std::string desc_ {};

        /**
         * Flag to know whether or not the filter graph is initialized.
         */
        bool initialized_ {false};
};

}; // namespace ring