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 "media/base/video_frame.h"
     11 #include "media/base/video_util.h"
     12 
     13 namespace content {
     14 
     15 VideoCaptureBufferPool::VideoCaptureBufferPool(size_t size, int count)
     16     : size_(size),
     17       count_(count) {
     18 }
     19 
     20 VideoCaptureBufferPool::~VideoCaptureBufferPool() {
     21 }
     22 
     23 bool VideoCaptureBufferPool::Allocate() {
     24   base::AutoLock lock(lock_);
     25   DCHECK(!IsAllocated());
     26   buffers_.resize(count_);
     27   for (int buffer_id = 0; buffer_id < count(); ++buffer_id) {
     28     Buffer* buffer = new Buffer();
     29     buffers_[buffer_id] = buffer;
     30     if (!buffer->shared_memory.CreateAndMapAnonymous(GetMemorySize()))
     31       return false;
     32   }
     33   return true;
     34 }
     35 
     36 base::SharedMemoryHandle VideoCaptureBufferPool::ShareToProcess(
     37     int buffer_id,
     38     base::ProcessHandle process_handle) {
     39   base::AutoLock lock(lock_);
     40   DCHECK(IsAllocated());
     41   DCHECK(buffer_id >= 0);
     42   DCHECK(buffer_id < count_);
     43   Buffer* buffer = buffers_[buffer_id];
     44   base::SharedMemoryHandle remote_handle;
     45   buffer->shared_memory.ShareToProcess(process_handle, &remote_handle);
     46   return remote_handle;
     47 }
     48 
     49 base::SharedMemoryHandle VideoCaptureBufferPool::GetHandle(int buffer_id) {
     50   base::AutoLock lock(lock_);
     51   DCHECK(IsAllocated());
     52   DCHECK(buffer_id >= 0);
     53   DCHECK(buffer_id < count_);
     54   return buffers_[buffer_id]->shared_memory.handle();
     55 }
     56 
     57 void* VideoCaptureBufferPool::GetMemory(int buffer_id) {
     58   base::AutoLock lock(lock_);
     59   DCHECK(IsAllocated());
     60   DCHECK(buffer_id >= 0);
     61   DCHECK(buffer_id < count_);
     62   return buffers_[buffer_id]->shared_memory.memory();
     63 }
     64 
     65 int VideoCaptureBufferPool::ReserveForProducer() {
     66   base::AutoLock lock(lock_);
     67   return ReserveForProducerInternal();
     68 }
     69 
     70 void VideoCaptureBufferPool::RelinquishProducerReservation(int buffer_id) {
     71   base::AutoLock lock(lock_);
     72   DCHECK(buffer_id >= 0);
     73   DCHECK(buffer_id < count());
     74   Buffer* buffer = buffers_[buffer_id];
     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   DCHECK(buffer_id >= 0);
     84   DCHECK(buffer_id < count());
     85   DCHECK(IsAllocated());
     86   Buffer* buffer = buffers_[buffer_id];
     87   DCHECK(buffer->held_by_producer);
     88   DCHECK(!buffer->consumer_hold_count);
     89 
     90   buffer->consumer_hold_count = num_clients;
     91   // Note: |held_by_producer| will stay true until
     92   // RelinquishProducerReservation() (usually called by destructor of the object
     93   // wrapping this buffer, e.g. a media::VideoFrame
     94 }
     95 
     96 void VideoCaptureBufferPool::RelinquishConsumerHold(int buffer_id,
     97                                                     int num_clients) {
     98   base::AutoLock lock(lock_);
     99   DCHECK(buffer_id >= 0);
    100   DCHECK(buffer_id < count());
    101   DCHECK_GT(num_clients, 0);
    102   DCHECK(IsAllocated());
    103   Buffer* buffer = buffers_[buffer_id];
    104   DCHECK_GE(buffer->consumer_hold_count, num_clients);
    105 
    106   buffer->consumer_hold_count -= num_clients;
    107 }
    108 
    109 // State query functions.
    110 size_t VideoCaptureBufferPool::GetMemorySize() const {
    111   // No need to take |lock_| currently.
    112   return size_;
    113 }
    114 
    115 int VideoCaptureBufferPool::RecognizeReservedBuffer(
    116     base::SharedMemoryHandle maybe_belongs_to_pool) {
    117   base::AutoLock lock(lock_);
    118   for (int buffer_id = 0; buffer_id < count(); ++buffer_id) {
    119     Buffer* buffer = buffers_[buffer_id];
    120     if (buffer->shared_memory.handle() == maybe_belongs_to_pool) {
    121       DCHECK(buffer->held_by_producer);
    122       return buffer_id;
    123     }
    124   }
    125   return -1;  // Buffer is not from our pool.
    126 }
    127 
    128 scoped_refptr<media::VideoFrame> VideoCaptureBufferPool::ReserveI420VideoFrame(
    129     const gfx::Size& size,
    130     int rotation) {
    131   if (static_cast<size_t>(size.GetArea() * 3 / 2) != GetMemorySize())
    132     return NULL;
    133 
    134   base::AutoLock lock(lock_);
    135 
    136   int buffer_id = ReserveForProducerInternal();
    137   if (buffer_id < 0)
    138     return NULL;
    139 
    140   base::Closure disposal_handler = base::Bind(
    141       &VideoCaptureBufferPool::RelinquishProducerReservation,
    142       this,
    143       buffer_id);
    144 
    145   Buffer* buffer = buffers_[buffer_id];
    146   // Wrap the buffer in a VideoFrame container.
    147   scoped_refptr<media::VideoFrame> frame =
    148       media::VideoFrame::WrapExternalSharedMemory(
    149           media::VideoFrame::I420,
    150           size,
    151           gfx::Rect(size),
    152           size,
    153           static_cast<uint8*>(buffer->shared_memory.memory()),
    154           buffer->shared_memory.handle(),
    155           base::TimeDelta(),
    156           disposal_handler);
    157 
    158   if (buffer->rotation != rotation) {
    159     // TODO(nick): Generalize the |rotation| mechanism.
    160     media::FillYUV(frame.get(), 0, 128, 128);
    161     buffer->rotation = rotation;
    162   }
    163 
    164   return frame;
    165 }
    166 
    167 bool VideoCaptureBufferPool::IsAnyBufferHeldForConsumers() {
    168   base::AutoLock lock(lock_);
    169   for (int buffer_id = 0; buffer_id < count(); ++buffer_id) {
    170     Buffer* buffer = buffers_[buffer_id];
    171     if (buffer->consumer_hold_count > 0)
    172       return true;
    173   }
    174   return false;
    175 }
    176 
    177 VideoCaptureBufferPool::Buffer::Buffer()
    178     : rotation(0),
    179       held_by_producer(false),
    180       consumer_hold_count(0) {}
    181 
    182 int VideoCaptureBufferPool::ReserveForProducerInternal() {
    183   lock_.AssertAcquired();
    184   DCHECK(IsAllocated());
    185 
    186   int buffer_id = -1;
    187   for (int candidate_id = 0; candidate_id < count(); ++candidate_id) {
    188     Buffer* candidate = buffers_[candidate_id];
    189     if (!candidate->consumer_hold_count && !candidate->held_by_producer) {
    190       buffer_id = candidate_id;
    191       break;
    192     }
    193   }
    194   if (buffer_id == -1)
    195     return -1;
    196 
    197   Buffer* buffer = buffers_[buffer_id];
    198   CHECK_GE(buffer->shared_memory.requested_size(), size_);
    199   buffer->held_by_producer = true;
    200   return buffer_id;
    201 }
    202 
    203 bool VideoCaptureBufferPool::IsAllocated() const {
    204   lock_.AssertAcquired();
    205   return !buffers_.empty();
    206 }
    207 
    208 }  // namespace content
    209 
    210