OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "webkit/plugins/ppapi/content_decryptor_delegate.h" | 5 #include "webkit/plugins/ppapi/content_decryptor_delegate.h" |
6 | 6 |
7 #include "base/callback_helpers.h" | 7 #include "base/callback_helpers.h" |
8 #include "base/debug/trace_event.h" | 8 #include "base/debug/trace_event.h" |
9 #include "media/base/audio_decoder_config.h" | 9 #include "media/base/audio_decoder_config.h" |
10 #include "media/base/channel_layout.h" | 10 #include "media/base/channel_layout.h" |
11 #include "media/base/data_buffer.h" | 11 #include "media/base/data_buffer.h" |
12 #include "media/base/decoder_buffer.h" | 12 #include "media/base/decoder_buffer.h" |
13 #include "media/base/decryptor_client.h" | 13 #include "media/base/decryptor_client.h" |
14 #include "media/base/video_decoder_config.h" | 14 #include "media/base/video_decoder_config.h" |
15 #include "media/base/video_frame.h" | 15 #include "media/base/video_frame.h" |
16 #include "media/base/video_util.h" | 16 #include "media/base/video_util.h" |
17 #include "ppapi/shared_impl/scoped_pp_resource.h" | |
18 #include "ppapi/shared_impl/var.h" | 17 #include "ppapi/shared_impl/var.h" |
19 #include "ppapi/shared_impl/var_tracker.h" | 18 #include "ppapi/shared_impl/var_tracker.h" |
20 #include "ppapi/thunk/enter.h" | 19 #include "ppapi/thunk/enter.h" |
21 #include "ppapi/thunk/ppb_buffer_api.h" | 20 #include "ppapi/thunk/ppb_buffer_api.h" |
22 #include "webkit/plugins/ppapi/ppb_buffer_impl.h" | 21 #include "webkit/plugins/ppapi/ppb_buffer_impl.h" |
23 | 22 |
24 using ppapi::PpapiGlobals; | 23 using ppapi::PpapiGlobals; |
25 using ppapi::ScopedPPResource; | 24 using ppapi::ScopedPPResource; |
26 using ppapi::StringVar; | 25 using ppapi::StringVar; |
27 using ppapi::thunk::EnterResourceNoLock; | 26 using ppapi::thunk::EnterResourceNoLock; |
28 using ppapi::thunk::PPB_Buffer_API; | 27 using ppapi::thunk::PPB_Buffer_API; |
29 | 28 |
30 namespace webkit { | 29 namespace webkit { |
31 namespace ppapi { | 30 namespace ppapi { |
32 | 31 |
33 namespace { | 32 namespace { |
34 | 33 |
35 // Fills |resource| with a PP_Resource containing a PPB_Buffer_Impl and copies | 34 // Fills |resource| with a PP_Resource containing a PPB_Buffer_Impl and copies |
36 // |data| into the buffer resource. The |resource| has a reference count of 1. | 35 // |data| into the buffer resource. The |resource| has a reference count of 1. |
37 // If |data| is NULL, fills |resource| with a PP_Resource with ID of 0. | 36 // If |data| is NULL, fills |resource| with a PP_Resource with ID of 0. |
38 // Returns true upon success and false if any error happened. | 37 // Returns true upon success and false if any error happened. |
39 bool MakeBufferResource(PP_Instance instance, | 38 bool MakeBufferResource(PP_Instance instance, |
40 const uint8* data, int size, | 39 const uint8* data, int size, |
41 ScopedPPResource* resource) { | 40 ScopedPPResource* resource) { |
| 41 TRACE_EVENT0("eme", "ContentDecryptorDelegate - MakeBufferResource"); |
42 DCHECK(resource); | 42 DCHECK(resource); |
43 | 43 |
44 if (!data || !size) { | 44 if (!data || !size) { |
45 DCHECK(!data && !size); | 45 DCHECK(!data && !size); |
46 resource->Release(); | 46 resource->Release(); |
47 return true; | 47 return true; |
48 } | 48 } |
49 | 49 |
50 ScopedPPResource scoped_resource(ScopedPPResource::PassRef(), | 50 ScopedPPResource scoped_resource(ScopedPPResource::PassRef(), |
51 PPB_Buffer_Impl::Create(instance, size)); | 51 PPB_Buffer_Impl::Create(instance, size)); |
(...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
267 const PPP_ContentDecryptor_Private* plugin_decryption_interface) | 267 const PPP_ContentDecryptor_Private* plugin_decryption_interface) |
268 : pp_instance_(pp_instance), | 268 : pp_instance_(pp_instance), |
269 plugin_decryption_interface_(plugin_decryption_interface), | 269 plugin_decryption_interface_(plugin_decryption_interface), |
270 decryptor_client_(NULL), | 270 decryptor_client_(NULL), |
271 next_decryption_request_id_(1), | 271 next_decryption_request_id_(1), |
272 pending_audio_decrypt_request_id_(0), | 272 pending_audio_decrypt_request_id_(0), |
273 pending_video_decrypt_request_id_(0), | 273 pending_video_decrypt_request_id_(0), |
274 pending_audio_decoder_init_request_id_(0), | 274 pending_audio_decoder_init_request_id_(0), |
275 pending_video_decoder_init_request_id_(0), | 275 pending_video_decoder_init_request_id_(0), |
276 pending_audio_decode_request_id_(0), | 276 pending_audio_decode_request_id_(0), |
277 pending_video_decode_request_id_(0) { | 277 pending_video_decode_request_id_(0), |
| 278 audio_input_resource_size_(0), |
| 279 video_input_resource_size_(0) { |
278 } | 280 } |
279 | 281 |
280 void ContentDecryptorDelegate::set_decrypt_client( | 282 void ContentDecryptorDelegate::set_decrypt_client( |
281 media::DecryptorClient* decryptor_client) { | 283 media::DecryptorClient* decryptor_client) { |
282 decryptor_client_ = decryptor_client; | 284 decryptor_client_ = decryptor_client; |
283 } | 285 } |
284 | 286 |
285 bool ContentDecryptorDelegate::GenerateKeyRequest(const std::string& key_system, | 287 bool ContentDecryptorDelegate::GenerateKeyRequest(const std::string& key_system, |
286 const std::string& type, | 288 const std::string& type, |
287 const uint8* init_data, | 289 const uint8* init_data, |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
328 return true; | 330 return true; |
329 } | 331 } |
330 | 332 |
331 // TODO(xhwang): Remove duplication of code in Decrypt(), | 333 // TODO(xhwang): Remove duplication of code in Decrypt(), |
332 // DecryptAndDecodeAudio() and DecryptAndDecodeVideo(). | 334 // DecryptAndDecodeAudio() and DecryptAndDecodeVideo(). |
333 bool ContentDecryptorDelegate::Decrypt( | 335 bool ContentDecryptorDelegate::Decrypt( |
334 media::Decryptor::StreamType stream_type, | 336 media::Decryptor::StreamType stream_type, |
335 const scoped_refptr<media::DecoderBuffer>& encrypted_buffer, | 337 const scoped_refptr<media::DecoderBuffer>& encrypted_buffer, |
336 const media::Decryptor::DecryptCB& decrypt_cb) { | 338 const media::Decryptor::DecryptCB& decrypt_cb) { |
337 DVLOG(3) << "Decrypt() - stream_type: " << stream_type; | 339 DVLOG(3) << "Decrypt() - stream_type: " << stream_type; |
| 340 // |{audio|video}_input_resource_[size_]| is not being used by the plugin |
| 341 // now because there is only one pending audio/video decrypt request at any |
| 342 // time. This is enforced by the media pipeline. |
338 ScopedPPResource encrypted_resource; | 343 ScopedPPResource encrypted_resource; |
339 if (!MakeBufferResource(pp_instance_, | 344 if (!MakeMediaBufferResource(stream_type, |
340 encrypted_buffer->GetData(), | 345 encrypted_buffer->GetData(), |
341 encrypted_buffer->GetDataSize(), | 346 encrypted_buffer->GetDataSize(), |
342 &encrypted_resource) || | 347 &encrypted_resource) || |
343 !encrypted_resource.get()) { | 348 !encrypted_resource.get()) { |
344 return false; | 349 return false; |
345 } | 350 } |
346 | 351 |
347 const uint32_t request_id = next_decryption_request_id_++; | 352 const uint32_t request_id = next_decryption_request_id_++; |
348 DVLOG(2) << "Decrypt() - request_id " << request_id; | 353 DVLOG(2) << "Decrypt() - request_id " << request_id; |
349 | 354 |
350 PP_EncryptedBlockInfo block_info; | 355 PP_EncryptedBlockInfo block_info; |
351 DCHECK(encrypted_buffer->GetDecryptConfig()); | 356 DCHECK(encrypted_buffer->GetDecryptConfig()); |
352 if (!MakeEncryptedBlockInfo(encrypted_buffer->GetDecryptConfig(), | 357 if (!MakeEncryptedBlockInfo(encrypted_buffer->GetDecryptConfig(), |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
492 pp_instance_, MediaDecryptorStreamTypeToPpStreamType(stream_type), 0); | 497 pp_instance_, MediaDecryptorStreamTypeToPpStreamType(stream_type), 0); |
493 return true; | 498 return true; |
494 } | 499 } |
495 | 500 |
496 bool ContentDecryptorDelegate::DecryptAndDecodeAudio( | 501 bool ContentDecryptorDelegate::DecryptAndDecodeAudio( |
497 const scoped_refptr<media::DecoderBuffer>& encrypted_buffer, | 502 const scoped_refptr<media::DecoderBuffer>& encrypted_buffer, |
498 const media::Decryptor::AudioDecodeCB& audio_decode_cb) { | 503 const media::Decryptor::AudioDecodeCB& audio_decode_cb) { |
499 // If |encrypted_buffer| is end-of-stream buffer, GetData() and GetDataSize() | 504 // If |encrypted_buffer| is end-of-stream buffer, GetData() and GetDataSize() |
500 // return NULL and 0 respectively. In that case, we'll just create a 0 | 505 // return NULL and 0 respectively. In that case, we'll just create a 0 |
501 // resource. | 506 // resource. |
| 507 // |audio_input_resource_size_| is not being used by the plugin now |
| 508 // because there is only one pending audio decode request at any time. |
| 509 // This is enforced by the media pipeline. |
502 ScopedPPResource encrypted_resource; | 510 ScopedPPResource encrypted_resource; |
503 if (!MakeBufferResource(pp_instance_, | 511 if (!MakeMediaBufferResource(media::Decryptor::kAudio, |
504 encrypted_buffer->GetData(), | 512 encrypted_buffer->GetData(), |
505 encrypted_buffer->GetDataSize(), | 513 encrypted_buffer->GetDataSize(), |
506 &encrypted_resource)) { | 514 &encrypted_resource)) { |
507 return false; | 515 return false; |
508 } | 516 } |
509 | 517 |
510 // The resource should not be 0 for non-EOS buffer. | 518 // The resource should not be 0 for non-EOS buffer. |
511 if (!encrypted_buffer->IsEndOfStream() && !encrypted_resource.get()) | 519 if (!encrypted_buffer->IsEndOfStream() && !encrypted_resource.get()) |
512 return false; | 520 return false; |
513 | 521 |
514 const uint32_t request_id = next_decryption_request_id_++; | 522 const uint32_t request_id = next_decryption_request_id_++; |
515 DVLOG(2) << "DecryptAndDecodeAudio() - request_id " << request_id; | 523 DVLOG(2) << "DecryptAndDecodeAudio() - request_id " << request_id; |
516 | 524 |
(...skipping 19 matching lines...) Expand all Loading... |
536 &block_info); | 544 &block_info); |
537 return true; | 545 return true; |
538 } | 546 } |
539 | 547 |
540 bool ContentDecryptorDelegate::DecryptAndDecodeVideo( | 548 bool ContentDecryptorDelegate::DecryptAndDecodeVideo( |
541 const scoped_refptr<media::DecoderBuffer>& encrypted_buffer, | 549 const scoped_refptr<media::DecoderBuffer>& encrypted_buffer, |
542 const media::Decryptor::VideoDecodeCB& video_decode_cb) { | 550 const media::Decryptor::VideoDecodeCB& video_decode_cb) { |
543 // If |encrypted_buffer| is end-of-stream buffer, GetData() and GetDataSize() | 551 // If |encrypted_buffer| is end-of-stream buffer, GetData() and GetDataSize() |
544 // return NULL and 0 respectively. In that case, we'll just create a 0 | 552 // return NULL and 0 respectively. In that case, we'll just create a 0 |
545 // resource. | 553 // resource. |
| 554 // |video_input_resource_size_| is not being used by the plugin now |
| 555 // because there is only one pending video decode request at any time. |
| 556 // This is enforced by the media pipeline. |
546 ScopedPPResource encrypted_resource; | 557 ScopedPPResource encrypted_resource; |
547 if (!MakeBufferResource(pp_instance_, | 558 if (!MakeMediaBufferResource(media::Decryptor::kVideo, |
548 encrypted_buffer->GetData(), | 559 encrypted_buffer->GetData(), |
549 encrypted_buffer->GetDataSize(), | 560 encrypted_buffer->GetDataSize(), |
550 &encrypted_resource)) { | 561 &encrypted_resource)) { |
551 return false; | 562 return false; |
552 } | 563 } |
553 | 564 |
554 // The resource should not be 0 for non-EOS buffer. | 565 // The resource should not be 0 for non-EOS buffer. |
555 if (!encrypted_buffer->IsEndOfStream() && !encrypted_resource.get()) | 566 if (!encrypted_buffer->IsEndOfStream() && !encrypted_resource.get()) |
556 return false; | 567 return false; |
557 | 568 |
558 const uint32_t request_id = next_decryption_request_id_++; | 569 const uint32_t request_id = next_decryption_request_id_++; |
559 DVLOG(2) << "DecryptAndDecodeVideo() - request_id " << request_id; | 570 DVLOG(2) << "DecryptAndDecodeVideo() - request_id " << request_id; |
560 TRACE_EVENT_ASYNC_BEGIN0( | 571 TRACE_EVENT_ASYNC_BEGIN0( |
561 "eme", "PluginInstance::DecryptAndDecodeVideo", request_id); | 572 "eme", "ContentDecryptorDelegate::DecryptAndDecodeVideo", request_id); |
562 | 573 |
563 PP_EncryptedBlockInfo block_info; | 574 PP_EncryptedBlockInfo block_info; |
564 if (!MakeEncryptedBlockInfo( | 575 if (!MakeEncryptedBlockInfo( |
565 encrypted_buffer->GetDecryptConfig(), | 576 encrypted_buffer->GetDecryptConfig(), |
566 encrypted_buffer->GetTimestamp().InMicroseconds(), | 577 encrypted_buffer->GetTimestamp().InMicroseconds(), |
567 request_id, | 578 request_id, |
568 &block_info)) { | 579 &block_info)) { |
569 return false; | 580 return false; |
570 } | 581 } |
571 | 582 |
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
765 const uint32_t request_id = frame_info->tracking_info.request_id; | 776 const uint32_t request_id = frame_info->tracking_info.request_id; |
766 DVLOG(2) << "DeliverFrame() - request_id: " << request_id; | 777 DVLOG(2) << "DeliverFrame() - request_id: " << request_id; |
767 | 778 |
768 // If the request ID is not valid or does not match what's saved, do nothing. | 779 // If the request ID is not valid or does not match what's saved, do nothing. |
769 if (request_id == 0 || request_id != pending_video_decode_request_id_) { | 780 if (request_id == 0 || request_id != pending_video_decode_request_id_) { |
770 DVLOG(1) << "DeliverFrame() - request_id " << request_id << " not found"; | 781 DVLOG(1) << "DeliverFrame() - request_id " << request_id << " not found"; |
771 return; | 782 return; |
772 } | 783 } |
773 | 784 |
774 TRACE_EVENT_ASYNC_END0( | 785 TRACE_EVENT_ASYNC_END0( |
775 "eme", "PluginInstance::DecryptAndDecodeVideo", request_id); | 786 "eme", "ContentDecryptorDelegate::DecryptAndDecodeVideo", request_id); |
776 | 787 |
777 DCHECK(!pending_video_decode_cb_.is_null()); | 788 DCHECK(!pending_video_decode_cb_.is_null()); |
778 pending_video_decode_request_id_ = 0; | 789 pending_video_decode_request_id_ = 0; |
779 media::Decryptor::VideoDecodeCB video_decode_cb = | 790 media::Decryptor::VideoDecodeCB video_decode_cb = |
780 base::ResetAndReturn(&pending_video_decode_cb_); | 791 base::ResetAndReturn(&pending_video_decode_cb_); |
781 | 792 |
782 media::Decryptor::Status status = | 793 media::Decryptor::Status status = |
783 PpDecryptResultToMediaDecryptorStatus(frame_info->result); | 794 PpDecryptResultToMediaDecryptorStatus(frame_info->result); |
784 if (status != media::Decryptor::kSuccess) { | 795 if (status != media::Decryptor::kSuccess) { |
785 video_decode_cb.Run(status, NULL); | 796 video_decode_cb.Run(status, NULL); |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
883 pending_video_decode_request_id_ = 0; | 894 pending_video_decode_request_id_ = 0; |
884 if (!pending_video_decode_cb_.is_null()) | 895 if (!pending_video_decode_cb_.is_null()) |
885 base::ResetAndReturn(&pending_video_decode_cb_).Run( | 896 base::ResetAndReturn(&pending_video_decode_cb_).Run( |
886 media::Decryptor::kSuccess, NULL); | 897 media::Decryptor::kSuccess, NULL); |
887 break; | 898 break; |
888 default: | 899 default: |
889 NOTREACHED(); | 900 NOTREACHED(); |
890 } | 901 } |
891 } | 902 } |
892 | 903 |
| 904 bool ContentDecryptorDelegate::MakeMediaBufferResource( |
| 905 media::Decryptor::StreamType stream_type, |
| 906 const uint8* data, int size, |
| 907 ScopedPPResource* resource) { |
| 908 TRACE_EVENT0("eme", "ContentDecryptorDelegate::MakeMediaBufferResource"); |
| 909 |
| 910 DCHECK(resource); |
| 911 |
| 912 if (!data || !size) { |
| 913 DCHECK(!data && !size); |
| 914 resource->Release(); |
| 915 return true; |
| 916 } |
| 917 |
| 918 DCHECK(stream_type == media::Decryptor::kAudio || |
| 919 stream_type == media::Decryptor::kVideo); |
| 920 ScopedPPResource& media_resource = (stream_type == media::Decryptor::kAudio) ? |
| 921 audio_input_resource_ : video_input_resource_; |
| 922 int& media_resource_size = (stream_type == media::Decryptor::kAudio) ? |
| 923 audio_input_resource_size_ : video_input_resource_size_; |
| 924 |
| 925 if (media_resource_size < size) { |
| 926 // Media resource size starts from |kMinimumMediaBufferSize| and grows |
| 927 // exponentially to avoid frequent re-allocation of PPB_Buffer_Impl, |
| 928 // which is usually expensive. Since input media buffers are compressed, |
| 929 // they are usually small (compared to outputs). The over-allocated memory |
| 930 // should be negligible. |
| 931 |
| 932 if (media_resource_size == 0) { |
| 933 const int kMinimumMediaBufferSize = 1024; |
| 934 media_resource_size = kMinimumMediaBufferSize; |
| 935 } |
| 936 |
| 937 while (media_resource_size < size) |
| 938 media_resource_size *= 2; |
| 939 |
| 940 DVLOG(2) << "Size of media buffer for " |
| 941 << ((stream_type == media::Decryptor::kAudio) ? "audio" : "video") |
| 942 << " stream bumped to " << media_resource_size |
| 943 << " bytes to fit input."; |
| 944 media_resource = ScopedPPResource( |
| 945 ScopedPPResource::PassRef(), |
| 946 PPB_Buffer_Impl::Create(pp_instance_, media_resource_size)); |
| 947 if (!media_resource.get()) { |
| 948 media_resource_size = 0; |
| 949 return false; |
| 950 } |
| 951 } |
| 952 |
| 953 EnterResourceNoLock<PPB_Buffer_API> enter(media_resource, true); |
| 954 if (enter.failed()) { |
| 955 media_resource.Release(); |
| 956 media_resource_size = 0; |
| 957 return false; |
| 958 } |
| 959 |
| 960 BufferAutoMapper mapper(enter.object()); |
| 961 if (!mapper.data() || mapper.size() < static_cast<size_t>(size)) { |
| 962 media_resource.Release(); |
| 963 media_resource_size = 0; |
| 964 return false; |
| 965 } |
| 966 memcpy(mapper.data(), data, size); |
| 967 |
| 968 *resource = media_resource; |
| 969 return true; |
| 970 } |
| 971 |
893 } // namespace ppapi | 972 } // namespace ppapi |
894 } // namespace webkit | 973 } // namespace webkit |
OLD | NEW |