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 size_t CalcBufferSize(VideoType type, int width, int height) {
     70   assert(width >= 0);
     71   assert(height >= 0);
     72   size_t buffer_size = 0;
     73   switch (type) {
     74     case kI420:
     75     case kNV12:
     76     case kNV21:
     77     case kIYUV:
     78     case kYV12: {
     79       int half_width = (width + 1) >> 1;
     80       int half_height = (height + 1) >> 1;
     81       buffer_size = width * height + half_width * half_height * 2;
     82       break;
     83     }
     84     case kARGB4444:
     85     case kRGB565:
     86     case kARGB1555:
     87     case kYUY2:
     88     case kUYVY:
     89       buffer_size = width * height * 2;
     90       break;
     91     case kRGB24:
     92       buffer_size = width * height * 3;
     93       break;
     94     case kBGRA:
     95     case kARGB:
     96       buffer_size = width * height * 4;
     97       break;
     98     default:
     99       assert(false);
    100       break;
    101   }
    102   return buffer_size;
    103 }
    104 
    105 int PrintVideoFrame(const VideoFrame& frame, FILE* file) {
    106   if (file == NULL)
    107     return -1;
    108   if (frame.IsZeroSize())
    109     return -1;
    110   for (int planeNum = 0; planeNum < kNumOfPlanes; ++planeNum) {
    111     int width = (planeNum ? (frame.width() + 1) / 2 : frame.width());
    112     int height = (planeNum ? (frame.height() + 1) / 2 : frame.height());
    113     PlaneType plane_type = static_cast<PlaneType>(planeNum);
    114     const uint8_t* plane_buffer = frame.buffer(plane_type);
    115     for (int y = 0; y < height; y++) {
    116      if (fwrite(plane_buffer, 1, width, file) !=
    117          static_cast<unsigned int>(width)) {
    118        return -1;
    119        }
    120        plane_buffer += frame.stride(plane_type);
    121     }
    122   }
    123   return 0;
    124 }
    125 
    126 int ExtractBuffer(const VideoFrame& input_frame, size_t size, uint8_t* buffer) {
    127   assert(buffer);
    128   if (input_frame.IsZeroSize())
    129     return -1;
    130   size_t length =
    131       CalcBufferSize(kI420, input_frame.width(), input_frame.height());
    132   if (size < length) {
    133      return -1;
    134   }
    135 
    136   int pos = 0;
    137   uint8_t* buffer_ptr = buffer;
    138 
    139   for (int plane = 0; plane < kNumOfPlanes; ++plane) {
    140     int width = (plane ? (input_frame.width() + 1) / 2 :
    141       input_frame.width());
    142     int height = (plane ? (input_frame.height() + 1) / 2 :
    143       input_frame.height());
    144     const uint8_t* plane_ptr = input_frame.buffer(
    145         static_cast<PlaneType>(plane));
    146     for (int y = 0; y < height; y++) {
    147       memcpy(&buffer_ptr[pos], plane_ptr, width);
    148       pos += width;
    149       plane_ptr += input_frame.stride(static_cast<PlaneType>(plane));
    150     }
    151   }
    152   return static_cast<int>(length);
    153 }
    154 
    155 
    156 int ConvertNV12ToRGB565(const uint8_t* src_frame,
    157                         uint8_t* dst_frame,
    158                         int width, int height) {
    159   int abs_height = (height < 0) ? -height : height;
    160   const uint8_t* yplane = src_frame;
    161   const uint8_t* uvInterlaced = src_frame + (width * abs_height);
    162 
    163   return libyuv::NV12ToRGB565(yplane, width,
    164                               uvInterlaced, (width + 1) >> 1,
    165                               dst_frame, width,
    166                               width, height);
    167 }
    168 
    169 int ConvertRGB24ToARGB(const uint8_t* src_frame, uint8_t* dst_frame,
    170                        int width, int height, int dst_stride) {
    171   if (dst_stride == 0)
    172     dst_stride = width;
    173   return libyuv::RGB24ToARGB(src_frame, width,
    174                              dst_frame, dst_stride,
    175                              width, height);
    176 }
    177 
    178 libyuv::RotationMode ConvertRotationMode(VideoRotation rotation) {
    179   switch (rotation) {
    180     case kVideoRotation_0:
    181       return libyuv::kRotate0;
    182     case kVideoRotation_90:
    183       return libyuv::kRotate90;
    184     case kVideoRotation_180:
    185       return libyuv::kRotate180;
    186     case kVideoRotation_270:
    187       return libyuv::kRotate270;
    188   }
    189   assert(false);
    190   return libyuv::kRotate0;
    191 }
    192 
    193 int ConvertVideoType(VideoType video_type) {
    194   switch (video_type) {
    195     case kUnknown:
    196       return libyuv::FOURCC_ANY;
    197     case  kI420:
    198       return libyuv::FOURCC_I420;
    199     case kIYUV:  // same as KYV12
    200     case kYV12:
    201       return libyuv::FOURCC_YV12;
    202     case kRGB24:
    203       return libyuv::FOURCC_24BG;
    204     case kABGR:
    205       return libyuv::FOURCC_ABGR;
    206     case kRGB565:
    207       return libyuv::FOURCC_RGBP;
    208     case kYUY2:
    209       return libyuv::FOURCC_YUY2;
    210     case kUYVY:
    211       return libyuv::FOURCC_UYVY;
    212     case kMJPG:
    213       return libyuv::FOURCC_MJPG;
    214     case kNV21:
    215       return libyuv::FOURCC_NV21;
    216     case kNV12:
    217       return libyuv::FOURCC_NV12;
    218     case kARGB:
    219       return libyuv::FOURCC_ARGB;
    220     case kBGRA:
    221       return libyuv::FOURCC_BGRA;
    222     case kARGB4444:
    223       return libyuv::FOURCC_R444;
    224     case kARGB1555:
    225       return libyuv::FOURCC_RGBO;
    226   }
    227   assert(false);
    228   return libyuv::FOURCC_ANY;
    229 }
    230 
    231 int ConvertToI420(VideoType src_video_type,
    232                   const uint8_t* src_frame,
    233                   int crop_x,
    234                   int crop_y,
    235                   int src_width,
    236                   int src_height,
    237                   size_t sample_size,
    238                   VideoRotation rotation,
    239                   VideoFrame* dst_frame) {
    240   int dst_width = dst_frame->width();
    241   int dst_height = dst_frame->height();
    242   // LibYuv expects pre-rotation values for dst.
    243   // Stride values should correspond to the destination values.
    244   if (rotation == kVideoRotation_90 || rotation == kVideoRotation_270) {
    245     dst_width = dst_frame->height();
    246     dst_height = dst_frame->width();
    247   }
    248   return libyuv::ConvertToI420(src_frame, sample_size,
    249                                dst_frame->buffer(kYPlane),
    250                                dst_frame->stride(kYPlane),
    251                                dst_frame->buffer(kUPlane),
    252                                dst_frame->stride(kUPlane),
    253                                dst_frame->buffer(kVPlane),
    254                                dst_frame->stride(kVPlane),
    255                                crop_x, crop_y,
    256                                src_width, src_height,
    257                                dst_width, dst_height,
    258                                ConvertRotationMode(rotation),
    259                                ConvertVideoType(src_video_type));
    260 }
    261 
    262 int ConvertFromI420(const VideoFrame& src_frame,
    263                     VideoType dst_video_type,
    264                     int dst_sample_size,
    265                     uint8_t* dst_frame) {
    266   return libyuv::ConvertFromI420(src_frame.buffer(kYPlane),
    267                                  src_frame.stride(kYPlane),
    268                                  src_frame.buffer(kUPlane),
    269                                  src_frame.stride(kUPlane),
    270                                  src_frame.buffer(kVPlane),
    271                                  src_frame.stride(kVPlane),
    272                                  dst_frame, dst_sample_size,
    273                                  src_frame.width(), src_frame.height(),
    274                                  ConvertVideoType(dst_video_type));
    275 }
    276 
    277 // TODO(mikhal): Create a designated VideoFrame for non I420.
    278 int ConvertFromYV12(const VideoFrame& src_frame,
    279                     VideoType dst_video_type,
    280                     int dst_sample_size,
    281                     uint8_t* dst_frame) {
    282   // YV12 = Y, V, U
    283   return libyuv::ConvertFromI420(src_frame.buffer(kYPlane),
    284                                  src_frame.stride(kYPlane),
    285                                  src_frame.buffer(kVPlane),
    286                                  src_frame.stride(kVPlane),
    287                                  src_frame.buffer(kUPlane),
    288                                  src_frame.stride(kUPlane),
    289                                  dst_frame, dst_sample_size,
    290                                  src_frame.width(), src_frame.height(),
    291                                  ConvertVideoType(dst_video_type));
    292 }
    293 
    294 // Compute PSNR for an I420 frame (all planes)
    295 double I420PSNR(const VideoFrame* ref_frame, const VideoFrame* test_frame) {
    296   if (!ref_frame || !test_frame)
    297     return -1;
    298   else if ((ref_frame->width() !=  test_frame->width()) ||
    299           (ref_frame->height() !=  test_frame->height()))
    300     return -1;
    301   else if (ref_frame->width() < 0 || ref_frame->height() < 0)
    302     return -1;
    303 
    304   double psnr = libyuv::I420Psnr(ref_frame->buffer(kYPlane),
    305                                  ref_frame->stride(kYPlane),
    306                                  ref_frame->buffer(kUPlane),
    307                                  ref_frame->stride(kUPlane),
    308                                  ref_frame->buffer(kVPlane),
    309                                  ref_frame->stride(kVPlane),
    310                                  test_frame->buffer(kYPlane),
    311                                  test_frame->stride(kYPlane),
    312                                  test_frame->buffer(kUPlane),
    313                                  test_frame->stride(kUPlane),
    314                                  test_frame->buffer(kVPlane),
    315                                  test_frame->stride(kVPlane),
    316                                  test_frame->width(), test_frame->height());
    317   // LibYuv sets the max psnr value to 128, we restrict it here.
    318   // In case of 0 mse in one frame, 128 can skew the results significantly.
    319   return (psnr > kPerfectPSNR) ? kPerfectPSNR : psnr;
    320 }
    321 
    322 // Compute SSIM for an I420 frame (all planes)
    323 double I420SSIM(const VideoFrame* ref_frame, const VideoFrame* test_frame) {
    324   if (!ref_frame || !test_frame)
    325     return -1;
    326   else if ((ref_frame->width() !=  test_frame->width()) ||
    327           (ref_frame->height() !=  test_frame->height()))
    328     return -1;
    329   else if (ref_frame->width() < 0 || ref_frame->height()  < 0)
    330     return -1;
    331 
    332   return libyuv::I420Ssim(ref_frame->buffer(kYPlane),
    333                           ref_frame->stride(kYPlane),
    334                           ref_frame->buffer(kUPlane),
    335                           ref_frame->stride(kUPlane),
    336                           ref_frame->buffer(kVPlane),
    337                           ref_frame->stride(kVPlane),
    338                           test_frame->buffer(kYPlane),
    339                           test_frame->stride(kYPlane),
    340                           test_frame->buffer(kUPlane),
    341                           test_frame->stride(kUPlane),
    342                           test_frame->buffer(kVPlane),
    343                           test_frame->stride(kVPlane),
    344                           test_frame->width(), test_frame->height());
    345 }
    346 }  // namespace webrtc
    347