tor-browser

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

i410_buffer.cc (7650B)


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