xref: /aosp_15_r20/external/webrtc/common_video/video_frame_buffer_pool.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1 /*
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 
15 #include "api/make_ref_counted.h"
16 #include "rtc_base/checks.h"
17 
18 namespace webrtc {
19 
20 namespace {
HasOneRef(const rtc::scoped_refptr<VideoFrameBuffer> & buffer)21 bool HasOneRef(const rtc::scoped_refptr<VideoFrameBuffer>& buffer) {
22   // Cast to rtc::RefCountedObject is safe because this function is only called
23   // on locally created VideoFrameBuffers, which are either
24   // `rtc::RefCountedObject<I420Buffer>`, `rtc::RefCountedObject<I444Buffer>` or
25   // `rtc::RefCountedObject<NV12Buffer>`.
26   switch (buffer->type()) {
27     case VideoFrameBuffer::Type::kI420: {
28       return static_cast<rtc::RefCountedObject<I420Buffer>*>(buffer.get())
29           ->HasOneRef();
30     }
31     case VideoFrameBuffer::Type::kI444: {
32       return static_cast<rtc::RefCountedObject<I444Buffer>*>(buffer.get())
33           ->HasOneRef();
34     }
35     case VideoFrameBuffer::Type::kI422: {
36       return static_cast<rtc::RefCountedObject<I422Buffer>*>(buffer.get())
37           ->HasOneRef();
38     }
39     case VideoFrameBuffer::Type::kI010: {
40       return static_cast<rtc::RefCountedObject<I010Buffer>*>(buffer.get())
41           ->HasOneRef();
42     }
43     case VideoFrameBuffer::Type::kI210: {
44       return static_cast<rtc::RefCountedObject<I210Buffer>*>(buffer.get())
45           ->HasOneRef();
46     }
47     case VideoFrameBuffer::Type::kNV12: {
48       return static_cast<rtc::RefCountedObject<NV12Buffer>*>(buffer.get())
49           ->HasOneRef();
50     }
51     default:
52       RTC_DCHECK_NOTREACHED();
53   }
54   return false;
55 }
56 
57 }  // namespace
58 
VideoFrameBufferPool()59 VideoFrameBufferPool::VideoFrameBufferPool() : VideoFrameBufferPool(false) {}
60 
VideoFrameBufferPool(bool zero_initialize)61 VideoFrameBufferPool::VideoFrameBufferPool(bool zero_initialize)
62     : VideoFrameBufferPool(zero_initialize,
63                            std::numeric_limits<size_t>::max()) {}
64 
VideoFrameBufferPool(bool zero_initialize,size_t max_number_of_buffers)65 VideoFrameBufferPool::VideoFrameBufferPool(bool zero_initialize,
66                                            size_t max_number_of_buffers)
67     : zero_initialize_(zero_initialize),
68       max_number_of_buffers_(max_number_of_buffers) {}
69 
70 VideoFrameBufferPool::~VideoFrameBufferPool() = default;
71 
Release()72 void VideoFrameBufferPool::Release() {
73   buffers_.clear();
74 }
75 
Resize(size_t max_number_of_buffers)76 bool VideoFrameBufferPool::Resize(size_t max_number_of_buffers) {
77   RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
78   size_t used_buffers_count = 0;
79   for (const rtc::scoped_refptr<VideoFrameBuffer>& buffer : buffers_) {
80     // If the buffer is in use, the ref count will be >= 2, one from the list we
81     // are looping over and one from the application. If the ref count is 1,
82     // then the list we are looping over holds the only reference and it's safe
83     // to reuse.
84     if (!HasOneRef(buffer)) {
85       used_buffers_count++;
86     }
87   }
88   if (used_buffers_count > max_number_of_buffers) {
89     return false;
90   }
91   max_number_of_buffers_ = max_number_of_buffers;
92 
93   size_t buffers_to_purge = buffers_.size() - max_number_of_buffers_;
94   auto iter = buffers_.begin();
95   while (iter != buffers_.end() && buffers_to_purge > 0) {
96     if (HasOneRef(*iter)) {
97       iter = buffers_.erase(iter);
98       buffers_to_purge--;
99     } else {
100       ++iter;
101     }
102   }
103   return true;
104 }
105 
CreateI420Buffer(int width,int height)106 rtc::scoped_refptr<I420Buffer> VideoFrameBufferPool::CreateI420Buffer(
107     int width,
108     int height) {
109   RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
110 
111   rtc::scoped_refptr<VideoFrameBuffer> existing_buffer =
112       GetExistingBuffer(width, height, VideoFrameBuffer::Type::kI420);
113   if (existing_buffer) {
114     // Cast is safe because the only way kI420 buffer is created is
115     // in the same function below, where `RefCountedObject<I420Buffer>` is
116     // created.
117     rtc::RefCountedObject<I420Buffer>* raw_buffer =
118         static_cast<rtc::RefCountedObject<I420Buffer>*>(existing_buffer.get());
119     // Creates a new scoped_refptr, which is also pointing to the same
120     // RefCountedObject as buffer, increasing ref count.
121     return rtc::scoped_refptr<I420Buffer>(raw_buffer);
122   }
123 
124   if (buffers_.size() >= max_number_of_buffers_)
125     return nullptr;
126   // Allocate new buffer.
127   rtc::scoped_refptr<I420Buffer> buffer =
128       rtc::make_ref_counted<I420Buffer>(width, height);
129 
130   if (zero_initialize_)
131     buffer->InitializeData();
132 
133   buffers_.push_back(buffer);
134   return buffer;
135 }
136 
CreateI444Buffer(int width,int height)137 rtc::scoped_refptr<I444Buffer> VideoFrameBufferPool::CreateI444Buffer(
138     int width,
139     int height) {
140   RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
141 
142   rtc::scoped_refptr<VideoFrameBuffer> existing_buffer =
143       GetExistingBuffer(width, height, VideoFrameBuffer::Type::kI444);
144   if (existing_buffer) {
145     // Cast is safe because the only way kI444 buffer is created is
146     // in the same function below, where |RefCountedObject<I444Buffer>|
147     // is created.
148     rtc::RefCountedObject<I444Buffer>* raw_buffer =
149         static_cast<rtc::RefCountedObject<I444Buffer>*>(existing_buffer.get());
150     // Creates a new scoped_refptr, which is also pointing to the same
151     // RefCountedObject as buffer, increasing ref count.
152     return rtc::scoped_refptr<I444Buffer>(raw_buffer);
153   }
154 
155   if (buffers_.size() >= max_number_of_buffers_)
156     return nullptr;
157   // Allocate new buffer.
158   rtc::scoped_refptr<I444Buffer> buffer =
159       rtc::make_ref_counted<I444Buffer>(width, height);
160 
161   if (zero_initialize_)
162     buffer->InitializeData();
163 
164   buffers_.push_back(buffer);
165   return buffer;
166 }
167 
CreateI422Buffer(int width,int height)168 rtc::scoped_refptr<I422Buffer> VideoFrameBufferPool::CreateI422Buffer(
169     int width,
170     int height) {
171   RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
172 
173   rtc::scoped_refptr<VideoFrameBuffer> existing_buffer =
174       GetExistingBuffer(width, height, VideoFrameBuffer::Type::kI422);
175   if (existing_buffer) {
176     // Cast is safe because the only way kI422 buffer is created is
177     // in the same function below, where |RefCountedObject<I422Buffer>|
178     // is created.
179     rtc::RefCountedObject<I422Buffer>* raw_buffer =
180         static_cast<rtc::RefCountedObject<I422Buffer>*>(existing_buffer.get());
181     // Creates a new scoped_refptr, which is also pointing to the same
182     // RefCountedObject as buffer, increasing ref count.
183     return rtc::scoped_refptr<I422Buffer>(raw_buffer);
184   }
185 
186   if (buffers_.size() >= max_number_of_buffers_)
187     return nullptr;
188   // Allocate new buffer.
189   rtc::scoped_refptr<I422Buffer> buffer =
190       rtc::make_ref_counted<I422Buffer>(width, height);
191 
192   if (zero_initialize_)
193     buffer->InitializeData();
194 
195   buffers_.push_back(buffer);
196   return buffer;
197 }
198 
CreateNV12Buffer(int width,int height)199 rtc::scoped_refptr<NV12Buffer> VideoFrameBufferPool::CreateNV12Buffer(
200     int width,
201     int height) {
202   RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
203 
204   rtc::scoped_refptr<VideoFrameBuffer> existing_buffer =
205       GetExistingBuffer(width, height, VideoFrameBuffer::Type::kNV12);
206   if (existing_buffer) {
207     // Cast is safe because the only way kI420 buffer is created is
208     // in the same function below, where `RefCountedObject<I420Buffer>` is
209     // created.
210     rtc::RefCountedObject<NV12Buffer>* raw_buffer =
211         static_cast<rtc::RefCountedObject<NV12Buffer>*>(existing_buffer.get());
212     // Creates a new scoped_refptr, which is also pointing to the same
213     // RefCountedObject as buffer, increasing ref count.
214     return rtc::scoped_refptr<NV12Buffer>(raw_buffer);
215   }
216 
217   if (buffers_.size() >= max_number_of_buffers_)
218     return nullptr;
219   // Allocate new buffer.
220   rtc::scoped_refptr<NV12Buffer> buffer =
221       rtc::make_ref_counted<NV12Buffer>(width, height);
222 
223   if (zero_initialize_)
224     buffer->InitializeData();
225 
226   buffers_.push_back(buffer);
227   return buffer;
228 }
229 
CreateI010Buffer(int width,int height)230 rtc::scoped_refptr<I010Buffer> VideoFrameBufferPool::CreateI010Buffer(
231     int width,
232     int height) {
233   RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
234 
235   rtc::scoped_refptr<VideoFrameBuffer> existing_buffer =
236       GetExistingBuffer(width, height, VideoFrameBuffer::Type::kI010);
237   if (existing_buffer) {
238     // Cast is safe because the only way kI010 buffer is created is
239     // in the same function below, where |RefCountedObject<I010Buffer>|
240     // is created.
241     rtc::RefCountedObject<I010Buffer>* raw_buffer =
242         static_cast<rtc::RefCountedObject<I010Buffer>*>(existing_buffer.get());
243     // Creates a new scoped_refptr, which is also pointing to the same
244     // RefCountedObject as buffer, increasing ref count.
245     return rtc::scoped_refptr<I010Buffer>(raw_buffer);
246   }
247 
248   if (buffers_.size() >= max_number_of_buffers_)
249     return nullptr;
250   // Allocate new buffer.
251   rtc::scoped_refptr<I010Buffer> buffer = I010Buffer::Create(width, height);
252 
253   buffers_.push_back(buffer);
254   return buffer;
255 }
256 
CreateI210Buffer(int width,int height)257 rtc::scoped_refptr<I210Buffer> VideoFrameBufferPool::CreateI210Buffer(
258     int width,
259     int height) {
260   RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
261 
262   rtc::scoped_refptr<VideoFrameBuffer> existing_buffer =
263       GetExistingBuffer(width, height, VideoFrameBuffer::Type::kI210);
264   if (existing_buffer) {
265     // Cast is safe because the only way kI210 buffer is created is
266     // in the same function below, where |RefCountedObject<I210Buffer>|
267     // is created.
268     rtc::RefCountedObject<I210Buffer>* raw_buffer =
269         static_cast<rtc::RefCountedObject<I210Buffer>*>(existing_buffer.get());
270     // Creates a new scoped_refptr, which is also pointing to the same
271     // RefCountedObject as buffer, increasing ref count.
272     return rtc::scoped_refptr<I210Buffer>(raw_buffer);
273   }
274 
275   if (buffers_.size() >= max_number_of_buffers_)
276     return nullptr;
277   // Allocate new buffer.
278   rtc::scoped_refptr<I210Buffer> buffer = I210Buffer::Create(width, height);
279 
280   buffers_.push_back(buffer);
281   return buffer;
282 }
283 
GetExistingBuffer(int width,int height,VideoFrameBuffer::Type type)284 rtc::scoped_refptr<VideoFrameBuffer> VideoFrameBufferPool::GetExistingBuffer(
285     int width,
286     int height,
287     VideoFrameBuffer::Type type) {
288   // Release buffers with wrong resolution or different type.
289   for (auto it = buffers_.begin(); it != buffers_.end();) {
290     const auto& buffer = *it;
291     if (buffer->width() != width || buffer->height() != height ||
292         buffer->type() != type) {
293       it = buffers_.erase(it);
294     } else {
295       ++it;
296     }
297   }
298   // Look for a free buffer.
299   for (const rtc::scoped_refptr<VideoFrameBuffer>& buffer : buffers_) {
300     // If the buffer is in use, the ref count will be >= 2, one from the list we
301     // are looping over and one from the application. If the ref count is 1,
302     // then the list we are looping over holds the only reference and it's safe
303     // to reuse.
304     if (HasOneRef(buffer)) {
305       RTC_CHECK(buffer->type() == type);
306       return buffer;
307     }
308   }
309   return nullptr;
310 }
311 
312 }  // namespace webrtc
313