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 <stdlib.h>
     12 
     13 #include "libyuv/convert.h"
     14 
     15 #include "libyuv/video_common.h"
     16 
     17 #ifdef __cplusplus
     18 namespace libyuv {
     19 extern "C" {
     20 #endif
     21 
     22 // Convert camera sample to I420 with cropping, rotation and vertical flip.
     23 // src_width is used for source stride computation
     24 // src_height is used to compute location of planes, and indicate inversion
     25 // sample_size is measured in bytes and is the size of the frame.
     26 //   With MJPEG it is the compressed size of the frame.
     27 LIBYUV_API
     28 int ConvertToI420(const uint8* sample,
     29                   size_t sample_size,
     30                   uint8* y, int y_stride,
     31                   uint8* u, int u_stride,
     32                   uint8* v, int v_stride,
     33                   int crop_x, int crop_y,
     34                   int src_width, int src_height,
     35                   int crop_width, int crop_height,
     36                   enum RotationMode rotation,
     37                   uint32 fourcc) {
     38   uint32 format = CanonicalFourCC(fourcc);
     39   int aligned_src_width = (src_width + 1) & ~1;
     40   const uint8* src;
     41   const uint8* src_uv;
     42   const int abs_src_height = (src_height < 0) ? -src_height : src_height;
     43   // TODO(nisse): Why allow crop_height < 0?
     44   const int abs_crop_height = (crop_height < 0) ? -crop_height : crop_height;
     45   int r = 0;
     46   LIBYUV_BOOL need_buf = (rotation && format != FOURCC_I420 &&
     47       format != FOURCC_NV12 && format != FOURCC_NV21 &&
     48       format != FOURCC_YV12) || y == sample;
     49   uint8* tmp_y = y;
     50   uint8* tmp_u = u;
     51   uint8* tmp_v = v;
     52   int tmp_y_stride = y_stride;
     53   int tmp_u_stride = u_stride;
     54   int tmp_v_stride = v_stride;
     55   uint8* rotate_buffer = NULL;
     56   const int inv_crop_height =
     57       (src_height < 0) ? -abs_crop_height : abs_crop_height;
     58 
     59   if (!y || !u || !v || !sample ||
     60       src_width <= 0 || crop_width <= 0  ||
     61       src_height == 0 || crop_height == 0) {
     62     return -1;
     63   }
     64 
     65   // One pass rotation is available for some formats. For the rest, convert
     66   // to I420 (with optional vertical flipping) into a temporary I420 buffer,
     67   // and then rotate the I420 to the final destination buffer.
     68   // For in-place conversion, if destination y is same as source sample,
     69   // also enable temporary buffer.
     70   if (need_buf) {
     71     int y_size = crop_width * abs_crop_height;
     72     int uv_size = ((crop_width + 1) / 2) * ((abs_crop_height + 1) / 2);
     73     rotate_buffer = (uint8*)malloc(y_size + uv_size * 2);
     74     if (!rotate_buffer) {
     75       return 1;  // Out of memory runtime error.
     76     }
     77     y = rotate_buffer;
     78     u = y + y_size;
     79     v = u + uv_size;
     80     y_stride = crop_width;
     81     u_stride = v_stride = ((crop_width + 1) / 2);
     82   }
     83 
     84   switch (format) {
     85     // Single plane formats
     86     case FOURCC_YUY2:
     87       src = sample + (aligned_src_width * crop_y + crop_x) * 2;
     88       r = YUY2ToI420(src, aligned_src_width * 2,
     89                      y, y_stride,
     90                      u, u_stride,
     91                      v, v_stride,
     92                      crop_width, inv_crop_height);
     93       break;
     94     case FOURCC_UYVY:
     95       src = sample + (aligned_src_width * crop_y + crop_x) * 2;
     96       r = UYVYToI420(src, aligned_src_width * 2,
     97                      y, y_stride,
     98                      u, u_stride,
     99                      v, v_stride,
    100                      crop_width, inv_crop_height);
    101       break;
    102     case FOURCC_RGBP:
    103       src = sample + (src_width * crop_y + crop_x) * 2;
    104       r = RGB565ToI420(src, src_width * 2,
    105                        y, y_stride,
    106                        u, u_stride,
    107                        v, v_stride,
    108                        crop_width, inv_crop_height);
    109       break;
    110     case FOURCC_RGBO:
    111       src = sample + (src_width * crop_y + crop_x) * 2;
    112       r = ARGB1555ToI420(src, src_width * 2,
    113                          y, y_stride,
    114                          u, u_stride,
    115                          v, v_stride,
    116                          crop_width, inv_crop_height);
    117       break;
    118     case FOURCC_R444:
    119       src = sample + (src_width * crop_y + crop_x) * 2;
    120       r = ARGB4444ToI420(src, src_width * 2,
    121                          y, y_stride,
    122                          u, u_stride,
    123                          v, v_stride,
    124                          crop_width, inv_crop_height);
    125       break;
    126     case FOURCC_24BG:
    127       src = sample + (src_width * crop_y + crop_x) * 3;
    128       r = RGB24ToI420(src, src_width * 3,
    129                       y, y_stride,
    130                       u, u_stride,
    131                       v, v_stride,
    132                       crop_width, inv_crop_height);
    133       break;
    134     case FOURCC_RAW:
    135       src = sample + (src_width * crop_y + crop_x) * 3;
    136       r = RAWToI420(src, src_width * 3,
    137                     y, y_stride,
    138                     u, u_stride,
    139                     v, v_stride,
    140                     crop_width, inv_crop_height);
    141       break;
    142     case FOURCC_ARGB:
    143       src = sample + (src_width * crop_y + crop_x) * 4;
    144       r = ARGBToI420(src, src_width * 4,
    145                      y, y_stride,
    146                      u, u_stride,
    147                      v, v_stride,
    148                      crop_width, inv_crop_height);
    149       break;
    150     case FOURCC_BGRA:
    151       src = sample + (src_width * crop_y + crop_x) * 4;
    152       r = BGRAToI420(src, src_width * 4,
    153                      y, y_stride,
    154                      u, u_stride,
    155                      v, v_stride,
    156                      crop_width, inv_crop_height);
    157       break;
    158     case FOURCC_ABGR:
    159       src = sample + (src_width * crop_y + crop_x) * 4;
    160       r = ABGRToI420(src, src_width * 4,
    161                      y, y_stride,
    162                      u, u_stride,
    163                      v, v_stride,
    164                      crop_width, inv_crop_height);
    165       break;
    166     case FOURCC_RGBA:
    167       src = sample + (src_width * crop_y + crop_x) * 4;
    168       r = RGBAToI420(src, src_width * 4,
    169                      y, y_stride,
    170                      u, u_stride,
    171                      v, v_stride,
    172                      crop_width, inv_crop_height);
    173       break;
    174     case FOURCC_I400:
    175       src = sample + src_width * crop_y + crop_x;
    176       r = I400ToI420(src, src_width,
    177                      y, y_stride,
    178                      u, u_stride,
    179                      v, v_stride,
    180                      crop_width, inv_crop_height);
    181       break;
    182     // Biplanar formats
    183     case FOURCC_NV12:
    184       src = sample + (src_width * crop_y + crop_x);
    185       src_uv = sample + (src_width * src_height) +
    186         ((crop_y / 2) * aligned_src_width) + ((crop_x / 2) * 2);
    187       r = NV12ToI420Rotate(src, src_width,
    188                            src_uv, aligned_src_width,
    189                            y, y_stride,
    190                            u, u_stride,
    191                            v, v_stride,
    192                            crop_width, inv_crop_height, rotation);
    193       break;
    194     case FOURCC_NV21:
    195       src = sample + (src_width * crop_y + crop_x);
    196       src_uv = sample + (src_width * src_height) +
    197         ((crop_y / 2) * aligned_src_width) + ((crop_x / 2) * 2);
    198       // Call NV12 but with u and v parameters swapped.
    199       r = NV12ToI420Rotate(src, src_width,
    200                            src_uv, aligned_src_width,
    201                            y, y_stride,
    202                            v, v_stride,
    203                            u, u_stride,
    204                            crop_width, inv_crop_height, rotation);
    205       break;
    206     case FOURCC_M420:
    207       src = sample + (src_width * crop_y) * 12 / 8 + crop_x;
    208       r = M420ToI420(src, src_width,
    209                      y, y_stride,
    210                      u, u_stride,
    211                      v, v_stride,
    212                      crop_width, inv_crop_height);
    213       break;
    214     // Triplanar formats
    215     case FOURCC_I420:
    216     case FOURCC_YV12: {
    217       const uint8* src_y = sample + (src_width * crop_y + crop_x);
    218       const uint8* src_u;
    219       const uint8* src_v;
    220       int halfwidth = (src_width + 1) / 2;
    221       int halfheight = (abs_src_height + 1) / 2;
    222       if (format == FOURCC_YV12) {
    223         src_v = sample + src_width * abs_src_height +
    224             (halfwidth * crop_y + crop_x) / 2;
    225         src_u = sample + src_width * abs_src_height +
    226             halfwidth * (halfheight + crop_y / 2) + crop_x / 2;
    227       } else {
    228         src_u = sample + src_width * abs_src_height +
    229             (halfwidth * crop_y + crop_x) / 2;
    230         src_v = sample + src_width * abs_src_height +
    231             halfwidth * (halfheight + crop_y / 2) + crop_x / 2;
    232       }
    233       r = I420Rotate(src_y, src_width,
    234                      src_u, halfwidth,
    235                      src_v, halfwidth,
    236                      y, y_stride,
    237                      u, u_stride,
    238                      v, v_stride,
    239                      crop_width, inv_crop_height, rotation);
    240       break;
    241     }
    242     case FOURCC_I422:
    243     case FOURCC_YV16: {
    244       const uint8* src_y = sample + src_width * crop_y + crop_x;
    245       const uint8* src_u;
    246       const uint8* src_v;
    247       int halfwidth = (src_width + 1) / 2;
    248       if (format == FOURCC_YV16) {
    249         src_v = sample + src_width * abs_src_height +
    250             halfwidth * crop_y + crop_x / 2;
    251         src_u = sample + src_width * abs_src_height +
    252             halfwidth * (abs_src_height + crop_y) + crop_x / 2;
    253       } else {
    254         src_u = sample + src_width * abs_src_height +
    255             halfwidth * crop_y + crop_x / 2;
    256         src_v = sample + src_width * abs_src_height +
    257             halfwidth * (abs_src_height + crop_y) + crop_x / 2;
    258       }
    259       r = I422ToI420(src_y, src_width,
    260                      src_u, halfwidth,
    261                      src_v, halfwidth,
    262                      y, y_stride,
    263                      u, u_stride,
    264                      v, v_stride,
    265                      crop_width, inv_crop_height);
    266       break;
    267     }
    268     case FOURCC_I444:
    269     case FOURCC_YV24: {
    270       const uint8* src_y = sample + src_width * crop_y + crop_x;
    271       const uint8* src_u;
    272       const uint8* src_v;
    273       if (format == FOURCC_YV24) {
    274         src_v = sample + src_width * (abs_src_height + crop_y) + crop_x;
    275         src_u = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x;
    276       } else {
    277         src_u = sample + src_width * (abs_src_height + crop_y) + crop_x;
    278         src_v = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x;
    279       }
    280       r = I444ToI420(src_y, src_width,
    281                      src_u, src_width,
    282                      src_v, src_width,
    283                      y, y_stride,
    284                      u, u_stride,
    285                      v, v_stride,
    286                      crop_width, inv_crop_height);
    287       break;
    288     }
    289     case FOURCC_I411: {
    290       int quarterwidth = (src_width + 3) / 4;
    291       const uint8* src_y = sample + src_width * crop_y + crop_x;
    292       const uint8* src_u = sample + src_width * abs_src_height +
    293           quarterwidth * crop_y + crop_x / 4;
    294       const uint8* src_v = sample + src_width * abs_src_height +
    295           quarterwidth * (abs_src_height + crop_y) + crop_x / 4;
    296       r = I411ToI420(src_y, src_width,
    297                      src_u, quarterwidth,
    298                      src_v, quarterwidth,
    299                      y, y_stride,
    300                      u, u_stride,
    301                      v, v_stride,
    302                      crop_width, inv_crop_height);
    303       break;
    304     }
    305 #ifdef HAVE_JPEG
    306     case FOURCC_MJPG:
    307       r = MJPGToI420(sample, sample_size,
    308                      y, y_stride,
    309                      u, u_stride,
    310                      v, v_stride,
    311                      src_width, abs_src_height, crop_width, inv_crop_height);
    312       break;
    313 #endif
    314     default:
    315       r = -1;  // unknown fourcc - return failure code.
    316   }
    317 
    318   if (need_buf) {
    319     if (!r) {
    320       r = I420Rotate(y, y_stride,
    321                      u, u_stride,
    322                      v, v_stride,
    323                      tmp_y, tmp_y_stride,
    324                      tmp_u, tmp_u_stride,
    325                      tmp_v, tmp_v_stride,
    326                      crop_width, abs_crop_height, rotation);
    327     }
    328     free(rotate_buffer);
    329   }
    330 
    331   return r;
    332 }
    333 
    334 #ifdef __cplusplus
    335 }  // extern "C"
    336 }  // namespace libyuv
    337 #endif
    338