blob: 749e6811e1c68ac9292544105c53474e3a0ed0b6 [file] [log] [blame]
Ilya Nikolaevskiy4c87d832020-09-18 13:18:541/*
2 * Copyright (c) 2015 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 "common_video/include/video_frame_buffer_pool.h"
12
13#include <limits>
14
Niels Möller105711e2022-06-14 13:48:2615#include "api/make_ref_counted.h"
Ilya Nikolaevskiy4c87d832020-09-18 13:18:5416#include "rtc_base/checks.h"
17
18namespace webrtc {
19
20namespace {
21bool HasOneRef(const rtc::scoped_refptr<VideoFrameBuffer>& buffer) {
Harald Alvestrandc74412b2024-06-06 11:01:0222 // Cast to RefCountedObject is safe because this function is only called
Ilya Nikolaevskiy4c87d832020-09-18 13:18:5423 // on locally created VideoFrameBuffers, which are either
Harald Alvestrandc74412b2024-06-06 11:01:0224 // `RefCountedObject<I420Buffer>`, `RefCountedObject<I444Buffer>` or
25 // `RefCountedObject<NV12Buffer>`.
Ilya Nikolaevskiy4c87d832020-09-18 13:18:5426 switch (buffer->type()) {
27 case VideoFrameBuffer::Type::kI420: {
Harald Alvestrandc74412b2024-06-06 11:01:0228 return static_cast<RefCountedObject<I420Buffer>*>(buffer.get())
Ilya Nikolaevskiy4c87d832020-09-18 13:18:5429 ->HasOneRef();
30 }
Stefan Miticffdc6802022-02-08 15:00:1631 case VideoFrameBuffer::Type::kI444: {
Harald Alvestrandc74412b2024-06-06 11:01:0232 return static_cast<RefCountedObject<I444Buffer>*>(buffer.get())
Stefan Miticffdc6802022-02-08 15:00:1633 ->HasOneRef();
34 }
Sergio Garcia Murillob63536f2022-03-25 08:04:0935 case VideoFrameBuffer::Type::kI422: {
Harald Alvestrandc74412b2024-06-06 11:01:0236 return static_cast<RefCountedObject<I422Buffer>*>(buffer.get())
Sergio Garcia Murillob63536f2022-03-25 08:04:0937 ->HasOneRef();
38 }
Sergio Garcia Murillo8545eba2022-06-17 09:48:1439 case VideoFrameBuffer::Type::kI010: {
Harald Alvestrandc74412b2024-06-06 11:01:0240 return static_cast<RefCountedObject<I010Buffer>*>(buffer.get())
Sergio Garcia Murillo8545eba2022-06-17 09:48:1441 ->HasOneRef();
42 }
43 case VideoFrameBuffer::Type::kI210: {
Harald Alvestrandc74412b2024-06-06 11:01:0244 return static_cast<RefCountedObject<I210Buffer>*>(buffer.get())
Sergio Garcia Murillo8545eba2022-06-17 09:48:1445 ->HasOneRef();
46 }
Sergio Garcia Murillo1389c4b2023-01-09 17:29:3447 case VideoFrameBuffer::Type::kI410: {
Harald Alvestrandc74412b2024-06-06 11:01:0248 return static_cast<RefCountedObject<I410Buffer>*>(buffer.get())
Sergio Garcia Murillo1389c4b2023-01-09 17:29:3449 ->HasOneRef();
50 }
Ilya Nikolaevskiy4c87d832020-09-18 13:18:5451 case VideoFrameBuffer::Type::kNV12: {
Harald Alvestrandc74412b2024-06-06 11:01:0252 return static_cast<RefCountedObject<NV12Buffer>*>(buffer.get())
Ilya Nikolaevskiy4c87d832020-09-18 13:18:5453 ->HasOneRef();
54 }
55 default:
Artem Titovd3251962021-11-15 15:57:0756 RTC_DCHECK_NOTREACHED();
Ilya Nikolaevskiy4c87d832020-09-18 13:18:5457 }
58 return false;
59}
60
61} // namespace
62
63VideoFrameBufferPool::VideoFrameBufferPool() : VideoFrameBufferPool(false) {}
64
65VideoFrameBufferPool::VideoFrameBufferPool(bool zero_initialize)
66 : VideoFrameBufferPool(zero_initialize,
67 std::numeric_limits<size_t>::max()) {}
68
69VideoFrameBufferPool::VideoFrameBufferPool(bool zero_initialize,
70 size_t max_number_of_buffers)
71 : zero_initialize_(zero_initialize),
72 max_number_of_buffers_(max_number_of_buffers) {}
73
74VideoFrameBufferPool::~VideoFrameBufferPool() = default;
75
76void VideoFrameBufferPool::Release() {
77 buffers_.clear();
78}
79
80bool VideoFrameBufferPool::Resize(size_t max_number_of_buffers) {
81 RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
82 size_t used_buffers_count = 0;
83 for (const rtc::scoped_refptr<VideoFrameBuffer>& buffer : buffers_) {
84 // If the buffer is in use, the ref count will be >= 2, one from the list we
85 // are looping over and one from the application. If the ref count is 1,
86 // then the list we are looping over holds the only reference and it's safe
87 // to reuse.
88 if (!HasOneRef(buffer)) {
89 used_buffers_count++;
90 }
91 }
92 if (used_buffers_count > max_number_of_buffers) {
93 return false;
94 }
95 max_number_of_buffers_ = max_number_of_buffers;
96
97 size_t buffers_to_purge = buffers_.size() - max_number_of_buffers_;
98 auto iter = buffers_.begin();
99 while (iter != buffers_.end() && buffers_to_purge > 0) {
100 if (HasOneRef(*iter)) {
101 iter = buffers_.erase(iter);
102 buffers_to_purge--;
103 } else {
104 ++iter;
105 }
106 }
107 return true;
108}
109
110rtc::scoped_refptr<I420Buffer> VideoFrameBufferPool::CreateI420Buffer(
111 int width,
112 int height) {
113 RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
114
115 rtc::scoped_refptr<VideoFrameBuffer> existing_buffer =
116 GetExistingBuffer(width, height, VideoFrameBuffer::Type::kI420);
117 if (existing_buffer) {
118 // Cast is safe because the only way kI420 buffer is created is
Artem Titovcfea2182021-08-09 23:22:31119 // in the same function below, where `RefCountedObject<I420Buffer>` is
Ilya Nikolaevskiy4c87d832020-09-18 13:18:54120 // created.
Harald Alvestrandc74412b2024-06-06 11:01:02121 RefCountedObject<I420Buffer>* raw_buffer =
122 static_cast<RefCountedObject<I420Buffer>*>(existing_buffer.get());
Ilya Nikolaevskiy4c87d832020-09-18 13:18:54123 // Creates a new scoped_refptr, which is also pointing to the same
124 // RefCountedObject as buffer, increasing ref count.
125 return rtc::scoped_refptr<I420Buffer>(raw_buffer);
126 }
127
128 if (buffers_.size() >= max_number_of_buffers_)
129 return nullptr;
130 // Allocate new buffer.
131 rtc::scoped_refptr<I420Buffer> buffer =
Tomas Gunnarssonc1d58912021-04-22 17:21:43132 rtc::make_ref_counted<I420Buffer>(width, height);
Ilya Nikolaevskiy4c87d832020-09-18 13:18:54133
134 if (zero_initialize_)
135 buffer->InitializeData();
136
137 buffers_.push_back(buffer);
138 return buffer;
139}
140
Stefan Miticffdc6802022-02-08 15:00:16141rtc::scoped_refptr<I444Buffer> VideoFrameBufferPool::CreateI444Buffer(
142 int width,
143 int height) {
144 RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
145
146 rtc::scoped_refptr<VideoFrameBuffer> existing_buffer =
147 GetExistingBuffer(width, height, VideoFrameBuffer::Type::kI444);
148 if (existing_buffer) {
149 // Cast is safe because the only way kI444 buffer is created is
150 // in the same function below, where |RefCountedObject<I444Buffer>|
151 // is created.
Harald Alvestrandc74412b2024-06-06 11:01:02152 RefCountedObject<I444Buffer>* raw_buffer =
153 static_cast<RefCountedObject<I444Buffer>*>(existing_buffer.get());
Stefan Miticffdc6802022-02-08 15:00:16154 // Creates a new scoped_refptr, which is also pointing to the same
155 // RefCountedObject as buffer, increasing ref count.
156 return rtc::scoped_refptr<I444Buffer>(raw_buffer);
157 }
158
159 if (buffers_.size() >= max_number_of_buffers_)
160 return nullptr;
161 // Allocate new buffer.
162 rtc::scoped_refptr<I444Buffer> buffer =
163 rtc::make_ref_counted<I444Buffer>(width, height);
164
165 if (zero_initialize_)
166 buffer->InitializeData();
167
168 buffers_.push_back(buffer);
169 return buffer;
170}
171
Sergio Garcia Murillob63536f2022-03-25 08:04:09172rtc::scoped_refptr<I422Buffer> VideoFrameBufferPool::CreateI422Buffer(
173 int width,
174 int height) {
175 RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
176
177 rtc::scoped_refptr<VideoFrameBuffer> existing_buffer =
178 GetExistingBuffer(width, height, VideoFrameBuffer::Type::kI422);
179 if (existing_buffer) {
180 // Cast is safe because the only way kI422 buffer is created is
181 // in the same function below, where |RefCountedObject<I422Buffer>|
182 // is created.
Harald Alvestrandc74412b2024-06-06 11:01:02183 RefCountedObject<I422Buffer>* raw_buffer =
184 static_cast<RefCountedObject<I422Buffer>*>(existing_buffer.get());
Sergio Garcia Murillob63536f2022-03-25 08:04:09185 // Creates a new scoped_refptr, which is also pointing to the same
186 // RefCountedObject as buffer, increasing ref count.
187 return rtc::scoped_refptr<I422Buffer>(raw_buffer);
188 }
189
190 if (buffers_.size() >= max_number_of_buffers_)
191 return nullptr;
192 // Allocate new buffer.
193 rtc::scoped_refptr<I422Buffer> buffer =
194 rtc::make_ref_counted<I422Buffer>(width, height);
195
196 if (zero_initialize_)
197 buffer->InitializeData();
198
199 buffers_.push_back(buffer);
200 return buffer;
201}
202
Ilya Nikolaevskiy4c87d832020-09-18 13:18:54203rtc::scoped_refptr<NV12Buffer> VideoFrameBufferPool::CreateNV12Buffer(
204 int width,
205 int height) {
206 RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
207
208 rtc::scoped_refptr<VideoFrameBuffer> existing_buffer =
209 GetExistingBuffer(width, height, VideoFrameBuffer::Type::kNV12);
210 if (existing_buffer) {
211 // Cast is safe because the only way kI420 buffer is created is
Artem Titovcfea2182021-08-09 23:22:31212 // in the same function below, where `RefCountedObject<I420Buffer>` is
Ilya Nikolaevskiy4c87d832020-09-18 13:18:54213 // created.
Harald Alvestrandc74412b2024-06-06 11:01:02214 RefCountedObject<NV12Buffer>* raw_buffer =
215 static_cast<RefCountedObject<NV12Buffer>*>(existing_buffer.get());
Ilya Nikolaevskiy4c87d832020-09-18 13:18:54216 // Creates a new scoped_refptr, which is also pointing to the same
217 // RefCountedObject as buffer, increasing ref count.
218 return rtc::scoped_refptr<NV12Buffer>(raw_buffer);
219 }
220
221 if (buffers_.size() >= max_number_of_buffers_)
222 return nullptr;
223 // Allocate new buffer.
224 rtc::scoped_refptr<NV12Buffer> buffer =
Tomas Gunnarssonc1d58912021-04-22 17:21:43225 rtc::make_ref_counted<NV12Buffer>(width, height);
Ilya Nikolaevskiy4c87d832020-09-18 13:18:54226
227 if (zero_initialize_)
228 buffer->InitializeData();
229
230 buffers_.push_back(buffer);
231 return buffer;
232}
233
Sergio Garcia Murillo8545eba2022-06-17 09:48:14234rtc::scoped_refptr<I010Buffer> VideoFrameBufferPool::CreateI010Buffer(
235 int width,
236 int height) {
237 RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
238
239 rtc::scoped_refptr<VideoFrameBuffer> existing_buffer =
240 GetExistingBuffer(width, height, VideoFrameBuffer::Type::kI010);
241 if (existing_buffer) {
242 // Cast is safe because the only way kI010 buffer is created is
243 // in the same function below, where |RefCountedObject<I010Buffer>|
244 // is created.
Harald Alvestrandc74412b2024-06-06 11:01:02245 RefCountedObject<I010Buffer>* raw_buffer =
246 static_cast<RefCountedObject<I010Buffer>*>(existing_buffer.get());
Sergio Garcia Murillo8545eba2022-06-17 09:48:14247 // Creates a new scoped_refptr, which is also pointing to the same
248 // RefCountedObject as buffer, increasing ref count.
249 return rtc::scoped_refptr<I010Buffer>(raw_buffer);
250 }
251
252 if (buffers_.size() >= max_number_of_buffers_)
253 return nullptr;
254 // Allocate new buffer.
255 rtc::scoped_refptr<I010Buffer> buffer = I010Buffer::Create(width, height);
256
257 buffers_.push_back(buffer);
258 return buffer;
259}
260
261rtc::scoped_refptr<I210Buffer> VideoFrameBufferPool::CreateI210Buffer(
262 int width,
263 int height) {
264 RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
265
266 rtc::scoped_refptr<VideoFrameBuffer> existing_buffer =
267 GetExistingBuffer(width, height, VideoFrameBuffer::Type::kI210);
268 if (existing_buffer) {
269 // Cast is safe because the only way kI210 buffer is created is
270 // in the same function below, where |RefCountedObject<I210Buffer>|
271 // is created.
Harald Alvestrandc74412b2024-06-06 11:01:02272 RefCountedObject<I210Buffer>* raw_buffer =
273 static_cast<RefCountedObject<I210Buffer>*>(existing_buffer.get());
Sergio Garcia Murillo8545eba2022-06-17 09:48:14274 // Creates a new scoped_refptr, which is also pointing to the same
275 // RefCountedObject as buffer, increasing ref count.
276 return rtc::scoped_refptr<I210Buffer>(raw_buffer);
277 }
278
279 if (buffers_.size() >= max_number_of_buffers_)
280 return nullptr;
281 // Allocate new buffer.
282 rtc::scoped_refptr<I210Buffer> buffer = I210Buffer::Create(width, height);
283
284 buffers_.push_back(buffer);
285 return buffer;
286}
287
Sergio Garcia Murillo1389c4b2023-01-09 17:29:34288rtc::scoped_refptr<I410Buffer> VideoFrameBufferPool::CreateI410Buffer(
289 int width,
290 int height) {
291 RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
292
293 rtc::scoped_refptr<VideoFrameBuffer> existing_buffer =
294 GetExistingBuffer(width, height, VideoFrameBuffer::Type::kI410);
295 if (existing_buffer) {
296 // Cast is safe because the only way kI410 buffer is created is
297 // in the same function below, where |RefCountedObject<I410Buffer>|
298 // is created.
Harald Alvestrandc74412b2024-06-06 11:01:02299 RefCountedObject<I410Buffer>* raw_buffer =
300 static_cast<RefCountedObject<I410Buffer>*>(existing_buffer.get());
Sergio Garcia Murillo1389c4b2023-01-09 17:29:34301 // Creates a new scoped_refptr, which is also pointing to the same
302 // RefCountedObject as buffer, increasing ref count.
303 return rtc::scoped_refptr<I410Buffer>(raw_buffer);
304 }
305
306 if (buffers_.size() >= max_number_of_buffers_)
307 return nullptr;
308 // Allocate new buffer.
309 rtc::scoped_refptr<I410Buffer> buffer = I410Buffer::Create(width, height);
310
311 buffers_.push_back(buffer);
312 return buffer;
313}
314
Ilya Nikolaevskiy4c87d832020-09-18 13:18:54315rtc::scoped_refptr<VideoFrameBuffer> VideoFrameBufferPool::GetExistingBuffer(
316 int width,
317 int height,
318 VideoFrameBuffer::Type type) {
319 // Release buffers with wrong resolution or different type.
320 for (auto it = buffers_.begin(); it != buffers_.end();) {
321 const auto& buffer = *it;
322 if (buffer->width() != width || buffer->height() != height ||
323 buffer->type() != type) {
324 it = buffers_.erase(it);
325 } else {
326 ++it;
327 }
328 }
329 // Look for a free buffer.
330 for (const rtc::scoped_refptr<VideoFrameBuffer>& buffer : buffers_) {
331 // If the buffer is in use, the ref count will be >= 2, one from the list we
332 // are looping over and one from the application. If the ref count is 1,
333 // then the list we are looping over holds the only reference and it's safe
334 // to reuse.
335 if (HasOneRef(buffer)) {
336 RTC_CHECK(buffer->type() == type);
337 return buffer;
338 }
339 }
340 return nullptr;
341}
342
343} // namespace webrtc