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