aboutsummaryrefslogtreecommitdiffstats
path: root/android/camera
diff options
context:
space:
mode:
authorVladimir Chtchetkine <vchtchetkine@google.com>2011-09-17 07:22:41 -0700
committerVladimir Chtchetkine <vchtchetkine@google.com>2011-09-17 07:22:41 -0700
commitd6362e54b7b116a42d45a1ef499ff180548c7674 (patch)
treee9107e575dbe39b5e1651ee8eaf39a608b038161 /android/camera
parent916106df33bcbceceb81b582a331915f487ea21e (diff)
downloadexternal_qemu-d6362e54b7b116a42d45a1ef499ff180548c7674.zip
external_qemu-d6362e54b7b116a42d45a1ef499ff180548c7674.tar.gz
external_qemu-d6362e54b7b116a42d45a1ef499ff180548c7674.tar.bz2
Refactor the converters to make them more manageable
The current conversion implementation was laking flexibility as far as adding support for new formats was concerned. In particular, adding support for each new format meant adding four converter routines: new format <--> RGB, new format <--> YUV. This was not scalable, so had to be rewritten. The new conversion implementation consists of four generic converters between different flavors og RGB/YUV formats, and array of descriptors for each supported format. Each descriptor contains information that is sufficient for the converter routines to perform its job. So, adding new format is just creating a new descriptor for that format, and adding it to the array of supported descriptors. Change-Id: Ica107d14fa03fa8f41eb9192f2c023a97f54b62c
Diffstat (limited to 'android/camera')
-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);
+ }
+ }
}
}