mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-10-14 02:27:39 -04:00
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
This commit is contained in:
parent
6649731563
commit
7f4a8891a6
7 changed files with 72 additions and 23 deletions
|
@ -867,7 +867,7 @@ static int load_image(int fd, const char *path,
|
||||||
#ifdef HAVE_JPEG
|
#ifdef HAVE_JPEG
|
||||||
if (aa != NULL) {
|
if (aa != NULL) {
|
||||||
lseek(fd, aa->pos, SEEK_SET);
|
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"))
|
else if (strcmp(path + strlen(path) - 4, ".bmp"))
|
||||||
rc = read_jpeg_fd(fd, bmp, (int)max_size, format, NULL);
|
rc = read_jpeg_fd(fd, bmp, (int)max_size, format, NULL);
|
||||||
|
|
|
@ -1922,7 +1922,7 @@ static int audio_load_albumart(struct track_info *infop,
|
||||||
/* We can only decode jpeg for embedded AA */
|
/* We can only decode jpeg for embedded AA */
|
||||||
if (global_settings.album_art != AA_OFF &&
|
if (global_settings.album_art != AA_OFF &&
|
||||||
hid < 0 && hid != ERR_BUFFER_FULL &&
|
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)
|
if (is_current_track)
|
||||||
clear_last_folder_album_art();
|
clear_last_folder_album_art();
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
* KIND, either express or implied.
|
* KIND, either express or implied.
|
||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
#include "embedded_metadata.h"
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "jpeg_load.h"
|
#include "jpeg_load.h"
|
||||||
|
@ -79,6 +79,9 @@ struct jpeg
|
||||||
int fd;
|
int fd;
|
||||||
int buf_left;
|
int buf_left;
|
||||||
int buf_index;
|
int buf_index;
|
||||||
|
|
||||||
|
int (*read_buf)(struct jpeg* p_jpeg, size_t count);
|
||||||
|
void* custom_param;
|
||||||
#endif
|
#endif
|
||||||
unsigned long len;
|
unsigned long len;
|
||||||
unsigned long int bitbuf;
|
unsigned long int bitbuf;
|
||||||
|
@ -872,11 +875,21 @@ INLINE void jpeg_putc(struct jpeg* p_jpeg)
|
||||||
p_jpeg->data--;
|
p_jpeg->data--;
|
||||||
}
|
}
|
||||||
#else
|
#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)
|
INLINE void fill_buf(struct jpeg* p_jpeg)
|
||||||
{
|
{
|
||||||
p_jpeg->buf_left = read(p_jpeg->fd, p_jpeg->buf,
|
p_jpeg->buf_left = p_jpeg->read_buf(p_jpeg, MIN(JPEG_READ_BUF_SIZE, p_jpeg->len));
|
||||||
(p_jpeg->len >= JPEG_READ_BUF_SIZE)?
|
|
||||||
JPEG_READ_BUF_SIZE : p_jpeg->len);
|
|
||||||
p_jpeg->buf_index = 0;
|
p_jpeg->buf_index = 0;
|
||||||
if (p_jpeg->buf_left > 0)
|
if (p_jpeg->buf_left > 0)
|
||||||
p_jpeg->len -= p_jpeg->buf_left;
|
p_jpeg->len -= p_jpeg->buf_left;
|
||||||
|
@ -1958,7 +1971,7 @@ int clip_jpeg_file(const char* filename,
|
||||||
return fd * 10 - 1;
|
return fd * 10 - 1;
|
||||||
}
|
}
|
||||||
lseek(fd, offset, SEEK_SET);
|
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);
|
close(fd);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -2007,7 +2020,7 @@ int get_jpeg_dim_mem(unsigned char *data, unsigned long len,
|
||||||
|
|
||||||
int decode_jpeg_mem(unsigned char *data,
|
int decode_jpeg_mem(unsigned char *data,
|
||||||
#else
|
#else
|
||||||
int clip_jpeg_fd(int fd,
|
int clip_jpeg_fd(int fd, int flags,
|
||||||
#endif
|
#endif
|
||||||
unsigned long len,
|
unsigned long len,
|
||||||
struct bitmap *bm,
|
struct bitmap *bm,
|
||||||
|
@ -2038,6 +2051,14 @@ int clip_jpeg_fd(int fd,
|
||||||
p_jpeg->fd = fd;
|
p_jpeg->fd = fd;
|
||||||
if (p_jpeg->len == 0)
|
if (p_jpeg->len == 0)
|
||||||
p_jpeg->len = filesize(p_jpeg->fd);
|
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
|
#endif
|
||||||
status = process_markers(p_jpeg);
|
status = process_markers(p_jpeg);
|
||||||
#ifndef JPEG_FROM_MEM
|
#ifndef JPEG_FROM_MEM
|
||||||
|
@ -2225,7 +2246,7 @@ int read_jpeg_fd(int fd,
|
||||||
int format,
|
int format,
|
||||||
const struct custom_format *cformat)
|
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
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -67,7 +67,7 @@ int clip_jpeg_file(const char* filename,
|
||||||
* read embedded jpeg files as above. Needs an open file descripter, and
|
* 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
|
* 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,
|
unsigned long jpeg_size,
|
||||||
struct bitmap *bm,
|
struct bitmap *bm,
|
||||||
int maxsize,
|
int maxsize,
|
||||||
|
|
23
lib/rbcodec/metadata/embedded_metadata.h
Normal file
23
lib/rbcodec/metadata/embedded_metadata.h
Normal file
|
@ -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 <stdbool.h>
|
||||||
|
|
||||||
|
int id3_unsynchronize(char* tag, int len, bool *ff_found);
|
|
@ -45,6 +45,7 @@
|
||||||
#include "mp3data.h"
|
#include "mp3data.h"
|
||||||
#include "metadata_common.h"
|
#include "metadata_common.h"
|
||||||
#include "metadata_parsers.h"
|
#include "metadata_parsers.h"
|
||||||
|
#include "embedded_metadata.h"
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
|
|
||||||
static unsigned long unsync(unsigned long b0,
|
static unsigned long unsync(unsigned long b0,
|
||||||
|
@ -161,7 +162,8 @@ struct tag_resolver {
|
||||||
|
|
||||||
static bool global_ff_found;
|
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;
|
int i;
|
||||||
unsigned char c;
|
unsigned char c;
|
||||||
|
@ -299,9 +301,7 @@ static int parsealbumart( struct mp3entry* entry, char* tag, int bufferpos )
|
||||||
if(entry->has_embedded_albumart)
|
if(entry->has_embedded_albumart)
|
||||||
return bufferpos;
|
return bufferpos;
|
||||||
|
|
||||||
/* we currently don't support unsynchronizing albumart */
|
bool unsync = entry->albumart.type == AA_FLAG_ID3_UNSYNC;
|
||||||
if (entry->albumart.type == AA_TYPE_UNSYNC)
|
|
||||||
return bufferpos;
|
|
||||||
|
|
||||||
entry->albumart.type = AA_TYPE_UNKNOWN;
|
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 */
|
/* fixup offset&size for image data */
|
||||||
entry->albumart.pos += tag - start;
|
entry->albumart.pos += tag - start;
|
||||||
entry->albumart.size -= tag - start;
|
entry->albumart.size -= tag - start;
|
||||||
|
if (unsync)
|
||||||
|
{
|
||||||
|
entry->albumart.type |= AA_FLAG_ID3_UNSYNC;
|
||||||
|
}
|
||||||
/* check for malformed tag with no picture data */
|
/* check for malformed tag with no picture data */
|
||||||
entry->has_embedded_albumart = (entry->albumart.size != 0);
|
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 == 4 && !memcmp( header, "APIC", 4)) ||
|
||||||
(tr->tag_length == 3 && !memcmp( header, "PIC" , 3))))
|
(tr->tag_length == 3 && !memcmp( header, "PIC" , 3))))
|
||||||
{
|
{
|
||||||
if (unsynch || (global_unsynch && version <= ID3_VER_2_3))
|
entry->albumart.pos = lseek(fd, 0, SEEK_CUR) - framelen;
|
||||||
entry->albumart.type = AA_TYPE_UNSYNC;
|
entry->albumart.size = totframelen;
|
||||||
else
|
entry->albumart.type = (unsynch || (global_unsynch && version <= ID3_VER_2_3))
|
||||||
{
|
? AA_FLAG_ID3_UNSYNC
|
||||||
entry->albumart.pos = lseek(fd, 0, SEEK_CUR) - framelen;
|
: AA_TYPE_UNKNOWN;
|
||||||
entry->albumart.size = totframelen;
|
|
||||||
entry->albumart.type = AA_TYPE_UNKNOWN;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if( tr->ppFunc )
|
if( tr->ppFunc )
|
||||||
|
|
|
@ -196,13 +196,17 @@ enum {
|
||||||
ID3_VER_2_4
|
ID3_VER_2_4
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define AA_FLAGS_SHIFT 4
|
||||||
|
#define AA_CLEAR_FLAGS_MASK ~(-1 << AA_FLAGS_SHIFT)
|
||||||
|
|
||||||
#ifdef HAVE_ALBUMART
|
#ifdef HAVE_ALBUMART
|
||||||
enum mp3_aa_type {
|
enum mp3_aa_type {
|
||||||
AA_TYPE_UNSYNC = -1,
|
|
||||||
AA_TYPE_UNKNOWN,
|
AA_TYPE_UNKNOWN,
|
||||||
AA_TYPE_BMP,
|
AA_TYPE_BMP,
|
||||||
AA_TYPE_PNG,
|
AA_TYPE_PNG,
|
||||||
AA_TYPE_JPG,
|
AA_TYPE_JPG,
|
||||||
|
|
||||||
|
AA_FLAG_ID3_UNSYNC = 1 << (AA_FLAGS_SHIFT + 0),
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mp3_albumart {
|
struct mp3_albumart {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue