tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

i010_buffer.cc (7201B)


      1 /*
      2 *  Copyright (c) 2018 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 #include "api/video/i010_buffer.h"
     11 
     12 #include <cstdint>
     13 #include <utility>
     14 
     15 #include "api/make_ref_counted.h"
     16 #include "api/scoped_refptr.h"
     17 #include "api/video/i420_buffer.h"
     18 #include "api/video/video_frame_buffer.h"
     19 #include "api/video/video_rotation.h"
     20 #include "rtc_base/checks.h"
     21 #include "rtc_base/memory/aligned_malloc.h"
     22 #include "rtc_base/numerics/safe_conversions.h"
     23 #include "third_party/libyuv/include/libyuv/convert.h"
     24 #include "third_party/libyuv/include/libyuv/convert_from.h"
     25 #include "third_party/libyuv/include/libyuv/rotate.h"
     26 #include "third_party/libyuv/include/libyuv/scale.h"
     27 
     28 // Aligning pointer to 64 bytes for improved performance, e.g. use SIMD.
     29 static const int kBufferAlignment = 64;
     30 static const int kBytesPerPixel = 2;
     31 
     32 namespace webrtc {
     33 
     34 namespace {
     35 
     36 int I010DataSize(int width,
     37                 int height,
     38                 int stride_y,
     39                 int stride_u,
     40                 int stride_v) {
     41  CheckValidDimensions(width, height, stride_y, stride_u, stride_v);
     42  int64_t h = height, y = stride_y, u = stride_u, v = stride_v;
     43  return checked_cast<int>(kBytesPerPixel * (y * h + (u + v) * ((h + 1) / 2)));
     44 }
     45 
     46 }  // namespace
     47 
     48 I010Buffer::I010Buffer(int width,
     49                       int height,
     50                       int stride_y,
     51                       int stride_u,
     52                       int stride_v)
     53    : width_(width),
     54      height_(height),
     55      stride_y_(stride_y),
     56      stride_u_(stride_u),
     57      stride_v_(stride_v),
     58      data_(static_cast<uint16_t*>(AlignedMalloc(
     59          I010DataSize(width, height, stride_y, stride_u, stride_v),
     60          kBufferAlignment))) {
     61  RTC_DCHECK_GE(stride_u, (width + 1) / 2);
     62  RTC_DCHECK_GE(stride_v, (width + 1) / 2);
     63 }
     64 
     65 I010Buffer::~I010Buffer() {}
     66 
     67 // static
     68 scoped_refptr<I010Buffer> I010Buffer::Create(int width, int height) {
     69  return make_ref_counted<I010Buffer>(width, height, width, (width + 1) / 2,
     70                                      (width + 1) / 2);
     71 }
     72 
     73 // static
     74 scoped_refptr<I010Buffer> I010Buffer::Copy(const I010BufferInterface& source) {
     75  const int width = source.width();
     76  const int height = source.height();
     77  scoped_refptr<I010Buffer> buffer = Create(width, height);
     78  int res = libyuv::I010Copy(
     79      source.DataY(), source.StrideY(), source.DataU(), source.StrideU(),
     80      source.DataV(), source.StrideV(), buffer->MutableDataY(),
     81      buffer->StrideY(), buffer->MutableDataU(), buffer->StrideU(),
     82      buffer->MutableDataV(), buffer->StrideV(), width, height);
     83  RTC_DCHECK_EQ(res, 0);
     84 
     85  return buffer;
     86 }
     87 
     88 // static
     89 scoped_refptr<I010Buffer> I010Buffer::Copy(const I420BufferInterface& source) {
     90  const int width = source.width();
     91  const int height = source.height();
     92  scoped_refptr<I010Buffer> buffer = Create(width, height);
     93  int res = libyuv::I420ToI010(
     94      source.DataY(), source.StrideY(), source.DataU(), source.StrideU(),
     95      source.DataV(), source.StrideV(), buffer->MutableDataY(),
     96      buffer->StrideY(), buffer->MutableDataU(), buffer->StrideU(),
     97      buffer->MutableDataV(), buffer->StrideV(), width, height);
     98  RTC_DCHECK_EQ(res, 0);
     99 
    100  return buffer;
    101 }
    102 
    103 // static
    104 scoped_refptr<I010Buffer> I010Buffer::Rotate(const I010BufferInterface& src,
    105                                             VideoRotation rotation) {
    106  if (rotation == kVideoRotation_0)
    107    return Copy(src);
    108 
    109  RTC_CHECK(src.DataY());
    110  RTC_CHECK(src.DataU());
    111  RTC_CHECK(src.DataV());
    112  int rotated_width = src.width();
    113  int rotated_height = src.height();
    114  if (rotation == kVideoRotation_90 || rotation == kVideoRotation_270) {
    115    std::swap(rotated_width, rotated_height);
    116  }
    117 
    118  scoped_refptr<I010Buffer> buffer = Create(rotated_width, rotated_height);
    119 
    120  int res = libyuv::I010Rotate(
    121      src.DataY(), src.StrideY(), src.DataU(), src.StrideU(), src.DataV(),
    122      src.StrideV(), buffer->MutableDataY(), buffer->StrideY(),
    123      buffer->MutableDataU(), buffer->StrideU(), buffer->MutableDataV(),
    124      buffer->StrideV(), src.width(), src.height(),
    125      static_cast<libyuv::RotationMode>(rotation));
    126  RTC_DCHECK_EQ(res, 0);
    127 
    128  return buffer;
    129 }
    130 
    131 scoped_refptr<I420BufferInterface> I010Buffer::ToI420() {
    132  scoped_refptr<I420Buffer> i420_buffer = I420Buffer::Create(width(), height());
    133  int res = libyuv::I010ToI420(
    134      DataY(), StrideY(), DataU(), StrideU(), DataV(), StrideV(),
    135      i420_buffer->MutableDataY(), i420_buffer->StrideY(),
    136      i420_buffer->MutableDataU(), i420_buffer->StrideU(),
    137      i420_buffer->MutableDataV(), i420_buffer->StrideV(), width(), height());
    138  RTC_DCHECK_EQ(res, 0);
    139 
    140  return i420_buffer;
    141 }
    142 
    143 int I010Buffer::width() const {
    144  return width_;
    145 }
    146 
    147 int I010Buffer::height() const {
    148  return height_;
    149 }
    150 
    151 const uint16_t* I010Buffer::DataY() const {
    152  return data_.get();
    153 }
    154 const uint16_t* I010Buffer::DataU() const {
    155  return data_.get() + stride_y_ * height_;
    156 }
    157 const uint16_t* I010Buffer::DataV() const {
    158  return data_.get() + stride_y_ * height_ + stride_u_ * ((height_ + 1) / 2);
    159 }
    160 
    161 int I010Buffer::StrideY() const {
    162  return stride_y_;
    163 }
    164 int I010Buffer::StrideU() const {
    165  return stride_u_;
    166 }
    167 int I010Buffer::StrideV() const {
    168  return stride_v_;
    169 }
    170 
    171 uint16_t* I010Buffer::MutableDataY() {
    172  return const_cast<uint16_t*>(DataY());
    173 }
    174 uint16_t* I010Buffer::MutableDataU() {
    175  return const_cast<uint16_t*>(DataU());
    176 }
    177 uint16_t* I010Buffer::MutableDataV() {
    178  return const_cast<uint16_t*>(DataV());
    179 }
    180 
    181 void I010Buffer::CropAndScaleFrom(const I010BufferInterface& src,
    182                                  int offset_x,
    183                                  int offset_y,
    184                                  int crop_width,
    185                                  int crop_height) {
    186  RTC_CHECK_LE(crop_width, src.width());
    187  RTC_CHECK_LE(crop_height, src.height());
    188  RTC_CHECK_LE(crop_width + offset_x, src.width());
    189  RTC_CHECK_LE(crop_height + offset_y, src.height());
    190  RTC_CHECK_GE(offset_x, 0);
    191  RTC_CHECK_GE(offset_y, 0);
    192 
    193  // Make sure offset is even so that u/v plane becomes aligned.
    194  const int uv_offset_x = offset_x / 2;
    195  const int uv_offset_y = offset_y / 2;
    196  offset_x = uv_offset_x * 2;
    197  offset_y = uv_offset_y * 2;
    198 
    199  const uint16_t* y_plane = src.DataY() + src.StrideY() * offset_y + offset_x;
    200  const uint16_t* u_plane =
    201      src.DataU() + src.StrideU() * uv_offset_y + uv_offset_x;
    202  const uint16_t* v_plane =
    203      src.DataV() + src.StrideV() * uv_offset_y + uv_offset_x;
    204  int res = libyuv::I420Scale_16(
    205      y_plane, src.StrideY(), u_plane, src.StrideU(), v_plane, src.StrideV(),
    206      crop_width, crop_height, MutableDataY(), StrideY(), MutableDataU(),
    207      StrideU(), MutableDataV(), StrideV(), width(), height(),
    208      libyuv::kFilterBox);
    209 
    210  RTC_DCHECK_EQ(res, 0);
    211 }
    212 
    213 void I010Buffer::ScaleFrom(const I010BufferInterface& src) {
    214  CropAndScaleFrom(src, 0, 0, src.width(), src.height());
    215 }
    216 
    217 }  // namespace webrtc