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