Home | History | Annotate | Download | only in source
      1 /*
      2  *  Copyright 2011 The LibYuv Project Authors. All rights reserved.
      3  *
      4  *  Use of this source code is governed by a BSD-style license
      5  *  that can be found in the LICENSE file in the root of the source
      6  *  tree. An additional intellectual property rights grant can be found
      7  *  in the file PATENTS. All contributing project authors may
      8  *  be found in the AUTHORS file in the root of the source tree.
      9  */
     10 
     11 #include "libyuv/convert_argb.h"
     12 
     13 #include "libyuv/cpu_id.h"
     14 #ifdef HAVE_JPEG
     15 #include "libyuv/mjpeg_decoder.h"
     16 #endif
     17 #include "libyuv/rotate_argb.h"
     18 #include "libyuv/row.h"
     19 #include "libyuv/video_common.h"
     20 
     21 #ifdef __cplusplus
     22 namespace libyuv {
     23 extern "C" {
     24 #endif
     25 
     26 // Convert camera sample to ARGB with cropping, rotation and vertical flip.
     27 // src_width is used for source stride computation
     28 // src_height is used to compute location of planes, and indicate inversion
     29 // sample_size is measured in bytes and is the size of the frame.
     30 //   With MJPEG it is the compressed size of the frame.
     31 LIBYUV_API
     32 int ConvertToARGB(const uint8* sample, size_t sample_size,
     33                   uint8* crop_argb, int argb_stride,
     34                   int crop_x, int crop_y,
     35                   int src_width, int src_height,
     36                   int crop_width, int crop_height,
     37                   enum RotationMode rotation,
     38                   uint32 fourcc) {
     39   uint32 format = CanonicalFourCC(fourcc);
     40   int aligned_src_width = (src_width + 1) & ~1;
     41   const uint8* src;
     42   const uint8* src_uv;
     43   int abs_src_height = (src_height < 0) ? -src_height : src_height;
     44   int inv_crop_height = (crop_height < 0) ? -crop_height : crop_height;
     45   int r = 0;
     46 
     47   // One pass rotation is available for some formats. For the rest, convert
     48   // to I420 (with optional vertical flipping) into a temporary I420 buffer,
     49   // and then rotate the I420 to the final destination buffer.
     50   // For in-place conversion, if destination crop_argb is same as source sample,
     51   // also enable temporary buffer.
     52   LIBYUV_BOOL need_buf = (rotation && format != FOURCC_ARGB) ||
     53       crop_argb == sample;
     54   uint8* dest_argb = crop_argb;
     55   int dest_argb_stride = argb_stride;
     56   uint8* rotate_buffer = NULL;
     57   int abs_crop_height = (crop_height < 0) ? -crop_height : crop_height;
     58 
     59   if (crop_argb == NULL || sample == NULL ||
     60       src_width <= 0 || crop_width <= 0 ||
     61       src_height == 0 || crop_height == 0) {
     62     return -1;
     63   }
     64   if (src_height < 0) {
     65     inv_crop_height = -inv_crop_height;
     66   }
     67 
     68   if (need_buf) {
     69     int argb_size = crop_width * 4 * abs_crop_height;
     70     rotate_buffer = (uint8*)malloc(argb_size);
     71     if (!rotate_buffer) {
     72       return 1;  // Out of memory runtime error.
     73     }
     74     crop_argb = rotate_buffer;
     75     argb_stride = crop_width * 4;
     76   }
     77 
     78   switch (format) {
     79     // Single plane formats
     80     case FOURCC_YUY2:
     81       src = sample + (aligned_src_width * crop_y + crop_x) * 2;
     82       r = YUY2ToARGB(src, aligned_src_width * 2,
     83                      crop_argb, argb_stride,
     84                      crop_width, inv_crop_height);
     85       break;
     86     case FOURCC_UYVY:
     87       src = sample + (aligned_src_width * crop_y + crop_x) * 2;
     88       r = UYVYToARGB(src, aligned_src_width * 2,
     89                      crop_argb, argb_stride,
     90                      crop_width, inv_crop_height);
     91       break;
     92     case FOURCC_24BG:
     93       src = sample + (src_width * crop_y + crop_x) * 3;
     94       r = RGB24ToARGB(src, src_width * 3,
     95                       crop_argb, argb_stride,
     96                       crop_width, inv_crop_height);
     97       break;
     98     case FOURCC_RAW:
     99       src = sample + (src_width * crop_y + crop_x) * 3;
    100       r = RAWToARGB(src, src_width * 3,
    101                     crop_argb, argb_stride,
    102                     crop_width, inv_crop_height);
    103       break;
    104     case FOURCC_ARGB:
    105       src = sample + (src_width * crop_y + crop_x) * 4;
    106       r = ARGBToARGB(src, src_width * 4,
    107                      crop_argb, argb_stride,
    108                      crop_width, inv_crop_height);
    109       break;
    110     case FOURCC_BGRA:
    111       src = sample + (src_width * crop_y + crop_x) * 4;
    112       r = BGRAToARGB(src, src_width * 4,
    113                      crop_argb, argb_stride,
    114                      crop_width, inv_crop_height);
    115       break;
    116     case FOURCC_ABGR:
    117       src = sample + (src_width * crop_y + crop_x) * 4;
    118       r = ABGRToARGB(src, src_width * 4,
    119                      crop_argb, argb_stride,
    120                      crop_width, inv_crop_height);
    121       break;
    122     case FOURCC_RGBA:
    123       src = sample + (src_width * crop_y + crop_x) * 4;
    124       r = RGBAToARGB(src, src_width * 4,
    125                      crop_argb, argb_stride,
    126                      crop_width, inv_crop_height);
    127       break;
    128     case FOURCC_RGBP:
    129       src = sample + (src_width * crop_y + crop_x) * 2;
    130       r = RGB565ToARGB(src, src_width * 2,
    131                        crop_argb, argb_stride,
    132                        crop_width, inv_crop_height);
    133       break;
    134     case FOURCC_RGBO:
    135       src = sample + (src_width * crop_y + crop_x) * 2;
    136       r = ARGB1555ToARGB(src, src_width * 2,
    137                          crop_argb, argb_stride,
    138                          crop_width, inv_crop_height);
    139       break;
    140     case FOURCC_R444:
    141       src = sample + (src_width * crop_y + crop_x) * 2;
    142       r = ARGB4444ToARGB(src, src_width * 2,
    143                          crop_argb, argb_stride,
    144                          crop_width, inv_crop_height);
    145       break;
    146     case FOURCC_I400:
    147       src = sample + src_width * crop_y + crop_x;
    148       r = I400ToARGB(src, src_width,
    149                      crop_argb, argb_stride,
    150                      crop_width, inv_crop_height);
    151       break;
    152 
    153     // Biplanar formats
    154     case FOURCC_NV12:
    155       src = sample + (src_width * crop_y + crop_x);
    156       src_uv = sample + aligned_src_width * (src_height + crop_y / 2) + crop_x;
    157       r = NV12ToARGB(src, src_width,
    158                      src_uv, aligned_src_width,
    159                      crop_argb, argb_stride,
    160                      crop_width, inv_crop_height);
    161       break;
    162     case FOURCC_NV21:
    163       src = sample + (src_width * crop_y + crop_x);
    164       src_uv = sample + aligned_src_width * (src_height + crop_y / 2) + crop_x;
    165       // Call NV12 but with u and v parameters swapped.
    166       r = NV21ToARGB(src, src_width,
    167                      src_uv, aligned_src_width,
    168                      crop_argb, argb_stride,
    169                      crop_width, inv_crop_height);
    170       break;
    171     case FOURCC_M420:
    172       src = sample + (src_width * crop_y) * 12 / 8 + crop_x;
    173       r = M420ToARGB(src, src_width,
    174                      crop_argb, argb_stride,
    175                      crop_width, inv_crop_height);
    176       break;
    177     // Triplanar formats
    178     case FOURCC_I420:
    179     case FOURCC_YV12: {
    180       const uint8* src_y = sample + (src_width * crop_y + crop_x);
    181       const uint8* src_u;
    182       const uint8* src_v;
    183       int halfwidth = (src_width + 1) / 2;
    184       int halfheight = (abs_src_height + 1) / 2;
    185       if (format == FOURCC_YV12) {
    186         src_v = sample + src_width * abs_src_height +
    187             (halfwidth * crop_y + crop_x) / 2;
    188         src_u = sample + src_width * abs_src_height +
    189             halfwidth * (halfheight + crop_y / 2) + crop_x / 2;
    190       } else {
    191         src_u = sample + src_width * abs_src_height +
    192             (halfwidth * crop_y + crop_x) / 2;
    193         src_v = sample + src_width * abs_src_height +
    194             halfwidth * (halfheight + crop_y / 2) + crop_x / 2;
    195       }
    196       r = I420ToARGB(src_y, src_width,
    197                      src_u, halfwidth,
    198                      src_v, halfwidth,
    199                      crop_argb, argb_stride,
    200                      crop_width, inv_crop_height);
    201       break;
    202     }
    203 
    204     case FOURCC_J420: {
    205       const uint8* src_y = sample + (src_width * crop_y + crop_x);
    206       const uint8* src_u;
    207       const uint8* src_v;
    208       int halfwidth = (src_width + 1) / 2;
    209       int halfheight = (abs_src_height + 1) / 2;
    210       src_u = sample + src_width * abs_src_height +
    211           (halfwidth * crop_y + crop_x) / 2;
    212       src_v = sample + src_width * abs_src_height +
    213           halfwidth * (halfheight + crop_y / 2) + crop_x / 2;
    214       r = J420ToARGB(src_y, src_width,
    215                      src_u, halfwidth,
    216                      src_v, halfwidth,
    217                      crop_argb, argb_stride,
    218                      crop_width, inv_crop_height);
    219       break;
    220     }
    221 
    222     case FOURCC_I422:
    223     case FOURCC_YV16: {
    224       const uint8* src_y = sample + src_width * crop_y + crop_x;
    225       const uint8* src_u;
    226       const uint8* src_v;
    227       int halfwidth = (src_width + 1) / 2;
    228       if (format == FOURCC_YV16) {
    229         src_v = sample + src_width * abs_src_height +
    230             halfwidth * crop_y + crop_x / 2;
    231         src_u = sample + src_width * abs_src_height +
    232             halfwidth * (abs_src_height + crop_y) + crop_x / 2;
    233       } else {
    234         src_u = sample + src_width * abs_src_height +
    235             halfwidth * crop_y + crop_x / 2;
    236         src_v = sample + src_width * abs_src_height +
    237             halfwidth * (abs_src_height + crop_y) + crop_x / 2;
    238       }
    239       r = I422ToARGB(src_y, src_width,
    240                      src_u, halfwidth,
    241                      src_v, halfwidth,
    242                      crop_argb, argb_stride,
    243                      crop_width, inv_crop_height);
    244       break;
    245     }
    246     case FOURCC_I444:
    247     case FOURCC_YV24: {
    248       const uint8* src_y = sample + src_width * crop_y + crop_x;
    249       const uint8* src_u;
    250       const uint8* src_v;
    251       if (format == FOURCC_YV24) {
    252         src_v = sample + src_width * (abs_src_height + crop_y) + crop_x;
    253         src_u = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x;
    254       } else {
    255         src_u = sample + src_width * (abs_src_height + crop_y) + crop_x;
    256         src_v = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x;
    257       }
    258       r = I444ToARGB(src_y, src_width,
    259                      src_u, src_width,
    260                      src_v, src_width,
    261                      crop_argb, argb_stride,
    262                      crop_width, inv_crop_height);
    263       break;
    264     }
    265     case FOURCC_I411: {
    266       int quarterwidth = (src_width + 3) / 4;
    267       const uint8* src_y = sample + src_width * crop_y + crop_x;
    268       const uint8* src_u = sample + src_width * abs_src_height +
    269           quarterwidth * crop_y + crop_x / 4;
    270       const uint8* src_v = sample + src_width * abs_src_height +
    271           quarterwidth * (abs_src_height + crop_y) + crop_x / 4;
    272       r = I411ToARGB(src_y, src_width,
    273                      src_u, quarterwidth,
    274                      src_v, quarterwidth,
    275                      crop_argb, argb_stride,
    276                      crop_width, inv_crop_height);
    277       break;
    278     }
    279 #ifdef HAVE_JPEG
    280     case FOURCC_MJPG:
    281       r = MJPGToARGB(sample, sample_size,
    282                      crop_argb, argb_stride,
    283                      src_width, abs_src_height, crop_width, inv_crop_height);
    284       break;
    285 #endif
    286     default:
    287       r = -1;  // unknown fourcc - return failure code.
    288   }
    289 
    290   if (need_buf) {
    291     if (!r) {
    292       r = ARGBRotate(crop_argb, argb_stride,
    293                      dest_argb, dest_argb_stride,
    294                      crop_width, abs_crop_height, rotation);
    295     }
    296     free(rotate_buffer);
    297   }
    298 
    299   return r;
    300 }
    301 
    302 #ifdef __cplusplus
    303 }  // extern "C"
    304 }  // namespace libyuv
    305 #endif
    306