arduino-audio-tools
Loading...
Searching...
No Matches
SampleTableStore.h
Go to the documentation of this file.
1#pragma once
2#include <type_traits>
3#include <utility>
4
7
8namespace audio_tools {
9
14namespace quickstart_detail {
15template <typename T>
17 template <typename U>
18 static auto test(int)
19 -> decltype(std::declval<U&>().quickStart(), std::true_type());
20 template <typename U>
21 static std::false_type test(...);
22
23 public:
24 static const bool value = decltype(test<T>(0))::value;
25};
26
27template <typename T>
28typename std::enable_if<HasQuickStart<T>::value, bool>::type
30 return writer.quickStart();
31}
32
33template <typename T>
34typename std::enable_if<!HasQuickStart<T>::value, bool>::type
36 return false;
37}
38} // namespace quickstart_detail
39
46enum class TrackKind { Unknown, Audio, Video };
47
60template <typename T>
62 public:
63 virtual ~SampleTableStore() = default;
65 virtual void clear() = 0;
67 virtual void append(T value) = 0;
69 virtual size_t size() = 0;
71 virtual T get(size_t index) = 0;
77 virtual void setNextEntryOffset(uint64_t fileOffset) {}
81 virtual void setOnDiskEntrySize(size_t bytes) {}
82};
83
91template <typename T>
93 public:
94 void clear() override { data.clear(); }
95 void append(T value) override { data.push_back(value); }
96 size_t size() override { return (size_t)data.size(); }
97 T get(size_t index) override { return data[(int)index]; }
98
99 protected:
101};
102
130template <typename T, size_t ChunkSize = 4096>
132 public:
134
135 void clear() override {
136 for (size_t i = 0; i < chunks.size(); i++) delete[] chunks[i];
137 chunks.clear();
138 count = 0;
139 }
140
141 void append(T value) override {
142 size_t chunk_idx = count / ChunkSize;
143 size_t local_pos = count % ChunkSize;
144 if (chunk_idx >= (size_t)chunks.size()) chunks.push_back(new T[ChunkSize]);
145 chunks[(int)chunk_idx][local_pos] = value;
146 count++;
147 }
148
149 size_t size() override { return count; }
150
151 T get(size_t index) override {
152 return chunks[(int)(index / ChunkSize)][index % ChunkSize];
153 }
154
155 protected:
156 Vector<T*> chunks; // small - one pointer per ChunkSize entries, not one per entry
157 size_t count = 0;
158};
159
169 public:
170 virtual ~SeekableSource() = default;
171 virtual bool seek(size_t pos) = 0;
172 virtual size_t readBytes(uint8_t* data, size_t len) = 0;
173};
174
209template <typename FileT, typename WriterT>
211 public:
217 FileSeekableSource(FileT& file, WriterT& writer, int bufferSize = 1024,
218 bool quickStart = true)
219 : p_file(&file),
220 p_writer(&writer),
221 buffer_len(bufferSize),
222 quick_start_enabled(quickStart) {
223 writer.setSeekSource(*this);
224 }
225
226 bool seek(size_t pos) override {
227 saved_pos = p_file->position();
228 bool ok = p_file->seek(pos);
229 if (debug_trace)
230 LOGI("FileSeekableSource: seek(%u) saved_pos=%u post-seek position()=%u ok=%d",
231 (unsigned)pos, (unsigned)saved_pos, (unsigned)p_file->position(), (int)ok);
232 return ok;
233 }
234
235 size_t readBytes(uint8_t* data, size_t len) override {
236 // File::readBytes() on some platforms (incl. this project's desktop
237 // emulator) takes char*, not uint8_t* - readBytes(uint8_t*,size_t) is
238 // the more common Arduino Stream signature, but not universal.
239 size_t pre_pos = p_file->position();
240 size_t n = p_file->readBytes((char*)data, len);
241 if (debug_trace)
242 LOGI("FileSeekableSource: readBytes len=%u pre_pos=%u got=%u restoring to saved_pos=%u",
243 (unsigned)len, (unsigned)pre_pos, (unsigned)n, (unsigned)saved_pos);
244 p_file->seek(saved_pos); // restore the sequential-read position
245 return n;
246 }
247
252 bool debug_trace = false;
253
264 size_t copy() {
266 quick_start_done = true;
268 }
269 uint8_t buffer[buffer_len];
270 size_t to_read = p_file->readBytes((char*)buffer, buffer_len);
271 if (to_read == 0) return 0;
272 size_t written = 0;
273 int attempts = 0;
274 while (written < to_read) {
275 size_t w = p_writer->write(buffer + written, to_read - written);
276 attempts++;
277 if (w == 0) {
278 LOGW("FileSeekableSource::copy(): writer stalled after accepting %u of %u "
279 "bytes (%d attempt(s)) - dropping the remaining %u bytes",
280 (unsigned)written, (unsigned)to_read, attempts, (unsigned)(to_read - written));
281 break;
282 }
283 written += w;
284 }
285 if (debug_trace && attempts > 1)
286 LOGI("FileSeekableSource::copy() needed %d attempts for to_read=%u", attempts, (unsigned)to_read);
287 return written;
288 }
289
290 protected:
291 FileT* p_file;
292 WriterT* p_writer;
294 size_t saved_pos = 0;
296 bool quick_start_done = false;
297};
298
338template <typename T>
340 public:
344 static constexpr size_t kMaxOnDiskSize = 16;
345
352 SourceSeekSampleTableStore(SeekableSource& source, size_t onDiskSize,
353 T (*decoder)(const uint8_t*),
354 size_t cacheEntries = 64)
355 : p_source(&source),
356 on_disk_size(onDiskSize),
357 decode(decoder),
358 cache_capacity(cacheEntries),
359 cache(new T[cacheEntries]),
360 raw_buf(new uint8_t[cacheEntries * kMaxOnDiskSize]) {}
361
363 delete[] cache;
364 delete[] raw_buf;
365 }
366
367 void clear() override {
368 count = 0;
369 start_offset = -1;
370 cache_len = 0;
371 }
372
373 void setNextEntryOffset(uint64_t fileOffset) override {
374 if (start_offset < 0) start_offset = (int64_t)fileOffset;
375 }
376
381 void setOnDiskEntrySize(size_t bytes) override {
382 on_disk_size = bytes;
383 cache_len = 0; // invalidate: any cached block used the old width
384 }
385
386 void append(T) override {
387 // value itself is intentionally discarded - only its position matters
388 count++;
389 }
390
391 size_t size() override { return count; }
392
393 T get(size_t index) override {
394 if (start_offset < 0 || p_source == nullptr) return T{};
395 if (index < cache_start || index >= cache_start + cache_len)
396 refillCache(index);
397 if (index >= cache_start && index < cache_start + cache_len)
398 return cache[index - cache_start];
399 return T{};
400 }
401
402 protected:
403 void refillCache(size_t index) {
404 p_source->seek((size_t)(start_offset + (int64_t)(index * on_disk_size)));
406 size_t got_entries = got / on_disk_size;
407 for (size_t i = 0; i < got_entries; i++)
408 cache[i] = decode(raw_buf + i * on_disk_size);
409 cache_start = index;
410 cache_len = got_entries;
411 }
412
415 T (*decode)(const uint8_t*);
416 int64_t start_offset = -1;
417 size_t count = 0;
418
421 uint8_t* raw_buf;
422 size_t cache_start = 0;
423 size_t cache_len = 0;
424};
425
435 public:
436 virtual size_t write(const uint8_t* data, size_t len) = 0;
437};
438
445template <typename FileT>
447 public:
448 FileSpoolStorage(FileT& file) : p_file(&file) {}
449 bool seek(size_t pos) override { return p_file->seek(pos); }
450 size_t readBytes(uint8_t* data, size_t len) override {
451 // see the identical comment in FileSeekableSource::readBytes()
452 return p_file->readBytes((char*)data, len);
453 }
454 size_t write(const uint8_t* data, size_t len) override {
455 return p_file->write(data, len);
456 }
457
458 protected:
459 FileT* p_file;
460};
461
484template <typename T>
486 public:
490
491 void clear() override {
492 entry_count = 0;
493 if (p_spool != nullptr) p_spool->seek(0);
494 }
495
496 void append(T value) override {
497 if (p_spool == nullptr) return;
498 p_spool->seek(entry_count * sizeof(T));
499 p_spool->write((const uint8_t*)&value, sizeof(T));
500 entry_count++;
501 }
502
503 size_t size() override { return entry_count; }
504
505 T get(size_t index) override {
506 T value{};
507 if (p_spool == nullptr) return value;
508 p_spool->seek(index * sizeof(T));
509 p_spool->readBytes((uint8_t*)&value, sizeof(T));
510 return value;
511 }
512
513 protected:
515 size_t entry_count = 0;
516};
517
524
538 public:
539 virtual ~SpoolStorageFactory() = default;
545 SampleTableKind tableKind) = 0;
546};
547
548} // namespace audio_tools
#define LOGW(...)
Definition AudioLoggerIDF.h:29
#define LOGI(...)
Definition AudioLoggerIDF.h:28
RAM-backed like RamSampleTableStore, but grows by allocating additional fixed-size chunks instead of ...
Definition SampleTableStore.h:131
size_t size() override
Number of entries appended so far.
Definition SampleTableStore.h:149
void append(T value) override
Appends one entry - call in file order, once per table entry.
Definition SampleTableStore.h:141
T get(size_t index) override
Reads back entry 'index' - index must be < size().
Definition SampleTableStore.h:151
~ChunkedSampleTableStore()
Definition SampleTableStore.h:133
size_t count
Definition SampleTableStore.h:157
Vector< T * > chunks
Definition SampleTableStore.h:156
void clear() override
Resets to empty - call once per begin()/track.
Definition SampleTableStore.h:135
Adapts a single concrete file/stream (Arduino's File, or anything else exposing position(),...
Definition SampleTableStore.h:210
bool seek(size_t pos) override
Definition SampleTableStore.h:226
size_t readBytes(uint8_t *data, size_t len) override
Definition SampleTableStore.h:235
FileT * p_file
Definition SampleTableStore.h:291
FileSeekableSource(FileT &file, WriterT &writer, int bufferSize=1024, bool quickStart=true)
Definition SampleTableStore.h:217
int buffer_len
Definition SampleTableStore.h:293
bool quick_start_enabled
Definition SampleTableStore.h:295
bool quick_start_done
Definition SampleTableStore.h:296
size_t saved_pos
Definition SampleTableStore.h:294
size_t copy()
Definition SampleTableStore.h:264
WriterT * p_writer
Definition SampleTableStore.h:292
bool debug_trace
Definition SampleTableStore.h:252
Adapts any concrete file/stream type to SpoolStorage - same role as FileSeekableSource,...
Definition SampleTableStore.h:446
bool seek(size_t pos) override
Definition SampleTableStore.h:449
FileSpoolStorage(FileT &file)
Definition SampleTableStore.h:448
size_t readBytes(uint8_t *data, size_t len) override
Definition SampleTableStore.h:450
FileT * p_file
Definition SampleTableStore.h:459
size_t write(const uint8_t *data, size_t len) override
Definition SampleTableStore.h:454
Keeps every entry in RAM (a plain Vector<T>) - the simplest and fastest option, but scales with the t...
Definition SampleTableStore.h:92
size_t size() override
Number of entries appended so far.
Definition SampleTableStore.h:96
void append(T value) override
Appends one entry - call in file order, once per table entry.
Definition SampleTableStore.h:95
T get(size_t index) override
Reads back entry 'index' - index must be < size().
Definition SampleTableStore.h:97
Vector< T > data
Definition SampleTableStore.h:100
void clear() override
Resets to empty - call once per begin()/track.
Definition SampleTableStore.h:94
Sequential-access storage for one MP4 sample table (e.g. stsz sample sizes, stco chunk offsets,...
Definition SampleTableStore.h:61
virtual size_t size()=0
Number of entries appended so far.
virtual void clear()=0
Resets to empty - call once per begin()/track.
virtual void append(T value)=0
Appends one entry - call in file order, once per table entry.
virtual void setNextEntryOffset(uint64_t fileOffset)
Definition SampleTableStore.h:77
virtual T get(size_t index)=0
Reads back entry 'index' - index must be < size().
virtual ~SampleTableStore()=default
virtual void setOnDiskEntrySize(size_t bytes)
Definition SampleTableStore.h:81
Minimal seek+read interface a SourceSeekSampleTableStore needs from "the original MP4 source" - kept ...
Definition SampleTableStore.h:168
virtual bool seek(size_t pos)=0
virtual ~SeekableSource()=default
virtual size_t readBytes(uint8_t *data, size_t len)=0
Discards every value right after appending it, keeping only the file offset of the first entry - get(...
Definition SampleTableStore.h:339
~SourceSeekSampleTableStore()
Definition SampleTableStore.h:362
size_t size() override
Number of entries appended so far.
Definition SampleTableStore.h:391
size_t cache_capacity
Definition SampleTableStore.h:419
T get(size_t index) override
Reads back entry 'index' - index must be < size().
Definition SampleTableStore.h:393
void setNextEntryOffset(uint64_t fileOffset) override
Definition SampleTableStore.h:373
size_t cache_len
Definition SampleTableStore.h:423
size_t count
Definition SampleTableStore.h:417
SeekableSource * p_source
Definition SampleTableStore.h:413
SourceSeekSampleTableStore(SeekableSource &source, size_t onDiskSize, T(*decoder)(const uint8_t *), size_t cacheEntries=64)
Definition SampleTableStore.h:352
T(* decode)(const uint8_t *)
Definition SampleTableStore.h:415
size_t cache_start
Definition SampleTableStore.h:422
uint8_t * raw_buf
Definition SampleTableStore.h:421
size_t on_disk_size
Definition SampleTableStore.h:414
void refillCache(size_t index)
Definition SampleTableStore.h:403
T * cache
Definition SampleTableStore.h:420
static constexpr size_t kMaxOnDiskSize
Definition SampleTableStore.h:344
void clear() override
Resets to empty - call once per begin()/track.
Definition SampleTableStore.h:367
int64_t start_offset
Definition SampleTableStore.h:416
void setOnDiskEntrySize(size_t bytes) override
Definition SampleTableStore.h:381
void append(T) override
Appends one entry - call in file order, once per table entry.
Definition SampleTableStore.h:386
Writes every entry to a caller-provided scratch file as it's appended, instead of keeping it in RAM -...
Definition SampleTableStore.h:485
size_t size() override
Number of entries appended so far.
Definition SampleTableStore.h:503
void append(T value) override
Appends one entry - call in file order, once per table entry.
Definition SampleTableStore.h:496
SpoolStorage * p_spool
Definition SampleTableStore.h:514
T get(size_t index) override
Reads back entry 'index' - index must be < size().
Definition SampleTableStore.h:505
size_t entry_count
Definition SampleTableStore.h:515
SpoolFileSampleTableStore(SpoolStorage &spool)
Definition SampleTableStore.h:489
void clear() override
Resets to empty - call once per begin()/track.
Definition SampleTableStore.h:491
Factory DemuxerMP4 calls once per table, per track, to obtain a SpoolStorage for spool-backed sample ...
Definition SampleTableStore.h:537
virtual SpoolStorage * createSpoolStorage(TrackKind trackKind, SampleTableKind tableKind)=0
virtual ~SpoolStorageFactory()=default
Minimal seek+read+write interface a SpoolFileSampleTableStore needs from its scratch file - SeekableS...
Definition SampleTableStore.h:434
virtual size_t write(const uint8_t *data, size_t len)=0
Vector implementation which provides the most important methods as defined by std::vector....
Definition Vector.h:21
void push_back(T &&value)
Definition Vector.h:182
void clear()
Definition Vector.h:176
int size()
Definition Vector.h:178
Definition SampleTableStore.h:16
static const bool value
Definition SampleTableStore.h:24
SampleTableKind
Identifies which of a track's four sample tables a SpoolStorageFactory is being asked to provide stor...
Definition SampleTableStore.h:523
TrackKind
Video vs. audio track classification - lives here (rather than nested inside DemuxerMP4::Track,...
Definition SampleTableStore.h:46
@ Audio
Definition Video.h:19
@ Video
Definition Video.h:19
std::enable_if< HasQuickStart< T >::value, bool >::type callQuickStartIfAvailable(T &writer)
Definition SampleTableStore.h:29
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition LMSEchoCancellationStream.h:6