Skip to content

Commit 2dcdc1c

Browse files
author
Valentin NOEL
committed
FilterGraph: fix audio frames management with different sample formats
Comparing the frame sizes in samples (instead of bytes)
1 parent d2a7f54 commit 2dcdc1c

File tree

2 files changed

+48
-12
lines changed

2 files changed

+48
-12
lines changed

src/AvTranscoder/filter/FilterGraph.cpp

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ AudioFrameBuffer::~AudioFrameBuffer()
3636
popFrame();
3737
}
3838

39+
size_t AudioFrameBuffer::getBytesPerSample()
40+
{
41+
return av_get_bytes_per_sample(_audioFrameDesc._sampleFormat);
42+
}
43+
3944
void AudioFrameBuffer::addFrame(IFrame* frame)
4045
{
4146
LOG_DEBUG("Add a new " << frame->getDataSize() << " bytes frame to frame buffer. New buffer size: " << _frameQueue.size() + 1);
@@ -113,6 +118,12 @@ IFrame* AudioFrameBuffer::getFrame(const size_t size)
113118
return newAudioFrame;
114119
}
115120

121+
IFrame* AudioFrameBuffer::getFrameSampleNb(const size_t sampleNb)
122+
{
123+
const size_t expectedSize = sampleNb * getBytesPerSample();
124+
return getFrame(expectedSize);
125+
}
126+
116127

117128

118129
/******************
@@ -149,19 +160,29 @@ size_t FilterGraph::getAvailableFrameSize(const std::vector<IFrame*>& inputs, co
149160
return frameSize;
150161
}
151162

152-
size_t FilterGraph::getMinInputFrameSize(const std::vector<IFrame*>& inputs)
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)
153174
{
154175
if(!inputs.size())
155176
return 0;
156177

157-
size_t minFrameSize = getAvailableFrameSize(inputs, 0);
178+
size_t minFrameSamplesNb = getAvailableFrameSamplesNb(inputs, 0);
158179
for(size_t index = 1; index < inputs.size(); ++index)
159180
{
160-
const size_t availableFrameSize = getAvailableFrameSize(inputs, index);
161-
if(minFrameSize > availableFrameSize)
162-
minFrameSize = availableFrameSize;
181+
const size_t availableFrameSampleNb = getAvailableFrameSamplesNb(inputs, index);
182+
if(minFrameSamplesNb > availableFrameSampleNb)
183+
minFrameSamplesNb = availableFrameSampleNb;
163184
}
164-
return minFrameSize;
185+
return minFrameSamplesNb;
165186
}
166187

167188
bool FilterGraph::hasBufferedFrames()
@@ -194,7 +215,16 @@ bool FilterGraph::areInputFrameSizesEqual(const std::vector<IFrame*>& inputs)
194215
for(size_t index = 1; index < inputs.size(); ++index)
195216
{
196217
if(frameSize != inputs.at(index)->getDataSize())
197-
return false;
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+
}
198228
}
199229
return true;
200230
}
@@ -220,7 +250,7 @@ void FilterGraph::process(const std::vector<IFrame*>& inputs, IFrame& output)
220250

221251
// Check whether we can bypass the input audio buffers
222252
const bool bypassBuffers = _inputAudioFrameBuffers.empty() || (areInputFrameSizesEqual(inputs) && areFrameBuffersEmpty());
223-
size_t minInputFrameSize = 0;
253+
size_t minInputFrameSamplesNb = 0;
224254

225255
if(!bypassBuffers)
226256
{
@@ -236,15 +266,15 @@ void FilterGraph::process(const std::vector<IFrame*>& inputs, IFrame& output)
236266
}
237267

238268
// Get the minimum input frames size
239-
minInputFrameSize = getMinInputFrameSize(inputs);
269+
minInputFrameSamplesNb = getMinInputFrameSamplesNb(inputs);
240270
}
241271

242272

243273
// Setup input frames into the filter graph
244274
for(size_t index = 0; index < inputs.size(); ++index)
245275
{
246276
// Retrieve frame from buffer or directly from input
247-
IFrame* inputFrame = (bypassBuffers)? inputs.at(index) : _inputAudioFrameBuffers.at(index).getFrame(minInputFrameSize);
277+
IFrame* inputFrame = (bypassBuffers)? inputs.at(index) : _inputAudioFrameBuffers.at(index).getFrameSampleNb(minInputFrameSamplesNb);
248278
const int ret = av_buffersrc_add_frame_flags(_filters.at(index)->getAVFilterContext(), &inputFrame->getAVFrame(), AV_BUFFERSRC_FLAG_PUSH);
249279

250280
if(ret < 0)

src/AvTranscoder/filter/FilterGraph.hpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ class AudioFrameBuffer
3939
* @brief Return the number of frames contained in the buffer.
4040
*/
4141
size_t getBufferSize() const { return _frameQueue.size(); }
42+
/**
43+
* @brief Return the number of bytes by sample from the internal AudioFrameDesc.
44+
*/
45+
size_t getBytesPerSample();
4246

4347
/**
4448
* @brief Push a frame at the end of the buffer.
@@ -50,6 +54,7 @@ class AudioFrameBuffer
5054
* If no size is specified, the whole first IFrame pointer is returned.
5155
*/
5256
IFrame* getFrame(const size_t size = 0);
57+
IFrame* getFrameSampleNb(const size_t sampleNb);
5358

5459
private:
5560
void popFrame();
@@ -138,10 +143,11 @@ class AvExport FilterGraph
138143
* @brief Return the input frame size if not null, or the available size into the corresponding frame buffer
139144
*/
140145
size_t getAvailableFrameSize(const std::vector<IFrame*>& inputs, const size_t& index);
146+
size_t getAvailableFrameSamplesNb(const std::vector<IFrame*>& inputs, const size_t& index);
141147
/**
142-
* @brief Get the minimum size between input frames, or available frame buffers
148+
* @brief Get the minimum samples number between input frames, or available frame buffers
143149
*/
144-
size_t getMinInputFrameSize(const std::vector<IFrame*>& inputs);
150+
size_t getMinInputFrameSamplesNb(const std::vector<IFrame*>& inputs);
145151

146152
bool areInputFrameSizesEqual(const std::vector<IFrame*>& inputs);
147153
bool areFrameBuffersEmpty();

0 commit comments

Comments
 (0)