Skip to content

Commit 732791a

Browse files
author
Clement Champetier
committed
FilterGraph: updated process method to manage several input buffers
1 parent 18dcdc4 commit 732791a

File tree

3 files changed

+74
-58
lines changed

3 files changed

+74
-58
lines changed

src/AvTranscoder/filter/FilterGraph.cpp

Lines changed: 60 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ FilterGraph::~FilterGraph()
3535
avfilter_graph_free(&_graph);
3636
}
3737

38-
void FilterGraph::process(const Frame& inputFrame, Frame& outputFrame)
38+
void FilterGraph::process(const std::vector<Frame*>& inputs, Frame& output)
3939
{
4040
if(!hasFilters())
4141
{
@@ -45,20 +45,23 @@ void FilterGraph::process(const Frame& inputFrame, Frame& outputFrame)
4545

4646
// init filter graph
4747
if(!_isInit)
48-
init(inputFrame, outputFrame);
48+
init(inputs, output);
4949

50-
// setup source frame
51-
int ret = av_buffersrc_write_frame(_filters.at(0)->getAVFilterContext(), &inputFrame.getAVFrame());
52-
if(ret < 0)
50+
// setup input frames
51+
for(size_t index = 0; index < inputs.size(); ++index)
5352
{
54-
throw std::runtime_error("Error when adding a frame to the source buffer used to start to process filters: " +
55-
getDescriptionFromErrorCode(ret));
53+
const int ret = av_buffersrc_write_frame(_filters.at(index)->getAVFilterContext(), &inputs.at(index)->getAVFrame());
54+
if(ret < 0)
55+
{
56+
throw std::runtime_error("Error when adding a frame to the source buffer used to start to process filters: " +
57+
getDescriptionFromErrorCode(ret));
58+
}
5659
}
5760

5861
// pull filtered data from the filter graph
5962
for(;;)
6063
{
61-
ret = av_buffersink_get_frame(_filters.at(_filters.size() - 1)->getAVFilterContext(), &outputFrame.getAVFrame());
64+
const int ret = av_buffersink_get_frame(_filters.at(_filters.size() - 1)->getAVFilterContext(), &output.getAVFrame());
6265
if(ret == AVERROR_EOF || ret == AVERROR(EAGAIN))
6366
break;
6467
if(ret < 0)
@@ -77,22 +80,27 @@ Filter& FilterGraph::addFilter(const std::string& filterName, const std::string&
7780
return *_filters.back();
7881
}
7982

80-
void FilterGraph::init(const Frame& inputFrame, Frame& outputFrame)
83+
void FilterGraph::init(const std::vector<Frame*>& inputs, Frame& output)
8184
{
8285
// push filters to the graph
83-
pushInBuffer(inputFrame);
86+
pushInBuffer(inputs);
8487
for(size_t i = 1; i < _filters.size(); ++i)
8588
{
8689
pushFilter(*_filters.at(i));
8790
}
88-
pushOutBuffer(outputFrame);
91+
pushOutBuffer(output);
8992

9093
// connect filters
9194
for(size_t index = 0; index < _filters.size() - 1; ++index)
9295
{
93-
LOG_INFO("Connect filter " << _filters.at(index)->getName() << " to filter " << _filters.at(index + 1)->getName())
96+
size_t indexOfFilterToConnect = index + 1;
97+
// handle cases with several inputs
98+
if(index < inputs.size())
99+
indexOfFilterToConnect = inputs.size();
100+
101+
LOG_INFO("Connect filter " << _filters.at(index)->getName() << " to filter " << _filters.at(indexOfFilterToConnect)->getName())
94102
const int err =
95-
avfilter_link(_filters.at(index)->getAVFilterContext(), 0, _filters.at(index + 1)->getAVFilterContext(), 0);
103+
avfilter_link(_filters.at(index)->getAVFilterContext(), 0, _filters.at(indexOfFilterToConnect)->getAVFilterContext(), 0);
96104
if(err < 0)
97105
{
98106
throw std::runtime_error("Error when connecting filters.");
@@ -128,51 +136,54 @@ void FilterGraph::pushFilter(Filter& filter)
128136
}
129137
}
130138

131-
void FilterGraph::pushInBuffer(const Frame& frame)
139+
void FilterGraph::pushInBuffer(const std::vector<Frame*>& inputs)
132140
{
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())
141+
for(std::vector<Frame*>::const_iterator it = inputs.begin(); it != inputs.end(); ++it)
148142
{
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;
143+
std::string filterName;
144+
std::stringstream filterOptions;
145+
// audio frame
146+
if((*it)->isAudioFrame())
147+
{
148+
filterName = "abuffer";
149+
const AudioFrame* audioFrame = dynamic_cast<const AudioFrame*>(*it);
150+
filterOptions << "time_base=" << _codec.getAVCodecContext().time_base.num << "/"
151+
<< _codec.getAVCodecContext().time_base.den << ":";
152+
filterOptions << "sample_rate=" << audioFrame->getSampleRate() << ":";
153+
filterOptions << "sample_fmt=" << getSampleFormatName(audioFrame->getSampleFormat()) << ":";
154+
filterOptions << "channel_layout=0x" << std::hex << audioFrame->getChannelLayout();
155+
}
156+
// video frame
157+
else if((*it)->isVideoFrame())
158+
{
159+
filterName = "buffer";
160+
const VideoFrame* videoFrame = dynamic_cast<const VideoFrame*>(*it);
161+
filterOptions << "video_size=" << videoFrame->getWidth() << "x" << videoFrame->getHeight() << ":";
162+
filterOptions << "pix_fmt=" << getPixelFormatName(videoFrame->getPixelFormat()) << ":";
163+
filterOptions << "time_base=" << _codec.getAVCodecContext().time_base.num << "/"
164+
<< _codec.getAVCodecContext().time_base.den << ":";
165+
filterOptions << "pixel_aspect=" << _codec.getAVCodecContext().sample_aspect_ratio.num << "/"
166+
<< _codec.getAVCodecContext().sample_aspect_ratio.den;
167+
}
168+
// invalid frame
169+
else
170+
throw std::runtime_error("Cannot create input buffer of filter graph: the given frame is invalid.");
171+
172+
// add in buffer
173+
Filter* in = new Filter(filterName, filterOptions.str(), "in");
174+
LOG_INFO("Add filter '" << filterName << "' at the beginning of the graph.")
175+
_filters.insert(_filters.begin(), in);
176+
pushFilter(*in);
157177
}
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);
167178
}
168179

169-
void FilterGraph::pushOutBuffer(const Frame& frame)
180+
void FilterGraph::pushOutBuffer(const Frame& output)
170181
{
171182
std::string filterName;
172183

173-
if(frame.isAudioFrame())
184+
if(output.isAudioFrame())
174185
filterName = "abuffersink";
175-
else if(frame.isVideoFrame())
186+
else if(output.isVideoFrame())
176187
filterName = "buffersink";
177188
else
178189
throw std::runtime_error("Cannot create output buffer of filter graph: the given frame is invalid.");

src/AvTranscoder/filter/FilterGraph.hpp

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@ namespace avtranscoder
1515

1616
/**
1717
* @brief Manager of filters.
18-
* @warning Currently, the class manages only filters which has one input and one output.
19-
* @note See 'complex graph' definition in ffmpeg documentation.
2018
**/
2119
class AvExport FilterGraph
2220
{
@@ -44,11 +42,18 @@ class AvExport FilterGraph
4442

4543
/**
4644
* @brief Pull filtered data from the filter graph, and put result to the given frame.
47-
* @param inputFrame: input data.
48-
* @param inputFrame: output data.
45+
* @param inputs: input data buffers.
46+
* @param output: output data buffer.
4947
* @note Do nothing if there was no filter added.
48+
* If there is one input buffer, the filter graph is a chain of effects: input -> filter 1 -> filter 2 -> output.
49+
* If there is several input buffers, the filter graph is like this:
50+
* input 1 ---|
51+
* |
52+
* filter 1 -> filter 2 -> output
53+
* |
54+
* input 2 ---|
5055
*/
51-
void process(const Frame& inputFrame, Frame& outputFrame);
56+
void process(const std::vector<Frame*>& inputs, Frame& output);
5257

5358
private:
5459
/**
@@ -62,7 +67,7 @@ class AvExport FilterGraph
6267
* @see pushInBuffer
6368
* @see pushOutBuffer
6469
*/
65-
void init(const Frame& inputFrame, Frame& outputFrame);
70+
void init(const std::vector<Frame*>& inputs, Frame& output);
6671

6772
/**
6873
* @brief Push the given Filter to the graph.
@@ -71,8 +76,8 @@ class AvExport FilterGraph
7176

7277
///@{
7378
/// @brief Push the input and output buffer at the beginning and the end of the graph.
74-
void pushInBuffer(const Frame& frame);
75-
void pushOutBuffer(const Frame& frame);
79+
void pushInBuffer(const std::vector<Frame*>& inputs);
80+
void pushOutBuffer(const Frame& output);
7681
//@}
7782

7883
private:

src/AvTranscoder/transcoder/StreamTranscoder.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -491,7 +491,7 @@ bool StreamTranscoder::processTranscode()
491491
if(decodingStatus)
492492
{
493493
LOG_DEBUG("Filtering")
494-
_filterGraph->process(*_sourceBuffers.at(0), *_sourceBuffers.at(0));
494+
_filterGraph->process(_sourceBuffers, *_sourceBuffers.at(0));
495495

496496
LOG_DEBUG("Convert")
497497
_transform->convert(*_sourceBuffers.at(0), *_frameBuffers.at(0));

0 commit comments

Comments
 (0)