Skip to content

Commit d33ffd2

Browse files
authored
Merge pull request #303 from valnoel/filter_inputMethod
Fix: different frame size as inputs of the filter graph
2 parents 93961f4 + 0e49751 commit d33ffd2

File tree

4 files changed

+448
-9
lines changed

4 files changed

+448
-9
lines changed

src/AvTranscoder/filter/FilterGraph.cpp

Lines changed: 242 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
#include "FilterGraph.hpp"
22

33
#include <AvTranscoder/util.hpp>
4-
#include <AvTranscoder/data/decoded/AudioFrame.hpp>
54
#include <AvTranscoder/data/decoded/VideoFrame.hpp>
65

76
extern "C" {
@@ -16,6 +15,123 @@ extern "C" {
1615
namespace avtranscoder
1716
{
1817

18+
19+
/******************
20+
21+
AudioFrameBuffer
22+
23+
******************/
24+
25+
AudioFrameBuffer::AudioFrameBuffer(const AudioFrameDesc& audioFrameDesc)
26+
: _audioFrameDesc(audioFrameDesc)
27+
, _frameQueue()
28+
, _totalDataSize(0)
29+
, _positionInFrontFrame(0)
30+
{
31+
}
32+
33+
AudioFrameBuffer::~AudioFrameBuffer()
34+
{
35+
for(size_t i = 0; i < _frameQueue.size(); ++i)
36+
popFrame();
37+
}
38+
39+
size_t AudioFrameBuffer::getBytesPerSample()
40+
{
41+
return av_get_bytes_per_sample(_audioFrameDesc._sampleFormat);
42+
}
43+
44+
void AudioFrameBuffer::addFrame(IFrame* frame)
45+
{
46+
LOG_DEBUG("Add a new " << frame->getDataSize() << " bytes frame to frame buffer. New buffer size: " << _frameQueue.size() + 1);
47+
// Copy the input frame to store it into the queue
48+
AudioFrame* newAudioFrame = new AudioFrame(_audioFrameDesc, false);
49+
const size_t expectedNbSamples = frame->getDataSize() / (newAudioFrame->getNbChannels() * newAudioFrame->getBytesPerSample());
50+
newAudioFrame->setNbSamplesPerChannel(expectedNbSamples);
51+
newAudioFrame->allocateData();
52+
newAudioFrame->copyData(*frame);
53+
54+
_totalDataSize += newAudioFrame->getDataSize();
55+
_frameQueue.push(newAudioFrame);
56+
}
57+
58+
void AudioFrameBuffer::popFrame()
59+
{
60+
_frameQueue.pop();
61+
LOG_DEBUG("Pop frame from buffer. Remaining frames in buffer: " << _frameQueue.size());
62+
}
63+
64+
IFrame* AudioFrameBuffer::getFrame(const size_t size)
65+
{
66+
LOG_DEBUG("Get a " << size << " bytes frame from a " << _totalDataSize << " bytes frame buffer");
67+
IFrame* next = _frameQueue.front();
68+
const size_t nextFrameSize = next->getDataSize();
69+
70+
// If no expected size, or if the expected size equals the front frame of the queue (with no offset)
71+
if(size == 0 || (size == nextFrameSize && _positionInFrontFrame == 0))
72+
{
73+
// Directly return the front frame of the queue
74+
_totalDataSize -= nextFrameSize;
75+
popFrame();
76+
return next;
77+
}
78+
79+
// Create a new frame
80+
AudioFrame* newAudioFrame = new AudioFrame(_audioFrameDesc, false);
81+
const size_t expectedNbSamples = size / (newAudioFrame->getNbChannels() * newAudioFrame->getBytesPerSample());
82+
newAudioFrame->setNbSamplesPerChannel(expectedNbSamples);
83+
newAudioFrame->allocateData();
84+
85+
// Concatenate frames data
86+
size_t extractedDataSize = 0;
87+
unsigned char* outputData = new unsigned char[size];
88+
while(extractedDataSize != size && _frameQueue.size() != 0)
89+
{
90+
// Get the front frame from queue
91+
next = _frameQueue.front();
92+
size_t remainingDataInFrontFrame = next->getDataSize() - _positionInFrontFrame;
93+
94+
// Compute the data size to get from the frame
95+
size_t dataToGet = size - extractedDataSize;
96+
if(dataToGet > remainingDataInFrontFrame)
97+
dataToGet = remainingDataInFrontFrame;
98+
99+
// Copy the data from the frame to temporal buffer
100+
for(size_t i = 0; i < dataToGet; i++)
101+
outputData[extractedDataSize++] = next->getData()[0][_positionInFrontFrame + i];
102+
103+
if(dataToGet < remainingDataInFrontFrame)
104+
{
105+
// Set new position into front frame
106+
_positionInFrontFrame += dataToGet;
107+
}
108+
else
109+
{
110+
// The whole front frame has been read, so pop it from queue
111+
popFrame();
112+
_positionInFrontFrame = 0;
113+
}
114+
}
115+
116+
_totalDataSize -= extractedDataSize;
117+
newAudioFrame->assignBuffer(outputData);
118+
return newAudioFrame;
119+
}
120+
121+
IFrame* AudioFrameBuffer::getFrameSampleNb(const size_t sampleNb)
122+
{
123+
const size_t expectedSize = sampleNb * getBytesPerSample();
124+
return getFrame(expectedSize);
125+
}
126+
127+
128+
129+
/******************
130+
131+
FilterGraph
132+
133+
******************/
134+
19135
FilterGraph::FilterGraph(const ICodec& codec)
20136
: _graph(avfilter_graph_alloc())
21137
, _filters()
@@ -28,31 +144,147 @@ FilterGraph::FilterGraph(const ICodec& codec)
28144

29145
FilterGraph::~FilterGraph()
30146
{
147+
_inputAudioFrameBuffers.clear();
31148
for(std::vector<Filter*>::iterator it = _filters.begin(); it < _filters.end(); ++it)
32149
{
33150
delete(*it);
34151
}
35152
avfilter_graph_free(&_graph);
36153
}
37154

155+
size_t FilterGraph::getAvailableFrameSize(const std::vector<IFrame*>& inputs, const size_t& index)
156+
{
157+
size_t frameSize = inputs.at(index)->getDataSize();
158+
if(frameSize == 0)
159+
frameSize = _inputAudioFrameBuffers.at(index).getDataSize();
160+
return frameSize;
161+
}
162+
163+
size_t FilterGraph::getAvailableFrameSamplesNb(const std::vector<IFrame*>& inputs, const size_t& index)
164+
{
165+
if(_inputAudioFrameBuffers.empty())
166+
throw std::runtime_error("Cannot compute filter graph input samples number for non-audio frames.");
167+
168+
const size_t bytesPerSample = _inputAudioFrameBuffers.at(index).getBytesPerSample();
169+
const size_t availableSamplesNb = getAvailableFrameSize(inputs, index) / bytesPerSample;
170+
return availableSamplesNb;
171+
}
172+
173+
size_t FilterGraph::getMinInputFrameSamplesNb(const std::vector<IFrame*>& inputs)
174+
{
175+
if(!inputs.size())
176+
return 0;
177+
178+
size_t minFrameSamplesNb = getAvailableFrameSamplesNb(inputs, 0);
179+
for(size_t index = 1; index < inputs.size(); ++index)
180+
{
181+
const size_t availableFrameSampleNb = getAvailableFrameSamplesNb(inputs, index);
182+
if(minFrameSamplesNb > availableFrameSampleNb)
183+
minFrameSamplesNb = availableFrameSampleNb;
184+
}
185+
return minFrameSamplesNb;
186+
}
187+
188+
bool FilterGraph::hasBufferedFrames()
189+
{
190+
if(!_inputAudioFrameBuffers.size())
191+
return false;
192+
193+
for(std::vector<AudioFrameBuffer>::iterator it = _inputAudioFrameBuffers.begin(); it != _inputAudioFrameBuffers.end(); ++it)
194+
{
195+
if(it->isEmpty())
196+
return false;
197+
}
198+
return true;
199+
}
200+
201+
bool FilterGraph::hasBufferedFrames(const size_t index)
202+
{
203+
if(index >= _inputAudioFrameBuffers.size())
204+
return false;
205+
206+
return !_inputAudioFrameBuffers.at(index).isEmpty();
207+
}
208+
209+
bool FilterGraph::areInputFrameSizesEqual(const std::vector<IFrame*>& inputs)
210+
{
211+
if(!inputs.size() || inputs.size() == 1)
212+
return true;
213+
214+
const int frameSize = inputs.at(0)->getDataSize();
215+
for(size_t index = 1; index < inputs.size(); ++index)
216+
{
217+
if(frameSize != inputs.at(index)->getDataSize())
218+
{
219+
if(_inputAudioFrameBuffers.empty())
220+
return false;
221+
else
222+
{
223+
const size_t refSampleNb = frameSize / _inputAudioFrameBuffers.at(0).getBytesPerSample();
224+
const size_t sampleNb = inputs.at(index)->getDataSize() / _inputAudioFrameBuffers.at(index).getBytesPerSample();
225+
return (refSampleNb == sampleNb);
226+
}
227+
}
228+
}
229+
return true;
230+
}
231+
232+
bool FilterGraph::areFrameBuffersEmpty()
233+
{
234+
if(!_inputAudioFrameBuffers.size())
235+
return true;
236+
237+
for(std::vector<AudioFrameBuffer>::iterator it = _inputAudioFrameBuffers.begin(); it != _inputAudioFrameBuffers.end(); ++it)
238+
{
239+
if(!it->isEmpty())
240+
return false;
241+
}
242+
return true;
243+
}
244+
38245
void FilterGraph::process(const std::vector<IFrame*>& inputs, IFrame& output)
39246
{
40-
// init filter graph
247+
// Init the filter graph
41248
if(!_isInit)
42249
init(inputs, output);
43250

44-
// setup input frames
251+
// Check whether we can bypass the input audio buffers
252+
const bool bypassBuffers = _inputAudioFrameBuffers.empty() || (areInputFrameSizesEqual(inputs) && areFrameBuffersEmpty());
253+
size_t minInputFrameSamplesNb = 0;
254+
255+
if(!bypassBuffers)
256+
{
257+
// Fill the frame buffer with inputs
258+
for(size_t index = 0; index < inputs.size(); ++index)
259+
{
260+
if(!inputs.at(index)->getDataSize())
261+
{
262+
LOG_DEBUG("Empty frame from filter graph input " << index << ". Remaining audio frames in buffer: " << _inputAudioFrameBuffers.at(index).getBufferSize());
263+
continue;
264+
}
265+
_inputAudioFrameBuffers.at(index).addFrame(inputs.at(index));
266+
}
267+
268+
// Get the minimum input frames size
269+
minInputFrameSamplesNb = getMinInputFrameSamplesNb(inputs);
270+
}
271+
272+
273+
// Setup input frames into the filter graph
45274
for(size_t index = 0; index < inputs.size(); ++index)
46275
{
47-
const int ret = av_buffersrc_write_frame(_filters.at(index)->getAVFilterContext(), &inputs.at(index)->getAVFrame());
276+
// Retrieve frame from buffer or directly from input
277+
IFrame* inputFrame = (bypassBuffers)? inputs.at(index) : _inputAudioFrameBuffers.at(index).getFrameSampleNb(minInputFrameSamplesNb);
278+
const int ret = av_buffersrc_add_frame_flags(_filters.at(index)->getAVFilterContext(), &inputFrame->getAVFrame(), AV_BUFFERSRC_FLAG_PUSH);
279+
48280
if(ret < 0)
49281
{
50282
throw std::runtime_error("Error when adding a frame to the source buffer used to start to process filters: " +
51283
getDescriptionFromErrorCode(ret));
52284
}
53285
}
54286

55-
// pull filtered data from the filter graph
287+
// Pull filtered data from the filter graph
56288
for(;;)
57289
{
58290
const int ret = av_buffersink_get_frame(_filters.at(_filters.size() - 1)->getAVFilterContext(), &output.getAVFrame());
@@ -150,6 +382,11 @@ void FilterGraph::addInBuffer(const std::vector<IFrame*>& inputs)
150382
filterOptions << "sample_rate=" << audioFrame->getSampleRate() << ":";
151383
filterOptions << "sample_fmt=" << getSampleFormatName(audioFrame->getSampleFormat()) << ":";
152384
filterOptions << "channel_layout=0x" << std::hex << audioFrame->getChannelLayout();
385+
386+
const AudioFrameDesc audioFrameDesc(audioFrame->getSampleRate(),
387+
audioFrame->getNbChannels(),
388+
getSampleFormatName(audioFrame->getSampleFormat()));
389+
_inputAudioFrameBuffers.insert(_inputAudioFrameBuffers.begin(), AudioFrameBuffer(audioFrameDesc));
153390
}
154391
// video frame
155392
else if((*it)->isVideoFrame())

0 commit comments

Comments
 (0)