Skip to content

Commit 748876c

Browse files
committed
2 parents 301a570 + 656245f commit 748876c

File tree

5 files changed

+155
-112
lines changed

5 files changed

+155
-112
lines changed

src/AudioTools/AudioCodecs/MP3HeaderParser.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -178,14 +178,14 @@ class MP3HeaderParser {
178178
}
179179

180180
int getFrameLength() {
181-
return int((144 * getBitrate() / getSampleRate()) + header.Padding);
181+
return int((144 * getBitrate() / getSampleRate()) + Padding);
182182
}
183183

184184
};
185185

186186
public:
187187
/// parses the header string and returns true if this is a valid mp3 file
188-
bool isValid(uint8_t* data, int len) {
188+
bool isValid(const uint8_t* data, int len) {
189189
memset(&header, 0, sizeof(header));
190190
StrView str((char*)data, len);
191191

@@ -219,11 +219,11 @@ class MP3HeaderParser {
219219
StrView header_str((char*)data + pos, len_available);
220220
header = readFrameHeader(header_str);
221221

222-
// check end of frame: it must contains a synch word
223-
int pos = findSynchWord(header_str.c_str(), header_str.length());
222+
// check end of frame: it must contains a sync word
223+
int end_pos = findSyncWord((uint8_t*)header_str.c_str(), header_str.length());
224224
int pos_expected = getFrameLength();
225225
if (pos_expected < header_str.length()){
226-
if (pos != pos_expected){
226+
if (end_pos != pos_expected){
227227
LOGE("Expected SynchWord missing");
228228
return false;
229229
}

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;
@@ -101,11 +108,6 @@ class MultiDecoder : public AudioDecoder {
101108
// decode the data
102109
return actual_decoder.decoder->write(data, len);
103110
}
104-
/// Define your own custom mime detector
105-
void setMimeDetector(const char* (*mimeDetectCallback)(uint8_t* data,
106-
size_t len)) {
107-
mime_detector.setMimeDetector(mimeDetectCallback);
108-
}
109111

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

src/AudioTools/CoreAudio/MimeDetector.h

Lines changed: 0 additions & 96 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)