| OLD | NEW |
| (Empty) |
| 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 <cstring> | |
| 6 #include <map> | |
| 7 #include <string> | |
| 8 #include <utility> | |
| 9 #include <vector> | |
| 10 | |
| 11 #include "base/basictypes.h" | |
| 12 #include "base/compiler_specific.h" | |
| 13 #include "ppapi/c/pp_errors.h" | |
| 14 #include "ppapi/c/pp_stdint.h" | |
| 15 #include "ppapi/c/private/pp_content_decryptor.h" | |
| 16 #include "ppapi/cpp/completion_callback.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" | |
| 22 #include "ppapi/cpp/pass_ref.h" | |
| 23 #include "ppapi/cpp/private/content_decryptor_private.h" | |
| 24 #include "ppapi/cpp/resource.h" | |
| 25 #include "ppapi/cpp/var.h" | |
| 26 #include "ppapi/cpp/var_array_buffer.h" | |
| 27 #include "ppapi/utility/completion_callback_factory.h" | |
| 28 #include "webkit/renderer/media/crypto/ppapi/cdm/content_decryption_module.h" | |
| 29 #include "webkit/renderer/media/crypto/ppapi/linked_ptr.h" | |
| 30 | |
| 31 #if defined(CHECK_DOCUMENT_URL) | |
| 32 #include "ppapi/cpp/dev/url_util_dev.h" | |
| 33 #include "ppapi/cpp/instance_handle.h" | |
| 34 #endif // defined(CHECK_DOCUMENT_URL) | |
| 35 | |
| 36 namespace { | |
| 37 | |
| 38 bool IsMainThread() { | |
| 39 return pp::Module::Get()->core()->IsMainThread(); | |
| 40 } | |
| 41 | |
| 42 // Posts a task to run |cb| on the main thread. The task is posted even if the | |
| 43 // current thread is the main thread. | |
| 44 void PostOnMain(pp::CompletionCallback cb) { | |
| 45 pp::Module::Get()->core()->CallOnMainThread(0, cb, PP_OK); | |
| 46 } | |
| 47 | |
| 48 // Ensures |cb| is called on the main thread, either because the current thread | |
| 49 // is the main thread or by posting it to the main thread. | |
| 50 void CallOnMain(pp::CompletionCallback cb) { | |
| 51 // TODO(tomfinegan): This is only necessary because PPAPI doesn't allow calls | |
| 52 // off the main thread yet. Remove this once the change lands. | |
| 53 if (IsMainThread()) | |
| 54 cb.Run(PP_OK); | |
| 55 else | |
| 56 PostOnMain(cb); | |
| 57 } | |
| 58 | |
| 59 // Configures a cdm::InputBuffer. |subsamples| must exist as long as | |
| 60 // |input_buffer| is in use. | |
| 61 void ConfigureInputBuffer( | |
| 62 const pp::Buffer_Dev& encrypted_buffer, | |
| 63 const PP_EncryptedBlockInfo& encrypted_block_info, | |
| 64 std::vector<cdm::SubsampleEntry>* subsamples, | |
| 65 cdm::InputBuffer* input_buffer) { | |
| 66 PP_DCHECK(subsamples); | |
| 67 PP_DCHECK(!encrypted_buffer.is_null()); | |
| 68 | |
| 69 input_buffer->data = static_cast<uint8_t*>(encrypted_buffer.data()); | |
| 70 input_buffer->data_size = encrypted_block_info.data_size; | |
| 71 PP_DCHECK(encrypted_buffer.size() >= | |
| 72 static_cast<uint32_t>(input_buffer->data_size)); | |
| 73 input_buffer->data_offset = encrypted_block_info.data_offset; | |
| 74 | |
| 75 PP_DCHECK(encrypted_block_info.key_id_size <= | |
| 76 arraysize(encrypted_block_info.key_id)); | |
| 77 input_buffer->key_id_size = encrypted_block_info.key_id_size; | |
| 78 input_buffer->key_id = input_buffer->key_id_size > 0 ? | |
| 79 encrypted_block_info.key_id : NULL; | |
| 80 | |
| 81 PP_DCHECK(encrypted_block_info.iv_size <= arraysize(encrypted_block_info.iv)); | |
| 82 input_buffer->iv_size = encrypted_block_info.iv_size; | |
| 83 input_buffer->iv = encrypted_block_info.iv_size > 0 ? | |
| 84 encrypted_block_info.iv : NULL; | |
| 85 | |
| 86 input_buffer->num_subsamples = encrypted_block_info.num_subsamples; | |
| 87 if (encrypted_block_info.num_subsamples > 0) { | |
| 88 subsamples->reserve(encrypted_block_info.num_subsamples); | |
| 89 | |
| 90 for (uint32_t i = 0; i < encrypted_block_info.num_subsamples; ++i) { | |
| 91 subsamples->push_back(cdm::SubsampleEntry( | |
| 92 encrypted_block_info.subsamples[i].clear_bytes, | |
| 93 encrypted_block_info.subsamples[i].cipher_bytes)); | |
| 94 } | |
| 95 | |
| 96 input_buffer->subsamples = &(*subsamples)[0]; | |
| 97 } | |
| 98 | |
| 99 input_buffer->timestamp = encrypted_block_info.tracking_info.timestamp; | |
| 100 } | |
| 101 | |
| 102 PP_DecryptResult CdmStatusToPpDecryptResult(cdm::Status status) { | |
| 103 switch (status) { | |
| 104 case cdm::kSuccess: | |
| 105 return PP_DECRYPTRESULT_SUCCESS; | |
| 106 case cdm::kNoKey: | |
| 107 return PP_DECRYPTRESULT_DECRYPT_NOKEY; | |
| 108 case cdm::kNeedMoreData: | |
| 109 return PP_DECRYPTRESULT_NEEDMOREDATA; | |
| 110 case cdm::kDecryptError: | |
| 111 return PP_DECRYPTRESULT_DECRYPT_ERROR; | |
| 112 case cdm::kDecodeError: | |
| 113 return PP_DECRYPTRESULT_DECODE_ERROR; | |
| 114 default: | |
| 115 PP_NOTREACHED(); | |
| 116 return PP_DECRYPTRESULT_DECODE_ERROR; | |
| 117 } | |
| 118 } | |
| 119 | |
| 120 PP_DecryptedFrameFormat CdmVideoFormatToPpDecryptedFrameFormat( | |
| 121 cdm::VideoFormat format) { | |
| 122 switch (format) { | |
| 123 case cdm::kYv12: | |
| 124 return PP_DECRYPTEDFRAMEFORMAT_YV12; | |
| 125 case cdm::kI420: | |
| 126 return PP_DECRYPTEDFRAMEFORMAT_I420; | |
| 127 default: | |
| 128 return PP_DECRYPTEDFRAMEFORMAT_UNKNOWN; | |
| 129 } | |
| 130 } | |
| 131 | |
| 132 cdm::AudioDecoderConfig::AudioCodec PpAudioCodecToCdmAudioCodec( | |
| 133 PP_AudioCodec codec) { | |
| 134 switch (codec) { | |
| 135 case PP_AUDIOCODEC_VORBIS: | |
| 136 return cdm::AudioDecoderConfig::kCodecVorbis; | |
| 137 case PP_AUDIOCODEC_AAC: | |
| 138 return cdm::AudioDecoderConfig::kCodecAac; | |
| 139 default: | |
| 140 return cdm::AudioDecoderConfig::kUnknownAudioCodec; | |
| 141 } | |
| 142 } | |
| 143 | |
| 144 cdm::VideoDecoderConfig::VideoCodec PpVideoCodecToCdmVideoCodec( | |
| 145 PP_VideoCodec codec) { | |
| 146 switch (codec) { | |
| 147 case PP_VIDEOCODEC_VP8: | |
| 148 return cdm::VideoDecoderConfig::kCodecVp8; | |
| 149 case PP_VIDEOCODEC_H264: | |
| 150 return cdm::VideoDecoderConfig::kCodecH264; | |
| 151 default: | |
| 152 return cdm::VideoDecoderConfig::kUnknownVideoCodec; | |
| 153 } | |
| 154 } | |
| 155 | |
| 156 cdm::VideoDecoderConfig::VideoCodecProfile PpVCProfileToCdmVCProfile( | |
| 157 PP_VideoCodecProfile profile) { | |
| 158 switch (profile) { | |
| 159 case PP_VIDEOCODECPROFILE_VP8_MAIN: | |
| 160 return cdm::VideoDecoderConfig::kVp8ProfileMain; | |
| 161 case PP_VIDEOCODECPROFILE_H264_BASELINE: | |
| 162 return cdm::VideoDecoderConfig::kH264ProfileBaseline; | |
| 163 case PP_VIDEOCODECPROFILE_H264_MAIN: | |
| 164 return cdm::VideoDecoderConfig::kH264ProfileMain; | |
| 165 case PP_VIDEOCODECPROFILE_H264_EXTENDED: | |
| 166 return cdm::VideoDecoderConfig::kH264ProfileExtended; | |
| 167 case PP_VIDEOCODECPROFILE_H264_HIGH: | |
| 168 return cdm::VideoDecoderConfig::kH264ProfileHigh; | |
| 169 case PP_VIDEOCODECPROFILE_H264_HIGH_10: | |
| 170 return cdm::VideoDecoderConfig::kH264ProfileHigh10; | |
| 171 case PP_VIDEOCODECPROFILE_H264_HIGH_422: | |
| 172 return cdm::VideoDecoderConfig::kH264ProfileHigh422; | |
| 173 case PP_VIDEOCODECPROFILE_H264_HIGH_444_PREDICTIVE: | |
| 174 return cdm::VideoDecoderConfig::kH264ProfileHigh444Predictive; | |
| 175 default: | |
| 176 return cdm::VideoDecoderConfig::kUnknownVideoCodecProfile; | |
| 177 } | |
| 178 } | |
| 179 | |
| 180 cdm::VideoFormat PpDecryptedFrameFormatToCdmVideoFormat( | |
| 181 PP_DecryptedFrameFormat format) { | |
| 182 switch (format) { | |
| 183 case PP_DECRYPTEDFRAMEFORMAT_YV12: | |
| 184 return cdm::kYv12; | |
| 185 case PP_DECRYPTEDFRAMEFORMAT_I420: | |
| 186 return cdm::kI420; | |
| 187 default: | |
| 188 return cdm::kUnknownVideoFormat; | |
| 189 } | |
| 190 } | |
| 191 | |
| 192 cdm::StreamType PpDecryptorStreamTypeToCdmStreamType( | |
| 193 PP_DecryptorStreamType stream_type) { | |
| 194 switch (stream_type) { | |
| 195 case PP_DECRYPTORSTREAMTYPE_AUDIO: | |
| 196 return cdm::kStreamTypeAudio; | |
| 197 case PP_DECRYPTORSTREAMTYPE_VIDEO: | |
| 198 return cdm::kStreamTypeVideo; | |
| 199 } | |
| 200 | |
| 201 PP_NOTREACHED(); | |
| 202 return cdm::kStreamTypeVideo; | |
| 203 } | |
| 204 | |
| 205 } // namespace | |
| 206 | |
| 207 namespace webkit_media { | |
| 208 | |
| 209 // cdm::Buffer implementation that provides access to memory owned by a | |
| 210 // pp::Buffer_Dev. | |
| 211 // This class holds a reference to the Buffer_Dev throughout its lifetime. | |
| 212 // TODO(xhwang): Find a better name. It's confusing to have PpbBuffer, | |
| 213 // pp::Buffer_Dev and PPB_Buffer_Dev. | |
| 214 class PpbBuffer : public cdm::Buffer { | |
| 215 public: | |
| 216 static PpbBuffer* Create(const pp::Buffer_Dev& buffer, uint32_t buffer_id) { | |
| 217 PP_DCHECK(buffer.data()); | |
| 218 PP_DCHECK(buffer.size()); | |
| 219 PP_DCHECK(buffer_id); | |
| 220 return new PpbBuffer(buffer, buffer_id); | |
| 221 } | |
| 222 | |
| 223 // cdm::Buffer implementation. | |
| 224 virtual void Destroy() OVERRIDE { delete this; } | |
| 225 | |
| 226 virtual int32_t Capacity() const OVERRIDE { return buffer_.size(); } | |
| 227 | |
| 228 virtual uint8_t* Data() OVERRIDE { | |
| 229 return static_cast<uint8_t*>(buffer_.data()); | |
| 230 } | |
| 231 | |
| 232 virtual void SetSize(int32_t size) OVERRIDE { | |
| 233 PP_DCHECK(size >= 0); | |
| 234 PP_DCHECK(size < Capacity()); | |
| 235 if (size < 0 || size > Capacity()) { | |
| 236 size_ = 0; | |
| 237 return; | |
| 238 } | |
| 239 | |
| 240 size_ = size; | |
| 241 } | |
| 242 | |
| 243 virtual int32_t Size() const OVERRIDE { return size_; } | |
| 244 | |
| 245 pp::Buffer_Dev buffer_dev() const { return buffer_; } | |
| 246 | |
| 247 uint32_t buffer_id() const { return buffer_id_; } | |
| 248 | |
| 249 private: | |
| 250 PpbBuffer(pp::Buffer_Dev buffer, uint32_t buffer_id) | |
| 251 : buffer_(buffer), | |
| 252 buffer_id_(buffer_id), | |
| 253 size_(0) {} | |
| 254 virtual ~PpbBuffer() {} | |
| 255 | |
| 256 pp::Buffer_Dev buffer_; | |
| 257 uint32_t buffer_id_; | |
| 258 int32_t size_; | |
| 259 | |
| 260 DISALLOW_COPY_AND_ASSIGN(PpbBuffer); | |
| 261 }; | |
| 262 | |
| 263 class PpbBufferAllocator { | |
| 264 public: | |
| 265 explicit PpbBufferAllocator(pp::Instance* instance) | |
| 266 : instance_(instance), | |
| 267 next_buffer_id_(1) {} | |
| 268 ~PpbBufferAllocator() {} | |
| 269 | |
| 270 cdm::Buffer* Allocate(int32_t capacity); | |
| 271 | |
| 272 // Releases the buffer with |buffer_id|. A buffer can be recycled after | |
| 273 // it is released. | |
| 274 void Release(uint32_t buffer_id); | |
| 275 | |
| 276 private: | |
| 277 typedef std::map<uint32_t, pp::Buffer_Dev> AllocatedBufferMap; | |
| 278 typedef std::multimap<int, std::pair<uint32_t, pp::Buffer_Dev> > | |
| 279 FreeBufferMap; | |
| 280 | |
| 281 // Always pad new allocated buffer so that we don't need to reallocate | |
| 282 // buffers frequently if requested sizes fluctuate slightly. | |
| 283 static const int kBufferPadding = 512; | |
| 284 | |
| 285 // Maximum number of free buffers we can keep when allocating new buffers. | |
| 286 static const int kFreeLimit = 3; | |
| 287 | |
| 288 pp::Buffer_Dev AllocateNewBuffer(int capacity); | |
| 289 | |
| 290 pp::Instance* const instance_; | |
| 291 uint32_t next_buffer_id_; | |
| 292 AllocatedBufferMap allocated_buffers_; | |
| 293 FreeBufferMap free_buffers_; | |
| 294 | |
| 295 DISALLOW_COPY_AND_ASSIGN(PpbBufferAllocator); | |
| 296 }; | |
| 297 | |
| 298 cdm::Buffer* PpbBufferAllocator::Allocate(int32_t capacity) { | |
| 299 PP_DCHECK(IsMainThread()); | |
| 300 | |
| 301 if (capacity <= 0) | |
| 302 return NULL; | |
| 303 | |
| 304 pp::Buffer_Dev buffer; | |
| 305 uint32_t buffer_id = 0; | |
| 306 | |
| 307 // Reuse a buffer in the free list if there is one that fits |capacity|. | |
| 308 // Otherwise, create a new one. | |
| 309 FreeBufferMap::iterator found = free_buffers_.lower_bound(capacity); | |
| 310 if (found == free_buffers_.end()) { | |
| 311 // TODO(xhwang): Report statistics about how many new buffers are allocated. | |
| 312 buffer = AllocateNewBuffer(capacity); | |
| 313 if (buffer.is_null()) | |
| 314 return NULL; | |
| 315 buffer_id = next_buffer_id_++; | |
| 316 } else { | |
| 317 buffer = found->second.second; | |
| 318 buffer_id = found->second.first; | |
| 319 free_buffers_.erase(found); | |
| 320 } | |
| 321 | |
| 322 allocated_buffers_.insert(std::make_pair(buffer_id, buffer)); | |
| 323 | |
| 324 return PpbBuffer::Create(buffer, buffer_id); | |
| 325 } | |
| 326 | |
| 327 void PpbBufferAllocator::Release(uint32_t buffer_id) { | |
| 328 if (!buffer_id) | |
| 329 return; | |
| 330 | |
| 331 AllocatedBufferMap::iterator found = allocated_buffers_.find(buffer_id); | |
| 332 if (found == allocated_buffers_.end()) | |
| 333 return; | |
| 334 | |
| 335 pp::Buffer_Dev& buffer = found->second; | |
| 336 free_buffers_.insert( | |
| 337 std::make_pair(buffer.size(), std::make_pair(buffer_id, buffer))); | |
| 338 | |
| 339 allocated_buffers_.erase(found); | |
| 340 } | |
| 341 | |
| 342 pp::Buffer_Dev PpbBufferAllocator::AllocateNewBuffer(int32_t capacity) { | |
| 343 // Destroy the smallest buffer before allocating a new bigger buffer if the | |
| 344 // number of free buffers exceeds a limit. This mechanism helps avoid ending | |
| 345 // up with too many small buffers, which could happen if the size to be | |
| 346 // allocated keeps increasing. | |
| 347 if (free_buffers_.size() >= static_cast<uint32_t>(kFreeLimit)) | |
| 348 free_buffers_.erase(free_buffers_.begin()); | |
| 349 | |
| 350 // Creation of pp::Buffer_Dev is expensive! It involves synchronous IPC calls. | |
| 351 // That's why we try to avoid AllocateNewBuffer() as much as we can. | |
| 352 return pp::Buffer_Dev(instance_, capacity + kBufferPadding); | |
| 353 } | |
| 354 | |
| 355 class DecryptedBlockImpl : public cdm::DecryptedBlock { | |
| 356 public: | |
| 357 DecryptedBlockImpl() : buffer_(NULL), timestamp_(0) {} | |
| 358 virtual ~DecryptedBlockImpl() { if (buffer_) buffer_->Destroy(); } | |
| 359 | |
| 360 virtual void SetDecryptedBuffer(cdm::Buffer* buffer) OVERRIDE { | |
| 361 buffer_ = static_cast<PpbBuffer*>(buffer); | |
| 362 } | |
| 363 virtual cdm::Buffer* DecryptedBuffer() OVERRIDE { return buffer_; } | |
| 364 | |
| 365 virtual void SetTimestamp(int64_t timestamp) OVERRIDE { | |
| 366 timestamp_ = timestamp; | |
| 367 } | |
| 368 virtual int64_t Timestamp() const OVERRIDE { return timestamp_; } | |
| 369 | |
| 370 private: | |
| 371 PpbBuffer* buffer_; | |
| 372 int64_t timestamp_; | |
| 373 | |
| 374 DISALLOW_COPY_AND_ASSIGN(DecryptedBlockImpl); | |
| 375 }; | |
| 376 | |
| 377 class VideoFrameImpl : public cdm::VideoFrame { | |
| 378 public: | |
| 379 VideoFrameImpl(); | |
| 380 virtual ~VideoFrameImpl(); | |
| 381 | |
| 382 virtual void SetFormat(cdm::VideoFormat format) OVERRIDE { | |
| 383 format_ = format; | |
| 384 } | |
| 385 virtual cdm::VideoFormat Format() const OVERRIDE { return format_; } | |
| 386 | |
| 387 virtual void SetSize(cdm::Size size) OVERRIDE { size_ = size; } | |
| 388 virtual cdm::Size Size() const OVERRIDE { return size_; } | |
| 389 | |
| 390 virtual void SetFrameBuffer(cdm::Buffer* frame_buffer) OVERRIDE { | |
| 391 frame_buffer_ = static_cast<PpbBuffer*>(frame_buffer); | |
| 392 } | |
| 393 virtual cdm::Buffer* FrameBuffer() OVERRIDE { return frame_buffer_; } | |
| 394 | |
| 395 virtual void SetPlaneOffset(cdm::VideoFrame::VideoPlane plane, | |
| 396 int32_t offset) OVERRIDE { | |
| 397 PP_DCHECK(0 <= plane && plane < kMaxPlanes); | |
| 398 PP_DCHECK(offset >= 0); | |
| 399 plane_offsets_[plane] = offset; | |
| 400 } | |
| 401 virtual int32_t PlaneOffset(VideoPlane plane) OVERRIDE { | |
| 402 PP_DCHECK(0 <= plane && plane < kMaxPlanes); | |
| 403 return plane_offsets_[plane]; | |
| 404 } | |
| 405 | |
| 406 virtual void SetStride(VideoPlane plane, int32_t stride) OVERRIDE { | |
| 407 PP_DCHECK(0 <= plane && plane < kMaxPlanes); | |
| 408 strides_[plane] = stride; | |
| 409 } | |
| 410 virtual int32_t Stride(VideoPlane plane) OVERRIDE { | |
| 411 PP_DCHECK(0 <= plane && plane < kMaxPlanes); | |
| 412 return strides_[plane]; | |
| 413 } | |
| 414 | |
| 415 virtual void SetTimestamp(int64_t timestamp) OVERRIDE { | |
| 416 timestamp_ = timestamp; | |
| 417 } | |
| 418 virtual int64_t Timestamp() const OVERRIDE { return timestamp_; } | |
| 419 | |
| 420 private: | |
| 421 // The video buffer format. | |
| 422 cdm::VideoFormat format_; | |
| 423 | |
| 424 // Width and height of the video frame. | |
| 425 cdm::Size size_; | |
| 426 | |
| 427 // The video frame buffer. | |
| 428 PpbBuffer* frame_buffer_; | |
| 429 | |
| 430 // Array of data pointers to each plane in the video frame buffer. | |
| 431 int32_t plane_offsets_[kMaxPlanes]; | |
| 432 | |
| 433 // Array of strides for each plane, typically greater or equal to the width | |
| 434 // of the surface divided by the horizontal sampling period. Note that | |
| 435 // strides can be negative. | |
| 436 int32_t strides_[kMaxPlanes]; | |
| 437 | |
| 438 // Presentation timestamp in microseconds. | |
| 439 int64_t timestamp_; | |
| 440 | |
| 441 DISALLOW_COPY_AND_ASSIGN(VideoFrameImpl); | |
| 442 }; | |
| 443 | |
| 444 VideoFrameImpl::VideoFrameImpl() | |
| 445 : format_(cdm::kUnknownVideoFormat), | |
| 446 frame_buffer_(NULL), | |
| 447 timestamp_(0) { | |
| 448 for (int32_t i = 0; i < kMaxPlanes; ++i) { | |
| 449 plane_offsets_[i] = 0; | |
| 450 strides_[i] = 0; | |
| 451 } | |
| 452 } | |
| 453 | |
| 454 VideoFrameImpl::~VideoFrameImpl() { | |
| 455 if (frame_buffer_) | |
| 456 frame_buffer_->Destroy(); | |
| 457 } | |
| 458 | |
| 459 class AudioFramesImpl : public cdm::AudioFrames { | |
| 460 public: | |
| 461 AudioFramesImpl() : buffer_(NULL) {} | |
| 462 virtual ~AudioFramesImpl() { | |
| 463 if (buffer_) | |
| 464 buffer_->Destroy(); | |
| 465 } | |
| 466 | |
| 467 // AudioFrames implementation. | |
| 468 virtual void SetFrameBuffer(cdm::Buffer* buffer) OVERRIDE { | |
| 469 buffer_ = static_cast<PpbBuffer*>(buffer); | |
| 470 } | |
| 471 virtual cdm::Buffer* FrameBuffer() OVERRIDE { | |
| 472 return buffer_; | |
| 473 } | |
| 474 | |
| 475 private: | |
| 476 PpbBuffer* buffer_; | |
| 477 | |
| 478 DISALLOW_COPY_AND_ASSIGN(AudioFramesImpl); | |
| 479 }; | |
| 480 | |
| 481 // GetCdmHostFunc implementation. | |
| 482 void* GetCdmHost(int host_interface_version, void* user_data); | |
| 483 | |
| 484 // A wrapper class for abstracting away PPAPI interaction and threading for a | |
| 485 // Content Decryption Module (CDM). | |
| 486 class CdmWrapper : public pp::Instance, | |
| 487 public pp::ContentDecryptor_Private, | |
| 488 public cdm::Host { | |
| 489 public: | |
| 490 CdmWrapper(PP_Instance instance, pp::Module* module); | |
| 491 virtual ~CdmWrapper(); | |
| 492 | |
| 493 // pp::Instance implementation. | |
| 494 virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]) { | |
| 495 return true; | |
| 496 } | |
| 497 | |
| 498 // PPP_ContentDecryptor_Private implementation. | |
| 499 // Note: Results of calls to these methods must be reported through the | |
| 500 // PPB_ContentDecryptor_Private interface. | |
| 501 virtual void GenerateKeyRequest(const std::string& key_system, | |
| 502 const std::string& type, | |
| 503 pp::VarArrayBuffer init_data) OVERRIDE; | |
| 504 virtual void AddKey(const std::string& session_id, | |
| 505 pp::VarArrayBuffer key, | |
| 506 pp::VarArrayBuffer init_data) OVERRIDE; | |
| 507 virtual void CancelKeyRequest(const std::string& session_id) OVERRIDE; | |
| 508 virtual void Decrypt( | |
| 509 pp::Buffer_Dev encrypted_buffer, | |
| 510 const PP_EncryptedBlockInfo& encrypted_block_info) OVERRIDE; | |
| 511 virtual void InitializeAudioDecoder( | |
| 512 const PP_AudioDecoderConfig& decoder_config, | |
| 513 pp::Buffer_Dev extra_data_buffer) OVERRIDE; | |
| 514 virtual void InitializeVideoDecoder( | |
| 515 const PP_VideoDecoderConfig& decoder_config, | |
| 516 pp::Buffer_Dev extra_data_buffer) OVERRIDE; | |
| 517 virtual void DeinitializeDecoder(PP_DecryptorStreamType decoder_type, | |
| 518 uint32_t request_id) OVERRIDE; | |
| 519 virtual void ResetDecoder(PP_DecryptorStreamType decoder_type, | |
| 520 uint32_t request_id) OVERRIDE; | |
| 521 virtual void DecryptAndDecode( | |
| 522 PP_DecryptorStreamType decoder_type, | |
| 523 pp::Buffer_Dev encrypted_buffer, | |
| 524 const PP_EncryptedBlockInfo& encrypted_block_info) OVERRIDE; | |
| 525 | |
| 526 // cdm::Host implementation. | |
| 527 virtual cdm::Buffer* Allocate(int32_t capacity) OVERRIDE; | |
| 528 virtual void SetTimer(int64_t delay_ms, void* context) OVERRIDE; | |
| 529 virtual double GetCurrentWallTimeInSeconds() OVERRIDE; | |
| 530 virtual void SendKeyMessage( | |
| 531 const char* session_id, int32_t session_id_length, | |
| 532 const char* message, int32_t message_length, | |
| 533 const char* default_url, int32_t default_url_length) OVERRIDE; | |
| 534 virtual void SendKeyError(const char* session_id, | |
| 535 int32_t session_id_length, | |
| 536 cdm::MediaKeyError error_code, | |
| 537 uint32_t system_code) OVERRIDE; | |
| 538 virtual void GetPrivateData(int32_t* instance, | |
| 539 GetPrivateInterface* get_interface) OVERRIDE; | |
| 540 | |
| 541 private: | |
| 542 struct SessionInfo { | |
| 543 SessionInfo(const std::string& key_system_in, | |
| 544 const std::string& session_id_in) | |
| 545 : key_system(key_system_in), | |
| 546 session_id(session_id_in) {} | |
| 547 const std::string key_system; | |
| 548 const std::string session_id; | |
| 549 }; | |
| 550 | |
| 551 typedef linked_ptr<DecryptedBlockImpl> LinkedDecryptedBlock; | |
| 552 typedef linked_ptr<VideoFrameImpl> LinkedVideoFrame; | |
| 553 typedef linked_ptr<AudioFramesImpl> LinkedAudioFrames; | |
| 554 | |
| 555 bool CreateCdmInstance(const std::string& key_system); | |
| 556 | |
| 557 void SendUnknownKeyError(const std::string& key_system, | |
| 558 const std::string& session_id); | |
| 559 | |
| 560 void SendKeyAdded(const std::string& key_system, | |
| 561 const std::string& session_id); | |
| 562 | |
| 563 void SendKeyErrorInternal(const std::string& key_system, | |
| 564 const std::string& session_id, | |
| 565 cdm::MediaKeyError error_code, | |
| 566 uint32_t system_code); | |
| 567 | |
| 568 // <code>PPB_ContentDecryptor_Private</code> dispatchers. These are passed to | |
| 569 // <code>callback_factory_</code> to ensure that calls into | |
| 570 // <code>PPP_ContentDecryptor_Private</code> are asynchronous. | |
| 571 void KeyAdded(int32_t result, const SessionInfo& session_info); | |
| 572 void KeyMessage(int32_t result, | |
| 573 const SessionInfo& session_info, | |
| 574 const std::vector<uint8>& message, | |
| 575 const std::string& default_url); | |
| 576 void KeyError(int32_t result, | |
| 577 const SessionInfo& session_info, | |
| 578 cdm::MediaKeyError error_code, | |
| 579 uint32_t system_code); | |
| 580 void DeliverBlock(int32_t result, | |
| 581 const cdm::Status& status, | |
| 582 const LinkedDecryptedBlock& decrypted_block, | |
| 583 const PP_DecryptTrackingInfo& tracking_info); | |
| 584 void DecoderInitializeDone(int32_t result, | |
| 585 PP_DecryptorStreamType decoder_type, | |
| 586 uint32_t request_id, | |
| 587 bool success); | |
| 588 void DecoderDeinitializeDone(int32_t result, | |
| 589 PP_DecryptorStreamType decoder_type, | |
| 590 uint32_t request_id); | |
| 591 void DecoderResetDone(int32_t result, | |
| 592 PP_DecryptorStreamType decoder_type, | |
| 593 uint32_t request_id); | |
| 594 void DeliverFrame(int32_t result, | |
| 595 const cdm::Status& status, | |
| 596 const LinkedVideoFrame& video_frame, | |
| 597 const PP_DecryptTrackingInfo& tracking_info); | |
| 598 void DeliverSamples(int32_t result, | |
| 599 const cdm::Status& status, | |
| 600 const LinkedAudioFrames& audio_frames, | |
| 601 const PP_DecryptTrackingInfo& tracking_info); | |
| 602 | |
| 603 // Helper for SetTimer(). | |
| 604 void TimerExpired(int32_t result, void* context); | |
| 605 | |
| 606 bool IsValidVideoFrame(const LinkedVideoFrame& video_frame); | |
| 607 | |
| 608 PpbBufferAllocator allocator_; | |
| 609 pp::CompletionCallbackFactory<CdmWrapper> callback_factory_; | |
| 610 cdm::ContentDecryptionModule* cdm_; | |
| 611 std::string key_system_; | |
| 612 | |
| 613 DISALLOW_COPY_AND_ASSIGN(CdmWrapper); | |
| 614 }; | |
| 615 | |
| 616 CdmWrapper::CdmWrapper(PP_Instance instance, pp::Module* module) | |
| 617 : pp::Instance(instance), | |
| 618 pp::ContentDecryptor_Private(this), | |
| 619 allocator_(this), | |
| 620 cdm_(NULL) { | |
| 621 callback_factory_.Initialize(this); | |
| 622 } | |
| 623 | |
| 624 CdmWrapper::~CdmWrapper() { | |
| 625 if (cdm_) | |
| 626 cdm_->Destroy(); | |
| 627 } | |
| 628 | |
| 629 bool CdmWrapper::CreateCdmInstance(const std::string& key_system) { | |
| 630 PP_DCHECK(!cdm_); | |
| 631 cdm_ = static_cast<cdm::ContentDecryptionModule*>( | |
| 632 ::CreateCdmInstance(cdm::kCdmInterfaceVersion, | |
| 633 key_system.data(), key_system.size(), | |
| 634 GetCdmHost, this)); | |
| 635 | |
| 636 return (cdm_ != NULL); | |
| 637 } | |
| 638 | |
| 639 void CdmWrapper::GenerateKeyRequest(const std::string& key_system, | |
| 640 const std::string& type, | |
| 641 pp::VarArrayBuffer init_data) { | |
| 642 PP_DCHECK(!key_system.empty()); | |
| 643 PP_DCHECK(key_system_.empty() || key_system_ == key_system); | |
| 644 | |
| 645 #if defined(CHECK_DOCUMENT_URL) | |
| 646 PP_URLComponents_Dev url_components = {}; | |
| 647 pp::Var href = pp::URLUtil_Dev::Get()->GetDocumentURL( | |
| 648 pp::InstanceHandle(pp_instance()), &url_components); | |
| 649 PP_DCHECK(href.is_string()); | |
| 650 PP_DCHECK(!href.AsString().empty()); | |
| 651 PP_DCHECK(url_components.host.begin); | |
| 652 PP_DCHECK(0 < url_components.host.len); | |
| 653 #endif // defined(CHECK_DOCUMENT_URL) | |
| 654 | |
| 655 if (!cdm_) { | |
| 656 if (!CreateCdmInstance(key_system)) { | |
| 657 SendUnknownKeyError(key_system, std::string()); | |
| 658 return; | |
| 659 } | |
| 660 } | |
| 661 PP_DCHECK(cdm_); | |
| 662 | |
| 663 // Must be set here in case the CDM synchronously calls a cdm::Host method. | |
| 664 // Clear below on error. | |
| 665 // TODO(ddorwin): Set/clear key_system_ & cdm_ at same time; clear both on | |
| 666 // error below. | |
| 667 key_system_ = key_system; | |
| 668 cdm::Status status = cdm_->GenerateKeyRequest( | |
| 669 type.data(), type.size(), | |
| 670 static_cast<const uint8_t*>(init_data.Map()), | |
| 671 init_data.ByteLength()); | |
| 672 PP_DCHECK(status == cdm::kSuccess || status == cdm::kSessionError); | |
| 673 if (status != cdm::kSuccess) { | |
| 674 key_system_.clear(); // See comment above. | |
| 675 return; | |
| 676 } | |
| 677 | |
| 678 key_system_ = key_system; | |
| 679 } | |
| 680 | |
| 681 void CdmWrapper::AddKey(const std::string& session_id, | |
| 682 pp::VarArrayBuffer key, | |
| 683 pp::VarArrayBuffer init_data) { | |
| 684 PP_DCHECK(cdm_); // GenerateKeyRequest() should have succeeded. | |
| 685 if (!cdm_) { | |
| 686 SendUnknownKeyError(key_system_, session_id); | |
| 687 return; | |
| 688 } | |
| 689 | |
| 690 const uint8_t* key_ptr = static_cast<const uint8_t*>(key.Map()); | |
| 691 int key_size = key.ByteLength(); | |
| 692 const uint8_t* init_data_ptr = static_cast<const uint8_t*>(init_data.Map()); | |
| 693 int init_data_size = init_data.ByteLength(); | |
| 694 PP_DCHECK(!init_data_ptr == !init_data_size); | |
| 695 | |
| 696 if (!key_ptr || key_size <= 0) { | |
| 697 SendUnknownKeyError(key_system_, session_id); | |
| 698 return; | |
| 699 } | |
| 700 | |
| 701 cdm::Status status = cdm_->AddKey(session_id.data(), session_id.size(), | |
| 702 key_ptr, key_size, | |
| 703 init_data_ptr, init_data_size); | |
| 704 PP_DCHECK(status == cdm::kSuccess || status == cdm::kSessionError); | |
| 705 if (status != cdm::kSuccess) { | |
| 706 SendUnknownKeyError(key_system_, session_id); | |
| 707 return; | |
| 708 } | |
| 709 | |
| 710 SendKeyAdded(key_system_, session_id); | |
| 711 } | |
| 712 | |
| 713 void CdmWrapper::CancelKeyRequest(const std::string& session_id) { | |
| 714 PP_DCHECK(cdm_); // GenerateKeyRequest() should have succeeded. | |
| 715 if (!cdm_) { | |
| 716 SendUnknownKeyError(key_system_, session_id); | |
| 717 return; | |
| 718 } | |
| 719 | |
| 720 cdm::Status status = cdm_->CancelKeyRequest(session_id.data(), | |
| 721 session_id.size()); | |
| 722 PP_DCHECK(status == cdm::kSuccess || status == cdm::kSessionError); | |
| 723 if (status != cdm::kSuccess) | |
| 724 SendUnknownKeyError(key_system_, session_id); | |
| 725 } | |
| 726 | |
| 727 // Note: In the following decryption/decoding related functions, errors are NOT | |
| 728 // reported via KeyError, but are reported via corresponding PPB calls. | |
| 729 | |
| 730 void CdmWrapper::Decrypt(pp::Buffer_Dev encrypted_buffer, | |
| 731 const PP_EncryptedBlockInfo& encrypted_block_info) { | |
| 732 PP_DCHECK(cdm_); // GenerateKeyRequest() should have succeeded. | |
| 733 PP_DCHECK(!encrypted_buffer.is_null()); | |
| 734 | |
| 735 // Release a buffer that the caller indicated it is finished with. | |
| 736 allocator_.Release(encrypted_block_info.tracking_info.buffer_id); | |
| 737 | |
| 738 cdm::Status status = cdm::kDecryptError; | |
| 739 LinkedDecryptedBlock decrypted_block(new DecryptedBlockImpl()); | |
| 740 | |
| 741 if (cdm_) { | |
| 742 cdm::InputBuffer input_buffer; | |
| 743 std::vector<cdm::SubsampleEntry> subsamples; | |
| 744 ConfigureInputBuffer(encrypted_buffer, encrypted_block_info, &subsamples, | |
| 745 &input_buffer); | |
| 746 status = cdm_->Decrypt(input_buffer, decrypted_block.get()); | |
| 747 PP_DCHECK(status != cdm::kSuccess || | |
| 748 (decrypted_block->DecryptedBuffer() && | |
| 749 decrypted_block->DecryptedBuffer()->Size())); | |
| 750 } | |
| 751 | |
| 752 CallOnMain(callback_factory_.NewCallback( | |
| 753 &CdmWrapper::DeliverBlock, | |
| 754 status, | |
| 755 decrypted_block, | |
| 756 encrypted_block_info.tracking_info)); | |
| 757 } | |
| 758 | |
| 759 void CdmWrapper::InitializeAudioDecoder( | |
| 760 const PP_AudioDecoderConfig& decoder_config, | |
| 761 pp::Buffer_Dev extra_data_buffer) { | |
| 762 PP_DCHECK(cdm_); // GenerateKeyRequest() should have succeeded. | |
| 763 | |
| 764 cdm::Status status = cdm::kSessionError; | |
| 765 if (cdm_) { | |
| 766 cdm::AudioDecoderConfig cdm_decoder_config; | |
| 767 cdm_decoder_config.codec = | |
| 768 PpAudioCodecToCdmAudioCodec(decoder_config.codec); | |
| 769 cdm_decoder_config.channel_count = decoder_config.channel_count; | |
| 770 cdm_decoder_config.bits_per_channel = decoder_config.bits_per_channel; | |
| 771 cdm_decoder_config.samples_per_second = decoder_config.samples_per_second; | |
| 772 cdm_decoder_config.extra_data = | |
| 773 static_cast<uint8_t*>(extra_data_buffer.data()); | |
| 774 cdm_decoder_config.extra_data_size = | |
| 775 static_cast<int32_t>(extra_data_buffer.size()); | |
| 776 status = cdm_->InitializeAudioDecoder(cdm_decoder_config); | |
| 777 } | |
| 778 | |
| 779 CallOnMain(callback_factory_.NewCallback( | |
| 780 &CdmWrapper::DecoderInitializeDone, | |
| 781 PP_DECRYPTORSTREAMTYPE_AUDIO, | |
| 782 decoder_config.request_id, | |
| 783 status == cdm::kSuccess)); | |
| 784 } | |
| 785 | |
| 786 void CdmWrapper::InitializeVideoDecoder( | |
| 787 const PP_VideoDecoderConfig& decoder_config, | |
| 788 pp::Buffer_Dev extra_data_buffer) { | |
| 789 PP_DCHECK(cdm_); // GenerateKeyRequest() should have succeeded. | |
| 790 | |
| 791 cdm::Status status = cdm::kSessionError; | |
| 792 if (cdm_) { | |
| 793 cdm::VideoDecoderConfig cdm_decoder_config; | |
| 794 cdm_decoder_config.codec = | |
| 795 PpVideoCodecToCdmVideoCodec(decoder_config.codec); | |
| 796 cdm_decoder_config.profile = | |
| 797 PpVCProfileToCdmVCProfile(decoder_config.profile); | |
| 798 cdm_decoder_config.format = | |
| 799 PpDecryptedFrameFormatToCdmVideoFormat(decoder_config.format); | |
| 800 cdm_decoder_config.coded_size.width = decoder_config.width; | |
| 801 cdm_decoder_config.coded_size.height = decoder_config.height; | |
| 802 cdm_decoder_config.extra_data = | |
| 803 static_cast<uint8_t*>(extra_data_buffer.data()); | |
| 804 cdm_decoder_config.extra_data_size = | |
| 805 static_cast<int32_t>(extra_data_buffer.size()); | |
| 806 status = cdm_->InitializeVideoDecoder(cdm_decoder_config); | |
| 807 } | |
| 808 | |
| 809 CallOnMain(callback_factory_.NewCallback( | |
| 810 &CdmWrapper::DecoderInitializeDone, | |
| 811 PP_DECRYPTORSTREAMTYPE_VIDEO, | |
| 812 decoder_config.request_id, | |
| 813 status == cdm::kSuccess)); | |
| 814 } | |
| 815 | |
| 816 void CdmWrapper::DeinitializeDecoder(PP_DecryptorStreamType decoder_type, | |
| 817 uint32_t request_id) { | |
| 818 PP_DCHECK(cdm_); // GenerateKeyRequest() should have succeeded. | |
| 819 if (cdm_) { | |
| 820 cdm_->DeinitializeDecoder( | |
| 821 PpDecryptorStreamTypeToCdmStreamType(decoder_type)); | |
| 822 } | |
| 823 | |
| 824 CallOnMain(callback_factory_.NewCallback( | |
| 825 &CdmWrapper::DecoderDeinitializeDone, | |
| 826 decoder_type, | |
| 827 request_id)); | |
| 828 } | |
| 829 | |
| 830 void CdmWrapper::ResetDecoder(PP_DecryptorStreamType decoder_type, | |
| 831 uint32_t request_id) { | |
| 832 PP_DCHECK(cdm_); // GenerateKeyRequest() should have succeeded. | |
| 833 if (cdm_) | |
| 834 cdm_->ResetDecoder(PpDecryptorStreamTypeToCdmStreamType(decoder_type)); | |
| 835 | |
| 836 CallOnMain(callback_factory_.NewCallback(&CdmWrapper::DecoderResetDone, | |
| 837 decoder_type, | |
| 838 request_id)); | |
| 839 } | |
| 840 | |
| 841 void CdmWrapper::DecryptAndDecode( | |
| 842 PP_DecryptorStreamType decoder_type, | |
| 843 pp::Buffer_Dev encrypted_buffer, | |
| 844 const PP_EncryptedBlockInfo& encrypted_block_info) { | |
| 845 PP_DCHECK(cdm_); // GenerateKeyRequest() should have succeeded. | |
| 846 | |
| 847 // Release a buffer that the caller indicated it is finished with. | |
| 848 allocator_.Release(encrypted_block_info.tracking_info.buffer_id); | |
| 849 | |
| 850 cdm::InputBuffer input_buffer; | |
| 851 std::vector<cdm::SubsampleEntry> subsamples; | |
| 852 if (cdm_ && !encrypted_buffer.is_null()) { | |
| 853 ConfigureInputBuffer(encrypted_buffer, | |
| 854 encrypted_block_info, | |
| 855 &subsamples, | |
| 856 &input_buffer); | |
| 857 } | |
| 858 | |
| 859 cdm::Status status = cdm::kDecodeError; | |
| 860 | |
| 861 switch (decoder_type) { | |
| 862 case PP_DECRYPTORSTREAMTYPE_VIDEO: { | |
| 863 LinkedVideoFrame video_frame(new VideoFrameImpl()); | |
| 864 if (cdm_) | |
| 865 status = cdm_->DecryptAndDecodeFrame(input_buffer, video_frame.get()); | |
| 866 CallOnMain(callback_factory_.NewCallback( | |
| 867 &CdmWrapper::DeliverFrame, | |
| 868 status, | |
| 869 video_frame, | |
| 870 encrypted_block_info.tracking_info)); | |
| 871 return; | |
| 872 } | |
| 873 | |
| 874 case PP_DECRYPTORSTREAMTYPE_AUDIO: { | |
| 875 LinkedAudioFrames audio_frames(new AudioFramesImpl()); | |
| 876 if (cdm_) { | |
| 877 status = cdm_->DecryptAndDecodeSamples(input_buffer, | |
| 878 audio_frames.get()); | |
| 879 } | |
| 880 CallOnMain(callback_factory_.NewCallback( | |
| 881 &CdmWrapper::DeliverSamples, | |
| 882 status, | |
| 883 audio_frames, | |
| 884 encrypted_block_info.tracking_info)); | |
| 885 return; | |
| 886 } | |
| 887 | |
| 888 default: | |
| 889 PP_NOTREACHED(); | |
| 890 return; | |
| 891 } | |
| 892 } | |
| 893 | |
| 894 cdm::Buffer* CdmWrapper::Allocate(int32_t capacity) { | |
| 895 return allocator_.Allocate(capacity); | |
| 896 } | |
| 897 | |
| 898 void CdmWrapper::SetTimer(int64_t delay_ms, void* context) { | |
| 899 // NOTE: doesn't really need to run on the main thread; could just as well run | |
| 900 // on a helper thread if |cdm_| were thread-friendly and care was taken. We | |
| 901 // only use CallOnMainThread() here to get delayed-execution behavior. | |
| 902 pp::Module::Get()->core()->CallOnMainThread( | |
| 903 delay_ms, | |
| 904 callback_factory_.NewCallback(&CdmWrapper::TimerExpired, context), | |
| 905 PP_OK); | |
| 906 } | |
| 907 | |
| 908 void CdmWrapper::TimerExpired(int32_t result, void* context) { | |
| 909 PP_DCHECK(result == PP_OK); | |
| 910 cdm_->TimerExpired(context); | |
| 911 } | |
| 912 | |
| 913 double CdmWrapper::GetCurrentWallTimeInSeconds() { | |
| 914 return pp::Module::Get()->core()->GetTime(); | |
| 915 } | |
| 916 | |
| 917 void CdmWrapper::SendKeyMessage( | |
| 918 const char* session_id, int32_t session_id_length, | |
| 919 const char* message, int32_t message_length, | |
| 920 const char* default_url, int32_t default_url_length) { | |
| 921 PP_DCHECK(!key_system_.empty()); | |
| 922 PostOnMain(callback_factory_.NewCallback( | |
| 923 &CdmWrapper::KeyMessage, | |
| 924 SessionInfo(key_system_, | |
| 925 std::string(session_id, session_id_length)), | |
| 926 std::vector<uint8>(message, message + message_length), | |
| 927 std::string(default_url, default_url_length))); | |
| 928 } | |
| 929 | |
| 930 void CdmWrapper::SendKeyError(const char* session_id, | |
| 931 int32_t session_id_length, | |
| 932 cdm::MediaKeyError error_code, | |
| 933 uint32_t system_code) { | |
| 934 SendKeyErrorInternal(key_system_, | |
| 935 std::string(session_id, session_id_length), | |
| 936 error_code, | |
| 937 system_code); | |
| 938 } | |
| 939 | |
| 940 void CdmWrapper::GetPrivateData(int32_t* instance, | |
| 941 cdm::Host::GetPrivateInterface* get_interface) { | |
| 942 *instance = pp_instance(); | |
| 943 *get_interface = pp::Module::Get()->get_browser_interface(); | |
| 944 } | |
| 945 | |
| 946 void CdmWrapper::SendUnknownKeyError(const std::string& key_system, | |
| 947 const std::string& session_id) { | |
| 948 SendKeyErrorInternal(key_system, session_id, cdm::kUnknownError, 0); | |
| 949 } | |
| 950 | |
| 951 void CdmWrapper::SendKeyAdded(const std::string& key_system, | |
| 952 const std::string& session_id) { | |
| 953 PostOnMain(callback_factory_.NewCallback( | |
| 954 &CdmWrapper::KeyAdded, | |
| 955 SessionInfo(key_system_, session_id))); | |
| 956 } | |
| 957 | |
| 958 void CdmWrapper::SendKeyErrorInternal(const std::string& key_system, | |
| 959 const std::string& session_id, | |
| 960 cdm::MediaKeyError error_code, | |
| 961 uint32_t system_code) { | |
| 962 PP_DCHECK(!key_system.empty()); | |
| 963 PostOnMain(callback_factory_.NewCallback(&CdmWrapper::KeyError, | |
| 964 SessionInfo(key_system_, session_id), | |
| 965 error_code, | |
| 966 system_code)); | |
| 967 } | |
| 968 | |
| 969 void CdmWrapper::KeyAdded(int32_t result, const SessionInfo& session_info) { | |
| 970 PP_DCHECK(result == PP_OK); | |
| 971 PP_DCHECK(!session_info.key_system.empty()); | |
| 972 pp::ContentDecryptor_Private::KeyAdded(session_info.key_system, | |
| 973 session_info.session_id); | |
| 974 } | |
| 975 | |
| 976 void CdmWrapper::KeyMessage(int32_t result, | |
| 977 const SessionInfo& session_info, | |
| 978 const std::vector<uint8>& message, | |
| 979 const std::string& default_url) { | |
| 980 PP_DCHECK(result == PP_OK); | |
| 981 PP_DCHECK(!session_info.key_system.empty()); | |
| 982 | |
| 983 pp::VarArrayBuffer message_array_buffer(message.size()); | |
| 984 if (message.size() > 0) { | |
| 985 memcpy(message_array_buffer.Map(), message.data(), message.size()); | |
| 986 } | |
| 987 | |
| 988 pp::ContentDecryptor_Private::KeyMessage( | |
| 989 session_info.key_system, session_info.session_id, | |
| 990 message_array_buffer, default_url); | |
| 991 } | |
| 992 | |
| 993 void CdmWrapper::KeyError(int32_t result, | |
| 994 const SessionInfo& session_info, | |
| 995 cdm::MediaKeyError error_code, | |
| 996 uint32_t system_code) { | |
| 997 PP_DCHECK(result == PP_OK); | |
| 998 PP_DCHECK(!session_info.key_system.empty()); | |
| 999 pp::ContentDecryptor_Private::KeyError( | |
| 1000 session_info.key_system, session_info.session_id, | |
| 1001 error_code, system_code); | |
| 1002 } | |
| 1003 | |
| 1004 void CdmWrapper::DeliverBlock(int32_t result, | |
| 1005 const cdm::Status& status, | |
| 1006 const LinkedDecryptedBlock& decrypted_block, | |
| 1007 const PP_DecryptTrackingInfo& tracking_info) { | |
| 1008 PP_DCHECK(result == PP_OK); | |
| 1009 PP_DecryptedBlockInfo decrypted_block_info; | |
| 1010 decrypted_block_info.tracking_info = tracking_info; | |
| 1011 decrypted_block_info.tracking_info.timestamp = decrypted_block->Timestamp(); | |
| 1012 decrypted_block_info.tracking_info.buffer_id = 0; | |
| 1013 decrypted_block_info.data_size = 0; | |
| 1014 decrypted_block_info.result = CdmStatusToPpDecryptResult(status); | |
| 1015 | |
| 1016 pp::Buffer_Dev buffer; | |
| 1017 | |
| 1018 if (decrypted_block_info.result == PP_DECRYPTRESULT_SUCCESS) { | |
| 1019 PP_DCHECK(decrypted_block.get() && decrypted_block->DecryptedBuffer()); | |
| 1020 if (!decrypted_block.get() || !decrypted_block->DecryptedBuffer()) { | |
| 1021 PP_NOTREACHED(); | |
| 1022 decrypted_block_info.result = PP_DECRYPTRESULT_DECRYPT_ERROR; | |
| 1023 } else { | |
| 1024 PpbBuffer* ppb_buffer = | |
| 1025 static_cast<PpbBuffer*>(decrypted_block->DecryptedBuffer()); | |
| 1026 buffer = ppb_buffer->buffer_dev(); | |
| 1027 decrypted_block_info.tracking_info.buffer_id = ppb_buffer->buffer_id(); | |
| 1028 decrypted_block_info.data_size = ppb_buffer->Size(); | |
| 1029 } | |
| 1030 } | |
| 1031 | |
| 1032 pp::ContentDecryptor_Private::DeliverBlock(buffer, decrypted_block_info); | |
| 1033 } | |
| 1034 | |
| 1035 void CdmWrapper::DecoderInitializeDone(int32_t result, | |
| 1036 PP_DecryptorStreamType decoder_type, | |
| 1037 uint32_t request_id, | |
| 1038 bool success) { | |
| 1039 PP_DCHECK(result == PP_OK); | |
| 1040 pp::ContentDecryptor_Private::DecoderInitializeDone(decoder_type, | |
| 1041 request_id, | |
| 1042 success); | |
| 1043 } | |
| 1044 | |
| 1045 void CdmWrapper::DecoderDeinitializeDone(int32_t result, | |
| 1046 PP_DecryptorStreamType decoder_type, | |
| 1047 uint32_t request_id) { | |
| 1048 pp::ContentDecryptor_Private::DecoderDeinitializeDone(decoder_type, | |
| 1049 request_id); | |
| 1050 } | |
| 1051 | |
| 1052 void CdmWrapper::DecoderResetDone(int32_t result, | |
| 1053 PP_DecryptorStreamType decoder_type, | |
| 1054 uint32_t request_id) { | |
| 1055 pp::ContentDecryptor_Private::DecoderResetDone(decoder_type, request_id); | |
| 1056 } | |
| 1057 | |
| 1058 void CdmWrapper::DeliverFrame( | |
| 1059 int32_t result, | |
| 1060 const cdm::Status& status, | |
| 1061 const LinkedVideoFrame& video_frame, | |
| 1062 const PP_DecryptTrackingInfo& tracking_info) { | |
| 1063 PP_DCHECK(result == PP_OK); | |
| 1064 PP_DecryptedFrameInfo decrypted_frame_info; | |
| 1065 decrypted_frame_info.tracking_info.request_id = tracking_info.request_id; | |
| 1066 decrypted_frame_info.tracking_info.buffer_id = 0; | |
| 1067 decrypted_frame_info.result = CdmStatusToPpDecryptResult(status); | |
| 1068 | |
| 1069 pp::Buffer_Dev buffer; | |
| 1070 | |
| 1071 if (decrypted_frame_info.result == PP_DECRYPTRESULT_SUCCESS) { | |
| 1072 if (!IsValidVideoFrame(video_frame)) { | |
| 1073 PP_NOTREACHED(); | |
| 1074 decrypted_frame_info.result = PP_DECRYPTRESULT_DECODE_ERROR; | |
| 1075 } else { | |
| 1076 PpbBuffer* ppb_buffer = | |
| 1077 static_cast<PpbBuffer*>(video_frame->FrameBuffer()); | |
| 1078 | |
| 1079 buffer = ppb_buffer->buffer_dev(); | |
| 1080 | |
| 1081 decrypted_frame_info.tracking_info.timestamp = video_frame->Timestamp(); | |
| 1082 decrypted_frame_info.tracking_info.buffer_id = ppb_buffer->buffer_id(); | |
| 1083 decrypted_frame_info.format = | |
| 1084 CdmVideoFormatToPpDecryptedFrameFormat(video_frame->Format()); | |
| 1085 decrypted_frame_info.width = video_frame->Size().width; | |
| 1086 decrypted_frame_info.height = video_frame->Size().height; | |
| 1087 decrypted_frame_info.plane_offsets[PP_DECRYPTEDFRAMEPLANES_Y] = | |
| 1088 video_frame->PlaneOffset(cdm::VideoFrame::kYPlane); | |
| 1089 decrypted_frame_info.plane_offsets[PP_DECRYPTEDFRAMEPLANES_U] = | |
| 1090 video_frame->PlaneOffset(cdm::VideoFrame::kUPlane); | |
| 1091 decrypted_frame_info.plane_offsets[PP_DECRYPTEDFRAMEPLANES_V] = | |
| 1092 video_frame->PlaneOffset(cdm::VideoFrame::kVPlane); | |
| 1093 decrypted_frame_info.strides[PP_DECRYPTEDFRAMEPLANES_Y] = | |
| 1094 video_frame->Stride(cdm::VideoFrame::kYPlane); | |
| 1095 decrypted_frame_info.strides[PP_DECRYPTEDFRAMEPLANES_U] = | |
| 1096 video_frame->Stride(cdm::VideoFrame::kUPlane); | |
| 1097 decrypted_frame_info.strides[PP_DECRYPTEDFRAMEPLANES_V] = | |
| 1098 video_frame->Stride(cdm::VideoFrame::kVPlane); | |
| 1099 } | |
| 1100 } | |
| 1101 pp::ContentDecryptor_Private::DeliverFrame(buffer, decrypted_frame_info); | |
| 1102 } | |
| 1103 | |
| 1104 void CdmWrapper::DeliverSamples(int32_t result, | |
| 1105 const cdm::Status& status, | |
| 1106 const LinkedAudioFrames& audio_frames, | |
| 1107 const PP_DecryptTrackingInfo& tracking_info) { | |
| 1108 PP_DCHECK(result == PP_OK); | |
| 1109 | |
| 1110 PP_DecryptedBlockInfo decrypted_block_info; | |
| 1111 decrypted_block_info.tracking_info = tracking_info; | |
| 1112 decrypted_block_info.tracking_info.timestamp = 0; | |
| 1113 decrypted_block_info.tracking_info.buffer_id = 0; | |
| 1114 decrypted_block_info.data_size = 0; | |
| 1115 decrypted_block_info.result = CdmStatusToPpDecryptResult(status); | |
| 1116 | |
| 1117 pp::Buffer_Dev buffer; | |
| 1118 | |
| 1119 if (decrypted_block_info.result == PP_DECRYPTRESULT_SUCCESS) { | |
| 1120 PP_DCHECK(audio_frames.get() && audio_frames->FrameBuffer()); | |
| 1121 if (!audio_frames.get() || !audio_frames->FrameBuffer()) { | |
| 1122 PP_NOTREACHED(); | |
| 1123 decrypted_block_info.result = PP_DECRYPTRESULT_DECRYPT_ERROR; | |
| 1124 } else { | |
| 1125 PpbBuffer* ppb_buffer = | |
| 1126 static_cast<PpbBuffer*>(audio_frames->FrameBuffer()); | |
| 1127 buffer = ppb_buffer->buffer_dev(); | |
| 1128 decrypted_block_info.tracking_info.buffer_id = ppb_buffer->buffer_id(); | |
| 1129 decrypted_block_info.data_size = ppb_buffer->Size(); | |
| 1130 } | |
| 1131 } | |
| 1132 | |
| 1133 pp::ContentDecryptor_Private::DeliverSamples(buffer, decrypted_block_info); | |
| 1134 } | |
| 1135 | |
| 1136 bool CdmWrapper::IsValidVideoFrame(const LinkedVideoFrame& video_frame) { | |
| 1137 if (!video_frame.get() || | |
| 1138 !video_frame->FrameBuffer() || | |
| 1139 (video_frame->Format() != cdm::kI420 && | |
| 1140 video_frame->Format() != cdm::kYv12)) { | |
| 1141 return false; | |
| 1142 } | |
| 1143 | |
| 1144 PpbBuffer* ppb_buffer = static_cast<PpbBuffer*>(video_frame->FrameBuffer()); | |
| 1145 | |
| 1146 for (int i = 0; i < cdm::VideoFrame::kMaxPlanes; ++i) { | |
| 1147 int plane_height = (i == cdm::VideoFrame::kYPlane) ? | |
| 1148 video_frame->Size().height : (video_frame->Size().height + 1) / 2; | |
| 1149 cdm::VideoFrame::VideoPlane plane = | |
| 1150 static_cast<cdm::VideoFrame::VideoPlane>(i); | |
| 1151 if (ppb_buffer->Size() < video_frame->PlaneOffset(plane) + | |
| 1152 plane_height * video_frame->Stride(plane)) { | |
| 1153 return false; | |
| 1154 } | |
| 1155 } | |
| 1156 | |
| 1157 return true; | |
| 1158 } | |
| 1159 | |
| 1160 void* GetCdmHost(int host_interface_version, void* user_data) { | |
| 1161 if (!host_interface_version || !user_data) | |
| 1162 return NULL; | |
| 1163 | |
| 1164 if (host_interface_version != cdm::kHostInterfaceVersion) | |
| 1165 return NULL; | |
| 1166 | |
| 1167 CdmWrapper* cdm_wrapper = static_cast<CdmWrapper*>(user_data); | |
| 1168 return static_cast<cdm::Host*>(cdm_wrapper); | |
| 1169 } | |
| 1170 | |
| 1171 // This object is the global object representing this plugin library as long | |
| 1172 // as it is loaded. | |
| 1173 class CdmWrapperModule : public pp::Module { | |
| 1174 public: | |
| 1175 CdmWrapperModule() : pp::Module() { | |
| 1176 // This function blocks the renderer thread (PluginInstance::Initialize()). | |
| 1177 // Move this call to other places if this may be a concern in the future. | |
| 1178 INITIALIZE_CDM_MODULE(); | |
| 1179 } | |
| 1180 virtual ~CdmWrapperModule() { | |
| 1181 DeinitializeCdmModule(); | |
| 1182 } | |
| 1183 | |
| 1184 virtual pp::Instance* CreateInstance(PP_Instance instance) { | |
| 1185 return new CdmWrapper(instance, this); | |
| 1186 } | |
| 1187 }; | |
| 1188 | |
| 1189 } // namespace webkit_media | |
| 1190 | |
| 1191 namespace pp { | |
| 1192 | |
| 1193 // Factory function for your specialization of the Module object. | |
| 1194 Module* CreateModule() { | |
| 1195 return new webkit_media::CdmWrapperModule(); | |
| 1196 } | |
| 1197 | |
| 1198 } // namespace pp | |
| OLD | NEW |