summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/common_video/video_frame_buffer_pool.cc
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--third_party/libwebrtc/common_video/video_frame_buffer_pool.cc343
1 files changed, 343 insertions, 0 deletions
diff --git a/third_party/libwebrtc/common_video/video_frame_buffer_pool.cc b/third_party/libwebrtc/common_video/video_frame_buffer_pool.cc
new file mode 100644
index 0000000000..c0215110fd
--- /dev/null
+++ b/third_party/libwebrtc/common_video/video_frame_buffer_pool.cc
@@ -0,0 +1,343 @@
+/*
+ * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "common_video/include/video_frame_buffer_pool.h"
+
+#include <limits>
+
+#include "api/make_ref_counted.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+namespace {
+bool HasOneRef(const rtc::scoped_refptr<VideoFrameBuffer>& buffer) {
+ // Cast to rtc::RefCountedObject is safe because this function is only called
+ // on locally created VideoFrameBuffers, which are either
+ // `rtc::RefCountedObject<I420Buffer>`, `rtc::RefCountedObject<I444Buffer>` or
+ // `rtc::RefCountedObject<NV12Buffer>`.
+ switch (buffer->type()) {
+ case VideoFrameBuffer::Type::kI420: {
+ return static_cast<rtc::RefCountedObject<I420Buffer>*>(buffer.get())
+ ->HasOneRef();
+ }
+ case VideoFrameBuffer::Type::kI444: {
+ return static_cast<rtc::RefCountedObject<I444Buffer>*>(buffer.get())
+ ->HasOneRef();
+ }
+ case VideoFrameBuffer::Type::kI422: {
+ return static_cast<rtc::RefCountedObject<I422Buffer>*>(buffer.get())
+ ->HasOneRef();
+ }
+ case VideoFrameBuffer::Type::kI010: {
+ return static_cast<rtc::RefCountedObject<I010Buffer>*>(buffer.get())
+ ->HasOneRef();
+ }
+ case VideoFrameBuffer::Type::kI210: {
+ return static_cast<rtc::RefCountedObject<I210Buffer>*>(buffer.get())
+ ->HasOneRef();
+ }
+ case VideoFrameBuffer::Type::kI410: {
+ return static_cast<rtc::RefCountedObject<I410Buffer>*>(buffer.get())
+ ->HasOneRef();
+ }
+ case VideoFrameBuffer::Type::kNV12: {
+ return static_cast<rtc::RefCountedObject<NV12Buffer>*>(buffer.get())
+ ->HasOneRef();
+ }
+ default:
+ RTC_DCHECK_NOTREACHED();
+ }
+ return false;
+}
+
+} // namespace
+
+VideoFrameBufferPool::VideoFrameBufferPool() : VideoFrameBufferPool(false) {}
+
+VideoFrameBufferPool::VideoFrameBufferPool(bool zero_initialize)
+ : VideoFrameBufferPool(zero_initialize,
+ std::numeric_limits<size_t>::max()) {}
+
+VideoFrameBufferPool::VideoFrameBufferPool(bool zero_initialize,
+ size_t max_number_of_buffers)
+ : zero_initialize_(zero_initialize),
+ max_number_of_buffers_(max_number_of_buffers) {}
+
+VideoFrameBufferPool::~VideoFrameBufferPool() = default;
+
+void VideoFrameBufferPool::Release() {
+ buffers_.clear();
+}
+
+bool VideoFrameBufferPool::Resize(size_t max_number_of_buffers) {
+ RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
+ size_t used_buffers_count = 0;
+ for (const rtc::scoped_refptr<VideoFrameBuffer>& buffer : buffers_) {
+ // If the buffer is in use, the ref count will be >= 2, one from the list we
+ // are looping over and one from the application. If the ref count is 1,
+ // then the list we are looping over holds the only reference and it's safe
+ // to reuse.
+ if (!HasOneRef(buffer)) {
+ used_buffers_count++;
+ }
+ }
+ if (used_buffers_count > max_number_of_buffers) {
+ return false;
+ }
+ max_number_of_buffers_ = max_number_of_buffers;
+
+ size_t buffers_to_purge = buffers_.size() - max_number_of_buffers_;
+ auto iter = buffers_.begin();
+ while (iter != buffers_.end() && buffers_to_purge > 0) {
+ if (HasOneRef(*iter)) {
+ iter = buffers_.erase(iter);
+ buffers_to_purge--;
+ } else {
+ ++iter;
+ }
+ }
+ return true;
+}
+
+rtc::scoped_refptr<I420Buffer> VideoFrameBufferPool::CreateI420Buffer(
+ int width,
+ int height) {
+ RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
+
+ rtc::scoped_refptr<VideoFrameBuffer> existing_buffer =
+ GetExistingBuffer(width, height, VideoFrameBuffer::Type::kI420);
+ if (existing_buffer) {
+ // Cast is safe because the only way kI420 buffer is created is
+ // in the same function below, where `RefCountedObject<I420Buffer>` is
+ // created.
+ rtc::RefCountedObject<I420Buffer>* raw_buffer =
+ static_cast<rtc::RefCountedObject<I420Buffer>*>(existing_buffer.get());
+ // Creates a new scoped_refptr, which is also pointing to the same
+ // RefCountedObject as buffer, increasing ref count.
+ return rtc::scoped_refptr<I420Buffer>(raw_buffer);
+ }
+
+ if (buffers_.size() >= max_number_of_buffers_)
+ return nullptr;
+ // Allocate new buffer.
+ rtc::scoped_refptr<I420Buffer> buffer =
+ rtc::make_ref_counted<I420Buffer>(width, height);
+
+ if (zero_initialize_)
+ buffer->InitializeData();
+
+ buffers_.push_back(buffer);
+ return buffer;
+}
+
+rtc::scoped_refptr<I444Buffer> VideoFrameBufferPool::CreateI444Buffer(
+ int width,
+ int height) {
+ RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
+
+ rtc::scoped_refptr<VideoFrameBuffer> existing_buffer =
+ GetExistingBuffer(width, height, VideoFrameBuffer::Type::kI444);
+ if (existing_buffer) {
+ // Cast is safe because the only way kI444 buffer is created is
+ // in the same function below, where |RefCountedObject<I444Buffer>|
+ // is created.
+ rtc::RefCountedObject<I444Buffer>* raw_buffer =
+ static_cast<rtc::RefCountedObject<I444Buffer>*>(existing_buffer.get());
+ // Creates a new scoped_refptr, which is also pointing to the same
+ // RefCountedObject as buffer, increasing ref count.
+ return rtc::scoped_refptr<I444Buffer>(raw_buffer);
+ }
+
+ if (buffers_.size() >= max_number_of_buffers_)
+ return nullptr;
+ // Allocate new buffer.
+ rtc::scoped_refptr<I444Buffer> buffer =
+ rtc::make_ref_counted<I444Buffer>(width, height);
+
+ if (zero_initialize_)
+ buffer->InitializeData();
+
+ buffers_.push_back(buffer);
+ return buffer;
+}
+
+rtc::scoped_refptr<I422Buffer> VideoFrameBufferPool::CreateI422Buffer(
+ int width,
+ int height) {
+ RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
+
+ rtc::scoped_refptr<VideoFrameBuffer> existing_buffer =
+ GetExistingBuffer(width, height, VideoFrameBuffer::Type::kI422);
+ if (existing_buffer) {
+ // Cast is safe because the only way kI422 buffer is created is
+ // in the same function below, where |RefCountedObject<I422Buffer>|
+ // is created.
+ rtc::RefCountedObject<I422Buffer>* raw_buffer =
+ static_cast<rtc::RefCountedObject<I422Buffer>*>(existing_buffer.get());
+ // Creates a new scoped_refptr, which is also pointing to the same
+ // RefCountedObject as buffer, increasing ref count.
+ return rtc::scoped_refptr<I422Buffer>(raw_buffer);
+ }
+
+ if (buffers_.size() >= max_number_of_buffers_)
+ return nullptr;
+ // Allocate new buffer.
+ rtc::scoped_refptr<I422Buffer> buffer =
+ rtc::make_ref_counted<I422Buffer>(width, height);
+
+ if (zero_initialize_)
+ buffer->InitializeData();
+
+ buffers_.push_back(buffer);
+ return buffer;
+}
+
+rtc::scoped_refptr<NV12Buffer> VideoFrameBufferPool::CreateNV12Buffer(
+ int width,
+ int height) {
+ RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
+
+ rtc::scoped_refptr<VideoFrameBuffer> existing_buffer =
+ GetExistingBuffer(width, height, VideoFrameBuffer::Type::kNV12);
+ if (existing_buffer) {
+ // Cast is safe because the only way kI420 buffer is created is
+ // in the same function below, where `RefCountedObject<I420Buffer>` is
+ // created.
+ rtc::RefCountedObject<NV12Buffer>* raw_buffer =
+ static_cast<rtc::RefCountedObject<NV12Buffer>*>(existing_buffer.get());
+ // Creates a new scoped_refptr, which is also pointing to the same
+ // RefCountedObject as buffer, increasing ref count.
+ return rtc::scoped_refptr<NV12Buffer>(raw_buffer);
+ }
+
+ if (buffers_.size() >= max_number_of_buffers_)
+ return nullptr;
+ // Allocate new buffer.
+ rtc::scoped_refptr<NV12Buffer> buffer =
+ rtc::make_ref_counted<NV12Buffer>(width, height);
+
+ if (zero_initialize_)
+ buffer->InitializeData();
+
+ buffers_.push_back(buffer);
+ return buffer;
+}
+
+rtc::scoped_refptr<I010Buffer> VideoFrameBufferPool::CreateI010Buffer(
+ int width,
+ int height) {
+ RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
+
+ rtc::scoped_refptr<VideoFrameBuffer> existing_buffer =
+ GetExistingBuffer(width, height, VideoFrameBuffer::Type::kI010);
+ if (existing_buffer) {
+ // Cast is safe because the only way kI010 buffer is created is
+ // in the same function below, where |RefCountedObject<I010Buffer>|
+ // is created.
+ rtc::RefCountedObject<I010Buffer>* raw_buffer =
+ static_cast<rtc::RefCountedObject<I010Buffer>*>(existing_buffer.get());
+ // Creates a new scoped_refptr, which is also pointing to the same
+ // RefCountedObject as buffer, increasing ref count.
+ return rtc::scoped_refptr<I010Buffer>(raw_buffer);
+ }
+
+ if (buffers_.size() >= max_number_of_buffers_)
+ return nullptr;
+ // Allocate new buffer.
+ rtc::scoped_refptr<I010Buffer> buffer = I010Buffer::Create(width, height);
+
+ buffers_.push_back(buffer);
+ return buffer;
+}
+
+rtc::scoped_refptr<I210Buffer> VideoFrameBufferPool::CreateI210Buffer(
+ int width,
+ int height) {
+ RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
+
+ rtc::scoped_refptr<VideoFrameBuffer> existing_buffer =
+ GetExistingBuffer(width, height, VideoFrameBuffer::Type::kI210);
+ if (existing_buffer) {
+ // Cast is safe because the only way kI210 buffer is created is
+ // in the same function below, where |RefCountedObject<I210Buffer>|
+ // is created.
+ rtc::RefCountedObject<I210Buffer>* raw_buffer =
+ static_cast<rtc::RefCountedObject<I210Buffer>*>(existing_buffer.get());
+ // Creates a new scoped_refptr, which is also pointing to the same
+ // RefCountedObject as buffer, increasing ref count.
+ return rtc::scoped_refptr<I210Buffer>(raw_buffer);
+ }
+
+ if (buffers_.size() >= max_number_of_buffers_)
+ return nullptr;
+ // Allocate new buffer.
+ rtc::scoped_refptr<I210Buffer> buffer = I210Buffer::Create(width, height);
+
+ buffers_.push_back(buffer);
+ return buffer;
+}
+
+rtc::scoped_refptr<I410Buffer> VideoFrameBufferPool::CreateI410Buffer(
+ int width,
+ int height) {
+ RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
+
+ rtc::scoped_refptr<VideoFrameBuffer> existing_buffer =
+ GetExistingBuffer(width, height, VideoFrameBuffer::Type::kI410);
+ if (existing_buffer) {
+ // Cast is safe because the only way kI410 buffer is created is
+ // in the same function below, where |RefCountedObject<I410Buffer>|
+ // is created.
+ rtc::RefCountedObject<I410Buffer>* raw_buffer =
+ static_cast<rtc::RefCountedObject<I410Buffer>*>(existing_buffer.get());
+ // Creates a new scoped_refptr, which is also pointing to the same
+ // RefCountedObject as buffer, increasing ref count.
+ return rtc::scoped_refptr<I410Buffer>(raw_buffer);
+ }
+
+ if (buffers_.size() >= max_number_of_buffers_)
+ return nullptr;
+ // Allocate new buffer.
+ rtc::scoped_refptr<I410Buffer> buffer = I410Buffer::Create(width, height);
+
+ buffers_.push_back(buffer);
+ return buffer;
+}
+
+rtc::scoped_refptr<VideoFrameBuffer> VideoFrameBufferPool::GetExistingBuffer(
+ int width,
+ int height,
+ VideoFrameBuffer::Type type) {
+ // Release buffers with wrong resolution or different type.
+ for (auto it = buffers_.begin(); it != buffers_.end();) {
+ const auto& buffer = *it;
+ if (buffer->width() != width || buffer->height() != height ||
+ buffer->type() != type) {
+ it = buffers_.erase(it);
+ } else {
+ ++it;
+ }
+ }
+ // Look for a free buffer.
+ for (const rtc::scoped_refptr<VideoFrameBuffer>& buffer : buffers_) {
+ // If the buffer is in use, the ref count will be >= 2, one from the list we
+ // are looping over and one from the application. If the ref count is 1,
+ // then the list we are looping over holds the only reference and it's safe
+ // to reuse.
+ if (HasOneRef(buffer)) {
+ RTC_CHECK(buffer->type() == type);
+ return buffer;
+ }
+ }
+ return nullptr;
+}
+
+} // namespace webrtc