blob: cff58ff8e7c703ef0f847efde7a89e40f48f502b [file] [log] [blame]
Henrik Boströmbd9e4a92021-03-22 12:24:30 +01001/*
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
21namespace webrtc {
22namespace test {
23
24namespace {
25
26class NV12BufferWithDidConvertToI420 : public NV12Buffer {
27 public:
28 NV12BufferWithDidConvertToI420(int width, int height)
29 : NV12Buffer(width, height), did_convert_to_i420_(false) {}
30
31 bool did_convert_to_i420() const { return did_convert_to_i420_; }
32
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
44VideoFrame CreateMappableNativeFrame(int64_t ntp_time_ms,
45 VideoFrameBuffer::Type mappable_type,
46 int width,
47 int height) {
48 VideoFrame frame = VideoFrame::Builder()
49 .set_video_frame_buffer(
50 new rtc::RefCountedObject<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
60rtc::scoped_refptr<MappableNativeBuffer> GetMappableNativeBufferFromVideoFrame(
61 const VideoFrame& frame) {
62 return static_cast<MappableNativeBuffer*>(frame.video_frame_buffer().get());
63}
64
65MappableNativeBuffer::ScaledBuffer::ScaledBuffer(
66 rtc::scoped_refptr<MappableNativeBuffer> parent,
67 int width,
68 int height)
69 : parent_(std::move(parent)), width_(width), height_(height) {}
70
71MappableNativeBuffer::ScaledBuffer::~ScaledBuffer() {}
72
73rtc::scoped_refptr<VideoFrameBuffer>
74MappableNativeBuffer::ScaledBuffer::CropAndScale(int offset_x,
75 int offset_y,
76 int crop_width,
77 int crop_height,
78 int scaled_width,
79 int scaled_height) {
80 return rtc::scoped_refptr<VideoFrameBuffer>(
81 new rtc::RefCountedObject<ScaledBuffer>(parent_, scaled_width,
82 scaled_height));
83}
84
85rtc::scoped_refptr<I420BufferInterface>
86MappableNativeBuffer::ScaledBuffer::ToI420() {
87 return parent_->GetOrCreateMappedBuffer(width_, height_)->ToI420();
88}
89
90rtc::scoped_refptr<VideoFrameBuffer>
91MappableNativeBuffer::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
98MappableNativeBuffer::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
106MappableNativeBuffer::~MappableNativeBuffer() {}
107
108rtc::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
119rtc::scoped_refptr<I420BufferInterface> MappableNativeBuffer::ToI420() {
120 return FullSizeBuffer()->ToI420();
121}
122
123rtc::scoped_refptr<VideoFrameBuffer> MappableNativeBuffer::GetMappedFrameBuffer(
124 rtc::ArrayView<VideoFrameBuffer::Type> types) {
125 return FullSizeBuffer()->GetMappedFrameBuffer(types);
126}
127
128std::vector<rtc::scoped_refptr<VideoFrameBuffer>>
129MappableNativeBuffer::GetMappedFramedBuffers() const {
130 MutexLock lock(&lock_);
131 return mapped_buffers_;
132}
133
134bool 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
147rtc::scoped_refptr<MappableNativeBuffer::ScaledBuffer>
148MappableNativeBuffer::FullSizeBuffer() {
149 return rtc::scoped_refptr<MappableNativeBuffer::ScaledBuffer>(
150 new rtc::RefCountedObject<ScaledBuffer>(this, width_, height_));
151}
152
153rtc::scoped_refptr<VideoFrameBuffer>
154MappableNativeBuffer::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);
167 mapped_buffer = i420_buffer;
168 break;
169 }
170 case VideoFrameBuffer::Type::kNV12: {
171 rtc::scoped_refptr<NV12Buffer> nv12_buffer;
172 nv12_buffer = new rtc::RefCountedObject<NV12BufferWithDidConvertToI420>(
173 width, height);
174 nv12_buffer->InitializeData();
175 mapped_buffer = nv12_buffer;
176 break;
177 }
178 default:
179 RTC_NOTREACHED();
180 }
181 mapped_buffers_.push_back(mapped_buffer);
182 return mapped_buffer;
183}
184
185} // namespace test
186} // namespace webrtc