Home | History | Annotate | Download | only in colorconversion
      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>
     19 
     20 namespace android {
     21 
     22 static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
     23 
     24 ColorConverter::ColorConverter(
     25         OMX_COLOR_FORMATTYPE from, OMX_COLOR_FORMATTYPE to)
     26     : mSrcFormat(from),
     27       mDstFormat(to),
     28       mClip(NULL) {
     29 }
     30 
     31 ColorConverter::~ColorConverter() {
     32     delete[] mClip;
     33     mClip = NULL;
     34 }
     35 
     36 bool ColorConverter::isValid() const {
     37     if (mDstFormat != OMX_COLOR_Format16bitRGB565) {
     38         return false;
     39     }
     40 
     41     switch (mSrcFormat) {
     42         case OMX_COLOR_FormatYUV420Planar:
     43         case OMX_COLOR_FormatCbYCrY:
     44         case OMX_QCOM_COLOR_FormatYVU420SemiPlanar:
     45         case OMX_COLOR_FormatYUV420SemiPlanar:
     46             return true;
     47 
     48         default:
     49             return false;
     50     }
     51 }
     52 
     53 void ColorConverter::convert(
     54         size_t width, size_t height,
     55         const void *srcBits, size_t srcSkip,
     56         void *dstBits, size_t dstSkip) {
     57     CHECK_EQ(mDstFormat, OMX_COLOR_Format16bitRGB565);
     58 
     59     switch (mSrcFormat) {
     60         case OMX_COLOR_FormatYUV420Planar:
     61             convertYUV420Planar(
     62                     width, height, srcBits, srcSkip, dstBits, dstSkip);
     63             break;
     64 
     65         case OMX_COLOR_FormatCbYCrY:
     66             convertCbYCrY(
     67                     width, height, srcBits, srcSkip, dstBits, dstSkip);
     68             break;
     69 
     70         case OMX_QCOM_COLOR_FormatYVU420SemiPlanar:
     71             convertQCOMYUV420SemiPlanar(
     72                     width, height, srcBits, srcSkip, dstBits, dstSkip);
     73             break;
     74 
     75         case OMX_COLOR_FormatYUV420SemiPlanar:
     76             convertYUV420SemiPlanar(
     77                     width, height, srcBits, srcSkip, dstBits, dstSkip);
     78             break;
     79 
     80         default:
     81         {
     82             CHECK(!"Should not be here. Unknown color conversion.");
     83             break;
     84         }
     85     }
     86 }
     87 
     88 void ColorConverter::convertCbYCrY(
     89         size_t width, size_t height,
     90         const void *srcBits, size_t srcSkip,
     91         void *dstBits, size_t dstSkip) {
     92     CHECK_EQ(srcSkip, 0);  // Doesn't really make sense for YUV formats.
     93     CHECK(dstSkip >= width * 2);
     94     CHECK((dstSkip & 3) == 0);
     95 
     96     uint8_t *kAdjustedClip = initClip();
     97 
     98     uint32_t *dst_ptr = (uint32_t *)dstBits;
     99 
    100     const uint8_t *src = (const uint8_t *)srcBits;
    101 
    102     for (size_t y = 0; y < height; ++y) {
    103         for (size_t x = 0; x < width; x += 2) {
    104             signed y1 = (signed)src[2 * x + 1] - 16;
    105             signed y2 = (signed)src[2 * x + 3] - 16;
    106             signed u = (signed)src[2 * x] - 128;
    107             signed v = (signed)src[2 * x + 2] - 128;
    108 
    109             signed u_b = u * 517;
    110             signed u_g = -u * 100;
    111             signed v_g = -v * 208;
    112             signed v_r = v * 409;
    113 
    114             signed tmp1 = y1 * 298;
    115             signed b1 = (tmp1 + u_b) / 256;
    116             signed g1 = (tmp1 + v_g + u_g) / 256;
    117             signed r1 = (tmp1 + v_r) / 256;
    118 
    119             signed tmp2 = y2 * 298;
    120             signed b2 = (tmp2 + u_b) / 256;
    121             signed g2 = (tmp2 + v_g + u_g) / 256;
    122             signed r2 = (tmp2 + v_r) / 256;
    123 
    124             uint32_t rgb1 =
    125                 ((kAdjustedClip[r1] >> 3) << 11)
    126                 | ((kAdjustedClip[g1] >> 2) << 5)
    127                 | (kAdjustedClip[b1] >> 3);
    128 
    129             uint32_t rgb2 =
    130                 ((kAdjustedClip[r2] >> 3) << 11)
    131                 | ((kAdjustedClip[g2] >> 2) << 5)
    132                 | (kAdjustedClip[b2] >> 3);
    133 
    134             dst_ptr[x / 2] = (rgb2 << 16) | rgb1;
    135         }
    136 
    137         src += width * 2;
    138         dst_ptr += dstSkip / 4;
    139     }
    140 }
    141 
    142 void ColorConverter::convertYUV420Planar(
    143         size_t width, size_t height,
    144         const void *srcBits, size_t srcSkip,
    145         void *dstBits, size_t dstSkip) {
    146     CHECK_EQ(srcSkip, 0);  // Doesn't really make sense for YUV formats.
    147     CHECK(dstSkip >= width * 2);
    148     CHECK((dstSkip & 3) == 0);
    149 
    150     uint8_t *kAdjustedClip = initClip();
    151 
    152     uint32_t *dst_ptr = (uint32_t *)dstBits;
    153     const uint8_t *src_y = (const uint8_t *)srcBits;
    154 
    155     const uint8_t *src_u =
    156         (const uint8_t *)src_y + width * height;
    157 
    158     const uint8_t *src_v =
    159         (const uint8_t *)src_u + (width / 2) * (height / 2);
    160 
    161     for (size_t y = 0; y < height; ++y) {
    162         for (size_t x = 0; x < width; x += 2) {
    163             // B = 1.164 * (Y - 16) + 2.018 * (U - 128)
    164             // G = 1.164 * (Y - 16) - 0.813 * (V - 128) - 0.391 * (U - 128)
    165             // R = 1.164 * (Y - 16) + 1.596 * (V - 128)
    166 
    167             // B = 298/256 * (Y - 16) + 517/256 * (U - 128)
    168             // G = .................. - 208/256 * (V - 128) - 100/256 * (U - 128)
    169             // R = .................. + 409/256 * (V - 128)
    170 
    171             // min_B = (298 * (- 16) + 517 * (- 128)) / 256 = -277
    172             // min_G = (298 * (- 16) - 208 * (255 - 128) - 100 * (255 - 128)) / 256 = -172
    173             // min_R = (298 * (- 16) + 409 * (- 128)) / 256 = -223
    174 
    175             // max_B = (298 * (255 - 16) + 517 * (255 - 128)) / 256 = 534
    176             // max_G = (298 * (255 - 16) - 208 * (- 128) - 100 * (- 128)) / 256 = 432
    177             // max_R = (298 * (255 - 16) + 409 * (255 - 128)) / 256 = 481
    178 
    179             // clip range -278 .. 535
    180 
    181             signed y1 = (signed)src_y[x] - 16;
    182             signed y2 = (signed)src_y[x + 1] - 16;
    183 
    184             signed u = (signed)src_u[x / 2] - 128;
    185             signed v = (signed)src_v[x / 2] - 128;
    186 
    187             signed u_b = u * 517;
    188             signed u_g = -u * 100;
    189             signed v_g = -v * 208;
    190             signed v_r = v * 409;
    191 
    192             signed tmp1 = y1 * 298;
    193             signed b1 = (tmp1 + u_b) / 256;
    194             signed g1 = (tmp1 + v_g + u_g) / 256;
    195             signed r1 = (tmp1 + v_r) / 256;
    196 
    197             signed tmp2 = y2 * 298;
    198             signed b2 = (tmp2 + u_b) / 256;
    199             signed g2 = (tmp2 + v_g + u_g) / 256;
    200             signed r2 = (tmp2 + v_r) / 256;
    201 
    202             uint32_t rgb1 =
    203                 ((kAdjustedClip[r1] >> 3) << 11)
    204                 | ((kAdjustedClip[g1] >> 2) << 5)
    205                 | (kAdjustedClip[b1] >> 3);
    206 
    207             uint32_t rgb2 =
    208                 ((kAdjustedClip[r2] >> 3) << 11)
    209                 | ((kAdjustedClip[g2] >> 2) << 5)
    210                 | (kAdjustedClip[b2] >> 3);
    211 
    212             dst_ptr[x / 2] = (rgb2 << 16) | rgb1;
    213         }
    214 
    215         src_y += width;
    216 
    217         if (y & 1) {
    218             src_u += width / 2;
    219             src_v += width / 2;
    220         }
    221 
    222         dst_ptr += dstSkip / 4;
    223     }
    224 }
    225 
    226 void ColorConverter::convertQCOMYUV420SemiPlanar(
    227         size_t width, size_t height,
    228         const void *srcBits, size_t srcSkip,
    229         void *dstBits, size_t dstSkip) {
    230     CHECK_EQ(srcSkip, 0);  // Doesn't really make sense for YUV formats.
    231     CHECK(dstSkip >= width * 2);
    232     CHECK((dstSkip & 3) == 0);
    233 
    234     uint8_t *kAdjustedClip = initClip();
    235 
    236     uint32_t *dst_ptr = (uint32_t *)dstBits;
    237     const uint8_t *src_y = (const uint8_t *)srcBits;
    238 
    239     const uint8_t *src_u =
    240         (const uint8_t *)src_y + width * height;
    241 
    242     for (size_t y = 0; y < height; ++y) {
    243         for (size_t x = 0; x < width; x += 2) {
    244             signed y1 = (signed)src_y[x] - 16;
    245             signed y2 = (signed)src_y[x + 1] - 16;
    246 
    247             signed u = (signed)src_u[x & ~1] - 128;
    248             signed v = (signed)src_u[(x & ~1) + 1] - 128;
    249 
    250             signed u_b = u * 517;
    251             signed u_g = -u * 100;
    252             signed v_g = -v * 208;
    253             signed v_r = v * 409;
    254 
    255             signed tmp1 = y1 * 298;
    256             signed b1 = (tmp1 + u_b) / 256;
    257             signed g1 = (tmp1 + v_g + u_g) / 256;
    258             signed r1 = (tmp1 + v_r) / 256;
    259 
    260             signed tmp2 = y2 * 298;
    261             signed b2 = (tmp2 + u_b) / 256;
    262             signed g2 = (tmp2 + v_g + u_g) / 256;
    263             signed r2 = (tmp2 + v_r) / 256;
    264 
    265             uint32_t rgb1 =
    266                 ((kAdjustedClip[b1] >> 3) << 11)
    267                 | ((kAdjustedClip[g1] >> 2) << 5)
    268                 | (kAdjustedClip[r1] >> 3);
    269 
    270             uint32_t rgb2 =
    271                 ((kAdjustedClip[b2] >> 3) << 11)
    272                 | ((kAdjustedClip[g2] >> 2) << 5)
    273                 | (kAdjustedClip[r2] >> 3);
    274 
    275             dst_ptr[x / 2] = (rgb2 << 16) | rgb1;
    276         }
    277 
    278         src_y += width;
    279 
    280         if (y & 1) {
    281             src_u += width;
    282         }
    283 
    284         dst_ptr += dstSkip / 4;
    285     }
    286 }
    287 
    288 void ColorConverter::convertYUV420SemiPlanar(
    289         size_t width, size_t height,
    290         const void *srcBits, size_t srcSkip,
    291         void *dstBits, size_t dstSkip) {
    292     CHECK_EQ(srcSkip, 0);  // Doesn't really make sense for YUV formats.
    293     CHECK(dstSkip >= width * 2);
    294     CHECK((dstSkip & 3) == 0);
    295 
    296     uint8_t *kAdjustedClip = initClip();
    297 
    298     uint32_t *dst_ptr = (uint32_t *)dstBits;
    299     const uint8_t *src_y = (const uint8_t *)srcBits;
    300 
    301     const uint8_t *src_u =
    302         (const uint8_t *)src_y + width * height;
    303 
    304     for (size_t y = 0; y < height; ++y) {
    305         for (size_t x = 0; x < width; x += 2) {
    306             signed y1 = (signed)src_y[x] - 16;
    307             signed y2 = (signed)src_y[x + 1] - 16;
    308 
    309             signed v = (signed)src_u[x & ~1] - 128;
    310             signed u = (signed)src_u[(x & ~1) + 1] - 128;
    311 
    312             signed u_b = u * 517;
    313             signed u_g = -u * 100;
    314             signed v_g = -v * 208;
    315             signed v_r = v * 409;
    316 
    317             signed tmp1 = y1 * 298;
    318             signed b1 = (tmp1 + u_b) / 256;
    319             signed g1 = (tmp1 + v_g + u_g) / 256;
    320             signed r1 = (tmp1 + v_r) / 256;
    321 
    322             signed tmp2 = y2 * 298;
    323             signed b2 = (tmp2 + u_b) / 256;
    324             signed g2 = (tmp2 + v_g + u_g) / 256;
    325             signed r2 = (tmp2 + v_r) / 256;
    326 
    327             uint32_t rgb1 =
    328                 ((kAdjustedClip[b1] >> 3) << 11)
    329                 | ((kAdjustedClip[g1] >> 2) << 5)
    330                 | (kAdjustedClip[r1] >> 3);
    331 
    332             uint32_t rgb2 =
    333                 ((kAdjustedClip[b2] >> 3) << 11)
    334                 | ((kAdjustedClip[g2] >> 2) << 5)
    335                 | (kAdjustedClip[r2] >> 3);
    336 
    337             dst_ptr[x / 2] = (rgb2 << 16) | rgb1;
    338         }
    339 
    340         src_y += width;
    341 
    342         if (y & 1) {
    343             src_u += width;
    344         }
    345 
    346         dst_ptr += dstSkip / 4;
    347     }
    348 }
    349 
    350 uint8_t *ColorConverter::initClip() {
    351     static const signed kClipMin = -278;
    352     static const signed kClipMax = 535;
    353 
    354     if (mClip == NULL) {
    355         mClip = new uint8_t[kClipMax - kClipMin + 1];
    356 
    357         for (signed i = kClipMin; i <= kClipMax; ++i) {
    358             mClip[i - kClipMin] = (i < 0) ? 0 : (i > 255) ? 255 : (uint8_t)i;
    359         }
    360     }
    361 
    362     return &mClip[-kClipMin];
    363 }
    364 
    365 }  // namespace android
    366