Skip to content

Commit

Permalink
m4a ilst atom not found, although it exists
Browse files Browse the repository at this point in the history
  • Loading branch information
schreibfaul1 committed Sep 6, 2024
1 parent 1bc79e5 commit 97f32ff
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 60 deletions.
120 changes: 61 additions & 59 deletions src/Audio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3156,7 +3156,7 @@ void Audio::processLocalFile() {
if(!(audiofile && m_f_running && getDatamode() == AUDIO_LOCALFILE)) return; // guard

static uint32_t ctime = 0;
const uint32_t timeout = 6500; // ms
const uint32_t timeout = 8000; // ms
const uint32_t maxFrameSize = InBuff.getMaxBlockSize(); // every mp3/aac frame is not bigger
static bool f_fileDataComplete;
static uint32_t byteCounter; // count received data
Expand Down Expand Up @@ -4732,6 +4732,7 @@ void Audio::computeAudioTime(uint16_t bytesDecoderIn, uint16_t bytesDecoderOut)
case AUDIOLOG_OUT_OF_MEMORY: e = "Out of memory"; logLevel = 1; break;
case AUDIOLOG_FILE_NOT_FOUND: e = "File doesn't exist: "; logLevel = 1; f = s; break;
case AUDIOLOG_FILE_READ_ERR: e = "Failed to open file for reading"; logLevel = 1; break;
case AUDIOLOG_M4A_ATOM_NOT_FOUND: e= "m4a atom ilst not found: "; logLevel = 3; f = s; break;

default: e = "UNKNOWN EVENT"; logLevel = 3; break;
}
Expand Down Expand Up @@ -5987,69 +5988,70 @@ boolean Audio::streamDetection(uint32_t bytesAvail) {
return false;
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void Audio::seek_m4a_ilst() {
// ilist - item list atom, contains the metadata

/* atom hierarchy (example)_________________________________________________________________________________________
ftyp -> moov -> udta -> meta -> ilst -> data
__________________________________________________________________________________________________________________*/

struct m4a_Atom {
int pos;
int size;
char name[5] = {0};
} atom, at, tmp;

// c99 has no inner functions, lambdas are only allowed from c11, please don't use ancient compiler
auto atomItems = [&](uint32_t startPos) { // lambda, inner function
char temp[5] = {0};
audiofile.seek(startPos);
audiofile.readBytes(temp, 4);
atom.size = bigEndian((uint8_t*)temp, 4);
if(!atom.size) atom.size = 4; // has no data, length is 0
audiofile.readBytes(atom.name, 4);
atom.name[4] = '\0';
atom.pos = startPos;
return atom;
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

boolean found = false;
uint32_t seekpos = 0;
uint32_t filesize = getFileSize();
char name[6][5] = {"moov", "udta", "meta", "ilst"};
const char info[12][6] = {"nam\0", "ART\0", "alb\0", "too\0", "cmt\0", "wrt\0", "tmpo\0", "trkn\0", "day\0", "cpil\0", "aART\0", "gen\0"};

uint32_t Audio::find_m4a_atom(uint32_t fileSize, const char* atomName, uint32_t depth) {

while (audiofile.position() < fileSize) {
uint32_t atomStart = audiofile.position(); // Position of the current atom
uint32_t atomSize;
char atomType[5] = {0};
audiofile.read((uint8_t*)&atomSize, 4); // Read the atom size (4 bytes) and the atom type (4 bytes)
if(!atomSize) audiofile.read((uint8_t*)&atomSize, 4); // skip 4 byte offset field
audiofile.read((uint8_t*)atomType, 4);

atomSize = bswap32(atomSize); // Convert atom size from big-endian to little-endian
/// log_w("%*sAtom '%s' found at position %u with size %u bytes", depth * 2, "", atomType, atomStart, atomSize);
if (strncmp(atomType, atomName, 4) == 0) return atomStart;

if (atomSize == 1) { // If the atom has a size of 1, an 'Extended Size' is used
uint64_t extendedSize;
audiofile.read((uint8_t*)&extendedSize, 8);
extendedSize = bswap64(extendedSize);
// log_w("%*sExtended size: %llu bytes\n", depth * 2, "", extendedSize);
atomSize = (uint32_t)extendedSize; // Limit to uint32_t for further processing
}

// If the atom is a container, read the atoms contained in it recursively
if (strncmp(atomType, "moov", 4) == 0 || strncmp(atomType, "trak", 4) == 0 ||
strncmp(atomType, "mdia", 4) == 0 || strncmp(atomType, "minf", 4) == 0 ||
strncmp(atomType, "stbl", 4) == 0 || strncmp(atomType, "meta", 4) == 0 ||
strncmp(atomType, "udta", 4) == 0 ) {
// Go recursively into the atom, read the contents
uint32_t pos = find_m4a_atom(atomStart + atomSize, atomName, depth + 1);
if(pos) return pos;
} else {
audiofile.seek(atomStart + atomSize); // No container atom, jump to the next atom
}
}
return 0;
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void Audio::seek_m4a_ilst() { // ilist - item list atom, contains the metadata
if(!audiofile) return; // guard
audiofile.seek(0);
uint32_t fileSize = audiofile.size();
const char atomName[] = "ilst";
uint32_t atomStart = find_m4a_atom(fileSize, atomName);
if(!atomStart) {
printProcessLog(AUDIOLOG_M4A_ATOM_NOT_FOUND, "ilst");
audiofile.seek(0);
return;
}

at.pos = 0;
at.size = filesize;
seekpos = 0;
uint32_t seekpos = atomStart;
const char info[12][6] = {"nam\0", "ART\0", "alb\0", "too\0", "cmt\0", "wrt\0", "tmpo\0", "trkn\0", "day\0", "cpil\0", "aART\0", "gen\0"};

for(int i = 0; i < 4; i++) {
found = false;
while(seekpos < at.pos + at.size) {
tmp = atomItems(seekpos);
seekpos += tmp.size;
if(strcmp(tmp.name, name[i]) == 0) {
memcpy((void*)&at, (void*)&tmp, sizeof(tmp));
found = true;
}
// log_i("name %s pos %d, size %d", tmp.name, tmp.pos, tmp.size);
}
if(!found) {
log_w("m4a atom ilst not found");
audiofile.seek(0);
return;
}
seekpos = at.pos + 8; // 4 bytes size + 4 bytes name
seekpos = atomStart;
char buff[4];
uint32_t len = 0;
audiofile.seek(seekpos);
audiofile.readBytes(buff, 4);
len = bigEndian((uint8_t*)buff, 4);
if(!len) {
audiofile.readBytes(buff, 4); // 4bytes offset filed
len = bigEndian((uint8_t*)buff, 4);
}

int len = tmp.size - 8;
if(len > 1024) len = 1024;
// log_i("found at pos %i, len %i", seekpos, len);
log_w("found at pos %i, len %i", seekpos, len);

uint8_t* data = (uint8_t*)calloc(len, sizeof(uint8_t));
if(!data) {
Expand Down
26 changes: 25 additions & 1 deletion src/Audio.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,8 @@ class Audio : private AudioBuffer{
#define ESP_ARDUINO_VERSION_PATCH 0
#endif

enum : int8_t { AUDIOLOG_PATH_IS_NULL = -1, AUDIOLOG_FILE_NOT_FOUND = -2, AUDIOLOG_OUT_OF_MEMORY = -3, AUDIOLOG_FILE_READ_ERR = -4, AUDIOLOG_ERR_UNKNOWN = -127 };
enum : int8_t { AUDIOLOG_PATH_IS_NULL = -1, AUDIOLOG_FILE_NOT_FOUND = -2, AUDIOLOG_OUT_OF_MEMORY = -3, AUDIOLOG_FILE_READ_ERR = -4,
AUDIOLOG_M4A_ATOM_NOT_FOUND = -5, AUDIOLOG_ERR_UNKNOWN = -127 };

void UTF8toASCII(char* str);
bool latinToUTF8(char* buff, size_t bufflen, bool UTF8check = true);
Expand Down Expand Up @@ -244,6 +245,7 @@ class Audio : private AudioBuffer{
inline uint32_t streamavail() { return _client ? _client->available() : 0; }
void IIR_calculateCoefficients(int8_t G1, int8_t G2, int8_t G3);
bool ts_parsePacket(uint8_t* packet, uint8_t* packetStart, uint8_t* packetLength);
uint32_t find_m4a_atom(uint32_t fileSize, const char* atomType, uint32_t depth = 0);

//+++ create a T A S K for playAudioData(), output via I2S +++
public:
Expand Down Expand Up @@ -476,6 +478,28 @@ uint64_t bigEndian(uint8_t* base, uint8_t numBytes, uint8_t shiftLeft = 8) {
return ps_str;
}
//————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
// Function to reverse the byte order of a 32-bit value (big-endian to little-endian)
uint32_t bswap32(uint32_t x) {
return ((x & 0xFF000000) >> 24) |
((x & 0x00FF0000) >> 8) |
((x & 0x0000FF00) << 8) |
((x & 0x000000FF) << 24);
}
//————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
// Function to reverse the byte order of a 64-bit value (big-endian to little-endian)
uint64_t bswap64(uint64_t x) {
return ((x & 0xFF00000000000000ULL) >> 56) |
((x & 0x00FF000000000000ULL) >> 40) |
((x & 0x0000FF0000000000ULL) >> 24) |
((x & 0x000000FF00000000ULL) >> 8) |
((x & 0x00000000FF000000ULL) << 8) |
((x & 0x0000000000FF0000ULL) << 24) |
((x & 0x000000000000FF00ULL) << 40) |
((x & 0x00000000000000FFULL) << 56);
}
//————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————



private:
const char *codecname[10] = {"unknown", "WAV", "MP3", "AAC", "M4A", "FLAC", "AACP", "OPUS", "OGG", "VORBIS" };
Expand Down

0 comments on commit 97f32ff

Please sign in to comment.