Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / content / renderer / pepper / content_decryptor_delegate.cc
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 "content/renderer/pepper/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/metrics/sparse_histogram.h"
11 #include "base/numerics/safe_conversions.h"
12 #include "content/renderer/media/crypto/key_systems.h"
13 #include "content/renderer/pepper/ppb_buffer_impl.h"
14 #include "media/base/audio_buffer.h"
15 #include "media/base/audio_decoder_config.h"
16 #include "media/base/bind_to_current_loop.h"
17 #include "media/base/cdm_promise.h"
18 #include "media/base/channel_layout.h"
19 #include "media/base/data_buffer.h"
20 #include "media/base/decoder_buffer.h"
21 #include "media/base/decrypt_config.h"
22 #include "media/base/limits.h"
23 #include "media/base/video_decoder_config.h"
24 #include "media/base/video_frame.h"
25 #include "media/base/video_util.h"
26 #include "ppapi/shared_impl/array_var.h"
27 #include "ppapi/shared_impl/scoped_pp_resource.h"
28 #include "ppapi/shared_impl/time_conversion.h"
29 #include "ppapi/shared_impl/var.h"
30 #include "ppapi/shared_impl/var_tracker.h"
31 #include "ppapi/thunk/enter.h"
32 #include "ppapi/thunk/ppb_buffer_api.h"
33 #include "ui/gfx/rect.h"
34
35 using media::CdmPromise;
36 using media::Decryptor;
37 using media::KeyIdsPromise;
38 using media::MediaKeys;
39 using media::NewSessionCdmPromise;
40 using media::SimpleCdmPromise;
41 using ppapi::ArrayBufferVar;
42 using ppapi::ArrayVar;
43 using ppapi::PpapiGlobals;
44 using ppapi::ScopedPPResource;
45 using ppapi::StringVar;
46 using ppapi::thunk::EnterResourceNoLock;
47 using ppapi::thunk::PPB_Buffer_API;
48
49 namespace content {
50
51 namespace {
52
53 // Fills |resource| with a PPB_Buffer_Impl and copies |data| into the buffer
54 // resource. The |*resource|, if valid, will be in the ResourceTracker with a
55 // reference-count of 0. If |data| is NULL, sets |*resource| to NULL. Returns
56 // true upon success and false if any error happened.
57 bool MakeBufferResource(PP_Instance instance,
58                         const uint8* data,
59                         uint32_t size,
60                         scoped_refptr<PPB_Buffer_Impl>* resource) {
61   TRACE_EVENT0("media", "ContentDecryptorDelegate - MakeBufferResource");
62   DCHECK(resource);
63
64   if (!data || !size) {
65     DCHECK(!data && !size);
66     resource = NULL;
67     return true;
68   }
69
70   scoped_refptr<PPB_Buffer_Impl> buffer(
71       PPB_Buffer_Impl::CreateResource(instance, size));
72   if (!buffer.get())
73     return false;
74
75   BufferAutoMapper mapper(buffer.get());
76   if (!mapper.data() || mapper.size() < size)
77     return false;
78   memcpy(mapper.data(), data, size);
79
80   *resource = buffer;
81   return true;
82 }
83
84 // Copies the content of |str| into |array|.
85 // Returns true if copy succeeded. Returns false if copy failed, e.g. if the
86 // |array_size| is smaller than the |str| length.
87 template <uint32_t array_size>
88 bool CopyStringToArray(const std::string& str, uint8 (&array)[array_size]) {
89   if (array_size < str.size())
90     return false;
91
92   memcpy(array, str.data(), str.size());
93   return true;
94 }
95
96 // Fills the |block_info| with information from |encrypted_buffer|.
97 //
98 // Returns true if |block_info| is successfully filled. Returns false
99 // otherwise.
100 bool MakeEncryptedBlockInfo(
101     const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
102     uint32_t request_id,
103     PP_EncryptedBlockInfo* block_info) {
104   // TODO(xhwang): Fix initialization of PP_EncryptedBlockInfo here and
105   // anywhere else.
106   memset(block_info, 0, sizeof(*block_info));
107   block_info->tracking_info.request_id = request_id;
108
109   // EOS buffers need a request ID and nothing more.
110   if (encrypted_buffer->end_of_stream())
111     return true;
112
113   DCHECK(encrypted_buffer->data_size())
114       << "DecryptConfig is set on an empty buffer";
115
116   block_info->tracking_info.timestamp =
117       encrypted_buffer->timestamp().InMicroseconds();
118   block_info->data_size = encrypted_buffer->data_size();
119
120   const media::DecryptConfig* decrypt_config =
121       encrypted_buffer->decrypt_config();
122
123   if (!CopyStringToArray(decrypt_config->key_id(), block_info->key_id) ||
124       !CopyStringToArray(decrypt_config->iv(), block_info->iv))
125     return false;
126
127   block_info->key_id_size = decrypt_config->key_id().size();
128   block_info->iv_size = decrypt_config->iv().size();
129
130   if (decrypt_config->subsamples().size() > arraysize(block_info->subsamples))
131     return false;
132
133   block_info->num_subsamples = decrypt_config->subsamples().size();
134   for (uint32_t i = 0; i < block_info->num_subsamples; ++i) {
135     block_info->subsamples[i].clear_bytes =
136         decrypt_config->subsamples()[i].clear_bytes;
137     block_info->subsamples[i].cipher_bytes =
138         decrypt_config->subsamples()[i].cypher_bytes;
139   }
140
141   return true;
142 }
143
144 PP_AudioCodec MediaAudioCodecToPpAudioCodec(media::AudioCodec codec) {
145   switch (codec) {
146     case media::kCodecVorbis:
147       return PP_AUDIOCODEC_VORBIS;
148     case media::kCodecAAC:
149       return PP_AUDIOCODEC_AAC;
150     default:
151       return PP_AUDIOCODEC_UNKNOWN;
152   }
153 }
154
155 PP_VideoCodec MediaVideoCodecToPpVideoCodec(media::VideoCodec codec) {
156   switch (codec) {
157     case media::kCodecVP8:
158       return PP_VIDEOCODEC_VP8;
159     case media::kCodecH264:
160       return PP_VIDEOCODEC_H264;
161     case media::kCodecVP9:
162       return PP_VIDEOCODEC_VP9;
163     default:
164       return PP_VIDEOCODEC_UNKNOWN;
165   }
166 }
167
168 PP_VideoCodecProfile MediaVideoCodecProfileToPpVideoCodecProfile(
169     media::VideoCodecProfile profile) {
170   switch (profile) {
171     case media::VP8PROFILE_ANY:
172     case media::VP9PROFILE_ANY:
173       return PP_VIDEOCODECPROFILE_NOT_NEEDED;
174     case media::H264PROFILE_BASELINE:
175       return PP_VIDEOCODECPROFILE_H264_BASELINE;
176     case media::H264PROFILE_MAIN:
177       return PP_VIDEOCODECPROFILE_H264_MAIN;
178     case media::H264PROFILE_EXTENDED:
179       return PP_VIDEOCODECPROFILE_H264_EXTENDED;
180     case media::H264PROFILE_HIGH:
181       return PP_VIDEOCODECPROFILE_H264_HIGH;
182     case media::H264PROFILE_HIGH10PROFILE:
183       return PP_VIDEOCODECPROFILE_H264_HIGH_10;
184     case media::H264PROFILE_HIGH422PROFILE:
185       return PP_VIDEOCODECPROFILE_H264_HIGH_422;
186     case media::H264PROFILE_HIGH444PREDICTIVEPROFILE:
187       return PP_VIDEOCODECPROFILE_H264_HIGH_444_PREDICTIVE;
188     default:
189       return PP_VIDEOCODECPROFILE_UNKNOWN;
190   }
191 }
192
193 PP_DecryptedFrameFormat MediaVideoFormatToPpDecryptedFrameFormat(
194     media::VideoFrame::Format format) {
195   switch (format) {
196     case media::VideoFrame::YV12:
197       return PP_DECRYPTEDFRAMEFORMAT_YV12;
198     case media::VideoFrame::I420:
199       return PP_DECRYPTEDFRAMEFORMAT_I420;
200     default:
201       return PP_DECRYPTEDFRAMEFORMAT_UNKNOWN;
202   }
203 }
204
205 Decryptor::Status PpDecryptResultToMediaDecryptorStatus(
206     PP_DecryptResult result) {
207   switch (result) {
208     case PP_DECRYPTRESULT_SUCCESS:
209       return Decryptor::kSuccess;
210     case PP_DECRYPTRESULT_DECRYPT_NOKEY:
211       return Decryptor::kNoKey;
212     case PP_DECRYPTRESULT_NEEDMOREDATA:
213       return Decryptor::kNeedMoreData;
214     case PP_DECRYPTRESULT_DECRYPT_ERROR:
215       return Decryptor::kError;
216     case PP_DECRYPTRESULT_DECODE_ERROR:
217       return Decryptor::kError;
218     default:
219       NOTREACHED();
220       return Decryptor::kError;
221   }
222 }
223
224 PP_DecryptorStreamType MediaDecryptorStreamTypeToPpStreamType(
225     Decryptor::StreamType stream_type) {
226   switch (stream_type) {
227     case Decryptor::kAudio:
228       return PP_DECRYPTORSTREAMTYPE_AUDIO;
229     case Decryptor::kVideo:
230       return PP_DECRYPTORSTREAMTYPE_VIDEO;
231     default:
232       NOTREACHED();
233       return PP_DECRYPTORSTREAMTYPE_VIDEO;
234   }
235 }
236
237 media::SampleFormat PpDecryptedSampleFormatToMediaSampleFormat(
238     PP_DecryptedSampleFormat result) {
239   switch (result) {
240     case PP_DECRYPTEDSAMPLEFORMAT_U8:
241       return media::kSampleFormatU8;
242     case PP_DECRYPTEDSAMPLEFORMAT_S16:
243       return media::kSampleFormatS16;
244     case PP_DECRYPTEDSAMPLEFORMAT_S32:
245       return media::kSampleFormatS32;
246     case PP_DECRYPTEDSAMPLEFORMAT_F32:
247       return media::kSampleFormatF32;
248     case PP_DECRYPTEDSAMPLEFORMAT_PLANAR_S16:
249       return media::kSampleFormatPlanarS16;
250     case PP_DECRYPTEDSAMPLEFORMAT_PLANAR_F32:
251       return media::kSampleFormatPlanarF32;
252     default:
253       NOTREACHED();
254       return media::kUnknownSampleFormat;
255   }
256 }
257
258 PP_SessionType MediaSessionTypeToPpSessionType(
259     MediaKeys::SessionType session_type) {
260   switch (session_type) {
261     case MediaKeys::TEMPORARY_SESSION:
262       return PP_SESSIONTYPE_TEMPORARY;
263     case MediaKeys::PERSISTENT_SESSION:
264       return PP_SESSIONTYPE_PERSISTENT;
265     default:
266       NOTREACHED();
267       return PP_SESSIONTYPE_TEMPORARY;
268   }
269 }
270
271 MediaKeys::Exception PpExceptionTypeToMediaException(
272     PP_CdmExceptionCode exception_code) {
273   switch (exception_code) {
274     case PP_CDMEXCEPTIONCODE_NOTSUPPORTEDERROR:
275       return MediaKeys::NOT_SUPPORTED_ERROR;
276     case PP_CDMEXCEPTIONCODE_INVALIDSTATEERROR:
277       return MediaKeys::INVALID_STATE_ERROR;
278     case PP_CDMEXCEPTIONCODE_INVALIDACCESSERROR:
279       return MediaKeys::INVALID_ACCESS_ERROR;
280     case PP_CDMEXCEPTIONCODE_QUOTAEXCEEDEDERROR:
281       return MediaKeys::QUOTA_EXCEEDED_ERROR;
282     case PP_CDMEXCEPTIONCODE_UNKNOWNERROR:
283       return MediaKeys::UNKNOWN_ERROR;
284     case PP_CDMEXCEPTIONCODE_CLIENTERROR:
285       return MediaKeys::CLIENT_ERROR;
286     case PP_CDMEXCEPTIONCODE_OUTPUTERROR:
287       return MediaKeys::OUTPUT_ERROR;
288     default:
289       NOTREACHED();
290       return MediaKeys::UNKNOWN_ERROR;
291   }
292 }
293
294 // TODO(xhwang): Unify EME UMA reporting code when prefixed EME is deprecated.
295 // See http://crbug.com/412987 for details.
296 void ReportSystemCodeUMA(const std::string& key_system, uint32 system_code) {
297   // Sparse histogram macro does not cache the histogram, so it's safe to use
298   // macro with non-static histogram name here.
299   UMA_HISTOGRAM_SPARSE_SLOWLY(
300       "Media.EME." + KeySystemNameForUMA(key_system) + ".SystemCode",
301       system_code);
302 }
303
304 }  // namespace
305
306 ContentDecryptorDelegate::ContentDecryptorDelegate(
307     PP_Instance pp_instance,
308     const PPP_ContentDecryptor_Private* plugin_decryption_interface)
309     : pp_instance_(pp_instance),
310       plugin_decryption_interface_(plugin_decryption_interface),
311       next_decryption_request_id_(1),
312       audio_samples_per_second_(0),
313       audio_channel_count_(0),
314       audio_channel_layout_(media::CHANNEL_LAYOUT_NONE),
315       next_promise_id_(1),
316       weak_ptr_factory_(this) {
317   weak_this_ = weak_ptr_factory_.GetWeakPtr();
318 }
319
320 ContentDecryptorDelegate::~ContentDecryptorDelegate() {
321   SatisfyAllPendingCallbacksOnError();
322 }
323
324 void ContentDecryptorDelegate::Initialize(
325     const std::string& key_system,
326     const media::SessionMessageCB& session_message_cb,
327     const media::SessionReadyCB& session_ready_cb,
328     const media::SessionClosedCB& session_closed_cb,
329     const media::SessionErrorCB& session_error_cb,
330     const media::SessionKeysChangeCB& session_keys_change_cb,
331     const media::SessionExpirationUpdateCB& session_expiration_update_cb,
332     const base::Closure& fatal_plugin_error_cb) {
333   DCHECK(!key_system.empty());
334   DCHECK(key_system_.empty());
335   key_system_ = key_system;
336
337   session_message_cb_ = session_message_cb;
338   session_ready_cb_ = session_ready_cb;
339   session_closed_cb_ = session_closed_cb;
340   session_error_cb_ = session_error_cb;
341   session_keys_change_cb_ = session_keys_change_cb;
342   session_expiration_update_cb_ = session_expiration_update_cb;
343   fatal_plugin_error_cb_ = fatal_plugin_error_cb;
344
345   plugin_decryption_interface_->Initialize(
346       pp_instance_, StringVar::StringToPPVar(key_system_));
347 }
348
349 void ContentDecryptorDelegate::InstanceCrashed() {
350   fatal_plugin_error_cb_.Run();
351   SatisfyAllPendingCallbacksOnError();
352 }
353
354 void ContentDecryptorDelegate::SetServerCertificate(
355     const uint8_t* certificate,
356     uint32_t certificate_length,
357     scoped_ptr<media::SimpleCdmPromise> promise) {
358   if (!certificate ||
359       certificate_length < media::limits::kMinCertificateLength ||
360       certificate_length > media::limits::kMaxCertificateLength) {
361     promise->reject(
362         media::MediaKeys::INVALID_ACCESS_ERROR, 0, "Incorrect certificate.");
363     return;
364   }
365
366   uint32_t promise_id = SavePromise(promise.PassAs<CdmPromise>());
367   PP_Var certificate_array =
368       PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
369           certificate_length, certificate);
370   plugin_decryption_interface_->SetServerCertificate(
371       pp_instance_, promise_id, certificate_array);
372 }
373
374 void ContentDecryptorDelegate::CreateSession(
375     const std::string& init_data_type,
376     const uint8* init_data,
377     int init_data_length,
378     MediaKeys::SessionType session_type,
379     scoped_ptr<NewSessionCdmPromise> promise) {
380   uint32_t promise_id = SavePromise(promise.PassAs<CdmPromise>());
381   PP_Var init_data_array =
382       PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
383           init_data_length, init_data);
384   plugin_decryption_interface_->CreateSession(
385       pp_instance_,
386       promise_id,
387       StringVar::StringToPPVar(init_data_type),
388       init_data_array,
389       MediaSessionTypeToPpSessionType(session_type));
390 }
391
392 void ContentDecryptorDelegate::LoadSession(
393     const std::string& web_session_id,
394     scoped_ptr<NewSessionCdmPromise> promise) {
395   uint32_t promise_id = SavePromise(promise.PassAs<CdmPromise>());
396   plugin_decryption_interface_->LoadSession(
397       pp_instance_, promise_id, StringVar::StringToPPVar(web_session_id));
398 }
399
400 void ContentDecryptorDelegate::UpdateSession(
401     const std::string& web_session_id,
402     const uint8* response,
403     int response_length,
404     scoped_ptr<SimpleCdmPromise> promise) {
405   uint32_t promise_id = SavePromise(promise.PassAs<CdmPromise>());
406   PP_Var response_array =
407       PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
408           response_length, response);
409   plugin_decryption_interface_->UpdateSession(
410       pp_instance_,
411       promise_id,
412       StringVar::StringToPPVar(web_session_id),
413       response_array);
414 }
415
416 void ContentDecryptorDelegate::CloseSession(
417     const std::string& web_session_id,
418     scoped_ptr<SimpleCdmPromise> promise) {
419   if (web_session_id.length() > media::limits::kMaxWebSessionIdLength) {
420     promise->reject(
421         media::MediaKeys::INVALID_ACCESS_ERROR, 0, "Incorrect session.");
422     return;
423   }
424
425   uint32_t promise_id = SavePromise(promise.PassAs<CdmPromise>());
426   plugin_decryption_interface_->CloseSession(
427       pp_instance_, promise_id, StringVar::StringToPPVar(web_session_id));
428 }
429
430 void ContentDecryptorDelegate::RemoveSession(
431     const std::string& web_session_id,
432     scoped_ptr<SimpleCdmPromise> promise) {
433   if (web_session_id.length() > media::limits::kMaxWebSessionIdLength) {
434     promise->reject(
435         media::MediaKeys::INVALID_ACCESS_ERROR, 0, "Incorrect session.");
436     return;
437   }
438
439   uint32_t promise_id = SavePromise(promise.PassAs<CdmPromise>());
440   plugin_decryption_interface_->RemoveSession(
441       pp_instance_, promise_id, StringVar::StringToPPVar(web_session_id));
442 }
443
444 void ContentDecryptorDelegate::GetUsableKeyIds(
445     const std::string& web_session_id,
446     scoped_ptr<media::KeyIdsPromise> promise) {
447   if (web_session_id.length() > media::limits::kMaxWebSessionIdLength) {
448     promise->reject(
449         media::MediaKeys::INVALID_ACCESS_ERROR, 0, "Incorrect session.");
450     return;
451   }
452
453   uint32_t promise_id = SavePromise(promise.PassAs<CdmPromise>());
454   plugin_decryption_interface_->GetUsableKeyIds(
455       pp_instance_, promise_id, StringVar::StringToPPVar(web_session_id));
456 }
457
458 // TODO(xhwang): Remove duplication of code in Decrypt(),
459 // DecryptAndDecodeAudio() and DecryptAndDecodeVideo().
460 bool ContentDecryptorDelegate::Decrypt(
461     Decryptor::StreamType stream_type,
462     const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
463     const Decryptor::DecryptCB& decrypt_cb) {
464   DVLOG(3) << "Decrypt() - stream_type: " << stream_type;
465
466   // |{audio|video}_input_resource_| is not being used by the plugin
467   // now because there is only one pending audio/video decrypt request at any
468   // time. This is enforced by the media pipeline.
469   scoped_refptr<PPB_Buffer_Impl> encrypted_resource;
470   if (!MakeMediaBufferResource(
471           stream_type, encrypted_buffer, &encrypted_resource) ||
472       !encrypted_resource.get()) {
473     return false;
474   }
475   ScopedPPResource pp_resource(encrypted_resource.get());
476
477   const uint32_t request_id = next_decryption_request_id_++;
478   DVLOG(2) << "Decrypt() - request_id " << request_id;
479
480   PP_EncryptedBlockInfo block_info = {};
481   DCHECK(encrypted_buffer->decrypt_config());
482   if (!MakeEncryptedBlockInfo(encrypted_buffer, request_id, &block_info)) {
483     return false;
484   }
485
486   // There is only one pending decrypt request at any time per stream. This is
487   // enforced by the media pipeline.
488   switch (stream_type) {
489     case Decryptor::kAudio:
490       audio_decrypt_cb_.Set(request_id, decrypt_cb);
491       break;
492     case Decryptor::kVideo:
493       video_decrypt_cb_.Set(request_id, decrypt_cb);
494       break;
495     default:
496       NOTREACHED();
497       return false;
498   }
499
500   SetBufferToFreeInTrackingInfo(&block_info.tracking_info);
501
502   plugin_decryption_interface_->Decrypt(pp_instance_, pp_resource, &block_info);
503   return true;
504 }
505
506 bool ContentDecryptorDelegate::CancelDecrypt(
507     Decryptor::StreamType stream_type) {
508   DVLOG(3) << "CancelDecrypt() - stream_type: " << stream_type;
509
510   Decryptor::DecryptCB decrypt_cb;
511   switch (stream_type) {
512     case Decryptor::kAudio:
513       // Release the shared memory as it can still be in use by the plugin.
514       // The next Decrypt() call will need to allocate a new shared memory
515       // buffer.
516       audio_input_resource_ = NULL;
517       decrypt_cb = audio_decrypt_cb_.ResetAndReturn();
518       break;
519     case Decryptor::kVideo:
520       // Release the shared memory as it can still be in use by the plugin.
521       // The next Decrypt() call will need to allocate a new shared memory
522       // buffer.
523       video_input_resource_ = NULL;
524       decrypt_cb = video_decrypt_cb_.ResetAndReturn();
525       break;
526     default:
527       NOTREACHED();
528       return false;
529   }
530
531   if (!decrypt_cb.is_null())
532     decrypt_cb.Run(Decryptor::kSuccess, NULL);
533
534   return true;
535 }
536
537 bool ContentDecryptorDelegate::InitializeAudioDecoder(
538     const media::AudioDecoderConfig& decoder_config,
539     const Decryptor::DecoderInitCB& init_cb) {
540   PP_AudioDecoderConfig pp_decoder_config;
541   pp_decoder_config.codec =
542       MediaAudioCodecToPpAudioCodec(decoder_config.codec());
543   pp_decoder_config.channel_count =
544       media::ChannelLayoutToChannelCount(decoder_config.channel_layout());
545   pp_decoder_config.bits_per_channel = decoder_config.bits_per_channel();
546   pp_decoder_config.samples_per_second = decoder_config.samples_per_second();
547   pp_decoder_config.request_id = next_decryption_request_id_++;
548
549   audio_samples_per_second_ = pp_decoder_config.samples_per_second;
550   audio_channel_count_ = pp_decoder_config.channel_count;
551   audio_channel_layout_ = decoder_config.channel_layout();
552
553   scoped_refptr<PPB_Buffer_Impl> extra_data_resource;
554   if (!MakeBufferResource(pp_instance_,
555                           decoder_config.extra_data(),
556                           decoder_config.extra_data_size(),
557                           &extra_data_resource)) {
558     return false;
559   }
560   ScopedPPResource pp_resource(extra_data_resource.get());
561
562   audio_decoder_init_cb_.Set(pp_decoder_config.request_id, init_cb);
563   plugin_decryption_interface_->InitializeAudioDecoder(
564       pp_instance_, &pp_decoder_config, pp_resource);
565   return true;
566 }
567
568 bool ContentDecryptorDelegate::InitializeVideoDecoder(
569     const media::VideoDecoderConfig& decoder_config,
570     const Decryptor::DecoderInitCB& init_cb) {
571   PP_VideoDecoderConfig pp_decoder_config;
572   pp_decoder_config.codec =
573       MediaVideoCodecToPpVideoCodec(decoder_config.codec());
574   pp_decoder_config.profile =
575       MediaVideoCodecProfileToPpVideoCodecProfile(decoder_config.profile());
576   pp_decoder_config.format =
577       MediaVideoFormatToPpDecryptedFrameFormat(decoder_config.format());
578   pp_decoder_config.width = decoder_config.coded_size().width();
579   pp_decoder_config.height = decoder_config.coded_size().height();
580   pp_decoder_config.request_id = next_decryption_request_id_++;
581
582   scoped_refptr<PPB_Buffer_Impl> extra_data_resource;
583   if (!MakeBufferResource(pp_instance_,
584                           decoder_config.extra_data(),
585                           decoder_config.extra_data_size(),
586                           &extra_data_resource)) {
587     return false;
588   }
589   ScopedPPResource pp_resource(extra_data_resource.get());
590
591   video_decoder_init_cb_.Set(pp_decoder_config.request_id, init_cb);
592   natural_size_ = decoder_config.natural_size();
593
594   plugin_decryption_interface_->InitializeVideoDecoder(
595       pp_instance_, &pp_decoder_config, pp_resource);
596   return true;
597 }
598
599 bool ContentDecryptorDelegate::DeinitializeDecoder(
600     Decryptor::StreamType stream_type) {
601   CancelDecode(stream_type);
602
603   if (stream_type == Decryptor::kVideo)
604     natural_size_ = gfx::Size();
605
606   // TODO(tomfinegan): Add decoder deinitialize request tracking, and get
607   // stream type from media stack.
608   plugin_decryption_interface_->DeinitializeDecoder(
609       pp_instance_, MediaDecryptorStreamTypeToPpStreamType(stream_type), 0);
610   return true;
611 }
612
613 bool ContentDecryptorDelegate::ResetDecoder(Decryptor::StreamType stream_type) {
614   CancelDecode(stream_type);
615
616   // TODO(tomfinegan): Add decoder reset request tracking.
617   plugin_decryption_interface_->ResetDecoder(
618       pp_instance_, MediaDecryptorStreamTypeToPpStreamType(stream_type), 0);
619   return true;
620 }
621
622 bool ContentDecryptorDelegate::DecryptAndDecodeAudio(
623     const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
624     const Decryptor::AudioDecodeCB& audio_decode_cb) {
625   // |audio_input_resource_| is not being used by the plugin now
626   // because there is only one pending audio decode request at any time.
627   // This is enforced by the media pipeline.
628   scoped_refptr<PPB_Buffer_Impl> encrypted_resource;
629   if (!MakeMediaBufferResource(
630           Decryptor::kAudio, encrypted_buffer, &encrypted_resource)) {
631     return false;
632   }
633
634   // The resource should not be NULL for non-EOS buffer.
635   if (!encrypted_buffer->end_of_stream() && !encrypted_resource.get())
636     return false;
637
638   const uint32_t request_id = next_decryption_request_id_++;
639   DVLOG(2) << "DecryptAndDecodeAudio() - request_id " << request_id;
640
641   PP_EncryptedBlockInfo block_info = {};
642   if (!MakeEncryptedBlockInfo(encrypted_buffer, request_id, &block_info)) {
643     return false;
644   }
645
646   SetBufferToFreeInTrackingInfo(&block_info.tracking_info);
647
648   // There is only one pending audio decode request at any time. This is
649   // enforced by the media pipeline. If this DCHECK is violated, our buffer
650   // reuse policy is not valid, and we may have race problems for the shared
651   // buffer.
652   audio_decode_cb_.Set(request_id, audio_decode_cb);
653
654   ScopedPPResource pp_resource(encrypted_resource.get());
655   plugin_decryption_interface_->DecryptAndDecode(
656       pp_instance_, PP_DECRYPTORSTREAMTYPE_AUDIO, pp_resource, &block_info);
657   return true;
658 }
659
660 bool ContentDecryptorDelegate::DecryptAndDecodeVideo(
661     const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
662     const Decryptor::VideoDecodeCB& video_decode_cb) {
663   // |video_input_resource_| is not being used by the plugin now
664   // because there is only one pending video decode request at any time.
665   // This is enforced by the media pipeline.
666   scoped_refptr<PPB_Buffer_Impl> encrypted_resource;
667   if (!MakeMediaBufferResource(
668           Decryptor::kVideo, encrypted_buffer, &encrypted_resource)) {
669     return false;
670   }
671
672   // The resource should not be 0 for non-EOS buffer.
673   if (!encrypted_buffer->end_of_stream() && !encrypted_resource.get())
674     return false;
675
676   const uint32_t request_id = next_decryption_request_id_++;
677   DVLOG(2) << "DecryptAndDecodeVideo() - request_id " << request_id;
678   TRACE_EVENT_ASYNC_BEGIN0(
679       "media", "ContentDecryptorDelegate::DecryptAndDecodeVideo", request_id);
680
681   PP_EncryptedBlockInfo block_info = {};
682   if (!MakeEncryptedBlockInfo(encrypted_buffer, request_id, &block_info)) {
683     return false;
684   }
685
686   SetBufferToFreeInTrackingInfo(&block_info.tracking_info);
687
688   // Only one pending video decode request at any time. This is enforced by the
689   // media pipeline. If this DCHECK is violated, our buffer
690   // reuse policy is not valid, and we may have race problems for the shared
691   // buffer.
692   video_decode_cb_.Set(request_id, video_decode_cb);
693
694   // TODO(tomfinegan): Need to get stream type from media stack.
695   ScopedPPResource pp_resource(encrypted_resource.get());
696   plugin_decryption_interface_->DecryptAndDecode(
697       pp_instance_, PP_DECRYPTORSTREAMTYPE_VIDEO, pp_resource, &block_info);
698   return true;
699 }
700
701 void ContentDecryptorDelegate::OnPromiseResolved(uint32 promise_id) {
702   scoped_ptr<CdmPromise> promise = TakePromise(promise_id);
703   if (!promise ||
704       promise->GetResolveParameterType() != media::CdmPromise::VOID_TYPE) {
705     NOTREACHED();
706     return;
707   }
708
709   SimpleCdmPromise* simple_promise =
710       static_cast<SimpleCdmPromise*>(promise.get());
711   simple_promise->resolve();
712 }
713
714 void ContentDecryptorDelegate::OnPromiseResolvedWithSession(
715     uint32 promise_id,
716     PP_Var web_session_id) {
717   scoped_ptr<CdmPromise> promise = TakePromise(promise_id);
718   if (!promise ||
719       promise->GetResolveParameterType() != media::CdmPromise::STRING_TYPE) {
720     NOTREACHED();
721     return;
722   }
723
724   StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id);
725   DCHECK(web_session_id_string);
726
727   NewSessionCdmPromise* session_promise =
728       static_cast<NewSessionCdmPromise*>(promise.get());
729   session_promise->resolve(web_session_id_string->value());
730 }
731
732 void ContentDecryptorDelegate::OnPromiseResolvedWithKeyIds(
733     uint32 promise_id,
734     PP_Var key_ids_array) {
735   scoped_ptr<CdmPromise> promise = TakePromise(promise_id);
736
737   ArrayVar* key_ids = ArrayVar::FromPPVar(key_ids_array);
738   DCHECK(key_ids && key_ids->GetLength() <= media::limits::kMaxKeyIds);
739   media::KeyIdsVector key_ids_vector;
740   if (key_ids && key_ids->GetLength() <= media::limits::kMaxKeyIds) {
741     for (size_t i = 0; i < key_ids->GetLength(); ++i) {
742       ArrayBufferVar* array_buffer = ArrayBufferVar::FromPPVar(key_ids->Get(i));
743
744       if (!array_buffer ||
745           array_buffer->ByteLength() < media::limits::kMinKeyIdLength ||
746           array_buffer->ByteLength() > media::limits::kMaxKeyIdLength) {
747         NOTREACHED();
748         continue;
749       }
750
751       std::vector<uint8> key_id;
752       const uint8* data = static_cast<const uint8*>(array_buffer->Map());
753       key_id.assign(data, data + array_buffer->ByteLength());
754       key_ids_vector.push_back(key_id);
755     }
756   }
757
758   if (!promise ||
759       promise->GetResolveParameterType() !=
760           media::CdmPromise::KEY_IDS_VECTOR_TYPE) {
761     NOTREACHED();
762     return;
763   }
764
765   KeyIdsPromise* key_ids_promise(static_cast<KeyIdsPromise*>(promise.get()));
766   key_ids_promise->resolve(key_ids_vector);
767 }
768
769 void ContentDecryptorDelegate::OnPromiseRejected(
770     uint32 promise_id,
771     PP_CdmExceptionCode exception_code,
772     uint32 system_code,
773     PP_Var error_description) {
774   ReportSystemCodeUMA(key_system_, system_code);
775
776   StringVar* error_description_string = StringVar::FromPPVar(error_description);
777   DCHECK(error_description_string);
778
779   scoped_ptr<CdmPromise> promise = TakePromise(promise_id);
780   DCHECK(promise);
781   if (promise) {
782     promise->reject(PpExceptionTypeToMediaException(exception_code),
783                     system_code,
784                     error_description_string->value());
785   }
786 }
787
788 void ContentDecryptorDelegate::OnSessionMessage(PP_Var web_session_id,
789                                                 PP_Var message,
790                                                 PP_Var destination_url) {
791   if (session_message_cb_.is_null())
792     return;
793
794   StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id);
795   DCHECK(web_session_id_string);
796
797   ArrayBufferVar* message_array_buffer = ArrayBufferVar::FromPPVar(message);
798   std::vector<uint8> message_vector;
799   if (message_array_buffer) {
800     const uint8* data = static_cast<const uint8*>(message_array_buffer->Map());
801     message_vector.assign(data, data + message_array_buffer->ByteLength());
802   }
803
804   StringVar* destination_url_string = StringVar::FromPPVar(destination_url);
805   DCHECK(destination_url_string);
806
807   GURL verified_gurl = GURL(destination_url_string->value());
808   if (!verified_gurl.is_valid() && !verified_gurl.is_empty()) {
809     DLOG(WARNING) << "SessionMessage default_url is invalid : "
810                   << verified_gurl.possibly_invalid_spec();
811     verified_gurl = GURL::EmptyGURL();  // Replace invalid destination_url.
812   }
813
814   session_message_cb_.Run(
815       web_session_id_string->value(), message_vector, verified_gurl);
816 }
817
818 void ContentDecryptorDelegate::OnSessionKeysChange(
819     PP_Var web_session_id,
820     PP_Bool has_additional_usable_key) {
821   if (session_keys_change_cb_.is_null())
822     return;
823
824   StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id);
825   DCHECK(web_session_id_string);
826
827   session_keys_change_cb_.Run(web_session_id_string->value(),
828                               PP_ToBool(has_additional_usable_key));
829 }
830
831 void ContentDecryptorDelegate::OnSessionExpirationChange(
832     PP_Var web_session_id,
833     PP_Time new_expiry_time) {
834   if (session_expiration_update_cb_.is_null())
835     return;
836
837   StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id);
838   DCHECK(web_session_id_string);
839
840   session_expiration_update_cb_.Run(web_session_id_string->value(),
841                                     ppapi::PPTimeToTime(new_expiry_time));
842 }
843
844 void ContentDecryptorDelegate::OnSessionReady(PP_Var web_session_id) {
845   if (session_ready_cb_.is_null())
846     return;
847
848   StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id);
849   DCHECK(web_session_id_string);
850
851   session_ready_cb_.Run(web_session_id_string->value());
852 }
853
854 void ContentDecryptorDelegate::OnSessionClosed(PP_Var web_session_id) {
855   if (session_closed_cb_.is_null())
856     return;
857
858   StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id);
859   DCHECK(web_session_id_string);
860
861   session_closed_cb_.Run(web_session_id_string->value());
862 }
863
864 void ContentDecryptorDelegate::OnSessionError(
865     PP_Var web_session_id,
866     PP_CdmExceptionCode exception_code,
867     uint32 system_code,
868     PP_Var error_description) {
869   ReportSystemCodeUMA(key_system_, system_code);
870
871   if (session_error_cb_.is_null())
872     return;
873
874   StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id);
875   DCHECK(web_session_id_string);
876
877   StringVar* error_description_string = StringVar::FromPPVar(error_description);
878   DCHECK(error_description_string);
879
880   session_error_cb_.Run(web_session_id_string->value(),
881                         PpExceptionTypeToMediaException(exception_code),
882                         system_code,
883                         error_description_string->value());
884 }
885
886 void ContentDecryptorDelegate::DecoderInitializeDone(
887     PP_DecryptorStreamType decoder_type,
888     uint32_t request_id,
889     PP_Bool success) {
890   if (decoder_type == PP_DECRYPTORSTREAMTYPE_AUDIO) {
891     // If the request ID is not valid or does not match what's saved, do
892     // nothing.
893     if (request_id == 0 || !audio_decoder_init_cb_.Matches(request_id))
894       return;
895
896     audio_decoder_init_cb_.ResetAndReturn().Run(PP_ToBool(success));
897   } else {
898     if (request_id == 0 || !video_decoder_init_cb_.Matches(request_id))
899       return;
900
901     if (!success)
902       natural_size_ = gfx::Size();
903
904     video_decoder_init_cb_.ResetAndReturn().Run(PP_ToBool(success));
905   }
906 }
907
908 void ContentDecryptorDelegate::DecoderDeinitializeDone(
909     PP_DecryptorStreamType decoder_type,
910     uint32_t request_id) {
911   // TODO(tomfinegan): Add decoder stop completion handling.
912 }
913
914 void ContentDecryptorDelegate::DecoderResetDone(
915     PP_DecryptorStreamType decoder_type,
916     uint32_t request_id) {
917   // TODO(tomfinegan): Add decoder reset completion handling.
918 }
919
920 void ContentDecryptorDelegate::DeliverBlock(
921     PP_Resource decrypted_block,
922     const PP_DecryptedBlockInfo* block_info) {
923   DCHECK(block_info);
924
925   FreeBuffer(block_info->tracking_info.buffer_id);
926
927   const uint32_t request_id = block_info->tracking_info.request_id;
928   DVLOG(2) << "DeliverBlock() - request_id: " << request_id;
929
930   // If the request ID is not valid or does not match what's saved, do nothing.
931   if (request_id == 0) {
932     DVLOG(1) << "DeliverBlock() - invalid request_id " << request_id;
933     return;
934   }
935
936   Decryptor::DecryptCB decrypt_cb;
937   if (audio_decrypt_cb_.Matches(request_id)) {
938     decrypt_cb = audio_decrypt_cb_.ResetAndReturn();
939   } else if (video_decrypt_cb_.Matches(request_id)) {
940     decrypt_cb = video_decrypt_cb_.ResetAndReturn();
941   } else {
942     DVLOG(1) << "DeliverBlock() - request_id " << request_id << " not found";
943     return;
944   }
945
946   Decryptor::Status status =
947       PpDecryptResultToMediaDecryptorStatus(block_info->result);
948   if (status != Decryptor::kSuccess) {
949     decrypt_cb.Run(status, NULL);
950     return;
951   }
952
953   EnterResourceNoLock<PPB_Buffer_API> enter(decrypted_block, true);
954   if (!enter.succeeded()) {
955     decrypt_cb.Run(Decryptor::kError, NULL);
956     return;
957   }
958   BufferAutoMapper mapper(enter.object());
959   if (!mapper.data() || !mapper.size() ||
960       mapper.size() < block_info->data_size) {
961     decrypt_cb.Run(Decryptor::kError, NULL);
962     return;
963   }
964
965   // TODO(tomfinegan): Find a way to take ownership of the shared memory
966   // managed by the PPB_Buffer_Dev, and avoid the extra copy.
967   scoped_refptr<media::DecoderBuffer> decrypted_buffer(
968       media::DecoderBuffer::CopyFrom(static_cast<uint8*>(mapper.data()),
969                                      block_info->data_size));
970   decrypted_buffer->set_timestamp(
971       base::TimeDelta::FromMicroseconds(block_info->tracking_info.timestamp));
972   decrypt_cb.Run(Decryptor::kSuccess, decrypted_buffer);
973 }
974
975 // Use a non-class-member function here so that if for some reason
976 // ContentDecryptorDelegate is destroyed before VideoFrame calls this callback,
977 // we can still get the shared memory unmapped.
978 static void BufferNoLongerNeeded(
979     const scoped_refptr<PPB_Buffer_Impl>& ppb_buffer,
980     base::Closure buffer_no_longer_needed_cb) {
981   ppb_buffer->Unmap();
982   buffer_no_longer_needed_cb.Run();
983 }
984
985 // Enters |resource|, maps shared memory and returns pointer of mapped data.
986 // Returns NULL if any error occurs.
987 static uint8* GetMappedBuffer(PP_Resource resource,
988                               scoped_refptr<PPB_Buffer_Impl>* ppb_buffer) {
989   EnterResourceNoLock<PPB_Buffer_API> enter(resource, true);
990   if (!enter.succeeded())
991     return NULL;
992
993   uint8* mapped_data = static_cast<uint8*>(enter.object()->Map());
994   if (!enter.object()->IsMapped() || !mapped_data)
995     return NULL;
996
997   uint32_t mapped_size = 0;
998   if (!enter.object()->Describe(&mapped_size) || !mapped_size) {
999     enter.object()->Unmap();
1000     return NULL;
1001   }
1002
1003   *ppb_buffer = static_cast<PPB_Buffer_Impl*>(enter.object());
1004
1005   return mapped_data;
1006 }
1007
1008 void ContentDecryptorDelegate::DeliverFrame(
1009     PP_Resource decrypted_frame,
1010     const PP_DecryptedFrameInfo* frame_info) {
1011   DCHECK(frame_info);
1012
1013   const uint32_t request_id = frame_info->tracking_info.request_id;
1014   DVLOG(2) << "DeliverFrame() - request_id: " << request_id;
1015
1016   // If the request ID is not valid or does not match what's saved, do nothing.
1017   if (request_id == 0 || !video_decode_cb_.Matches(request_id)) {
1018     DVLOG(1) << "DeliverFrame() - request_id " << request_id << " not found";
1019     FreeBuffer(frame_info->tracking_info.buffer_id);
1020     return;
1021   }
1022
1023   TRACE_EVENT_ASYNC_END0(
1024       "media", "ContentDecryptorDelegate::DecryptAndDecodeVideo", request_id);
1025
1026   Decryptor::VideoDecodeCB video_decode_cb = video_decode_cb_.ResetAndReturn();
1027
1028   Decryptor::Status status =
1029       PpDecryptResultToMediaDecryptorStatus(frame_info->result);
1030   if (status != Decryptor::kSuccess) {
1031     DCHECK(!frame_info->tracking_info.buffer_id);
1032     video_decode_cb.Run(status, NULL);
1033     return;
1034   }
1035
1036   scoped_refptr<PPB_Buffer_Impl> ppb_buffer;
1037   uint8* frame_data = GetMappedBuffer(decrypted_frame, &ppb_buffer);
1038   if (!frame_data) {
1039     FreeBuffer(frame_info->tracking_info.buffer_id);
1040     video_decode_cb.Run(Decryptor::kError, NULL);
1041     return;
1042   }
1043
1044   gfx::Size frame_size(frame_info->width, frame_info->height);
1045   DCHECK_EQ(frame_info->format, PP_DECRYPTEDFRAMEFORMAT_YV12);
1046
1047   scoped_refptr<media::VideoFrame> decoded_frame =
1048       media::VideoFrame::WrapExternalYuvData(
1049           media::VideoFrame::YV12,
1050           frame_size,
1051           gfx::Rect(frame_size),
1052           natural_size_,
1053           frame_info->strides[PP_DECRYPTEDFRAMEPLANES_Y],
1054           frame_info->strides[PP_DECRYPTEDFRAMEPLANES_U],
1055           frame_info->strides[PP_DECRYPTEDFRAMEPLANES_V],
1056           frame_data + frame_info->plane_offsets[PP_DECRYPTEDFRAMEPLANES_Y],
1057           frame_data + frame_info->plane_offsets[PP_DECRYPTEDFRAMEPLANES_U],
1058           frame_data + frame_info->plane_offsets[PP_DECRYPTEDFRAMEPLANES_V],
1059           base::TimeDelta::FromMicroseconds(
1060               frame_info->tracking_info.timestamp),
1061           media::BindToCurrentLoop(
1062               base::Bind(&BufferNoLongerNeeded,
1063                          ppb_buffer,
1064                          base::Bind(&ContentDecryptorDelegate::FreeBuffer,
1065                                     weak_this_,
1066                                     frame_info->tracking_info.buffer_id))));
1067
1068   video_decode_cb.Run(Decryptor::kSuccess, decoded_frame);
1069 }
1070
1071 void ContentDecryptorDelegate::DeliverSamples(
1072     PP_Resource audio_frames,
1073     const PP_DecryptedSampleInfo* sample_info) {
1074   DCHECK(sample_info);
1075
1076   FreeBuffer(sample_info->tracking_info.buffer_id);
1077
1078   const uint32_t request_id = sample_info->tracking_info.request_id;
1079   DVLOG(2) << "DeliverSamples() - request_id: " << request_id;
1080
1081   // If the request ID is not valid or does not match what's saved, do nothing.
1082   if (request_id == 0 || !audio_decode_cb_.Matches(request_id)) {
1083     DVLOG(1) << "DeliverSamples() - request_id " << request_id << " not found";
1084     return;
1085   }
1086
1087   Decryptor::AudioDecodeCB audio_decode_cb = audio_decode_cb_.ResetAndReturn();
1088
1089   const Decryptor::AudioBuffers empty_frames;
1090
1091   Decryptor::Status status =
1092       PpDecryptResultToMediaDecryptorStatus(sample_info->result);
1093   if (status != Decryptor::kSuccess) {
1094     audio_decode_cb.Run(status, empty_frames);
1095     return;
1096   }
1097
1098   media::SampleFormat sample_format =
1099       PpDecryptedSampleFormatToMediaSampleFormat(sample_info->format);
1100
1101   Decryptor::AudioBuffers audio_frame_list;
1102   if (!DeserializeAudioFrames(audio_frames,
1103                               sample_info->data_size,
1104                               sample_format,
1105                               &audio_frame_list)) {
1106     NOTREACHED() << "CDM did not serialize the buffer correctly.";
1107     audio_decode_cb.Run(Decryptor::kError, empty_frames);
1108     return;
1109   }
1110
1111   audio_decode_cb.Run(Decryptor::kSuccess, audio_frame_list);
1112 }
1113
1114 // TODO(xhwang): Try to remove duplicate logic here and in CancelDecrypt().
1115 void ContentDecryptorDelegate::CancelDecode(Decryptor::StreamType stream_type) {
1116   switch (stream_type) {
1117     case Decryptor::kAudio:
1118       // Release the shared memory as it can still be in use by the plugin.
1119       // The next DecryptAndDecode() call will need to allocate a new shared
1120       // memory buffer.
1121       audio_input_resource_ = NULL;
1122       if (!audio_decode_cb_.is_null())
1123         audio_decode_cb_.ResetAndReturn().Run(Decryptor::kSuccess,
1124                                               Decryptor::AudioBuffers());
1125       break;
1126     case Decryptor::kVideo:
1127       // Release the shared memory as it can still be in use by the plugin.
1128       // The next DecryptAndDecode() call will need to allocate a new shared
1129       // memory buffer.
1130       video_input_resource_ = NULL;
1131       if (!video_decode_cb_.is_null())
1132         video_decode_cb_.ResetAndReturn().Run(Decryptor::kSuccess, NULL);
1133       break;
1134     default:
1135       NOTREACHED();
1136   }
1137 }
1138
1139 bool ContentDecryptorDelegate::MakeMediaBufferResource(
1140     Decryptor::StreamType stream_type,
1141     const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
1142     scoped_refptr<PPB_Buffer_Impl>* resource) {
1143   TRACE_EVENT0("media", "ContentDecryptorDelegate::MakeMediaBufferResource");
1144
1145   // End of stream buffers are represented as null resources.
1146   if (encrypted_buffer->end_of_stream()) {
1147     *resource = NULL;
1148     return true;
1149   }
1150
1151   DCHECK(stream_type == Decryptor::kAudio || stream_type == Decryptor::kVideo);
1152   scoped_refptr<PPB_Buffer_Impl>& media_resource =
1153       (stream_type == Decryptor::kAudio) ? audio_input_resource_
1154                                          : video_input_resource_;
1155
1156   const size_t data_size = static_cast<size_t>(encrypted_buffer->data_size());
1157   if (!media_resource.get() || media_resource->size() < data_size) {
1158     // Either the buffer hasn't been created yet, or we have one that isn't big
1159     // enough to fit |size| bytes.
1160
1161     // Media resource size starts from |kMinimumMediaBufferSize| and grows
1162     // exponentially to avoid frequent re-allocation of PPB_Buffer_Impl,
1163     // which is usually expensive. Since input media buffers are compressed,
1164     // they are usually small (compared to outputs). The over-allocated memory
1165     // should be negligible.
1166     const uint32_t kMinimumMediaBufferSize = 1024;
1167     uint32_t media_resource_size =
1168         media_resource.get() ? media_resource->size() : kMinimumMediaBufferSize;
1169     while (media_resource_size < data_size)
1170       media_resource_size *= 2;
1171
1172     DVLOG(2) << "Size of media buffer for "
1173              << ((stream_type == Decryptor::kAudio) ? "audio" : "video")
1174              << " stream bumped to " << media_resource_size
1175              << " bytes to fit input.";
1176     media_resource =
1177         PPB_Buffer_Impl::CreateResource(pp_instance_, media_resource_size);
1178     if (!media_resource.get())
1179       return false;
1180   }
1181
1182   BufferAutoMapper mapper(media_resource.get());
1183   if (!mapper.data() || mapper.size() < data_size) {
1184     media_resource = NULL;
1185     return false;
1186   }
1187   memcpy(mapper.data(), encrypted_buffer->data(), data_size);
1188
1189   *resource = media_resource;
1190   return true;
1191 }
1192
1193 void ContentDecryptorDelegate::FreeBuffer(uint32_t buffer_id) {
1194   if (buffer_id)
1195     free_buffers_.push(buffer_id);
1196 }
1197
1198 void ContentDecryptorDelegate::SetBufferToFreeInTrackingInfo(
1199     PP_DecryptTrackingInfo* tracking_info) {
1200   DCHECK_EQ(tracking_info->buffer_id, 0u);
1201
1202   if (free_buffers_.empty())
1203     return;
1204
1205   tracking_info->buffer_id = free_buffers_.front();
1206   free_buffers_.pop();
1207 }
1208
1209 bool ContentDecryptorDelegate::DeserializeAudioFrames(
1210     PP_Resource audio_frames,
1211     size_t data_size,
1212     media::SampleFormat sample_format,
1213     Decryptor::AudioBuffers* frames) {
1214   DCHECK(frames);
1215   EnterResourceNoLock<PPB_Buffer_API> enter(audio_frames, true);
1216   if (!enter.succeeded())
1217     return false;
1218
1219   BufferAutoMapper mapper(enter.object());
1220   if (!mapper.data() || !mapper.size() ||
1221       mapper.size() < static_cast<uint32_t>(data_size))
1222     return false;
1223
1224   // TODO(jrummell): Pass ownership of data() directly to AudioBuffer to avoid
1225   // the copy. Since it is possible to get multiple buffers, it would need to be
1226   // sliced and ref counted appropriately. http://crbug.com/255576.
1227   const uint8* cur = static_cast<uint8*>(mapper.data());
1228   size_t bytes_left = data_size;
1229
1230   const int audio_bytes_per_frame =
1231       media::SampleFormatToBytesPerChannel(sample_format) *
1232       audio_channel_count_;
1233   if (audio_bytes_per_frame <= 0)
1234     return false;
1235
1236   // Allocate space for the channel pointers given to AudioBuffer.
1237   std::vector<const uint8*> channel_ptrs(audio_channel_count_,
1238                                          static_cast<const uint8*>(NULL));
1239   do {
1240     int64 timestamp = 0;
1241     int64 frame_size = -1;
1242     const size_t kHeaderSize = sizeof(timestamp) + sizeof(frame_size);
1243
1244     if (bytes_left < kHeaderSize)
1245       return false;
1246
1247     memcpy(&timestamp, cur, sizeof(timestamp));
1248     cur += sizeof(timestamp);
1249     bytes_left -= sizeof(timestamp);
1250
1251     memcpy(&frame_size, cur, sizeof(frame_size));
1252     cur += sizeof(frame_size);
1253     bytes_left -= sizeof(frame_size);
1254
1255     // We should *not* have empty frames in the list.
1256     if (frame_size <= 0 ||
1257         bytes_left < base::checked_cast<size_t>(frame_size)) {
1258       return false;
1259     }
1260
1261     // Setup channel pointers.  AudioBuffer::CopyFrom() will only use the first
1262     // one in the case of interleaved data.
1263     const int size_per_channel = frame_size / audio_channel_count_;
1264     for (int i = 0; i < audio_channel_count_; ++i)
1265       channel_ptrs[i] = cur + i * size_per_channel;
1266
1267     const int frame_count = frame_size / audio_bytes_per_frame;
1268     scoped_refptr<media::AudioBuffer> frame = media::AudioBuffer::CopyFrom(
1269         sample_format,
1270         audio_channel_layout_,
1271         audio_channel_count_,
1272         audio_samples_per_second_,
1273         frame_count,
1274         &channel_ptrs[0],
1275         base::TimeDelta::FromMicroseconds(timestamp));
1276     frames->push_back(frame);
1277
1278     cur += frame_size;
1279     bytes_left -= frame_size;
1280   } while (bytes_left > 0);
1281
1282   return true;
1283 }
1284
1285 void ContentDecryptorDelegate::SatisfyAllPendingCallbacksOnError() {
1286   if (!audio_decoder_init_cb_.is_null())
1287     audio_decoder_init_cb_.ResetAndReturn().Run(false);
1288
1289   if (!video_decoder_init_cb_.is_null())
1290     video_decoder_init_cb_.ResetAndReturn().Run(false);
1291
1292   audio_input_resource_ = NULL;
1293   video_input_resource_ = NULL;
1294
1295   if (!audio_decrypt_cb_.is_null())
1296     audio_decrypt_cb_.ResetAndReturn().Run(media::Decryptor::kError, NULL);
1297
1298   if (!video_decrypt_cb_.is_null())
1299     video_decrypt_cb_.ResetAndReturn().Run(media::Decryptor::kError, NULL);
1300
1301   if (!audio_decode_cb_.is_null()) {
1302     const media::Decryptor::AudioBuffers empty_frames;
1303     audio_decode_cb_.ResetAndReturn().Run(media::Decryptor::kError,
1304                                           empty_frames);
1305   }
1306
1307   if (!video_decode_cb_.is_null())
1308     video_decode_cb_.ResetAndReturn().Run(media::Decryptor::kError, NULL);
1309
1310   // Reject all outstanding promises.
1311   for (PromiseMap::iterator it = promises_.begin(); it != promises_.end();
1312        ++it) {
1313     it->second->reject(
1314         media::MediaKeys::UNKNOWN_ERROR, 0, "Failure calling plugin.");
1315   }
1316   promises_.clear();
1317 }
1318
1319 uint32_t ContentDecryptorDelegate::SavePromise(scoped_ptr<CdmPromise> promise) {
1320   uint32_t promise_id = next_promise_id_++;
1321   promises_.add(promise_id, promise.Pass());
1322   return promise_id;
1323 }
1324
1325 scoped_ptr<CdmPromise> ContentDecryptorDelegate::TakePromise(
1326     uint32_t promise_id) {
1327   PromiseMap::iterator it = promises_.find(promise_id);
1328   if (it == promises_.end())
1329     return scoped_ptr<CdmPromise>();
1330   return promises_.take_and_erase(it);
1331 }
1332
1333 }  // namespace content