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
Create(const pp::Buffer_Dev & buffer,uint32_t buffer_id,PpbBufferAllocator * allocator)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
Destroy()35 void PpbBuffer::Destroy() {
36 delete this;
37 }
38
Capacity() const39 uint32_t PpbBuffer::Capacity() const {
40 return buffer_.size();
41 }
42
Data()43 uint8_t* PpbBuffer::Data() {
44 return static_cast<uint8_t*>(buffer_.data());
45 }
46
SetSize(uint32_t size)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
TakeBuffer()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
PpbBuffer(pp::Buffer_Dev buffer,uint32_t buffer_id,PpbBufferAllocator * allocator)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
~PpbBuffer()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
Allocate(uint32_t capacity)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
Release(uint32_t buffer_id)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
AllocateNewBuffer(uint32_t capacity)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
VideoFrameImpl()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
~VideoFrameImpl()153 VideoFrameImpl::~VideoFrameImpl() {
154 if (frame_buffer_)
155 frame_buffer_->Destroy();
156 }
157
158 } // namespace media
159