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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy