Andreas Huber | 53a76bd | 2009-10-06 16:20:44 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2009 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 <media/stagefright/ColorConverter.h> |
| 18 | #include <media/stagefright/MediaDebug.h> |
Andreas Huber | f341eb5 | 2011-01-06 11:26:54 -0800 | [diff] [blame] | 19 | #include <media/stagefright/MediaErrors.h> |
Andreas Huber | 53a76bd | 2009-10-06 16:20:44 -0700 | [diff] [blame] | 20 | |
| 21 | namespace android { |
| 22 | |
| 23 | static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00; |
| 24 | |
| 25 | ColorConverter::ColorConverter( |
| 26 | OMX_COLOR_FORMATTYPE from, OMX_COLOR_FORMATTYPE to) |
| 27 | : mSrcFormat(from), |
| 28 | mDstFormat(to), |
| 29 | mClip(NULL) { |
| 30 | } |
| 31 | |
| 32 | ColorConverter::~ColorConverter() { |
| 33 | delete[] mClip; |
| 34 | mClip = NULL; |
| 35 | } |
| 36 | |
| 37 | bool ColorConverter::isValid() const { |
| 38 | if (mDstFormat != OMX_COLOR_Format16bitRGB565) { |
| 39 | return false; |
| 40 | } |
| 41 | |
| 42 | switch (mSrcFormat) { |
| 43 | case OMX_COLOR_FormatYUV420Planar: |
| 44 | case OMX_COLOR_FormatCbYCrY: |
| 45 | case OMX_QCOM_COLOR_FormatYVU420SemiPlanar: |
Andreas Huber | c543a21 | 2010-06-30 10:32:20 -0700 | [diff] [blame] | 46 | case OMX_COLOR_FormatYUV420SemiPlanar: |
Andreas Huber | 53a76bd | 2009-10-06 16:20:44 -0700 | [diff] [blame] | 47 | return true; |
| 48 | |
| 49 | default: |
| 50 | return false; |
| 51 | } |
| 52 | } |
| 53 | |
Andreas Huber | 1bb0ffd | 2010-11-22 13:06:35 -0800 | [diff] [blame] | 54 | ColorConverter::BitmapParams::BitmapParams( |
| 55 | void *bits, |
Andreas Huber | 53a76bd | 2009-10-06 16:20:44 -0700 | [diff] [blame] | 56 | size_t width, size_t height, |
Andreas Huber | 1bb0ffd | 2010-11-22 13:06:35 -0800 | [diff] [blame] | 57 | size_t cropLeft, size_t cropTop, |
| 58 | size_t cropRight, size_t cropBottom) |
| 59 | : mBits(bits), |
| 60 | mWidth(width), |
| 61 | mHeight(height), |
| 62 | mCropLeft(cropLeft), |
| 63 | mCropTop(cropTop), |
| 64 | mCropRight(cropRight), |
| 65 | mCropBottom(cropBottom) { |
| 66 | } |
| 67 | |
| 68 | size_t ColorConverter::BitmapParams::cropWidth() const { |
| 69 | return mCropRight - mCropLeft + 1; |
| 70 | } |
| 71 | |
| 72 | size_t ColorConverter::BitmapParams::cropHeight() const { |
| 73 | return mCropBottom - mCropTop + 1; |
| 74 | } |
| 75 | |
Andreas Huber | f341eb5 | 2011-01-06 11:26:54 -0800 | [diff] [blame] | 76 | status_t ColorConverter::convert( |
Andreas Huber | 1bb0ffd | 2010-11-22 13:06:35 -0800 | [diff] [blame] | 77 | const void *srcBits, |
| 78 | size_t srcWidth, size_t srcHeight, |
| 79 | size_t srcCropLeft, size_t srcCropTop, |
| 80 | size_t srcCropRight, size_t srcCropBottom, |
| 81 | void *dstBits, |
| 82 | size_t dstWidth, size_t dstHeight, |
| 83 | size_t dstCropLeft, size_t dstCropTop, |
| 84 | size_t dstCropRight, size_t dstCropBottom) { |
Andreas Huber | f341eb5 | 2011-01-06 11:26:54 -0800 | [diff] [blame] | 85 | if (mDstFormat != OMX_COLOR_Format16bitRGB565) { |
| 86 | return ERROR_UNSUPPORTED; |
| 87 | } |
Andreas Huber | 53a76bd | 2009-10-06 16:20:44 -0700 | [diff] [blame] | 88 | |
Andreas Huber | 1bb0ffd | 2010-11-22 13:06:35 -0800 | [diff] [blame] | 89 | BitmapParams src( |
| 90 | const_cast<void *>(srcBits), |
| 91 | srcWidth, srcHeight, |
| 92 | srcCropLeft, srcCropTop, srcCropRight, srcCropBottom); |
| 93 | |
| 94 | BitmapParams dst( |
| 95 | dstBits, |
| 96 | dstWidth, dstHeight, |
| 97 | dstCropLeft, dstCropTop, dstCropRight, dstCropBottom); |
| 98 | |
Andreas Huber | f341eb5 | 2011-01-06 11:26:54 -0800 | [diff] [blame] | 99 | status_t err; |
| 100 | |
Andreas Huber | 53a76bd | 2009-10-06 16:20:44 -0700 | [diff] [blame] | 101 | switch (mSrcFormat) { |
| 102 | case OMX_COLOR_FormatYUV420Planar: |
Andreas Huber | f341eb5 | 2011-01-06 11:26:54 -0800 | [diff] [blame] | 103 | err = convertYUV420Planar(src, dst); |
Andreas Huber | 53a76bd | 2009-10-06 16:20:44 -0700 | [diff] [blame] | 104 | break; |
| 105 | |
| 106 | case OMX_COLOR_FormatCbYCrY: |
Andreas Huber | f341eb5 | 2011-01-06 11:26:54 -0800 | [diff] [blame] | 107 | err = convertCbYCrY(src, dst); |
Andreas Huber | 53a76bd | 2009-10-06 16:20:44 -0700 | [diff] [blame] | 108 | break; |
| 109 | |
| 110 | case OMX_QCOM_COLOR_FormatYVU420SemiPlanar: |
Andreas Huber | f341eb5 | 2011-01-06 11:26:54 -0800 | [diff] [blame] | 111 | err = convertQCOMYUV420SemiPlanar(src, dst); |
Andreas Huber | 53a76bd | 2009-10-06 16:20:44 -0700 | [diff] [blame] | 112 | break; |
| 113 | |
Andreas Huber | c543a21 | 2010-06-30 10:32:20 -0700 | [diff] [blame] | 114 | case OMX_COLOR_FormatYUV420SemiPlanar: |
Andreas Huber | f341eb5 | 2011-01-06 11:26:54 -0800 | [diff] [blame] | 115 | err = convertYUV420SemiPlanar(src, dst); |
Andreas Huber | c543a21 | 2010-06-30 10:32:20 -0700 | [diff] [blame] | 116 | break; |
| 117 | |
Andreas Huber | 53a76bd | 2009-10-06 16:20:44 -0700 | [diff] [blame] | 118 | default: |
| 119 | { |
| 120 | CHECK(!"Should not be here. Unknown color conversion."); |
| 121 | break; |
| 122 | } |
| 123 | } |
Andreas Huber | f341eb5 | 2011-01-06 11:26:54 -0800 | [diff] [blame] | 124 | |
| 125 | return err; |
Andreas Huber | 53a76bd | 2009-10-06 16:20:44 -0700 | [diff] [blame] | 126 | } |
| 127 | |
Andreas Huber | f341eb5 | 2011-01-06 11:26:54 -0800 | [diff] [blame] | 128 | status_t ColorConverter::convertCbYCrY( |
Andreas Huber | 1bb0ffd | 2010-11-22 13:06:35 -0800 | [diff] [blame] | 129 | const BitmapParams &src, const BitmapParams &dst) { |
| 130 | // XXX Untested |
Andreas Huber | 53a76bd | 2009-10-06 16:20:44 -0700 | [diff] [blame] | 131 | |
| 132 | uint8_t *kAdjustedClip = initClip(); |
| 133 | |
Andreas Huber | f341eb5 | 2011-01-06 11:26:54 -0800 | [diff] [blame] | 134 | if (!((src.mCropLeft & 1) == 0 |
| 135 | && src.cropWidth() == dst.cropWidth() |
| 136 | && src.cropHeight() == dst.cropHeight())) { |
| 137 | return ERROR_UNSUPPORTED; |
| 138 | } |
Andreas Huber | 53a76bd | 2009-10-06 16:20:44 -0700 | [diff] [blame] | 139 | |
Andreas Huber | 1bb0ffd | 2010-11-22 13:06:35 -0800 | [diff] [blame] | 140 | uint32_t *dst_ptr = (uint32_t *)dst.mBits |
| 141 | + (dst.mCropTop * dst.mWidth + dst.mCropLeft) / 2; |
Andreas Huber | 53a76bd | 2009-10-06 16:20:44 -0700 | [diff] [blame] | 142 | |
Andreas Huber | 1bb0ffd | 2010-11-22 13:06:35 -0800 | [diff] [blame] | 143 | const uint8_t *src_ptr = (const uint8_t *)src.mBits |
| 144 | + (src.mCropTop * dst.mWidth + src.mCropLeft) * 2; |
| 145 | |
| 146 | for (size_t y = 0; y < src.cropHeight(); ++y) { |
| 147 | for (size_t x = 0; x < src.cropWidth(); x += 2) { |
| 148 | signed y1 = (signed)src_ptr[2 * x + 1] - 16; |
| 149 | signed y2 = (signed)src_ptr[2 * x + 3] - 16; |
| 150 | signed u = (signed)src_ptr[2 * x] - 128; |
| 151 | signed v = (signed)src_ptr[2 * x + 2] - 128; |
Andreas Huber | 53a76bd | 2009-10-06 16:20:44 -0700 | [diff] [blame] | 152 | |
| 153 | signed u_b = u * 517; |
| 154 | signed u_g = -u * 100; |
| 155 | signed v_g = -v * 208; |
| 156 | signed v_r = v * 409; |
| 157 | |
| 158 | signed tmp1 = y1 * 298; |
| 159 | signed b1 = (tmp1 + u_b) / 256; |
| 160 | signed g1 = (tmp1 + v_g + u_g) / 256; |
| 161 | signed r1 = (tmp1 + v_r) / 256; |
| 162 | |
| 163 | signed tmp2 = y2 * 298; |
| 164 | signed b2 = (tmp2 + u_b) / 256; |
| 165 | signed g2 = (tmp2 + v_g + u_g) / 256; |
| 166 | signed r2 = (tmp2 + v_r) / 256; |
| 167 | |
| 168 | uint32_t rgb1 = |
| 169 | ((kAdjustedClip[r1] >> 3) << 11) |
| 170 | | ((kAdjustedClip[g1] >> 2) << 5) |
| 171 | | (kAdjustedClip[b1] >> 3); |
| 172 | |
| 173 | uint32_t rgb2 = |
| 174 | ((kAdjustedClip[r2] >> 3) << 11) |
| 175 | | ((kAdjustedClip[g2] >> 2) << 5) |
| 176 | | (kAdjustedClip[b2] >> 3); |
| 177 | |
| 178 | dst_ptr[x / 2] = (rgb2 << 16) | rgb1; |
| 179 | } |
| 180 | |
Andreas Huber | 1bb0ffd | 2010-11-22 13:06:35 -0800 | [diff] [blame] | 181 | src_ptr += src.mWidth * 2; |
| 182 | dst_ptr += dst.mWidth / 2; |
Andreas Huber | 53a76bd | 2009-10-06 16:20:44 -0700 | [diff] [blame] | 183 | } |
Andreas Huber | f341eb5 | 2011-01-06 11:26:54 -0800 | [diff] [blame] | 184 | |
| 185 | return OK; |
Andreas Huber | 53a76bd | 2009-10-06 16:20:44 -0700 | [diff] [blame] | 186 | } |
| 187 | |
Andreas Huber | f341eb5 | 2011-01-06 11:26:54 -0800 | [diff] [blame] | 188 | status_t ColorConverter::convertYUV420Planar( |
Andreas Huber | 1bb0ffd | 2010-11-22 13:06:35 -0800 | [diff] [blame] | 189 | const BitmapParams &src, const BitmapParams &dst) { |
James Dong | 94738e4 | 2011-02-11 13:04:32 -0800 | [diff] [blame] | 190 | if (!((dst.mWidth & 1) == 0 |
Andreas Huber | f341eb5 | 2011-01-06 11:26:54 -0800 | [diff] [blame] | 191 | && (src.mCropLeft & 1) == 0 |
| 192 | && src.cropWidth() == dst.cropWidth() |
| 193 | && src.cropHeight() == dst.cropHeight())) { |
| 194 | return ERROR_UNSUPPORTED; |
| 195 | } |
Andreas Huber | 53a76bd | 2009-10-06 16:20:44 -0700 | [diff] [blame] | 196 | |
Andreas Huber | f341eb5 | 2011-01-06 11:26:54 -0800 | [diff] [blame] | 197 | uint8_t *kAdjustedClip = initClip(); |
Andreas Huber | 1bb0ffd | 2010-11-22 13:06:35 -0800 | [diff] [blame] | 198 | |
| 199 | uint32_t *dst_ptr = (uint32_t *)dst.mBits |
| 200 | + (dst.mCropTop * dst.mWidth + dst.mCropLeft) / 2; |
| 201 | |
| 202 | const uint8_t *src_y = |
| 203 | (const uint8_t *)src.mBits + src.mCropTop * src.mWidth + src.mCropLeft; |
Andreas Huber | 53a76bd | 2009-10-06 16:20:44 -0700 | [diff] [blame] | 204 | |
| 205 | const uint8_t *src_u = |
Andreas Huber | 1bb0ffd | 2010-11-22 13:06:35 -0800 | [diff] [blame] | 206 | (const uint8_t *)src_y + src.mWidth * src.mHeight |
| 207 | + src.mCropTop * (src.mWidth / 2) + src.mCropLeft / 2; |
Andreas Huber | 53a76bd | 2009-10-06 16:20:44 -0700 | [diff] [blame] | 208 | |
| 209 | const uint8_t *src_v = |
Andreas Huber | 1bb0ffd | 2010-11-22 13:06:35 -0800 | [diff] [blame] | 210 | src_u + (src.mWidth / 2) * (src.mHeight / 2); |
Andreas Huber | 53a76bd | 2009-10-06 16:20:44 -0700 | [diff] [blame] | 211 | |
Andreas Huber | 1bb0ffd | 2010-11-22 13:06:35 -0800 | [diff] [blame] | 212 | for (size_t y = 0; y < src.cropHeight(); ++y) { |
| 213 | for (size_t x = 0; x < src.cropWidth(); x += 2) { |
Andreas Huber | 53a76bd | 2009-10-06 16:20:44 -0700 | [diff] [blame] | 214 | // B = 1.164 * (Y - 16) + 2.018 * (U - 128) |
| 215 | // G = 1.164 * (Y - 16) - 0.813 * (V - 128) - 0.391 * (U - 128) |
| 216 | // R = 1.164 * (Y - 16) + 1.596 * (V - 128) |
| 217 | |
| 218 | // B = 298/256 * (Y - 16) + 517/256 * (U - 128) |
| 219 | // G = .................. - 208/256 * (V - 128) - 100/256 * (U - 128) |
| 220 | // R = .................. + 409/256 * (V - 128) |
| 221 | |
| 222 | // min_B = (298 * (- 16) + 517 * (- 128)) / 256 = -277 |
| 223 | // min_G = (298 * (- 16) - 208 * (255 - 128) - 100 * (255 - 128)) / 256 = -172 |
| 224 | // min_R = (298 * (- 16) + 409 * (- 128)) / 256 = -223 |
| 225 | |
| 226 | // max_B = (298 * (255 - 16) + 517 * (255 - 128)) / 256 = 534 |
| 227 | // max_G = (298 * (255 - 16) - 208 * (- 128) - 100 * (- 128)) / 256 = 432 |
| 228 | // max_R = (298 * (255 - 16) + 409 * (255 - 128)) / 256 = 481 |
| 229 | |
| 230 | // clip range -278 .. 535 |
| 231 | |
| 232 | signed y1 = (signed)src_y[x] - 16; |
| 233 | signed y2 = (signed)src_y[x + 1] - 16; |
| 234 | |
| 235 | signed u = (signed)src_u[x / 2] - 128; |
| 236 | signed v = (signed)src_v[x / 2] - 128; |
| 237 | |
| 238 | signed u_b = u * 517; |
| 239 | signed u_g = -u * 100; |
| 240 | signed v_g = -v * 208; |
| 241 | signed v_r = v * 409; |
| 242 | |
| 243 | signed tmp1 = y1 * 298; |
| 244 | signed b1 = (tmp1 + u_b) / 256; |
| 245 | signed g1 = (tmp1 + v_g + u_g) / 256; |
| 246 | signed r1 = (tmp1 + v_r) / 256; |
| 247 | |
| 248 | signed tmp2 = y2 * 298; |
| 249 | signed b2 = (tmp2 + u_b) / 256; |
| 250 | signed g2 = (tmp2 + v_g + u_g) / 256; |
| 251 | signed r2 = (tmp2 + v_r) / 256; |
| 252 | |
| 253 | uint32_t rgb1 = |
| 254 | ((kAdjustedClip[r1] >> 3) << 11) |
| 255 | | ((kAdjustedClip[g1] >> 2) << 5) |
| 256 | | (kAdjustedClip[b1] >> 3); |
| 257 | |
| 258 | uint32_t rgb2 = |
| 259 | ((kAdjustedClip[r2] >> 3) << 11) |
| 260 | | ((kAdjustedClip[g2] >> 2) << 5) |
| 261 | | (kAdjustedClip[b2] >> 3); |
| 262 | |
| 263 | dst_ptr[x / 2] = (rgb2 << 16) | rgb1; |
| 264 | } |
| 265 | |
Andreas Huber | 1bb0ffd | 2010-11-22 13:06:35 -0800 | [diff] [blame] | 266 | src_y += src.mWidth; |
Andreas Huber | 53a76bd | 2009-10-06 16:20:44 -0700 | [diff] [blame] | 267 | |
| 268 | if (y & 1) { |
Andreas Huber | 1bb0ffd | 2010-11-22 13:06:35 -0800 | [diff] [blame] | 269 | src_u += src.mWidth / 2; |
| 270 | src_v += src.mWidth / 2; |
Andreas Huber | 53a76bd | 2009-10-06 16:20:44 -0700 | [diff] [blame] | 271 | } |
| 272 | |
Andreas Huber | 1bb0ffd | 2010-11-22 13:06:35 -0800 | [diff] [blame] | 273 | dst_ptr += dst.mWidth / 2; |
Andreas Huber | 53a76bd | 2009-10-06 16:20:44 -0700 | [diff] [blame] | 274 | } |
Andreas Huber | f341eb5 | 2011-01-06 11:26:54 -0800 | [diff] [blame] | 275 | |
| 276 | return OK; |
Andreas Huber | 53a76bd | 2009-10-06 16:20:44 -0700 | [diff] [blame] | 277 | } |
| 278 | |
Andreas Huber | f341eb5 | 2011-01-06 11:26:54 -0800 | [diff] [blame] | 279 | status_t ColorConverter::convertQCOMYUV420SemiPlanar( |
Andreas Huber | 1bb0ffd | 2010-11-22 13:06:35 -0800 | [diff] [blame] | 280 | const BitmapParams &src, const BitmapParams &dst) { |
Andreas Huber | 53a76bd | 2009-10-06 16:20:44 -0700 | [diff] [blame] | 281 | uint8_t *kAdjustedClip = initClip(); |
| 282 | |
Andreas Huber | f341eb5 | 2011-01-06 11:26:54 -0800 | [diff] [blame] | 283 | if (!((dst.mWidth & 3) == 0 |
| 284 | && (src.mCropLeft & 1) == 0 |
| 285 | && src.cropWidth() == dst.cropWidth() |
| 286 | && src.cropHeight() == dst.cropHeight())) { |
| 287 | return ERROR_UNSUPPORTED; |
| 288 | } |
Andreas Huber | 1bb0ffd | 2010-11-22 13:06:35 -0800 | [diff] [blame] | 289 | |
| 290 | uint32_t *dst_ptr = (uint32_t *)dst.mBits |
| 291 | + (dst.mCropTop * dst.mWidth + dst.mCropLeft) / 2; |
| 292 | |
| 293 | const uint8_t *src_y = |
| 294 | (const uint8_t *)src.mBits + src.mCropTop * src.mWidth + src.mCropLeft; |
Andreas Huber | 53a76bd | 2009-10-06 16:20:44 -0700 | [diff] [blame] | 295 | |
| 296 | const uint8_t *src_u = |
Andreas Huber | 1bb0ffd | 2010-11-22 13:06:35 -0800 | [diff] [blame] | 297 | (const uint8_t *)src_y + src.mWidth * src.mHeight |
| 298 | + src.mCropTop * src.mWidth + src.mCropLeft; |
Andreas Huber | 53a76bd | 2009-10-06 16:20:44 -0700 | [diff] [blame] | 299 | |
Andreas Huber | 1bb0ffd | 2010-11-22 13:06:35 -0800 | [diff] [blame] | 300 | for (size_t y = 0; y < src.cropHeight(); ++y) { |
| 301 | for (size_t x = 0; x < src.cropWidth(); x += 2) { |
Andreas Huber | 53a76bd | 2009-10-06 16:20:44 -0700 | [diff] [blame] | 302 | signed y1 = (signed)src_y[x] - 16; |
| 303 | signed y2 = (signed)src_y[x + 1] - 16; |
| 304 | |
| 305 | signed u = (signed)src_u[x & ~1] - 128; |
| 306 | signed v = (signed)src_u[(x & ~1) + 1] - 128; |
| 307 | |
| 308 | signed u_b = u * 517; |
| 309 | signed u_g = -u * 100; |
| 310 | signed v_g = -v * 208; |
| 311 | signed v_r = v * 409; |
| 312 | |
| 313 | signed tmp1 = y1 * 298; |
| 314 | signed b1 = (tmp1 + u_b) / 256; |
| 315 | signed g1 = (tmp1 + v_g + u_g) / 256; |
| 316 | signed r1 = (tmp1 + v_r) / 256; |
| 317 | |
| 318 | signed tmp2 = y2 * 298; |
| 319 | signed b2 = (tmp2 + u_b) / 256; |
| 320 | signed g2 = (tmp2 + v_g + u_g) / 256; |
| 321 | signed r2 = (tmp2 + v_r) / 256; |
| 322 | |
| 323 | uint32_t rgb1 = |
| 324 | ((kAdjustedClip[b1] >> 3) << 11) |
| 325 | | ((kAdjustedClip[g1] >> 2) << 5) |
| 326 | | (kAdjustedClip[r1] >> 3); |
| 327 | |
| 328 | uint32_t rgb2 = |
| 329 | ((kAdjustedClip[b2] >> 3) << 11) |
| 330 | | ((kAdjustedClip[g2] >> 2) << 5) |
| 331 | | (kAdjustedClip[r2] >> 3); |
| 332 | |
| 333 | dst_ptr[x / 2] = (rgb2 << 16) | rgb1; |
| 334 | } |
| 335 | |
Andreas Huber | 1bb0ffd | 2010-11-22 13:06:35 -0800 | [diff] [blame] | 336 | src_y += src.mWidth; |
Andreas Huber | 53a76bd | 2009-10-06 16:20:44 -0700 | [diff] [blame] | 337 | |
| 338 | if (y & 1) { |
Andreas Huber | 1bb0ffd | 2010-11-22 13:06:35 -0800 | [diff] [blame] | 339 | src_u += src.mWidth; |
Andreas Huber | 53a76bd | 2009-10-06 16:20:44 -0700 | [diff] [blame] | 340 | } |
| 341 | |
Andreas Huber | 1bb0ffd | 2010-11-22 13:06:35 -0800 | [diff] [blame] | 342 | dst_ptr += dst.mWidth / 2; |
Andreas Huber | 53a76bd | 2009-10-06 16:20:44 -0700 | [diff] [blame] | 343 | } |
Andreas Huber | f341eb5 | 2011-01-06 11:26:54 -0800 | [diff] [blame] | 344 | |
| 345 | return OK; |
Andreas Huber | 53a76bd | 2009-10-06 16:20:44 -0700 | [diff] [blame] | 346 | } |
| 347 | |
Andreas Huber | f341eb5 | 2011-01-06 11:26:54 -0800 | [diff] [blame] | 348 | status_t ColorConverter::convertYUV420SemiPlanar( |
Andreas Huber | 1bb0ffd | 2010-11-22 13:06:35 -0800 | [diff] [blame] | 349 | const BitmapParams &src, const BitmapParams &dst) { |
| 350 | // XXX Untested |
Andreas Huber | c543a21 | 2010-06-30 10:32:20 -0700 | [diff] [blame] | 351 | |
| 352 | uint8_t *kAdjustedClip = initClip(); |
| 353 | |
Andreas Huber | f341eb5 | 2011-01-06 11:26:54 -0800 | [diff] [blame] | 354 | if (!((dst.mWidth & 3) == 0 |
| 355 | && (src.mCropLeft & 1) == 0 |
| 356 | && src.cropWidth() == dst.cropWidth() |
| 357 | && src.cropHeight() == dst.cropHeight())) { |
| 358 | return ERROR_UNSUPPORTED; |
| 359 | } |
Andreas Huber | 1bb0ffd | 2010-11-22 13:06:35 -0800 | [diff] [blame] | 360 | |
| 361 | uint32_t *dst_ptr = (uint32_t *)dst.mBits |
| 362 | + (dst.mCropTop * dst.mWidth + dst.mCropLeft) / 2; |
| 363 | |
| 364 | const uint8_t *src_y = |
| 365 | (const uint8_t *)src.mBits + src.mCropTop * src.mWidth + src.mCropLeft; |
Andreas Huber | c543a21 | 2010-06-30 10:32:20 -0700 | [diff] [blame] | 366 | |
| 367 | const uint8_t *src_u = |
Andreas Huber | 1bb0ffd | 2010-11-22 13:06:35 -0800 | [diff] [blame] | 368 | (const uint8_t *)src_y + src.mWidth * src.mHeight |
| 369 | + src.mCropTop * src.mWidth + src.mCropLeft; |
Andreas Huber | c543a21 | 2010-06-30 10:32:20 -0700 | [diff] [blame] | 370 | |
Andreas Huber | 1bb0ffd | 2010-11-22 13:06:35 -0800 | [diff] [blame] | 371 | for (size_t y = 0; y < src.cropHeight(); ++y) { |
| 372 | for (size_t x = 0; x < src.cropWidth(); x += 2) { |
Andreas Huber | c543a21 | 2010-06-30 10:32:20 -0700 | [diff] [blame] | 373 | signed y1 = (signed)src_y[x] - 16; |
| 374 | signed y2 = (signed)src_y[x + 1] - 16; |
| 375 | |
| 376 | signed v = (signed)src_u[x & ~1] - 128; |
| 377 | signed u = (signed)src_u[(x & ~1) + 1] - 128; |
| 378 | |
| 379 | signed u_b = u * 517; |
| 380 | signed u_g = -u * 100; |
| 381 | signed v_g = -v * 208; |
| 382 | signed v_r = v * 409; |
| 383 | |
| 384 | signed tmp1 = y1 * 298; |
| 385 | signed b1 = (tmp1 + u_b) / 256; |
| 386 | signed g1 = (tmp1 + v_g + u_g) / 256; |
| 387 | signed r1 = (tmp1 + v_r) / 256; |
| 388 | |
| 389 | signed tmp2 = y2 * 298; |
| 390 | signed b2 = (tmp2 + u_b) / 256; |
| 391 | signed g2 = (tmp2 + v_g + u_g) / 256; |
| 392 | signed r2 = (tmp2 + v_r) / 256; |
| 393 | |
| 394 | uint32_t rgb1 = |
| 395 | ((kAdjustedClip[b1] >> 3) << 11) |
| 396 | | ((kAdjustedClip[g1] >> 2) << 5) |
| 397 | | (kAdjustedClip[r1] >> 3); |
| 398 | |
| 399 | uint32_t rgb2 = |
| 400 | ((kAdjustedClip[b2] >> 3) << 11) |
| 401 | | ((kAdjustedClip[g2] >> 2) << 5) |
| 402 | | (kAdjustedClip[r2] >> 3); |
| 403 | |
| 404 | dst_ptr[x / 2] = (rgb2 << 16) | rgb1; |
| 405 | } |
| 406 | |
Andreas Huber | 1bb0ffd | 2010-11-22 13:06:35 -0800 | [diff] [blame] | 407 | src_y += src.mWidth; |
Andreas Huber | c543a21 | 2010-06-30 10:32:20 -0700 | [diff] [blame] | 408 | |
| 409 | if (y & 1) { |
Andreas Huber | 1bb0ffd | 2010-11-22 13:06:35 -0800 | [diff] [blame] | 410 | src_u += src.mWidth; |
Andreas Huber | c543a21 | 2010-06-30 10:32:20 -0700 | [diff] [blame] | 411 | } |
| 412 | |
Andreas Huber | 1bb0ffd | 2010-11-22 13:06:35 -0800 | [diff] [blame] | 413 | dst_ptr += dst.mWidth / 2; |
Andreas Huber | c543a21 | 2010-06-30 10:32:20 -0700 | [diff] [blame] | 414 | } |
Andreas Huber | f341eb5 | 2011-01-06 11:26:54 -0800 | [diff] [blame] | 415 | |
| 416 | return OK; |
Andreas Huber | c543a21 | 2010-06-30 10:32:20 -0700 | [diff] [blame] | 417 | } |
| 418 | |
Andreas Huber | 53a76bd | 2009-10-06 16:20:44 -0700 | [diff] [blame] | 419 | uint8_t *ColorConverter::initClip() { |
| 420 | static const signed kClipMin = -278; |
| 421 | static const signed kClipMax = 535; |
| 422 | |
| 423 | if (mClip == NULL) { |
| 424 | mClip = new uint8_t[kClipMax - kClipMin + 1]; |
| 425 | |
| 426 | for (signed i = kClipMin; i <= kClipMax; ++i) { |
| 427 | mClip[i - kClipMin] = (i < 0) ? 0 : (i > 255) ? 255 : (uint8_t)i; |
| 428 | } |
| 429 | } |
| 430 | |
| 431 | return &mClip[-kClipMin]; |
| 432 | } |
| 433 | |
| 434 | } // namespace android |