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