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 |