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 /* 18 * Contains implemenation of framebuffer conversion routines. 19 */ 20 21 #define LOG_NDEBUG 0 22 #define LOG_TAG "EmulatedCamera_Converter" 23 #include <log/log.h> 24 #include "Converters.h" 25 26 #include "Alignment.h" 27 28 namespace android { 29 30 static void _YUV420SToRGB565(const uint8_t* Y, 31 const uint8_t* U, 32 const uint8_t* V, 33 int dUV, 34 uint16_t* rgb, 35 int width, 36 int height, 37 int y_stride, 38 int uv_stride) 39 { 40 const uint8_t* Y_pos = Y; 41 const uint8_t* U_pos = U; 42 const uint8_t* V_pos = V; 43 44 for (int y = 0; y < height; y++) { 45 Y = Y_pos + y_stride * y; 46 U = U_pos + uv_stride * (y / 2); 47 V = V_pos + uv_stride * (y / 2); 48 for (int x = 0; x < width; x += 2, U += dUV, V += dUV) { 49 const uint8_t nU = *U; 50 const uint8_t nV = *V; 51 *rgb = YUVToRGB565(*Y, nU, nV); 52 Y++; rgb++; 53 *rgb = YUVToRGB565(*Y, nU, nV); 54 Y++; rgb++; 55 } 56 } 57 } 58 59 static void _YUV420SToRGB32(const uint8_t* Y, 60 const uint8_t* U, 61 const uint8_t* V, 62 int dUV, 63 uint32_t* rgb, 64 int width, 65 int height, 66 int y_stride, 67 int uv_stride) 68 { 69 const uint8_t* Y_pos = Y; 70 const uint8_t* U_pos = U; 71 const uint8_t* V_pos = V; 72 73 for (int y = 0; y < height; y++) { 74 Y = Y_pos + y_stride * y; 75 U = U_pos + uv_stride * (y / 2); 76 V = V_pos + uv_stride * (y / 2); 77 for (int x = 0; x < width; x += 2, U += dUV, V += dUV) { 78 const uint8_t nU = *U; 79 const uint8_t nV = *V; 80 *rgb = YUVToRGB32(*Y, nU, nV); 81 Y++; rgb++; 82 *rgb = YUVToRGB32(*Y, nU, nV); 83 Y++; rgb++; 84 } 85 } 86 } 87 88 /* The YV12 and YU12 formats require that the row strides are aligned to 16 byte 89 * boundaries as per the format specification at: 90 * https://developer.android.com/reference/android/graphics/ImageFormat.html#YV12 91 * 92 * This means that we can't just use the width or assume that pixels are 93 * tightly packed, we have to calculate aligned strides and use them to find the 94 * next row. 95 */ 96 void YV12ToRGB565(const void* yv12, void* rgb, int width, int height) 97 { 98 // See note above about alignment 99 const int y_stride = align(width, 16); 100 const int uv_stride = align(y_stride / 2, 16); 101 const uint8_t* Y = reinterpret_cast<const uint8_t*>(yv12); 102 const uint8_t* U = Y + y_stride * height; 103 const uint8_t* V = U + uv_stride * (height / 2); 104 _YUV420SToRGB565(Y, U, V, 1, reinterpret_cast<uint16_t*>(rgb), 105 width, height, y_stride, uv_stride); 106 } 107 108 void YV12ToRGB32(const void* yv12, void* rgb, int width, int height) 109 { 110 // See note above about alignment 111 const int y_stride = align(width, 16); 112 const int uv_stride = align(y_stride / 2, 16); 113 const uint8_t* Y = reinterpret_cast<const uint8_t*>(yv12); 114 const uint8_t* V = Y + y_stride * height; 115 const uint8_t* U = V + uv_stride * (height / 2); 116 _YUV420SToRGB32(Y, U, V, 1, reinterpret_cast<uint32_t*>(rgb), width, height, 117 y_stride, uv_stride); 118 } 119 120 void YU12ToRGB32(const void* yu12, void* rgb, int width, int height) 121 { 122 // See note above about alignment 123 const int y_stride = align(width, 16); 124 const int uv_stride = align(y_stride / 2, 16); 125 const uint8_t* Y = reinterpret_cast<const uint8_t*>(yu12); 126 const uint8_t* U = Y + y_stride * height; 127 const uint8_t* V = U + uv_stride * (height / 2); 128 _YUV420SToRGB32(Y, U, V, 1, reinterpret_cast<uint32_t*>(rgb), width, height, 129 y_stride, uv_stride); 130 } 131 132 /* Common converter for YUV 4:2:0 interleaved to RGB565. 133 * y, u, and v point to Y,U, and V panes, where U and V values are interleaved. 134 */ 135 static void _NVXXToRGB565(const uint8_t* Y, 136 const uint8_t* U, 137 const uint8_t* V, 138 uint16_t* rgb, 139 int width, 140 int height) 141 { 142 // The UV stride for NV21 and NV12 is the same as the width because the 143 // U and V values are interleaved, making each row twice as wide even though 144 // each value covers a two pixel wide area. These formats do not require any 145 // kind of alignment. 146 int y_stride = width; 147 int uv_stride = width; 148 _YUV420SToRGB565(Y, U, V, 2, rgb, width, height, y_stride, uv_stride); 149 } 150 151 /* Common converter for YUV 4:2:0 interleaved to RGB32. 152 * y, u, and v point to Y,U, and V panes, where U and V values are interleaved. 153 */ 154 static void _NVXXToRGB32(const uint8_t* Y, 155 const uint8_t* U, 156 const uint8_t* V, 157 uint32_t* rgb, 158 int width, 159 int height) 160 { 161 // The UV stride for NV21 and NV12 is the same as the width because the 162 // U and V values are interleaved, making each row twice as wide even though 163 // each value covers a two pixel wide area. These formats do not require any 164 // kind of alignment. 165 int y_stride = width; 166 int uv_stride = width; 167 _YUV420SToRGB32(Y, U, V, 2, rgb, width, height, y_stride, uv_stride); 168 } 169 170 void NV12ToRGB565(const void* nv12, void* rgb, int width, int height) 171 { 172 const int pix_total = width * height; 173 const uint8_t* y = reinterpret_cast<const uint8_t*>(nv12); 174 _NVXXToRGB565(y, y + pix_total, y + pix_total + 1, 175 reinterpret_cast<uint16_t*>(rgb), width, height); 176 } 177 178 void NV12ToRGB32(const void* nv12, void* rgb, int width, int height) 179 { 180 const int pix_total = width * height; 181 const uint8_t* y = reinterpret_cast<const uint8_t*>(nv12); 182 _NVXXToRGB32(y, y + pix_total, y + pix_total + 1, 183 reinterpret_cast<uint32_t*>(rgb), width, height); 184 } 185 186 void NV21ToRGB565(const void* nv21, void* rgb, int width, int height) 187 { 188 const int pix_total = width * height; 189 const uint8_t* y = reinterpret_cast<const uint8_t*>(nv21); 190 _NVXXToRGB565(y, y + pix_total + 1, y + pix_total, 191 reinterpret_cast<uint16_t*>(rgb), width, height); 192 } 193 194 void NV21ToRGB32(const void* nv21, void* rgb, int width, int height) 195 { 196 const int pix_total = width * height; 197 const uint8_t* y = reinterpret_cast<const uint8_t*>(nv21); 198 _NVXXToRGB32(y, y + pix_total + 1, y + pix_total, 199 reinterpret_cast<uint32_t*>(rgb), width, height); 200 } 201 202 }; /* namespace android */ 203