tor-browser

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

i422_buffer.cc (8374B)


      1 /*
      2 *  Copyright (c) 2021 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/i422_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/convert_from.h"
     27 #include "third_party/libyuv/include/libyuv/planar_functions.h"
     28 #include "third_party/libyuv/include/libyuv/rotate.h"
     29 #include "third_party/libyuv/include/libyuv/scale.h"
     30 
     31 // Aligning pointer to 64 bytes for improved performance, e.g. use SIMD.
     32 static const int kBufferAlignment = 64;
     33 
     34 namespace webrtc {
     35 
     36 namespace {
     37 
     38 int I422DataSize(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>(y * h + u * h + v * h);
     46 }
     47 }  // namespace
     48 
     49 I422Buffer::I422Buffer(int width, int height)
     50    : I422Buffer(width, height, width, (width + 1) / 2, (width + 1) / 2) {}
     51 
     52 I422Buffer::I422Buffer(int width,
     53                       int height,
     54                       int stride_y,
     55                       int stride_u,
     56                       int stride_v)
     57    : width_(width),
     58      height_(height),
     59      stride_y_(stride_y),
     60      stride_u_(stride_u),
     61      stride_v_(stride_v),
     62      data_(static_cast<uint8_t*>(AlignedMalloc(
     63          I422DataSize(width, height, stride_y, stride_u, stride_v),
     64          kBufferAlignment))) {
     65  RTC_DCHECK_GE(stride_u, (width + 1) / 2);
     66  RTC_DCHECK_GE(stride_v, (width + 1) / 2);
     67 }
     68 
     69 I422Buffer::~I422Buffer() {}
     70 
     71 // static
     72 scoped_refptr<I422Buffer> I422Buffer::Create(int width, int height) {
     73  return make_ref_counted<I422Buffer>(width, height);
     74 }
     75 
     76 // static
     77 scoped_refptr<I422Buffer> I422Buffer::Create(int width,
     78                                             int height,
     79                                             int stride_y,
     80                                             int stride_u,
     81                                             int stride_v) {
     82  return make_ref_counted<I422Buffer>(width, height, stride_y, stride_u,
     83                                      stride_v);
     84 }
     85 
     86 // static
     87 scoped_refptr<I422Buffer> I422Buffer::Copy(const I422BufferInterface& source) {
     88  return Copy(source.width(), source.height(), source.DataY(), source.StrideY(),
     89              source.DataU(), source.StrideU(), source.DataV(),
     90              source.StrideV());
     91 }
     92 
     93 // static
     94 scoped_refptr<I422Buffer> I422Buffer::Copy(const I420BufferInterface& source) {
     95  const int width = source.width();
     96  const int height = source.height();
     97  scoped_refptr<I422Buffer> buffer = Create(width, height);
     98  int res = libyuv::I420ToI422(
     99      source.DataY(), source.StrideY(), source.DataU(), source.StrideU(),
    100      source.DataV(), source.StrideV(), buffer->MutableDataY(),
    101      buffer->StrideY(), buffer->MutableDataU(), buffer->StrideU(),
    102      buffer->MutableDataV(), buffer->StrideV(), width, height);
    103  RTC_DCHECK_EQ(res, 0);
    104 
    105  return buffer;
    106 }
    107 
    108 // static
    109 scoped_refptr<I422Buffer> I422Buffer::Copy(int width,
    110                                           int height,
    111                                           const uint8_t* data_y,
    112                                           int stride_y,
    113                                           const uint8_t* data_u,
    114                                           int stride_u,
    115                                           const uint8_t* data_v,
    116                                           int stride_v) {
    117  // Note: May use different strides than the input data.
    118  scoped_refptr<I422Buffer> buffer = Create(width, height);
    119  int res = libyuv::I422Copy(data_y, stride_y, data_u, stride_u, data_v,
    120                             stride_v, buffer->MutableDataY(),
    121                             buffer->StrideY(), buffer->MutableDataU(),
    122                             buffer->StrideU(), buffer->MutableDataV(),
    123                             buffer->StrideV(), width, height);
    124  RTC_DCHECK_EQ(res, 0);
    125 
    126  return buffer;
    127 }
    128 
    129 // static
    130 scoped_refptr<I422Buffer> I422Buffer::Rotate(const I422BufferInterface& src,
    131                                             VideoRotation rotation) {
    132  RTC_CHECK(src.DataY());
    133  RTC_CHECK(src.DataU());
    134  RTC_CHECK(src.DataV());
    135 
    136  int rotated_width = src.width();
    137  int rotated_height = src.height();
    138  if (rotation == kVideoRotation_90 || rotation == kVideoRotation_270) {
    139    std::swap(rotated_width, rotated_height);
    140  }
    141 
    142  scoped_refptr<I422Buffer> buffer =
    143      I422Buffer::Create(rotated_width, rotated_height);
    144 
    145  int res = libyuv::I422Rotate(
    146      src.DataY(), src.StrideY(), src.DataU(), src.StrideU(), src.DataV(),
    147      src.StrideV(), buffer->MutableDataY(), buffer->StrideY(),
    148      buffer->MutableDataU(), buffer->StrideU(), buffer->MutableDataV(),
    149      buffer->StrideV(), src.width(), src.height(),
    150      static_cast<libyuv::RotationMode>(rotation));
    151  RTC_DCHECK_EQ(res, 0);
    152 
    153  return buffer;
    154 }
    155 
    156 scoped_refptr<I420BufferInterface> I422Buffer::ToI420() {
    157  scoped_refptr<I420Buffer> i420_buffer = I420Buffer::Create(width(), height());
    158  int res = libyuv::I422ToI420(
    159      DataY(), StrideY(), DataU(), StrideU(), DataV(), StrideV(),
    160      i420_buffer->MutableDataY(), i420_buffer->StrideY(),
    161      i420_buffer->MutableDataU(), i420_buffer->StrideU(),
    162      i420_buffer->MutableDataV(), i420_buffer->StrideV(), width(), height());
    163  RTC_DCHECK_EQ(res, 0);
    164 
    165  return i420_buffer;
    166 }
    167 
    168 void I422Buffer::InitializeData() {
    169  memset(data_.get(), 0,
    170         I422DataSize(width_, height_, stride_y_, stride_u_, stride_v_));
    171 }
    172 
    173 int I422Buffer::width() const {
    174  return width_;
    175 }
    176 
    177 int I422Buffer::height() const {
    178  return height_;
    179 }
    180 
    181 const uint8_t* I422Buffer::DataY() const {
    182  return data_.get();
    183 }
    184 const uint8_t* I422Buffer::DataU() const {
    185  return data_.get() + stride_y_ * height_;
    186 }
    187 const uint8_t* I422Buffer::DataV() const {
    188  return data_.get() + stride_y_ * height_ + stride_u_ * height_;
    189 }
    190 
    191 int I422Buffer::StrideY() const {
    192  return stride_y_;
    193 }
    194 int I422Buffer::StrideU() const {
    195  return stride_u_;
    196 }
    197 int I422Buffer::StrideV() const {
    198  return stride_v_;
    199 }
    200 
    201 uint8_t* I422Buffer::MutableDataY() {
    202  return const_cast<uint8_t*>(DataY());
    203 }
    204 uint8_t* I422Buffer::MutableDataU() {
    205  return const_cast<uint8_t*>(DataU());
    206 }
    207 uint8_t* I422Buffer::MutableDataV() {
    208  return const_cast<uint8_t*>(DataV());
    209 }
    210 
    211 void I422Buffer::CropAndScaleFrom(const I422BufferInterface& src,
    212                                  int offset_x,
    213                                  int offset_y,
    214                                  int crop_width,
    215                                  int crop_height) {
    216  RTC_CHECK_LE(crop_width, src.width());
    217  RTC_CHECK_LE(crop_height, src.height());
    218  RTC_CHECK_LE(crop_width + offset_x, src.width());
    219  RTC_CHECK_LE(crop_height + offset_y, src.height());
    220  RTC_CHECK_GE(offset_x, 0);
    221  RTC_CHECK_GE(offset_y, 0);
    222 
    223  // Make sure offset is even so that u/v plane becomes aligned.
    224  const int uv_offset_x = offset_x / 2;
    225  const int uv_offset_y = offset_y;
    226  offset_x = uv_offset_x * 2;
    227 
    228  const uint8_t* y_plane = src.DataY() + src.StrideY() * offset_y + offset_x;
    229  const uint8_t* u_plane =
    230      src.DataU() + src.StrideU() * uv_offset_y + uv_offset_x;
    231  const uint8_t* v_plane =
    232      src.DataV() + src.StrideV() * uv_offset_y + uv_offset_x;
    233 
    234  int res =
    235      libyuv::I422Scale(y_plane, src.StrideY(), u_plane, src.StrideU(), v_plane,
    236                        src.StrideV(), crop_width, crop_height, MutableDataY(),
    237                        StrideY(), MutableDataU(), StrideU(), MutableDataV(),
    238                        StrideV(), width(), height(), libyuv::kFilterBox);
    239  RTC_DCHECK_EQ(res, 0);
    240 }
    241 
    242 }  // namespace webrtc