OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | |
xhwang
2013/10/15 20:42:33
This file is copied from cdm_wrapper.cc, with smal
| |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #ifndef MEDIA_CDM_PPAPI_CDM_HELPERS_H_ | |
6 #define MEDIA_CDM_PPAPI_CDM_HELPERS_H_ | |
7 | |
8 #include <map> | |
9 #include <utility> | |
10 | |
11 #include "base/basictypes.h" | |
12 #include "base/compiler_specific.h" | |
13 #include "build/build_config.h" | |
14 #include "media/cdm/ppapi/api/content_decryption_module.h" | |
15 #include "ppapi/c/pp_errors.h" | |
16 #include "ppapi/c/pp_stdint.h" | |
17 #include "ppapi/cpp/core.h" | |
18 #include "ppapi/cpp/dev/buffer_dev.h" | |
19 #include "ppapi/cpp/instance.h" | |
20 #include "ppapi/cpp/logging.h" | |
21 #include "ppapi/cpp/module.h" | |
xhwang
2013/10/15 20:42:33
Includes are trimmed to reflect what we use.
| |
22 | |
23 namespace media { | |
24 | |
25 // cdm::Buffer implementation that provides access to memory owned by a | |
26 // pp::Buffer_Dev. | |
27 // This class holds a reference to the Buffer_Dev throughout its lifetime. | |
28 // TODO(xhwang): Find a better name. It's confusing to have PpbBuffer, | |
29 // pp::Buffer_Dev and PPB_Buffer_Dev. | |
30 class PpbBuffer : public cdm::Buffer { | |
31 public: | |
32 static PpbBuffer* Create(const pp::Buffer_Dev& buffer, uint32_t buffer_id) { | |
33 PP_DCHECK(buffer.data()); | |
34 PP_DCHECK(buffer.size()); | |
35 PP_DCHECK(buffer_id); | |
36 return new PpbBuffer(buffer, buffer_id); | |
37 } | |
38 | |
39 // cdm::Buffer implementation. | |
40 virtual void Destroy() OVERRIDE { delete this; } | |
41 | |
42 virtual int32_t Capacity() const OVERRIDE { return buffer_.size(); } | |
43 | |
44 virtual uint8_t* Data() OVERRIDE { | |
45 return static_cast<uint8_t*>(buffer_.data()); | |
46 } | |
47 | |
48 virtual void SetSize(int32_t size) OVERRIDE { | |
49 PP_DCHECK(size >= 0); | |
50 PP_DCHECK(size < Capacity()); | |
51 if (size < 0 || size > Capacity()) { | |
52 size_ = 0; | |
53 return; | |
54 } | |
55 | |
56 size_ = size; | |
57 } | |
58 | |
59 virtual int32_t Size() const OVERRIDE { return size_; } | |
60 | |
61 pp::Buffer_Dev buffer_dev() const { return buffer_; } | |
62 | |
63 uint32_t buffer_id() const { return buffer_id_; } | |
64 | |
65 private: | |
66 PpbBuffer(pp::Buffer_Dev buffer, uint32_t buffer_id) | |
67 : buffer_(buffer), | |
68 buffer_id_(buffer_id), | |
69 size_(0) {} | |
70 virtual ~PpbBuffer() {} | |
71 | |
72 pp::Buffer_Dev buffer_; | |
73 uint32_t buffer_id_; | |
74 int32_t size_; | |
75 | |
76 DISALLOW_COPY_AND_ASSIGN(PpbBuffer); | |
77 }; | |
78 | |
79 class PpbBufferAllocator { | |
80 public: | |
81 explicit PpbBufferAllocator(pp::Instance* instance) | |
82 : instance_(instance), | |
83 next_buffer_id_(1) {} | |
84 ~PpbBufferAllocator() {} | |
85 | |
86 cdm::Buffer* Allocate(int32_t capacity); | |
87 | |
88 // Releases the buffer with |buffer_id|. A buffer can be recycled after | |
89 // it is released. | |
90 void Release(uint32_t buffer_id); | |
91 | |
92 private: | |
93 typedef std::map<uint32_t, pp::Buffer_Dev> AllocatedBufferMap; | |
94 typedef std::multimap<int, std::pair<uint32_t, pp::Buffer_Dev> > | |
95 FreeBufferMap; | |
96 | |
97 // Always pad new allocated buffer so that we don't need to reallocate | |
98 // buffers frequently if requested sizes fluctuate slightly. | |
99 static const int kBufferPadding = 512; | |
100 | |
101 // Maximum number of free buffers we can keep when allocating new buffers. | |
102 static const int kFreeLimit = 3; | |
103 | |
104 pp::Buffer_Dev AllocateNewBuffer(int capacity); | |
105 | |
106 pp::Instance* const instance_; | |
107 uint32_t next_buffer_id_; | |
108 AllocatedBufferMap allocated_buffers_; | |
109 FreeBufferMap free_buffers_; | |
110 | |
111 DISALLOW_COPY_AND_ASSIGN(PpbBufferAllocator); | |
112 }; | |
113 | |
114 cdm::Buffer* PpbBufferAllocator::Allocate(int32_t capacity) { | |
115 PP_DCHECK(pp::Module::Get()->core()->IsMainThread()); | |
xhwang
2013/10/15 20:42:33
This was IsMainThread() in cdm_wrapper.cc. I am no
| |
116 | |
117 if (capacity <= 0) | |
118 return NULL; | |
119 | |
120 pp::Buffer_Dev buffer; | |
121 uint32_t buffer_id = 0; | |
122 | |
123 // Reuse a buffer in the free list if there is one that fits |capacity|. | |
124 // Otherwise, create a new one. | |
125 FreeBufferMap::iterator found = free_buffers_.lower_bound(capacity); | |
126 if (found == free_buffers_.end()) { | |
127 // TODO(xhwang): Report statistics about how many new buffers are allocated. | |
128 buffer = AllocateNewBuffer(capacity); | |
129 if (buffer.is_null()) | |
130 return NULL; | |
131 buffer_id = next_buffer_id_++; | |
132 } else { | |
133 buffer = found->second.second; | |
134 buffer_id = found->second.first; | |
135 free_buffers_.erase(found); | |
136 } | |
137 | |
138 allocated_buffers_.insert(std::make_pair(buffer_id, buffer)); | |
139 | |
140 return PpbBuffer::Create(buffer, buffer_id); | |
141 } | |
142 | |
143 void PpbBufferAllocator::Release(uint32_t buffer_id) { | |
144 if (!buffer_id) | |
145 return; | |
146 | |
147 AllocatedBufferMap::iterator found = allocated_buffers_.find(buffer_id); | |
148 if (found == allocated_buffers_.end()) | |
149 return; | |
150 | |
151 pp::Buffer_Dev& buffer = found->second; | |
152 free_buffers_.insert( | |
153 std::make_pair(buffer.size(), std::make_pair(buffer_id, buffer))); | |
154 | |
155 allocated_buffers_.erase(found); | |
156 } | |
157 | |
158 pp::Buffer_Dev PpbBufferAllocator::AllocateNewBuffer(int32_t capacity) { | |
159 // Destroy the smallest buffer before allocating a new bigger buffer if the | |
160 // number of free buffers exceeds a limit. This mechanism helps avoid ending | |
161 // up with too many small buffers, which could happen if the size to be | |
162 // allocated keeps increasing. | |
163 if (free_buffers_.size() >= static_cast<uint32_t>(kFreeLimit)) | |
164 free_buffers_.erase(free_buffers_.begin()); | |
165 | |
166 // Creation of pp::Buffer_Dev is expensive! It involves synchronous IPC calls. | |
167 // That's why we try to avoid AllocateNewBuffer() as much as we can. | |
168 return pp::Buffer_Dev(instance_, capacity + kBufferPadding); | |
169 } | |
170 | |
171 class DecryptedBlockImpl : public cdm::DecryptedBlock { | |
172 public: | |
173 DecryptedBlockImpl() : buffer_(NULL), timestamp_(0) {} | |
174 virtual ~DecryptedBlockImpl() { if (buffer_) buffer_->Destroy(); } | |
175 | |
176 virtual void SetDecryptedBuffer(cdm::Buffer* buffer) OVERRIDE { | |
177 buffer_ = static_cast<PpbBuffer*>(buffer); | |
178 } | |
179 virtual cdm::Buffer* DecryptedBuffer() OVERRIDE { return buffer_; } | |
180 | |
181 virtual void SetTimestamp(int64_t timestamp) OVERRIDE { | |
182 timestamp_ = timestamp; | |
183 } | |
184 virtual int64_t Timestamp() const OVERRIDE { return timestamp_; } | |
185 | |
186 private: | |
187 PpbBuffer* buffer_; | |
188 int64_t timestamp_; | |
189 | |
190 DISALLOW_COPY_AND_ASSIGN(DecryptedBlockImpl); | |
191 }; | |
192 | |
193 class VideoFrameImpl : public cdm::VideoFrame { | |
194 public: | |
195 VideoFrameImpl(); | |
196 virtual ~VideoFrameImpl(); | |
197 | |
198 virtual void SetFormat(cdm::VideoFormat format) OVERRIDE { | |
199 format_ = format; | |
200 } | |
201 virtual cdm::VideoFormat Format() const OVERRIDE { return format_; } | |
202 | |
203 virtual void SetSize(cdm::Size size) OVERRIDE { size_ = size; } | |
204 virtual cdm::Size Size() const OVERRIDE { return size_; } | |
205 | |
206 virtual void SetFrameBuffer(cdm::Buffer* frame_buffer) OVERRIDE { | |
207 frame_buffer_ = static_cast<PpbBuffer*>(frame_buffer); | |
208 } | |
209 virtual cdm::Buffer* FrameBuffer() OVERRIDE { return frame_buffer_; } | |
210 | |
211 virtual void SetPlaneOffset(cdm::VideoFrame::VideoPlane plane, | |
212 int32_t offset) OVERRIDE { | |
213 PP_DCHECK(0 <= plane && plane < kMaxPlanes); | |
214 PP_DCHECK(offset >= 0); | |
215 plane_offsets_[plane] = offset; | |
216 } | |
217 virtual int32_t PlaneOffset(VideoPlane plane) OVERRIDE { | |
218 PP_DCHECK(0 <= plane && plane < kMaxPlanes); | |
219 return plane_offsets_[plane]; | |
220 } | |
221 | |
222 virtual void SetStride(VideoPlane plane, int32_t stride) OVERRIDE { | |
223 PP_DCHECK(0 <= plane && plane < kMaxPlanes); | |
224 strides_[plane] = stride; | |
225 } | |
226 virtual int32_t Stride(VideoPlane plane) OVERRIDE { | |
227 PP_DCHECK(0 <= plane && plane < kMaxPlanes); | |
228 return strides_[plane]; | |
229 } | |
230 | |
231 virtual void SetTimestamp(int64_t timestamp) OVERRIDE { | |
232 timestamp_ = timestamp; | |
233 } | |
234 virtual int64_t Timestamp() const OVERRIDE { return timestamp_; } | |
235 | |
236 private: | |
237 // The video buffer format. | |
238 cdm::VideoFormat format_; | |
239 | |
240 // Width and height of the video frame. | |
241 cdm::Size size_; | |
242 | |
243 // The video frame buffer. | |
244 PpbBuffer* frame_buffer_; | |
245 | |
246 // Array of data pointers to each plane in the video frame buffer. | |
247 int32_t plane_offsets_[kMaxPlanes]; | |
248 | |
249 // Array of strides for each plane, typically greater or equal to the width | |
250 // of the surface divided by the horizontal sampling period. Note that | |
251 // strides can be negative. | |
252 int32_t strides_[kMaxPlanes]; | |
253 | |
254 // Presentation timestamp in microseconds. | |
255 int64_t timestamp_; | |
256 | |
257 DISALLOW_COPY_AND_ASSIGN(VideoFrameImpl); | |
258 }; | |
259 | |
260 VideoFrameImpl::VideoFrameImpl() | |
261 : format_(cdm::kUnknownVideoFormat), | |
262 frame_buffer_(NULL), | |
263 timestamp_(0) { | |
264 for (int32_t i = 0; i < kMaxPlanes; ++i) { | |
265 plane_offsets_[i] = 0; | |
266 strides_[i] = 0; | |
267 } | |
268 } | |
269 | |
270 VideoFrameImpl::~VideoFrameImpl() { | |
271 if (frame_buffer_) | |
272 frame_buffer_->Destroy(); | |
273 } | |
274 | |
275 class AudioFramesImpl : public cdm::AudioFrames_1, | |
276 public cdm::AudioFrames_2 { | |
277 public: | |
278 AudioFramesImpl() : buffer_(NULL), format_(cdm::kAudioFormatS16) {} | |
279 virtual ~AudioFramesImpl() { | |
280 if (buffer_) | |
281 buffer_->Destroy(); | |
282 } | |
283 | |
284 // AudioFrames implementation. | |
285 virtual void SetFrameBuffer(cdm::Buffer* buffer) OVERRIDE { | |
286 buffer_ = static_cast<PpbBuffer*>(buffer); | |
287 } | |
288 virtual cdm::Buffer* FrameBuffer() OVERRIDE { | |
289 return buffer_; | |
290 } | |
291 virtual void SetFormat(cdm::AudioFormat format) OVERRIDE { | |
292 format_ = format; | |
293 } | |
294 virtual cdm::AudioFormat Format() const OVERRIDE { | |
295 return format_; | |
296 } | |
297 | |
298 cdm::Buffer* PassFrameBuffer() { | |
xhwang
2013/10/15 20:42:33
Added this function so that we can transfer owners
| |
299 PpbBuffer* temp_buffer = buffer_; | |
300 if (buffer_) | |
301 buffer_ = NULL; | |
302 return temp_buffer; | |
303 } | |
304 | |
305 private: | |
306 PpbBuffer* buffer_; | |
307 cdm::AudioFormat format_; | |
308 | |
309 DISALLOW_COPY_AND_ASSIGN(AudioFramesImpl); | |
310 }; | |
311 | |
312 } // namespace media | |
313 | |
314 #endif // MEDIA_CDM_PPAPI_CDM_HELPERS_H_ | |
OLD | NEW |