Skip to content

Commit 79f1bf4

Browse files
committed
ContainerM4A allow custom buffer for size table
1 parent c861c6d commit 79f1bf4

File tree

4 files changed

+88
-28
lines changed

4 files changed

+88
-28
lines changed

src/AudioTools/AudioCodecs/ContainerM4A.h

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ namespace audio_tools {
1616
*/
1717
class ContainerM4A : public ContainerDecoder {
1818
public:
19+
1920
/**
2021
* @brief Default constructor. Sets up the demuxer callback.
2122
*/
@@ -25,7 +26,8 @@ class ContainerM4A : public ContainerDecoder {
2526
};
2627

2728
/**
28-
* @brief Constructor with decoder. Sets up the demuxer and decoder notification.
29+
* @brief Constructor with decoder. Sets up the demuxer and decoder
30+
* notification.
2931
* @param decoder Reference to a MultiDecoder for PCM output.
3032
*/
3133
ContainerM4A(MultiDecoder& decoder) : ContainerM4A() {
@@ -86,12 +88,31 @@ class ContainerM4A : public ContainerDecoder {
8688
* @return true if active, false otherwise.
8789
*/
8890
operator bool() override { return is_active; }
91+
/**
92+
* @brief Sets the buffer to use for sample sizes.
93+
* You can use this to provide a custom buffer that
94+
* does not rely on RAM (e.g a file based buffer or
95+
* one using Redis)
96+
* @param buffer Reference to the buffer to use.
97+
*/
98+
virtual void setSampleSizesBuffer(BaseBuffer<stsz_sample_size_t>& buffer) {
99+
demux.setSampleSizesBuffer(buffer);
100+
}
101+
/**
102+
* @brief Sets the buffer to use for sample sizes. This is currently
103+
* not used!
104+
* @param buffer Reference to the buffer to use.
105+
*/
106+
virtual void setChunkOffsetsBuffer(BaseBuffer<uint32_t>& buffer) {
107+
demux.setChunkOffsetsBuffer(buffer);
108+
}
89109

90110
protected:
91-
bool is_active = false; ///< True if demuxer is active.
92-
bool is_magic_cookie_processed = false;///< True if ALAC magic cookie has been processed.
93-
MultiDecoder* p_decoder = nullptr; ///< Pointer to the MultiDecoder.
94-
M4AAudioDemuxer demux; ///< Internal demuxer instance.
111+
bool is_active = false; ///< True if demuxer is active.
112+
bool is_magic_cookie_processed =
113+
false; ///< True if ALAC magic cookie has been processed.
114+
MultiDecoder* p_decoder = nullptr; ///< Pointer to the MultiDecoder.
115+
M4AAudioDemuxer demux; ///< Internal demuxer instance.
95116

96117
/**
97118
* @brief Static callback for demuxed audio frames.
@@ -102,7 +123,8 @@ class ContainerM4A : public ContainerDecoder {
102123
static void decodeAudio(const M4AAudioDemuxer::Frame& frame, void* ref) {
103124
ContainerM4A* self = static_cast<ContainerM4A*>(ref);
104125
if (self->p_decoder == nullptr) {
105-
LOGE("No decoder defined, cannot decode audio frame: %s (%u bytes)", frame.mime, (unsigned) frame.size);
126+
LOGE("No decoder defined, cannot decode audio frame: %s (%u bytes)",
127+
frame.mime, (unsigned)frame.size);
106128
return;
107129
}
108130
MultiDecoder& dec = *(self->p_decoder);
@@ -120,8 +142,9 @@ class ContainerM4A : public ContainerDecoder {
120142
!self->is_magic_cookie_processed) {
121143
auto& magic_cookie = self->demux.getALACMagicCookie();
122144
if (magic_cookie.size() > 0) {
123-
if (!dec.setCodecConfig(magic_cookie.data(), magic_cookie.size())){
124-
LOGE("Failed to set ALAC magic cookie for decoder: %s", dec.selectedMime());
145+
if (!dec.setCodecConfig(magic_cookie.data(), magic_cookie.size())) {
146+
LOGE("Failed to set ALAC magic cookie for decoder: %s",
147+
dec.selectedMime());
125148
}
126149
}
127150
self->is_magic_cookie_processed = true;

src/AudioTools/AudioCodecs/M4ACommonDemuxer.h

Lines changed: 55 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,8 @@ class M4ACommonDemuxer {
113113
void begin() {
114114
sampleIndex = 0;
115115
buffer.clear();
116-
sampleSizes.clear();
116+
p_chunk_offsets->clear();
117+
p_sample_sizes->clear();
117118
buffer.resize(1024);
118119
current_size = 0;
119120
box_pos = 0;
@@ -169,7 +170,7 @@ class M4ACommonDemuxer {
169170
/// fill buffer up to the current sample size
170171
for (int j = 0; j < len; j++) {
171172
buffer.write(data[j]);
172-
if (buffer.available() == currentSize) {
173+
if (buffer.available() >= currentSize) {
173174
LOGI("Sample# %zu: size %zu bytes", sampleIndex, currentSize);
174175
executeCallback(currentSize);
175176
buffer.clear();
@@ -185,23 +186,34 @@ class M4ACommonDemuxer {
185186
LOGE("No sample size defined, cannot write data");
186187
return j;
187188
}
188-
resize(currentSize);
189189
}
190190
}
191191
return len;
192192
}
193193

194194
/**
195-
* @brief Returns the vector of sample sizes.
196-
* @return Reference to the vector of sample sizes.
195+
* @brief Returns the buffer of sample sizes.
196+
* @return Reference to the buffer of sample sizes.
197197
*/
198-
Vector<stsz_sample_size_t>& getSampleSizes() { return sampleSizes; }
198+
BaseBuffer<stsz_sample_size_t>& getSampleSizesBuffer() { return *p_sample_sizes; }
199199

200200
/**
201-
* @brief Returns the vector of chunk offsets.
202-
* @return Reference to the vector of chunk offsets.
201+
* @brief Sets the buffer to use for sample sizes.
202+
* @param buffer Reference to the buffer to use.
203203
*/
204-
Vector<uint32_t>& getChunkOffsets() { return chunkOffsets; }
204+
void setSampleSizesBuffer(BaseBuffer<stsz_sample_size_t> &buffer){ p_sample_sizes = &buffer;}
205+
206+
/**
207+
* @brief Returns the buffer of chunk offsets.
208+
* @return Reference to the buffer of chunk offsets.
209+
*/
210+
BaseBuffer<uint32_t>& getChunkOffsetsBuffer() { return *p_chunk_offsets; }
211+
212+
/**
213+
* @brief Sets the buffer to use for chunk offsets.
214+
* @param buffer Reference to the buffer to use.
215+
*/
216+
void setChunkOffsetsBuffer(BaseBuffer<uint32_t>&buffer){ p_chunk_offsets = &buffer;}
205217

206218
/**
207219
* @brief Sets a fixed sample size/count instead of using the sampleSizes
@@ -263,8 +275,10 @@ class M4ACommonDemuxer {
263275
}
264276

265277
protected:
266-
Vector<stsz_sample_size_t> sampleSizes; ///< Table of sample sizes.
267-
Vector<uint32_t> chunkOffsets; ///< Table of chunk offsets.
278+
SingleBuffer<stsz_sample_size_t> defaultSampleSizes; ///< Table of sample sizes.
279+
SingleBuffer<uint32_t> defaultChunkOffsets; ///< Table of chunk offsets.
280+
BaseBuffer<stsz_sample_size_t> *p_sample_sizes = &defaultSampleSizes;
281+
BaseBuffer<uint32_t> *p_chunk_offsets = &defaultChunkOffsets;
268282
Vector<uint8_t> tmp;
269283
Codec codec = Codec::Unknown; ///< Current codec.
270284
FrameCallback callback = nullptr; ///< Frame callback.
@@ -305,13 +319,24 @@ class M4ACommonDemuxer {
305319
* @return Size of the current sample.
306320
*/
307321
size_t currentSampleSize() {
322+
static size_t last_index = -1;
323+
static size_t last_size = -1;
324+
325+
// Return cached size
326+
if (sampleIndex == last_index) {
327+
return last_size;
328+
}
329+
308330
// using fixed sizes w/o table
309331
if (fixed_sample_size > 0 && fixed_sample_count > 0 &&
310332
sampleIndex < fixed_sample_count) {
311333
return fixed_sample_size;
312334
}
313-
if (sampleSizes && sampleIndex < sampleSizes.size()) {
314-
return sampleSizes[sampleIndex];
335+
stsz_sample_size_t nextSize = 0;
336+
if (p_sample_sizes->read(nextSize)) {
337+
last_index = sampleIndex;
338+
last_size = nextSize;
339+
return nextSize;
315340
}
316341
return 0;
317342
}
@@ -347,6 +372,16 @@ class M4ACommonDemuxer {
347372
* @param cb Frame callback function.
348373
*/
349374
virtual void setCallback(FrameCallback cb) { frame_callback = cb; }
375+
/**
376+
* @brief Sets the buffer to use for sample sizes.
377+
* @param buffer Reference to the buffer to use.
378+
*/
379+
void setSampleSizesBuffer(BaseBuffer<stsz_sample_size_t> &buffer){ sampleExtractor.setSampleSizesBuffer(buffer);}
380+
/**
381+
* @brief Sets the buffer to use for sample sizes.
382+
* @param buffer Reference to the buffer to use.
383+
*/
384+
void setChunkOffsetsBuffer(BaseBuffer<uint32_t> &buffer){ sampleExtractor.setChunkOffsetsBuffer(buffer);}
350385

351386
protected:
352387
FrameCallback frame_callback = nullptr;
@@ -507,14 +542,16 @@ class M4ACommonDemuxer {
507542
uint32_t sampleSize = readU32(data + 4);
508543
uint32_t sampleCount = readU32(data + 8);
509544
sampleExtractor.begin();
510-
Vector<stsz_sample_size_t>& sampleSizes = sampleExtractor.getSampleSizes();
545+
BaseBuffer<stsz_sample_size_t>& sampleSizes = sampleExtractor.getSampleSizesBuffer();
511546
if (sampleSize == 0) {
512547
LOGI("-> Sample Sizes Count: %u", sampleCount);
513548
sampleSizes.resize(sampleCount);
514549
for (uint32_t i = 0; i < sampleCount; ++i) {
515550
uint32_t sampleSizes32 = readU32(data + 12 + i * 4);
516-
sampleSizes[i] = static_cast<stsz_sample_size_t>(sampleSizes32);
517-
assert(static_cast<uint32_t>(sampleSizes[i]) == sampleSizes32);
551+
// if this is giving an error change the stsz_sample_size_t
552+
assert(sampleSizes32 <= UINT16_MAX);
553+
stsz_sample_size_t sampleSizes16 = sampleSizes32;
554+
assert(sampleSizes.write(sampleSizes16));
518555
}
519556
} else {
520557
sampleExtractor.setFixedSampleCount(sampleSize, sampleCount);
@@ -534,12 +571,12 @@ class M4ACommonDemuxer {
534571
size_t size = box.data_size;
535572
if (size < 4) return;
536573
uint32_t entryCount = readU32(data);
537-
Vector<uint32_t>& chunkOffsets = sampleExtractor.getChunkOffsets();
574+
BaseBuffer<uint32_t>& chunkOffsets = sampleExtractor.getChunkOffsetsBuffer();
538575
if (size < 4 + 4 * entryCount) return;
539576
chunkOffsets.resize(entryCount);
540577
LOGI("-> Chunk offsets count: %u", entryCount);
541578
for (uint32_t i = 0; i < entryCount; ++i) {
542-
chunkOffsets[i] = readU32(data + 4 + i * 4);
579+
chunkOffsets.write(readU32(data + 4 + i * 4));
543580
}
544581
stco_processed = true;
545582
}

src/AudioTools/CoreAudio/Buffers.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ class SingleBuffer : public BaseBuffer<T> {
174174
/**
175175
* @brief Construct a new Single Buffer object
176176
*
177-
* @param size
177+
* @param size in entries
178178
*/
179179
SingleBuffer(int size) {
180180
buffer.resize(size);

tests-cmake/codec/container-m4a/m4a.ino

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ void setup() {
3232
return;
3333
}
3434

35-
file = SD.open("/home/pschatzmann/Music/m4a/alac.m4a");
35+
file = SD.open("/home/pschatzmann/Music/m4a/aac.m4a");
3636
if (!file) {
3737
Serial.println("Failed to open file!");
3838
return;

0 commit comments

Comments
 (0)