3#include "AudioTools/AudioCodecs/HeaderParserAAC.h"
4#include "AudioTools/AudioCodecs/HeaderParserMP3.h"
5#include "AudioTools/CoreAudio/AudioBasic/StrView.h"
43 virtual const char*
mime() = 0;
65 setCheck(
"audio/vnd.wave", checkWAV);
67 setCheck(
"audio/ogg; codecs=flac", checkOggFLAC);
73 setCheck(
"audio/m4a", checkM4A,
false);
87 actual_mime =
nullptr;
93 size_t write(uint8_t* data,
size_t len) {
94 actual_mime = default_mime;
100 void setCheck(
const char*
mime,
bool (*check)(uint8_t* start,
size_t len),
bool isActvie =
true) {
102 for (
int j = 0; j < checks.size(); j++) {
103 Check l_check = checks[j];
104 if (mime_str.equals(l_check.mime)) {
105 l_check.check = check;
106 l_check.is_active = isActvie;
111 check_to_add.is_active = isActvie;
112 checks.push_back(check_to_add);
113 LOGI(
"MimeDetector for %s: %s",
mime, isActvie ?
"active" :
"inactive");
117 void setMimeCallback(
void (*callback)(
const char*)) {
119 this->notifyMimeCallback = callback;
124 const char*
mime() {
return actual_mime; }
126 static bool checkAAC(uint8_t* start,
size_t len) {
127 return start[0] == 0xFF &&
128 (start[1] == 0xF0 || start[1] == 0xF1 || start[1] == 0xF9);
131 static bool checkAACExt(uint8_t* start,
size_t len) {
133 if (memcmp(start + 4,
"ftypM4A", 7) == 0) {
139 int pos = aac.findSyncWord((
const uint8_t*)start, len);
144 if (aac.isValid(start + pos, len - pos)) {
150 static bool checkMP3(uint8_t* start,
size_t len) {
151 return memcmp(start,
"ID3", 3) == 0 ||
152 (start[0] == 0xFF && ((start[1] & 0xE0) == 0xE0));
155 static bool checkMP3Ext(uint8_t* start,
size_t len) {
157 return mp3.isValid(start, len);
160 static bool checkWAV(uint8_t* start,
size_t len) {
161 return memcmp(start,
"RIFF", 4) == 0;
164 static bool checkOGG(uint8_t* start,
size_t len) {
165 return memcmp(start,
"OggS", 4) == 0;
168 static bool checkFLAC(uint8_t* start,
size_t len) {
169 if (len < 4)
return false;
172 if (memcmp(start,
"fLaC", 4) == 0) {
178 static bool checkOggFLAC(uint8_t* start,
size_t len) {
181 if (len >= 32 && memcmp(start,
"OggS", 4) == 0) {
184 for (
size_t i = 4; i < len - 4 && i < 64; i++) {
185 if (memcmp(start + i,
"FLAC", 4) == 0) {
189 if (i < len - 5 && start[i] == 0x7F &&
190 memcmp(start + i + 1,
"FLAC", 4) == 0) {
213 if (len >= 32 && memcmp(start,
"OggS", 4) == 0) {
216 for (
size_t i = 4; i < len - 8 && i < 80; i++) {
217 if (memcmp(start + i,
"OpusHead", 8) == 0) {
240 if (len >= 32 && memcmp(start,
"OggS", 4) == 0) {
243 for (
size_t i = 4; i < len - 7 && i < 80; i++) {
244 if (start[i] == 0x01 && memcmp(start + i + 1,
"vorbis", 6) == 0) {
255 if (len < 189)
return start[0] == 0x47;
257 return start[0] == 0x47 && start[188] == 0x47;
262 return memcmp(start,
"PSID", 4) == 0 || memcmp(start,
"RSID", 4) == 0;
265 static bool checkM4A(uint8_t* header,
size_t len) {
266 if (len < 12)
return false;
269 if (memcmp(header,
"ID3", 3) == 0)
return false;
272 if (memcmp(header + 4,
"mdat", 4) != 0)
return true;
275 if (memcmp(header + 4,
"ftyp", 4) != 0)
return false;
278 if (memcmp(header + 8,
"M4A ", 4) == 0 ||
279 memcmp(header + 8,
"mp42", 4) == 0 ||
280 memcmp(header + 8,
"isom", 4) == 0)
292 for (
auto& check : checks) {
294 check.is_active = active;
295 LOGI(
"MimeDetector for %s: %s", check.mime, check.is_active ?
"active" :
"inactive");
305 actual_mime =
nullptr;
311 const char* mime =
nullptr;
312 bool (*check)(uint8_t* data,
size_t len) =
nullptr;
313 bool is_active =
true;
314 Check(
const char* mime,
bool (*check)(uint8_t* data,
size_t len)) {
321 bool is_first =
false;
322 const char* actual_mime =
nullptr;
323 const char* default_mime =
nullptr;
324 void (*notifyMimeCallback)(
const char*
mime) =
nullptr;
329 actual_mime =
lookupMime((uint8_t*)data, len);
330 if (notifyMimeCallback !=
nullptr && actual_mime !=
nullptr) {
331 notifyMimeCallback(actual_mime);
339 for (
int j = 0; j < checks.size(); j++) {
340 Check l_check = checks[j];
341 if (l_check.is_active && l_check.check(data, len)) {