Chromium Code Reviews| 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 |