media/libyuv/source/convert_to_i420.cc

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial