3#include "AudioTools/AudioCodecs/HeaderParserAAC.h"
4#include "AudioTools/AudioCodecs/HeaderParserMP3.h"
5#include "AudioTools/CoreAudio/AudioBasic/StrView.h"
6#include "AudioTools/AudioCodecs/CodecWAV.h"
44 virtual const char*
mime() = 0;
66 setCheck(
"audio/vnd.wave; codecs=ms-adpcm", checkWAV_ADPCM);
67 setCheck(
"audio/vnd.wave", checkWAV);
69 setCheck(
"audio/ogg; codecs=flac", checkOggFLAC);
75 setCheck(
"audio/m4a", checkM4A,
false);
89 actual_mime =
nullptr;
94 size_t write(uint8_t* data,
size_t len) {
95 actual_mime = default_mime;
94 size_t write(uint8_t* data,
size_t len) {
…}
101 void setCheck(
const char*
mime,
bool (*check)(uint8_t* start,
size_t len),
102 bool isActvie =
true) {
104 for (
int j = 0; j < checks.size(); j++) {
105 Check l_check = checks[j];
106 if (mime_str.equals(l_check.mime)) {
107 l_check.check = check;
108 l_check.is_active = isActvie;
113 check_to_add.is_active = isActvie;
114 checks.push_back(check_to_add);
115 LOGI(
"MimeDetector for %s: %s",
mime, isActvie ?
"active" :
"inactive");
101 void setCheck(
const char*
mime,
bool (*check)(uint8_t* start,
size_t len), {
…}
119 void setMimeCallback(
void (*callback)(
const char*)) {
121 this->notifyMimeCallback = callback;
126 const char*
mime() {
return actual_mime; }
128 static bool checkAAC(uint8_t* start,
size_t len) {
129 return start[0] == 0xFF &&
130 (start[1] == 0xF0 || start[1] == 0xF1 || start[1] == 0xF9);
133 static bool checkAACExt(uint8_t* start,
size_t len) {
135 if (memcmp(start + 4,
"ftypM4A", 7) == 0) {
141 int pos = aac.findSyncWord((
const uint8_t*)start, len);
146 if (aac.isValid(start + pos, len - pos)) {
152 static bool checkMP3(uint8_t* start,
size_t len) {
153 return memcmp(start,
"ID3", 3) == 0 ||
154 (start[0] == 0xFF && ((start[1] & 0xE0) == 0xE0));
157 static bool checkMP3Ext(uint8_t* start,
size_t len) {
159 return mp3.isValid(start, len);
162 static bool checkWAV_ADPCM(uint8_t* start,
size_t len) {
163 if (memcmp(start,
"RIFF", 4) != 0)
return false;
165 header.write(start, len);
166 if (!header.parse())
return false;
167 if (header.audioInfo().format == AudioFormat::ADPCM) {
173 static bool checkWAV(uint8_t* start,
size_t len) {
174 return memcmp(start,
"RIFF", 4) == 0;
177 static bool checkOGG(uint8_t* start,
size_t len) {
178 return memcmp(start,
"OggS", 4) == 0;
181 static bool checkFLAC(uint8_t* start,
size_t len) {
182 if (len < 4)
return false;
185 if (memcmp(start,
"fLaC", 4) == 0) {
191 static bool checkOggFLAC(uint8_t* start,
size_t len) {
194 if (len >= 32 && memcmp(start,
"OggS", 4) == 0) {
197 for (
size_t i = 4; i < len - 4 && i < 64; i++) {
198 if (memcmp(start + i,
"FLAC", 4) == 0) {
202 if (i < len - 5 && start[i] == 0x7F &&
203 memcmp(start + i + 1,
"FLAC", 4) == 0) {
226 if (len >= 32 && memcmp(start,
"OggS", 4) == 0) {
229 for (
size_t i = 4; i < len - 8 && i < 80; i++) {
230 if (memcmp(start + i,
"OpusHead", 8) == 0) {
253 if (len >= 32 && memcmp(start,
"OggS", 4) == 0) {
256 for (
size_t i = 4; i < len - 7 && i < 80; i++) {
257 if (start[i] == 0x01 && memcmp(start + i + 1,
"vorbis", 6) == 0) {
268 if (len < 189)
return start[0] == 0x47;
270 return start[0] == 0x47 && start[188] == 0x47;
275 return memcmp(start,
"PSID", 4) == 0 || memcmp(start,
"RSID", 4) == 0;
278 static bool checkM4A(uint8_t* header,
size_t len) {
279 if (len < 12)
return false;
282 if (memcmp(header,
"ID3", 3) == 0)
return false;
285 if (memcmp(header + 4,
"mdat", 4) != 0)
return true;
288 if (memcmp(header + 4,
"ftyp", 4) != 0)
return false;
291 if (memcmp(header + 8,
"M4A ", 4) == 0 ||
292 memcmp(header + 8,
"mp42", 4) == 0 ||
293 memcmp(header + 8,
"isom", 4) == 0)
305 for (
auto& check : checks) {
307 check.is_active = active;
308 LOGI(
"MimeDetector for %s: %s", check.mime,
309 check.is_active ?
"active" :
"inactive");
319 actual_mime =
nullptr;
325 const char* mime =
nullptr;
326 bool (*check)(uint8_t* data,
size_t len) =
nullptr;
327 bool is_active =
true;
328 Check(
const char* mime,
bool (*check)(uint8_t* data,
size_t len)) {
335 bool is_first =
false;
336 const char* actual_mime =
nullptr;
337 const char* default_mime =
nullptr;
338 void (*notifyMimeCallback)(
const char*
mime) =
nullptr;
343 actual_mime =
lookupMime((uint8_t*)data, len);
344 if (notifyMimeCallback !=
nullptr && actual_mime !=
nullptr) {
345 notifyMimeCallback(actual_mime);
353 for (
int j = 0; j < checks.size(); j++) {
354 Check l_check = checks[j];
355 if (l_check.is_active && l_check.check(data, len)) {