diff options
-rw-r--r-- | ChangeLog | 22 | ||||
-rw-r--r-- | src/itdb_artwork.c | 134 | ||||
-rw-r--r-- | src/itdb_device.c | 52 | ||||
-rw-r--r-- | src/itdb_device.h | 14 | ||||
-rw-r--r-- | src/itdb_private.h | 4 | ||||
-rw-r--r-- | src/ithumb-writer.c | 159 |
6 files changed, 318 insertions, 67 deletions
@@ -14,6 +14,28 @@ will NOT be truncated. Patches are welcome (probably add code at the end of ithumb_rearrange_thumbnail_file()) :-) + * itdb_artwork.c: added support for UYVY format for iPod Video and + iPod Photo TV output. Code adapted from the GPixPod project. + + (itdb_thumb_get_byteorder): return the byte order for the + current thumbnail (internal function). + + * itdb_device.[hc]: added thumbnail storage format to the + Itdb_ArtworkFormat image information. Currently the following + are defined: + THUMB_FORMAT_UYVY + THUMB_FORMAT_RGB565_LE + THUMB_FORMAT_RGB565_BE + THUMB_FORMAT_RGB565_BE_90 + THUMB_FORMAT_RGB565_LE_90 + THUMB_FORMAT_RGB565_LE_90 does not appear to be used by any iPod + model. THUMB_FORMAT_RGB565_BE_90 is used for full screen iPod + Photo photos but currently is handeled the same as + THUMB_FORMAT_RGB565_BE pending input from iPod Photo users. + + * ithumb-writer.c: added support for UYVY format for iPod Video and + iPod Photo TV output. Code adapted from the GPixPod project. + 2006-11-11 Jorg Schuler <jcsjcs at users.sourceforge.net> * itdb.h: Itdb_Artwork: diff --git a/src/itdb_artwork.c b/src/itdb_artwork.c index 8c87c87..d1b312e 100644 --- a/src/itdb_artwork.c +++ b/src/itdb_artwork.c @@ -1,4 +1,4 @@ -/* Time-stamp: <2006-09-18 02:23:53 jcs> +/* Time-stamp: <2006-11-12 23:17:20 jcs> | | Copyright (C) 2002-2005 Jorg Schuler <jcsjcs at users sourceforge net> | Part of the gtkpod project. @@ -29,6 +29,7 @@ #include <config.h> +#include "itdb_device.h" #include "itdb_private.h" #include "db-image-parser.h" #include "itdb_endianness.h" @@ -364,6 +365,84 @@ unpack_RGB_565 (guint16 *pixels, guint bytes_len, guint byte_order) } +/* limit8bit() and unpack_UYVY() adapted from imgconvert.c from the + * GPixPod project (www.gpixpod.org) */ +static gint limit8bit (float x) +{ + if(x >= 255) + { + return 255; + } + if(x <= 0) + { + return 0; + } + return x; +} +static guchar * +unpack_UYVY (guchar *yuvdata, gint bytes_len, gint width, gint height) +{ + gint imgsize = width*3*height; + guchar* rgbdata; + gint halfimgsize = imgsize/2; + gint halfyuv = halfimgsize/3*2; + gint x = 0; + gint z = 0; + gint z2 = 0; + gint u0, y0, v0, y1, u1, y2, v1, y3; + gint h = 0; + + g_return_val_if_fail (bytes_len < 2*(G_MAXUINT/3), NULL); + g_return_val_if_fail (width * height * 2 == bytes_len, NULL); + + rgbdata = g_malloc(imgsize); + + while(h < height) + { + gint w = 0; + if((h % 2) == 0) + { + while(w < width) + { + u0 = yuvdata[z]; + y0 = yuvdata[z+1]; + v0 = yuvdata[z+2]; + y1 = yuvdata[z+3]; + rgbdata[x] = limit8bit((y0-16)*1.164 + (v0-128)*1.596);/*R0*/ + rgbdata[x+1] = limit8bit((y0-16)*1.164 - (v0-128)*0.813 - (u0-128)*0.391);/*G0*/ + rgbdata[x+2] = limit8bit((y0-16)*1.164 + (u0-128)*2.018);/*B0*/ + rgbdata[x+3] = limit8bit((y0-16)*1.164 + (v0-128)*1.596);/*R1*/ + rgbdata[x+4] = limit8bit((y1-16)*1.164 - (v0-128)*0.813 - (u0-128)*0.391);/*G1*/ + rgbdata[x+5] = limit8bit((y1-16)*1.164 + (u0-128)*2.018);/*B1*/ + w += 2; + z += 4; + x += 6; + } + } + else + { + while(w < width) + { + u1 = yuvdata[halfyuv+z2]; + y2 = yuvdata[halfyuv+z2+1]; + v1 = yuvdata[halfyuv+z2+2]; + y3 = yuvdata[halfyuv+z2+3]; + rgbdata[x] = limit8bit((y2-16)*1.164 + (v1-128)*1.596); + rgbdata[x+1] = limit8bit((y2-16)*1.164 - (v1-128)*0.813 - (u1-128)*0.391); + rgbdata[x+2] = limit8bit((y2-16)*1.164 + (u1-128)*2.018); + rgbdata[x+3] = limit8bit((y2-16)*1.164 + (v1-128)*1.596); + rgbdata[x+4] = limit8bit((y3-16)*1.164 - (v1-128)*0.813 - (u1-128)*0.391); + rgbdata[x+5] = limit8bit((y3-16)*1.164 + (u1-128)*2.018); + w += 2; + z2 += 4; + x += 6; + } + } + h++; + } + return rgbdata; +} + static guchar * get_pixel_data (Itdb_Device *device, Itdb_Thumb *thumb) { @@ -427,9 +506,8 @@ get_pixel_data (Itdb_Device *device, Itdb_Thumb *thumb) static guchar * itdb_thumb_get_rgb_data (Itdb_Device *device, Itdb_Thumb *thumb) { - void *pixels565; - guchar *pixels; - guint byte_order; + void *pixels_raw; + guchar *pixels=NULL; const Itdb_ArtworkFormat *img_info; g_return_val_if_fail (device, NULL); @@ -438,23 +516,29 @@ itdb_thumb_get_rgb_data (Itdb_Device *device, Itdb_Thumb *thumb) img_info = itdb_get_artwork_info_from_type (device, thumb->type); g_return_val_if_fail (img_info, NULL); - pixels565 = get_pixel_data (device, thumb); - if (pixels565 == NULL) { + pixels_raw = get_pixel_data (device, thumb); + if (pixels_raw == NULL) { return NULL; } - byte_order = device->byte_order; - /* Swap the byte order on full screen nano photos */ - if (img_info->correlation_id == 1023) + switch (img_info->format) { - if (byte_order == G_LITTLE_ENDIAN) - byte_order = G_BIG_ENDIAN; - else - byte_order = G_LITTLE_ENDIAN; + case THUMB_FORMAT_RGB565_LE_90: + case THUMB_FORMAT_RGB565_BE_90: + /* FIXME: actually the previous two might require + different treatment (used on iPod Photo for the full + screen photo thumbnail) */ + case THUMB_FORMAT_RGB565_LE: + case THUMB_FORMAT_RGB565_BE: + pixels = unpack_RGB_565 (pixels_raw, thumb->size, + itdb_thumb_get_byteorder (img_info->format)); + break; + case THUMB_FORMAT_UYVY: + pixels = unpack_UYVY (pixels_raw, thumb->size, + img_info->width, img_info->height); + break; } - - pixels = unpack_RGB_565 (pixels565, thumb->size, byte_order); - g_free (pixels565); + g_free (pixels_raw); return pixels; @@ -701,3 +785,21 @@ Itdb_Thumb *itdb_thumb_duplicate (Itdb_Thumb *thumb) } return new_thumb; } + + +G_GNUC_INTERNAL gint +itdb_thumb_get_byteorder (const ItdbThumbFormat format) +{ + switch (format) + { + case THUMB_FORMAT_RGB565_LE: + case THUMB_FORMAT_RGB565_LE_90: + return G_LITTLE_ENDIAN; + case THUMB_FORMAT_RGB565_BE: + case THUMB_FORMAT_RGB565_BE_90: + return G_BIG_ENDIAN; + case THUMB_FORMAT_UYVY: + return -1; + } + g_return_val_if_reached (-1); +} diff --git a/src/itdb_device.c b/src/itdb_device.c index 8afe097..a0f746b 100644 --- a/src/itdb_device.c +++ b/src/itdb_device.c @@ -1,4 +1,4 @@ -/* Time-stamp: <2006-09-21 20:37:09 jcs> +/* Time-stamp: <2006-11-12 23:07:06 jcs> | | Copyright (C) 2002-2005 Jorg Schuler <jcsjcs at users sourceforge net> | Part of the gtkpod project. @@ -205,38 +205,38 @@ static const gchar *ipod_generation_name_table [] = { NULL }; -static const Itdb_ArtworkFormat ipod_color_artwork_info[] = { - {ITDB_THUMB_COVER_SMALL, 56, 56, 1017}, - {ITDB_THUMB_COVER_LARGE, 140, 140, 1016}, - {ITDB_THUMB_PHOTO_SMALL, 42, 30, 1009}, - {ITDB_THUMB_PHOTO_LARGE, 130, 88, 1015}, - {ITDB_THUMB_PHOTO_FULL_SCREEN, 220, 176, 1013}, - {ITDB_THUMB_PHOTO_TV_SCREEN, 720, 480, 1019}, - {-1, -1, -1, -1} +static const Itdb_ArtworkFormat ipod_photo_artwork_info[] = { + {ITDB_THUMB_COVER_SMALL, 56, 56, 1017, THUMB_FORMAT_RGB565_LE}, + {ITDB_THUMB_COVER_LARGE, 140, 140, 1016, THUMB_FORMAT_RGB565_LE}, + {ITDB_THUMB_PHOTO_SMALL, 42, 30, 1009, THUMB_FORMAT_RGB565_LE}, + {ITDB_THUMB_PHOTO_LARGE, 130, 88, 1015, THUMB_FORMAT_RGB565_LE}, + {ITDB_THUMB_PHOTO_FULL_SCREEN,220, 176, 1013, THUMB_FORMAT_RGB565_BE_90}, + {ITDB_THUMB_PHOTO_TV_SCREEN, 720, 480, 1019, THUMB_FORMAT_UYVY}, + {-1, -1, -1, -1, -1} }; static const Itdb_ArtworkFormat ipod_nano_artwork_info[] = { - {ITDB_THUMB_COVER_SMALL, 42, 42, 1031}, - {ITDB_THUMB_COVER_LARGE, 100, 100, 1027}, - {ITDB_THUMB_PHOTO_LARGE, 42, 37, 1032}, - {ITDB_THUMB_PHOTO_FULL_SCREEN, 176, 132, 1023}, - {-1, -1, -1, -1} + {ITDB_THUMB_COVER_SMALL, 42, 42, 1031, THUMB_FORMAT_RGB565_LE}, + {ITDB_THUMB_COVER_LARGE, 100, 100, 1027, THUMB_FORMAT_RGB565_LE}, + {ITDB_THUMB_PHOTO_LARGE, 42, 37, 1032, THUMB_FORMAT_RGB565_LE}, + {ITDB_THUMB_PHOTO_FULL_SCREEN,176, 132, 1023, THUMB_FORMAT_RGB565_BE}, + {-1, -1, -1, -1, -1} }; static const Itdb_ArtworkFormat ipod_video_artwork_info[] = { - {ITDB_THUMB_COVER_SMALL, 100, 100, 1028}, - {ITDB_THUMB_COVER_LARGE, 200, 200, 1029}, - {ITDB_THUMB_PHOTO_SMALL, 50, 41, 1036}, - {ITDB_THUMB_PHOTO_LARGE, 130, 88, 1015}, - {ITDB_THUMB_PHOTO_FULL_SCREEN, 320, 240, 1024}, - {ITDB_THUMB_PHOTO_TV_SCREEN, 720, 480, 1019}, - {-1, -1, -1, -1} + {ITDB_THUMB_COVER_SMALL, 100, 100, 1028, THUMB_FORMAT_RGB565_LE}, + {ITDB_THUMB_COVER_LARGE, 200, 200, 1029, THUMB_FORMAT_RGB565_LE}, + {ITDB_THUMB_PHOTO_SMALL, 50, 41, 1036, THUMB_FORMAT_RGB565_LE}, + {ITDB_THUMB_PHOTO_LARGE, 130, 88, 1015, THUMB_FORMAT_RGB565_LE}, + {ITDB_THUMB_PHOTO_FULL_SCREEN,320, 240, 1024, THUMB_FORMAT_RGB565_LE}, + {ITDB_THUMB_PHOTO_TV_SCREEN, 720, 480, 1019, THUMB_FORMAT_UYVY}, + {-1, -1, -1, -1, -1} }; static const Itdb_ArtworkFormat ipod_mobile_1_artwork_info[] = { - {ITDB_THUMB_COVER_SMALL, 50, 50, 2002}, - {ITDB_THUMB_COVER_LARGE, 150, 150, 2003}, - {-1, -1, -1, -1} + {ITDB_THUMB_COVER_SMALL, 50, 50, 2002, THUMB_FORMAT_RGB565_BE}, + {ITDB_THUMB_COVER_LARGE, 150, 150, 2003, THUMB_FORMAT_RGB565_BE}, + {-1, -1, -1, -1, -1} }; @@ -244,8 +244,8 @@ static const Itdb_ArtworkFormat ipod_mobile_1_artwork_info[] = { static const Itdb_ArtworkFormat *ipod_artwork_info_table[] = { NULL, /* Invalid */ NULL, /* Unknown */ - ipod_color_artwork_info, /* Color */ - ipod_color_artwork_info, /* Color U2 */ + ipod_photo_artwork_info, /* Color */ + ipod_photo_artwork_info, /* Color U2 */ NULL, /* Grayscale */ NULL, /* Grayscale U2 */ NULL, /* Mini (Silver) */ diff --git a/src/itdb_device.h b/src/itdb_device.h index ec97a5a..0601ea4 100644 --- a/src/itdb_device.h +++ b/src/itdb_device.h @@ -1,4 +1,4 @@ -/* Time-stamp: <2006-06-07 23:48:37 jcs> +/* Time-stamp: <2006-11-12 23:03:35 jcs> | | Copyright (C) 2002-2005 Jorg Schuler <jcsjcs at users sourceforge net> | Part of the gtkpod project. @@ -47,6 +47,17 @@ G_BEGIN_DECLS typedef struct _Itdb_ArtworkFormat Itdb_ArtworkFormat; +typedef enum _ItdbThumbFormat ItdbThumbFormat; + +enum _ItdbThumbFormat +{ + THUMB_FORMAT_UYVY, + THUMB_FORMAT_RGB565_LE, + THUMB_FORMAT_RGB565_LE_90, + THUMB_FORMAT_RGB565_BE, + THUMB_FORMAT_RGB565_BE_90, +}; + struct _Itdb_Device { @@ -68,6 +79,7 @@ struct _Itdb_ArtworkFormat gint16 width; gint16 height; gint16 correlation_id; + ItdbThumbFormat format; }; G_GNUC_INTERNAL const Itdb_ArtworkFormat *itdb_device_get_artwork_formats (Itdb_Device *device); diff --git a/src/itdb_private.h b/src/itdb_private.h index 037b762..f2ecccc 100644 --- a/src/itdb_private.h +++ b/src/itdb_private.h @@ -1,4 +1,4 @@ -/* Time-stamp: <2006-06-01 23:31:27 jcs> +/* Time-stamp: <2006-11-12 22:17:17 jcs> | | Copyright (C) 2002-2005 Jorg Schuler <jcsjcs at users sourceforge net> | Part of the gtkpod project. @@ -34,6 +34,7 @@ # include <config.h> #endif #include "glib-compat.h" +#include "itdb_device.h" #include "itdb.h" /* always use itdb_playlist_is_mpl() to check for MPL! */ @@ -148,4 +149,5 @@ G_GNUC_INTERNAL Itdb_Device *db_get_device(Itdb_DB *db); G_GNUC_INTERNAL gint itdb_get_free_photo_id ( Itdb_PhotoDB *db ); G_GNUC_INTERNAL Itdb_iTunesDB *db_get_itunesdb (Itdb_DB *db); G_GNUC_INTERNAL Itdb_PhotoDB *db_get_photodb (Itdb_DB *db); +G_GNUC_INTERNAL gint itdb_thumb_get_byteorder (ItdbThumbFormat format); #endif diff --git a/src/ithumb-writer.c b/src/ithumb-writer.c index 3b6a6ec..060ff2a 100644 --- a/src/ithumb-writer.c +++ b/src/ithumb-writer.c @@ -1,4 +1,4 @@ -/* Time-stamp: <2006-11-12 19:07:29 jcs> +/* Time-stamp: <2006-11-13 00:03:30 jcs> * * Copyright (C) 2005 Christophe Fergeau * @@ -62,13 +62,9 @@ struct _iThumbWriter { }; typedef struct _iThumbWriter iThumbWriter; -/* The iPod expect square thumbnails with 2 specific side sizes (0x38 and 0x8c - * respectively for small and fullscreen thumbnails), the 'size' parameter is - * here to specify which size we are interested in in case the pixbuf is non - * square - */ + static guint16 * -pack_RGB_565 (GdkPixbuf *pixbuf, iThumbWriter *writer, +pack_RGB_565 (GdkPixbuf *pixbuf, const Itdb_ArtworkFormat *img_info, gint horizontal_padding, gint vertical_padding) { guchar *pixels; @@ -85,24 +81,17 @@ pack_RGB_565 (GdkPixbuf *pixbuf, iThumbWriter *writer, "rowstride", &row_stride, "n-channels", &channels, "height", &height, "width", &width, "pixels", &pixels, NULL); - g_return_val_if_fail ((width <= writer->img_info->width) && (height <= writer->img_info->height), NULL); + g_return_val_if_fail ((width <= img_info->width) && (height <= img_info->height), NULL); /* dst_width and dst_height come from a width/height database * hardcoded in libipoddevice code, so dst_width * dst_height * 2 can't * overflow, even on an iPod containing malicious data */ - result = g_malloc0 (writer->img_info->width * writer->img_info->height * 2); - - /* Swap the byte order on full screen nano photos */ - byte_order = writer->byte_order; - if ( writer->img_info->correlation_id == 1023) { - if (byte_order == G_LITTLE_ENDIAN) - byte_order = G_BIG_ENDIAN; - else - byte_order = G_LITTLE_ENDIAN; - } + result = g_malloc0 (img_info->width * img_info->height * 2); + + byte_order = itdb_thumb_get_byteorder (img_info->format); for (h = 0; h < height; h++) { - gint line = (h+vertical_padding)*writer->img_info->width; + gint line = (h+vertical_padding)*img_info->width; for (w = 0; w < width; w++) { gint r; gint g; @@ -126,6 +115,112 @@ pack_RGB_565 (GdkPixbuf *pixbuf, iThumbWriter *writer, } +/* pack_UYVY() is adapted from imgconvert.c from the GPixPod project + * (www.gpixpod.org) */ +static guchar * +pack_UYVY (GdkPixbuf *orig_pixbuf, const Itdb_ArtworkFormat *img_info, + gint horizontal_padding, gint vertical_padding) +{ + GdkPixbuf *pixbuf; + guchar *pixels, *yuvdata; + gint width; + gint height; + gint orig_height, orig_width; + gint x = 0; + gint z = 0; + gint z2 = 0; + gint h = 0; + gint r0, g0, b0, r1, g1, b1, r2, g2, b2, r3, g3, b3; + gint rowstride; + gint yuvsize, halfyuv; + gint alphabit, rgbpx; + gint exc; + + g_return_val_if_fail (img_info, NULL); + + width = img_info->width; + height = img_info->height; + + g_object_get (G_OBJECT (orig_pixbuf), + "height", &orig_height, "width", &orig_width, NULL); + + /* copy into new pixmap with padding applied */ + pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, + gdk_pixbuf_get_has_alpha (orig_pixbuf), + 8, + width, height); + gdk_pixbuf_copy_area (orig_pixbuf, 0, 0, orig_width, orig_height, + pixbuf, horizontal_padding, vertical_padding); + + g_object_get (G_OBJECT (pixbuf), + "rowstride", &rowstride, + "pixels", &pixels, NULL); + + yuvsize = width*2*height; + yuvdata = g_malloc (yuvsize); + halfyuv = yuvsize/2; + if (gdk_pixbuf_get_has_alpha(pixbuf)) + { + alphabit = 1; + rgbpx = 4; + } + else + { + alphabit = 0; + rgbpx = 3; + } + exc = rowstride - width*rgbpx; + + while(h < height) + { + gint w = 0; + if((h % 2) == 0) + { + while(w < width) + { + r0 = pixels[x]; + g0 = pixels[x+1]; + b0 = pixels[x+2]; + r1 = pixels[x+3+alphabit]; + g1 = pixels[x+4+alphabit]; + b1 = pixels[x+5+alphabit]; + yuvdata[z] = ((r0*-38 + g0*-74 + b0*112 + 128) >> 8) + 128;/*U0*/ + yuvdata[z+1] = ((r0*66 + g0*129 + b0*25 + 128) >> 8) + 16;/*Y0*/ + yuvdata[z+2] = ((r0*112 + g0*-94 + b0*-18 + 128) >> 8) + 128;/*V0*/ + yuvdata[z+3] = ((r1*66 + g1*129 + b1*25 + 128) >> 8) + 16;/*Y1*/ + w += 2; + z += 4; + x += rgbpx*2; + } + } + else + { + while(w < width) + { + r2 = pixels[x]; + g2 = pixels[x+1]; + b2 = pixels[x+2]; + r3 = pixels[x+3+alphabit]; + g3 = pixels[x+4+alphabit]; + b3 = pixels[x+5+alphabit]; + yuvdata[halfyuv+z2] = ((r2*-38 + g2*-74 + b2*112 + 128) >> 8) + 128;/*U1*/ + yuvdata[halfyuv+z2+1] = ((r2*66 + g2*129 + b2*25 + 128) >> 8) + 16;/*Y2*/ + yuvdata[halfyuv+z2+2] = ((r2*112 + g2*-94 + b2*-18 + 128) >> 8) + 128;/*V1*/ + yuvdata[halfyuv+z2+3] = ((r3*66 + g3*129 + b3*25 + 128) >> 8) + 16;/*Y3*/ + w += 2; + z2 += 4; + x += rgbpx*2; + } + } + x += exc; + h++; + } + g_object_unref (pixbuf); + return yuvdata; +} + + + static char * ipod_image_get_ithmb_filename (const char *mount_point, gint correlation_id, gint index, DbType db_type ) { @@ -205,7 +300,7 @@ ithumb_writer_write_thumbnail (iThumbWriter *writer, Itdb_Thumb *thumb) { GdkPixbuf *pixbuf = NULL; - guint16 *pixels; + void *pixels = NULL; gint width, height; /* must be gint -- see comment below */ g_return_val_if_fail (writer, FALSE); @@ -298,9 +393,27 @@ ithumb_writer_write_thumbnail (iThumbWriter *writer, thumb->offset = writer->cur_offset; thumb->size = writer->img_info->width * writer->img_info->height * 2; - pixels = pack_RGB_565 (pixbuf, writer, - thumb->horizontal_padding, - thumb->vertical_padding); + switch (writer->img_info->format) + { + case THUMB_FORMAT_RGB565_LE_90: + case THUMB_FORMAT_RGB565_BE_90: + /* FIXME: actually the previous two might require + different treatment (used on iPod Photo for the full + screen photo thumbnail) */ + case THUMB_FORMAT_RGB565_LE: + case THUMB_FORMAT_RGB565_BE: + pixels = pack_RGB_565 (pixbuf, writer->img_info, + thumb->horizontal_padding, + thumb->vertical_padding); + break; + case THUMB_FORMAT_UYVY: + pixels = pack_UYVY (pixbuf, writer->img_info, + thumb->horizontal_padding, + thumb->vertical_padding); + break; + } + + g_object_unref (G_OBJECT (pixbuf)); if (pixels == NULL) |