Skip to content

Commit

Permalink
WIP metadata: vorbis: support embedded jpeg album art
Browse files Browse the repository at this point in the history
Change-Id: I5e1313f4f5523b26cb022bc69125670ed363e5a6
  • Loading branch information
bahusoid committed Nov 9, 2024
1 parent 221a5ad commit e27626f
Show file tree
Hide file tree
Showing 11 changed files with 526 additions and 87 deletions.
2 changes: 1 addition & 1 deletion apps/buffering.c
Original file line number Diff line number Diff line change
Expand Up @@ -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->type & AA_TYPE_UNSYNC, 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);
Expand Down
3 changes: 2 additions & 1 deletion apps/playback.c
Original file line number Diff line number Diff line change
Expand Up @@ -1795,7 +1795,8 @@ static int audio_load_albumart(struct track_info *infop,
hid < 0 && hid != ERR_BUFFER_FULL &&
track_id3->has_embedded_albumart &&
(track_id3->albumart.type == AA_TYPE_JPG ||
track_id3->albumart.type == (AA_TYPE_JPG | AA_TYPE_UNSYNC)))
track_id3->albumart.type == (AA_TYPE_JPG | AA_TYPE_UNSYNC) ||
track_id3->albumart.type == (AA_TYPE_JPG | AA_FLAG_BASE64)))
{
if (is_current_track)
clear_last_folder_album_art();
Expand Down
81 changes: 73 additions & 8 deletions apps/recorder/jpeg_load.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
* KIND, either express or implied.
*
****************************************************************************/
#include "metadata_parsers.h"
#include "embedded_metadata.h"
#include "plugin.h"
#include "debug.h"
#include "jpeg_load.h"
Expand Down Expand Up @@ -878,6 +878,46 @@ static int read_buf(int fildes, unsigned char *buf, size_t count)
return read(fildes, buf, count);
}

static struct file ogg;
static int read_buf_base64(int fd, unsigned char *buf, size_t count)
{
// count = read(fildes, buf, count);
// b64_decode(buf, count, buf, &count);
// return count;
size_t nbuf;
if (ogg.packet_remaining < count)
{
nbuf = read(fd,buf, ogg.packet_remaining);
//base64 requires size to be multiple of four,
// so combine data from two packets with proper size if required
int num_to_add = 4 - nbuf % 4;
if (!file_read_page_header(&ogg))
{
//looks like we lost in file...
return 0;
}
nbuf += read(fd, buf + (count - num_to_add), num_to_add);
ogg.packet_remaining -= num_to_add;
}
else
{
nbuf = read(fd, buf, count);
ogg.packet_remaining -= nbuf;
}

bool exit = false;
while (nbuf > 0 && buf[nbuf - 1] < 2)
{
exit = true;
--nbuf;
}

size_t outlen;

b64_decode(buf,nbuf, buf, &outlen );
return outlen;
}

static int read_buf_id3_unsync(int fildes, unsigned char *buf, size_t count)
{
static bool global_ff_found = false;
Expand Down Expand Up @@ -905,15 +945,19 @@ static unsigned char *jpeg_getc(struct jpeg* p_jpeg)
return (p_jpeg->buf_index++) + p_jpeg->buf;
}

INLINE bool skip_bytes_seek(struct jpeg* p_jpeg)
bool skip_bytes(struct jpeg* p_jpeg, int count);

bool skip_bytes_seek(struct jpeg* p_jpeg)
{
if (UNLIKELY(lseek(p_jpeg->fd, -p_jpeg->buf_left, SEEK_CUR) < 0))
int count = -p_jpeg->buf_left;
fill_buf(p_jpeg);
if (p_jpeg->buf_left < 0)
return false;
p_jpeg->buf_left = 0;
return true;

return skip_bytes(p_jpeg, count);
}

static bool skip_bytes(struct jpeg* p_jpeg, int count)
bool skip_bytes(struct jpeg* p_jpeg, int count)
{
p_jpeg->buf_left -= count;
p_jpeg->buf_index += count;
Expand Down Expand Up @@ -2020,7 +2064,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, bool unsync,
int clip_jpeg_fd(int fd, int flags,
#endif
unsigned long len,
struct bitmap *bm,
Expand All @@ -2036,7 +2080,28 @@ int clip_jpeg_fd(int fd, bool unsync,
#ifdef JPEG_FROM_MEM
struct jpeg *p_jpeg = &jpeg;
#else
read_buf_ptr = unsync ? read_buf_id3_unsync : read_buf;
if(flags & AA_TYPE_UNSYNC)
read_buf_ptr = read_buf_id3_unsync;
else if( flags & AA_FLAG_BASE64)
{
off_t pos = lseek(fd, 0, SEEK_CUR);

lseek(fd, 0, SEEK_SET);
unsigned char buf_format[92];
int type = get_ogg_format_and_move_to_comments(fd, buf_format);

file_init(&ogg,fd, type, 0 );
int packet_start_pos = lseek(fd, 0, SEEK_CUR);

int x_pos = pos - packet_start_pos;
ogg.packet_remaining -= x_pos;
lseek(fd, pos, SEEK_SET);

read_buf_ptr = read_buf_base64;
}
else
read_buf_ptr = read_buf;

struct jpeg *p_jpeg = (struct jpeg*)bm->data;
int tmp_size = maxsize;
ALIGN_BUFFER(p_jpeg, tmp_size, sizeof(long));
Expand Down
2 changes: 1 addition & 1 deletion apps/recorder/jpeg_load.h
Original file line number Diff line number Diff line change
Expand Up @@ -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, bool unsync,
int clip_jpeg_fd(int fd, int flags,
unsigned long jpeg_size,
struct bitmap *bm,
int maxsize,
Expand Down
158 changes: 158 additions & 0 deletions firmware/common/base64.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
/*
* Base64 encoding/decoding (RFC1341)
* Copyright (c) 2005-2011, Jouni Malinen <[email protected]>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include <string.h>
#include <stddef.h>

#define os_malloc(...) NULL
#define os_memset memset
#define os_free(...)



static const unsigned char base64_table[65] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

/**
* base64_encode - Base64 encode
* @src: Data to be encoded
* @len: Length of the data to be encoded
* @out_len: Pointer to output length variable, or %NULL if not used
* Returns: Allocated buffer of out_len bytes of encoded data,
* or %NULL on failure
*
* Caller is responsible for freeing the returned buffer. Returned buffer is
* nul terminated to make it easier to use as a C string. The nul terminator is
* not included in out_len.
*/
unsigned char * base64_encode(const unsigned char *src, size_t len,
size_t *out_len)
{
unsigned char *out, *pos;
const unsigned char *end, *in;
size_t olen;
int line_len;

olen = len * 4 / 3 + 4; /* 3-byte blocks to 4-byte */
olen += olen / 72; /* line feeds */
olen++; /* nul termination */
if (olen < len)
return NULL; /* integer overflow */
out = os_malloc(olen);
if (out == NULL)
return NULL;

end = src + len;
in = src;
pos = out;
line_len = 0;
while (end - in >= 3) {
*pos++ = base64_table[in[0] >> 2];
*pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)];
*pos++ = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)];
*pos++ = base64_table[in[2] & 0x3f];
in += 3;
line_len += 4;
if (line_len >= 72) {
*pos++ = '\n';
line_len = 0;
}
}

if (end - in) {
*pos++ = base64_table[in[0] >> 2];
if (end - in == 1) {
*pos++ = base64_table[(in[0] & 0x03) << 4];
*pos++ = '=';
} else {
*pos++ = base64_table[((in[0] & 0x03) << 4) |
(in[1] >> 4)];
*pos++ = base64_table[(in[1] & 0x0f) << 2];
}
*pos++ = '=';
line_len += 4;
}

if (line_len)
*pos++ = '\n';

*pos = '\0';
if (out_len)
*out_len = pos - out;
return out;
}


/**
* base64_decode - Base64 decode
* @src: Data to be decoded
* @len: Length of the data to be decoded
* @out_len: Pointer to output length variable
* Returns: Allocated buffer of out_len bytes of decoded data,
* or %NULL on failure
*
* Caller is responsible for freeing the returned buffer.
*/
unsigned char * base64_decode(const unsigned char *src, size_t len,
size_t *out_len)
{
unsigned char dtable[256], *out, *pos, block[4], tmp;
size_t i, count, olen;
int pad = 0;

os_memset(dtable, 0x80, 256);
for (i = 0; i < sizeof(base64_table) - 1; i++)
dtable[base64_table[i]] = (unsigned char) i;
dtable['='] = 0;

count = 0;
for (i = 0; i < len; i++) {
if (dtable[src[i]] != 0x80)
count++;
}

if (count == 0 || count % 4)
return NULL;

olen = count / 4 * 3;
pos = out = os_malloc(olen);
if (out == NULL)
return NULL;

count = 0;
for (i = 0; i < len; i++) {
tmp = dtable[src[i]];
if (tmp == 0x80)
continue;

if (src[i] == '=')
pad++;
block[count] = tmp;
count++;
if (count == 4) {
*pos++ = (block[0] << 2) | (block[1] >> 4);
*pos++ = (block[1] << 4) | (block[2] >> 2);
*pos++ = (block[2] << 6) | block[3];
count = 0;
if (pad) {
if (pad == 1)
pos--;
else if (pad == 2)
pos -= 2;
else {
/* Invalid padding */
os_free(out);
return NULL;
}
break;
}
}
}

*out_len = pos - out;
return out;
}
42 changes: 42 additions & 0 deletions lib/rbcodec/metadata/embedded_metadata.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2005 Dave Chapman
*
* 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 <stdio.h>
//#include <stdlib.h>
//#include <ctype.h>
//#include <inttypes.h>
#include "platform.h"


int get_ogg_format_and_move_to_comments(int fd, unsigned char *buf);

int b64_decode(const char *in, size_t in_len, unsigned char *out, size_t *outlen);

struct file
{
int fd;
bool packet_ended;
long packet_remaining;
};

bool file_init(struct file* file, int fd, int type, int remaining);
ssize_t file_read(struct file* file, void* buffer, size_t buffer_size);
bool file_read_page_header(struct file* file);
int id3_unsynchronize(char* tag, int len, bool *ff_found);
1 change: 1 addition & 0 deletions lib/rbcodec/metadata/id3tags.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
4 changes: 3 additions & 1 deletion lib/rbcodec/metadata/metadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -197,14 +197,16 @@ enum {
ID3_VER_2_4
};

#define AA_FLAGS_SHIFT 4
#ifdef HAVE_ALBUMART
enum mp3_aa_type {
AA_TYPE_UNKNOWN,
AA_TYPE_BMP,
AA_TYPE_PNG,
AA_TYPE_JPG,

AA_TYPE_UNSYNC = 0x100, //it's a flag
AA_TYPE_UNSYNC = 1<< (AA_FLAGS_SHIFT + 1), //it's a flag
AA_FLAG_BASE64 = 1<< (AA_FLAGS_SHIFT + 2),
};

struct mp3_albumart {
Expand Down
1 change: 0 additions & 1 deletion lib/rbcodec/metadata/metadata_parsers.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
#include <stdbool.h>

char* id3_get_num_genre(unsigned int genre_num);
int id3_unsynchronize(char* tag, int len, bool *ff_found);
int getid3v1len(int fd);
int getid3v2len(int fd);
bool setid3v1title(int fd, struct mp3entry *entry);
Expand Down
Loading

0 comments on commit e27626f

Please sign in to comment.