@@ -35,30 +35,35 @@ FilterGraph::~FilterGraph()
35
35
avfilter_graph_free (&_graph);
36
36
}
37
37
38
- void FilterGraph::process (Frame& frame )
38
+ void FilterGraph::process (const std::vector< Frame*>& inputs, Frame& output )
39
39
{
40
40
if (!hasFilters ())
41
41
{
42
- LOG_DEBUG (" No filter to process." )
42
+ LOG_DEBUG (" No filter to process: reference first input frame to the given output." )
43
+ output.clear ();
44
+ output.refFrame (*inputs.at (0 ));
43
45
return ;
44
46
}
45
47
46
48
// init filter graph
47
49
if (!_isInit)
48
- init (frame );
50
+ init (inputs, output );
49
51
50
- // setup source frame
51
- int ret = av_buffersrc_write_frame (_filters.at (0 )->getAVFilterContext (), &frame.getAVFrame ());
52
- if (ret < 0 )
52
+ // setup input frames
53
+ for (size_t index = 0 ; index < inputs.size (); ++index)
53
54
{
54
- throw std::runtime_error (" Error when adding a frame to the source buffer used to start to process filters: " +
55
- getDescriptionFromErrorCode (ret));
55
+ const int ret = av_buffersrc_write_frame (_filters.at (index)->getAVFilterContext (), &inputs.at (index)->getAVFrame ());
56
+ if (ret < 0 )
57
+ {
58
+ throw std::runtime_error (" Error when adding a frame to the source buffer used to start to process filters: " +
59
+ getDescriptionFromErrorCode (ret));
60
+ }
56
61
}
57
62
58
63
// pull filtered data from the filter graph
59
64
for (;;)
60
65
{
61
- ret = av_buffersink_get_frame (_filters.at (_filters.size () - 1 )->getAVFilterContext (), &frame .getAVFrame ());
66
+ const int ret = av_buffersink_get_frame (_filters.at (_filters.size () - 1 )->getAVFilterContext (), &output .getAVFrame ());
62
67
if (ret == AVERROR_EOF || ret == AVERROR (EAGAIN))
63
68
break ;
64
69
if (ret < 0 )
@@ -77,22 +82,31 @@ Filter& FilterGraph::addFilter(const std::string& filterName, const std::string&
77
82
return *_filters.back ();
78
83
}
79
84
80
- void FilterGraph::init (const Frame& frame )
85
+ void FilterGraph::init (const std::vector< Frame*>& inputs, Frame& output )
81
86
{
82
87
// push filters to the graph
83
- pushInBuffer (frame);
84
- for (size_t i = 1 ; i < _filters.size (); ++i)
88
+ addInBuffer (inputs);
89
+ addOutBuffer (output);
90
+ for (size_t i = 0 ; i < _filters.size (); ++i)
85
91
{
86
92
pushFilter (*_filters.at (i));
87
93
}
88
- pushOutBuffer (frame);
89
94
90
95
// connect filters
91
96
for (size_t index = 0 ; index < _filters.size () - 1 ; ++index)
92
97
{
93
- LOG_INFO (" Connect filter " << _filters.at (index)->getName () << " to filter " << _filters.at (index + 1 )->getName ())
98
+ size_t indexOfOutputFilterToConnect = index + 1 ;
99
+ size_t indexOfInputPadOfDestinationFilter = 0 ;
100
+ // handle cases with several inputs
101
+ if (index < inputs.size ())
102
+ {
103
+ indexOfOutputFilterToConnect = inputs.size ();
104
+ indexOfInputPadOfDestinationFilter = index;
105
+ }
106
+
107
+ LOG_INFO (" Connect filter " << _filters.at (index)->getName () << " to filter " << _filters.at (indexOfOutputFilterToConnect)->getName ())
94
108
const int err =
95
- avfilter_link (_filters.at (index)->getAVFilterContext (), 0 , _filters.at (index + 1 )->getAVFilterContext (), 0 );
109
+ avfilter_link (_filters.at (index)->getAVFilterContext (), 0 , _filters.at (indexOfOutputFilterToConnect )->getAVFilterContext (), indexOfInputPadOfDestinationFilter );
96
110
if (err < 0 )
97
111
{
98
112
throw std::runtime_error (" Error when connecting filters." );
@@ -128,57 +142,58 @@ void FilterGraph::pushFilter(Filter& filter)
128
142
}
129
143
}
130
144
131
- void FilterGraph::pushInBuffer (const Frame& frame )
145
+ void FilterGraph::addInBuffer (const std::vector< Frame*>& inputs )
132
146
{
133
- std::string filterName;
134
- std::stringstream filterOptions;
135
- // audio frame
136
- if (frame.isAudioFrame ())
147
+ for (std::vector<Frame*>::const_reverse_iterator it = inputs.rbegin (); it != inputs.rend (); ++it)
137
148
{
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 ;
149
+ std::string filterName;
150
+ std::stringstream filterOptions;
151
+ // audio frame
152
+ if ((*it)->isAudioFrame ())
153
+ {
154
+ filterName = " abuffer" ;
155
+ const AudioFrame* audioFrame = dynamic_cast <const AudioFrame*>(*it);
156
+ filterOptions << " time_base=" << _codec.getAVCodecContext ().time_base .num << " /"
157
+ << _codec.getAVCodecContext ().time_base .den << " :" ;
158
+ filterOptions << " sample_rate=" << audioFrame->getSampleRate () << " :" ;
159
+ filterOptions << " sample_fmt=" << getSampleFormatName (audioFrame->getSampleFormat ()) << " :" ;
160
+ filterOptions << " channel_layout=0x" << std::hex << audioFrame->getChannelLayout ();
161
+ }
162
+ // video frame
163
+ else if ((*it)->isVideoFrame ())
164
+ {
165
+ filterName = " buffer" ;
166
+ const VideoFrame* videoFrame = dynamic_cast <const VideoFrame*>(*it);
167
+ filterOptions << " video_size=" << videoFrame->getWidth () << " x" << videoFrame->getHeight () << " :" ;
168
+ filterOptions << " pix_fmt=" << getPixelFormatName (videoFrame->getPixelFormat ()) << " :" ;
169
+ filterOptions << " time_base=" << _codec.getAVCodecContext ().time_base .num << " /"
170
+ << _codec.getAVCodecContext ().time_base .den << " :" ;
171
+ filterOptions << " pixel_aspect=" << _codec.getAVCodecContext ().sample_aspect_ratio .num << " /"
172
+ << _codec.getAVCodecContext ().sample_aspect_ratio .den ;
173
+ }
174
+ // invalid frame
175
+ else
176
+ throw std::runtime_error (" Cannot create input buffer of filter graph: the given frame is invalid." );
177
+
178
+ // add in buffer
179
+ Filter* in = new Filter (filterName, filterOptions.str (), " in" );
180
+ LOG_INFO (" Add filter '" << filterName << " ' at the beginning of the graph." )
181
+ _filters.insert (_filters.begin (), in);
157
182
}
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
183
}
168
184
169
- void FilterGraph::pushOutBuffer (const Frame& frame )
185
+ void FilterGraph::addOutBuffer (const Frame& output )
170
186
{
171
187
std::string filterName;
172
188
173
- if (frame .isAudioFrame ())
189
+ if (output .isAudioFrame ())
174
190
filterName = " abuffersink" ;
175
- else if (frame .isVideoFrame ())
191
+ else if (output .isVideoFrame ())
176
192
filterName = " buffersink" ;
177
193
else
178
194
throw std::runtime_error (" Cannot create output buffer of filter graph: the given frame is invalid." );
179
195
180
196
// add out buffer
181
- Filter& out = addFilter (filterName, " " , " out" );
182
- pushFilter (out);
197
+ addFilter (filterName, " " , " out" );
183
198
}
184
199
}
0 commit comments