summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/buffering.c29
-rw-r--r--apps/metadata.h21
-rw-r--r--apps/metadata/id3tags.c76
-rw-r--r--apps/playback.c35
-rw-r--r--apps/playback.h7
-rw-r--r--apps/recorder/jpeg_load.c43
-rw-r--r--apps/recorder/jpeg_load.h23
7 files changed, 213 insertions, 21 deletions
diff --git a/apps/buffering.c b/apps/buffering.c
index 123c7bc85f..9c0ad138f7 100644
--- a/apps/buffering.c
+++ b/apps/buffering.c
@@ -52,6 +52,7 @@
52#include "albumart.h" 52#include "albumart.h"
53#include "jpeg_load.h" 53#include "jpeg_load.h"
54#include "bmp.h" 54#include "bmp.h"
55#include "playback.h"
55#endif 56#endif
56 57
57#define GUARD_BUFSIZE (32*1024) 58#define GUARD_BUFSIZE (32*1024)
@@ -908,10 +909,12 @@ static bool fill_buffer(void)
908/* Given a file descriptor to a bitmap file, write the bitmap data to the 909/* Given a file descriptor to a bitmap file, write the bitmap data to the
909 buffer, with a struct bitmap and the actual data immediately following. 910 buffer, with a struct bitmap and the actual data immediately following.
910 Return value is the total size (struct + data). */ 911 Return value is the total size (struct + data). */
911static int load_image(int fd, const char *path, struct dim *dim) 912static int load_image(int fd, const char *path, struct bufopen_bitmap_data *data)
912{ 913{
913 int rc; 914 int rc;
914 struct bitmap *bmp = (struct bitmap *)&buffer[buf_widx]; 915 struct bitmap *bmp = (struct bitmap *)&buffer[buf_widx];
916 struct dim *dim = data->dim;
917 struct mp3_albumart *aa = data->embedded_albumart;
915 918
916 /* get the desired image size */ 919 /* get the desired image size */
917 bmp->width = dim->width, bmp->height = dim->height; 920 bmp->width = dim->width, bmp->height = dim->height;
@@ -928,8 +931,13 @@ static int load_image(int fd, const char *path, struct dim *dim)
928 - sizeof(struct bitmap); 931 - sizeof(struct bitmap);
929 932
930#ifdef HAVE_JPEG 933#ifdef HAVE_JPEG
931 int pathlen = strlen(path); 934 if (aa != NULL)
932 if (strcmp(path + pathlen - 4, ".bmp")) 935 {
936 lseek(fd, aa->pos, SEEK_SET);
937 rc = clip_jpeg_fd(fd, aa->size, bmp, free, FORMAT_NATIVE|FORMAT_DITHER|
938 FORMAT_RESIZE|FORMAT_KEEP_ASPECT, NULL);
939 }
940 else if (strcmp(path + strlen(path) - 4, ".bmp"))
933 rc = read_jpeg_fd(fd, bmp, free, FORMAT_NATIVE|FORMAT_DITHER| 941 rc = read_jpeg_fd(fd, bmp, free, FORMAT_NATIVE|FORMAT_DITHER|
934 FORMAT_RESIZE|FORMAT_KEEP_ASPECT, NULL); 942 FORMAT_RESIZE|FORMAT_KEEP_ASPECT, NULL);
935 else 943 else
@@ -1010,7 +1018,18 @@ int bufopen(const char *file, size_t offset, enum data_type type,
1010 if (fd < 0) 1018 if (fd < 0)
1011 return ERR_FILE_ERROR; 1019 return ERR_FILE_ERROR;
1012 1020
1013 size_t size = filesize(fd); 1021 size_t size = 0;
1022#ifdef HAVE_ALBUMART
1023 if (type == TYPE_BITMAP)
1024 { /* if albumart is embedded, the complete file is not buffered,
1025 * but only the jpeg part; filesize() would be wrong */
1026 struct bufopen_bitmap_data *aa = (struct bufopen_bitmap_data*)user_data;
1027 if (aa->embedded_albumart)
1028 size = aa->embedded_albumart->size;
1029 }
1030#endif
1031 if (size == 0)
1032 size = filesize(fd);
1014 bool can_wrap = type==TYPE_PACKET_AUDIO || type==TYPE_CODEC; 1033 bool can_wrap = type==TYPE_PACKET_AUDIO || type==TYPE_CODEC;
1015 1034
1016 size_t adjusted_offset = offset; 1035 size_t adjusted_offset = offset;
@@ -1058,7 +1077,7 @@ int bufopen(const char *file, size_t offset, enum data_type type,
1058 /* Bitmap file: we load the data instead of the file */ 1077 /* Bitmap file: we load the data instead of the file */
1059 int rc; 1078 int rc;
1060 mutex_lock(&llist_mod_mutex); /* Lock because load_bitmap yields */ 1079 mutex_lock(&llist_mod_mutex); /* Lock because load_bitmap yields */
1061 rc = load_image(fd, file, (struct dim*)user_data); 1080 rc = load_image(fd, file, (struct bufopen_bitmap_data*)user_data);
1062 mutex_unlock(&llist_mod_mutex); 1081 mutex_unlock(&llist_mod_mutex);
1063 if (rc <= 0) 1082 if (rc <= 0)
1064 { 1083 {
diff --git a/apps/metadata.h b/apps/metadata.h
index b99d4d09d6..8d20882835 100644
--- a/apps/metadata.h
+++ b/apps/metadata.h
@@ -190,6 +190,22 @@ enum {
190 ID3_VER_2_4 190 ID3_VER_2_4
191}; 191};
192 192
193#ifdef HAVE_ALBUMART
194enum mp3_aa_type {
195 AA_TYPE_UNSYNC = -1,
196 AA_TYPE_UNKNOWN,
197 AA_TYPE_BMP,
198 AA_TYPE_PNG,
199 AA_TYPE_JPG,
200};
201
202struct mp3_albumart {
203 enum mp3_aa_type type;
204 int size;
205 off_t pos;
206};
207#endif
208
193struct mp3entry { 209struct mp3entry {
194 char path[MAX_PATH]; 210 char path[MAX_PATH];
195 char* title; 211 char* title;
@@ -277,6 +293,11 @@ struct mp3entry {
277 long album_peak; 293 long album_peak;
278#endif 294#endif
279 295
296#ifdef HAVE_ALBUMART
297 bool embed_albumart;
298 struct mp3_albumart albumart;
299#endif
300
280 /* Cuesheet support */ 301 /* Cuesheet support */
281 struct cuesheet *cuesheet; 302 struct cuesheet *cuesheet;
282 303
diff --git a/apps/metadata/id3tags.c b/apps/metadata/id3tags.c
index 75056a273c..a20a59f06e 100644
--- a/apps/metadata/id3tags.c
+++ b/apps/metadata/id3tags.c
@@ -290,6 +290,63 @@ static int parsegenre( struct mp3entry* entry, char* tag, int bufferpos )
290 } 290 }
291} 291}
292 292
293#ifdef HAVE_ALBUMART
294/* parse embed albumart */
295static int parsealbumart( struct mp3entry* entry, char* tag, int bufferpos )
296{
297 entry->embed_albumart = false;
298
299 /* we currently don't support unsynchronizing albumart */
300 if (entry->albumart.type == AA_TYPE_UNSYNC)
301 return bufferpos;
302
303 entry->albumart.type = AA_TYPE_UNKNOWN;
304
305 char *start = tag;
306 /* skip text encoding */
307 tag += 1;
308
309 if (memcmp(tag, "image/", 6) == 0)
310 {
311 /* ID3 v2.3+ */
312 tag += 6;
313 if (strcmp(tag, "jpeg") == 0)
314 {
315 entry->albumart.type = AA_TYPE_JPG;
316 tag += 5;
317 }
318 else if (strcmp(tag, "png") == 0)
319 {
320 entry->albumart.type = AA_TYPE_PNG;
321 tag += 4;
322 }
323 }
324 else
325 {
326 /* ID3 v2.2 */
327 if (memcmp(tag, "JPG", 3) == 0)
328 entry->albumart.type = AA_TYPE_JPG;
329 else if (memcmp(tag, "PNG", 3) == 0)
330 entry->albumart.type = AA_TYPE_PNG;
331 tag += 3;
332 }
333
334 if (entry->albumart.type != AA_TYPE_UNKNOWN)
335 {
336 /* skip picture type */
337 tag += 1;
338 /* skip description */
339 tag = strchr(tag, '\0') + 1;
340 /* fixup offset&size for image data */
341 entry->albumart.pos += tag - start;
342 entry->albumart.size -= tag - start;
343 entry->embed_albumart = true;
344 }
345 /* return bufferpos as we didn't store anything in id3v2buf */
346 return bufferpos;
347}
348#endif
349
293/* parse user defined text, looking for album artist and replaygain 350/* parse user defined text, looking for album artist and replaygain
294 * information. 351 * information.
295 */ 352 */
@@ -439,6 +496,10 @@ static const struct tag_resolver taglist[] = {
439 { "COM", 3, offsetof(struct mp3entry, comment), NULL, false }, 496 { "COM", 3, offsetof(struct mp3entry, comment), NULL, false },
440 { "TCON", 4, offsetof(struct mp3entry, genre_string), &parsegenre, false }, 497 { "TCON", 4, offsetof(struct mp3entry, genre_string), &parsegenre, false },
441 { "TCO", 3, offsetof(struct mp3entry, genre_string), &parsegenre, false }, 498 { "TCO", 3, offsetof(struct mp3entry, genre_string), &parsegenre, false },
499#ifdef HAVE_ALBUMART
500 { "APIC", 4, 0, &parsealbumart, true },
501 { "PIC", 3, 0, &parsealbumart, true },
502#endif
442 { "TXXX", 4, 0, &parseuser, false }, 503 { "TXXX", 4, 0, &parseuser, false },
443#if CONFIG_CODEC == SWCODEC 504#if CONFIG_CODEC == SWCODEC
444 { "RVA2", 4, 0, &parserva2, true }, 505 { "RVA2", 4, 0, &parserva2, true },
@@ -961,6 +1022,21 @@ void setid3v2title(int fd, struct mp3entry *entry)
961 if (ptag && !*ptag) 1022 if (ptag && !*ptag)
962 *ptag = tag; 1023 *ptag = tag;
963 1024
1025 /* albumart */
1026 if ((!entry->embed_albumart) &&
1027 ((tr->tag_length == 4 && !memcmp( header, "APIC", 4)) ||
1028 (tr->tag_length == 3 && !memcmp( header, "PIC" , 3))))
1029 {
1030 if (unsynch || (global_unsynch && version <= ID3_VER_2_3))
1031 entry->albumart.type = AA_TYPE_UNSYNC;
1032 else
1033 {
1034 entry->albumart.pos = lseek(fd, 0, SEEK_CUR) - framelen;
1035 entry->albumart.size = totframelen;
1036 entry->albumart.type = AA_TYPE_UNKNOWN;
1037 }
1038 }
1039
964 if( tr->ppFunc ) 1040 if( tr->ppFunc )
965 bufferpos = tr->ppFunc(entry, tag, bufferpos); 1041 bufferpos = tr->ppFunc(entry, tag, bufferpos);
966 1042
diff --git a/apps/playback.c b/apps/playback.c
index fe7b74893a..9030161f4a 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -142,6 +142,7 @@ static struct cuesheet *curr_cue = NULL;
142#define MAX_MULTIPLE_AA SKINNABLE_SCREENS_COUNT 142#define MAX_MULTIPLE_AA SKINNABLE_SCREENS_COUNT
143 143
144#ifdef HAVE_ALBUMART 144#ifdef HAVE_ALBUMART
145
145static struct albumart_slot { 146static struct albumart_slot {
146 struct dim dim; /* holds width, height of the albumart */ 147 struct dim dim; /* holds width, height of the albumart */
147 int used; /* counter, increments if something uses it */ 148 int used; /* counter, increments if something uses it */
@@ -228,7 +229,6 @@ static bool audio_have_tracks(void);
228static void audio_reset_buffer(void); 229static void audio_reset_buffer(void);
229static void audio_stop_playback(void); 230static void audio_stop_playback(void);
230 231
231
232/**************************************/ 232/**************************************/
233 233
234 234
@@ -647,6 +647,7 @@ bool audio_peek_track(struct mp3entry** id3, int offset)
647} 647}
648 648
649#ifdef HAVE_ALBUMART 649#ifdef HAVE_ALBUMART
650
650int playback_current_aa_hid(int slot) 651int playback_current_aa_hid(int slot)
651{ 652{
652 if (slot < 0) 653 if (slot < 0)
@@ -656,13 +657,13 @@ int playback_current_aa_hid(int slot)
656 657
657 cur_idx = track_ridx + offset; 658 cur_idx = track_ridx + offset;
658 cur_idx &= MAX_TRACK_MASK; 659 cur_idx &= MAX_TRACK_MASK;
659
660 return tracks[cur_idx].aa_hid[slot]; 660 return tracks[cur_idx].aa_hid[slot];
661} 661}
662 662
663int playback_claim_aa_slot(struct dim *dim) 663int playback_claim_aa_slot(struct dim *dim)
664{ 664{
665 int i; 665 int i;
666
666 /* first try to find a slot already having the size to reuse it 667 /* first try to find a slot already having the size to reuse it
667 * since we don't want albumart of the same size buffered multiple times */ 668 * since we don't want albumart of the same size buffered multiple times */
668 FOREACH_ALBUMART(i) 669 FOREACH_ALBUMART(i)
@@ -693,6 +694,7 @@ void playback_release_aa_slot(int slot)
693{ 694{
694 /* invalidate the albumart_slot */ 695 /* invalidate the albumart_slot */
695 struct albumart_slot *aa_slot = &albumart_slots[slot]; 696 struct albumart_slot *aa_slot = &albumart_slots[slot];
697
696 if (aa_slot->used > 0) 698 if (aa_slot->used > 0)
697 aa_slot->used--; 699 aa_slot->used--;
698} 700}
@@ -1315,19 +1317,37 @@ static void audio_finish_load_track(void)
1315 { 1317 {
1316 int i; 1318 int i;
1317 char aa_path[MAX_PATH]; 1319 char aa_path[MAX_PATH];
1320
1318 FOREACH_ALBUMART(i) 1321 FOREACH_ALBUMART(i)
1319 { 1322 {
1320 /* albumart_slots may change during a yield of bufopen, 1323 /* albumart_slots may change during a yield of bufopen,
1321 * but that's no problem */ 1324 * but that's no problem */
1322 if (tracks[track_widx].aa_hid[i] >= 0 || !albumart_slots[i].used) 1325 if (tracks[track_widx].aa_hid[i] >= 0 || !albumart_slots[i].used)
1323 continue; 1326 continue;
1327
1328 /* we can only decode jpeg for embedded AA */
1329 bool embedded_albumart =
1330 track_id3->embed_albumart && track_id3->albumart.type == AA_TYPE_JPG;
1324 /* find_albumart will error out if the wps doesn't have AA */ 1331 /* find_albumart will error out if the wps doesn't have AA */
1325 if (find_albumart(track_id3, aa_path, sizeof(aa_path), 1332 if (embedded_albumart || find_albumart(track_id3, aa_path,
1326 &(albumart_slots[i].dim))) 1333 sizeof(aa_path), &(albumart_slots[i].dim)))
1327 { 1334 {
1328 int aa_hid = bufopen(aa_path, 0, TYPE_BITMAP, 1335 int aa_hid;
1329 &(albumart_slots[i].dim)); 1336 struct bufopen_bitmap_data user_data = {
1330 1337 .dim = &(albumart_slots[i].dim),
1338 .embedded_albumart = NULL,
1339 };
1340 if (embedded_albumart)
1341 {
1342 user_data.embedded_albumart = &(track_id3->albumart);
1343 aa_hid = bufopen(track_id3->path, 0,
1344 TYPE_BITMAP, &user_data);
1345 }
1346 else
1347 {
1348 aa_hid = bufopen(aa_path, 0, TYPE_BITMAP,
1349 &user_data);
1350 }
1331 if(aa_hid == ERR_BUFFER_FULL) 1351 if(aa_hid == ERR_BUFFER_FULL)
1332 { 1352 {
1333 filling = STATE_FULL; 1353 filling = STATE_FULL;
@@ -1342,7 +1362,6 @@ static void audio_finish_load_track(void)
1342 tracks[track_widx].aa_hid[i] = aa_hid; 1362 tracks[track_widx].aa_hid[i] = aa_hid;
1343 } 1363 }
1344 } 1364 }
1345
1346 } 1365 }
1347#endif 1366#endif
1348 1367
diff --git a/apps/playback.h b/apps/playback.h
index 27e27ff240..475e2fb662 100644
--- a/apps/playback.h
+++ b/apps/playback.h
@@ -29,6 +29,7 @@
29#ifdef HAVE_ALBUMART 29#ifdef HAVE_ALBUMART
30 30
31#include "bmp.h" 31#include "bmp.h"
32#include "metadata.h"
32/* 33/*
33 * Returns the handle id of the buffered albumart for the given slot id 34 * Returns the handle id of the buffered albumart for the given slot id
34 **/ 35 **/
@@ -50,6 +51,12 @@ int playback_claim_aa_slot(struct dim *dim);
50 * 51 *
51 * Save to call from other threads */ 52 * Save to call from other threads */
52void playback_release_aa_slot(int slot); 53void playback_release_aa_slot(int slot);
54
55struct bufopen_bitmap_data {
56 struct dim *dim;
57 struct mp3_albumart *embedded_albumart;
58};
59
53#endif 60#endif
54 61
55/* Functions */ 62/* Functions */
diff --git a/apps/recorder/jpeg_load.c b/apps/recorder/jpeg_load.c
index 1af65fab6c..cd13934921 100644
--- a/apps/recorder/jpeg_load.c
+++ b/apps/recorder/jpeg_load.c
@@ -75,12 +75,12 @@ struct jpeg
75{ 75{
76#ifdef JPEG_FROM_MEM 76#ifdef JPEG_FROM_MEM
77 unsigned char *data; 77 unsigned char *data;
78 unsigned long len;
79#else 78#else
80 int fd; 79 int fd;
81 int buf_left; 80 int buf_left;
82 int buf_index; 81 int buf_index;
83#endif 82#endif
83 unsigned long len;
84 unsigned long int bitbuf; 84 unsigned long int bitbuf;
85 int bitbuf_bits; 85 int bitbuf_bits;
86 int marker_ind; 86 int marker_ind;
@@ -888,8 +888,12 @@ INLINE void jpeg_putc(struct jpeg* p_jpeg)
888#else 888#else
889INLINE void fill_buf(struct jpeg* p_jpeg) 889INLINE void fill_buf(struct jpeg* p_jpeg)
890{ 890{
891 p_jpeg->buf_left = read(p_jpeg->fd, p_jpeg->buf, JPEG_READ_BUF_SIZE); 891 p_jpeg->buf_left = read(p_jpeg->fd, p_jpeg->buf,
892 (p_jpeg->len >= JPEG_READ_BUF_SIZE)?
893 JPEG_READ_BUF_SIZE : p_jpeg->len);
892 p_jpeg->buf_index = 0; 894 p_jpeg->buf_index = 0;
895 if (p_jpeg->buf_left > 0)
896 p_jpeg->len -= p_jpeg->buf_left;
893} 897}
894 898
895static unsigned char *jpeg_getc(struct jpeg* p_jpeg) 899static unsigned char *jpeg_getc(struct jpeg* p_jpeg)
@@ -1960,7 +1964,9 @@ block_end:
1960 * 1964 *
1961 *****************************************************************************/ 1965 *****************************************************************************/
1962#ifndef JPEG_FROM_MEM 1966#ifndef JPEG_FROM_MEM
1963int read_jpeg_file(const char* filename, 1967int clip_jpeg_file(const char* filename,
1968 int offset,
1969 unsigned long jpeg_size,
1964 struct bitmap *bm, 1970 struct bitmap *bm,
1965 int maxsize, 1971 int maxsize,
1966 int format, 1972 int format,
@@ -1975,11 +1981,20 @@ int read_jpeg_file(const char* filename,
1975 DEBUGF("read_jpeg_file: can't open '%s', rc: %d\n", filename, fd); 1981 DEBUGF("read_jpeg_file: can't open '%s', rc: %d\n", filename, fd);
1976 return fd * 10 - 1; 1982 return fd * 10 - 1;
1977 } 1983 }
1978 1984 lseek(fd, offset, SEEK_SET);
1979 ret = read_jpeg_fd(fd, bm, maxsize, format, cformat); 1985 ret = clip_jpeg_fd(fd, jpeg_size, bm, maxsize, format, cformat);
1980 close(fd); 1986 close(fd);
1981 return ret; 1987 return ret;
1982} 1988}
1989
1990int read_jpeg_file(const char* filename,
1991 struct bitmap *bm,
1992 int maxsize,
1993 int format,
1994 const struct custom_format *cformat)
1995{
1996 return clip_jpeg_file(filename, 0, 0, bm, maxsize, format, cformat);
1997}
1983#endif 1998#endif
1984 1999
1985static int calc_scale(int in_size, int out_size) 2000static int calc_scale(int in_size, int out_size)
@@ -2014,10 +2029,11 @@ int get_jpeg_dim_mem(unsigned char *data, unsigned long len,
2014 return 0; 2029 return 0;
2015} 2030}
2016 2031
2017int decode_jpeg_mem(unsigned char *data, unsigned long len, 2032int decode_jpeg_mem(unsigned char *data,
2018#else 2033#else
2019int read_jpeg_fd(int fd, 2034int clip_jpeg_fd(int fd,
2020#endif 2035#endif
2036 unsigned long len,
2021 struct bitmap *bm, 2037 struct bitmap *bm,
2022 int maxsize, 2038 int maxsize,
2023 int format, 2039 int format,
@@ -2039,11 +2055,13 @@ int read_jpeg_fd(int fd,
2039 return -1; 2055 return -1;
2040#endif 2056#endif
2041 memset(p_jpeg, 0, sizeof(struct jpeg)); 2057 memset(p_jpeg, 0, sizeof(struct jpeg));
2058 p_jpeg->len = len;
2042#ifdef JPEG_FROM_MEM 2059#ifdef JPEG_FROM_MEM
2043 p_jpeg->data = data; 2060 p_jpeg->data = data;
2044 p_jpeg->len = len;
2045#else 2061#else
2046 p_jpeg->fd = fd; 2062 p_jpeg->fd = fd;
2063 if (p_jpeg->len == 0)
2064 p_jpeg->len = filesize(p_jpeg->fd);
2047#endif 2065#endif
2048 status = process_markers(p_jpeg); 2066 status = process_markers(p_jpeg);
2049#ifndef JPEG_FROM_MEM 2067#ifndef JPEG_FROM_MEM
@@ -2212,4 +2230,13 @@ int read_jpeg_fd(int fd,
2212 return 0; 2230 return 0;
2213} 2231}
2214 2232
2233int read_jpeg_fd(int fd,
2234 struct bitmap *bm,
2235 int maxsize,
2236 int format,
2237 const struct custom_format *cformat)
2238{
2239 return clip_jpeg_fd(fd, 0, bm, maxsize, format, cformat);
2240}
2241
2215/**************** end JPEG code ********************/ 2242/**************** end JPEG code ********************/
diff --git a/apps/recorder/jpeg_load.h b/apps/recorder/jpeg_load.h
index 73b6c51bf3..6ff96dabad 100644
--- a/apps/recorder/jpeg_load.h
+++ b/apps/recorder/jpeg_load.h
@@ -44,4 +44,27 @@ int read_jpeg_fd(int fd,
44 int format, 44 int format,
45 const struct custom_format *cformat); 45 const struct custom_format *cformat);
46 46
47/**
48 * read embedded jpeg files as above. Needs an offset and length into
49 * the file
50 **/
51int clip_jpeg_file(const char* filename,
52 int offset,
53 unsigned long jpeg_size,
54 struct bitmap *bm,
55 int maxsize,
56 int format,
57 const struct custom_format *cformat);
58
59/**
60 * read embedded jpeg files as above. Needs an open file descripter, and
61 * assumes the caller has lseek()'d to the start of the jpeg blob
62 **/
63int clip_jpeg_fd(int fd,
64 unsigned long jpeg_size,
65 struct bitmap *bm,
66 int maxsize,
67 int format,
68 const struct custom_format *cformat);
69
47#endif /* _JPEG_JPEG_DECODER_H */ 70#endif /* _JPEG_JPEG_DECODER_H */