tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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