Index: apps/plugins/properties.c =================================================================== --- apps/plugins/properties.c (revision 15306) +++ apps/plugins/properties.c (working copy) @@ -100,7 +100,7 @@ static bool file_properties(char* select #if (CONFIG_CODEC == SWCODEC) int fd = rb->open(selected_file, O_RDONLY); if (fd >= 0 && - rb->get_metadata(&id3, fd, selected_file)) + rb->get_metadata(&id3, fd, selected_file, false)) #else if (!rb->mp3info(&id3, selected_file)) #endif Index: apps/gui/gwps-common.c =================================================================== --- apps/gui/gwps-common.c (revision 15306) +++ apps/gui/gwps-common.c (working copy) @@ -73,9 +73,12 @@ void gui_wps_statusbar_draw(struct gui_w if (draw) gui_statusbar_draw(wps->statusbar, force); } + +static bool wps_data_albumart_load(struct gui_wps *gwps); #else #define gui_wps_statusbar_draw(wps, force) \ gui_statusbar_draw((wps)->statusbar, (force)) +#define wps_data_albumart_load(dummy) #endif /* fades the volume */ @@ -348,6 +351,7 @@ bool gui_wps_display(void) yield(); FOR_NB_SCREENS(i) { + wps_data_albumart_load(&gui_wps[i]); gui_wps_refresh(&gui_wps[i], 0, WPS_REFRESH_ALL); } return false; @@ -364,6 +368,9 @@ bool update(struct gui_wps *gwps) gwps->display->stop_scroll(); gwps->state->id3 = audio_current_track(); + /* track has changed : update the album art information */ + wps_data_albumart_load(gwps); + if (cuesheet_is_enabled() && gwps->state->id3->cuesheet_type && strcmp(gwps->state->id3->path, curr_cue->audio_filename)) { @@ -555,6 +562,88 @@ static void wps_display_images(struct gu display->set_drawmode(DRMODE_SOLID); } +static bool wps_data_albumart_load(struct gui_wps *gwps) +{ + if(!gwps || !gwps->data) + return false; + +// if(gwps->data->wps_uses_albumart == WPS_ALBUMART_NONE) +// return false; + + if(!gwps->display || gwps->display->depth < 16) + return false; + + if(!gwps->state->id3->albumart_found) + return false; + + struct wps_data * data = gwps->data; + + if(0 == strcasecmp(gwps->state->id3->albumart_path, data->cur_displayed_albumart_path)) + { + /* new bitmap is same as old bitmap - trivially succeed */ + gwps->state->id3->albumart_data = (fb_data *)data->img_buf_ptr; + gwps->state->id3->albumart_width = data->cur_displayed_albumart_width; + gwps->state->id3->albumart_height = data->cur_displayed_albumart_height; + + return true; + } + + int rc; + struct bitmap temp_bitmap; + temp_bitmap.data = data->img_buf_ptr; + rc = read_bmp_file(gwps->state->id3->albumart_path, &temp_bitmap, data->img_buf_free, FORMAT_ANY|FORMAT_TRANSPARENT); + if(rc <= 0) + { + /* load failed */ + gwps->state->id3->albumart_data = NULL; + data->cur_displayed_albumart_path[0] = '\0'; + return false; + } + + data->cur_displayed_albumart_width = gwps->state->id3->albumart_width = temp_bitmap.width; + data->cur_displayed_albumart_height = gwps->state->id3->albumart_height = temp_bitmap.height; + gwps->state->id3->albumart_data = (fb_data *)temp_bitmap.data; + strcpy(data->cur_displayed_albumart_path, gwps->state->id3->albumart_path); + return true; +} + +static void draw_album_art(struct gui_wps *gwps) +{ + if(!gwps || !gwps->data || !gwps->display) + return; + + struct wps_data * data = gwps->data; + if(data->wps_uses_albumart == WPS_ALBUMART_NONE) + return; + + if(!gwps->state->id3->albumart_found || gwps->state->id3->albumart_data == NULL) + return; + + short x = data->albumart_x; + short y = data->albumart_y; + if(data->albumart_max_width>0) + { + if (data->albumart_xalign & WPS_ALBUMART_ALIGN_RIGHT) + x += data->albumart_max_width - gwps->state->id3->albumart_width; + else if (data->albumart_xalign & WPS_ALBUMART_ALIGN_CENTER) + x += (data->albumart_max_width - gwps->state->id3->albumart_width)/2; + } + if(data->albumart_max_height>0) + { + if (data->albumart_yalign & WPS_ALBUMART_ALIGN_BOTTOM) + y += data->albumart_max_height - gwps->state->id3->albumart_height; + else if (data->albumart_yalign & WPS_ALBUMART_ALIGN_CENTER) + y += (data->albumart_max_height - gwps->state->id3->albumart_height)/2; + } + + gwps->display->set_drawmode(DRMODE_FG); + gwps->display->bitmap((fb_data*)gwps->state->id3->albumart_data, + x, y, + gwps->state->id3->albumart_width, + gwps->state->id3->albumart_height ); + gwps->display->set_drawmode(DRMODE_SOLID); +} + #else /* HAVE_LCD_CHARCELL */ static bool draw_player_progress(struct gui_wps *gwps) @@ -929,6 +1018,19 @@ static char *get_token_value(struct gui_ case WPS_TOKEN_METADATA_COMMENT: return id3->comment; +#ifdef HAVE_LCD_BITMAP + case WPS_TOKEN_ALBUMART_DISPLAY: + draw_album_art(gwps); + return NULL; + + case WPS_TOKEN_ALBUMART_FOUND: + if(id3->albumart_found) { + snprintf(buf, buf_size, "C"); + return buf; + } + return NULL; +#endif + case WPS_TOKEN_FILE_BITRATE: if(id3->bitrate) snprintf(buf, buf_size, "%d", id3->bitrate); Index: apps/gui/gwps.c =================================================================== --- apps/gui/gwps.c (revision 15306) +++ apps/gui/gwps.c (working copy) @@ -794,3 +794,24 @@ void gui_sync_wps_init(void) unload_remote_wps_backdrop(); #endif } + +/* +** returns true if at least one of the gui_wps screens +** has an albumart tag in its wps structure +*/ +bool gui_sync_wps_uses_albumart(void) +{ +#if 0 + int i; + FOR_NB_SCREENS(i) { + struct gui_wps *gwps = &gui_wps[i]; + if (gwps->data && (gwps->data->wps_uses_albumart != WPS_ALBUMART_NONE)) + return true; + } + return false; +#else + return true; /* If wps has albumart tag or not, always returns true */ +#endif +} + +/* vi: set ts=4 sts=4 sw=4 et ai: */ Index: apps/gui/gwps.h =================================================================== --- apps/gui/gwps.h (revision 15306) +++ apps/gui/gwps.h (working copy) @@ -39,6 +39,19 @@ #define WPS_ALIGN_CENTER 64 #define WPS_ALIGN_LEFT 128 +/* albumart definitions */ +#define WPS_ALBUMART_NONE 0 /* WPS does not contain AA tag */ +#define WPS_ALBUMART_CHECK 1 /* WPS contains AA conditional tag */ +#define WPS_ALBUMART_LOAD 2 /* WPS contains AA tag */ + +#define WPS_ALBUMART_ALIGN_RIGHT WPS_ALIGN_RIGHT /* x align: right */ +#define WPS_ALBUMART_ALIGN_CENTER WPS_ALIGN_CENTER /* x/y align: center */ +#define WPS_ALBUMART_ALIGN_LEFT WPS_ALIGN_LEFT /* x align: left */ +#define WPS_ALBUMART_ALIGN_TOP WPS_ALIGN_RIGHT /* y align: top */ +#define WPS_ALBUMART_ALIGN_BOTTOM WPS_ALIGN_LEFT /* y align: bottom */ +#define WPS_ALBUMART_INCREASE 8 /* increase if smaller */ +#define WPS_ALBUMART_DECREASE 16 /* decrease if larger */ + /* wps_data*/ #ifdef HAVE_LCD_BITMAP @@ -185,6 +198,10 @@ enum wps_token_type { WPS_TOKEN_IMAGE_PRELOAD, WPS_TOKEN_IMAGE_PRELOAD_DISPLAY, WPS_TOKEN_IMAGE_DISPLAY, + + /* Albumart */ + WPS_TOKEN_ALBUMART_DISPLAY, + WPS_TOKEN_ALBUMART_FOUND, #endif /* Metadata */ @@ -309,6 +326,19 @@ struct wps_data short progress_start; short progress_end; bool peak_meter_enabled; + + /* Album art additions */ + unsigned char wps_uses_albumart; /* WPS_ALBUMART_NONE, WPS_ALBUMART_CHECK, WPS_ALBUMART_LOAD */ + short albumart_x; + short albumart_y; + unsigned short albumart_xalign; /* WPS_ALBUMART_ALIGN_LEFT, .._CENTER, .._RIGHT, + .._INCREASE, + .._DECREASE */ + unsigned short albumart_yalign; /* WPS_ALBUMART_ALIGN_TOP, .._CENTER, .._BOTTOM, + .._INCREASE, + .._DECREASE */ + short albumart_max_width; + short albumart_max_height; + char cur_displayed_albumart_path[MAX_PATH]; /* Information about the */ + short cur_displayed_albumart_width; /* currently displayed */ + short cur_displayed_albumart_height; /* album art bitmap */ + #else /*HAVE_LCD_CHARCELLS */ unsigned short wps_progress_pat[8]; bool full_line_progressbar; @@ -417,4 +447,7 @@ extern struct gui_wps gui_wps[NB_SCREENS void gui_sync_wps_init(void); void gui_sync_wps_screen_init(void); +/* gives back if WPS contains an albumart tag */ +bool gui_sync_wps_uses_albumart(void); + #endif Index: apps/gui/wps_parser.c =================================================================== --- apps/gui/wps_parser.c (revision 15306) +++ apps/gui/wps_parser.c (working copy) @@ -124,6 +124,10 @@ static int parse_image_display(const cha struct wps_token *token, struct wps_data *wps_data); static int parse_image_load(const char *wps_bufptr, struct wps_token *token, struct wps_data *wps_data); +static int parse_albumart_load(const char *wps_bufptr, + struct wps_token *token, struct wps_data *wps_data); +static int parse_albumart_conditional(const char *wps_bufptr, + struct wps_token *token, struct wps_data *wps_data); #endif /*HAVE_LCD_BITMAP */ #ifdef CONFIG_RTC @@ -283,6 +287,8 @@ static const struct wps_tag all_tags[] = { WPS_TOKEN_IMAGE_DISPLAY, "x", 0, parse_image_load }, { WPS_TOKEN_IMAGE_PROGRESS_BAR, "P", 0, parse_image_special }, + { WPS_NO_TOKEN, "Cl", 0, parse_albumart_load }, + { WPS_TOKEN_ALBUMART_DISPLAY, "C", WPS_REFRESH_DYNAMIC, parse_albumart_conditional }, #if (LCD_DEPTH > 1) || (defined(HAVE_LCD_REMOTE) && (LCD_REMOTE_DEPTH > 1)) { WPS_TOKEN_IMAGE_BACKDROP, "X", 0, parse_image_special }, #endif @@ -606,6 +612,192 @@ static int parse_progressbar(const char #endif } +#ifdef HAVE_LCD_BITMAP +static int parse_albumart_load(const char *wps_bufptr, + struct wps_token *token, + struct wps_data *wps_data) +{ + const char* _pos; + bool parsing; + const short xalign_mask = WPS_ALBUMART_ALIGN_LEFT | WPS_ALBUMART_ALIGN_CENTER | WPS_ALBUMART_ALIGN_RIGHT; + const short yalign_mask = WPS_ALBUMART_ALIGN_TOP | WPS_ALBUMART_ALIGN_CENTER | WPS_ALBUMART_ALIGN_BOTTOM; + + (void)(token); /* silence warning */ + + /* reset albumart info in wps */ + wps_data->wps_uses_albumart = WPS_ALBUMART_NONE; + wps_data->albumart_max_width = -1; + wps_data->albumart_max_height = -1; + wps_data->albumart_xalign = WPS_ALBUMART_ALIGN_CENTER; /* default */ + wps_data->albumart_yalign = WPS_ALBUMART_ALIGN_CENTER; /* default */ + + /* format: %Cl|x|y|[[l|c|r][d|i|s]mwidth]|[[t|c|b][d|i|s]mheight]| */ + /* initial validation and parsing of x and y components */ + if(*wps_bufptr!='|') + return(0); /* malformed token: e.g. %Cl7 */ + + _pos=wps_bufptr+1; + if(!isdigit(*_pos)) + return(0); /* malformed token: e.g. %Cl|@ */ + wps_data->albumart_x = atoi(_pos); + + _pos=strchr(_pos,'|'); + if(!_pos || !isdigit(*(++_pos))) + return(0); /* malformed token: e.g. %Cl|7\n or %Cl|7|@ */ + + wps_data->albumart_y = atoi(_pos); + + _pos=strchr(_pos,'|'); + if(!_pos) + return(0); /* malformed token: e.g. %Cl|7|59\n (no | after y coordinate) */ + + /* parsing width field */ + parsing=true; + while(parsing) + { + /* apply each modifier in turn */ + ++_pos; + switch(*_pos) + { + case 'l': + case 'L': + case '+': + wps_data->albumart_xalign = (wps_data->albumart_xalign & xalign_mask) | WPS_ALBUMART_ALIGN_LEFT; + break; + case 'c': + case 'C': + wps_data->albumart_xalign = (wps_data->albumart_xalign & xalign_mask) | WPS_ALBUMART_ALIGN_CENTER; + break; + case 'r': + case 'R': + case '-': + wps_data->albumart_xalign = (wps_data->albumart_xalign & xalign_mask) | WPS_ALBUMART_ALIGN_RIGHT; + break; + case 'd': + case 'D': + wps_data->albumart_xalign |= WPS_ALBUMART_DECREASE; + break; + case 'i': + case 'I': + wps_data->albumart_xalign |= WPS_ALBUMART_INCREASE; + break; + case 's': + case 'S': + wps_data->albumart_xalign |= (WPS_ALBUMART_DECREASE | WPS_ALBUMART_INCREASE); + break; + default: + parsing = false; + break; + } + } + /* extract max width data */ + if(*_pos != '|') + { + if(!isdigit(*_pos)) + return(0); /* malformed token: e.g. %Cl|7|59|# */ + wps_data->albumart_max_width = atoi(_pos); + _pos = strchr(_pos,'|'); + if(!_pos) + return(0); /* malformed token: e.g. %Cl|7|59|200\n (no | after width field) */ + } + + /* parsing height field */ + parsing=true; + while(parsing) + { + /* apply each modifier in turn */ + ++_pos; + switch(*_pos) + { + case 't': + case 'T': + case 'r': /* yuck */ + case 'R': + case '-': + wps_data->albumart_yalign = (wps_data->albumart_yalign & yalign_mask) | WPS_ALBUMART_ALIGN_TOP; + break; + case 'c': + case 'C': + wps_data->albumart_yalign = (wps_data->albumart_yalign & yalign_mask) | WPS_ALBUMART_ALIGN_CENTER; + break; + case 'b': + case 'B': + case 'l': /* yuck */ + case 'L': + case '+': + wps_data->albumart_yalign = (wps_data->albumart_yalign & yalign_mask) | WPS_ALBUMART_ALIGN_BOTTOM; + break; + case 'd': + case 'D': + wps_data->albumart_yalign |= WPS_ALBUMART_DECREASE; + break; + case 'i': + case 'I': + wps_data->albumart_yalign |= WPS_ALBUMART_INCREASE; + break; + case 's': + case 'S': + wps_data->albumart_yalign |= (WPS_ALBUMART_DECREASE | WPS_ALBUMART_INCREASE); + break; + default: + parsing = false; + break; + } + } + /* extract max height data */ + if(*_pos != '|') + { + if(!isdigit(*_pos)) + return(0); /* malformed token e.g. %Cl|7|59|200|@ */ + wps_data->albumart_max_height = atoi(_pos); + _pos = strchr(_pos, '|'); + if(!_pos) + return(0); /* malformed token e.g. %Cl|7|59|200|200\n (no closing |) */ + } + + /* if we got here, we parsed everything ok .. ! */ + if(wps_data->albumart_max_width<0) + wps_data->albumart_max_width = 0; + else if(wps_data->albumart_max_width > LCD_WIDTH) + wps_data->albumart_max_width = LCD_WIDTH; + + if(wps_data->albumart_max_height<0) + wps_data->albumart_max_height = 0; + else if(wps_data->albumart_max_height > LCD_HEIGHT) + wps_data->albumart_max_height = LCD_HEIGHT; + + wps_data->wps_uses_albumart = WPS_ALBUMART_LOAD; + + return( _pos - wps_bufptr + 1 ); +} + +static int parse_albumart_conditional(const char *wps_bufptr, struct wps_token *token, struct wps_data *wps_data) +{ + struct wps_token *prevtoken = token; + --prevtoken; + if(wps_data->num_tokens >= 1 && prevtoken->type == WPS_TOKEN_CONDITIONAL) + { + /* This %C is part of a %?C construct. It's either %?C or %?Cn */ + token->type = WPS_TOKEN_ALBUMART_FOUND; + if(*wps_bufptr == 'n' && *(wps_bufptr+1) == '<') + { + token->next = true; + return(1); + } + else if(*wps_bufptr == '<') + { + return(0); + } + else + { + token->type = WPS_NO_TOKEN; + return(0); + } + } + else return 0; +}; +#endif /* HAVE_LCD_BITMAP */ + /* Parse a generic token from the given string. Return the length read */ static int parse_token(const char *wps_bufptr, struct wps_data *wps_data) { @@ -898,6 +1090,9 @@ void wps_data_init(struct wps_data *wps_ wps_data->img_buf_ptr = wps_data->img_buf; /* where in image buffer */ wps_data->img_buf_free = IMG_BUFSIZE; /* free space in image buffer */ wps_data->peak_meter_enabled = false; + wps_data->cur_displayed_albumart_path[0] = '\0'; + wps_data->cur_displayed_albumart_width = -1; + wps_data->cur_displayed_albumart_height = -1; #else /* HAVE_LCD_CHARCELLS */ int i; for (i = 0; i < 8; i++) @@ -915,6 +1110,9 @@ static void wps_reset(struct wps_data *d bool rwps = data->remote_wps; /* remember whether the data is for a RWPS */ #endif memset(data, 0, sizeof(*data)); +#ifdef HAVE_LCD_BITMAP + data->wps_uses_albumart = WPS_ALBUMART_NONE; +#endif wps_data_init(data); #ifdef HAVE_REMOTE_LCD data->remote_wps = rwps; Index: apps/metadata.c =================================================================== --- apps/metadata.c (revision 15306) +++ apps/metadata.c (working copy) @@ -28,6 +28,10 @@ #include "logf.h" #include "cuesheet.h" +#ifdef HAVE_LCD_BITMAP +#include "gwps.h" +#endif + #if CONFIG_CODEC == SWCODEC #include "metadata/metadata_common.h" @@ -90,10 +94,164 @@ unsigned int probe_file_format(const cha return AFMT_UNKNOWN; } +#ifdef HAVE_LCD_BITMAP +/* Strip filename from a full path + * + * buf - buffer to extract directory to. + * buf_size - size of buffer. + * fullpath - fullpath to extract from. + * + * Split the directory part of the given fullpath and store it in buf + * (including last '/'). + * The function return parameter is a pointer to the filename + * inside the given fullpath. + */ +static char* strip_filename(char* buf, int buf_size, const char* fullpath) +{ + char* sep; + int len; + + if (!buf || buf_size <= 0 || !fullpath) + return NULL; + + /* if 'fullpath' is only a filename return immediately */ + sep = strrchr(fullpath, '/'); + if (sep == NULL) + { + buf[0] = 0; + return (char*)fullpath; + } + + len = MIN(sep - fullpath + 1, buf_size - 1); + strncpy(buf, fullpath, len); + buf[len] = 0; + return (sep + 1); +} + +static char* strip_extension(char* buf, int buf_size, const char* file) +{ + char* sep; + int len; + + if (!buf || buf_size <= 0 || !file) + return NULL; + + buf[0] = 0; + + sep = strrchr(file,'.'); + if (sep == NULL) + return NULL; + + len = MIN(sep - file, buf_size - 1); + strncpy(buf, file, len); + buf[len] = 0; + return buf; +} + +static bool file_exists(char *file) +{ + int fd; + + if (!file || strlen(file) <= 0) + return false; + + fd = open(file, O_RDONLY); + if (fd<0) + return false; + close(fd); + return true; +} + +/* Look for albumart bitmap in the same dir as the track and in its parent dir; + * stores the found filename in the track->albumart_path. + * Returns true if a bitmap was found, false otherwise */ +static bool find_albumart(struct mp3entry* id3, const char* trackname) +{ + char path[MAX_PATH + 1]; + char dir[MAX_PATH + 1]; + bool found = false; + + if (!id3 || !trackname) + return false; + + strcpy(id3->albumart_path, ""); + + strip_filename(dir, sizeof(dir), trackname); + + DEBUGF("Looking for album art for %s\n", trackname); + + /* the first file we look for is one specific to the track playing */ + strip_extension(path, sizeof(path) - 4, trackname); + strcat(path, ".bmp"); + found = file_exists(path); + if (!found && id3->album && strlen(id3->album) > 0) + { /* if it doesn't exist, + * we look for a file specific to the track's album name */ + snprintf(path, sizeof(path) - 1, + "%s%s.bmp", + (strlen(dir) >= 1) ? dir : "", + id3->album); + path[sizeof(path) - 1] = 0; + found = file_exists(path); + } + + if (!found) + { + /* if it still doesn't exist, we look for a generic file */ + snprintf(path, sizeof(path)-1, + "%scover.bmp", + (strlen(dir) >= 1) ? dir : ""); + path[sizeof(path)-1] = 0; + found = file_exists(path); + } + + if (!found) + { + /* if it still doesn't exist, + * we continue to search in the parent directory */ + char temp[MAX_PATH + 1]; + strncpy(temp, dir, strlen(dir) - 1); + temp[strlen(dir) - 1] = 0; + + strip_filename(dir, sizeof(dir), temp); + } + + if (!found && id3->album && strlen(id3->album) > 0) + { + /* we look in the parent directory + ** for a file specific to the track's album name */ + snprintf(path, sizeof(path)-1, + "%s%s.bmp", + (strlen(dir) >= 1) ? dir : "", + id3->album); + found = file_exists(path); + } + + if (!found) + { + /* if it still doesn't exist, we look in the parent directory + * for a generic file */ + snprintf(path, sizeof(path)-1, + "%scover.bmp", + (strlen(dir) >= 1) ? dir : ""); + path[sizeof(path)-1] = 0; + found = file_exists(path); + } + + if (!found) + return false; + + strcpy(id3->albumart_path, path); + DEBUGF("Album art found for %s : %s\n", trackname, path); + return true; +} +#endif + /* Get metadata for track - return false if parsing showed problems with the * file that would prevent playback. */ -bool get_metadata(struct mp3entry* id3, int fd, const char* trackname) +bool get_metadata(struct mp3entry* id3, int fd, const char* trackname, + bool search_album_art) { #if CONFIG_CODEC == SWCODEC unsigned char* buf; @@ -315,6 +473,13 @@ bool get_metadata(struct mp3entry* id3, id3->cuesheet_type = 1; } #endif + +#ifdef HAVE_LCD_BITMAP + if (search_album_art && gui_sync_wps_uses_albumart()) + id3->albumart_found = find_albumart(id3, trackname); +#else + (void) search_album_art; +#endif lseek(fd, 0, SEEK_SET); strncpy(id3->path, trackname, sizeof(id3->path)); Index: apps/metadata.h =================================================================== --- apps/metadata.h (revision 15306) +++ apps/metadata.h (working copy) @@ -23,7 +23,8 @@ #include "playback.h" unsigned int probe_file_format(const char *filename); -bool get_metadata(struct mp3entry* id3, int fd, const char* trackname); +bool get_metadata(struct mp3entry* id3, int fd, const char* trackname, + bool search_album_art); #endif Index: apps/tagcache.c =================================================================== --- apps/tagcache.c (revision 15306) +++ apps/tagcache.c (working copy) @@ -1660,7 +1660,7 @@ static void add_tagcache(char *path) memset(&id3, 0, sizeof(struct mp3entry)); memset(&entry, 0, sizeof(struct temp_file_entry)); memset(&tracknumfix, 0, sizeof(tracknumfix)); - ret = get_metadata(&id3, fd, path); + ret = get_metadata(&id3, fd, path, false); close(fd); if (!ret) Index: apps/playback.c =================================================================== --- apps/playback.c (revision 15306) +++ apps/playback.c (working copy) @@ -2409,7 +2409,7 @@ static bool audio_load_track(int offset, /* Get track metadata if we don't already have it. */ if (tracks[track_widx].id3_hid <= 0) { - if (get_metadata(&id3, fd, trackname)) + if (get_metadata(&id3, fd, trackname, true)) { tracks[track_widx].id3_hid = bufalloc(&id3, sizeof(struct mp3entry), TYPE_ID3); Index: apps/plugin.h =================================================================== --- apps/plugin.h (revision 15306) +++ apps/plugin.h (working copy) @@ -583,7 +583,8 @@ struct plugin_api { #if CONFIG_CODEC == SWCODEC int (*codec_load_file)(const char* codec, struct codec_api *api); const char *(*get_codec_filename)(int cod_spec); - bool (*get_metadata)(struct mp3entry* id3, int fd, const char* trackname); + bool (*get_metadata)(struct mp3entry* id3, int fd, const char* trackname, + bool search_album_art); #endif bool (*mp3info)(struct mp3entry *entry, const char *filename); int (*count_mp3_frames)(int fd, int startpos, int filesize, Index: firmware/export/id3.h =================================================================== --- firmware/export/id3.h (revision 15306) +++ firmware/export/id3.h (working copy) @@ -22,6 +22,8 @@ #include #include "config.h" #include "file.h" +#include "lcd.h" +#include "system.h" #define ID3V2_BUF_SIZE 300 @@ -225,6 +227,15 @@ struct mp3entry { /* Cuesheet support */ int cuesheet_type; /* 0: none, 1: external, 2: embedded */ + +#ifdef HAVE_LCD_BITMAP + /* album art support */ + fb_data* albumart_data; + unsigned int albumart_width; + unsigned int albumart_height; + bool albumart_found; + char albumart_path[MAX_PATH]; +#endif }; enum {