Home | History | Annotate | Download | only in libyuv
      1 /*
      2  *  Copyright (c) 2012 The WebRTC 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 "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
     12 
     13 #include <assert.h>
     14 #include <string.h>
     15 
     16 // NOTE(ajm): Path provided by gyp.
     17 #include "libyuv.h"  // NOLINT
     18 
     19 namespace webrtc {
     20 
     21 const int k16ByteAlignment = 16;
     22 
     23 VideoType RawVideoTypeToCommonVideoVideoType(RawVideoType type) {
     24   switch (type) {
     25     case kVideoI420:
     26       return kI420;
     27     case kVideoIYUV:
     28       return kIYUV;
     29     case kVideoRGB24:
     30       return kRGB24;
     31     case kVideoARGB:
     32       return kARGB;
     33     case kVideoARGB4444:
     34       return kARGB4444;
     35     case kVideoRGB565:
     36       return kRGB565;
     37     case kVideoARGB1555:
     38       return kARGB1555;
     39     case kVideoYUY2:
     40       return kYUY2;
     41     case kVideoYV12:
     42       return kYV12;
     43     case kVideoUYVY:
     44       return kUYVY;
     45     case kVideoNV21:
     46       return kNV21;
     47     case kVideoNV12:
     48       return kNV12;
     49     case kVideoBGRA:
     50       return kBGRA;
     51     case kVideoMJPEG:
     52       return kMJPG;
     53     default:
     54       assert(false);
     55   }
     56   return kUnknown;
     57 }
     58 
     59 int AlignInt(int value, int alignment) {
     60   assert(!((alignment - 1) & alignment));
     61   return ((value + alignment - 1) & ~ (alignment - 1));
     62 }
     63 
     64 void Calc16ByteAlignedStride(int width, int* stride_y, int* stride_uv) {
     65   *stride_y = AlignInt(width, k16ByteAlignment);
     66   *stride_uv = AlignInt((width + 1) / 2, k16ByteAlignment);
     67 }
     68 
     69 int CalcBufferSize(VideoType type, int width, int height) {
     70   int buffer_size = 0;
     71   switch (type) {
     72     case kI420:
     73     case kNV12:
     74     case kNV21:
     75     case kIYUV:
     76     case kYV12: {
     77       int half_width = (width + 1) >> 1;
     78       int half_height = (height + 1) >> 1;
     79       buffer_size = width * height + half_width * half_height * 2;
     80       break;
     81     }
     82     case kARGB4444:
     83     case kRGB565:
     84     case kARGB1555:
     85     case kYUY2:
     86     case kUYVY:
     87       buffer_size = width * height * 2;
     88       break;
     89     case kRGB24:
     90       buffer_size = width * height * 3;
     91       break;
     92     case kBGRA:
     93     case kARGB:
     94       buffer_size = width * height * 4;
     95       break;
     96     default:
     97       assert(false);
     98       return -1;
     99   }
    100   return buffer_size;
    101 }
    102 
    103 int PrintI420VideoFrame(const I420VideoFrame& frame, FILE* file) {
    104   if (file == NULL)
    105     return -1;
    106   if (frame.IsZeroSize())
    107     return -1;
    108   for (int planeNum = 0; planeNum < kNumOfPlanes; ++planeNum) {
    109     int width = (planeNum ? (frame.width() + 1) / 2 : frame.width());
    110     int height = (planeNum ? (frame.height() + 1) / 2 : frame.height());
    111     PlaneType plane_type = static_cast<PlaneType>(planeNum);
    112     const uint8_t* plane_buffer = frame.buffer(plane_type);
    113     for (int y = 0; y < height; y++) {
    114      if (fwrite(plane_buffer, 1, width, file) !=
    115          static_cast<unsigned int>(width)) {
    116        return -1;
    117        }
    118        plane_buffer += frame.stride(plane_type);
    119     }
    120  }
    121  return 0;
    122 }
    123 
    124 int ExtractBuffer(const I420VideoFrame& input_frame,
    125                   int size, uint8_t* buffer) {
    126   assert(buffer);
    127   if (input_frame.IsZeroSize())
    128     return -1;
    129   int length = CalcBufferSize(kI420, input_frame.width(), input_frame.height());
    130   if (size < length) {
    131      return -1;
    132   }
    133 
    134   int pos = 0;
    135   uint8_t* buffer_ptr = buffer;
    136 
    137   for (int plane = 0; plane < kNumOfPlanes; ++plane) {
    138     int width = (plane ? (input_frame.width() + 1) / 2 :
    139       input_frame.width());
    140     int height = (plane ? (input_frame.height() + 1) / 2 :
    141       input_frame.height());
    142     const uint8_t* plane_ptr = input_frame.buffer(
    143         static_cast<PlaneType>(plane));
    144     for (int y = 0; y < height; y++) {
    145       memcpy(&buffer_ptr[pos], plane_ptr, width);
    146       pos += width;
    147       plane_ptr += input_frame.stride(static_cast<PlaneType>(plane));
    148     }
    149   }
    150   return length;
    151 }
    152 
    153 
    154 int ConvertNV12ToRGB565(const uint8_t* src_frame,
    155                         uint8_t* dst_frame,
    156                         int width, int height) {
    157   int abs_height = (height < 0) ? -height : height;
    158   const uint8_t* yplane = src_frame;
    159   const uint8_t* uvInterlaced = src_frame + (width * abs_height);
    160 
    161   return libyuv::NV12ToRGB565(yplane, width,
    162                               uvInterlaced, (width + 1) >> 1,
    163                               dst_frame, width,
    164                               width, height);
    165 }
    166 
    167 int ConvertRGB24ToARGB(const uint8_t* src_frame, uint8_t* dst_frame,
    168                        int width, int height, int dst_stride) {
    169   if (dst_stride == 0)
    170     dst_stride = width;
    171   return libyuv::RGB24ToARGB(src_frame, width,
    172                              dst_frame, dst_stride,
    173                              width, height);
    174 }
    175 
    176 libyuv::RotationMode ConvertRotationMode(VideoRotationMode rotation) {
    177   switch(rotation) {
    178     case kRotateNone:
    179       return libyuv::kRotate0;
    180     case kRotate90:
    181       return libyuv::kRotate90;
    182     case kRotate180:
    183       return libyuv::kRotate180;
    184     case kRotate270:
    185       return libyuv::kRotate270;
    186   }
    187   assert(false);
    188   return libyuv::kRotate0;
    189 }
    190 
    191 int ConvertVideoType(VideoType video_type) {
    192   switch(video_type) {
    193     case kUnknown:
    194       return libyuv::FOURCC_ANY;
    195     case  kI420:
    196       return libyuv::FOURCC_I420;
    197     case kIYUV:  // same as KYV12
    198     case kYV12:
    199       return libyuv::FOURCC_YV12;
    200     case kRGB24:
    201       return libyuv::FOURCC_24BG;
    202     case kABGR:
    203       return libyuv::FOURCC_ABGR;
    204     case kRGB565:
    205       return libyuv::FOURCC_RGBP;
    206     case kYUY2:
    207       return libyuv::FOURCC_YUY2;
    208     case kUYVY:
    209       return libyuv::FOURCC_UYVY;
    210     case kMJPG:
    211       return libyuv::FOURCC_MJPG;
    212     case kNV21:
    213       return libyuv::FOURCC_NV21;
    214     case kNV12:
    215       return libyuv::FOURCC_NV12;
    216     case kARGB:
    217       return libyuv::FOURCC_ARGB;
    218     case kBGRA:
    219       return libyuv::FOURCC_BGRA;
    220     case kARGB4444:
    221       return libyuv::FOURCC_R444;
    222     case kARGB1555:
    223       return libyuv::FOURCC_RGBO;
    224   }
    225   assert(false);
    226   return libyuv::FOURCC_ANY;
    227 }
    228 
    229 int ConvertToI420(VideoType src_video_type,
    230                   const uint8_t* src_frame,
    231                   int crop_x, int crop_y,
    232                   int src_width, int src_height,
    233                   int sample_size,
    234                   VideoRotationMode rotation,
    235                   I420VideoFrame* dst_frame) {
    236   int dst_width = dst_frame->width();
    237   int dst_height = dst_frame->height();
    238   // LibYuv expects pre-rotation values for dst.
    239   // Stride values should correspond to the destination values.
    240   if (rotation == kRotate90 || rotation == kRotate270) {
    241     dst_width = dst_frame->height();
    242     dst_height =dst_frame->width();
    243   }
    244   return libyuv::ConvertToI420(src_frame, sample_size,
    245                                dst_frame->buffer(kYPlane),
    246                                dst_frame->stride(kYPlane),
    247                                dst_frame->buffer(kUPlane),
    248                                dst_frame->stride(kUPlane),
    249                                dst_frame->buffer(kVPlane),
    250                                dst_frame->stride(kVPlane),
    251                                crop_x, crop_y,
    252                                src_width, src_height,
    253                                dst_width, dst_height,
    254                                ConvertRotationMode(rotation),
    255                                ConvertVideoType(src_video_type));
    256 }
    257 
    258 int ConvertFromI420(const I420VideoFrame& src_frame,
    259                     VideoType dst_video_type, int dst_sample_size,
    260                     uint8_t* dst_frame) {
    261   return libyuv::ConvertFromI420(src_frame.buffer(kYPlane),
    262                                  src_frame.stride(kYPlane),
    263                                  src_frame.buffer(kUPlane),
    264                                  src_frame.stride(kUPlane),
    265                                  src_frame.buffer(kVPlane),
    266                                  src_frame.stride(kVPlane),
    267                                  dst_frame, dst_sample_size,
    268                                  src_frame.width(), src_frame.height(),
    269                                  ConvertVideoType(dst_video_type));
    270 }
    271 
    272 // TODO(mikhal): Create a designated VideoFrame for non I420.
    273 int ConvertFromYV12(const I420VideoFrame& src_frame,
    274                     VideoType dst_video_type, int dst_sample_size,
    275                     uint8_t* dst_frame) {
    276   // YV12 = Y, V, U
    277   return libyuv::ConvertFromI420(src_frame.buffer(kYPlane),
    278                                  src_frame.stride(kYPlane),
    279                                  src_frame.buffer(kVPlane),
    280                                  src_frame.stride(kVPlane),
    281                                  src_frame.buffer(kUPlane),
    282                                  src_frame.stride(kUPlane),
    283                                  dst_frame, dst_sample_size,
    284                                  src_frame.width(), src_frame.height(),
    285                                  ConvertVideoType(dst_video_type));
    286 }
    287 
    288 int MirrorI420LeftRight(const I420VideoFrame* src_frame,
    289                         I420VideoFrame* dst_frame) {
    290   // Source and destination frames should have equal resolution.
    291   if (src_frame->width() != dst_frame->width() ||
    292       src_frame->height() != dst_frame->height())
    293     return -1;
    294   return libyuv::I420Mirror(src_frame->buffer(kYPlane),
    295                             src_frame->stride(kYPlane),
    296                             src_frame->buffer(kUPlane),
    297                             src_frame->stride(kUPlane),
    298                             src_frame->buffer(kVPlane),
    299                             src_frame->stride(kVPlane),
    300                             dst_frame->buffer(kYPlane),
    301                             dst_frame->stride(kYPlane),
    302                             dst_frame->buffer(kUPlane),
    303                             dst_frame->stride(kUPlane),
    304                             dst_frame->buffer(kVPlane),
    305                             dst_frame->stride(kVPlane),
    306                             src_frame->width(), src_frame->height());
    307 }
    308 
    309 int MirrorI420UpDown(const I420VideoFrame* src_frame,
    310                      I420VideoFrame* dst_frame) {
    311   // Source and destination frames should have equal resolution
    312   if (src_frame->width() != dst_frame->width() ||
    313       src_frame->height() != dst_frame->height())
    314     return -1;
    315 
    316   // Inserting negative height flips the frame.
    317   return libyuv::I420Copy(src_frame->buffer(kYPlane),
    318                           src_frame->stride(kYPlane),
    319                           src_frame->buffer(kUPlane),
    320                           src_frame->stride(kUPlane),
    321                           src_frame->buffer(kVPlane),
    322                           src_frame->stride(kVPlane),
    323                           dst_frame->buffer(kYPlane),
    324                           dst_frame->stride(kYPlane),
    325                           dst_frame->buffer(kUPlane),
    326                           dst_frame->stride(kUPlane),
    327                           dst_frame->buffer(kVPlane),
    328                           dst_frame->stride(kVPlane),
    329                           src_frame->width(), -(src_frame->height()));
    330 }
    331 
    332 // Compute PSNR for an I420 frame (all planes)
    333 double I420PSNR(const I420VideoFrame* ref_frame,
    334                 const I420VideoFrame* test_frame) {
    335   if (!ref_frame || !test_frame)
    336     return -1;
    337   else if ((ref_frame->width() !=  test_frame->width()) ||
    338           (ref_frame->height() !=  test_frame->height()))
    339     return -1;
    340   else if (ref_frame->width() < 0 || ref_frame->height() < 0)
    341     return -1;
    342 
    343   double psnr = libyuv::I420Psnr(ref_frame->buffer(kYPlane),
    344                                  ref_frame->stride(kYPlane),
    345                                  ref_frame->buffer(kUPlane),
    346                                  ref_frame->stride(kUPlane),
    347                                  ref_frame->buffer(kVPlane),
    348                                  ref_frame->stride(kVPlane),
    349                                  test_frame->buffer(kYPlane),
    350                                  test_frame->stride(kYPlane),
    351                                  test_frame->buffer(kUPlane),
    352                                  test_frame->stride(kUPlane),
    353                                  test_frame->buffer(kVPlane),
    354                                  test_frame->stride(kVPlane),
    355                                  test_frame->width(), test_frame->height());
    356   // LibYuv sets the max psnr value to 128, we restrict it here.
    357   // In case of 0 mse in one frame, 128 can skew the results significantly.
    358   return (psnr > kPerfectPSNR) ? kPerfectPSNR : psnr;
    359 }
    360 
    361 // Compute SSIM for an I420 frame (all planes)
    362 double I420SSIM(const I420VideoFrame* ref_frame,
    363                 const I420VideoFrame* test_frame) {
    364   if (!ref_frame || !test_frame)
    365     return -1;
    366   else if ((ref_frame->width() !=  test_frame->width()) ||
    367           (ref_frame->height() !=  test_frame->height()))
    368     return -1;
    369   else if (ref_frame->width() < 0 || ref_frame->height()  < 0)
    370     return -1;
    371 
    372   return libyuv::I420Ssim(ref_frame->buffer(kYPlane),
    373                           ref_frame->stride(kYPlane),
    374                           ref_frame->buffer(kUPlane),
    375                           ref_frame->stride(kUPlane),
    376                           ref_frame->buffer(kVPlane),
    377                           ref_frame->stride(kVPlane),
    378                           test_frame->buffer(kYPlane),
    379                           test_frame->stride(kYPlane),
    380                           test_frame->buffer(kUPlane),
    381                           test_frame->stride(kUPlane),
    382                           test_frame->buffer(kVPlane),
    383                           test_frame->stride(kVPlane),
    384                           test_frame->width(), test_frame->height());
    385 }
    386 }  // namespace webrtc
    387