tor-browser

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

i210_buffer.cc (7562B)


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