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 "test/mappable_native_buffer.h"
12
13 #include "absl/algorithm/container.h"
14 #include "api/video/i420_buffer.h"
15 #include "api/video/nv12_buffer.h"
16 #include "api/video/video_frame.h"
17 #include "api/video/video_rotation.h"
18 #include "common_video/include/video_frame_buffer.h"
19 #include "rtc_base/checks.h"
20
21 namespace webrtc {
22 namespace test {
23
24 namespace {
25
26 class NV12BufferWithDidConvertToI420 : public NV12Buffer {
27 public:
NV12BufferWithDidConvertToI420(int width,int height)28 NV12BufferWithDidConvertToI420(int width, int height)
29 : NV12Buffer(width, height), did_convert_to_i420_(false) {}
30
did_convert_to_i420() const31 bool did_convert_to_i420() const { return did_convert_to_i420_; }
32
ToI420()33 rtc::scoped_refptr<I420BufferInterface> ToI420() override {
34 did_convert_to_i420_ = true;
35 return NV12Buffer::ToI420();
36 }
37
38 private:
39 bool did_convert_to_i420_;
40 };
41
42 } // namespace
43
CreateMappableNativeFrame(int64_t ntp_time_ms,VideoFrameBuffer::Type mappable_type,int width,int height)44 VideoFrame CreateMappableNativeFrame(int64_t ntp_time_ms,
45 VideoFrameBuffer::Type mappable_type,
46 int width,
47 int height) {
48 VideoFrame frame =
49 VideoFrame::Builder()
50 .set_video_frame_buffer(rtc::make_ref_counted<MappableNativeBuffer>(
51 mappable_type, width, height))
52 .set_timestamp_rtp(99)
53 .set_timestamp_ms(99)
54 .set_rotation(kVideoRotation_0)
55 .build();
56 frame.set_ntp_time_ms(ntp_time_ms);
57 return frame;
58 }
59
GetMappableNativeBufferFromVideoFrame(const VideoFrame & frame)60 rtc::scoped_refptr<MappableNativeBuffer> GetMappableNativeBufferFromVideoFrame(
61 const VideoFrame& frame) {
62 return rtc::scoped_refptr<MappableNativeBuffer>(
63 static_cast<MappableNativeBuffer*>(frame.video_frame_buffer().get()));
64 }
65
ScaledBuffer(rtc::scoped_refptr<MappableNativeBuffer> parent,int width,int height)66 MappableNativeBuffer::ScaledBuffer::ScaledBuffer(
67 rtc::scoped_refptr<MappableNativeBuffer> parent,
68 int width,
69 int height)
70 : parent_(std::move(parent)), width_(width), height_(height) {}
71
~ScaledBuffer()72 MappableNativeBuffer::ScaledBuffer::~ScaledBuffer() {}
73
74 rtc::scoped_refptr<VideoFrameBuffer>
CropAndScale(int offset_x,int offset_y,int crop_width,int crop_height,int scaled_width,int scaled_height)75 MappableNativeBuffer::ScaledBuffer::CropAndScale(int offset_x,
76 int offset_y,
77 int crop_width,
78 int crop_height,
79 int scaled_width,
80 int scaled_height) {
81 return rtc::make_ref_counted<ScaledBuffer>(parent_, scaled_width,
82 scaled_height);
83 }
84
85 rtc::scoped_refptr<I420BufferInterface>
ToI420()86 MappableNativeBuffer::ScaledBuffer::ToI420() {
87 return parent_->GetOrCreateMappedBuffer(width_, height_)->ToI420();
88 }
89
90 rtc::scoped_refptr<VideoFrameBuffer>
GetMappedFrameBuffer(rtc::ArrayView<VideoFrameBuffer::Type> types)91 MappableNativeBuffer::ScaledBuffer::GetMappedFrameBuffer(
92 rtc::ArrayView<VideoFrameBuffer::Type> types) {
93 if (absl::c_find(types, parent_->mappable_type_) == types.end())
94 return nullptr;
95 return parent_->GetOrCreateMappedBuffer(width_, height_);
96 }
97
MappableNativeBuffer(VideoFrameBuffer::Type mappable_type,int width,int height)98 MappableNativeBuffer::MappableNativeBuffer(VideoFrameBuffer::Type mappable_type,
99 int width,
100 int height)
101 : mappable_type_(mappable_type), width_(width), height_(height) {
102 RTC_DCHECK(mappable_type_ == VideoFrameBuffer::Type::kI420 ||
103 mappable_type_ == VideoFrameBuffer::Type::kNV12);
104 }
105
~MappableNativeBuffer()106 MappableNativeBuffer::~MappableNativeBuffer() {}
107
CropAndScale(int offset_x,int offset_y,int crop_width,int crop_height,int scaled_width,int scaled_height)108 rtc::scoped_refptr<VideoFrameBuffer> MappableNativeBuffer::CropAndScale(
109 int offset_x,
110 int offset_y,
111 int crop_width,
112 int crop_height,
113 int scaled_width,
114 int scaled_height) {
115 return FullSizeBuffer()->CropAndScale(
116 offset_x, offset_y, crop_width, crop_height, scaled_width, scaled_height);
117 }
118
ToI420()119 rtc::scoped_refptr<I420BufferInterface> MappableNativeBuffer::ToI420() {
120 return FullSizeBuffer()->ToI420();
121 }
122
GetMappedFrameBuffer(rtc::ArrayView<VideoFrameBuffer::Type> types)123 rtc::scoped_refptr<VideoFrameBuffer> MappableNativeBuffer::GetMappedFrameBuffer(
124 rtc::ArrayView<VideoFrameBuffer::Type> types) {
125 return FullSizeBuffer()->GetMappedFrameBuffer(types);
126 }
127
128 std::vector<rtc::scoped_refptr<VideoFrameBuffer>>
GetMappedFramedBuffers() const129 MappableNativeBuffer::GetMappedFramedBuffers() const {
130 MutexLock lock(&lock_);
131 return mapped_buffers_;
132 }
133
DidConvertToI420() const134 bool MappableNativeBuffer::DidConvertToI420() const {
135 if (mappable_type_ != VideoFrameBuffer::Type::kNV12)
136 return false;
137 MutexLock lock(&lock_);
138 for (auto& mapped_buffer : mapped_buffers_) {
139 if (static_cast<NV12BufferWithDidConvertToI420*>(mapped_buffer.get())
140 ->did_convert_to_i420()) {
141 return true;
142 }
143 }
144 return false;
145 }
146
147 rtc::scoped_refptr<MappableNativeBuffer::ScaledBuffer>
FullSizeBuffer()148 MappableNativeBuffer::FullSizeBuffer() {
149 return rtc::make_ref_counted<ScaledBuffer>(
150 rtc::scoped_refptr<MappableNativeBuffer>(this), width_, height_);
151 }
152
153 rtc::scoped_refptr<VideoFrameBuffer>
GetOrCreateMappedBuffer(int width,int height)154 MappableNativeBuffer::GetOrCreateMappedBuffer(int width, int height) {
155 MutexLock lock(&lock_);
156 for (auto& mapped_buffer : mapped_buffers_) {
157 if (mapped_buffer->width() == width && mapped_buffer->height() == height) {
158 return mapped_buffer;
159 }
160 }
161 rtc::scoped_refptr<VideoFrameBuffer> mapped_buffer;
162 switch (mappable_type_) {
163 case VideoFrameBuffer::Type::kI420: {
164 rtc::scoped_refptr<I420Buffer> i420_buffer =
165 I420Buffer::Create(width, height);
166 I420Buffer::SetBlack(i420_buffer.get());
167 mapped_buffer = i420_buffer;
168 break;
169 }
170 case VideoFrameBuffer::Type::kNV12: {
171 auto nv12_buffer =
172 rtc::make_ref_counted<NV12BufferWithDidConvertToI420>(width, height);
173 nv12_buffer->InitializeData();
174 mapped_buffer = std::move(nv12_buffer);
175 break;
176 }
177 default:
178 RTC_DCHECK_NOTREACHED();
179 }
180 mapped_buffers_.push_back(mapped_buffer);
181 return mapped_buffer;
182 }
183
184 } // namespace test
185 } // namespace webrtc
186