Move YUV->RGB in JPEG load from before scaler to after scaler. Required change to struct custom_format, so sorted the plugin API as well.

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@20856 a1c6a512-1295-4272-9138-f99709370657
diff --git a/apps/plugin.c b/apps/plugin.c
index 2d996a4..f079e84 100644
--- a/apps/plugin.c
+++ b/apps/plugin.c
@@ -135,11 +135,18 @@
     lcd_blit_mono,
     lcd_blit_grey_phase,
 #endif /* LCD_DEPTH */
+#if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_PAL256)
+    lcd_blit_pal256,
+    lcd_pal256_update_pal,
+#endif
     lcd_puts_style,
     lcd_puts_scroll_style,
 #ifdef HAVE_LCD_INVERT
     lcd_set_invert_display,
 #endif /* HAVE_LCD_INVERT */
+#if defined(HAVE_LCD_MODES)
+    lcd_set_mode,
+#endif
 #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP)
     lcd_activation_set_hook,
     &button_queue,
@@ -571,6 +578,11 @@
 #endif
 #ifdef HAVE_LCD_BITMAP
     read_bmp_file,
+    read_bmp_fd,
+#ifdef HAVE_JPEG
+    read_jpeg_file,
+    read_jpeg_fd,
+#endif
     screen_dump_set_hook,
 #endif
     show_logo,
@@ -632,24 +644,6 @@
     appsversion,
     /* new stuff at the end, sort into place next time
        the API gets incompatible */
-       
-#if defined(HAVE_LCD_MODES)
-	lcd_set_mode,
-#endif
-
-#if defined(HAVE_LCD_MODES)
-#if HAVE_LCD_MODES & LCD_MODE_PAL256
-	lcd_blit_pal256,
-	lcd_pal256_update_pal,
-#endif
-#endif
-#ifdef HAVE_LCD_BITMAP
-#ifdef HAVE_JPEG
-    read_jpeg_file,
-    read_jpeg_fd,
-#endif
-    read_bmp_fd,
-#endif
 };
 
 int plugin_load(const char* plugin, const void* parameter)
diff --git a/apps/plugin.h b/apps/plugin.h
index 72d71b6..d017d63 100644
--- a/apps/plugin.h
+++ b/apps/plugin.h
@@ -129,12 +129,12 @@
 #define PLUGIN_MAGIC 0x526F634B /* RocK */
 
 /* increase this every time the api struct changes */
-#define PLUGIN_API_VERSION 149
+#define PLUGIN_API_VERSION 150
 
 /* update this to latest version if a change to the api struct breaks
    backwards compatibility (and please take the opportunity to sort in any
    new function which are "waiting" at the end of the function table) */
-#define PLUGIN_MIN_API_VERSION 147
+#define PLUGIN_MIN_API_VERSION 150
 
 /* plugin return codes */
 enum plugin_status {
@@ -220,12 +220,20 @@
                                 int bx, int by, int bwidth, int bheight,
                                 int stride);
 #endif /* LCD_DEPTH */
+#if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_PAL256)
+    void (*lcd_blit_pal256)(unsigned char *src, int src_x, int src_y, int x, int y,
+                            int width, int height);
+    void (*lcd_pal256_update_pal)(fb_data *palette);
+#endif
     void (*lcd_puts_style)(int x, int y, const unsigned char *str, int style);
     void (*lcd_puts_scroll_style)(int x, int y, const unsigned char* string,
                                   int style);
 #ifdef HAVE_LCD_INVERT
     void (*lcd_set_invert_display)(bool yesno);
 #endif /* HAVE_LCD_INVERT */
+#if defined(HAVE_LCD_MODES)
+    void (*lcd_set_mode)(int mode);
+#endif
 
 #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP)
     void (*lcd_activation_set_hook)(void (*enable_hook)(void));
@@ -723,6 +731,14 @@
 #ifdef HAVE_LCD_BITMAP
     int (*read_bmp_file)(const char* filename, struct bitmap *bm, int maxsize,
                          int format, const struct custom_format *cformat);
+    int (*read_bmp_fd)(int fd, struct bitmap *bm, int maxsize,
+                       int format, const struct custom_format *cformat);
+#ifdef HAVE_JPEG
+    int (*read_jpeg_file)(const char* filename, struct bitmap *bm, int maxsize,
+                          int format, const struct custom_format *cformat);
+    int (*read_jpeg_fd)(int fd, struct bitmap *bm, int maxsize,
+                        int format, const struct custom_format *cformat);
+#endif
     void (*screen_dump_set_hook)(void (*hook)(int fh));
 #endif
     int (*show_logo)(void);
@@ -788,32 +804,9 @@
     void (*semaphore_release)(struct semaphore *s);
 #endif
 
-	const char *appsversion;
+    const char *appsversion;
     /* new stuff at the end, sort into place next time
        the API gets incompatible */
-       
-#if defined(HAVE_LCD_MODES)
-	void (*lcd_set_mode)(int mode);
-#endif
-
-#if defined(HAVE_LCD_MODES)
-#if HAVE_LCD_MODES & LCD_MODE_PAL256
-	void (*lcd_blit_pal256)(unsigned char *src, int src_x, int src_y, int x, int y,
-							int width, int height);
-	void (*lcd_pal256_update_pal)(fb_data *palette);
-#endif
-#endif
-
-#ifdef HAVE_LCD_BITMAP
-#ifdef HAVE_JPEG
-    int (*read_jpeg_file)(const char* filename, struct bitmap *bm, int maxsize,
-                          int format, const struct custom_format *cformat);
-    int (*read_jpeg_fd)(int fd, struct bitmap *bm, int maxsize,
-                        int format, const struct custom_format *cformat);
-#endif
-    int (*read_bmp_fd)(int fd, struct bitmap *bm, int maxsize,
-                       int format, const struct custom_format *cformat);
-#endif
 };
 
 /* plugin header */
diff --git a/apps/plugins/jpeg/yuv2rgb.c b/apps/plugins/jpeg/yuv2rgb.c
index c246492..ed88d54 100644
--- a/apps/plugins/jpeg/yuv2rgb.c
+++ b/apps/plugins/jpeg/yuv2rgb.c
@@ -48,13 +48,6 @@
 #define COMPONENT_SHIFT  15
 #define MATRIX_SHIFT      7
 
-static inline int clamp_component(int x)
-{
-    if ((unsigned)x > YUV_WHITE)
-        x = x < 0 ? 0 : YUV_WHITE;
-    return x;
-}
-
 static inline int clamp_component_bits(int x, int bits)
 {
     if ((unsigned)x > (1u << bits) - 1)
diff --git a/apps/plugins/pictureflow.c b/apps/plugins/pictureflow.c
index b78b953..7261d7a 100644
--- a/apps/plugins/pictureflow.c
+++ b/apps/plugins/pictureflow.c
@@ -634,13 +634,43 @@
 #endif
 }
 
+#ifdef HAVE_LCD_COLOR
+static void output_row_transposed_fromyuv(uint32_t row, void * row_in,
+                                       struct scaler_context *ctx)
+{
+    pix_t *dest = (pix_t*)ctx->bm->data + row;
+    pix_t *end = dest + ctx->bm->height * ctx->bm->width;
+    struct uint32_rgb *qp = (struct uint32_rgb*)row_in;
+    for (; dest < end; dest += ctx->bm->height)
+    {
+        unsigned r, g, b, y, u, v;
+        y = SC_MUL(qp->b + ctx->round, ctx->divisor);
+        u = SC_MUL(qp->g + ctx->round, ctx->divisor);
+        v = SC_MUL(qp->r + ctx->round, ctx->divisor);
+        qp++;
+        yuv_to_rgb(y, u, v, &r, &g, &b);
+        r = (31 * r + (r >> 3) + 127) >> 8;
+        g = (63 * g + (g >> 2) + 127) >> 8;
+        b = (31 * b + (b >> 3) + 127) >> 8;
+        *dest = LCD_RGBPACK_LCD(r, g, b);
+    }
+}
+#endif
+
 static unsigned int get_size(struct bitmap *bm)
 {
     return bm->width * bm->height * sizeof(pix_t);
 }
 
 const struct custom_format format_transposed = {
+#ifdef HAVE_LCD_COLOR
+    .output_row = {
+        output_row_transposed,
+        output_row_transposed_fromyuv
+    },
+#else
     .output_row = output_row_transposed,
+#endif
     .get_size = get_size
 };
 
diff --git a/apps/recorder/bmp.c b/apps/recorder/bmp.c
index 403c34d..f1fc1f8 100644
--- a/apps/recorder/bmp.c
+++ b/apps/recorder/bmp.c
@@ -603,7 +603,7 @@
     {
         if (resize_on_load(bm, dither, &src_dim, &rset,
                            bitmap + totalsize, maxsize - totalsize,
-                           cformat, store_part_bmp, &ba))
+                           cformat, IF_PIX_FMT(0,) store_part_bmp, &ba))
             return totalsize;
         else
             return 0;
diff --git a/apps/recorder/jpeg_common.h b/apps/recorder/jpeg_common.h
index 44bf81e..061cfc8 100644
--- a/apps/recorder/jpeg_common.h
+++ b/apps/recorder/jpeg_common.h
@@ -28,6 +28,8 @@
 #ifndef _JPEG_COMMON_H
 #define _JPEG_COMMON_H
 
+#include "bmp.h"
+
 #define HUFF_LOOKAHEAD 8 /* # of bits of lookahead */
 #define JPEG_READ_BUF_SIZE 16
 struct derived_tbl
@@ -51,6 +53,55 @@
 
 #define QUANT_TABLE_LENGTH  64
 
+/*
+ * Conversion of full 0-255 range YCrCb to RGB:
+ *   |R|   |1.000000 -0.000001  1.402000| |Y'|
+ *   |G| = |1.000000 -0.334136 -0.714136| |Pb|
+ *   |B|   |1.000000  1.772000  0.000000| |Pr|
+ * Scaled (yields s15-bit output):
+ *   |R|   |128    0  179| |Y       |
+ *   |G| = |128  -43  -91| |Cb - 128|
+ *   |B|   |128  227    0| |Cr - 128|
+ */
+#define YFAC            128
+#define RVFAC           179
+#define GUFAC           (-43)
+#define GVFAC           (-91)
+#define BUFAC           227
+#define COMPONENT_SHIFT  15
+
+struct uint8_yuv {
+    uint8_t y;
+    uint8_t u;
+    uint8_t v;
+};
+
+union uint8_rgbyuv {
+    struct uint8_yuv yuv;
+    struct uint8_rgb rgb;
+};
+
+static inline int clamp_component(int x)
+{
+    if ((unsigned)x > 255)
+        x = x < 0 ? 0 : 255;
+    return x;
+}
+#include <debug.h>
+static inline void yuv_to_rgb(int y, int u, int v, unsigned *r, unsigned *g, unsigned *b)
+{
+    int rv, guv, bu;
+    y = y * YFAC + (YFAC >> 1);
+    u = u - 128;
+    v = v - 128;
+    rv = RVFAC * v;
+    guv = GUFAC * u + GVFAC * v;
+    bu = BUFAC * u;
+    *r = clamp_component((y + rv) / YFAC);
+    *g = clamp_component((y + guv) / YFAC);
+    *b = clamp_component((y + bu) / YFAC);
+}
+
 /* for type of Huffman table */
 #define DC_LEN 28
 #define AC_LEN 178
diff --git a/apps/recorder/jpeg_load.c b/apps/recorder/jpeg_load.c
index 8b2c3f2..14aa024 100644
--- a/apps/recorder/jpeg_load.c
+++ b/apps/recorder/jpeg_load.c
@@ -153,13 +153,6 @@
 #endif
 }
 
-static inline int clamp_component(int x)
-{
-    if ((unsigned)x > 255)
-        x = x < 0 ? 0 : 255;
-    return x;
-}
-
 /* IDCT implementation */
 
 
@@ -1810,27 +1803,8 @@
             unsigned int xp;
             int yp;
             unsigned char *row = out;
-            if (p_jpeg->blocks > 1) {
-                for (yp = 0; yp < height; yp++, row += b_width)
-                {
-                    unsigned char *px = row;
-                    for (xp = 0; xp < 1U << p_jpeg->h_scale[1];
-                        xp++, px += JPEG_PIX_SZ)
-                    {
-                        int y, u, v, rv, guv, bu;
-                        y = px[0] * YFAC + (YFAC >> 1);
-                        u = px[1] - 128;
-                        v = px[2] - 128;
-                        rv = RVFAC * v;
-                        guv = GUFAC * u + GVFAC * v;
-                        bu = BUFAC * u;
-                        struct uint8_rgb *rgb = (struct uint8_rgb *)px;
-                        rgb->red = clamp_component((y + rv) / YFAC);
-                        rgb->green = clamp_component((y + guv) / YFAC);
-                        rgb->blue = clamp_component((y + bu) / YFAC);
-                    }
-                }
-            } else {
+            if (p_jpeg->blocks == 1)
+            {
                 for (yp = 0; yp < height; yp++, row += b_width)
                 {
                     unsigned char *px = row;
@@ -2003,7 +1977,7 @@
     rset.rowstop = bm->height;
     rset.rowstep = 1;
     if (resize_on_load(bm, dither, &src_dim, &rset, buf_start, maxsize, cformat,
-        store_row_jpeg, p_jpeg))
+        IF_PIX_FMT(p_jpeg->blocks == 1 ? 0 : 1,) store_row_jpeg, p_jpeg))
         return bm_size;
     else
         return 0;
diff --git a/apps/recorder/resize.c b/apps/recorder/resize.c
index 7000c44..1852519 100644
--- a/apps/recorder/resize.c
+++ b/apps/recorder/resize.c
@@ -59,6 +59,7 @@
 #undef DEBUGF
 #define DEBUGF(...)
 #endif
+#include <jpeg_load.h>
 
 #if CONFIG_CPU == SH7034
 /* 16*16->32 bit multiplication is a single instrcution on the SH1 */
@@ -516,6 +517,35 @@
 }
 #endif /* HAVE_UPSCALER */
 
+#if defined(HAVE_LCD_COLOR) && (defined(HAVE_JPEG) || defined(PLUGIN))
+void output_row_native_fromyuv(uint32_t row, void * row_in,
+                               struct scaler_context *ctx)
+{
+    int col;
+    int fb_width = BM_WIDTH(ctx->bm->width,FORMAT_NATIVE,0);
+    uint8_t dy = DITHERY(row);
+    struct uint32_rgb *qp = (struct uint32_rgb *)row_in;
+    SDEBUGF("output_row: y: %lu in: %p\n",row, row_in);
+    fb_data *dest = (fb_data *)ctx->bm->data + fb_width * row;
+    int delta = 127;
+    unsigned r, g, b, y, u, v;
+
+    for (col = 0; col < ctx->bm->width; col++) {
+        if (ctx->dither)
+            delta = DITHERXDY(col,dy);
+        y = SC_MUL(qp->b + ctx->round, ctx->divisor);
+        u = SC_MUL(qp->g + ctx->round, ctx->divisor);
+        v = SC_MUL(qp->r + ctx->round, ctx->divisor);
+        qp++;
+        yuv_to_rgb(y, u, v, &r, &g, &b);
+        r = (31 * r + (r >> 3) + delta) >> 8;
+        g = (63 * g + (g >> 2) + delta) >> 8;
+        b = (31 * b + (b >> 3) + delta) >> 8;
+        *dest++ = LCD_RGBPACK_LCD(r, g, b);
+    }
+}
+#endif
+
 #if !defined(PLUGIN) || LCD_DEPTH > 1
 void output_row_native(uint32_t row, void * row_in,
                               struct scaler_context *ctx)
@@ -614,7 +644,14 @@
 }
 
 const struct custom_format format_native = {
+#if defined(HAVE_LCD_COLOR) && (defined(HAVE_JPEG) || defined(PLUGIN))
+    .output_row = {
+        output_row_native,
+        output_row_native_fromyuv
+    },
+#else
     .output_row = output_row_native,
+#endif
     .get_size = get_size_native
 };
 #endif
@@ -622,6 +659,7 @@
 int resize_on_load(struct bitmap *bm, bool dither, struct dim *src,
                    struct rowset *rset, unsigned char *buf, unsigned int len,
                    const struct custom_format *format,
+                   IF_PIX_FMT(int format_index,)
                    struct img_part* (*store_part)(void *args),
                    void *args)
 {
@@ -683,10 +721,19 @@
     ctx.src = src;
     ctx.dither = dither;
 #if !defined(PLUGIN)
+#if defined(HAVE_LCD_COLOR) && defined(HAVE_JPEG)
+    ctx.output_row = format_index ? output_row_native_fromyuv
+                                  : output_row_native;
+#else
     ctx.output_row = output_row_native;
+#endif
     if (format)
 #endif
+#if defined(HAVE_LCD_COLOR) && (defined(HAVE_JPEG) || defined(PLUGIN))
+        ctx.output_row = format->output_row[format_index];
+#else
         ctx.output_row = format->output_row;
+#endif
 #ifdef HAVE_UPSCALER
     if (sw > dw)
     {
diff --git a/apps/recorder/resize.h b/apps/recorder/resize.h
index de9e8a9..f7cda15 100644
--- a/apps/recorder/resize.h
+++ b/apps/recorder/resize.h
@@ -143,8 +143,18 @@
     bool (*h_scaler)(void*,struct scaler_context*, bool);
 };
 
+#if defined(HAVE_LCD_COLOR) && (defined(HAVE_JPEG) || defined(PLUGIN))
+#define IF_PIX_FMT(...) __VA_ARGS__
+#else
+#define IF_PIX_FMT(...)
+#endif
+
 struct custom_format {
+#if defined(HAVE_LCD_COLOR)
+    void (*output_row[2])(uint32_t,void*,struct scaler_context*);
+#else
     void (*output_row)(uint32_t,void*,struct scaler_context*);
+#endif
     unsigned int (*get_size)(struct bitmap *bm);
 };
 
@@ -161,6 +171,7 @@
                    struct dim *src, struct rowset *tmp_row,
                    unsigned char *buf, unsigned int len,
                    const struct custom_format *cformat,
+                   IF_PIX_FMT(int format_index,)
                    struct img_part* (*store_part)(void *args),
                    void *args);