Skip to content

Commit 656245f

Browse files
committed
MimeDetector: new setCheck method
1 parent aba3b13 commit 656245f

File tree

4 files changed

+127
-95
lines changed

4 files changed

+127
-95
lines changed

src/AudioTools/AudioCodecs/MultiDecoder.h

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
#include "AudioTools/AudioCodecs/AudioCodecsBase.h"
55
#include "AudioTools/CoreAudio/AudioBasic/StrView.h"
6-
#include "AudioTools/CoreAudio/MimeDetector.h"
6+
#include "AudioTools/CoreAudio/AudioMetaData/MimeDetector.h"
77

88
namespace audio_tools {
99

@@ -43,6 +43,13 @@ class MultiDecoder : public AudioDecoder {
4343
decoder.addNotifyAudioChange(*this);
4444
decoders.push_back(info);
4545
}
46+
47+
/// Adds a decoder that will be selected by it's mime type and defines the mime checking logic
48+
void addDecoder(AudioDecoder& decoder, const char* mime, bool(*check)(uint8_t*data, size_t len)) {
49+
addDecoder(decoder, mime);
50+
mime_detector.setCheck(mime, check);
51+
}
52+
4653

4754
virtual void setOutput(Print &out_stream) override {
4855
p_print = &out_stream;
@@ -99,11 +106,6 @@ class MultiDecoder : public AudioDecoder {
99106
// decode the data
100107
return actual_decoder.decoder->write(data, len);
101108
}
102-
/// Define your own custom mime detector
103-
void setMimeDetector(const char* (*mimeDetectCallback)(uint8_t* data,
104-
size_t len)) {
105-
mime_detector.setMimeDetector(mimeDetectCallback);
106-
}
107109

108110
virtual operator bool() {
109111
if (actual_decoder.decoder == &nop) return false;
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
#pragma once
2+
3+
#include "AudioTools/CoreAudio/AudioBasic/StrView.h"
4+
5+
namespace audio_tools {
6+
7+
/**
8+
* @brief Logic to detemine the mime type from the content.
9+
* By default the following mime types are supported (audio/aac, audio/mpeg,
10+
* audio/vnd.wave, audio/ogg). You can register your own custom detection logic
11+
* to cover additional file types.
12+
* @ingroup codecs
13+
* @ingroup decoder
14+
* @author Phil Schatzmann
15+
* @copyright GPLv3
16+
*/
17+
18+
class MimeDetector {
19+
public:
20+
MimeDetector() {
21+
setCheck("audio/aac", checkAAC);
22+
setCheck("audio/mpeg", checkMP3);
23+
setCheck("audio/vnd.wave", checkWAV);
24+
setCheck("audio/ogg", checkOGG);
25+
}
26+
27+
bool begin() {
28+
is_first = true;
29+
return true;
30+
}
31+
32+
/// write the header to determine the mime
33+
size_t write(uint8_t* data, size_t len) {
34+
determineMime(data, len);
35+
return len;
36+
}
37+
38+
/// adds/updates the checking logic for the indicated mime
39+
void setCheck(const char* mime, bool (*check)(uint8_t* start, size_t len)) {
40+
StrView mime_str{mime};
41+
for (int j = 0; j < checks.size(); j++) {
42+
Check l_check = checks[j];
43+
if (mime_str.equals(l_check.mime)) {
44+
l_check.check = check;
45+
return;
46+
}
47+
}
48+
Check check_to_add{mime, check};
49+
checks.push_back(check_to_add);
50+
}
51+
52+
// /// Define the callback that will notify about mime changes
53+
void setMimeCallback(void (*callback)(const char*)) {
54+
TRACED();
55+
this->notifyMimeCallback = callback;
56+
}
57+
58+
/// Provides the actual mime type, that was determined from the first
59+
/// available data
60+
const char* mime() { return actual_mime; }
61+
62+
static bool checkAAC(uint8_t* start, size_t len) {
63+
return start[0] == 0xFF &&
64+
(start[1] == 0xF0 || start[1] == 0xF1 || start[1] == 0xF9);
65+
}
66+
67+
static bool checkMP3(uint8_t* start, size_t len) {
68+
return memcmp(start, "ID3", 3) == 0 ||
69+
(start[0] == 0xFF && ((start[1] & 0xE0) == 0xE0));
70+
}
71+
72+
static bool checkWAV(uint8_t* start, size_t len) {
73+
return memcmp(start, "OggS", 4) == 0;
74+
}
75+
76+
static bool checkOGG(uint8_t* start, size_t len) {
77+
return memcmp(start, "OggS", 4) == 0;
78+
}
79+
80+
protected:
81+
struct Check {
82+
const char* mime = nullptr;
83+
bool (*check)(uint8_t* data, size_t len) = nullptr;
84+
Check(const char* mime, bool (*check)(uint8_t* data, size_t len)) {
85+
this->mime = mime;
86+
this->check = check;
87+
}
88+
Check() = default;
89+
};
90+
Vector<Check> checks{0};
91+
bool is_first = false;
92+
const char* actual_mime = nullptr;
93+
void (*notifyMimeCallback)(const char* mime) = nullptr;
94+
95+
/// Update the mime type
96+
void determineMime(void* data, size_t len) {
97+
if (is_first) {
98+
actual_mime = lookupMime((uint8_t*)data, len);
99+
if (notifyMimeCallback != nullptr && actual_mime != nullptr) {
100+
notifyMimeCallback(actual_mime);
101+
}
102+
is_first = false;
103+
}
104+
}
105+
106+
/// Default logic which supports aac, mp3, wav and ogg
107+
const char* lookupMime(uint8_t* data, size_t len) {
108+
for (int j = 0; j < checks.size(); j++) {
109+
Check l_check = checks[j];
110+
if (l_check.check(data, len)) {
111+
return l_check.mime;
112+
}
113+
}
114+
return nullptr;
115+
}
116+
};
117+
118+
} // namespace audio_tools

src/AudioTools/CoreAudio/MimeDetector.h

Lines changed: 0 additions & 84 deletions
This file was deleted.

src/AudioTools/CoreAudio/StreamCopy.h

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
#include "AudioTools/CoreAudio/BaseConverter.h"
77
#include "AudioTools/CoreAudio/AudioLogger.h"
88
#include "AudioTools/CoreAudio/AudioStreams.h"
9-
#include "AudioTools/CoreAudio/MimeDetector.h"
9+
#include "AudioTools/CoreAudio/AudioMetaData/MimeDetector.h"
1010

1111
#define NOT_ENOUGH_MEMORY_MSG "Could not allocate enough memory: %d bytes"
1212

@@ -352,10 +352,6 @@ class StreamCopyT {
352352
mime_detector.setMimeCallback(callback);
353353
}
354354

355-
/// Defines the mime detector
356-
void setMimeDetector(const char* (*mimeDetectCallback)(uint8_t* data, size_t len)){
357-
mime_detector.setMimeDetector(mimeDetectCallback);
358-
}
359355

360356
protected:
361357
Stream *from = nullptr;

0 commit comments

Comments
 (0)