xref: /aosp_15_r20/external/webrtc/api/video/nv12_buffer.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker  *  Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
3*d9f75844SAndroid Build Coastguard Worker  *
4*d9f75844SAndroid Build Coastguard Worker  *  Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker  *  that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker  *  tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker  *  in the file PATENTS.  All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker  *  be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker  */
10*d9f75844SAndroid Build Coastguard Worker 
11*d9f75844SAndroid Build Coastguard Worker #include "api/video/nv12_buffer.h"
12*d9f75844SAndroid Build Coastguard Worker 
13*d9f75844SAndroid Build Coastguard Worker #include "api/make_ref_counted.h"
14*d9f75844SAndroid Build Coastguard Worker #include "api/video/i420_buffer.h"
15*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/checks.h"
16*d9f75844SAndroid Build Coastguard Worker #include "third_party/libyuv/include/libyuv/convert.h"
17*d9f75844SAndroid Build Coastguard Worker #include "third_party/libyuv/include/libyuv/scale.h"
18*d9f75844SAndroid Build Coastguard Worker 
19*d9f75844SAndroid Build Coastguard Worker namespace webrtc {
20*d9f75844SAndroid Build Coastguard Worker 
21*d9f75844SAndroid Build Coastguard Worker namespace {
22*d9f75844SAndroid Build Coastguard Worker 
23*d9f75844SAndroid Build Coastguard Worker static const int kBufferAlignment = 64;
24*d9f75844SAndroid Build Coastguard Worker 
NV12DataSize(int height,int stride_y,int stride_uv)25*d9f75844SAndroid Build Coastguard Worker int NV12DataSize(int height, int stride_y, int stride_uv) {
26*d9f75844SAndroid Build Coastguard Worker   return stride_y * height + stride_uv * ((height + 1) / 2);
27*d9f75844SAndroid Build Coastguard Worker }
28*d9f75844SAndroid Build Coastguard Worker 
29*d9f75844SAndroid Build Coastguard Worker }  // namespace
30*d9f75844SAndroid Build Coastguard Worker 
NV12Buffer(int width,int height)31*d9f75844SAndroid Build Coastguard Worker NV12Buffer::NV12Buffer(int width, int height)
32*d9f75844SAndroid Build Coastguard Worker     : NV12Buffer(width, height, width, width + width % 2) {}
33*d9f75844SAndroid Build Coastguard Worker 
NV12Buffer(int width,int height,int stride_y,int stride_uv)34*d9f75844SAndroid Build Coastguard Worker NV12Buffer::NV12Buffer(int width, int height, int stride_y, int stride_uv)
35*d9f75844SAndroid Build Coastguard Worker     : width_(width),
36*d9f75844SAndroid Build Coastguard Worker       height_(height),
37*d9f75844SAndroid Build Coastguard Worker       stride_y_(stride_y),
38*d9f75844SAndroid Build Coastguard Worker       stride_uv_(stride_uv),
39*d9f75844SAndroid Build Coastguard Worker       data_(static_cast<uint8_t*>(
40*d9f75844SAndroid Build Coastguard Worker           AlignedMalloc(NV12DataSize(height_, stride_y_, stride_uv),
41*d9f75844SAndroid Build Coastguard Worker                         kBufferAlignment))) {
42*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_GT(width, 0);
43*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_GT(height, 0);
44*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_GE(stride_y, width);
45*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_GE(stride_uv, (width + width % 2));
46*d9f75844SAndroid Build Coastguard Worker }
47*d9f75844SAndroid Build Coastguard Worker 
48*d9f75844SAndroid Build Coastguard Worker NV12Buffer::~NV12Buffer() = default;
49*d9f75844SAndroid Build Coastguard Worker 
50*d9f75844SAndroid Build Coastguard Worker // static
Create(int width,int height)51*d9f75844SAndroid Build Coastguard Worker rtc::scoped_refptr<NV12Buffer> NV12Buffer::Create(int width, int height) {
52*d9f75844SAndroid Build Coastguard Worker   return rtc::make_ref_counted<NV12Buffer>(width, height);
53*d9f75844SAndroid Build Coastguard Worker }
54*d9f75844SAndroid Build Coastguard Worker 
55*d9f75844SAndroid Build Coastguard Worker // static
Create(int width,int height,int stride_y,int stride_uv)56*d9f75844SAndroid Build Coastguard Worker rtc::scoped_refptr<NV12Buffer> NV12Buffer::Create(int width,
57*d9f75844SAndroid Build Coastguard Worker                                                   int height,
58*d9f75844SAndroid Build Coastguard Worker                                                   int stride_y,
59*d9f75844SAndroid Build Coastguard Worker                                                   int stride_uv) {
60*d9f75844SAndroid Build Coastguard Worker   return rtc::make_ref_counted<NV12Buffer>(width, height, stride_y, stride_uv);
61*d9f75844SAndroid Build Coastguard Worker }
62*d9f75844SAndroid Build Coastguard Worker 
63*d9f75844SAndroid Build Coastguard Worker // static
Copy(const I420BufferInterface & i420_buffer)64*d9f75844SAndroid Build Coastguard Worker rtc::scoped_refptr<NV12Buffer> NV12Buffer::Copy(
65*d9f75844SAndroid Build Coastguard Worker     const I420BufferInterface& i420_buffer) {
66*d9f75844SAndroid Build Coastguard Worker   rtc::scoped_refptr<NV12Buffer> buffer =
67*d9f75844SAndroid Build Coastguard Worker       NV12Buffer::Create(i420_buffer.width(), i420_buffer.height());
68*d9f75844SAndroid Build Coastguard Worker   libyuv::I420ToNV12(
69*d9f75844SAndroid Build Coastguard Worker       i420_buffer.DataY(), i420_buffer.StrideY(), i420_buffer.DataU(),
70*d9f75844SAndroid Build Coastguard Worker       i420_buffer.StrideU(), i420_buffer.DataV(), i420_buffer.StrideV(),
71*d9f75844SAndroid Build Coastguard Worker       buffer->MutableDataY(), buffer->StrideY(), buffer->MutableDataUV(),
72*d9f75844SAndroid Build Coastguard Worker       buffer->StrideUV(), buffer->width(), buffer->height());
73*d9f75844SAndroid Build Coastguard Worker   return buffer;
74*d9f75844SAndroid Build Coastguard Worker }
75*d9f75844SAndroid Build Coastguard Worker 
ToI420()76*d9f75844SAndroid Build Coastguard Worker rtc::scoped_refptr<I420BufferInterface> NV12Buffer::ToI420() {
77*d9f75844SAndroid Build Coastguard Worker   rtc::scoped_refptr<I420Buffer> i420_buffer =
78*d9f75844SAndroid Build Coastguard Worker       I420Buffer::Create(width(), height());
79*d9f75844SAndroid Build Coastguard Worker   libyuv::NV12ToI420(DataY(), StrideY(), DataUV(), StrideUV(),
80*d9f75844SAndroid Build Coastguard Worker                      i420_buffer->MutableDataY(), i420_buffer->StrideY(),
81*d9f75844SAndroid Build Coastguard Worker                      i420_buffer->MutableDataU(), i420_buffer->StrideU(),
82*d9f75844SAndroid Build Coastguard Worker                      i420_buffer->MutableDataV(), i420_buffer->StrideV(),
83*d9f75844SAndroid Build Coastguard Worker                      width(), height());
84*d9f75844SAndroid Build Coastguard Worker   return i420_buffer;
85*d9f75844SAndroid Build Coastguard Worker }
86*d9f75844SAndroid Build Coastguard Worker 
width() const87*d9f75844SAndroid Build Coastguard Worker int NV12Buffer::width() const {
88*d9f75844SAndroid Build Coastguard Worker   return width_;
89*d9f75844SAndroid Build Coastguard Worker }
height() const90*d9f75844SAndroid Build Coastguard Worker int NV12Buffer::height() const {
91*d9f75844SAndroid Build Coastguard Worker   return height_;
92*d9f75844SAndroid Build Coastguard Worker }
93*d9f75844SAndroid Build Coastguard Worker 
StrideY() const94*d9f75844SAndroid Build Coastguard Worker int NV12Buffer::StrideY() const {
95*d9f75844SAndroid Build Coastguard Worker   return stride_y_;
96*d9f75844SAndroid Build Coastguard Worker }
StrideUV() const97*d9f75844SAndroid Build Coastguard Worker int NV12Buffer::StrideUV() const {
98*d9f75844SAndroid Build Coastguard Worker   return stride_uv_;
99*d9f75844SAndroid Build Coastguard Worker }
100*d9f75844SAndroid Build Coastguard Worker 
DataY() const101*d9f75844SAndroid Build Coastguard Worker const uint8_t* NV12Buffer::DataY() const {
102*d9f75844SAndroid Build Coastguard Worker   return data_.get();
103*d9f75844SAndroid Build Coastguard Worker }
104*d9f75844SAndroid Build Coastguard Worker 
DataUV() const105*d9f75844SAndroid Build Coastguard Worker const uint8_t* NV12Buffer::DataUV() const {
106*d9f75844SAndroid Build Coastguard Worker   return data_.get() + UVOffset();
107*d9f75844SAndroid Build Coastguard Worker }
108*d9f75844SAndroid Build Coastguard Worker 
MutableDataY()109*d9f75844SAndroid Build Coastguard Worker uint8_t* NV12Buffer::MutableDataY() {
110*d9f75844SAndroid Build Coastguard Worker   return data_.get();
111*d9f75844SAndroid Build Coastguard Worker }
112*d9f75844SAndroid Build Coastguard Worker 
MutableDataUV()113*d9f75844SAndroid Build Coastguard Worker uint8_t* NV12Buffer::MutableDataUV() {
114*d9f75844SAndroid Build Coastguard Worker   return data_.get() + UVOffset();
115*d9f75844SAndroid Build Coastguard Worker }
116*d9f75844SAndroid Build Coastguard Worker 
UVOffset() const117*d9f75844SAndroid Build Coastguard Worker size_t NV12Buffer::UVOffset() const {
118*d9f75844SAndroid Build Coastguard Worker   return stride_y_ * height_;
119*d9f75844SAndroid Build Coastguard Worker }
120*d9f75844SAndroid Build Coastguard Worker 
InitializeData()121*d9f75844SAndroid Build Coastguard Worker void NV12Buffer::InitializeData() {
122*d9f75844SAndroid Build Coastguard Worker   memset(data_.get(), 0, NV12DataSize(height_, stride_y_, stride_uv_));
123*d9f75844SAndroid Build Coastguard Worker }
124*d9f75844SAndroid Build Coastguard Worker 
CropAndScaleFrom(const NV12BufferInterface & src,int offset_x,int offset_y,int crop_width,int crop_height)125*d9f75844SAndroid Build Coastguard Worker void NV12Buffer::CropAndScaleFrom(const NV12BufferInterface& src,
126*d9f75844SAndroid Build Coastguard Worker                                   int offset_x,
127*d9f75844SAndroid Build Coastguard Worker                                   int offset_y,
128*d9f75844SAndroid Build Coastguard Worker                                   int crop_width,
129*d9f75844SAndroid Build Coastguard Worker                                   int crop_height) {
130*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK_LE(crop_width, src.width());
131*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK_LE(crop_height, src.height());
132*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK_LE(crop_width + offset_x, src.width());
133*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK_LE(crop_height + offset_y, src.height());
134*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK_GE(offset_x, 0);
135*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK_GE(offset_y, 0);
136*d9f75844SAndroid Build Coastguard Worker 
137*d9f75844SAndroid Build Coastguard Worker   // Make sure offset is even so that u/v plane becomes aligned.
138*d9f75844SAndroid Build Coastguard Worker   const int uv_offset_x = offset_x / 2;
139*d9f75844SAndroid Build Coastguard Worker   const int uv_offset_y = offset_y / 2;
140*d9f75844SAndroid Build Coastguard Worker   offset_x = uv_offset_x * 2;
141*d9f75844SAndroid Build Coastguard Worker   offset_y = uv_offset_y * 2;
142*d9f75844SAndroid Build Coastguard Worker 
143*d9f75844SAndroid Build Coastguard Worker   const uint8_t* y_plane = src.DataY() + src.StrideY() * offset_y + offset_x;
144*d9f75844SAndroid Build Coastguard Worker   const uint8_t* uv_plane =
145*d9f75844SAndroid Build Coastguard Worker       src.DataUV() + src.StrideUV() * uv_offset_y + uv_offset_x * 2;
146*d9f75844SAndroid Build Coastguard Worker 
147*d9f75844SAndroid Build Coastguard Worker   int res = libyuv::NV12Scale(y_plane, src.StrideY(), uv_plane, src.StrideUV(),
148*d9f75844SAndroid Build Coastguard Worker                               crop_width, crop_height, MutableDataY(),
149*d9f75844SAndroid Build Coastguard Worker                               StrideY(), MutableDataUV(), StrideUV(), width(),
150*d9f75844SAndroid Build Coastguard Worker                               height(), libyuv::kFilterBox);
151*d9f75844SAndroid Build Coastguard Worker 
152*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_EQ(res, 0);
153*d9f75844SAndroid Build Coastguard Worker }
154*d9f75844SAndroid Build Coastguard Worker 
155*d9f75844SAndroid Build Coastguard Worker }  // namespace webrtc
156