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