AvTranscoder  0.9.4
C++APIforLibav/FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
FilterGraph.cpp
Go to the documentation of this file.
1 #include "FilterGraph.hpp"
2 
3 #include <AvTranscoder/util.hpp>
6 
7 extern "C" {
8 #include <libavfilter/avfilter.h>
9 #include <libavfilter/buffersrc.h>
10 #include <libavfilter/buffersink.h>
11 }
12 
13 #include <stdexcept>
14 #include <sstream>
15 
16 namespace avtranscoder
17 {
18 
20  : _graph(avfilter_graph_alloc())
21  , _filters()
22  , _codec(codec)
23  , _isInit(false)
24 {
25  if(!_graph)
26  throw std::runtime_error("Unable to create filter graph: out of memory.");
27 }
28 
30 {
31  for(std::vector<Filter*>::iterator it = _filters.begin(); it < _filters.end(); ++it)
32  {
33  it = _filters.erase(it);
34  }
35  avfilter_graph_free(&_graph);
36 }
37 
39 {
40  if(!hasFilters())
41  {
42  LOG_DEBUG("No filter to process.")
43  return;
44  }
45 
46  // init filter graph
47  if(!_isInit)
48  init(frame);
49 
50  // setup source frame
51  int ret = av_buffersrc_write_frame(_filters.at(0)->getAVFilterContext(), &frame.getAVFrame());
52  if(ret < 0)
53  {
54  throw std::runtime_error("Error when adding a frame to the source buffer used to start to process filters: " +
56  }
57 
58  // pull filtered data from the filter graph
59  for(;;)
60  {
61  ret = av_buffersink_get_frame(_filters.at(_filters.size() - 1)->getAVFilterContext(), &frame.getAVFrame());
62  if(ret == AVERROR_EOF || ret == AVERROR(EAGAIN))
63  break;
64  if(ret < 0)
65  {
66  throw std::runtime_error("Error reading buffer from buffersink: " + getDescriptionFromErrorCode(ret));
67  }
68  }
69 }
70 
71 Filter& FilterGraph::addFilter(const std::string& filterName, const std::string& filterOptions,
72  const std::string& instanceName)
73 {
74  LOG_INFO("Add filter " << filterName << " to the graph.")
75  Filter* filter = new Filter(filterName, filterOptions, instanceName);
76  _filters.push_back(filter);
77  return *_filters.back();
78 }
79 
80 void FilterGraph::init(const Frame& frame)
81 {
82  // push filters to the graph
83  pushInBuffer(frame);
84  for(size_t i = 1; i < _filters.size(); ++i)
85  {
86  pushFilter(*_filters.at(i));
87  }
88  pushOutBuffer(frame);
89 
90  // connect filters
91  for(size_t index = 0; index < _filters.size() - 1; ++index)
92  {
93  LOG_INFO("Connect filter " << _filters.at(index)->getName() << " to filter " << _filters.at(index + 1)->getName())
94  const int err =
95  avfilter_link(_filters.at(index)->getAVFilterContext(), 0, _filters.at(index + 1)->getAVFilterContext(), 0);
96  if(err < 0)
97  {
98  throw std::runtime_error("Error when connecting filters.");
99  }
100  }
101 
102  // configuring the graph
103  LOG_INFO("Configuring filter graph.")
104  const int err = avfilter_graph_config(_graph, NULL);
105  if(err < 0)
106  {
107  throw std::runtime_error("Error configuring the filter graph: " + getDescriptionFromErrorCode(err));
108  }
109 
110  _isInit = true;
111 }
112 
114 {
115  AVFilterContext* context = NULL;
116  const int err = avfilter_graph_create_filter(&context, &filter.getAVFilter(), filter.getInstanceName().c_str(),
117  filter.getOptions().c_str(), NULL, _graph);
118  filter.setAVFilterContext(context);
119  if(err < 0)
120  {
121  std::string msg("Cannot add filter ");
122  msg += filter.getName();
123  msg += " (instance=";
124  msg += filter.getInstanceName();
125  msg += ") to the graph: ";
126  msg += getDescriptionFromErrorCode(err);
127  throw std::runtime_error(msg);
128  }
129 }
130 
132 {
133  std::string filterName;
134  std::stringstream filterOptions;
135  // audio frame
136  if(frame.isAudioFrame())
137  {
138  filterName = "abuffer";
139  const AudioFrame& audioFrame = dynamic_cast<const AudioFrame&>(frame);
140  filterOptions << "time_base=" << _codec.getAVCodecContext().time_base.num << "/"
141  << _codec.getAVCodecContext().time_base.den << ":";
142  filterOptions << "sample_rate=" << audioFrame.getSampleRate() << ":";
143  filterOptions << "sample_fmt=" << getSampleFormatName(audioFrame.getSampleFormat()) << ":";
144  filterOptions << "channel_layout=0x" << std::hex << audioFrame.getChannelLayout();
145  }
146  // video frame
147  else if(frame.isVideoFrame())
148  {
149  filterName = "buffer";
150  const VideoFrame& videoFrame = dynamic_cast<const VideoFrame&>(frame);
151  filterOptions << "video_size=" << videoFrame.getWidth() << "x" << videoFrame.getHeight() << ":";
152  filterOptions << "pix_fmt=" << getPixelFormatName(videoFrame.getPixelFormat()) << ":";
153  filterOptions << "time_base=" << _codec.getAVCodecContext().time_base.num << "/"
154  << _codec.getAVCodecContext().time_base.den << ":";
155  filterOptions << "pixel_aspect=" << _codec.getAVCodecContext().sample_aspect_ratio.num << "/"
156  << _codec.getAVCodecContext().sample_aspect_ratio.den;
157  }
158  // invalid frame
159  else
160  throw std::runtime_error("Cannot create input buffer of filter graph: the given frame is invalid.");
161 
162  // add in buffer
163  Filter* in = new Filter(filterName, filterOptions.str(), "in");
164  LOG_INFO("Add filter '" << filterName << "' at the beginning of the graph.")
165  _filters.insert(_filters.begin(), in);
166  pushFilter(*in);
167 }
168 
170 {
171  std::string filterName;
172 
173  if(frame.isAudioFrame())
174  filterName = "abuffersink";
175  else if(frame.isVideoFrame())
176  filterName = "buffersink";
177  else
178  throw std::runtime_error("Cannot create output buffer of filter graph: the given frame is invalid.");
179 
180  // add out buffer
181  Filter& out = addFilter(filterName, "", "out");
182  pushFilter(out);
183 }
184 }
size_t getChannelLayout() const
Definition: AudioFrame.hpp:47
Describe a filter and its options.
Definition: Filter.hpp:15
bool _isInit
Is the FilterGraph initialized.
Definition: FilterGraph.hpp:86
void pushOutBuffer(const Frame &frame)
bool isVideoFrame() const
Definition: Frame.cpp:96
This class describes decoded video data.
Definition: VideoFrame.hpp:43
FilterGraph(const FilterGraph &otherFilterGraph)
void setAVFilterContext(AVFilterContext *newContext)
Definition: Filter.hpp:29
AVSampleFormat getSampleFormat() const
Definition: AudioFrame.hpp:48
AVFilter & getAVFilter()
Definition: Filter.hpp:26
std::string getInstanceName() const
Definition: Filter.hpp:23
std::string getDescriptionFromErrorCode(const int code)
Get the string description corresponding to the error code provided by ffmpeg/libav.
Definition: common.cpp:22
bool isAudioFrame() const
Definition: Frame.cpp:89
#define LOG_INFO(...)
Definition: log.hpp:23
std::string getPixelFormatName(const AVPixelFormat pixelFormat)
Definition: util.cpp:100
AVPixelFormat getPixelFormat() const
Definition: VideoFrame.hpp:51
std::string getOptions() const
Definition: Filter.hpp:22
void init(const Frame &frame)
Initialize the graph of filters to process.
Definition: FilterGraph.cpp:80
Filter & addFilter(const std::string &filterName, const std::string &filterOptions="", const std::string &instanceName="")
Add a filter.
Definition: FilterGraph.cpp:71
void pushInBuffer(const Frame &frame)
Push the input and output buffer at the beginning and the end of the graph.
size_t getHeight() const
Definition: VideoFrame.hpp:50
std::vector< Filter * > _filters
List of filters to process.
Definition: FilterGraph.hpp:79
size_t getSampleRate() const
Definition: AudioFrame.hpp:45
This class describes decoded audio data.
Definition: AudioFrame.hpp:36
This class describes decoded (raw) audio or video data.
Definition: Frame.hpp:16
std::string getName() const
Definition: Filter.cpp:33
void process(Frame &frame)
Pull filtered data from the filter graph, and put result to the given frame.
Definition: FilterGraph.cpp:38
AVCodecContext & getAVCodecContext()
Definition: ICodec.hpp:53
#define LOG_DEBUG(...)
Definition: log.hpp:17
size_t getWidth() const
Definition: VideoFrame.hpp:49
void pushFilter(Filter &filter)
Push the given Filter to the graph.
const ICodec & _codec
Codec of the stream on which the filters will be applied.
Definition: FilterGraph.hpp:80
std::string getSampleFormatName(const AVSampleFormat sampleFormat)
Definition: util.cpp:106
AVFrame & getAVFrame()
Definition: Frame.hpp:88
AVFilterGraph * _graph
The graph which holds the filters.
Definition: FilterGraph.hpp:78