camera-format-converters.c revision 88fceb022e53ede2f6a7e57a8cbd63f5ac2e1bb3
1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <stdint.h>
18#include <stdio.h>
19#include <stdlib.h>
20#ifdef _WIN32
21#elif _DARWIN_C_SOURCE
22#else
23#include <linux/videodev2.h>
24#endif
25#include "android/camera/camera-format-converters.h"
26
27/* Describes a convertor for one pixel format to another. */
28typedef struct FormatConverterEntry {
29    /* Pixel format to convert from. */
30    uint32_t          from_format;
31    /* Pixel format to convert to. */
32    uint32_t          to_format;
33    /* Address of the conversion routine. */
34    FormatConverter   converter;
35} FormatConverterEntry;
36
37/* Converts frame from RGB24 (8 bits per color) to NV12 (YUV420)
38 * Param:
39 *  rgb - RGB frame to convert.
40 *  width, height - Width, and height of the RGB frame.
41 *  yuv - Buffer to receive the converted frame. Note that this buffer must
42 *    be big enough to contain all the converted pixels!
43 */
44static void
45_RGB8_to_YUV420(const uint8_t* rgb,
46                int width,
47                int height,
48                uint8_t* yuv)
49{
50    const uint8_t* rgb_current = rgb;
51    int x, y, yi = 0;
52    const int num_pixels = width * height;
53    int ui = num_pixels;
54    int vi = num_pixels + num_pixels / 4;
55
56    for (y = 0; y < height; y++) {
57        for (x = 0; x < width; x++) {
58            const uint32_t b = rgb_current[0];
59            const uint32_t g = rgb_current[1];
60            const uint32_t r = rgb_current[2];
61            rgb_current += 3;
62            yuv[yi++] = (uint8_t)((66*r + 129*g +  25*b + 128) >> 8) + 16;
63            if((x % 2 ) == 0 && (y % 2) == 0) {
64                yuv[ui++] = (uint8_t)((-38*r - 74*g + 112*b + 128) >> 8 ) + 128;
65                yuv[vi++] = (uint8_t)((112*r - 94*g - 18*b + 128) >> 8 ) + 128;
66            }
67        }
68    }
69}
70
71/* Converts frame from RGB24 (8 bits per color) to NV21 (YVU420)
72 * Param:
73 *  rgb - RGB frame to convert.
74 *  width, height - Width, and height of the RGB frame.
75 *  yuv - Buffer to receive the converted frame. Note that this buffer must
76 *    be big enough to contain all the converted pixels!
77 */
78static void
79_RGB8_to_YVU420(const uint8_t* rgb,
80                int width,
81                int height,
82                uint8_t* yuv)
83{
84    const uint8_t* rgb_current = rgb;
85    int x, y, yi = 0;
86    const int num_pixels = width * height;
87    int vi = num_pixels;
88    int ui = num_pixels + num_pixels / 4;
89
90    for (y = 0; y < height; y++) {
91        for (x = 0; x < width; x++) {
92          const uint32_t b = rgb_current[0];
93          const uint32_t g = rgb_current[1];
94          const uint32_t r = rgb_current[2];
95          rgb_current += 3;
96          yuv[yi++] = (uint8_t)((66*r + 129*g +  25*b + 128) >> 8) + 16;
97          if((x % 2 ) == 0 && (y % 2) == 0) {
98              yuv[ui++] = (uint8_t)((-38*r - 74*g + 112*b + 128) >> 8 ) + 128;
99              yuv[vi++] = (uint8_t)((112*r - 94*g - 18*b + 128) >> 8 ) + 128;
100          }
101        }
102    }
103}
104
105/* Lists currently implemented converters. */
106static const FormatConverterEntry _converters[] = {
107    /* RGB24 -> NV12 */
108    { V4L2_PIX_FMT_RGB24, V4L2_PIX_FMT_NV12, _RGB8_to_YUV420 },
109    /* RGB24 -> YUV420 */
110    { V4L2_PIX_FMT_RGB24, V4L2_PIX_FMT_YUV420, _RGB8_to_YUV420 },
111    /* RGB24 -> NV21 */
112    { V4L2_PIX_FMT_RGB24, V4L2_PIX_FMT_NV21, _RGB8_to_YVU420 },
113};
114
115FormatConverter
116get_format_converted(uint32_t from, uint32_t to)
117{
118    const int num_converters = sizeof(_converters) / sizeof(*_converters);
119    int n;
120    for (n = 0; n < num_converters; n++) {
121        if (_converters[n].from_format == from &&
122            _converters[n].to_format == to) {
123            return _converters[n].converter;
124        }
125    }
126
127    return NULL;
128}
129