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.
5 #include "content/renderer/pepper/content_decryptor_delegate.h"
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/numerics/safe_conversions.h"
11 #include "content/renderer/pepper/ppb_buffer_impl.h"
12 #include "media/base/audio_buffer.h"
13 #include "media/base/audio_decoder_config.h"
14 #include "media/base/bind_to_current_loop.h"
15 #include "media/base/channel_layout.h"
16 #include "media/base/data_buffer.h"
17 #include "media/base/decoder_buffer.h"
18 #include "media/base/decrypt_config.h"
19 #include "media/base/video_decoder_config.h"
20 #include "media/base/video_frame.h"
21 #include "media/base/video_util.h"
22 #include "ppapi/shared_impl/scoped_pp_resource.h"
23 #include "ppapi/shared_impl/var.h"
24 #include "ppapi/shared_impl/var_tracker.h"
25 #include "ppapi/thunk/enter.h"
26 #include "ppapi/thunk/ppb_buffer_api.h"
27 #include "ui/gfx/rect.h"
29 using media::Decryptor;
30 using ppapi::ArrayBufferVar;
31 using ppapi::PpapiGlobals;
32 using ppapi::ScopedPPResource;
33 using ppapi::StringVar;
34 using ppapi::thunk::EnterResourceNoLock;
35 using ppapi::thunk::PPB_Buffer_API;
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("media", "ContentDecryptorDelegate - MakeBufferResource");
52 DCHECK(!data && !size);
57 scoped_refptr<PPB_Buffer_Impl> buffer(
58 PPB_Buffer_Impl::CreateResource(instance, size));
62 BufferAutoMapper mapper(buffer.get());
63 if (!mapper.data() || mapper.size() < size)
65 memcpy(mapper.data(), data, size);
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())
79 memcpy(array, str.data(), str.size());
83 // Fills the |block_info| with information from |encrypted_buffer|.
85 // Returns true if |block_info| is successfully filled. Returns false
87 static bool MakeEncryptedBlockInfo(
88 const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
90 PP_EncryptedBlockInfo* block_info) {
91 // TODO(xhwang): Fix initialization of PP_EncryptedBlockInfo here and
93 memset(block_info, 0, sizeof(*block_info));
94 block_info->tracking_info.request_id = request_id;
96 // EOS buffers need a request ID and nothing more.
97 if (encrypted_buffer->end_of_stream())
100 DCHECK(encrypted_buffer->data_size())
101 << "DecryptConfig is set on an empty buffer";
103 block_info->tracking_info.timestamp =
104 encrypted_buffer->timestamp().InMicroseconds();
105 block_info->data_size = encrypted_buffer->data_size();
107 const media::DecryptConfig* decrypt_config =
108 encrypted_buffer->decrypt_config();
110 if (!CopyStringToArray(decrypt_config->key_id(), block_info->key_id) ||
111 !CopyStringToArray(decrypt_config->iv(), block_info->iv))
114 block_info->key_id_size = decrypt_config->key_id().size();
115 block_info->iv_size = decrypt_config->iv().size();
117 if (decrypt_config->subsamples().size() > arraysize(block_info->subsamples))
120 block_info->num_subsamples = decrypt_config->subsamples().size();
121 for (uint32_t i = 0; i < block_info->num_subsamples; ++i) {
122 block_info->subsamples[i].clear_bytes =
123 decrypt_config->subsamples()[i].clear_bytes;
124 block_info->subsamples[i].cipher_bytes =
125 decrypt_config->subsamples()[i].cypher_bytes;
131 PP_AudioCodec MediaAudioCodecToPpAudioCodec(media::AudioCodec codec) {
133 case media::kCodecVorbis:
134 return PP_AUDIOCODEC_VORBIS;
135 case media::kCodecAAC:
136 return PP_AUDIOCODEC_AAC;
138 return PP_AUDIOCODEC_UNKNOWN;
142 PP_VideoCodec MediaVideoCodecToPpVideoCodec(media::VideoCodec codec) {
144 case media::kCodecVP8:
145 return PP_VIDEOCODEC_VP8;
146 case media::kCodecH264:
147 return PP_VIDEOCODEC_H264;
149 return PP_VIDEOCODEC_UNKNOWN;
153 PP_VideoCodecProfile MediaVideoCodecProfileToPpVideoCodecProfile(
154 media::VideoCodecProfile profile) {
156 case media::VP8PROFILE_MAIN:
157 return PP_VIDEOCODECPROFILE_VP8_MAIN;
158 case media::H264PROFILE_BASELINE:
159 return PP_VIDEOCODECPROFILE_H264_BASELINE;
160 case media::H264PROFILE_MAIN:
161 return PP_VIDEOCODECPROFILE_H264_MAIN;
162 case media::H264PROFILE_EXTENDED:
163 return PP_VIDEOCODECPROFILE_H264_EXTENDED;
164 case media::H264PROFILE_HIGH:
165 return PP_VIDEOCODECPROFILE_H264_HIGH;
166 case media::H264PROFILE_HIGH10PROFILE:
167 return PP_VIDEOCODECPROFILE_H264_HIGH_10;
168 case media::H264PROFILE_HIGH422PROFILE:
169 return PP_VIDEOCODECPROFILE_H264_HIGH_422;
170 case media::H264PROFILE_HIGH444PREDICTIVEPROFILE:
171 return PP_VIDEOCODECPROFILE_H264_HIGH_444_PREDICTIVE;
173 return PP_VIDEOCODECPROFILE_UNKNOWN;
177 PP_DecryptedFrameFormat MediaVideoFormatToPpDecryptedFrameFormat(
178 media::VideoFrame::Format format) {
180 case media::VideoFrame::YV12:
181 return PP_DECRYPTEDFRAMEFORMAT_YV12;
182 case media::VideoFrame::I420:
183 return PP_DECRYPTEDFRAMEFORMAT_I420;
185 return PP_DECRYPTEDFRAMEFORMAT_UNKNOWN;
189 Decryptor::Status PpDecryptResultToMediaDecryptorStatus(
190 PP_DecryptResult result) {
192 case PP_DECRYPTRESULT_SUCCESS:
193 return Decryptor::kSuccess;
194 case PP_DECRYPTRESULT_DECRYPT_NOKEY:
195 return Decryptor::kNoKey;
196 case PP_DECRYPTRESULT_NEEDMOREDATA:
197 return Decryptor::kNeedMoreData;
198 case PP_DECRYPTRESULT_DECRYPT_ERROR:
199 return Decryptor::kError;
200 case PP_DECRYPTRESULT_DECODE_ERROR:
201 return Decryptor::kError;
204 return Decryptor::kError;
208 PP_DecryptorStreamType MediaDecryptorStreamTypeToPpStreamType(
209 Decryptor::StreamType stream_type) {
210 switch (stream_type) {
211 case Decryptor::kAudio:
212 return PP_DECRYPTORSTREAMTYPE_AUDIO;
213 case Decryptor::kVideo:
214 return PP_DECRYPTORSTREAMTYPE_VIDEO;
217 return PP_DECRYPTORSTREAMTYPE_VIDEO;
221 media::SampleFormat PpDecryptedSampleFormatToMediaSampleFormat(
222 PP_DecryptedSampleFormat result) {
224 case PP_DECRYPTEDSAMPLEFORMAT_U8:
225 return media::kSampleFormatU8;
226 case PP_DECRYPTEDSAMPLEFORMAT_S16:
227 return media::kSampleFormatS16;
228 case PP_DECRYPTEDSAMPLEFORMAT_S32:
229 return media::kSampleFormatS32;
230 case PP_DECRYPTEDSAMPLEFORMAT_F32:
231 return media::kSampleFormatF32;
232 case PP_DECRYPTEDSAMPLEFORMAT_PLANAR_S16:
233 return media::kSampleFormatPlanarS16;
234 case PP_DECRYPTEDSAMPLEFORMAT_PLANAR_F32:
235 return media::kSampleFormatPlanarF32;
238 return media::kUnknownSampleFormat;
244 ContentDecryptorDelegate::ContentDecryptorDelegate(
245 PP_Instance pp_instance,
246 const PPP_ContentDecryptor_Private* plugin_decryption_interface)
247 : pp_instance_(pp_instance),
248 plugin_decryption_interface_(plugin_decryption_interface),
249 next_decryption_request_id_(1),
250 audio_samples_per_second_(0),
251 audio_channel_count_(0),
252 audio_channel_layout_(media::CHANNEL_LAYOUT_NONE),
253 weak_ptr_factory_(this) {
254 weak_this_ = weak_ptr_factory_.GetWeakPtr();
257 ContentDecryptorDelegate::~ContentDecryptorDelegate() {
258 SatisfyAllPendingCallbacksOnError();
261 void ContentDecryptorDelegate::Initialize(
262 const std::string& key_system,
263 const media::SessionCreatedCB& session_created_cb,
264 const media::SessionMessageCB& session_message_cb,
265 const media::SessionReadyCB& session_ready_cb,
266 const media::SessionClosedCB& session_closed_cb,
267 const media::SessionErrorCB& session_error_cb,
268 const base::Closure& fatal_plugin_error_cb) {
269 DCHECK(!key_system.empty());
270 DCHECK(key_system_.empty());
271 key_system_ = key_system;
273 session_created_cb_ = session_created_cb;
274 session_message_cb_ = session_message_cb;
275 session_ready_cb_ = session_ready_cb;
276 session_closed_cb_ = session_closed_cb;
277 session_error_cb_ = session_error_cb;
278 fatal_plugin_error_cb_ = fatal_plugin_error_cb;
280 plugin_decryption_interface_->Initialize(
281 pp_instance_, StringVar::StringToPPVar(key_system_));
284 void ContentDecryptorDelegate::InstanceCrashed() {
285 fatal_plugin_error_cb_.Run();
286 SatisfyAllPendingCallbacksOnError();
289 bool ContentDecryptorDelegate::CreateSession(uint32 session_id,
290 const std::string& content_type,
291 const uint8* init_data,
292 int init_data_length) {
293 PP_Var init_data_array =
294 PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
295 init_data_length, init_data);
297 plugin_decryption_interface_->CreateSession(
300 StringVar::StringToPPVar(content_type),
305 void ContentDecryptorDelegate::LoadSession(uint32 session_id,
306 const std::string& web_session_id) {
307 plugin_decryption_interface_->LoadSession(
308 pp_instance_, session_id, StringVar::StringToPPVar(web_session_id));
311 bool ContentDecryptorDelegate::UpdateSession(uint32 session_id,
312 const uint8* response,
313 int response_length) {
314 PP_Var response_array =
315 PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
316 response_length, response);
317 plugin_decryption_interface_->UpdateSession(
318 pp_instance_, session_id, response_array);
322 bool ContentDecryptorDelegate::ReleaseSession(uint32 session_id) {
323 plugin_decryption_interface_->ReleaseSession(pp_instance_, session_id);
327 // TODO(xhwang): Remove duplication of code in Decrypt(),
328 // DecryptAndDecodeAudio() and DecryptAndDecodeVideo().
329 bool ContentDecryptorDelegate::Decrypt(
330 Decryptor::StreamType stream_type,
331 const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
332 const Decryptor::DecryptCB& decrypt_cb) {
333 DVLOG(3) << "Decrypt() - stream_type: " << stream_type;
335 // |{audio|video}_input_resource_| is not being used by the plugin
336 // now because there is only one pending audio/video decrypt request at any
337 // time. This is enforced by the media pipeline.
338 scoped_refptr<PPB_Buffer_Impl> encrypted_resource;
339 if (!MakeMediaBufferResource(
340 stream_type, encrypted_buffer, &encrypted_resource) ||
341 !encrypted_resource.get()) {
344 ScopedPPResource pp_resource(encrypted_resource.get());
346 const uint32_t request_id = next_decryption_request_id_++;
347 DVLOG(2) << "Decrypt() - request_id " << request_id;
349 PP_EncryptedBlockInfo block_info = {};
350 DCHECK(encrypted_buffer->decrypt_config());
351 if (!MakeEncryptedBlockInfo(encrypted_buffer, request_id, &block_info)) {
355 // There is only one pending decrypt request at any time per stream. This is
356 // enforced by the media pipeline.
357 switch (stream_type) {
358 case Decryptor::kAudio:
359 audio_decrypt_cb_.Set(request_id, decrypt_cb);
361 case Decryptor::kVideo:
362 video_decrypt_cb_.Set(request_id, decrypt_cb);
369 SetBufferToFreeInTrackingInfo(&block_info.tracking_info);
371 plugin_decryption_interface_->Decrypt(pp_instance_,
377 bool ContentDecryptorDelegate::CancelDecrypt(
378 Decryptor::StreamType stream_type) {
379 DVLOG(3) << "CancelDecrypt() - stream_type: " << stream_type;
381 Decryptor::DecryptCB decrypt_cb;
382 switch (stream_type) {
383 case Decryptor::kAudio:
384 // Release the shared memory as it can still be in use by the plugin.
385 // The next Decrypt() call will need to allocate a new shared memory
387 audio_input_resource_ = NULL;
388 decrypt_cb = audio_decrypt_cb_.ResetAndReturn();
390 case Decryptor::kVideo:
391 // Release the shared memory as it can still be in use by the plugin.
392 // The next Decrypt() call will need to allocate a new shared memory
394 video_input_resource_ = NULL;
395 decrypt_cb = video_decrypt_cb_.ResetAndReturn();
402 if (!decrypt_cb.is_null())
403 decrypt_cb.Run(Decryptor::kSuccess, NULL);
408 bool ContentDecryptorDelegate::InitializeAudioDecoder(
409 const media::AudioDecoderConfig& decoder_config,
410 const Decryptor::DecoderInitCB& init_cb) {
411 PP_AudioDecoderConfig pp_decoder_config;
412 pp_decoder_config.codec =
413 MediaAudioCodecToPpAudioCodec(decoder_config.codec());
414 pp_decoder_config.channel_count =
415 media::ChannelLayoutToChannelCount(decoder_config.channel_layout());
416 pp_decoder_config.bits_per_channel = decoder_config.bits_per_channel();
417 pp_decoder_config.samples_per_second = decoder_config.samples_per_second();
418 pp_decoder_config.request_id = next_decryption_request_id_++;
420 audio_samples_per_second_ = pp_decoder_config.samples_per_second;
421 audio_channel_count_ = pp_decoder_config.channel_count;
422 audio_channel_layout_ = decoder_config.channel_layout();
424 scoped_refptr<PPB_Buffer_Impl> extra_data_resource;
425 if (!MakeBufferResource(pp_instance_,
426 decoder_config.extra_data(),
427 decoder_config.extra_data_size(),
428 &extra_data_resource)) {
431 ScopedPPResource pp_resource(extra_data_resource.get());
433 audio_decoder_init_cb_.Set(pp_decoder_config.request_id, init_cb);
434 plugin_decryption_interface_->InitializeAudioDecoder(pp_instance_,
440 bool ContentDecryptorDelegate::InitializeVideoDecoder(
441 const media::VideoDecoderConfig& decoder_config,
442 const Decryptor::DecoderInitCB& init_cb) {
443 PP_VideoDecoderConfig pp_decoder_config;
444 pp_decoder_config.codec =
445 MediaVideoCodecToPpVideoCodec(decoder_config.codec());
446 pp_decoder_config.profile =
447 MediaVideoCodecProfileToPpVideoCodecProfile(decoder_config.profile());
448 pp_decoder_config.format =
449 MediaVideoFormatToPpDecryptedFrameFormat(decoder_config.format());
450 pp_decoder_config.width = decoder_config.coded_size().width();
451 pp_decoder_config.height = decoder_config.coded_size().height();
452 pp_decoder_config.request_id = next_decryption_request_id_++;
454 scoped_refptr<PPB_Buffer_Impl> extra_data_resource;
455 if (!MakeBufferResource(pp_instance_,
456 decoder_config.extra_data(),
457 decoder_config.extra_data_size(),
458 &extra_data_resource)) {
461 ScopedPPResource pp_resource(extra_data_resource.get());
463 video_decoder_init_cb_.Set(pp_decoder_config.request_id, init_cb);
464 natural_size_ = decoder_config.natural_size();
466 plugin_decryption_interface_->InitializeVideoDecoder(pp_instance_,
472 bool ContentDecryptorDelegate::DeinitializeDecoder(
473 Decryptor::StreamType stream_type) {
474 CancelDecode(stream_type);
476 if (stream_type == Decryptor::kVideo)
477 natural_size_ = gfx::Size();
479 // TODO(tomfinegan): Add decoder deinitialize request tracking, and get
480 // stream type from media stack.
481 plugin_decryption_interface_->DeinitializeDecoder(
482 pp_instance_, MediaDecryptorStreamTypeToPpStreamType(stream_type), 0);
486 bool ContentDecryptorDelegate::ResetDecoder(Decryptor::StreamType stream_type) {
487 CancelDecode(stream_type);
489 // TODO(tomfinegan): Add decoder reset request tracking.
490 plugin_decryption_interface_->ResetDecoder(
491 pp_instance_, MediaDecryptorStreamTypeToPpStreamType(stream_type), 0);
495 bool ContentDecryptorDelegate::DecryptAndDecodeAudio(
496 const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
497 const Decryptor::AudioDecodeCB& audio_decode_cb) {
498 // |audio_input_resource_| is not being used by the plugin now
499 // because there is only one pending audio decode request at any time.
500 // This is enforced by the media pipeline.
501 scoped_refptr<PPB_Buffer_Impl> encrypted_resource;
502 if (!MakeMediaBufferResource(
503 Decryptor::kAudio, encrypted_buffer, &encrypted_resource)) {
507 // The resource should not be NULL for non-EOS buffer.
508 if (!encrypted_buffer->end_of_stream() && !encrypted_resource.get())
511 const uint32_t request_id = next_decryption_request_id_++;
512 DVLOG(2) << "DecryptAndDecodeAudio() - request_id " << request_id;
514 PP_EncryptedBlockInfo block_info = {};
515 if (!MakeEncryptedBlockInfo(encrypted_buffer, request_id, &block_info)) {
519 SetBufferToFreeInTrackingInfo(&block_info.tracking_info);
521 // There is only one pending audio decode request at any time. This is
522 // enforced by the media pipeline. If this DCHECK is violated, our buffer
523 // reuse policy is not valid, and we may have race problems for the shared
525 audio_decode_cb_.Set(request_id, audio_decode_cb);
527 ScopedPPResource pp_resource(encrypted_resource.get());
528 plugin_decryption_interface_->DecryptAndDecode(pp_instance_,
529 PP_DECRYPTORSTREAMTYPE_AUDIO,
535 bool ContentDecryptorDelegate::DecryptAndDecodeVideo(
536 const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
537 const Decryptor::VideoDecodeCB& video_decode_cb) {
538 // |video_input_resource_| is not being used by the plugin now
539 // because there is only one pending video decode request at any time.
540 // This is enforced by the media pipeline.
541 scoped_refptr<PPB_Buffer_Impl> encrypted_resource;
542 if (!MakeMediaBufferResource(
543 Decryptor::kVideo, encrypted_buffer, &encrypted_resource)) {
547 // The resource should not be 0 for non-EOS buffer.
548 if (!encrypted_buffer->end_of_stream() && !encrypted_resource.get())
551 const uint32_t request_id = next_decryption_request_id_++;
552 DVLOG(2) << "DecryptAndDecodeVideo() - request_id " << request_id;
553 TRACE_EVENT_ASYNC_BEGIN0(
554 "media", "ContentDecryptorDelegate::DecryptAndDecodeVideo", request_id);
556 PP_EncryptedBlockInfo block_info = {};
557 if (!MakeEncryptedBlockInfo(encrypted_buffer, request_id, &block_info)) {
561 SetBufferToFreeInTrackingInfo(&block_info.tracking_info);
563 // Only one pending video decode request at any time. This is enforced by the
564 // media pipeline. If this DCHECK is violated, our buffer
565 // reuse policy is not valid, and we may have race problems for the shared
567 video_decode_cb_.Set(request_id, video_decode_cb);
569 // TODO(tomfinegan): Need to get stream type from media stack.
570 ScopedPPResource pp_resource(encrypted_resource.get());
571 plugin_decryption_interface_->DecryptAndDecode(pp_instance_,
572 PP_DECRYPTORSTREAMTYPE_VIDEO,
578 void ContentDecryptorDelegate::OnSessionCreated(uint32 session_id,
579 PP_Var web_session_id_var) {
580 if (session_created_cb_.is_null())
583 StringVar* session_id_string = StringVar::FromPPVar(web_session_id_var);
585 if (!session_id_string) {
586 OnSessionError(session_id, media::MediaKeys::kUnknownError, 0);
590 session_created_cb_.Run(session_id, session_id_string->value());
593 void ContentDecryptorDelegate::OnSessionMessage(uint32 session_id,
595 PP_Var default_url_var) {
596 if (session_message_cb_.is_null())
599 ArrayBufferVar* message_array_buffer = ArrayBufferVar::FromPPVar(message_var);
601 std::vector<uint8> message;
602 if (message_array_buffer) {
603 const uint8* data = static_cast<const uint8*>(message_array_buffer->Map());
604 message.assign(data, data + message_array_buffer->ByteLength());
607 StringVar* default_url_string = StringVar::FromPPVar(default_url_var);
609 if (!default_url_string) {
610 OnSessionError(session_id, media::MediaKeys::kUnknownError, 0);
614 session_message_cb_.Run(session_id, message, default_url_string->value());
617 void ContentDecryptorDelegate::OnSessionReady(uint32 session_id) {
618 if (session_ready_cb_.is_null())
621 session_ready_cb_.Run(session_id);
624 void ContentDecryptorDelegate::OnSessionClosed(uint32 session_id) {
625 if (session_closed_cb_.is_null())
628 session_closed_cb_.Run(session_id);
631 void ContentDecryptorDelegate::OnSessionError(uint32 session_id,
633 uint32_t system_code) {
634 if (session_error_cb_.is_null())
637 session_error_cb_.Run(session_id,
638 static_cast<media::MediaKeys::KeyError>(media_error),
642 void ContentDecryptorDelegate::DecoderInitializeDone(
643 PP_DecryptorStreamType decoder_type,
646 if (decoder_type == PP_DECRYPTORSTREAMTYPE_AUDIO) {
647 // If the request ID is not valid or does not match what's saved, do
649 if (request_id == 0 || !audio_decoder_init_cb_.Matches(request_id))
652 audio_decoder_init_cb_.ResetAndReturn().Run(PP_ToBool(success));
654 if (request_id == 0 || !video_decoder_init_cb_.Matches(request_id))
658 natural_size_ = gfx::Size();
660 video_decoder_init_cb_.ResetAndReturn().Run(PP_ToBool(success));
664 void ContentDecryptorDelegate::DecoderDeinitializeDone(
665 PP_DecryptorStreamType decoder_type,
666 uint32_t request_id) {
667 // TODO(tomfinegan): Add decoder stop completion handling.
670 void ContentDecryptorDelegate::DecoderResetDone(
671 PP_DecryptorStreamType decoder_type,
672 uint32_t request_id) {
673 // TODO(tomfinegan): Add decoder reset completion handling.
676 void ContentDecryptorDelegate::DeliverBlock(
677 PP_Resource decrypted_block,
678 const PP_DecryptedBlockInfo* block_info) {
681 FreeBuffer(block_info->tracking_info.buffer_id);
683 const uint32_t request_id = block_info->tracking_info.request_id;
684 DVLOG(2) << "DeliverBlock() - request_id: " << request_id;
686 // If the request ID is not valid or does not match what's saved, do nothing.
687 if (request_id == 0) {
688 DVLOG(1) << "DeliverBlock() - invalid request_id " << request_id;
692 Decryptor::DecryptCB decrypt_cb;
693 if (audio_decrypt_cb_.Matches(request_id)) {
694 decrypt_cb = audio_decrypt_cb_.ResetAndReturn();
695 } else if (video_decrypt_cb_.Matches(request_id)) {
696 decrypt_cb = video_decrypt_cb_.ResetAndReturn();
698 DVLOG(1) << "DeliverBlock() - request_id " << request_id << " not found";
702 Decryptor::Status status =
703 PpDecryptResultToMediaDecryptorStatus(block_info->result);
704 if (status != Decryptor::kSuccess) {
705 decrypt_cb.Run(status, NULL);
709 EnterResourceNoLock<PPB_Buffer_API> enter(decrypted_block, true);
710 if (!enter.succeeded()) {
711 decrypt_cb.Run(Decryptor::kError, NULL);
714 BufferAutoMapper mapper(enter.object());
715 if (!mapper.data() || !mapper.size() ||
716 mapper.size() < block_info->data_size) {
717 decrypt_cb.Run(Decryptor::kError, NULL);
721 // TODO(tomfinegan): Find a way to take ownership of the shared memory
722 // managed by the PPB_Buffer_Dev, and avoid the extra copy.
723 scoped_refptr<media::DecoderBuffer> decrypted_buffer(
724 media::DecoderBuffer::CopyFrom(
725 static_cast<uint8*>(mapper.data()), block_info->data_size));
726 decrypted_buffer->set_timestamp(base::TimeDelta::FromMicroseconds(
727 block_info->tracking_info.timestamp));
728 decrypt_cb.Run(Decryptor::kSuccess, decrypted_buffer);
731 // Use a non-class-member function here so that if for some reason
732 // ContentDecryptorDelegate is destroyed before VideoFrame calls this callback,
733 // we can still get the shared memory unmapped.
734 static void BufferNoLongerNeeded(
735 const scoped_refptr<PPB_Buffer_Impl>& ppb_buffer,
736 base::Closure buffer_no_longer_needed_cb) {
738 buffer_no_longer_needed_cb.Run();
741 // Enters |resource|, maps shared memory and returns pointer of mapped data.
742 // Returns NULL if any error occurs.
743 static uint8* GetMappedBuffer(PP_Resource resource,
744 scoped_refptr<PPB_Buffer_Impl>* ppb_buffer) {
745 EnterResourceNoLock<PPB_Buffer_API> enter(resource, true);
746 if (!enter.succeeded())
749 uint8* mapped_data = static_cast<uint8*>(enter.object()->Map());
750 if (!enter.object()->IsMapped() || !mapped_data)
753 uint32_t mapped_size = 0;
754 if (!enter.object()->Describe(&mapped_size) || !mapped_size) {
755 enter.object()->Unmap();
759 *ppb_buffer = static_cast<PPB_Buffer_Impl*>(enter.object());
764 void ContentDecryptorDelegate::DeliverFrame(
765 PP_Resource decrypted_frame,
766 const PP_DecryptedFrameInfo* frame_info) {
769 const uint32_t request_id = frame_info->tracking_info.request_id;
770 DVLOG(2) << "DeliverFrame() - request_id: " << request_id;
772 // If the request ID is not valid or does not match what's saved, do nothing.
773 if (request_id == 0 || !video_decode_cb_.Matches(request_id)) {
774 DVLOG(1) << "DeliverFrame() - request_id " << request_id << " not found";
775 FreeBuffer(frame_info->tracking_info.buffer_id);
779 TRACE_EVENT_ASYNC_END0(
780 "media", "ContentDecryptorDelegate::DecryptAndDecodeVideo", request_id);
782 Decryptor::VideoDecodeCB video_decode_cb = video_decode_cb_.ResetAndReturn();
784 Decryptor::Status status =
785 PpDecryptResultToMediaDecryptorStatus(frame_info->result);
786 if (status != Decryptor::kSuccess) {
787 DCHECK(!frame_info->tracking_info.buffer_id);
788 video_decode_cb.Run(status, NULL);
792 scoped_refptr<PPB_Buffer_Impl> ppb_buffer;
793 uint8* frame_data = GetMappedBuffer(decrypted_frame, &ppb_buffer);
795 FreeBuffer(frame_info->tracking_info.buffer_id);
796 video_decode_cb.Run(Decryptor::kError, NULL);
800 gfx::Size frame_size(frame_info->width, frame_info->height);
801 DCHECK_EQ(frame_info->format, PP_DECRYPTEDFRAMEFORMAT_YV12);
803 scoped_refptr<media::VideoFrame> decoded_frame =
804 media::VideoFrame::WrapExternalYuvData(
805 media::VideoFrame::YV12,
807 gfx::Rect(frame_size),
809 frame_info->strides[PP_DECRYPTEDFRAMEPLANES_Y],
810 frame_info->strides[PP_DECRYPTEDFRAMEPLANES_U],
811 frame_info->strides[PP_DECRYPTEDFRAMEPLANES_V],
812 frame_data + frame_info->plane_offsets[PP_DECRYPTEDFRAMEPLANES_Y],
813 frame_data + frame_info->plane_offsets[PP_DECRYPTEDFRAMEPLANES_U],
814 frame_data + frame_info->plane_offsets[PP_DECRYPTEDFRAMEPLANES_V],
815 base::TimeDelta::FromMicroseconds(
816 frame_info->tracking_info.timestamp),
817 media::BindToCurrentLoop(
818 base::Bind(&BufferNoLongerNeeded,
820 base::Bind(&ContentDecryptorDelegate::FreeBuffer,
822 frame_info->tracking_info.buffer_id))));
824 video_decode_cb.Run(Decryptor::kSuccess, decoded_frame);
827 void ContentDecryptorDelegate::DeliverSamples(
828 PP_Resource audio_frames,
829 const PP_DecryptedSampleInfo* sample_info) {
832 FreeBuffer(sample_info->tracking_info.buffer_id);
834 const uint32_t request_id = sample_info->tracking_info.request_id;
835 DVLOG(2) << "DeliverSamples() - request_id: " << request_id;
837 // If the request ID is not valid or does not match what's saved, do nothing.
838 if (request_id == 0 || !audio_decode_cb_.Matches(request_id)) {
839 DVLOG(1) << "DeliverSamples() - request_id " << request_id << " not found";
843 Decryptor::AudioDecodeCB audio_decode_cb = audio_decode_cb_.ResetAndReturn();
845 const Decryptor::AudioBuffers empty_frames;
847 Decryptor::Status status =
848 PpDecryptResultToMediaDecryptorStatus(sample_info->result);
849 if (status != Decryptor::kSuccess) {
850 audio_decode_cb.Run(status, empty_frames);
854 media::SampleFormat sample_format =
855 PpDecryptedSampleFormatToMediaSampleFormat(sample_info->format);
857 Decryptor::AudioBuffers audio_frame_list;
858 if (!DeserializeAudioFrames(audio_frames,
859 sample_info->data_size,
861 &audio_frame_list)) {
862 NOTREACHED() << "CDM did not serialize the buffer correctly.";
863 audio_decode_cb.Run(Decryptor::kError, empty_frames);
867 audio_decode_cb.Run(Decryptor::kSuccess, audio_frame_list);
870 // TODO(xhwang): Try to remove duplicate logic here and in CancelDecrypt().
871 void ContentDecryptorDelegate::CancelDecode(Decryptor::StreamType stream_type) {
872 switch (stream_type) {
873 case Decryptor::kAudio:
874 // Release the shared memory as it can still be in use by the plugin.
875 // The next DecryptAndDecode() call will need to allocate a new shared
877 audio_input_resource_ = NULL;
878 if (!audio_decode_cb_.is_null())
879 audio_decode_cb_.ResetAndReturn().Run(Decryptor::kSuccess,
880 Decryptor::AudioBuffers());
882 case Decryptor::kVideo:
883 // Release the shared memory as it can still be in use by the plugin.
884 // The next DecryptAndDecode() call will need to allocate a new shared
886 video_input_resource_ = NULL;
887 if (!video_decode_cb_.is_null())
888 video_decode_cb_.ResetAndReturn().Run(Decryptor::kSuccess, NULL);
895 bool ContentDecryptorDelegate::MakeMediaBufferResource(
896 Decryptor::StreamType stream_type,
897 const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
898 scoped_refptr<PPB_Buffer_Impl>* resource) {
899 TRACE_EVENT0("media", "ContentDecryptorDelegate::MakeMediaBufferResource");
901 // End of stream buffers are represented as null resources.
902 if (encrypted_buffer->end_of_stream()) {
907 DCHECK(stream_type == Decryptor::kAudio || stream_type == Decryptor::kVideo);
908 scoped_refptr<PPB_Buffer_Impl>& media_resource =
909 (stream_type == Decryptor::kAudio) ? audio_input_resource_
910 : video_input_resource_;
912 const size_t data_size = static_cast<size_t>(encrypted_buffer->data_size());
913 if (!media_resource.get() || media_resource->size() < data_size) {
914 // Either the buffer hasn't been created yet, or we have one that isn't big
915 // enough to fit |size| bytes.
917 // Media resource size starts from |kMinimumMediaBufferSize| and grows
918 // exponentially to avoid frequent re-allocation of PPB_Buffer_Impl,
919 // which is usually expensive. Since input media buffers are compressed,
920 // they are usually small (compared to outputs). The over-allocated memory
921 // should be negligible.
922 const uint32_t kMinimumMediaBufferSize = 1024;
923 uint32_t media_resource_size =
924 media_resource.get() ? media_resource->size() : kMinimumMediaBufferSize;
925 while (media_resource_size < data_size)
926 media_resource_size *= 2;
928 DVLOG(2) << "Size of media buffer for "
929 << ((stream_type == Decryptor::kAudio) ? "audio" : "video")
930 << " stream bumped to " << media_resource_size
931 << " bytes to fit input.";
932 media_resource = PPB_Buffer_Impl::CreateResource(pp_instance_,
933 media_resource_size);
934 if (!media_resource.get())
938 BufferAutoMapper mapper(media_resource.get());
939 if (!mapper.data() || mapper.size() < data_size) {
940 media_resource = NULL;
943 memcpy(mapper.data(), encrypted_buffer->data(), data_size);
945 *resource = media_resource;
949 void ContentDecryptorDelegate::FreeBuffer(uint32_t buffer_id) {
951 free_buffers_.push(buffer_id);
954 void ContentDecryptorDelegate::SetBufferToFreeInTrackingInfo(
955 PP_DecryptTrackingInfo* tracking_info) {
956 DCHECK_EQ(tracking_info->buffer_id, 0u);
958 if (free_buffers_.empty())
961 tracking_info->buffer_id = free_buffers_.front();
965 bool ContentDecryptorDelegate::DeserializeAudioFrames(
966 PP_Resource audio_frames,
968 media::SampleFormat sample_format,
969 Decryptor::AudioBuffers* frames) {
971 EnterResourceNoLock<PPB_Buffer_API> enter(audio_frames, true);
972 if (!enter.succeeded())
975 BufferAutoMapper mapper(enter.object());
976 if (!mapper.data() || !mapper.size() ||
977 mapper.size() < static_cast<uint32_t>(data_size))
980 // TODO(jrummell): Pass ownership of data() directly to AudioBuffer to avoid
981 // the copy. Since it is possible to get multiple buffers, it would need to be
982 // sliced and ref counted appropriately. http://crbug.com/255576.
983 const uint8* cur = static_cast<uint8*>(mapper.data());
984 size_t bytes_left = data_size;
986 const int audio_bytes_per_frame =
987 media::SampleFormatToBytesPerChannel(sample_format) *
988 audio_channel_count_;
989 if (audio_bytes_per_frame <= 0)
992 // Allocate space for the channel pointers given to AudioBuffer.
993 std::vector<const uint8*> channel_ptrs(
994 audio_channel_count_, static_cast<const uint8*>(NULL));
997 int64 frame_size = -1;
998 const size_t kHeaderSize = sizeof(timestamp) + sizeof(frame_size);
1000 if (bytes_left < kHeaderSize)
1003 memcpy(×tamp, cur, sizeof(timestamp));
1004 cur += sizeof(timestamp);
1005 bytes_left -= sizeof(timestamp);
1007 memcpy(&frame_size, cur, sizeof(frame_size));
1008 cur += sizeof(frame_size);
1009 bytes_left -= sizeof(frame_size);
1011 // We should *not* have empty frames in the list.
1012 if (frame_size <= 0 ||
1013 bytes_left < base::checked_cast<size_t>(frame_size)) {
1017 // Setup channel pointers. AudioBuffer::CopyFrom() will only use the first
1018 // one in the case of interleaved data.
1019 const int size_per_channel = frame_size / audio_channel_count_;
1020 for (int i = 0; i < audio_channel_count_; ++i)
1021 channel_ptrs[i] = cur + i * size_per_channel;
1023 const int frame_count = frame_size / audio_bytes_per_frame;
1024 scoped_refptr<media::AudioBuffer> frame = media::AudioBuffer::CopyFrom(
1026 audio_channel_layout_,
1027 audio_channel_count_,
1028 audio_samples_per_second_,
1031 base::TimeDelta::FromMicroseconds(timestamp),
1032 base::TimeDelta::FromMicroseconds(audio_samples_per_second_ /
1034 frames->push_back(frame);
1037 bytes_left -= frame_size;
1038 } while (bytes_left > 0);
1043 void ContentDecryptorDelegate::SatisfyAllPendingCallbacksOnError() {
1044 if (!audio_decoder_init_cb_.is_null())
1045 audio_decoder_init_cb_.ResetAndReturn().Run(false);
1047 if (!video_decoder_init_cb_.is_null())
1048 video_decoder_init_cb_.ResetAndReturn().Run(false);
1050 audio_input_resource_ = NULL;
1051 video_input_resource_ = NULL;
1053 if (!audio_decrypt_cb_.is_null())
1054 audio_decrypt_cb_.ResetAndReturn().Run(media::Decryptor::kError, NULL);
1056 if (!video_decrypt_cb_.is_null())
1057 video_decrypt_cb_.ResetAndReturn().Run(media::Decryptor::kError, NULL);
1059 if (!audio_decode_cb_.is_null()) {
1060 const media::Decryptor::AudioBuffers empty_frames;
1061 audio_decode_cb_.ResetAndReturn().Run(media::Decryptor::kError,
1065 if (!video_decode_cb_.is_null())
1066 video_decode_cb_.ResetAndReturn().Run(media::Decryptor::kError, NULL);
1069 } // namespace content