Home | History | Annotate | Download | only in media
      1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "content/browser/renderer_host/media/video_capture_buffer_pool.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/callback.h"
      9 #include "base/logging.h"
     10 #include "base/memory/scoped_ptr.h"
     11 #include "base/stl_util.h"
     12 #include "media/base/video_frame.h"
     13 #include "media/base/video_util.h"
     14 
     15 namespace content {
     16 
     17 const int VideoCaptureBufferPool::kInvalidId = -1;
     18 
     19 VideoCaptureBufferPool::VideoCaptureBufferPool(int count)
     20     : count_(count),
     21       next_buffer_id_(0) {
     22   DCHECK_GT(count, 0);
     23 }
     24 
     25 VideoCaptureBufferPool::~VideoCaptureBufferPool() {
     26   STLDeleteValues(&buffers_);
     27 }
     28 
     29 base::SharedMemoryHandle VideoCaptureBufferPool::ShareToProcess(
     30     int buffer_id,
     31     base::ProcessHandle process_handle,
     32     size_t* memory_size) {
     33   base::AutoLock lock(lock_);
     34 
     35   Buffer* buffer = GetBuffer(buffer_id);
     36   if (!buffer) {
     37     NOTREACHED() << "Invalid buffer_id.";
     38     return base::SharedMemory::NULLHandle();
     39   }
     40   base::SharedMemoryHandle remote_handle;
     41   buffer->shared_memory.ShareToProcess(process_handle, &remote_handle);
     42   *memory_size = buffer->shared_memory.requested_size();
     43   return remote_handle;
     44 }
     45 
     46 bool VideoCaptureBufferPool::GetBufferInfo(int buffer_id,
     47                                            void** memory,
     48                                            size_t* size) {
     49   base::AutoLock lock(lock_);
     50 
     51   Buffer* buffer = GetBuffer(buffer_id);
     52   if (!buffer) {
     53     NOTREACHED() << "Invalid buffer_id.";
     54     return false;
     55   }
     56 
     57   DCHECK(buffer->held_by_producer);
     58   *memory = buffer->shared_memory.memory();
     59   *size = buffer->shared_memory.mapped_size();
     60   return true;
     61 }
     62 
     63 int VideoCaptureBufferPool::ReserveForProducer(size_t size,
     64                                                int* buffer_id_to_drop) {
     65   base::AutoLock lock(lock_);
     66   return ReserveForProducerInternal(size, buffer_id_to_drop);
     67 }
     68 
     69 void VideoCaptureBufferPool::RelinquishProducerReservation(int buffer_id) {
     70   base::AutoLock lock(lock_);
     71   Buffer* buffer = GetBuffer(buffer_id);
     72   if (!buffer) {
     73     NOTREACHED() << "Invalid buffer_id.";
     74     return;
     75   }
     76   DCHECK(buffer->held_by_producer);
     77   buffer->held_by_producer = false;
     78 }
     79 
     80 void VideoCaptureBufferPool::HoldForConsumers(
     81     int buffer_id,
     82     int num_clients) {
     83   base::AutoLock lock(lock_);
     84   Buffer* buffer = GetBuffer(buffer_id);
     85   if (!buffer) {
     86     NOTREACHED() << "Invalid buffer_id.";
     87     return;
     88   }
     89   DCHECK(buffer->held_by_producer);
     90   DCHECK(!buffer->consumer_hold_count);
     91 
     92   buffer->consumer_hold_count = num_clients;
     93   // Note: |held_by_producer| will stay true until
     94   // RelinquishProducerReservation() (usually called by destructor of the object
     95   // wrapping this buffer, e.g. a media::VideoFrame).
     96 }
     97 
     98 void VideoCaptureBufferPool::RelinquishConsumerHold(int buffer_id,
     99                                                     int num_clients) {
    100   base::AutoLock lock(lock_);
    101   Buffer* buffer = GetBuffer(buffer_id);
    102   if (!buffer) {
    103     NOTREACHED() << "Invalid buffer_id.";
    104     return;
    105   }
    106   DCHECK_GE(buffer->consumer_hold_count, num_clients);
    107 
    108   buffer->consumer_hold_count -= num_clients;
    109 }
    110 
    111 VideoCaptureBufferPool::Buffer::Buffer()
    112     : held_by_producer(false), consumer_hold_count(0) {}
    113 
    114 int VideoCaptureBufferPool::ReserveForProducerInternal(size_t size,
    115                                                        int* buffer_id_to_drop) {
    116   lock_.AssertAcquired();
    117 
    118   // Look for a buffer that's allocated, big enough, and not in use. Track the
    119   // largest one that's not big enough, in case we have to reallocate a buffer.
    120   *buffer_id_to_drop = kInvalidId;
    121   size_t realloc_size = 0;
    122   BufferMap::iterator realloc = buffers_.end();
    123   for (BufferMap::iterator it = buffers_.begin(); it != buffers_.end(); ++it) {
    124     Buffer* buffer = it->second;
    125     if (!buffer->consumer_hold_count && !buffer->held_by_producer) {
    126       if (buffer->shared_memory.requested_size() >= size) {
    127         // Existing buffer is big enough. Reuse it.
    128         buffer->held_by_producer = true;
    129         return it->first;
    130       }
    131       if (buffer->shared_memory.requested_size() > realloc_size) {
    132         realloc_size = buffer->shared_memory.requested_size();
    133         realloc = it;
    134       }
    135     }
    136   }
    137 
    138   // Preferentially grow the pool by creating a new buffer. If we're at maximum
    139   // size, then reallocate by deleting an existing one instead.
    140   if (buffers_.size() == static_cast<size_t>(count_)) {
    141     if (realloc == buffers_.end()) {
    142       // We're out of space, and can't find an unused buffer to reallocate.
    143       return kInvalidId;
    144     }
    145     *buffer_id_to_drop = realloc->first;
    146     delete realloc->second;
    147     buffers_.erase(realloc);
    148   }
    149 
    150   // Create the new buffer.
    151   int buffer_id = next_buffer_id_++;
    152   scoped_ptr<Buffer> buffer(new Buffer());
    153   if (size) {
    154     // |size| can be 0 for buffers that do not require memory backing.
    155     if (!buffer->shared_memory.CreateAndMapAnonymous(size))
    156       return kInvalidId;
    157   }
    158   buffer->held_by_producer = true;
    159   buffers_[buffer_id] = buffer.release();
    160   return buffer_id;
    161 }
    162 
    163 VideoCaptureBufferPool::Buffer* VideoCaptureBufferPool::GetBuffer(
    164     int buffer_id) {
    165   BufferMap::iterator it = buffers_.find(buffer_id);
    166   if (it == buffers_.end())
    167     return NULL;
    168   return it->second;
    169 }
    170 
    171 }  // namespace content
    172