tor-browser

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

nv12_buffer.cc (5219B)


      1 /*
      2 *  Copyright (c) 2020 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 "api/video/nv12_buffer.h"
     12 
     13 #include <cstddef>
     14 #include <cstdint>
     15 #include <cstring>
     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 "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/convert_from.h"
     26 #include "third_party/libyuv/include/libyuv/scale.h"
     27 
     28 namespace webrtc {
     29 
     30 namespace {
     31 
     32 const int kBufferAlignment = 64;
     33 
     34 int NV12DataSize(int width, int height, int stride_y, int stride_uv) {
     35  CheckValidDimensions(width, height, stride_y, stride_uv, stride_uv);
     36  int64_t h = height, y = stride_y, uv = stride_uv;
     37  return checked_cast<int>(y * h + uv * ((h + 1) / 2));
     38 }
     39 
     40 }  // namespace
     41 
     42 NV12Buffer::NV12Buffer(int width, int height)
     43    : NV12Buffer(width, height, width, width + width % 2) {}
     44 
     45 NV12Buffer::NV12Buffer(int width, int height, int stride_y, int stride_uv)
     46    : width_(width),
     47      height_(height),
     48      stride_y_(stride_y),
     49      stride_uv_(stride_uv),
     50      data_(static_cast<uint8_t*>(
     51          AlignedMalloc(NV12DataSize(width, height, stride_y, stride_uv),
     52                        kBufferAlignment))) {
     53  RTC_DCHECK_GE(stride_uv, width + width % 2);
     54 }
     55 
     56 NV12Buffer::~NV12Buffer() = default;
     57 
     58 // static
     59 scoped_refptr<NV12Buffer> NV12Buffer::Create(int width, int height) {
     60  return make_ref_counted<NV12Buffer>(width, height);
     61 }
     62 
     63 // static
     64 scoped_refptr<NV12Buffer> NV12Buffer::Create(int width,
     65                                             int height,
     66                                             int stride_y,
     67                                             int stride_uv) {
     68  return make_ref_counted<NV12Buffer>(width, height, stride_y, stride_uv);
     69 }
     70 
     71 // static
     72 scoped_refptr<NV12Buffer> NV12Buffer::Copy(
     73    const I420BufferInterface& i420_buffer) {
     74  scoped_refptr<NV12Buffer> buffer =
     75      NV12Buffer::Create(i420_buffer.width(), i420_buffer.height());
     76  libyuv::I420ToNV12(
     77      i420_buffer.DataY(), i420_buffer.StrideY(), i420_buffer.DataU(),
     78      i420_buffer.StrideU(), i420_buffer.DataV(), i420_buffer.StrideV(),
     79      buffer->MutableDataY(), buffer->StrideY(), buffer->MutableDataUV(),
     80      buffer->StrideUV(), buffer->width(), buffer->height());
     81  return buffer;
     82 }
     83 
     84 scoped_refptr<I420BufferInterface> NV12Buffer::ToI420() {
     85  scoped_refptr<I420Buffer> i420_buffer = I420Buffer::Create(width(), height());
     86  libyuv::NV12ToI420(DataY(), StrideY(), DataUV(), StrideUV(),
     87                     i420_buffer->MutableDataY(), i420_buffer->StrideY(),
     88                     i420_buffer->MutableDataU(), i420_buffer->StrideU(),
     89                     i420_buffer->MutableDataV(), i420_buffer->StrideV(),
     90                     width(), height());
     91  return i420_buffer;
     92 }
     93 
     94 int NV12Buffer::width() const {
     95  return width_;
     96 }
     97 int NV12Buffer::height() const {
     98  return height_;
     99 }
    100 
    101 int NV12Buffer::StrideY() const {
    102  return stride_y_;
    103 }
    104 int NV12Buffer::StrideUV() const {
    105  return stride_uv_;
    106 }
    107 
    108 const uint8_t* NV12Buffer::DataY() const {
    109  return data_.get();
    110 }
    111 
    112 const uint8_t* NV12Buffer::DataUV() const {
    113  return data_.get() + UVOffset();
    114 }
    115 
    116 uint8_t* NV12Buffer::MutableDataY() {
    117  return data_.get();
    118 }
    119 
    120 uint8_t* NV12Buffer::MutableDataUV() {
    121  return data_.get() + UVOffset();
    122 }
    123 
    124 size_t NV12Buffer::UVOffset() const {
    125  return stride_y_ * height_;
    126 }
    127 
    128 void NV12Buffer::InitializeData() {
    129  memset(data_.get(), 0, NV12DataSize(width_, height_, stride_y_, stride_uv_));
    130 }
    131 
    132 void NV12Buffer::CropAndScaleFrom(const NV12BufferInterface& src,
    133                                  int offset_x,
    134                                  int offset_y,
    135                                  int crop_width,
    136                                  int crop_height) {
    137  RTC_CHECK_LE(crop_width, src.width());
    138  RTC_CHECK_LE(crop_height, src.height());
    139  RTC_CHECK_LE(crop_width + offset_x, src.width());
    140  RTC_CHECK_LE(crop_height + offset_y, src.height());
    141  RTC_CHECK_GE(offset_x, 0);
    142  RTC_CHECK_GE(offset_y, 0);
    143 
    144  // Make sure offset is even so that u/v plane becomes aligned.
    145  const int uv_offset_x = offset_x / 2;
    146  const int uv_offset_y = offset_y / 2;
    147  offset_x = uv_offset_x * 2;
    148  offset_y = uv_offset_y * 2;
    149 
    150  const uint8_t* y_plane = src.DataY() + src.StrideY() * offset_y + offset_x;
    151  const uint8_t* uv_plane =
    152      src.DataUV() + src.StrideUV() * uv_offset_y + uv_offset_x * 2;
    153 
    154  int res = libyuv::NV12Scale(y_plane, src.StrideY(), uv_plane, src.StrideUV(),
    155                              crop_width, crop_height, MutableDataY(),
    156                              StrideY(), MutableDataUV(), StrideUV(), width(),
    157                              height(), libyuv::kFilterBox);
    158 
    159  RTC_DCHECK_EQ(res, 0);
    160 }
    161 
    162 }  // namespace webrtc