From 7f4a8891a6082c9428ff269f64c11663380be2ad Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Wed, 6 Nov 2024 22:28:24 +0200 Subject: [PATCH] metadata: mp3: Support unsync embedded jpeg album art Support parsing alubm art from id3 metadata with "unsynchronisation scheme": https://id3.org/id3v2.3.0#The_unsynchronisation_scheme Change-Id: I1e2ca4ae0aa967f7e80142a04c9a7d99e38e68b2 --- apps/buffering.c | 2 +- apps/playback.c | 2 +- apps/recorder/jpeg_load.c | 35 +++++++++++++++++++----- apps/recorder/jpeg_load.h | 2 +- lib/rbcodec/metadata/embedded_metadata.h | 23 ++++++++++++++++ lib/rbcodec/metadata/id3tags.c | 25 +++++++++-------- lib/rbcodec/metadata/metadata.h | 6 +++- 7 files changed, 72 insertions(+), 23 deletions(-) create mode 100644 lib/rbcodec/metadata/embedded_metadata.h diff --git a/apps/buffering.c b/apps/buffering.c index b9f30fc6df..9a52d60b3f 100644 --- a/apps/buffering.c +++ b/apps/buffering.c @@ -867,7 +867,7 @@ static int load_image(int fd, const char *path, #ifdef HAVE_JPEG if (aa != NULL) { lseek(fd, aa->pos, SEEK_SET); - rc = clip_jpeg_fd(fd, aa->size, bmp, (int)max_size, format, NULL); + rc = clip_jpeg_fd(fd, aa->type, aa->size, bmp, (int)max_size, format, NULL); } else if (strcmp(path + strlen(path) - 4, ".bmp")) rc = read_jpeg_fd(fd, bmp, (int)max_size, format, NULL); diff --git a/apps/playback.c b/apps/playback.c index eb3ce3b1d1..92000ad0ec 100644 --- a/apps/playback.c +++ b/apps/playback.c @@ -1922,7 +1922,7 @@ static int audio_load_albumart(struct track_info *infop, /* We can only decode jpeg for embedded AA */ if (global_settings.album_art != AA_OFF && hid < 0 && hid != ERR_BUFFER_FULL && - track_id3->has_embedded_albumart && track_id3->albumart.type == AA_TYPE_JPG) + track_id3->has_embedded_albumart && (track_id3->albumart.type & AA_CLEAR_FLAGS_MASK) == AA_TYPE_JPG) { if (is_current_track) clear_last_folder_album_art(); diff --git a/apps/recorder/jpeg_load.c b/apps/recorder/jpeg_load.c index 154a57b98c..2e64fed93a 100644 --- a/apps/recorder/jpeg_load.c +++ b/apps/recorder/jpeg_load.c @@ -26,7 +26,7 @@ * KIND, either express or implied. * ****************************************************************************/ - +#include "embedded_metadata.h" #include "plugin.h" #include "debug.h" #include "jpeg_load.h" @@ -79,6 +79,9 @@ struct jpeg int fd; int buf_left; int buf_index; + + int (*read_buf)(struct jpeg* p_jpeg, size_t count); + void* custom_param; #endif unsigned long len; unsigned long int bitbuf; @@ -872,11 +875,21 @@ INLINE void jpeg_putc(struct jpeg* p_jpeg) p_jpeg->data--; } #else + +static int read_buf(struct jpeg* p_jpeg, size_t count) +{ + return read(p_jpeg->fd, p_jpeg->buf, count); +} + +static int read_buf_id3_unsync(struct jpeg* p_jpeg, size_t count) +{ + count = read(p_jpeg->fd, p_jpeg->buf, count); + return id3_unsynchronize(p_jpeg->buf, count, (bool*) &p_jpeg->custom_param); +} + INLINE void fill_buf(struct jpeg* p_jpeg) { - p_jpeg->buf_left = read(p_jpeg->fd, p_jpeg->buf, - (p_jpeg->len >= JPEG_READ_BUF_SIZE)? - JPEG_READ_BUF_SIZE : p_jpeg->len); + p_jpeg->buf_left = p_jpeg->read_buf(p_jpeg, MIN(JPEG_READ_BUF_SIZE, p_jpeg->len)); p_jpeg->buf_index = 0; if (p_jpeg->buf_left > 0) p_jpeg->len -= p_jpeg->buf_left; @@ -1958,7 +1971,7 @@ int clip_jpeg_file(const char* filename, return fd * 10 - 1; } lseek(fd, offset, SEEK_SET); - ret = clip_jpeg_fd(fd, jpeg_size, bm, maxsize, format, cformat); + ret = clip_jpeg_fd(fd, 0, jpeg_size, bm, maxsize, format, cformat); close(fd); return ret; } @@ -2007,7 +2020,7 @@ int get_jpeg_dim_mem(unsigned char *data, unsigned long len, int decode_jpeg_mem(unsigned char *data, #else -int clip_jpeg_fd(int fd, +int clip_jpeg_fd(int fd, int flags, #endif unsigned long len, struct bitmap *bm, @@ -2038,6 +2051,14 @@ int clip_jpeg_fd(int fd, p_jpeg->fd = fd; if (p_jpeg->len == 0) p_jpeg->len = filesize(p_jpeg->fd); + + p_jpeg->read_buf = read_buf; + + if (flags & AA_FLAG_ID3_UNSYNC) + { + p_jpeg->read_buf = read_buf_id3_unsync; + p_jpeg->custom_param = false; + } #endif status = process_markers(p_jpeg); #ifndef JPEG_FROM_MEM @@ -2225,7 +2246,7 @@ int read_jpeg_fd(int fd, int format, const struct custom_format *cformat) { - return clip_jpeg_fd(fd, 0, bm, maxsize, format, cformat); + return clip_jpeg_fd(fd, 0, 0, bm, maxsize, format, cformat); } #endif diff --git a/apps/recorder/jpeg_load.h b/apps/recorder/jpeg_load.h index 129b0fbf19..d4c345d06c 100644 --- a/apps/recorder/jpeg_load.h +++ b/apps/recorder/jpeg_load.h @@ -67,7 +67,7 @@ int clip_jpeg_file(const char* filename, * read embedded jpeg files as above. Needs an open file descripter, and * assumes the caller has lseek()'d to the start of the jpeg blob **/ -int clip_jpeg_fd(int fd, +int clip_jpeg_fd(int fd, int flags, unsigned long jpeg_size, struct bitmap *bm, int maxsize, diff --git a/lib/rbcodec/metadata/embedded_metadata.h b/lib/rbcodec/metadata/embedded_metadata.h new file mode 100644 index 0000000000..4f2416548a --- /dev/null +++ b/lib/rbcodec/metadata/embedded_metadata.h @@ -0,0 +1,23 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2024 Roman Artiukhin + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include + +int id3_unsynchronize(char* tag, int len, bool *ff_found); diff --git a/lib/rbcodec/metadata/id3tags.c b/lib/rbcodec/metadata/id3tags.c index 064321b2e0..c7e63b0921 100644 --- a/lib/rbcodec/metadata/id3tags.c +++ b/lib/rbcodec/metadata/id3tags.c @@ -45,6 +45,7 @@ #include "mp3data.h" #include "metadata_common.h" #include "metadata_parsers.h" +#include "embedded_metadata.h" #include "misc.h" static unsigned long unsync(unsigned long b0, @@ -161,7 +162,8 @@ struct tag_resolver { static bool global_ff_found; -static int unsynchronize(char* tag, int len, bool *ff_found) +#define unsynchronize id3_unsynchronize +int id3_unsynchronize(char* tag, int len, bool *ff_found) { int i; unsigned char c; @@ -299,9 +301,7 @@ static int parsealbumart( struct mp3entry* entry, char* tag, int bufferpos ) if(entry->has_embedded_albumart) return bufferpos; - /* we currently don't support unsynchronizing albumart */ - if (entry->albumart.type == AA_TYPE_UNSYNC) - return bufferpos; + bool unsync = entry->albumart.type == AA_FLAG_ID3_UNSYNC; entry->albumart.type = AA_TYPE_UNKNOWN; @@ -353,6 +353,10 @@ static int parsealbumart( struct mp3entry* entry, char* tag, int bufferpos ) /* fixup offset&size for image data */ entry->albumart.pos += tag - start; entry->albumart.size -= tag - start; + if (unsync) + { + entry->albumart.type |= AA_FLAG_ID3_UNSYNC; + } /* check for malformed tag with no picture data */ entry->has_embedded_albumart = (entry->albumart.size != 0); } @@ -1142,14 +1146,11 @@ retry_with_limit: ((tr->tag_length == 4 && !memcmp( header, "APIC", 4)) || (tr->tag_length == 3 && !memcmp( header, "PIC" , 3)))) { - if (unsynch || (global_unsynch && version <= ID3_VER_2_3)) - entry->albumart.type = AA_TYPE_UNSYNC; - else - { - entry->albumart.pos = lseek(fd, 0, SEEK_CUR) - framelen; - entry->albumart.size = totframelen; - entry->albumart.type = AA_TYPE_UNKNOWN; - } + entry->albumart.pos = lseek(fd, 0, SEEK_CUR) - framelen; + entry->albumart.size = totframelen; + entry->albumart.type = (unsynch || (global_unsynch && version <= ID3_VER_2_3)) + ? AA_FLAG_ID3_UNSYNC + : AA_TYPE_UNKNOWN; } #endif if( tr->ppFunc ) diff --git a/lib/rbcodec/metadata/metadata.h b/lib/rbcodec/metadata/metadata.h index 56dbd5151d..de06b63efc 100644 --- a/lib/rbcodec/metadata/metadata.h +++ b/lib/rbcodec/metadata/metadata.h @@ -196,13 +196,17 @@ enum { ID3_VER_2_4 }; +#define AA_FLAGS_SHIFT 4 +#define AA_CLEAR_FLAGS_MASK ~(-1 << AA_FLAGS_SHIFT) + #ifdef HAVE_ALBUMART enum mp3_aa_type { - AA_TYPE_UNSYNC = -1, AA_TYPE_UNKNOWN, AA_TYPE_BMP, AA_TYPE_PNG, AA_TYPE_JPG, + + AA_FLAG_ID3_UNSYNC = 1 << (AA_FLAGS_SHIFT + 0), }; struct mp3_albumart {