Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(162)

Side by Side Diff: webkit/plugins/ppapi/content_decryptor_delegate.cc

Issue 20165002: Move webkit/plugins/ppapi to content/renderer/pepper. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: more more clang fun Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012 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 "webkit/plugins/ppapi/content_decryptor_delegate.h"
6
7 #include "base/callback_helpers.h"
8 #include "base/debug/trace_event.h"
9 #include "base/message_loop/message_loop_proxy.h"
10 #include "base/safe_numerics.h"
11 #include "media/base/audio_buffer.h"
12 #include "media/base/audio_decoder_config.h"
13 #include "media/base/bind_to_loop.h"
14 #include "media/base/channel_layout.h"
15 #include "media/base/data_buffer.h"
16 #include "media/base/decoder_buffer.h"
17 #include "media/base/decrypt_config.h"
18 #include "media/base/video_decoder_config.h"
19 #include "media/base/video_frame.h"
20 #include "media/base/video_util.h"
21 #include "ppapi/shared_impl/scoped_pp_resource.h"
22 #include "ppapi/shared_impl/var.h"
23 #include "ppapi/shared_impl/var_tracker.h"
24 #include "ppapi/thunk/enter.h"
25 #include "ppapi/thunk/ppb_buffer_api.h"
26 #include "ui/gfx/rect.h"
27 #include "webkit/plugins/ppapi/ppb_buffer_impl.h"
28
29 using ppapi::ArrayBufferVar;
30 using ppapi::PpapiGlobals;
31 using ppapi::ScopedPPResource;
32 using ppapi::StringVar;
33 using ppapi::thunk::EnterResourceNoLock;
34 using ppapi::thunk::PPB_Buffer_API;
35
36 namespace webkit {
37 namespace ppapi {
38
39 namespace {
40
41 // Fills |resource| with a PPB_Buffer_Impl and copies |data| into the buffer
42 // resource. The |*resource|, if valid, will be in the ResourceTracker with a
43 // reference-count of 0. If |data| is NULL, sets |*resource| to NULL. Returns
44 // true upon success and false if any error happened.
45 bool MakeBufferResource(PP_Instance instance,
46 const uint8* data, uint32_t size,
47 scoped_refptr<PPB_Buffer_Impl>* resource) {
48 TRACE_EVENT0("eme", "ContentDecryptorDelegate - MakeBufferResource");
49 DCHECK(resource);
50
51 if (!data || !size) {
52 DCHECK(!data && !size);
53 resource = NULL;
54 return true;
55 }
56
57 scoped_refptr<PPB_Buffer_Impl> buffer(
58 PPB_Buffer_Impl::CreateResource(instance, size));
59 if (!buffer.get())
60 return false;
61
62 BufferAutoMapper mapper(buffer.get());
63 if (!mapper.data() || mapper.size() < size)
64 return false;
65 memcpy(mapper.data(), data, size);
66
67 *resource = buffer;
68 return true;
69 }
70
71 // Copies the content of |str| into |array|.
72 // Returns true if copy succeeded. Returns false if copy failed, e.g. if the
73 // |array_size| is smaller than the |str| length.
74 template <uint32_t array_size>
75 bool CopyStringToArray(const std::string& str, uint8 (&array)[array_size]) {
76 if (array_size < str.size())
77 return false;
78
79 memcpy(array, str.data(), str.size());
80 return true;
81 }
82
83 // Fills the |block_info| with information from |encrypted_buffer|.
84 //
85 // Returns true if |block_info| is successfully filled. Returns false
86 // otherwise.
87 static bool MakeEncryptedBlockInfo(
88 const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
89 uint32_t request_id,
90 PP_EncryptedBlockInfo* block_info) {
91 // TODO(xhwang): Fix initialization of PP_EncryptedBlockInfo here and
92 // anywhere else.
93 memset(block_info, 0, sizeof(*block_info));
94 block_info->tracking_info.request_id = request_id;
95
96 // EOS buffers need a request ID and nothing more.
97 if (encrypted_buffer->end_of_stream())
98 return true;
99
100 DCHECK(encrypted_buffer->data_size())
101 << "DecryptConfig is set on an empty buffer";
102
103 block_info->tracking_info.timestamp =
104 encrypted_buffer->timestamp().InMicroseconds();
105 block_info->data_size = encrypted_buffer->data_size();
106
107 const media::DecryptConfig* decrypt_config =
108 encrypted_buffer->decrypt_config();
109 block_info->data_offset = decrypt_config->data_offset();
110
111 if (!CopyStringToArray(decrypt_config->key_id(), block_info->key_id) ||
112 !CopyStringToArray(decrypt_config->iv(), block_info->iv))
113 return false;
114
115 block_info->key_id_size = decrypt_config->key_id().size();
116 block_info->iv_size = decrypt_config->iv().size();
117
118 if (decrypt_config->subsamples().size() > arraysize(block_info->subsamples))
119 return false;
120
121 block_info->num_subsamples = decrypt_config->subsamples().size();
122 for (uint32_t i = 0; i < block_info->num_subsamples; ++i) {
123 block_info->subsamples[i].clear_bytes =
124 decrypt_config->subsamples()[i].clear_bytes;
125 block_info->subsamples[i].cipher_bytes =
126 decrypt_config->subsamples()[i].cypher_bytes;
127 }
128
129 return true;
130 }
131
132 PP_AudioCodec MediaAudioCodecToPpAudioCodec(media::AudioCodec codec) {
133 switch (codec) {
134 case media::kCodecVorbis:
135 return PP_AUDIOCODEC_VORBIS;
136 case media::kCodecAAC:
137 return PP_AUDIOCODEC_AAC;
138 default:
139 return PP_AUDIOCODEC_UNKNOWN;
140 }
141 }
142
143 PP_VideoCodec MediaVideoCodecToPpVideoCodec(media::VideoCodec codec) {
144 switch (codec) {
145 case media::kCodecVP8:
146 return PP_VIDEOCODEC_VP8;
147 case media::kCodecH264:
148 return PP_VIDEOCODEC_H264;
149 default:
150 return PP_VIDEOCODEC_UNKNOWN;
151 }
152 }
153
154 PP_VideoCodecProfile MediaVideoCodecProfileToPpVideoCodecProfile(
155 media::VideoCodecProfile profile) {
156 switch (profile) {
157 case media::VP8PROFILE_MAIN:
158 return PP_VIDEOCODECPROFILE_VP8_MAIN;
159 case media::H264PROFILE_BASELINE:
160 return PP_VIDEOCODECPROFILE_H264_BASELINE;
161 case media::H264PROFILE_MAIN:
162 return PP_VIDEOCODECPROFILE_H264_MAIN;
163 case media::H264PROFILE_EXTENDED:
164 return PP_VIDEOCODECPROFILE_H264_EXTENDED;
165 case media::H264PROFILE_HIGH:
166 return PP_VIDEOCODECPROFILE_H264_HIGH;
167 case media::H264PROFILE_HIGH10PROFILE:
168 return PP_VIDEOCODECPROFILE_H264_HIGH_10;
169 case media::H264PROFILE_HIGH422PROFILE:
170 return PP_VIDEOCODECPROFILE_H264_HIGH_422;
171 case media::H264PROFILE_HIGH444PREDICTIVEPROFILE:
172 return PP_VIDEOCODECPROFILE_H264_HIGH_444_PREDICTIVE;
173 default:
174 return PP_VIDEOCODECPROFILE_UNKNOWN;
175 }
176 }
177
178 PP_DecryptedFrameFormat MediaVideoFormatToPpDecryptedFrameFormat(
179 media::VideoFrame::Format format) {
180 switch (format) {
181 case media::VideoFrame::YV12:
182 return PP_DECRYPTEDFRAMEFORMAT_YV12;
183 case media::VideoFrame::I420:
184 return PP_DECRYPTEDFRAMEFORMAT_I420;
185 default:
186 return PP_DECRYPTEDFRAMEFORMAT_UNKNOWN;
187 }
188 }
189
190 media::Decryptor::Status PpDecryptResultToMediaDecryptorStatus(
191 PP_DecryptResult result) {
192 switch (result) {
193 case PP_DECRYPTRESULT_SUCCESS:
194 return media::Decryptor::kSuccess;
195 case PP_DECRYPTRESULT_DECRYPT_NOKEY:
196 return media::Decryptor::kNoKey;
197 case PP_DECRYPTRESULT_NEEDMOREDATA:
198 return media::Decryptor::kNeedMoreData;
199 case PP_DECRYPTRESULT_DECRYPT_ERROR:
200 return media::Decryptor::kError;
201 case PP_DECRYPTRESULT_DECODE_ERROR:
202 return media::Decryptor::kError;
203 default:
204 NOTREACHED();
205 return media::Decryptor::kError;
206 }
207 }
208
209 PP_DecryptorStreamType MediaDecryptorStreamTypeToPpStreamType(
210 media::Decryptor::StreamType stream_type) {
211 switch (stream_type) {
212 case media::Decryptor::kAudio:
213 return PP_DECRYPTORSTREAMTYPE_AUDIO;
214 case media::Decryptor::kVideo:
215 return PP_DECRYPTORSTREAMTYPE_VIDEO;
216 default:
217 NOTREACHED();
218 return PP_DECRYPTORSTREAMTYPE_VIDEO;
219 }
220 }
221
222 } // namespace
223
224 ContentDecryptorDelegate::ContentDecryptorDelegate(
225 PP_Instance pp_instance,
226 const PPP_ContentDecryptor_Private* plugin_decryption_interface)
227 : pp_instance_(pp_instance),
228 plugin_decryption_interface_(plugin_decryption_interface),
229 next_decryption_request_id_(1),
230 pending_audio_decrypt_request_id_(0),
231 pending_video_decrypt_request_id_(0),
232 pending_audio_decoder_init_request_id_(0),
233 pending_video_decoder_init_request_id_(0),
234 pending_audio_decode_request_id_(0),
235 pending_video_decode_request_id_(0),
236 weak_ptr_factory_(this),
237 weak_this_(weak_ptr_factory_.GetWeakPtr()),
238 audio_sample_format_(media::kUnknownSampleFormat),
239 audio_samples_per_second_(0),
240 audio_channel_count_(0),
241 audio_bytes_per_frame_(0) {
242 }
243
244 void ContentDecryptorDelegate::Initialize(const std::string& key_system) {
245 // TODO(ddorwin): Add an Initialize method to PPP_ContentDecryptor_Private.
246 DCHECK(!key_system.empty());
247 key_system_ = key_system;
248 }
249
250 void ContentDecryptorDelegate::SetKeyEventCallbacks(
251 const media::KeyAddedCB& key_added_cb,
252 const media::KeyErrorCB& key_error_cb,
253 const media::KeyMessageCB& key_message_cb) {
254 key_added_cb_ = key_added_cb;
255 key_error_cb_ = key_error_cb;
256 key_message_cb_ = key_message_cb;
257 }
258
259 bool ContentDecryptorDelegate::GenerateKeyRequest(const std::string& type,
260 const uint8* init_data,
261 int init_data_length) {
262 PP_Var init_data_array =
263 PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
264 init_data_length, init_data);
265
266 plugin_decryption_interface_->GenerateKeyRequest(
267 pp_instance_,
268 StringVar::StringToPPVar(key_system_), // TODO(ddorwin): Remove.
269 StringVar::StringToPPVar(type),
270 init_data_array);
271 return true;
272 }
273
274 bool ContentDecryptorDelegate::AddKey(const std::string& session_id,
275 const uint8* key,
276 int key_length,
277 const uint8* init_data,
278 int init_data_length) {
279 PP_Var key_array =
280 PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(key_length,
281 key);
282 PP_Var init_data_array =
283 PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
284 init_data_length, init_data);
285
286 plugin_decryption_interface_->AddKey(
287 pp_instance_,
288 StringVar::StringToPPVar(session_id),
289 key_array,
290 init_data_array);
291 return true;
292 }
293
294 bool ContentDecryptorDelegate::CancelKeyRequest(const std::string& session_id) {
295 plugin_decryption_interface_->CancelKeyRequest(
296 pp_instance_,
297 StringVar::StringToPPVar(session_id));
298 return true;
299 }
300
301 // TODO(xhwang): Remove duplication of code in Decrypt(),
302 // DecryptAndDecodeAudio() and DecryptAndDecodeVideo().
303 bool ContentDecryptorDelegate::Decrypt(
304 media::Decryptor::StreamType stream_type,
305 const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
306 const media::Decryptor::DecryptCB& decrypt_cb) {
307 DVLOG(3) << "Decrypt() - stream_type: " << stream_type;
308 // |{audio|video}_input_resource_| is not being used by the plugin
309 // now because there is only one pending audio/video decrypt request at any
310 // time. This is enforced by the media pipeline.
311 scoped_refptr<PPB_Buffer_Impl> encrypted_resource;
312 if (!MakeMediaBufferResource(
313 stream_type, encrypted_buffer, &encrypted_resource) ||
314 !encrypted_resource.get()) {
315 return false;
316 }
317 ScopedPPResource pp_resource(encrypted_resource.get());
318
319 const uint32_t request_id = next_decryption_request_id_++;
320 DVLOG(2) << "Decrypt() - request_id " << request_id;
321
322 PP_EncryptedBlockInfo block_info = {};
323 DCHECK(encrypted_buffer->decrypt_config());
324 if (!MakeEncryptedBlockInfo(encrypted_buffer, request_id, &block_info)) {
325 return false;
326 }
327
328 // There is only one pending decrypt request at any time per stream. This is
329 // enforced by the media pipeline.
330 switch (stream_type) {
331 case media::Decryptor::kAudio:
332 DCHECK_EQ(pending_audio_decrypt_request_id_, 0u);
333 DCHECK(pending_audio_decrypt_cb_.is_null());
334 pending_audio_decrypt_request_id_ = request_id;
335 pending_audio_decrypt_cb_ = decrypt_cb;
336 break;
337 case media::Decryptor::kVideo:
338 DCHECK_EQ(pending_video_decrypt_request_id_, 0u);
339 DCHECK(pending_video_decrypt_cb_.is_null());
340 pending_video_decrypt_request_id_ = request_id;
341 pending_video_decrypt_cb_ = decrypt_cb;
342 break;
343 default:
344 NOTREACHED();
345 return false;
346 }
347
348 SetBufferToFreeInTrackingInfo(&block_info.tracking_info);
349
350 plugin_decryption_interface_->Decrypt(pp_instance_,
351 pp_resource,
352 &block_info);
353 return true;
354 }
355
356 bool ContentDecryptorDelegate::CancelDecrypt(
357 media::Decryptor::StreamType stream_type) {
358 DVLOG(3) << "CancelDecrypt() - stream_type: " << stream_type;
359
360 media::Decryptor::DecryptCB decrypt_cb;
361 switch (stream_type) {
362 case media::Decryptor::kAudio:
363 // Release the shared memory as it can still be in use by the plugin.
364 // The next Decrypt() call will need to allocate a new shared memory
365 // buffer.
366 audio_input_resource_ = NULL;
367 pending_audio_decrypt_request_id_ = 0;
368 decrypt_cb = base::ResetAndReturn(&pending_audio_decrypt_cb_);
369 break;
370 case media::Decryptor::kVideo:
371 // Release the shared memory as it can still be in use by the plugin.
372 // The next Decrypt() call will need to allocate a new shared memory
373 // buffer.
374 video_input_resource_ = NULL;
375 pending_video_decrypt_request_id_ = 0;
376 decrypt_cb = base::ResetAndReturn(&pending_video_decrypt_cb_);
377 break;
378 default:
379 NOTREACHED();
380 return false;
381 }
382
383 if (!decrypt_cb.is_null())
384 decrypt_cb.Run(media::Decryptor::kSuccess, NULL);
385
386 return true;
387 }
388
389 bool ContentDecryptorDelegate::InitializeAudioDecoder(
390 const media::AudioDecoderConfig& decoder_config,
391 const media::Decryptor::DecoderInitCB& init_cb) {
392 PP_AudioDecoderConfig pp_decoder_config;
393 pp_decoder_config.codec =
394 MediaAudioCodecToPpAudioCodec(decoder_config.codec());
395 pp_decoder_config.channel_count =
396 media::ChannelLayoutToChannelCount(decoder_config.channel_layout());
397 pp_decoder_config.bits_per_channel = decoder_config.bits_per_channel();
398 pp_decoder_config.samples_per_second = decoder_config.samples_per_second();
399 pp_decoder_config.request_id = next_decryption_request_id_++;
400
401 audio_sample_format_ = decoder_config.sample_format();
402 audio_samples_per_second_ = pp_decoder_config.samples_per_second;
403 audio_channel_count_ = pp_decoder_config.channel_count;
404 audio_bytes_per_frame_ = decoder_config.bytes_per_frame();
405
406 scoped_refptr<PPB_Buffer_Impl> extra_data_resource;
407 if (!MakeBufferResource(pp_instance_,
408 decoder_config.extra_data(),
409 decoder_config.extra_data_size(),
410 &extra_data_resource)) {
411 return false;
412 }
413 ScopedPPResource pp_resource(extra_data_resource.get());
414
415 DCHECK_EQ(pending_audio_decoder_init_request_id_, 0u);
416 DCHECK(pending_audio_decoder_init_cb_.is_null());
417 pending_audio_decoder_init_request_id_ = pp_decoder_config.request_id;
418 pending_audio_decoder_init_cb_ = init_cb;
419
420 plugin_decryption_interface_->InitializeAudioDecoder(pp_instance_,
421 &pp_decoder_config,
422 pp_resource);
423 return true;
424 }
425
426 bool ContentDecryptorDelegate::InitializeVideoDecoder(
427 const media::VideoDecoderConfig& decoder_config,
428 const media::Decryptor::DecoderInitCB& init_cb) {
429 PP_VideoDecoderConfig pp_decoder_config;
430 pp_decoder_config.codec =
431 MediaVideoCodecToPpVideoCodec(decoder_config.codec());
432 pp_decoder_config.profile =
433 MediaVideoCodecProfileToPpVideoCodecProfile(decoder_config.profile());
434 pp_decoder_config.format =
435 MediaVideoFormatToPpDecryptedFrameFormat(decoder_config.format());
436 pp_decoder_config.width = decoder_config.coded_size().width();
437 pp_decoder_config.height = decoder_config.coded_size().height();
438 pp_decoder_config.request_id = next_decryption_request_id_++;
439
440 scoped_refptr<PPB_Buffer_Impl> extra_data_resource;
441 if (!MakeBufferResource(pp_instance_,
442 decoder_config.extra_data(),
443 decoder_config.extra_data_size(),
444 &extra_data_resource)) {
445 return false;
446 }
447 ScopedPPResource pp_resource(extra_data_resource.get());
448
449 DCHECK_EQ(pending_video_decoder_init_request_id_, 0u);
450 DCHECK(pending_video_decoder_init_cb_.is_null());
451 pending_video_decoder_init_request_id_ = pp_decoder_config.request_id;
452 pending_video_decoder_init_cb_ = init_cb;
453
454 natural_size_ = decoder_config.natural_size();
455
456 plugin_decryption_interface_->InitializeVideoDecoder(pp_instance_,
457 &pp_decoder_config,
458 pp_resource);
459 return true;
460 }
461
462 bool ContentDecryptorDelegate::DeinitializeDecoder(
463 media::Decryptor::StreamType stream_type) {
464 CancelDecode(stream_type);
465
466 natural_size_ = gfx::Size();
467
468 // TODO(tomfinegan): Add decoder deinitialize request tracking, and get
469 // stream type from media stack.
470 plugin_decryption_interface_->DeinitializeDecoder(
471 pp_instance_, MediaDecryptorStreamTypeToPpStreamType(stream_type), 0);
472 return true;
473 }
474
475 bool ContentDecryptorDelegate::ResetDecoder(
476 media::Decryptor::StreamType stream_type) {
477 CancelDecode(stream_type);
478
479 // TODO(tomfinegan): Add decoder reset request tracking.
480 plugin_decryption_interface_->ResetDecoder(
481 pp_instance_, MediaDecryptorStreamTypeToPpStreamType(stream_type), 0);
482 return true;
483 }
484
485 bool ContentDecryptorDelegate::DecryptAndDecodeAudio(
486 const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
487 const media::Decryptor::AudioDecodeCB& audio_decode_cb) {
488 // |audio_input_resource_| is not being used by the plugin now
489 // because there is only one pending audio decode request at any time.
490 // This is enforced by the media pipeline.
491 scoped_refptr<PPB_Buffer_Impl> encrypted_resource;
492 if (!MakeMediaBufferResource(media::Decryptor::kAudio,
493 encrypted_buffer,
494 &encrypted_resource)) {
495 return false;
496 }
497
498 // The resource should not be NULL for non-EOS buffer.
499 if (!encrypted_buffer->end_of_stream() && !encrypted_resource.get())
500 return false;
501
502 const uint32_t request_id = next_decryption_request_id_++;
503 DVLOG(2) << "DecryptAndDecodeAudio() - request_id " << request_id;
504
505 PP_EncryptedBlockInfo block_info = {};
506 if (!MakeEncryptedBlockInfo(encrypted_buffer, request_id, &block_info)) {
507 return false;
508 }
509
510 SetBufferToFreeInTrackingInfo(&block_info.tracking_info);
511
512 // There is only one pending audio decode request at any time. This is
513 // enforced by the media pipeline. If this DCHECK is violated, our buffer
514 // reuse policy is not valid, and we may have race problems for the shared
515 // buffer.
516 DCHECK_EQ(pending_audio_decode_request_id_, 0u);
517 DCHECK(pending_audio_decode_cb_.is_null());
518 pending_audio_decode_request_id_ = request_id;
519 pending_audio_decode_cb_ = audio_decode_cb;
520
521 ScopedPPResource pp_resource(encrypted_resource.get());
522 plugin_decryption_interface_->DecryptAndDecode(pp_instance_,
523 PP_DECRYPTORSTREAMTYPE_AUDIO,
524 pp_resource,
525 &block_info);
526 return true;
527 }
528
529 bool ContentDecryptorDelegate::DecryptAndDecodeVideo(
530 const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
531 const media::Decryptor::VideoDecodeCB& video_decode_cb) {
532 // |video_input_resource_| is not being used by the plugin now
533 // because there is only one pending video decode request at any time.
534 // This is enforced by the media pipeline.
535 scoped_refptr<PPB_Buffer_Impl> encrypted_resource;
536 if (!MakeMediaBufferResource(media::Decryptor::kVideo,
537 encrypted_buffer,
538 &encrypted_resource)) {
539 return false;
540 }
541
542 // The resource should not be 0 for non-EOS buffer.
543 if (!encrypted_buffer->end_of_stream() && !encrypted_resource.get())
544 return false;
545
546 const uint32_t request_id = next_decryption_request_id_++;
547 DVLOG(2) << "DecryptAndDecodeVideo() - request_id " << request_id;
548 TRACE_EVENT_ASYNC_BEGIN0(
549 "eme", "ContentDecryptorDelegate::DecryptAndDecodeVideo", request_id);
550
551 PP_EncryptedBlockInfo block_info = {};
552 if (!MakeEncryptedBlockInfo(encrypted_buffer, request_id, &block_info)) {
553 return false;
554 }
555
556 SetBufferToFreeInTrackingInfo(&block_info.tracking_info);
557
558 // Only one pending video decode request at any time. This is enforced by the
559 // media pipeline. If this DCHECK is violated, our buffer
560 // reuse policy is not valid, and we may have race problems for the shared
561 // buffer.
562 DCHECK_EQ(pending_video_decode_request_id_, 0u);
563 DCHECK(pending_video_decode_cb_.is_null());
564 pending_video_decode_request_id_ = request_id;
565 pending_video_decode_cb_ = video_decode_cb;
566
567 // TODO(tomfinegan): Need to get stream type from media stack.
568 ScopedPPResource pp_resource(encrypted_resource.get());
569 plugin_decryption_interface_->DecryptAndDecode(pp_instance_,
570 PP_DECRYPTORSTREAMTYPE_VIDEO,
571 pp_resource,
572 &block_info);
573 return true;
574 }
575
576 void ContentDecryptorDelegate::NeedKey(PP_Var key_system_var,
577 PP_Var session_id_var,
578 PP_Var init_data_var) {
579 // TODO(ddorwin): Remove from PPB_ContentDecryptor_Private.
580 NOTREACHED();
581 }
582
583 void ContentDecryptorDelegate::KeyAdded(PP_Var key_system_var,
584 PP_Var session_id_var) {
585 if (key_added_cb_.is_null())
586 return;
587
588 StringVar* session_id_string = StringVar::FromPPVar(session_id_var);
589 if (!session_id_string) {
590 key_error_cb_.Run(std::string(), media::MediaKeys::kUnknownError, 0);
591 return;
592 }
593
594 key_added_cb_.Run(session_id_string->value());
595 }
596
597 void ContentDecryptorDelegate::KeyMessage(PP_Var key_system_var,
598 PP_Var session_id_var,
599 PP_Var message_var,
600 PP_Var default_url_var) {
601 if (key_message_cb_.is_null())
602 return;
603
604 StringVar* session_id_string = StringVar::FromPPVar(session_id_var);
605
606 ArrayBufferVar* message_array_buffer =
607 ArrayBufferVar::FromPPVar(message_var);
608
609 std::vector<uint8> message;
610 if (message_array_buffer) {
611 const uint8* data = static_cast<const uint8*>(message_array_buffer->Map());
612 message.assign(data, data + message_array_buffer->ByteLength());
613 }
614
615 StringVar* default_url_string = StringVar::FromPPVar(default_url_var);
616
617 if (!session_id_string || !default_url_string) {
618 key_error_cb_.Run(std::string(), media::MediaKeys::kUnknownError, 0);
619 return;
620 }
621
622 key_message_cb_.Run(session_id_string->value(),
623 message,
624 default_url_string->value());
625 }
626
627 void ContentDecryptorDelegate::KeyError(PP_Var key_system_var,
628 PP_Var session_id_var,
629 int32_t media_error,
630 int32_t system_code) {
631 if (key_error_cb_.is_null())
632 return;
633
634 StringVar* session_id_string = StringVar::FromPPVar(session_id_var);
635 if (!session_id_string) {
636 key_error_cb_.Run(std::string(), media::MediaKeys::kUnknownError, 0);
637 return;
638 }
639
640 key_error_cb_.Run(session_id_string->value(),
641 static_cast<media::MediaKeys::KeyError>(media_error),
642 system_code);
643 }
644
645 void ContentDecryptorDelegate::DecoderInitializeDone(
646 PP_DecryptorStreamType decoder_type,
647 uint32_t request_id,
648 PP_Bool success) {
649 if (decoder_type == PP_DECRYPTORSTREAMTYPE_AUDIO) {
650 // If the request ID is not valid or does not match what's saved, do
651 // nothing.
652 if (request_id == 0 ||
653 request_id != pending_audio_decoder_init_request_id_)
654 return;
655
656 DCHECK(!pending_audio_decoder_init_cb_.is_null());
657 pending_audio_decoder_init_request_id_ = 0;
658 base::ResetAndReturn(
659 &pending_audio_decoder_init_cb_).Run(PP_ToBool(success));
660 } else {
661 if (request_id == 0 ||
662 request_id != pending_video_decoder_init_request_id_)
663 return;
664
665 if (!success)
666 natural_size_ = gfx::Size();
667
668 DCHECK(!pending_video_decoder_init_cb_.is_null());
669 pending_video_decoder_init_request_id_ = 0;
670 base::ResetAndReturn(
671 &pending_video_decoder_init_cb_).Run(PP_ToBool(success));
672 }
673 }
674
675 void ContentDecryptorDelegate::DecoderDeinitializeDone(
676 PP_DecryptorStreamType decoder_type,
677 uint32_t request_id) {
678 // TODO(tomfinegan): Add decoder stop completion handling.
679 }
680
681 void ContentDecryptorDelegate::DecoderResetDone(
682 PP_DecryptorStreamType decoder_type,
683 uint32_t request_id) {
684 // TODO(tomfinegan): Add decoder reset completion handling.
685 }
686
687 void ContentDecryptorDelegate::DeliverBlock(
688 PP_Resource decrypted_block,
689 const PP_DecryptedBlockInfo* block_info) {
690 DCHECK(block_info);
691
692 FreeBuffer(block_info->tracking_info.buffer_id);
693
694 const uint32_t request_id = block_info->tracking_info.request_id;
695 DVLOG(2) << "DeliverBlock() - request_id: " << request_id;
696
697 // If the request ID is not valid or does not match what's saved, do nothing.
698 if (request_id == 0) {
699 DVLOG(1) << "DeliverBlock() - invalid request_id " << request_id;
700 return;
701 }
702
703 media::Decryptor::DecryptCB decrypt_cb;
704 if (request_id == pending_audio_decrypt_request_id_) {
705 DCHECK(!pending_audio_decrypt_cb_.is_null());
706 pending_audio_decrypt_request_id_ = 0;
707 decrypt_cb = base::ResetAndReturn(&pending_audio_decrypt_cb_);
708 } else if (request_id == pending_video_decrypt_request_id_) {
709 DCHECK(!pending_video_decrypt_cb_.is_null());
710 pending_video_decrypt_request_id_ = 0;
711 decrypt_cb = base::ResetAndReturn(&pending_video_decrypt_cb_);
712 } else {
713 DVLOG(1) << "DeliverBlock() - request_id " << request_id << " not found";
714 return;
715 }
716
717 media::Decryptor::Status status =
718 PpDecryptResultToMediaDecryptorStatus(block_info->result);
719 if (status != media::Decryptor::kSuccess) {
720 decrypt_cb.Run(status, NULL);
721 return;
722 }
723
724 EnterResourceNoLock<PPB_Buffer_API> enter(decrypted_block, true);
725 if (!enter.succeeded()) {
726 decrypt_cb.Run(media::Decryptor::kError, NULL);
727 return;
728 }
729 BufferAutoMapper mapper(enter.object());
730 if (!mapper.data() || !mapper.size() ||
731 mapper.size() < block_info->data_size) {
732 decrypt_cb.Run(media::Decryptor::kError, NULL);
733 return;
734 }
735
736 // TODO(tomfinegan): Find a way to take ownership of the shared memory
737 // managed by the PPB_Buffer_Dev, and avoid the extra copy.
738 scoped_refptr<media::DecoderBuffer> decrypted_buffer(
739 media::DecoderBuffer::CopyFrom(
740 static_cast<uint8*>(mapper.data()), block_info->data_size));
741 decrypted_buffer->set_timestamp(base::TimeDelta::FromMicroseconds(
742 block_info->tracking_info.timestamp));
743 decrypt_cb.Run(media::Decryptor::kSuccess, decrypted_buffer);
744 }
745
746 // Use a non-class-member function here so that if for some reason
747 // ContentDecryptorDelegate is destroyed before VideoFrame calls this callback,
748 // we can still get the shared memory unmapped.
749 static void BufferNoLongerNeeded(
750 const scoped_refptr<PPB_Buffer_Impl>& ppb_buffer,
751 base::Closure buffer_no_longer_needed_cb) {
752 ppb_buffer->Unmap();
753 buffer_no_longer_needed_cb.Run();
754 }
755
756 // Enters |resource|, maps shared memory and returns pointer of mapped data.
757 // Returns NULL if any error occurs.
758 static uint8* GetMappedBuffer(PP_Resource resource,
759 scoped_refptr<PPB_Buffer_Impl>* ppb_buffer) {
760 EnterResourceNoLock<PPB_Buffer_API> enter(resource, true);
761 if (!enter.succeeded())
762 return NULL;
763
764 uint8* mapped_data = static_cast<uint8*>(enter.object()->Map());
765 if (!enter.object()->IsMapped() || !mapped_data)
766 return NULL;
767
768 uint32_t mapped_size = 0;
769 if (!enter.object()->Describe(&mapped_size) || !mapped_size) {
770 enter.object()->Unmap();
771 return NULL;
772 }
773
774 *ppb_buffer = static_cast<PPB_Buffer_Impl*>(enter.object());
775
776 return mapped_data;
777 }
778
779 void ContentDecryptorDelegate::DeliverFrame(
780 PP_Resource decrypted_frame,
781 const PP_DecryptedFrameInfo* frame_info) {
782 DCHECK(frame_info);
783
784 const uint32_t request_id = frame_info->tracking_info.request_id;
785 DVLOG(2) << "DeliverFrame() - request_id: " << request_id;
786
787 // If the request ID is not valid or does not match what's saved, do nothing.
788 if (request_id == 0 || request_id != pending_video_decode_request_id_) {
789 DVLOG(1) << "DeliverFrame() - request_id " << request_id << " not found";
790 FreeBuffer(frame_info->tracking_info.buffer_id);
791 return;
792 }
793
794 TRACE_EVENT_ASYNC_END0(
795 "eme", "ContentDecryptorDelegate::DecryptAndDecodeVideo", request_id);
796
797 DCHECK(!pending_video_decode_cb_.is_null());
798 pending_video_decode_request_id_ = 0;
799 media::Decryptor::VideoDecodeCB video_decode_cb =
800 base::ResetAndReturn(&pending_video_decode_cb_);
801
802 media::Decryptor::Status status =
803 PpDecryptResultToMediaDecryptorStatus(frame_info->result);
804 if (status != media::Decryptor::kSuccess) {
805 DCHECK(!frame_info->tracking_info.buffer_id);
806 video_decode_cb.Run(status, NULL);
807 return;
808 }
809
810 scoped_refptr<PPB_Buffer_Impl> ppb_buffer;
811 uint8* frame_data = GetMappedBuffer(decrypted_frame, &ppb_buffer);
812 if (!frame_data) {
813 FreeBuffer(frame_info->tracking_info.buffer_id);
814 video_decode_cb.Run(media::Decryptor::kError, NULL);
815 return;
816 }
817
818 gfx::Size frame_size(frame_info->width, frame_info->height);
819 DCHECK_EQ(frame_info->format, PP_DECRYPTEDFRAMEFORMAT_YV12);
820
821 scoped_refptr<media::VideoFrame> decoded_frame =
822 media::VideoFrame::WrapExternalYuvData(
823 media::VideoFrame::YV12,
824 frame_size, gfx::Rect(frame_size), natural_size_,
825 frame_info->strides[PP_DECRYPTEDFRAMEPLANES_Y],
826 frame_info->strides[PP_DECRYPTEDFRAMEPLANES_U],
827 frame_info->strides[PP_DECRYPTEDFRAMEPLANES_V],
828 frame_data + frame_info->plane_offsets[PP_DECRYPTEDFRAMEPLANES_Y],
829 frame_data + frame_info->plane_offsets[PP_DECRYPTEDFRAMEPLANES_U],
830 frame_data + frame_info->plane_offsets[PP_DECRYPTEDFRAMEPLANES_V],
831 base::TimeDelta::FromMicroseconds(
832 frame_info->tracking_info.timestamp),
833 ppb_buffer->shared_memory()->handle(),
834 media::BindToLoop(
835 base::MessageLoopProxy::current(),
836 base::Bind(&BufferNoLongerNeeded, ppb_buffer,
837 base::Bind(&ContentDecryptorDelegate::FreeBuffer,
838 weak_this_,
839 frame_info->tracking_info.buffer_id))));
840
841 video_decode_cb.Run(media::Decryptor::kSuccess, decoded_frame);
842 }
843
844 void ContentDecryptorDelegate::DeliverSamples(
845 PP_Resource audio_frames,
846 const PP_DecryptedBlockInfo* block_info) {
847 DCHECK(block_info);
848
849 FreeBuffer(block_info->tracking_info.buffer_id);
850
851 const uint32_t request_id = block_info->tracking_info.request_id;
852 DVLOG(2) << "DeliverSamples() - request_id: " << request_id;
853
854 // If the request ID is not valid or does not match what's saved, do nothing.
855 if (request_id == 0 || request_id != pending_audio_decode_request_id_) {
856 DVLOG(1) << "DeliverSamples() - request_id " << request_id << " not found";
857 return;
858 }
859
860 DCHECK(!pending_audio_decode_cb_.is_null());
861 pending_audio_decode_request_id_ = 0;
862 media::Decryptor::AudioDecodeCB audio_decode_cb =
863 base::ResetAndReturn(&pending_audio_decode_cb_);
864
865 const media::Decryptor::AudioBuffers empty_frames;
866
867 media::Decryptor::Status status =
868 PpDecryptResultToMediaDecryptorStatus(block_info->result);
869 if (status != media::Decryptor::kSuccess) {
870 audio_decode_cb.Run(status, empty_frames);
871 return;
872 }
873
874 media::Decryptor::AudioBuffers audio_frame_list;
875 if (!DeserializeAudioFrames(audio_frames,
876 block_info->data_size,
877 &audio_frame_list)) {
878 NOTREACHED() << "CDM did not serialize the buffer correctly.";
879 audio_decode_cb.Run(media::Decryptor::kError, empty_frames);
880 return;
881 }
882
883 audio_decode_cb.Run(media::Decryptor::kSuccess, audio_frame_list);
884 }
885
886 // TODO(xhwang): Try to remove duplicate logic here and in CancelDecrypt().
887 void ContentDecryptorDelegate::CancelDecode(
888 media::Decryptor::StreamType stream_type) {
889 switch (stream_type) {
890 case media::Decryptor::kAudio:
891 // Release the shared memory as it can still be in use by the plugin.
892 // The next DecryptAndDecode() call will need to allocate a new shared
893 // memory buffer.
894 audio_input_resource_ = NULL;
895 pending_audio_decode_request_id_ = 0;
896 if (!pending_audio_decode_cb_.is_null())
897 base::ResetAndReturn(&pending_audio_decode_cb_).Run(
898 media::Decryptor::kSuccess, media::Decryptor::AudioBuffers());
899 break;
900 case media::Decryptor::kVideo:
901 // Release the shared memory as it can still be in use by the plugin.
902 // The next DecryptAndDecode() call will need to allocate a new shared
903 // memory buffer.
904 video_input_resource_ = NULL;
905 pending_video_decode_request_id_ = 0;
906 if (!pending_video_decode_cb_.is_null())
907 base::ResetAndReturn(&pending_video_decode_cb_).Run(
908 media::Decryptor::kSuccess, NULL);
909 break;
910 default:
911 NOTREACHED();
912 }
913 }
914
915 bool ContentDecryptorDelegate::MakeMediaBufferResource(
916 media::Decryptor::StreamType stream_type,
917 const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
918 scoped_refptr<PPB_Buffer_Impl>* resource) {
919 TRACE_EVENT0("eme", "ContentDecryptorDelegate::MakeMediaBufferResource");
920
921 // End of stream buffers are represented as null resources.
922 if (encrypted_buffer->end_of_stream()) {
923 *resource = NULL;
924 return true;
925 }
926
927 DCHECK(stream_type == media::Decryptor::kAudio ||
928 stream_type == media::Decryptor::kVideo);
929 scoped_refptr<PPB_Buffer_Impl>& media_resource =
930 (stream_type == media::Decryptor::kAudio) ? audio_input_resource_ :
931 video_input_resource_;
932
933 const size_t data_size = static_cast<size_t>(encrypted_buffer->data_size());
934 if (!media_resource.get() || media_resource->size() < data_size) {
935 // Either the buffer hasn't been created yet, or we have one that isn't big
936 // enough to fit |size| bytes.
937
938 // Media resource size starts from |kMinimumMediaBufferSize| and grows
939 // exponentially to avoid frequent re-allocation of PPB_Buffer_Impl,
940 // which is usually expensive. Since input media buffers are compressed,
941 // they are usually small (compared to outputs). The over-allocated memory
942 // should be negligible.
943 const uint32_t kMinimumMediaBufferSize = 1024;
944 uint32_t media_resource_size =
945 media_resource.get() ? media_resource->size() : kMinimumMediaBufferSize;
946 while (media_resource_size < data_size)
947 media_resource_size *= 2;
948
949 DVLOG(2) << "Size of media buffer for "
950 << ((stream_type == media::Decryptor::kAudio) ? "audio" : "video")
951 << " stream bumped to " << media_resource_size
952 << " bytes to fit input.";
953 media_resource = PPB_Buffer_Impl::CreateResource(pp_instance_,
954 media_resource_size);
955 if (!media_resource.get())
956 return false;
957 }
958
959 BufferAutoMapper mapper(media_resource.get());
960 if (!mapper.data() || mapper.size() < data_size) {
961 media_resource = NULL;
962 return false;
963 }
964 memcpy(mapper.data(), encrypted_buffer->data(), data_size);
965
966 *resource = media_resource;
967 return true;
968 }
969
970 void ContentDecryptorDelegate::FreeBuffer(uint32_t buffer_id) {
971 if (buffer_id)
972 free_buffers_.push(buffer_id);
973 }
974
975 void ContentDecryptorDelegate::SetBufferToFreeInTrackingInfo(
976 PP_DecryptTrackingInfo* tracking_info) {
977 DCHECK_EQ(tracking_info->buffer_id, 0u);
978
979 if (free_buffers_.empty())
980 return;
981
982 tracking_info->buffer_id = free_buffers_.front();
983 free_buffers_.pop();
984 }
985
986 bool ContentDecryptorDelegate::DeserializeAudioFrames(
987 PP_Resource audio_frames,
988 size_t data_size,
989 media::Decryptor::AudioBuffers* frames) {
990 DCHECK(frames);
991 EnterResourceNoLock<PPB_Buffer_API> enter(audio_frames, true);
992 if (!enter.succeeded())
993 return false;
994
995 BufferAutoMapper mapper(enter.object());
996 if (!mapper.data() || !mapper.size() ||
997 mapper.size() < static_cast<uint32_t>(data_size))
998 return false;
999
1000 // TODO(jrummell): Pass ownership of data() directly to AudioBuffer to avoid
1001 // the copy. Since it is possible to get multiple buffers, it would need to be
1002 // sliced and ref counted appropriately. http://crbug.com/255576.
1003 const uint8* cur = static_cast<uint8*>(mapper.data());
1004 size_t bytes_left = data_size;
1005
1006 do {
1007 int64 timestamp = 0;
1008 int64 frame_size = -1;
1009 const size_t kHeaderSize = sizeof(timestamp) + sizeof(frame_size);
1010
1011 if (bytes_left < kHeaderSize)
1012 return false;
1013
1014 memcpy(&timestamp, cur, sizeof(timestamp));
1015 cur += sizeof(timestamp);
1016 bytes_left -= sizeof(timestamp);
1017
1018 memcpy(&frame_size, cur, sizeof(frame_size));
1019 cur += sizeof(frame_size);
1020 bytes_left -= sizeof(frame_size);
1021
1022 // We should *not* have empty frames in the list.
1023 if (frame_size <= 0 ||
1024 bytes_left < base::checked_numeric_cast<size_t>(frame_size)) {
1025 return false;
1026 }
1027
1028 const uint8* data[] = {cur};
1029 int frame_count = frame_size / audio_bytes_per_frame_;
1030 scoped_refptr<media::AudioBuffer> frame = media::AudioBuffer::CopyFrom(
1031 audio_sample_format_,
1032 audio_channel_count_,
1033 frame_count,
1034 data,
1035 base::TimeDelta::FromMicroseconds(timestamp),
1036 base::TimeDelta::FromMicroseconds(audio_samples_per_second_ /
1037 frame_count));
1038 frames->push_back(frame);
1039
1040 cur += frame_size;
1041 bytes_left -= frame_size;
1042 } while (bytes_left > 0);
1043
1044 return true;
1045 }
1046
1047 } // namespace ppapi
1048 } // namespace webkit
OLDNEW
« no previous file with comments | « webkit/plugins/ppapi/content_decryptor_delegate.h ('k') | webkit/plugins/ppapi/event_conversion.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698