aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xandroid/camera/camera-format-converters.c1841
1 files changed, 690 insertions, 1151 deletions
diff --git a/android/camera/camera-format-converters.c b/android/camera/camera-format-converters.c
index ff4a048..172f46f 100755
--- a/android/camera/camera-format-converters.c
+++ b/android/camera/camera-format-converters.c
@@ -42,18 +42,6 @@
* 0xff000000, and blue color would be masked as 0x0000ff00,
*/
-/* Prototype of a routine that converts frame from one pixel format to another.
- * Param:
- * from - Frame to convert.
- * width, height - Width, and height of the frame to convert.
- * to - Buffer to receive the converted frame. Note that this buffer must
- * be big enough to contain all the converted pixels!
- */
-typedef void (*FormatConverter)(const uint8_t* from,
- int width,
- int height,
- uint8_t* to);
-
/*
* RGB565 color masks
*/
@@ -88,38 +76,38 @@ static const uint32_t kBlue8 = 0x000000ff;
#ifndef HOST_WORDS_BIGENDIAN
/* Extract red, green, and blue bytes from RGB565 word. */
-#define R16(rgb) (uint8_t)(rgb & kRed5)
-#define G16(rgb) (uint8_t)((rgb & kGreen6) >> 5)
-#define B16(rgb) (uint8_t)((rgb & kBlue5) >> 11)
+#define R16(rgb) (uint8_t)((rgb) & kRed5)
+#define G16(rgb) (uint8_t)(((rgb) & kGreen6) >> 5)
+#define B16(rgb) (uint8_t)(((rgb) & kBlue5) >> 11)
/* Make 8 bits red, green, and blue, extracted from RGB565 word. */
-#define R16_32(rgb) (uint8_t)(((rgb & kRed5) << 3) | ((rgb & kRed5) >> 2))
-#define G16_32(rgb) (uint8_t)(((rgb & kGreen6) >> 3) | ((rgb & kGreen6) >> 9))
-#define B16_32(rgb) (uint8_t)(((rgb & kBlue5) >> 8) | ((rgb & kBlue5) >> 14))
+#define R16_32(rgb) (uint8_t)((((rgb) & kRed5) << 3) | (((rgb) & kRed5) >> 2))
+#define G16_32(rgb) (uint8_t)((((rgb) & kGreen6) >> 3) | (((rgb) & kGreen6) >> 9))
+#define B16_32(rgb) (uint8_t)((((rgb) & kBlue5) >> 8) | (((rgb) & kBlue5) >> 14))
/* Extract red, green, and blue bytes from RGB32 dword. */
-#define R32(rgb) (uint8_t)(rgb & kRed8)
-#define G32(rgb) (uint8_t)(((rgb & kGreen8) >> 8) & 0xff)
-#define B32(rgb) (uint8_t)(((rgb & kBlue8) >> 16) & 0xff)
+#define R32(rgb) (uint8_t)((rgb) & kRed8)
+#define G32(rgb) (uint8_t)((((rgb) & kGreen8) >> 8) & 0xff)
+#define B32(rgb) (uint8_t)((((rgb) & kBlue8) >> 16) & 0xff)
/* Build RGB565 word from red, green, and blue bytes. */
-#define RGB565(r, g, b) (uint16_t)(((((uint16_t)(b) << 6) | g) << 5) | r)
+#define RGB565(r, g, b) (uint16_t)(((((uint16_t)(b) << 6) | (g)) << 5) | (r))
/* Build RGB32 dword from red, green, and blue bytes. */
-#define RGB32(r, g, b) (uint32_t)(((((uint32_t)(b) << 8) | g) << 8) | r)
+#define RGB32(r, g, b) (uint32_t)(((((uint32_t)(b) << 8) | (g)) << 8) | (r))
#else // !HOST_WORDS_BIGENDIAN
/* Extract red, green, and blue bytes from RGB565 word. */
-#define R16(rgb) (uint8_t)((rgb & kRed5) >> 11)
-#define G16(rgb) (uint8_t)((rgb & kGreen6) >> 5)
-#define B16(rgb) (uint8_t)(rgb & kBlue5)
+#define R16(rgb) (uint8_t)(((rgb) & kRed5) >> 11)
+#define G16(rgb) (uint8_t)(((rgb) & kGreen6) >> 5)
+#define B16(rgb) (uint8_t)((rgb) & kBlue5)
/* Make 8 bits red, green, and blue, extracted from RGB565 word. */
-#define R16_32(rgb) (uint8_t)(((rgb & kRed5) >> 8) | ((rgb & kRed5) >> 14))
-#define G16_32(rgb) (uint8_t)(((rgb & kGreen6) >> 3) | ((rgb & kGreen6) >> 9))
-#define B16_32(rgb) (uint8_t)(((rgb & kBlue5) << 3) | ((rgb & kBlue5) >> 2))
+#define R16_32(rgb) (uint8_t)((((rgb) & kRed5) >> 8) | (((rgb) & kRed5) >> 14))
+#define G16_32(rgb) (uint8_t)((((rgb) & kGreen6) >> 3) | (((rgb) & kGreen6) >> 9))
+#define B16_32(rgb) (uint8_t)((((rgb) & kBlue5) << 3) | (((rgb) & kBlue5) >> 2))
/* Extract red, green, and blue bytes from RGB32 dword. */
-#define R32(rgb) (uint8_t)((rgb & kRed8) >> 16)
-#define G32(rgb) (uint8_t)((rgb & kGreen8) >> 8)
-#define B32(rgb) (uint8_t)(rgb & kBlue8)
+#define R32(rgb) (uint8_t)(((rgb) & kRed8) >> 16)
+#define G32(rgb) (uint8_t)(((rgb) & kGreen8) >> 8)
+#define B32(rgb) (uint8_t)((rgb) & kBlue8)
/* Build RGB565 word from red, green, and blue bytes. */
-#define RGB565(r, g, b) (uint16_t)(((((uint16_t)(r) << 6) | g) << 5) | b)
+#define RGB565(r, g, b) (uint16_t)(((((uint16_t)(r) << 6) | (g)) << 5) | (b))
/* Build RGB32 dword from red, green, and blue bytes. */
-#define RGB32(r, g, b) (uint32_t)(((((uint32_t)(r) << 8) | g) << 8) | b)
+#define RGB32(r, g, b) (uint32_t)(((((uint32_t)(r) << 8) | (g)) << 8) | (b))
#endif // !HOST_WORDS_BIGENDIAN
/* An union that simplifies breaking 32 bit RGB into separate R, G, and B colors.
@@ -183,9 +171,6 @@ RGB32ToYUV(uint32_t rgb, uint8_t* y, uint8_t* u, uint8_t* v)
/********************************************************************************
* Basics of YUV -> RGB conversion.
- * Note that due to the fact that guest uses RGB only on preview window, and the
- * RGB format that is used is RGB565, we can limit YUV -> RGB conversions to
- * RGB565 only.
*******************************************************************************/
/*
@@ -228,1252 +213,784 @@ YUVToRGB32(int y, int u, int v)
/* Calculate C, D, and E values for the optimized macro. */
y -= 16; u -= 128; v -= 128;
RGB32_t rgb;
- rgb.r = YUV2RO(y,u,v) & 0xff;
- rgb.g = YUV2GO(y,u,v) & 0xff;
- rgb.b = YUV2BO(y,u,v) & 0xff;
+ rgb.r = YUV2RO(y,u,v);
+ rgb.g = YUV2GO(y,u,v);
+ rgb.b = YUV2BO(y,u,v);
return rgb.color;
}
-/********************************************************************************
- * YUV -> RGB565 converters.
- *******************************************************************************/
-
-/* Common converter for a variety of YUV 4:2:2 formats to RGB565.
- * Meaning of the parameters is pretty much straight forward here, except for the
- * 'next_Y'. In all YUV 4:2:2 formats, every two pixels are encoded in subseqent
- * four bytes, that contain two Ys (one for each pixel), one U, and one V values
- * that are shared between the two pixels. The only difference between formats is
- * how Y,U, and V values are arranged inside the pair. The actual arrangment
- * doesn't make any difference how to advance Us and Vs: subsequent Us and Vs are
- * always four bytes apart. However, with Y things are a bit more messy inside
- * the pair. The only thing that is certain here is that Ys for subsequent pairs
- * are also always four bytes apart. And we have parameter 'next_Y' here that
- * controls the distance between two Ys inside a pixel pair. */
-static void _YUY422_to_RGB565(const uint8_t* from_Y,
- const uint8_t* from_U,
- const uint8_t* from_V,
- int next_Y,
- int width,
- int height,
- uint16_t* rgb)
-{
- int x, y;
- for (y = 0; y < height; y++) {
- for (x = 0; x < width; x += 2, from_Y += 4, from_U += 4, from_V += 4) {
- const uint8_t u = *from_U, v = *from_V;
- *rgb = YUVToRGB565(*from_Y, u, v); rgb++;
- *rgb = YUVToRGB565(from_Y[next_Y], u, v); rgb++;
- }
- }
-}
-
-/* Converts YUYV frame into RGB565 frame. */
-static void _YUYV_to_RGB565(const uint8_t* from,
- int width,
- int height,
- uint8_t* to)
-{
- _YUY422_to_RGB565(from, from + 1, from + 3, 2, width, height, (uint16_t*)to);
-}
-
-/* Converts YVYU frame into RGB565 frame. */
-static void _YVYU_to_RGB565(const uint8_t* from,
- int width,
- int height,
- uint8_t* to)
-{
- _YUY422_to_RGB565(from, from + 3, from + 1, 2, width, height, (uint16_t*)to);
-}
-
-/* Converts UYVY frame into RGB565 frame. */
-static void _UYVY_to_RGB565(const uint8_t* from,
- int width,
- int height,
- uint8_t* to)
-{
- _YUY422_to_RGB565(from + 1, from, from + 2, 2, width, height, (uint16_t*)to);
-}
-
-/* Converts VYUY frame into RGB565 frame. */
-static void _VYUY_to_RGB565(const uint8_t* from,
- int width,
- int height,
- uint8_t* to)
-{
- _YUY422_to_RGB565(from + 1, from + 2, from, 2, width, height, (uint16_t*)to);
-}
-
-/* Converts YYUV frame into RGB565 frame. */
-static void _YYUV_to_RGB565(const uint8_t* from,
- int width,
- int height,
- uint8_t* to)
-{
- _YUY422_to_RGB565(from, from + 2, from + 3, 1, width, height, (uint16_t*)to);
-}
-
-/* Converts YYVU frame into RGB565 frame. */
-static void _YYVU_to_RGB565(const uint8_t* from,
- int width,
- int height,
- uint8_t* to)
+/* Converts YUV color to separated RGB32 colors. */
+static __inline__ void
+YUVToRGBPix(int y, int u, int v, uint8_t* r, uint8_t* g, uint8_t* b)
{
- _YUY422_to_RGB565(from, from + 3, from + 2, 1, width, height, (uint16_t*)to);
+ /* Calculate C, D, and E values for the optimized macro. */
+ y -= 16; u -= 128; v -= 128;
+ *r = (uint8_t)YUV2RO(y,u,v);
+ *g = (uint8_t)YUV2GO(y,u,v);
+ *b = (uint8_t)YUV2BO(y,u,v);
}
/********************************************************************************
- * YUV -> RGB32 converters.
+ * Generic converters between YUV and RGB formats
*******************************************************************************/
-/* Common converter for a variety of YUV 4:2:2 formats to RGB32.
- * See _YUY422_to_RGB565 comments for explanations. */
-static void _YUY422_to_RGB32(const uint8_t* from_Y,
- const uint8_t* from_U,
- const uint8_t* from_V,
- int next_Y,
- int width,
- int height,
- uint32_t* rgb)
-{
- int x, y;
- for (y = 0; y < height; y++) {
- for (x = 0; x < width; x += 2, from_Y += 4, from_U += 4, from_V += 4) {
- const uint8_t u = *from_U, v = *from_V;
- *rgb = YUVToRGB32(*from_Y, u, v); rgb++;
- *rgb = YUVToRGB32(from_Y[next_Y], u, v); rgb++;
- }
- }
-}
+/*
+ * The converters go line by line, convering one frame format to another.
+ * It's pretty much straight forward for RGB/BRG, where all colors are
+ * grouped next to each other in memory. The only two things that differ one RGB
+ * format from another are:
+ * - Is it an RGB, or BRG (i.e. color ordering)
+ * - Is it 16, 24, or 32 bits format.
+ * All these differences are addressed by load_rgb / save_rgb routines, provided
+ * for each format in the RGB descriptor to load / save RGB color bytes from / to
+ * the buffer. As far as moving from one RGB pixel to the next, there
+ * are two question to consider:
+ * - How many bytes it takes to encode one RGB pixel (could be 2, 3, or 4)
+ * - How many bytes it takes to encode a line (i.e. line alignment issue, which
+ * makes sence only for 24-bit formats, since 16, and 32 bit formats provide
+ * automatic word alignment.)
+ * The first question is answered with the 'rgb_inc' field of the RGB descriptor,
+ * and the second one is done by aligning rgb pointer up to the nearest 16 bit
+ * boundaries at the end of each line.
+ * YUV format has much greater complexity for conversion. in YUV color encoding
+ * is divided into three separate panes that can be mixed together in any way
+ * imaginable. Fortunately, there are still some consistent patterns in different
+
+ * YUV formats that can be abstracted through a descriptor:
+ * - At the line-by-line level, colors are always groupped aroud pairs of pixels,
+ * where each pixel in the pair has its own Y value, and each pair of pixels
+ * share thesame U, and V values.
+ * - Position of Y, U, and V is the same for each pair, so the distance between
+ * Ys, and U/V for adjacent pairs is the same.
+ * - Inside the pair, the distance between two Ys is always the same.
+
+ * Moving between the lines in YUV can also be easily formalized. Essentially,
+ * there are three ways how color panes are arranged:
+ * 1. All interleaved, where all three Y, U, and V values are encoded together in
+ * one block:
+ * 1,2 3,4 5,6 n,n+1
+ * YUVY YUVY YUVY .... YUVY
+ *
+ * This type is used to encode YUV 4:2:2 formats.
+ *
+ * 2. One separate block of memory for Y pane, and one separate block of memory
+ * containing interleaved U, and V panes.
+ *
+ * YY | YY | YY | YY
+ * YY | YY | YY | YY
+ * -----------------
+ * UV | UV | UV | UV
+ * -----------------
+ *
+ * This type is used to encode 4:2:0 formats.
+ *
+ * 3. Three separate blocks of memory for each pane.
+ *
+ * YY | YY | YY | YY
+ * YY | YY | YY | YY
+ * -----------------
+ * U | U | U | U
+ * V | V | V | V
+ * -----------------
+ *
+ * This type is also used to encode 4:2:0 formats.
+ *
+ * Note that in cases 2, and 3 each pair of U and V is shared among four pixels,
+ * grouped together as they are groupped in the framebeffer: divide the frame's
+ * rectangle into 2x2 pixels squares, starting from 0,0 corner - and each square
+ * represents the group of pixels that share same pair of UV values. So, each
+ * line in the U/V panes table is shared between two adjacent lines in Y pane,
+ * which provides a pattern on how to move between U/V lines as we move between
+ * Y lines.
+ *
+ * So, all these patterns can be coded in a YUV format descriptor, so there can
+ * just one generic way of walking YUV frame.
+ *
+ * Performance considerations:
+ * Since converters implemented here are intended to work as part of the camera
+ * emulation, making the code super performant is not a priority at all. There
+ * will be enough loses in other parts of the emultion to overlook any slight
+ * inefficiences in the conversion algorithm as neglectable.
+ */
-/* Converts YUYV frame into RGB32 frame. */
-static void _YUYV_to_RGB32(const uint8_t* from,
- int width,
- int height,
- uint8_t* to)
-{
- _YUY422_to_RGB32(from, from + 1, from + 3, 2, width, height, (uint32_t*)to);
-}
+typedef struct RGBDesc RGBDesc;
+typedef struct YUVDesc YUVDesc;
-/* Converts YVYU frame into RGB32 frame. */
-static void _YVYU_to_RGB32(const uint8_t* from,
- int width,
- int height,
- uint8_t* to)
-{
- _YUY422_to_RGB32(from, from + 3, from + 1, 2, width, height, (uint32_t*)to);
-}
+/* Prototype for a routine that loads RGB colors from an RGB/BRG stream.
+ * Param:
+ * rgb - Pointer to a pixel inside the stream where to load colors from.
+ * r, g, b - Upon return will contain red, green, and blue colors for the pixel
+ * addressed by 'rgb' pointer.
+ * Return:
+ * Pointer to the next pixel in the stream.
+ */
+typedef const void* (*load_rgb_func)(const void* rgb,
+ uint8_t* r,
+ uint8_t* g,
+ uint8_t* b);
-/* Converts UYVY frame into RGB32 frame. */
-static void _UYVY_to_RGB32(const uint8_t* from,
- int width,
- int height,
- uint8_t* to)
-{
- _YUY422_to_RGB32(from + 1, from, from + 2, 2, width, height, (uint32_t*)to);
-}
+/* Prototype for a routine that saves RGB colors to an RGB/BRG stream.
+ * Param:
+ * rgb - Pointer to a pixel inside the stream where to save colors.
+ * r, g, b - Red, green, and blue colors to save to the pixel addressed by
+ * 'rgb' pointer.
+ * Return:
+ * Pointer to the next pixel in the stream.
+ */
+typedef void* (*save_rgb_func)(void* rgb, uint8_t r, uint8_t g, uint8_t b);
-/* Converts VYUY frame into RGB32 frame. */
-static void _VYUY_to_RGB32(const uint8_t* from,
- int width,
- int height,
- uint8_t* to)
-{
- _YUY422_to_RGB32(from + 1, from + 2, from, 2, width, height, (uint32_t*)to);
-}
+/* Prototype for a routine that calculates an offset of the first U value for the
+ * given line in a YUV framebuffer.
+ * Param:
+ * desc - Descriptor for the YUV frame for which the offset is being calculated.
+ * line - Zero-based line number for which to calculate the offset.
+ * width, height - Frame dimensions.
+ * Return:
+ * Offset of the first U value for the given frame line. The offset returned
+ * here is relative to the beginning of the YUV framebuffer.
+ */
+typedef int (*u_offset_func)(const YUVDesc* desc, int line, int width, int height);
-/* Converts YYUV frame into RGB32 frame. */
-static void _YYUV_to_RGB32(const uint8_t* from,
- int width,
- int height,
- uint8_t* to)
-{
- _YUY422_to_RGB32(from, from + 2, from + 3, 1, width, height, (uint32_t*)to);
-}
+/* Prototype for a routine that calculates an offset of the first V value for the
+ * given line in a YUV framebuffer.
+ * Param:
+ * desc - Descriptor for the YUV frame for which the offset is being calculated.
+ * line - Zero-based line number for which to calculate the offset.
+ * width, height - Frame dimensions.
+ * Return:
+ * Offset of the first V value for the given frame line. The offset returned
+ * here is relative to the beginning of the YUV framebuffer.
+ */
+typedef int (*v_offset_func)(const YUVDesc* desc, int line, int width, int height);
+
+/* RGB/BRG format descriptor. */
+struct RGBDesc {
+ /* Routine that loads RGB colors from a buffer. */
+ load_rgb_func load_rgb;
+ /* Routine that saves RGB colors into a buffer. */
+ save_rgb_func save_rgb;
+ /* Byte size of an encoded RGB pixel. */
+ int rgb_inc;
+};
-/* Converts YYVU frame into RGB32 frame. */
-static void _YYVU_to_RGB32(const uint8_t* from,
- int width,
- int height,
- uint8_t* to)
-{
- _YUY422_to_RGB32(from, from + 3, from + 2, 1, width, height, (uint32_t*)to);
-}
+/* YUV format descriptor. */
+struct YUVDesc {
+ /* Offset of the first Y value in a fully interleaved YUV framebuffer. */
+ int Y_offset;
+ /* Distance between two Y values inside a pair of pixels in a fully
+ * interleaved YUV framebuffer. */
+ int Y_inc;
+ /* Distance between first Y values of the adjacent pixel pairs in a fully
+ * interleaved YUV framebuffer. */
+ int Y_next_pair;
+ /* Increment between adjacent U/V values in a YUV framebuffer. */
+ int UV_inc;
+ /* Controls location of the first U value in YUV framebuffer. Depending on
+ * the actual YUV format can mean three things:
+ * - For fully interleaved YUV formats contains offset of the first U value
+ * in each line.
+ * - For YUV format that use separate, but interleaved UV pane, this field
+ * contains an offset of the first U value in the UV pane.
+ * - For YUV format that use fully separated Y, U, and V panes this field
+ * defines order of U and V panes in the framebuffer:
+ * = 1 - U pane comes first, right after Y pane.
+ * = 0 - U pane follows V pane that startes right after Y pane. */
+ int U_offset;
+ /* Controls location of the first V value in YUV framebuffer.
+ * See comments to U_offset for more info. */
+ int V_offset;
+ /* Routine that calculates an offset of the first U value for the given line
+ * in a YUV framebuffer. */
+ u_offset_func u_offset;
+ /* Routine that calculates an offset of the first V value for the given line
+ * in a YUV framebuffer. */
+ v_offset_func v_offset;
+};
/********************************************************************************
- * YUV -> YV12 converters.
+ * RGB/BRG load / save routines.
*******************************************************************************/
-/* Common converter for a variety of YUV 4:2:2 formats to YV12.
- * See comments to _YUY422_to_RGB565 for more information. */
-static void _YUY422_to_YV12(const uint8_t* from_Y,
- const uint8_t* from_U,
- const uint8_t* from_V,
- int next_Y,
- int width,
- int height,
- uint8_t* yv12)
+/* Loads R, G, and B colors from a RGB32 framebuffer. */
+static const void*
+_load_RGB32(const void* rgb, uint8_t* r, uint8_t* g, uint8_t* b)
{
- const int total_pix = width * height;
- uint8_t* to_Y = yv12;
- uint8_t* to_U = yv12 + total_pix;
- uint8_t* to_V = to_U + total_pix / 4;
- uint8_t* c_U = to_U;
- uint8_t* c_V = to_V;
- int x, y;
-
- for (y = 0; y < height; y++) {
- for (x = 0; x < width; x += 2, to_Y += 2, c_U++, c_V++,
- from_Y += 4, from_U += 4, from_V += 4) {
- *to_Y = *from_Y; to_Y[1] = from_Y[next_Y];
- *c_U = *from_U; *c_V = *from_V;
- }
- if (y & 0x1) {
- /* Finished two pixel lines: move to the next U/V line */
- to_U = c_U; to_V = c_V;
- } else {
- /* Reset U/V pointers to the beginning of the line */
- c_U = to_U; c_V = to_V;
- }
- }
-}
-
-/* Converts YUYV frame into YV12 frame. */
-static void _YUYV_to_YV12(const uint8_t* from,
- int width,
- int height,
- uint8_t* to)
-{
- _YUY422_to_YV12(from, from + 1, from + 3, 2, width, height, to);
+ const uint8_t* rgb_ptr = (const uint8_t*)rgb;
+ *r = rgb_ptr[0]; *g = rgb_ptr[1]; *b = rgb_ptr[2];
+ return rgb_ptr + 4;
}
-/* Converts YVYU frame into YV12 frame. */
-static void _YVYU_to_YV12(const uint8_t* from,
- int width,
- int height,
- uint8_t* to)
+/* Saves R, G, and B colors to a RGB32 framebuffer. */
+static void*
+_save_RGB32(void* rgb, uint8_t r, uint8_t g, uint8_t b)
{
- _YUY422_to_YV12(from, from + 3, from + 1, 2, width, height, to);
+ uint8_t* rgb_ptr = (uint8_t*)rgb;
+ rgb_ptr[0] = r; rgb_ptr[1] = g; rgb_ptr[2] = b;
+ return rgb_ptr + 4;
}
-/* Converts UYVY frame into YV12 frame. */
-static void _UYVY_to_YV12(const uint8_t* from,
- int width,
- int height,
- uint8_t* to)
+/* Loads R, G, and B colors from a BRG32 framebuffer. */
+static const void*
+_load_BRG32(const void* rgb, uint8_t* r, uint8_t* g, uint8_t* b)
{
- _YUY422_to_YV12(from + 1, from, from + 2, 2, width, height, to);
+ const uint8_t* rgb_ptr = (const uint8_t*)rgb;
+ *r = rgb_ptr[2]; *g = rgb_ptr[1]; *b = rgb_ptr[0];
+ return rgb_ptr + 4;
}
-/* Converts VYUY frame into YV12 frame. */
-static void _VYUY_to_YV12(const uint8_t* from,
- int width,
- int height,
- uint8_t* to)
+/* Saves R, G, and B colors to a BRG32 framebuffer. */
+static void*
+_save_BRG32(void* rgb, uint8_t r, uint8_t g, uint8_t b)
{
- _YUY422_to_YV12(from + 1, from + 2, from, 2, width, height, to);
+ uint8_t* rgb_ptr = (uint8_t*)rgb;
+ rgb_ptr[2] = r; rgb_ptr[1] = g; rgb_ptr[0] = b;
+ return rgb_ptr + 4;
}
-/* Converts YYUV frame into YV12 frame. */
-static void _YYUV_to_YV12(const uint8_t* from,
- int width,
- int height,
- uint8_t* to)
+/* Loads R, G, and B colors from a RGB24 framebuffer.
+ * Note that it's the caller's responsibility to ensure proper alignment of the
+ * returned pointer at the line's break. */
+static const void*
+_load_RGB24(const void* rgb, uint8_t* r, uint8_t* g, uint8_t* b)
{
- _YUY422_to_YV12(from, from + 2, from + 3, 1, width, height, to);
+ const uint8_t* rgb_ptr = (const uint8_t*)rgb;
+ *r = rgb_ptr[0]; *g = rgb_ptr[1]; *b = rgb_ptr[2];
+ return rgb_ptr + 3;
}
-/* Converts YYVU frame into YV12 frame. */
-static void _YYVU_to_YV12(const uint8_t* from,
- int width,
- int height,
- uint8_t* to)
-{
- _YUY422_to_YV12(from, from + 3, from + 2, 1, width, height, to);
-}
-
-/********************************************************************************
- * YUV -> NV21 converters.
- *******************************************************************************/
-
-/* Common converter for a variety of YUV 4:2:2 formats to NV21.
- * NV21 contains a single interleaved UV pane, with V taking the lead. */
-static void _YUY422_to_NV21(const uint8_t* from_Y,
- const uint8_t* from_U,
- const uint8_t* from_V,
- int next_Y,
- int width,
- int height,
- uint8_t* nv21)
+/* Saves R, G, and B colors to a RGB24 framebuffer.
+ * Note that it's the caller's responsibility to ensure proper alignment of the
+ * returned pointer at the line's break. */
+static void*
+_save_RGB24(void* rgb, uint8_t r, uint8_t g, uint8_t b)
{
- const int total_pix = width * height;
- uint8_t* to_Y = nv21;
- uint8_t* to_V = nv21 + total_pix;
- uint8_t* to_U = to_V + 1;
- uint8_t* c_U = to_U;
- uint8_t* c_V = to_V;
- int x, y;
-
- for (y = 0; y < height; y++) {
- for (x = 0; x < width; x += 2, to_Y += 2, c_U += 2, c_V += 2,
- from_Y += 4, from_U += 4, from_V += 4) {
- *to_Y = *from_Y; to_Y[1] = from_Y[next_Y];
- *c_U = *from_U; *c_V = *from_V;
- }
- if (y & 0x1) {
- /* Finished two pixel lines: move to the next U/V line */
- to_U = c_U; to_V = c_V;
- } else {
- /* Reset U/V pointers to the beginning of the line */
- c_U = to_U; c_V = to_V;
- }
- }
+ uint8_t* rgb_ptr = (uint8_t*)rgb;
+ rgb_ptr[0] = r; rgb_ptr[1] = g; rgb_ptr[2] = b;
+ return rgb_ptr + 3;
}
-/* Converts YUYV frame into NV21 frame. */
-static void _YUYV_to_NV21(const uint8_t* from,
- int width,
- int height,
- uint8_t* to)
+/* Loads R, G, and B colors from a BRG32 framebuffer.
+ * Note that it's the caller's responsibility to ensure proper alignment of the
+ * returned pointer at the line's break. */
+static const void*
+_load_BRG24(const void* rgb, uint8_t* r, uint8_t* g, uint8_t* b)
{
- _YUY422_to_NV21(from, from + 1, from + 3, 2, width, height, to);
+ const uint8_t* rgb_ptr = (const uint8_t*)rgb;
+ *r = rgb_ptr[2]; *g = rgb_ptr[1]; *b = rgb_ptr[0];
+ return rgb_ptr + 3;
}
-/* Converts YVYU frame into NV21 frame. */
-static void _YVYU_to_NV21(const uint8_t* from,
- int width,
- int height,
- uint8_t* to)
+/* Saves R, G, and B colors to a BRG24 framebuffer.
+ * Note that it's the caller's responsibility to ensure proper alignment of the
+ * returned pointer at the line's break. */
+static void*
+_save_BRG24(void* rgb, uint8_t r, uint8_t g, uint8_t b)
{
- _YUY422_to_NV21(from, from + 3, from + 1, 2, width, height, to);
+ uint8_t* rgb_ptr = (uint8_t*)rgb;
+ rgb_ptr[2] = r; rgb_ptr[1] = g; rgb_ptr[0] = b;
+ return rgb_ptr + 3;
}
-/* Converts UYVY frame into NV21 frame. */
-static void _UYVY_to_NV21(const uint8_t* from,
- int width,
- int height,
- uint8_t* to)
+/* Loads R, G, and B colors from a RGB565 framebuffer. */
+static const void*
+_load_RGB16(const void* rgb, uint8_t* r, uint8_t* g, uint8_t* b)
{
- _YUY422_to_NV21(from + 1, from, from + 2, 2, width, height, to);
+ const uint16_t rgb16 = *(const uint16_t*)rgb;
+ *r = R16(rgb16); *g = G16(rgb16); *b = B16(rgb16);
+ return (const uint8_t*)rgb + 2;
}
-/* Converts VYUY frame into NV21 frame. */
-static void _VYUY_to_NV21(const uint8_t* from,
- int width,
- int height,
- uint8_t* to)
+/* Saves R, G, and B colors to a RGB565 framebuffer. */
+static void*
+_save_RGB16(void* rgb, uint8_t r, uint8_t g, uint8_t b)
{
- _YUY422_to_NV21(from + 1, from + 2, from, 2, width, height, to);
+ *(uint16_t*)rgb = RGB565(r & 0x1f, g & 0x3f, b & 0x1f);
+ return (uint8_t*)rgb + 2;
}
-/* Converts YYUV frame into NV21 frame. */
-static void _YYUV_to_NV21(const uint8_t* from,
- int width,
- int height,
- uint8_t* to)
+/* Loads R, G, and B colors from a BRG565 framebuffer. */
+static const void*
+_load_BRG16(const void* rgb, uint8_t* r, uint8_t* g, uint8_t* b)
{
- _YUY422_to_NV21(from, from + 2, from + 3, 1, width, height, to);
+ const uint16_t rgb16 = *(const uint16_t*)rgb;
+ *r = B16(rgb16); *g = G16(rgb16); *b = R16(rgb16);
+ return (const uint8_t*)rgb + 2;
}
-/* Converts YYVU frame into NV21 frame. */
-static void _YYVU_to_NV21(const uint8_t* from,
- int width,
- int height,
- uint8_t* to)
+/* Saves R, G, and B colors to a BRG565 framebuffer. */
+static void*
+_save_BRG16(void* rgb, uint8_t r, uint8_t g, uint8_t b)
{
- _YUY422_to_NV21(from, from + 3, from + 2, 1, width, height, to);
+ *(uint16_t*)rgb = RGB565(b & 0x1f, g & 0x3f, r & 0x1f);
+ return (uint8_t*)rgb + 2;
}
/********************************************************************************
- * YUV -> NV12 converters.
+ * YUV's U/V offset calculation routines.
*******************************************************************************/
-/* Common converter for a variety of YUV 4:2:2 formats to NV12.
- * NV12 contains a single interleaved UV pane, with U taking the lead. */
-static void _YUY422_to_NV12(const uint8_t* from_Y,
- const uint8_t* from_U,
- const uint8_t* from_V,
- int next_Y,
- int width,
- int height,
- uint8_t* nv21)
-{
- const int total_pix = width * height;
- uint8_t* to_Y = nv21;
- uint8_t* to_U = nv21 + total_pix;
- uint8_t* to_V = to_U + 1;
- uint8_t* c_U = to_U;
- uint8_t* c_V = to_V;
- int x, y;
-
- for (y = 0; y < height; y++) {
- for (x = 0; x < width; x += 2, to_Y += 2, c_U += 2, c_V += 2,
- from_Y += 4, from_U += 4, from_V += 4) {
- *to_Y = *from_Y; to_Y[1] = from_Y[next_Y];
- *c_U = *from_U; *c_V = *from_V;
- }
- if (y & 0x1) {
- /* Finished two pixel lines: move to the next U/V line */
- to_U = c_U; to_V = c_V;
- } else {
- /* Reset U/V pointers to the beginning of the line */
- c_U = to_U; c_V = to_V;
- }
- }
-}
-
-/* Converts YUYV frame into NV12 frame. */
-static void _YUYV_to_NV12(const uint8_t* from,
- int width,
- int height,
- uint8_t* to)
+/* U offset in a fully interleaved YUV 4:2:2 */
+static int
+_UOffIntrlYUV(const YUVDesc* desc, int line, int width, int height)
{
- _YUY422_to_NV12(from, from + 1, from + 3, 2, width, height, to);
+ /* In interleaved YUV 4:2:2 each pair of pixels is encoded with 4 consecutive
+ * bytes (or 2 bytes per pixel). So line size in a fully interleaved YUV 4:2:2
+ * is twice its width. */
+ return line * width * 2 + desc->U_offset;
}
-/* Converts YVYU frame into NV12 frame. */
-static void _YVYU_to_NV12(const uint8_t* from,
- int width,
- int height,
- uint8_t* to)
+/* V offset in a fully interleaved YUV 4:2:2 */
+static int
+_VOffIntrlYUV(const YUVDesc* desc, int line, int width, int height)
{
- _YUY422_to_NV12(from, from + 3, from + 1, 2, width, height, to);
+ /* See _UOffIntrlYUV comments. */
+ return line * width * 2 + desc->V_offset;
}
-/* Converts UYVY frame into NV12 frame. */
-static void _UYVY_to_NV12(const uint8_t* from,
- int width,
- int height,
- uint8_t* to)
+/* U offset in an interleaved UV pane of YUV 4:2:0 */
+static int
+_UOffIntrlUV(const YUVDesc* desc, int line, int width, int height)
{
- _YUY422_to_NV12(from + 1, from, from + 2, 2, width, height, to);
+ /* UV pane starts right after the Y pane, that occupies 'height * width'
+ * bytes. Eacht line in UV pane contains width / 2 'UV' pairs, which makes UV
+ * lane to contain as many bytes, as the width is.
+ * Each line in the UV pane is shared between two Y lines. So, final formula
+ * for the beggining of the UV pane's line for the given line in YUV
+ * framebuffer is:
+ *
+ * height * width + (line / 2) * width = (height + line / 2) * width
+ */
+ return (height + line / 2) * width + desc->U_offset;
}
-/* Converts VYUY frame into NV12 frame. */
-static void _VYUY_to_NV12(const uint8_t* from,
- int width,
- int height,
- uint8_t* to)
+/* V offset in an interleaved UV pane of YUV 4:2:0 */
+static int
+_VOffIntrlUV(const YUVDesc* desc, int line, int width, int height)
{
- _YUY422_to_NV12(from + 1, from + 2, from, 2, width, height, to);
+ /* See comments in _UOffIntrlUV. */
+ return (height + line / 2) * width + desc->V_offset;
}
-/* Converts YYUV frame into NV12 frame. */
-static void _YYUV_to_NV12(const uint8_t* from,
- int width,
- int height,
- uint8_t* to)
+/* U offset in a 3-pane YUV 4:2:0 */
+static int
+_UOffSepYUV(const YUVDesc* desc, int line, int width, int height)
{
- _YUY422_to_NV12(from, from + 2, from + 3, 1, width, height, to);
+ /* U, or V pane starts right after the Y pane, that occupies 'height * width'
+ * bytes. Eacht line in each of U and V panes contains width / 2 elements.
+ * Also, each line in each of U and V panes is shared between two Y lines.
+ * So, final formula for the beggining of a line in the U/V pane is:
+ *
+ * <Y pane size> + (line / 2) * width / 2
+ *
+ * for the pane that follows right after the Y pane, or
+ *
+ * <Y pane size> + <Y pane size> / 4 + (line / 2) * width / 2
+ *
+ * for the second pane.
+ */
+ const int y_pane_size = height * width;
+ if (desc->U_offset) {
+ /* U pane comes right after the Y pane. */
+ return y_pane_size + (line / 2) * width / 2;
+ } else {
+ /* U pane follows V pane. */
+ return y_pane_size + y_pane_size / 4 + (line / 2) * width / 2;
+ }
}
-/* Converts YYVU frame into NV12 frame. */
-static void _YYVU_to_NV12(const uint8_t* from,
- int width,
- int height,
- uint8_t* to)
+/* V offset in a 3-pane YUV 4:2:0 */
+static int
+_VOffSepYUV(const YUVDesc* desc, int line, int width, int height)
{
- _YUY422_to_NV12(from, from + 3, from + 2, 1, width, height, to);
+ /* See comment for _UOffSepYUV. */
+ const int y_pane_size = height * width;
+ if (desc->V_offset) {
+ /* V pane comes right after the Y pane. */
+ return y_pane_size + (line / 2) * width / 2;
+ } else {
+ /* V pane follows U pane. */
+ return y_pane_size + y_pane_size / 4 + (line / 2) * width / 2;
+ }
}
/********************************************************************************
- * RGB -> YV12 converters.
+ * Generic YUV/RGB converters
*******************************************************************************/
-/* Converts RGB565 frame into YV12 frame. */
-static void _RGB565_to_YV12(const uint8_t* from,
- int width,
- int height,
- uint8_t* to)
+/* Generic converter from an RGB/BRG format to a YUV format. */
+static void
+RGBToYUV(const RGBDesc* rgb_fmt,
+ const YUVDesc* yuv_fmt,
+ const void* rgb,
+ void* yuv,
+ int width,
+ int height)
{
- const int total_pix = width * height;
- const uint16_t* rgb = (const uint16_t*)from;
- uint8_t* to_Y = to;
- uint8_t* to_Cb = to + total_pix;
- uint8_t* to_Cr = to_Cb + total_pix / 4;
- uint8_t* Cb = to_Cb;
- uint8_t* Cr = to_Cr;
- int x, y;
-
+ int y, x;
+ const int Y_Inc = yuv_fmt->Y_inc;
+ const int UV_inc = yuv_fmt->UV_inc;
+ const int Y_next_pair = yuv_fmt->Y_next_pair;
+ uint8_t* pY = (uint8_t*)yuv + yuv_fmt->Y_offset;
for (y = 0; y < height; y++) {
- for (x = 0; x < width; x += 2, to_Cb++, to_Cr++) {
- RGB565ToYUV(*rgb, to_Y, to_Cb, to_Cr); rgb++; to_Y++;
- RGB565ToYUV(*rgb, to_Y, to_Cb, to_Cr); rgb++; to_Y++;
- }
- if (y & 0x1) {
- to_Cb = Cb; to_Cr = Cr;
- } else {
- Cb = to_Cb; Cr = to_Cr;
+ uint8_t* pU =
+ (uint8_t*)yuv + yuv_fmt->u_offset(yuv_fmt, y, width, height);
+ uint8_t* pV =
+ (uint8_t*)yuv + yuv_fmt->v_offset(yuv_fmt, y, width, height);
+ for (x = 0; x < width; x += 2,
+ pY += Y_next_pair, pU += UV_inc, pV += UV_inc) {
+ uint8_t r, g, b;
+ rgb = rgb_fmt->load_rgb(rgb, &r, &g, &b);
+ R8G8B8ToYUV(r, g, b, pY, pU, pV);
+ rgb = rgb_fmt->load_rgb(rgb, &r, &g, &b);
+ pY[Y_Inc] = RGB2Y((int)r, (int)g, (int)b);
}
+ /* Aling rgb_ptr to 16 bit */
+ if (((uintptr_t)rgb & 1) != 0) rgb = (const uint8_t*)rgb + 1;
}
}
-/* Converts RGB24 frame into YV12 frame. */
-static void _RGB24_to_YV12(const uint8_t* from,
- int width,
- int height,
- uint8_t* to)
+/* Generic converter from one RGB/BRG format to another RGB/BRG format. */
+static void
+RGBToRGB(const RGBDesc* src_rgb_fmt,
+ const RGBDesc* dst_rgb_fmt,
+ const void* src_rgb,
+ void* dst_rgb,
+ int width,
+ int height)
{
- const int total_pix = width * height;
- /* Bytes per line: each line must be WORD aligned. */
- const int bpl = (width * 3 + 1) & ~1;
- const uint8_t* line_start = from;
- uint8_t* to_Y = to;
- uint8_t* to_Cb = to + total_pix;
- uint8_t* to_Cr = to_Cb + total_pix / 4;
- uint8_t* Cb = to_Cb;
- uint8_t* Cr = to_Cr;
int x, y;
-
for (y = 0; y < height; y++) {
- from = line_start;
- for (x = 0; x < width; x += 2, from += 6, to_Cb++, to_Cr++) {
- R8G8B8ToYUV(from[0], from[1], from[2], to_Y, to_Cb, to_Cr); to_Y++;
- R8G8B8ToYUV(from[3], from[4], from[5], to_Y, to_Cb, to_Cr); to_Y++;
+ for (x = 0; x < width; x++) {
+ uint8_t r, g, b;
+ src_rgb = src_rgb_fmt->load_rgb(src_rgb, &r, &g, &b);
+ dst_rgb = dst_rgb_fmt->save_rgb(dst_rgb, r, g, b);
}
- if (y & 0x1) {
- to_Cb = Cb; to_Cr = Cr;
- } else {
- Cb = to_Cb; Cr = to_Cr;
- }
- /* Advance to next line, keeping proper alignment. */
- line_start += bpl;
+ /* Aling rgb pinters to 16 bit */
+ if (((uintptr_t)src_rgb & 1) != 0) src_rgb = (uint8_t*)src_rgb + 1;
+ if (((uintptr_t)dst_rgb & 1) != 0) dst_rgb = (uint8_t*)dst_rgb + 1;
}
}
-/* Converts RGB32 frame into YV12 frame. */
-static void _RGB32_to_YV12(const uint8_t* from,
- int width,
- int height,
- uint8_t* to)
+/* Generic converter from a YUV format to an RGB/BRG format. */
+static void
+YUVToRGB(const YUVDesc* yuv_fmt,
+ const RGBDesc* rgb_fmt,
+ const void* yuv,
+ void* rgb,
+ int width,
+ int height)
{
- const int total_pix = width * height;
- uint8_t* to_Y = to;
- uint8_t* to_Cb = to + total_pix;
- uint8_t* to_Cr = to_Cb + total_pix / 4;
- uint8_t* Cb = to_Cb;
- uint8_t* Cr = to_Cr;
- int x, y;
-
- for (y = 0; y < height; y++) {
- for (x = 0; x < width; x += 2, from += 8, to_Cb++, to_Cr++) {
- R8G8B8ToYUV(from[0], from[1], from[2], to_Y, to_Cb, to_Cr); to_Y++;
- R8G8B8ToYUV(from[4], from[5], from[6], to_Y, to_Cb, to_Cr); to_Y++;
- }
- if (y & 0x1) {
- to_Cb = Cb; to_Cr = Cr;
- } else {
- Cb = to_Cb; Cr = to_Cr;
- }
- }
-}
-
-/********************************************************************************
- * RGB -> NV12 converters.
- *******************************************************************************/
-
-/* Converts RGB565 frame into NV12 frame. */
-static void _RGB565_to_NV12(const uint8_t* from,
- int width,
- int height,
- uint8_t* to)
-{
- const int total_pix = width * height;
- const uint16_t* rgb = (const uint16_t*)from;
- uint8_t* to_Y = to;
- uint8_t* to_Cb = to + total_pix;
- uint8_t* to_Cr = to_Cb + 1;
- uint8_t* Cb = to_Cb;
- uint8_t* Cr = to_Cr;
- int x, y;
-
+ int y, x;
+ const int Y_Inc = yuv_fmt->Y_inc;
+ const int UV_inc = yuv_fmt->UV_inc;
+ const int Y_next_pair = yuv_fmt->Y_next_pair;
+ const uint8_t* pY = (const uint8_t*)yuv + yuv_fmt->Y_offset;
for (y = 0; y < height; y++) {
- for (x = 0; x < width; x += 2, to_Cb += 2, to_Cr += 2) {
- RGB565ToYUV(*rgb, to_Y, to_Cb, to_Cr); rgb++; to_Y++;
- RGB565ToYUV(*rgb, to_Y, to_Cb, to_Cr); rgb++; to_Y++;
- }
- if (y & 0x1) {
- to_Cb = Cb; to_Cr = Cr;
- } else {
- Cb = to_Cb; Cr = to_Cr;
+ const uint8_t* pU =
+ (const uint8_t*)yuv + yuv_fmt->u_offset(yuv_fmt, y, width, height);
+ const uint8_t* pV =
+ (const uint8_t*)yuv + yuv_fmt->v_offset(yuv_fmt, y, width, height);
+ for (x = 0; x < width; x += 2,
+ pY += Y_next_pair, pU += UV_inc, pV += UV_inc) {
+ uint8_t r, g, b;
+ const uint8_t U = *pU;
+ const uint8_t V = *pV;
+ YUVToRGBPix(*pY, U, V, &r, &g, &b);
+ rgb = rgb_fmt->save_rgb(rgb, r, g, b);
+ YUVToRGBPix(pY[Y_Inc], U, V, &r, &g, &b);
+ rgb = rgb_fmt->save_rgb(rgb, r, g, b);
}
+ /* Aling rgb_ptr to 16 bit */
+ if (((uintptr_t)rgb & 1) != 0) rgb = (uint8_t*)rgb + 1;
}
}
-/* Converts RGB24 frame into NV12 frame. */
-static void _RGB24_to_NV12(const uint8_t* from,
- int width,
- int height,
- uint8_t* to)
+/* Generic converter from one YUV format to another YUV format. */
+static void
+YUVToYUV(const YUVDesc* src_fmt,
+ const YUVDesc* dst_fmt,
+ const void* src,
+ void* dst,
+ int width,
+ int height)
{
- const int total_pix = width * height;
- /* Bytes per line: each line must be WORD aligned. */
- const int bpl = (width * 3 + 1) & ~1;
- const uint8_t* line_start = from;
- uint8_t* to_Y = to;
- uint8_t* to_Cb = to + total_pix;
- uint8_t* to_Cr = to_Cb + 1;
- uint8_t* Cb = to_Cb;
- uint8_t* Cr = to_Cr;
- int x, y;
-
+ int y, x;
+ const int Y_Inc_src = src_fmt->Y_inc;
+ const int UV_inc_src = src_fmt->UV_inc;
+ const int Y_next_pair_src = src_fmt->Y_next_pair;
+ const int Y_Inc_dst = dst_fmt->Y_inc;
+ const int UV_inc_dst = dst_fmt->UV_inc;
+ const int Y_next_pair_dst = dst_fmt->Y_next_pair;
+ const uint8_t* pYsrc = (const uint8_t*)src + src_fmt->Y_offset;
+ uint8_t* pYdst = (uint8_t*)dst + dst_fmt->Y_offset;
for (y = 0; y < height; y++) {
- from = line_start;
- for (x = 0; x < width; x += 2, from += 6, to_Cb += 2, to_Cr += 2) {
- R8G8B8ToYUV(from[0], from[1], from[2], to_Y, to_Cb, to_Cr); to_Y++;
- R8G8B8ToYUV(from[3], from[4], from[5], to_Y, to_Cb, to_Cr); to_Y++;
- }
- if (y & 0x1) {
- to_Cb = Cb; to_Cr = Cr;
- } else {
- Cb = to_Cb; Cr = to_Cr;
- }
- /* Advance to next line, keeping proper alignment. */
- line_start += bpl;
- }
-}
-
-/* Converts RGB32 frame into NV12 frame. */
-static void _RGB32_to_NV12(const uint8_t* from,
- int width,
- int height,
- uint8_t* to)
-{
- const int total_pix = width * height;
- uint8_t* to_Y = to;
- uint8_t* to_Cb = to + total_pix;
- uint8_t* to_Cr = to_Cb + 1;
- uint8_t* Cb = to_Cb;
- uint8_t* Cr = to_Cr;
- int x, y;
-
- for (y = 0; y < height; y++) {
- for (x = 0; x < width; x += 2, from += 8, to_Cb += 2, to_Cr += 2) {
- R8G8B8ToYUV(from[0], from[1], from[2], to_Y, to_Cb, to_Cr); to_Y++;
- R8G8B8ToYUV(from[4], from[5], from[6], to_Y, to_Cb, to_Cr); to_Y++;
- }
- if (y & 0x1) {
- to_Cb = Cb; to_Cr = Cr;
- } else {
- Cb = to_Cb; Cr = to_Cr;
+ const uint8_t* pUsrc =
+ (const uint8_t*)src + src_fmt->u_offset(src_fmt, y, width, height);
+ const uint8_t* pVsrc =
+ (const uint8_t*)src + src_fmt->v_offset(src_fmt, y, width, height);
+ uint8_t* pUdst =
+ (uint8_t*)dst + dst_fmt->u_offset(dst_fmt, y, width, height);
+ uint8_t* pVdst =
+ (uint8_t*)dst + dst_fmt->v_offset(dst_fmt, y, width, height);
+ for (x = 0; x < width; x += 2, pYsrc += Y_next_pair_src,
+ pUsrc += UV_inc_src,
+ pVsrc += UV_inc_src,
+ pYdst += Y_next_pair_dst,
+ pUdst += UV_inc_dst,
+ pVdst += UV_inc_dst) {
+ *pYdst = *pYsrc; *pUdst = *pUsrc; *pVdst = *pVsrc;
+ pYdst[Y_Inc_dst] = pYsrc[Y_Inc_src];
}
}
}
/********************************************************************************
- * RGB -> NV21 converters.
- *******************************************************************************/
+ * RGB format descriptors.
+ */
-/* Converts RGB565 frame into NV21 frame. */
-static void _RGB565_to_NV21(const uint8_t* from,
- int width,
- int height,
- uint8_t* to)
+/* Describes RGB32 format. */
+static const RGBDesc _RGB32 =
{
- const int total_pix = width * height;
- const uint16_t* rgb = (const uint16_t*)from;
- uint8_t* to_Y = to;
- uint8_t* to_Cr = to + total_pix;
- uint8_t* to_Cb = to_Cr + 1;
- uint8_t* Cb = to_Cb;
- uint8_t* Cr = to_Cr;
- int x, y;
-
- for (y = 0; y < height; y++) {
- for (x = 0; x < width; x += 2, to_Cb += 2, to_Cr += 2) {
- RGB565ToYUV(*rgb, to_Y, to_Cb, to_Cr); rgb++; to_Y++;
- RGB565ToYUV(*rgb, to_Y, to_Cb, to_Cr); rgb++; to_Y++;
- }
- if (y & 0x1) {
- to_Cb = Cb; to_Cr = Cr;
- } else {
- Cb = to_Cb; Cr = to_Cr;
- }
- }
-}
+ .load_rgb = _load_RGB32,
+ .save_rgb = _save_RGB32,
+ .rgb_inc = 4
+};
-/* Converts RGB24 frame into NV21 frame. */
-static void _RGB24_to_NV21(const uint8_t* from,
- int width,
- int height,
- uint8_t* to)
+/* Describes BRG32 format. */
+static const RGBDesc _BRG32 =
{
- const int total_pix = width * height;
- /* Bytes per line: each line must be WORD aligned. */
- const int bpl = (width * 3 + 1) & ~1;
- const uint8_t* line_start = from;
- uint8_t* to_Y = to;
- uint8_t* to_Cr = to + total_pix;
- uint8_t* to_Cb = to_Cr + 1;
- uint8_t* Cb = to_Cb;
- uint8_t* Cr = to_Cr;
- int x, y;
-
- for (y = 0; y < height; y++) {
- from = line_start;
- for (x = 0; x < width; x += 2, from += 6, to_Cb += 2, to_Cr += 2) {
- R8G8B8ToYUV(from[0], from[1], from[2], to_Y, to_Cb, to_Cr); to_Y++;
- R8G8B8ToYUV(from[3], from[4], from[5], to_Y, to_Cb, to_Cr); to_Y++;
- }
- if (y & 0x1) {
- to_Cb = Cb; to_Cr = Cr;
- } else {
- Cb = to_Cb; Cr = to_Cr;
- }
- /* Advance to next line, keeping proper alignment. */
- line_start += bpl;
- }
-}
+ .load_rgb = _load_BRG32,
+ .save_rgb = _save_BRG32,
+ .rgb_inc = 4
+};
-/* Converts RGB32 frame into NV21 frame. */
-static void _RGB32_to_NV21(const uint8_t* from,
- int width,
- int height,
- uint8_t* to)
+/* Describes RGB24 format. */
+static const RGBDesc _RGB24 =
{
- const int total_pix = width * height;
- uint8_t* to_Y = to;
- uint8_t* to_Cr = to + total_pix;
- uint8_t* to_Cb = to_Cr + 1;
- uint8_t* Cb = to_Cb;
- uint8_t* Cr = to_Cr;
- int x, y;
-
- for (y = 0; y < height; y++) {
- for (x = 0; x < width; x += 2, from += 8, to_Cb += 2, to_Cr += 2) {
- R8G8B8ToYUV(from[0], from[1], from[2], to_Y, to_Cb, to_Cr); to_Y++;
- R8G8B8ToYUV(from[4], from[5], from[6], to_Y, to_Cb, to_Cr); to_Y++;
- }
- if (y & 0x1) {
- to_Cb = Cb; to_Cr = Cr;
- } else {
- Cb = to_Cb; Cr = to_Cr;
- }
- }
-}
-
-/********************************************************************************
- * BGR -> YV12 converters.
- *******************************************************************************/
+ .load_rgb = _load_RGB24,
+ .save_rgb = _save_RGB24,
+ .rgb_inc = 3
+};
-/* Converts BGR24 frame into YV12 frame. */
-static void _BGR24_to_YV12(const uint8_t* from,
- int width,
- int height,
- uint8_t* to)
+/* Describes BRG24 format. */
+static const RGBDesc _BRG24 =
{
- const int total_pix = width * height;
- /* Bytes per line: each line must be WORD aligned. */
- const int bpl = (width * 3 + 1) & ~1;
- const uint8_t* line_start = from;
- uint8_t* to_Y = to;
- uint8_t* to_Cb = to + total_pix;
- uint8_t* to_Cr = to_Cb + total_pix / 4;
- uint8_t* Cb = to_Cb;
- uint8_t* Cr = to_Cr;
- int x, y;
-
- for (y = 0; y < height; y++) {
- from = line_start;
- for (x = 0; x < width; x += 2, from += 6, to_Cb++, to_Cr++) {
- R8G8B8ToYUV(from[2], from[1], from[0], to_Y, to_Cb, to_Cr); to_Y++;
- R8G8B8ToYUV(from[5], from[4], from[3], to_Y, to_Cb, to_Cr); to_Y++;
- }
- if (y & 0x1) {
- to_Cb = Cb; to_Cr = Cr;
- } else {
- Cb = to_Cb; Cr = to_Cr;
- }
- /* Advance to next line, keeping proper alignment. */
- line_start += bpl;
- }
-}
+ .load_rgb = _load_BRG24,
+ .save_rgb = _save_BRG24,
+ .rgb_inc = 3
+};
-/* Converts BGR32 frame into YV12 frame. */
-static void _BGR32_to_YV12(const uint8_t* from,
- int width,
- int height,
- uint8_t* to)
+/* Describes RGB16 format. */
+static const RGBDesc _RGB16 =
{
- const int total_pix = width * height;
- uint8_t* to_Y = to;
- uint8_t* to_Cb = to + total_pix;
- uint8_t* to_Cr = to_Cb + total_pix / 4;
- uint8_t* Cb = to_Cb;
- uint8_t* Cr = to_Cr;
- int x, y;
+ .load_rgb = _load_RGB16,
+ .save_rgb = _save_RGB16,
+ .rgb_inc = 2
+};
- for (y = 0; y < height; y++) {
- for (x = 0; x < width; x += 2, from += 8, to_Cb++, to_Cr++) {
- R8G8B8ToYUV(from[2], from[1], from[0], to_Y, to_Cb, to_Cr); to_Y++;
- R8G8B8ToYUV(from[6], from[5], from[4], to_Y, to_Cb, to_Cr); to_Y++;
- }
- if (y & 0x1) {
- to_Cb = Cb; to_Cr = Cr;
- } else {
- Cb = to_Cb; Cr = to_Cr;
- }
- }
-}
+/* Describes BRG16 format. */
+static const RGBDesc _BRG16 =
+{
+ .load_rgb = _load_BRG16,
+ .save_rgb = _save_BRG16,
+ .rgb_inc = 2
+};
/********************************************************************************
- * BGR -> NV12 converters.
- *******************************************************************************/
+ * YUV 4:2:2 format descriptors.
+ */
-/* Converts BGR24 frame into NV12 frame. */
-static void _BGR24_to_NV12(const uint8_t* from,
- int width,
- int height,
- uint8_t* to)
+/* YUYV: 4:2:2, YUV are interleaved. */
+static const YUVDesc _YUYV =
{
- const int total_pix = width * height;
- /* Bytes per line: each line must be WORD aligned. */
- const int bpl = (width * 3 + 1) & ~1;
- const uint8_t* line_start = from;
- uint8_t* to_Y = to;
- uint8_t* to_Cb = to + total_pix;
- uint8_t* to_Cr = to_Cb + 1;
- uint8_t* Cb = to_Cb;
- uint8_t* Cr = to_Cr;
- int x, y;
-
- for (y = 0; y < height; y++) {
- from = line_start;
- for (x = 0; x < width; x += 2, from += 6, to_Cb += 2, to_Cr += 2) {
- R8G8B8ToYUV(from[2], from[1], from[0], to_Y, to_Cb, to_Cr); to_Y++;
- R8G8B8ToYUV(from[5], from[4], from[3], to_Y, to_Cb, to_Cr); to_Y++;
- }
- if (y & 0x1) {
- to_Cb = Cb; to_Cr = Cr;
- } else {
- Cb = to_Cb; Cr = to_Cr;
- }
- /* Advance to next line, keeping proper alignment. */
- line_start += bpl;
- }
-}
+ .Y_offset = 0,
+ .Y_inc = 2,
+ .Y_next_pair = 4,
+ .UV_inc = 4,
+ .U_offset = 1,
+ .V_offset = 3,
+ .u_offset = &_UOffIntrlYUV,
+ .v_offset = &_VOffIntrlYUV
+};
-/* Converts BGR32 frame into NV12 frame. */
-static void _BGR32_to_NV12(const uint8_t* from,
- int width,
- int height,
- uint8_t* to)
+/* UYVY: 4:2:2, YUV are interleaved. */
+static const YUVDesc _UYVY =
{
- const int total_pix = width * height;
- uint8_t* to_Y = to;
- uint8_t* to_Cb = to + total_pix;
- uint8_t* to_Cr = to_Cb + 1;
- uint8_t* Cb = to_Cb;
- uint8_t* Cr = to_Cr;
- int x, y;
-
- for (y = 0; y < height; y++) {
- for (x = 0; x < width; x += 2, from += 8, to_Cb += 2, to_Cr += 2) {
- R8G8B8ToYUV(from[2], from[1], from[0], to_Y, to_Cb, to_Cr); to_Y++;
- R8G8B8ToYUV(from[6], from[5], from[4], to_Y, to_Cb, to_Cr); to_Y++;
- }
- if (y & 0x1) {
- to_Cb = Cb; to_Cr = Cr;
- } else {
- Cb = to_Cb; Cr = to_Cr;
- }
- }
-}
-
-/********************************************************************************
- * BGR -> NV21 converters.
- *******************************************************************************/
+ .Y_offset = 1,
+ .Y_inc = 2,
+ .Y_next_pair = 4,
+ .UV_inc = 4,
+ .U_offset = 0,
+ .V_offset = 2,
+ .u_offset = &_UOffIntrlYUV,
+ .v_offset = &_VOffIntrlYUV
+};
-/* Converts BGR24 frame into NV21 frame. */
-static void _BGR24_to_NV21(const uint8_t* from,
- int width,
- int height,
- uint8_t* to)
+/* YVYU: 4:2:2, YUV are interleaved. */
+static const YUVDesc _YVYU =
{
- const int total_pix = width * height;
- /* Bytes per line: each line must be WORD aligned. */
- const int bpl = (width * 3 + 1) & ~1;
- const uint8_t* line_start = from;
- uint8_t* to_Y = to;
- uint8_t* to_Cr = to + total_pix;
- uint8_t* to_Cb = to_Cr + 1;
- uint8_t* Cb = to_Cb;
- uint8_t* Cr = to_Cr;
- int x, y;
+ .Y_offset = 0,
+ .Y_inc = 2,
+ .Y_next_pair = 4,
+ .UV_inc = 4,
+ .U_offset = 3,
+ .V_offset = 1,
+ .u_offset = &_UOffIntrlYUV,
+ .v_offset = &_VOffIntrlYUV
+};
- for (y = 0; y < height; y++) {
- from = line_start;
- for (x = 0; x < width; x += 2, from += 6, to_Cb += 2, to_Cr += 2) {
- R8G8B8ToYUV(from[2], from[1], from[0], to_Y, to_Cb, to_Cr); to_Y++;
- R8G8B8ToYUV(from[5], from[4], from[3], to_Y, to_Cb, to_Cr); to_Y++;
- }
- if (y & 0x1) {
- to_Cb = Cb; to_Cr = Cr;
- } else {
- Cb = to_Cb; Cr = to_Cr;
- }
- /* Advance to next line, keeping proper alignment. */
- line_start += bpl;
- }
-}
+/* VYUY: 4:2:2, YUV are interleaved. */
+static const YUVDesc _VYUY =
+{
+ .Y_offset = 1,
+ .Y_inc = 2,
+ .Y_next_pair = 4,
+ .UV_inc = 4,
+ .U_offset = 2,
+ .V_offset = 0,
+ .u_offset = &_UOffIntrlYUV,
+ .v_offset = &_VOffIntrlYUV
+};
-/* Converts BGR32 frame into NV21 frame. */
-static void _BGR32_to_NV21(const uint8_t* from,
- int width,
- int height,
- uint8_t* to)
+/* YYUV (also YUY2, YUNV, V422) : 4:2:2, YUV are interleaved. */
+static const YUVDesc _YYUV =
{
- const int total_pix = width * height;
- uint8_t* to_Y = to;
- uint8_t* to_Cr = to + total_pix;
- uint8_t* to_Cb = to_Cr + 1;
- uint8_t* Cb = to_Cb;
- uint8_t* Cr = to_Cr;
- int x, y;
+ .Y_offset = 0,
+ .Y_inc = 1,
+ .Y_next_pair = 4,
+ .UV_inc = 4,
+ .U_offset = 2,
+ .V_offset = 3,
+ .u_offset = &_UOffIntrlYUV,
+ .v_offset = &_VOffIntrlYUV
+};
- for (y = 0; y < height; y++) {
- for (x = 0; x < width; x += 2, from += 8, to_Cb += 2, to_Cr += 2) {
- R8G8B8ToYUV(from[2], from[1], from[0], to_Y, to_Cb, to_Cr); to_Y++;
- R8G8B8ToYUV(from[6], from[5], from[4], to_Y, to_Cb, to_Cr); to_Y++;
- }
- if (y & 0x1) {
- to_Cb = Cb; to_Cr = Cr;
- } else {
- Cb = to_Cb; Cr = to_Cr;
- }
- }
-}
+/* YYVU: 4:2:2, YUV are interleaved. */
+static const YUVDesc _YYVU =
+{
+ .Y_offset = 0,
+ .Y_inc = 1,
+ .Y_next_pair = 4,
+ .UV_inc = 4,
+ .U_offset = 3,
+ .V_offset = 2,
+ .u_offset = &_UOffIntrlYUV,
+ .v_offset = &_VOffIntrlYUV
+};
/********************************************************************************
- * RGB -> RGB565 converters.
- *******************************************************************************/
+ * YUV 4:2:0 descriptors.
+ */
-/* Converts RGB24 frame into RGB565 frame. */
-static void _RGB24_to_RGB565(const uint8_t* from,
- int width,
- int height,
- uint8_t* to)
+/* YV12: 4:2:0, YUV are fully separated, U pane follows V pane */
+static const YUVDesc _YV12 =
{
- /* Bytes per line: each line must be WORD aligned. */
- const int bpl = (width * 3 + 1) & ~1;
- const uint8_t* line_start = from;
- uint16_t* rgb = (uint16_t*)to;
- int x, y;
-
- for (y = 0; y < height; y++) {
- from = line_start;
- for (x = 0; x < width; x++, rgb++) {
- const uint16_t r = *from >> 3; from++;
- const uint16_t g = *from >> 2; from++;
- const uint16_t b = *from >> 3; from++;
- *rgb = b | (g << 5) | (r << 11);
- }
- /* Advance to next line, keeping proper alignment. */
- line_start += bpl;
- }
-}
+ .Y_offset = 0,
+ .Y_inc = 1,
+ .Y_next_pair = 2,
+ .UV_inc = 1,
+ .U_offset = 0,
+ .V_offset = 1,
+ .u_offset = &_UOffSepYUV,
+ .v_offset = &_VOffSepYUV
+};
-/* Converts RGB32 frame into RGB565 frame. */
-static void _RGB32_to_RGB565(const uint8_t* from,
- int width,
- int height,
- uint8_t* to)
+/* NV12: 4:2:0, UV are interleaved, V follows U in UV pane */
+static const YUVDesc _NV12 =
{
- /* Bytes per line: each line must be WORD aligned. */
- uint16_t* rgb = (uint16_t*)to;
- int x, y;
+ .Y_offset = 0,
+ .Y_inc = 1,
+ .Y_next_pair = 2,
+ .UV_inc = 2,
+ .U_offset = 1,
+ .V_offset = 0,
+ .u_offset = &_UOffIntrlUV,
+ .v_offset = &_VOffIntrlUV
+};
- for (y = 0; y < height; y++) {
- for (x = 0; x < width; x++, rgb++, from++) {
- const uint16_t r = *from >> 3; from++;
- const uint16_t g = *from >> 2; from++;
- const uint16_t b = *from >> 3; from++;
- *rgb = b | (g << 5) | (r << 11);
- }
- }
-}
+/* NV21: 4:2:0, UV are interleaved, U follows V in UV pane */
+static const YUVDesc _NV21 =
+{
+ .Y_offset = 0,
+ .Y_inc = 1,
+ .Y_next_pair = 2,
+ .UV_inc = 2,
+ .U_offset = 0,
+ .V_offset = 1,
+ .u_offset = &_UOffIntrlUV,
+ .v_offset = &_VOffIntrlUV
+};
/********************************************************************************
- * BGR -> RGB565 converters.
+ * List of descriptors for supported formats.
*******************************************************************************/
-/* Converts BGR24 frame into RGB565 frame. */
-static void _BGR24_to_RGB565(const uint8_t* from,
- int width,
- int height,
- uint8_t* to)
-{
- /* Bytes per line: each line must be WORD aligned. */
- const int bpl = (width * 3 + 1) & ~1;
- const uint8_t* line_start = from;
- uint16_t* rgb = (uint16_t*)to;
- int x, y;
-
- for (y = 0; y < height; y++) {
- from = line_start;
- for (x = 0; x < width; x++, rgb++) {
- const uint16_t b = *from >> 3; from++;
- const uint16_t g = *from >> 2; from++;
- const uint16_t r = *from >> 3; from++;
- *rgb = b | (g << 5) | (r << 11);
- }
- /* Advance to next line, keeping proper alignment. */
- line_start += bpl;
- }
-}
+/* Formats entry in the list of descriptors for supported formats. */
+typedef struct PIXFormat {
+ /* "FOURCC" (V4L2_PIX_FMT_XXX) format type. */
+ uint32_t fourcc_type;
+ /* RGB/YUV selector:
+ * 1 - Entry is related to an RGB/BRG format.
+ * 0 - Entry is related to a YUV format. */
+ int is_RGB;
+ union {
+ /* References RGB format descriptor for that format. */
+ const RGBDesc* rgb_desc;
+ /* References YUV format descriptor for that format. */
+ const YUVDesc* yuv_desc;
+ } desc;
+} PIXFormat;
+
+/* Array of supported pixel format descriptors. */
+static const PIXFormat _PIXFormats[] = {
+ /* RGB/BRG formats. */
+ { V4L2_PIX_FMT_RGB32, 1, .desc.rgb_desc = &_RGB32 },
+ { V4L2_PIX_FMT_BGR32, 1, .desc.rgb_desc = &_BRG32 },
+ { V4L2_PIX_FMT_RGB565, 1, .desc.rgb_desc = &_RGB16 },
+ { V4L2_PIX_FMT_RGB24, 1, .desc.rgb_desc = &_RGB24 },
+ { V4L2_PIX_FMT_BGR24, 1, .desc.rgb_desc = &_BRG24 },
+
+ /* YUV 4:2:0 formats. */
+ { V4L2_PIX_FMT_YVU420, 0, .desc.yuv_desc = &_YV12 },
+ { V4L2_PIX_FMT_NV12, 0, .desc.yuv_desc = &_NV12 },
+ { V4L2_PIX_FMT_NV21, 0, .desc.yuv_desc = &_NV21 },
+
+ /* YUV 4:2:2 formats. */
+ { V4L2_PIX_FMT_YUYV, 0, .desc.yuv_desc = &_YUYV },
+ { V4L2_PIX_FMT_YYUV, 0, .desc.yuv_desc = &_YYUV },
+ { V4L2_PIX_FMT_YVYU, 0, .desc.yuv_desc = &_YVYU },
+ { V4L2_PIX_FMT_UYVY, 0, .desc.yuv_desc = &_UYVY },
+ { V4L2_PIX_FMT_VYUY, 0, .desc.yuv_desc = &_VYUY },
+ { V4L2_PIX_FMT_YVYU, 0, .desc.yuv_desc = &_YVYU },
+ { V4L2_PIX_FMT_VYUY, 0, .desc.yuv_desc = &_VYUY },
+ { V4L2_PIX_FMT_YYVU, 0, .desc.yuv_desc = &_YYVU },
+ { V4L2_PIX_FMT_YUY2, 0, .desc.yuv_desc = &_YUYV },
+ { V4L2_PIX_FMT_YUNV, 0, .desc.yuv_desc = &_YUYV },
+ { V4L2_PIX_FMT_V422, 0, .desc.yuv_desc = &_YUYV },
+};
+static const int _PIXFormats_num = sizeof(_PIXFormats) / sizeof(*_PIXFormats);
-/* Converts BGR32 frame into RGB565 frame. */
-static void _BGR32_to_RGB565(const uint8_t* from,
- int width,
- int height,
- uint8_t* to)
+/* Get an entry in the array of supported pixel format descriptors.
+ * Param:
+ * pixel_format - "fourcc" pixel format to lookup an entry for.
+ * Return"
+ * Pointer to the found entry, or NULL if no entry exists for the given pixel
+ * format.
+ */
+static const PIXFormat*
+_get_pixel_format_descriptor(uint32_t pixel_format)
{
- /* Bytes per line: each line must be WORD aligned. */
- uint16_t* rgb = (uint16_t*)to;
- int x, y;
-
- for (y = 0; y < height; y++) {
- for (x = 0; x < width; x++, rgb++, from++) {
- const uint16_t b = *from >> 3; from++;
- const uint16_t g = *from >> 2; from++;
- const uint16_t r = *from >> 3; from++;
- *rgb = b | (g << 5) | (r << 11);
+ int f;
+ for (f = 0; f < _PIXFormats_num; f++) {
+ if (_PIXFormats[f].fourcc_type == pixel_format) {
+ return &_PIXFormats[f];
}
}
+ W("%s: Pixel format %.4s is unknown",
+ __FUNCTION__, (const char*)&pixel_format);
+ return NULL;
}
-/* Describes a converter for one pixel format to another. */
-typedef struct FormatConverterEntry {
- /* Pixel format to convert from. */
- uint32_t from_format;
- /* Pixel format to convert to. */
- uint32_t to_format;
- /* Address of the conversion routine. */
- FormatConverter converter;
-} FormatConverterEntry;
-
-
-/* Lists currently implemented converters. */
-static const FormatConverterEntry _converters[] = {
- /*
- * YUV 4:2:2 variety -> YV12
- */
-
- /* YUYV -> YV12 */
- { V4L2_PIX_FMT_YUYV, V4L2_PIX_FMT_YVU420, _YUYV_to_YV12 },
- /* UYVY -> YV12 */
- { V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YVU420, _UYVY_to_YV12 },
- /* YVYU -> YV12 */
- { V4L2_PIX_FMT_YVYU, V4L2_PIX_FMT_YVU420, _YVYU_to_YV12 },
- /* VYUY -> YV12 */
- { V4L2_PIX_FMT_VYUY, V4L2_PIX_FMT_YVU420, _VYUY_to_YV12 },
- /* YYUV -> YV12 */
- { V4L2_PIX_FMT_YYUV, V4L2_PIX_FMT_YVU420, _YYUV_to_YV12 },
- /* YUY2 -> YV12 This format is the same as YYUV */
- { V4L2_PIX_FMT_YUY2, V4L2_PIX_FMT_YVU420, _YYUV_to_YV12 },
- /* YUNV -> YV12 This format is the same as YYUV */
- { V4L2_PIX_FMT_YUNV, V4L2_PIX_FMT_YVU420, _YYUV_to_YV12 },
- /* V422 -> YV12 This format is the same as YYUV */
- { V4L2_PIX_FMT_V422, V4L2_PIX_FMT_YVU420, _YYUV_to_YV12 },
- /* YYVU -> YV12 */
- { V4L2_PIX_FMT_YYVU, V4L2_PIX_FMT_YVU420, _YYVU_to_YV12 },
-
- /*
- * YUV 4:2:2 variety -> NV21
- */
-
- /* YUYV -> YV12 */
- { V4L2_PIX_FMT_YUYV, V4L2_PIX_FMT_NV21, _YUYV_to_NV21 },
- /* UYVY -> YV12 */
- { V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_NV21, _UYVY_to_NV21 },
- /* YVYU -> YV12 */
- { V4L2_PIX_FMT_YVYU, V4L2_PIX_FMT_NV21, _YVYU_to_NV21 },
- /* VYUY -> YV12 */
- { V4L2_PIX_FMT_VYUY, V4L2_PIX_FMT_NV21, _VYUY_to_NV21 },
- /* YYUV -> YV12 */
- { V4L2_PIX_FMT_YYUV, V4L2_PIX_FMT_NV21, _YYUV_to_NV21 },
- /* YUY2 -> YV12 This format is the same as YYUV */
- { V4L2_PIX_FMT_YUY2, V4L2_PIX_FMT_NV21, _YYUV_to_NV21 },
- /* YUNV -> YV12 This format is the same as YYUV */
- { V4L2_PIX_FMT_YUNV, V4L2_PIX_FMT_NV21, _YYUV_to_NV21 },
- /* V422 -> YV12 This format is the same as YYUV */
- { V4L2_PIX_FMT_V422, V4L2_PIX_FMT_NV21, _YYUV_to_NV21 },
- /* YYVU -> YV12 */
- { V4L2_PIX_FMT_YYVU, V4L2_PIX_FMT_NV21, _YYVU_to_NV21 },
-
- /*
- * YUV 4:2:2 variety -> NV12
- */
-
- /* YUYV -> YV12 */
- { V4L2_PIX_FMT_YUYV, V4L2_PIX_FMT_NV12, _YUYV_to_NV12 },
- /* UYVY -> YV12 */
- { V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_NV12, _UYVY_to_NV12 },
- /* YVYU -> YV12 */
- { V4L2_PIX_FMT_YVYU, V4L2_PIX_FMT_NV12, _YVYU_to_NV12 },
- /* VYUY -> YV12 */
- { V4L2_PIX_FMT_VYUY, V4L2_PIX_FMT_NV12, _VYUY_to_NV12 },
- /* YYUV -> YV12 */
- { V4L2_PIX_FMT_YYUV, V4L2_PIX_FMT_NV12, _YYUV_to_NV12 },
- /* YUY2 -> YV12 This format is the same as YYUV */
- { V4L2_PIX_FMT_YUY2, V4L2_PIX_FMT_NV12, _YYUV_to_NV12 },
- /* YUNV -> YV12 This format is the same as YYUV */
- { V4L2_PIX_FMT_YUNV, V4L2_PIX_FMT_NV12, _YYUV_to_NV12 },
- /* V422 -> YV12 This format is the same as YYUV */
- { V4L2_PIX_FMT_V422, V4L2_PIX_FMT_NV12, _YYUV_to_NV12 },
- /* YYVU -> YV12 */
- { V4L2_PIX_FMT_YYVU, V4L2_PIX_FMT_NV12, _YYVU_to_NV12 },
-
- /*
- * YUV 4:2:2 variety -> RGB565
- */
-
- /* YUYV -> RGB565 */
- { V4L2_PIX_FMT_YUYV, V4L2_PIX_FMT_RGB565, _YUYV_to_RGB565 },
- /* UYVY -> RGB565 */
- { V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_RGB565, _UYVY_to_RGB565 },
- /* YVYU -> RGB565 */
- { V4L2_PIX_FMT_YVYU, V4L2_PIX_FMT_RGB565, _YVYU_to_RGB565 },
- /* VYUY -> RGB565 */
- { V4L2_PIX_FMT_VYUY, V4L2_PIX_FMT_RGB565, _VYUY_to_RGB565 },
- /* YYUV -> RGB565 */
- { V4L2_PIX_FMT_YYUV, V4L2_PIX_FMT_RGB565, _YYUV_to_RGB565 },
- /* YUY2 -> RGB565 This format is the same as YYUV */
- { V4L2_PIX_FMT_YUY2, V4L2_PIX_FMT_RGB565, _YUYV_to_RGB565 },
- /* YUNV -> RGB565 This format is the same as YYUV */
- { V4L2_PIX_FMT_YUNV, V4L2_PIX_FMT_RGB565, _YUYV_to_RGB565 },
- /* V422 -> RGB565 This format is the same as YYUV */
- { V4L2_PIX_FMT_V422, V4L2_PIX_FMT_RGB565, _YUYV_to_RGB565 },
- /* YYVU -> RGB565 This format is the same as YYUV */
- { V4L2_PIX_FMT_YYVU, V4L2_PIX_FMT_RGB565, _YYVU_to_RGB565 },
-
- /*
- * YUV 4:2:2 variety -> RGB32
- */
-
- /* YUYV -> RGB565 */
- { V4L2_PIX_FMT_YUYV, V4L2_PIX_FMT_RGB32, _YUYV_to_RGB32 },
- /* UYVY -> RGB565 */
- { V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_RGB32, _UYVY_to_RGB32 },
- /* YVYU -> RGB565 */
- { V4L2_PIX_FMT_YVYU, V4L2_PIX_FMT_RGB32, _YVYU_to_RGB32 },
- /* VYUY -> RGB565 */
- { V4L2_PIX_FMT_VYUY, V4L2_PIX_FMT_RGB32, _VYUY_to_RGB32 },
- /* YYUV -> RGB565 */
- { V4L2_PIX_FMT_YYUV, V4L2_PIX_FMT_RGB32, _YYUV_to_RGB32 },
- /* YUY2 -> RGB565 This format is the same as YYUV */
- { V4L2_PIX_FMT_YUY2, V4L2_PIX_FMT_RGB32, _YUYV_to_RGB32 },
- /* YUNV -> RGB565 This format is the same as YYUV */
- { V4L2_PIX_FMT_YUNV, V4L2_PIX_FMT_RGB32, _YUYV_to_RGB32 },
- /* V422 -> RGB565 This format is the same as YYUV */
- { V4L2_PIX_FMT_V422, V4L2_PIX_FMT_RGB32, _YUYV_to_RGB32 },
- /* YYVU -> RGB565 This format is the same as YYUV */
- { V4L2_PIX_FMT_YYVU, V4L2_PIX_FMT_RGB32, _YYVU_to_RGB32 },
-
- /*
- * RGB variety -> YV12
- */
-
- /* RGB565 -> YV12 */
- { V4L2_PIX_FMT_RGB565, V4L2_PIX_FMT_YVU420, _RGB565_to_YV12 },
- /* RGB24 -> YV12 */
- { V4L2_PIX_FMT_RGB24, V4L2_PIX_FMT_YVU420, _RGB24_to_YV12 },
- /* RGB32 -> YV12 */
- { V4L2_PIX_FMT_RGB32, V4L2_PIX_FMT_YVU420, _RGB32_to_YV12 },
-
- /*
- * RGB variety -> NV12
- */
-
- /* RGB565 -> YV12 */
- { V4L2_PIX_FMT_RGB565, V4L2_PIX_FMT_NV12, _RGB565_to_NV12 },
- /* RGB24 -> YV12 */
- { V4L2_PIX_FMT_RGB24, V4L2_PIX_FMT_NV12, _RGB24_to_NV12 },
- /* RGB32 -> YV12 */
- { V4L2_PIX_FMT_RGB32, V4L2_PIX_FMT_NV12, _RGB32_to_NV12 },
-
- /*
- * RGB variety -> NV21
- */
-
- /* RGB565 -> YV12 */
- { V4L2_PIX_FMT_RGB565, V4L2_PIX_FMT_NV21, _RGB565_to_NV21 },
- /* RGB24 -> YV12 */
- { V4L2_PIX_FMT_RGB24, V4L2_PIX_FMT_NV21, _RGB24_to_NV21 },
- /* RGB32 -> YV12 */
- { V4L2_PIX_FMT_RGB32, V4L2_PIX_FMT_NV21, _RGB32_to_NV21 },
-
- /*
- * BGR variety -> YV12
- */
-
- /* BGR24 -> YV12 */
- { V4L2_PIX_FMT_BGR24, V4L2_PIX_FMT_YVU420, _BGR24_to_YV12 },
- /* BGR32 -> YV12 */
- { V4L2_PIX_FMT_BGR32, V4L2_PIX_FMT_YVU420, _BGR32_to_YV12 },
-
- /*
- * BGR variety -> NV12
- */
-
- /* BGR24 -> NV12 */
- { V4L2_PIX_FMT_BGR24, V4L2_PIX_FMT_NV12, _BGR24_to_NV12 },
- /* BGR32 -> NV12 */
- { V4L2_PIX_FMT_BGR32, V4L2_PIX_FMT_NV12, _BGR32_to_NV12 },
-
- /*
- * BGR variety -> NV21
- */
-
- /* BGR24 -> NV21 */
- { V4L2_PIX_FMT_BGR24, V4L2_PIX_FMT_NV21, _BGR24_to_NV21 },
- /* BGR32 -> NV21 */
- { V4L2_PIX_FMT_BGR32, V4L2_PIX_FMT_NV21, _BGR32_to_NV21 },
-
- /*
- * RGB variety -> RGB565
- */
-
- /* RGB24 -> RGB565 */
- { V4L2_PIX_FMT_RGB24, V4L2_PIX_FMT_RGB565, _RGB24_to_RGB565 },
- /* RGB32 -> RGB565 */
- { V4L2_PIX_FMT_RGB32, V4L2_PIX_FMT_RGB565, _RGB32_to_RGB565 },
-
- /*
- * BGR variety -> RGB565
- */
-
- /* BGR24 -> RGB565 */
- { V4L2_PIX_FMT_BGR24, V4L2_PIX_FMT_RGB565, _BGR24_to_RGB565 },
- /* BGR32 -> RGB565 */
- { V4L2_PIX_FMT_BGR32, V4L2_PIX_FMT_RGB565, _BGR32_to_RGB565 },
-};
-
-/* Gets an address of a routine that provides frame conversion for the
- * given pixel formats.
- * Param:
- * from - Pixel format to convert from.
- * to - Pixel format to convert to.
- * Return:
- * Address of an appropriate conversion routine, or NULL if no conversion
- * routine exsits for the given pair of pixel formats.
- */
-static FormatConverter
-_get_format_converter(uint32_t from, uint32_t to)
-{
- const int num_converters = sizeof(_converters) / sizeof(*_converters);
- int n;
- for (n = 0; n < num_converters; n++) {
- if (_converters[n].from_format == from &&
- _converters[n].to_format == to) {
- return _converters[n].converter;
- }
- }
-
- E("%s: No converter found from %.4s to %.4s pixel formats",
- __FUNCTION__, (const char*)&from, (const char*)&to);
- return NULL;
-}
-
/********************************************************************************
* Public API
*******************************************************************************/
@@ -1481,8 +998,12 @@ _get_format_converter(uint32_t from, uint32_t to)
int
has_converter(uint32_t from, uint32_t to)
{
- return (from == to) ? 1 :
- (_get_format_converter(from, to) != NULL);
+ if (from == to) {
+ /* Same format: converter esists. */
+ return 1;
+ }
+ return _get_pixel_format_descriptor(from) != NULL &&
+ _get_pixel_format_descriptor(to) != NULL;
}
int
@@ -1495,24 +1016,42 @@ convert_frame(const void* frame,
int fbs_num)
{
int n;
+ const PIXFormat* src_desc = _get_pixel_format_descriptor(pixel_format);
+ if (src_desc == NULL) {
+ E("%s: Source pixel format %.4s is unknown",
+ __FUNCTION__, (const char*)&pixel_format);
+ return -1;
+ }
for (n = 0; n < fbs_num; n++) {
if (framebuffers[n].pixel_format == pixel_format) {
- /* Same pixel format. No conversion needed. */
+ /* Same pixel format. No conversion needed: just make a copy. */
memcpy(framebuffers[n].framebuffer, frame, framebuffer_size);
} else {
- /* Get the converter. Note that the client must have ensured the
- * existence of the converter when it was starting the camera. */
- FormatConverter convert =
- _get_format_converter(pixel_format, framebuffers[n].pixel_format);
- if (convert != NULL) {
- convert(frame, width, height, framebuffers[n].framebuffer);
- } else {
- E("%s No converter from %.4s to %.4s for framebuffer # %d ",
- __FUNCTION__, (const char*)&pixel_format,
- (const char*)&framebuffers[n].pixel_format, n);
+ const PIXFormat* dst_desc =
+ _get_pixel_format_descriptor(framebuffers[n].pixel_format);
+ if (dst_desc == NULL) {
+ E("%s: Destination pixel format %.4s is unknown",
+ __FUNCTION__, (const char*)&framebuffers[n].pixel_format);
return -1;
}
+ if (src_desc->is_RGB) {
+ if (dst_desc->is_RGB) {
+ RGBToRGB(src_desc->desc.rgb_desc, dst_desc->desc.rgb_desc,
+ frame, framebuffers[n].framebuffer, width, height);
+ } else {
+ RGBToYUV(src_desc->desc.rgb_desc, dst_desc->desc.yuv_desc,
+ frame, framebuffers[n].framebuffer, width, height);
+ }
+ } else {
+ if (dst_desc->is_RGB) {
+ YUVToRGB(src_desc->desc.yuv_desc, dst_desc->desc.rgb_desc,
+ frame, framebuffers[n].framebuffer, width, height);
+ } else {
+ YUVToYUV(src_desc->desc.yuv_desc, dst_desc->desc.yuv_desc,
+ frame, framebuffers[n].framebuffer, width, height);
+ }
+ }
}
}