Home | History | Annotate | Download | only in ppapi
      1 // Copyright 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 "media/cdm/ppapi/cdm_helpers.h"
      6 
      7 #include <algorithm>
      8 #include <utility>
      9 
     10 #include "base/basictypes.h"
     11 #include "base/compiler_specific.h"
     12 #include "build/build_config.h"
     13 #include "media/cdm/ppapi/api/content_decryption_module.h"
     14 #include "ppapi/c/pp_errors.h"
     15 #include "ppapi/c/pp_stdint.h"
     16 #include "ppapi/cpp/core.h"
     17 #include "ppapi/cpp/dev/buffer_dev.h"
     18 #include "ppapi/cpp/instance.h"
     19 #include "ppapi/cpp/logging.h"
     20 #include "ppapi/cpp/module.h"
     21 
     22 namespace media {
     23 
     24 // static
     25 PpbBuffer* PpbBuffer::Create(const pp::Buffer_Dev& buffer,
     26                              uint32_t buffer_id,
     27                              PpbBufferAllocator* allocator) {
     28   PP_DCHECK(buffer.data());
     29   PP_DCHECK(buffer.size());
     30   PP_DCHECK(buffer_id);
     31   PP_DCHECK(allocator);
     32   return new PpbBuffer(buffer, buffer_id, allocator);
     33 }
     34 
     35 void PpbBuffer::Destroy() {
     36   delete this;
     37 }
     38 
     39 uint32_t PpbBuffer::Capacity() const {
     40   return buffer_.size();
     41 }
     42 
     43 uint8_t* PpbBuffer::Data() {
     44   return static_cast<uint8_t*>(buffer_.data());
     45 }
     46 
     47 void PpbBuffer::SetSize(uint32_t size) {
     48   PP_DCHECK(size <= Capacity());
     49   if (size > Capacity()) {
     50     size_ = 0;
     51     return;
     52   }
     53 
     54   size_ = size;
     55 }
     56 
     57 pp::Buffer_Dev PpbBuffer::TakeBuffer() {
     58   PP_DCHECK(!buffer_.is_null());
     59   pp::Buffer_Dev buffer;
     60   std::swap(buffer, buffer_);
     61   buffer_id_ = 0;
     62   size_ = 0;
     63   return buffer;
     64 }
     65 
     66 PpbBuffer::PpbBuffer(pp::Buffer_Dev buffer,
     67                      uint32_t buffer_id,
     68                      PpbBufferAllocator* allocator)
     69     : buffer_(buffer), buffer_id_(buffer_id), size_(0), allocator_(allocator) {
     70 }
     71 
     72 PpbBuffer::~PpbBuffer() {
     73   PP_DCHECK(!buffer_id_ == buffer_.is_null());
     74   // If still owning the |buffer_|, release it in the |allocator_|.
     75   if (buffer_id_)
     76     allocator_->Release(buffer_id_);
     77 }
     78 
     79 cdm::Buffer* PpbBufferAllocator::Allocate(uint32_t capacity) {
     80   PP_DCHECK(pp::Module::Get()->core()->IsMainThread());
     81 
     82   if (!capacity)
     83     return NULL;
     84 
     85   pp::Buffer_Dev buffer;
     86   uint32_t buffer_id = 0;
     87 
     88   // Reuse a buffer in the free list if there is one that fits |capacity|.
     89   // Otherwise, create a new one.
     90   FreeBufferMap::iterator found = free_buffers_.lower_bound(capacity);
     91   if (found == free_buffers_.end()) {
     92     // TODO(xhwang): Report statistics about how many new buffers are allocated.
     93     buffer = AllocateNewBuffer(capacity);
     94     if (buffer.is_null())
     95       return NULL;
     96     buffer_id = next_buffer_id_++;
     97   } else {
     98     buffer = found->second.second;
     99     buffer_id = found->second.first;
    100     free_buffers_.erase(found);
    101   }
    102 
    103   allocated_buffers_.insert(std::make_pair(buffer_id, buffer));
    104 
    105   return PpbBuffer::Create(buffer, buffer_id, this);
    106 }
    107 
    108 void PpbBufferAllocator::Release(uint32_t buffer_id) {
    109   if (!buffer_id)
    110     return;
    111 
    112   AllocatedBufferMap::iterator found = allocated_buffers_.find(buffer_id);
    113   if (found == allocated_buffers_.end())
    114     return;
    115 
    116   pp::Buffer_Dev& buffer = found->second;
    117   free_buffers_.insert(
    118       std::make_pair(buffer.size(), std::make_pair(buffer_id, buffer)));
    119 
    120   allocated_buffers_.erase(found);
    121 }
    122 
    123 pp::Buffer_Dev PpbBufferAllocator::AllocateNewBuffer(uint32_t capacity) {
    124   // Always pad new allocated buffer so that we don't need to reallocate
    125   // buffers frequently if requested sizes fluctuate slightly.
    126   static const uint32_t kBufferPadding = 512;
    127 
    128   // Maximum number of free buffers we can keep when allocating new buffers.
    129   static const uint32_t kFreeLimit = 3;
    130 
    131   // Destroy the smallest buffer before allocating a new bigger buffer if the
    132   // number of free buffers exceeds a limit. This mechanism helps avoid ending
    133   // up with too many small buffers, which could happen if the size to be
    134   // allocated keeps increasing.
    135   if (free_buffers_.size() >= kFreeLimit)
    136     free_buffers_.erase(free_buffers_.begin());
    137 
    138   // Creation of pp::Buffer_Dev is expensive! It involves synchronous IPC calls.
    139   // That's why we try to avoid AllocateNewBuffer() as much as we can.
    140   return pp::Buffer_Dev(instance_, capacity + kBufferPadding);
    141 }
    142 
    143 VideoFrameImpl::VideoFrameImpl()
    144     : format_(cdm::kUnknownVideoFormat),
    145       frame_buffer_(NULL),
    146       timestamp_(0) {
    147   for (uint32_t i = 0; i < kMaxPlanes; ++i) {
    148     plane_offsets_[i] = 0;
    149     strides_[i] = 0;
    150   }
    151 }
    152 
    153 VideoFrameImpl::~VideoFrameImpl() {
    154   if (frame_buffer_)
    155     frame_buffer_->Destroy();
    156 }
    157 
    158 }  // namespace media
    159