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

Side by Side Diff: webkit/media/crypto/ppapi/clear_key_cdm.cc

Issue 11260007: Add FFmpeg audio decoder for the clear key CDM. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebased on 11242005 and 11189082 Created 8 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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/media/crypto/ppapi/clear_key_cdm.h" 5 #include "webkit/media/crypto/ppapi/clear_key_cdm.h"
6 6
7 #include <vector> 7 #include <vector>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/time.h" 11 #include "base/time.h"
12 #include "media/base/buffers.h"
12 #include "media/base/decoder_buffer.h" 13 #include "media/base/decoder_buffer.h"
13 14
14 #if defined(CLEAR_KEY_CDM_USE_FFMPEG_DECODER) 15 #if defined(CLEAR_KEY_CDM_USE_FFMPEG_DECODER)
15 #include "base/at_exit.h" 16 #include "base/at_exit.h"
16 #include "base/file_path.h" 17 #include "base/file_path.h"
17 #include "base/path_service.h" 18 #include "base/path_service.h"
18 #include "media/base/media.h" 19 #include "media/base/media.h"
20 #include "webkit/media/crypto/ppapi/ffmpeg_cdm_audio_decoder.h"
19 #include "webkit/media/crypto/ppapi/ffmpeg_cdm_video_decoder.h" 21 #include "webkit/media/crypto/ppapi/ffmpeg_cdm_video_decoder.h"
20 22
23 // Include FFmpeg avformat.h for av_register_all().
24 extern "C" {
25 // Temporarily disable possible loss of data warning.
26 MSVC_PUSH_DISABLE_WARNING(4244);
27 #include <libavformat/avformat.h>
28 MSVC_POP_WARNING();
29 } // extern "C"
30
21 // TODO(tomfinegan): When COMPONENT_BUILD is not defined an AtExitManager must 31 // TODO(tomfinegan): When COMPONENT_BUILD is not defined an AtExitManager must
22 // exist before the call to InitializeFFmpegLibraries(). This should no longer 32 // exist before the call to InitializeFFmpegLibraries(). This should no longer
23 // be required after http://crbug.com/91970 because we'll be able to get rid of 33 // be required after http://crbug.com/91970 because we'll be able to get rid of
24 // InitializeFFmpegLibraries(). 34 // InitializeFFmpegLibraries().
25 #if !defined COMPONENT_BUILD 35 #if !defined COMPONENT_BUILD
26 static base::AtExitManager g_at_exit_manager; 36 static base::AtExitManager g_at_exit_manager;
27 #endif 37 #endif
28 38
29 // TODO(tomfinegan): InitializeFFmpegLibraries() and |g_cdm_module_initialized| 39 // TODO(tomfinegan): InitializeFFmpegLibraries() and |g_cdm_module_initialized|
30 // are required for running in the sandbox, and should no longer be required 40 // are required for running in the sandbox, and should no longer be required
31 // after http://crbug.com/91970 is fixed. 41 // after http://crbug.com/91970 is fixed.
32 static bool InitializeFFmpegLibraries() { 42 static bool InitializeFFmpegLibraries() {
33 FilePath file_path; 43 FilePath file_path;
34 CHECK(PathService::Get(base::DIR_EXE, &file_path)); 44 CHECK(PathService::Get(base::DIR_EXE, &file_path));
35 CHECK(media::InitializeMediaLibrary(file_path)); 45 CHECK(media::InitializeMediaLibrary(file_path));
46 av_register_all();
36 return true; 47 return true;
37 } 48 }
38 49
39 static bool g_cdm_module_initialized = InitializeFFmpegLibraries(); 50 static bool g_cdm_module_initialized = InitializeFFmpegLibraries();
40 #endif // CLEAR_KEY_CDM_USE_FFMPEG_DECODER 51 #endif // CLEAR_KEY_CDM_USE_FFMPEG_DECODER
41 52
42 static const char kClearKeyCdmVersion[] = "0.1.0.0"; 53 static const char kClearKeyCdmVersion[] = "0.1.0.0";
43 54
44 // Copies |input_buffer| into a media::DecoderBuffer. If the |input_buffer| is 55 // Copies |input_buffer| into a media::DecoderBuffer. If the |input_buffer| is
45 // empty, an empty (end-of-stream) media::DecoderBuffer is returned. 56 // empty, an empty (end-of-stream) media::DecoderBuffer is returned.
(...skipping 28 matching lines...) Expand all
74 output_buffer->SetTimestamp( 85 output_buffer->SetTimestamp(
75 base::TimeDelta::FromMicroseconds(input_buffer.timestamp)); 86 base::TimeDelta::FromMicroseconds(input_buffer.timestamp));
76 87
77 return output_buffer; 88 return output_buffer;
78 } 89 }
79 90
80 template<typename Type> 91 template<typename Type>
81 class ScopedResetter { 92 class ScopedResetter {
82 public: 93 public:
83 explicit ScopedResetter(Type* object) : object_(object) {} 94 explicit ScopedResetter(Type* object) : object_(object) {}
84 ~ScopedResetter() { 95 ~ScopedResetter() { object_->Reset(); }
85 object_->Reset();
86 }
87 96
88 private: 97 private:
89 Type* const object_; 98 Type* const object_;
90 }; 99 };
91 100
92 template<typename Type> 101 template<typename Type>
93 static Type* AllocateAndCopy(const Type* data, int size) { 102 static Type* AllocateAndCopy(const Type* data, int size) {
94 COMPILE_ASSERT(sizeof(Type) == 1, type_size_is_not_one); 103 COMPILE_ASSERT(sizeof(Type) == 1, type_size_is_not_one);
95 Type* copy = new Type[size]; 104 Type* copy = new Type[size];
96 memcpy(copy, data, size); 105 memcpy(copy, data, size);
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
155 const std::string& session_id, 164 const std::string& session_id,
156 scoped_array<uint8> init_data, 165 scoped_array<uint8> init_data,
157 int init_data_length) { 166 int init_data_length) {
158 // In the current implementation of AesDecryptor, NeedKey is not used. 167 // In the current implementation of AesDecryptor, NeedKey is not used.
159 // If no key is available to decrypt an input buffer, it returns kNoKey to 168 // If no key is available to decrypt an input buffer, it returns kNoKey to
160 // the caller instead of firing NeedKey. 169 // the caller instead of firing NeedKey.
161 NOTREACHED(); 170 NOTREACHED();
162 } 171 }
163 172
164 ClearKeyCdm::ClearKeyCdm(cdm::Allocator* allocator, cdm::CdmHost*) 173 ClearKeyCdm::ClearKeyCdm(cdm::Allocator* allocator, cdm::CdmHost*)
165 : decryptor_(&client_), allocator_(allocator) { 174 : decryptor_(&client_),
175 allocator_(allocator) {
166 DCHECK(allocator_); 176 DCHECK(allocator_);
177 #if defined(CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER)
178 channel_count_ = 0;
179 bits_per_channel_ = 0;
180 samples_per_second_ = 0;
181 last_timestamp_ = media::kNoTimestamp();
182 last_duration_ = media::kInfiniteDuration();
183 #endif // CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER
167 } 184 }
168 185
169 ClearKeyCdm::~ClearKeyCdm() {} 186 ClearKeyCdm::~ClearKeyCdm() {}
170 187
171 cdm::Status ClearKeyCdm::GenerateKeyRequest(const uint8_t* init_data, 188 cdm::Status ClearKeyCdm::GenerateKeyRequest(const uint8_t* init_data,
172 int init_data_size, 189 int init_data_size,
173 cdm::KeyMessage* key_request) { 190 cdm::KeyMessage* key_request) {
174 DVLOG(1) << "GenerateKeyRequest()"; 191 DVLOG(1) << "GenerateKeyRequest()";
175 base::AutoLock auto_lock(client_lock_); 192 base::AutoLock auto_lock(client_lock_);
176 ScopedResetter<Client> auto_resetter(&client_); 193 ScopedResetter<Client> auto_resetter(&client_);
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
255 memcpy(reinterpret_cast<void*>(decrypted_block->buffer()->data()), 272 memcpy(reinterpret_cast<void*>(decrypted_block->buffer()->data()),
256 buffer->GetData(), 273 buffer->GetData(),
257 buffer->GetDataSize()); 274 buffer->GetDataSize());
258 decrypted_block->set_timestamp(buffer->GetTimestamp().InMicroseconds()); 275 decrypted_block->set_timestamp(buffer->GetTimestamp().InMicroseconds());
259 276
260 return cdm::kSuccess; 277 return cdm::kSuccess;
261 } 278 }
262 279
263 cdm::Status ClearKeyCdm::InitializeAudioDecoder( 280 cdm::Status ClearKeyCdm::InitializeAudioDecoder(
264 const cdm::AudioDecoderConfig& audio_decoder_config) { 281 const cdm::AudioDecoderConfig& audio_decoder_config) {
282 #if defined(CLEAR_KEY_CDM_USE_FFMPEG_DECODER)
283 if (!audio_decoder_)
284 audio_decoder_.reset(new webkit_media::FFmpegCdmAudioDecoder(allocator_));
285
286 if (!audio_decoder_->Initialize(audio_decoder_config))
287 return cdm::kSessionError;
288
289 return cdm::kSuccess;
290 #elif defined(CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER)
291 channel_count_ = audio_decoder_config.channel_count;
292 bits_per_channel_ = audio_decoder_config.bits_per_channel;
293 samples_per_second_ = audio_decoder_config.samples_per_second;
294 return cdm::kSuccess;
295 #else
265 NOTIMPLEMENTED(); 296 NOTIMPLEMENTED();
266 return cdm::kSessionError; 297 return cdm::kSessionError;
298 #endif // CLEAR_KEY_CDM_USE_FFMPEG_DECODER
267 } 299 }
268 300
269 cdm::Status ClearKeyCdm::InitializeVideoDecoder( 301 cdm::Status ClearKeyCdm::InitializeVideoDecoder(
270 const cdm::VideoDecoderConfig& video_decoder_config) { 302 const cdm::VideoDecoderConfig& video_decoder_config) {
271 #if defined(CLEAR_KEY_CDM_USE_FFMPEG_DECODER) 303 #if defined(CLEAR_KEY_CDM_USE_FFMPEG_DECODER)
272 if (!video_decoder_) 304 if (!video_decoder_)
273 video_decoder_.reset(new webkit_media::FFmpegCdmVideoDecoder(allocator_)); 305 video_decoder_.reset(new webkit_media::FFmpegCdmVideoDecoder(allocator_));
274 306
275 if (!video_decoder_->Initialize(video_decoder_config)) 307 if (!video_decoder_->Initialize(video_decoder_config))
276 return cdm::kSessionError; 308 return cdm::kSessionError;
277 309
278 return cdm::kSuccess; 310 return cdm::kSuccess;
279 #elif defined(CLEAR_KEY_CDM_USE_FAKE_VIDEO_DECODER) 311 #elif defined(CLEAR_KEY_CDM_USE_FAKE_VIDEO_DECODER)
280 video_size_ = video_decoder_config.coded_size; 312 video_size_ = video_decoder_config.coded_size;
281 return cdm::kSuccess; 313 return cdm::kSuccess;
282 #else 314 #else
283 NOTIMPLEMENTED(); 315 NOTIMPLEMENTED();
284 return cdm::kSessionError; 316 return cdm::kSessionError;
285 #endif // CLEAR_KEY_CDM_USE_FFMPEG_DECODER 317 #endif // CLEAR_KEY_CDM_USE_FFMPEG_DECODER
286
287 } 318 }
288 319
289 void ClearKeyCdm::ResetDecoder(cdm::StreamType decoder_type) { 320 void ClearKeyCdm::ResetDecoder(cdm::StreamType decoder_type) {
290 #if defined(CLEAR_KEY_CDM_USE_FFMPEG_DECODER) 321 #if defined(CLEAR_KEY_CDM_USE_FFMPEG_DECODER)
291 DCHECK(decoder_type == cdm::kStreamTypeVideo); 322 switch (decoder_type) {
292 video_decoder_->Reset(); 323 case cdm::kStreamTypeVideo:
293 #endif 324 video_decoder_->Reset();
325 break;
326 case cdm::kStreamTypeAudio:
327 audio_decoder_->Reset();
328 break;
329 default:
330 NOTREACHED() << "ResetDecoder(): invalid cdm::StreamType";
331 }
332 #elif defined(CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER)
333 if (decoder_type == cdm::kStreamTypeAudio) {
334 last_timestamp_ = media::kNoTimestamp();
335 last_duration_ = media::kInfiniteDuration();
336 }
337 #endif // CLEAR_KEY_CDM_USE_FFMPEG_DECODER
294 } 338 }
295 339
296 void ClearKeyCdm::DeinitializeDecoder(cdm::StreamType decoder_type) { 340 void ClearKeyCdm::DeinitializeDecoder(cdm::StreamType decoder_type) {
297 #if defined(CLEAR_KEY_CDM_USE_FFMPEG_DECODER) 341 #if defined(CLEAR_KEY_CDM_USE_FFMPEG_DECODER)
298 DCHECK(decoder_type == cdm::kStreamTypeVideo); 342 switch (decoder_type) {
299 video_decoder_->Deinitialize(); 343 case cdm::kStreamTypeVideo:
300 #endif 344 video_decoder_->Deinitialize();
345 break;
346 case cdm::kStreamTypeAudio:
347 audio_decoder_->Deinitialize();
348 break;
349 default:
350 NOTREACHED() << "DeinitializeDecoder(): invalid cdm::StreamType";
351 }
352 #elif defined(CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER)
353 if (decoder_type == cdm::kStreamTypeAudio) {
354 last_timestamp_ = media::kNoTimestamp();
355 last_duration_ = media::kInfiniteDuration();
356 }
357 #endif // CLEAR_KEY_CDM_USE_FFMPEG_DECODER
301 } 358 }
302 359
303 cdm::Status ClearKeyCdm::DecryptAndDecodeFrame( 360 cdm::Status ClearKeyCdm::DecryptAndDecodeFrame(
304 const cdm::InputBuffer& encrypted_buffer, 361 const cdm::InputBuffer& encrypted_buffer,
305 cdm::VideoFrame* decoded_frame) { 362 cdm::VideoFrame* decoded_frame) {
306 DVLOG(1) << "DecryptAndDecodeFrame()"; 363 DVLOG(1) << "DecryptAndDecodeFrame()";
307 364
308 scoped_refptr<media::DecoderBuffer> buffer; 365 scoped_refptr<media::DecoderBuffer> buffer;
309 cdm::Status status = DecryptToMediaDecoderBuffer(encrypted_buffer, &buffer); 366 cdm::Status status = DecryptToMediaDecoderBuffer(encrypted_buffer, &buffer);
310 367
(...skipping 14 matching lines...) Expand all
325 return cdm::kNeedMoreData; 382 return cdm::kNeedMoreData;
326 383
327 GenerateFakeVideoFrame(buffer->GetTimestamp(), decoded_frame); 384 GenerateFakeVideoFrame(buffer->GetTimestamp(), decoded_frame);
328 return cdm::kSuccess; 385 return cdm::kSuccess;
329 #else 386 #else
330 NOTIMPLEMENTED(); 387 NOTIMPLEMENTED();
331 return cdm::kDecodeError; 388 return cdm::kDecodeError;
332 #endif // CLEAR_KEY_CDM_USE_FFMPEG_DECODER 389 #endif // CLEAR_KEY_CDM_USE_FFMPEG_DECODER
333 } 390 }
334 391
392 cdm::Status ClearKeyCdm::DecryptAndDecodeSamples(
393 const cdm::InputBuffer& encrypted_buffer,
394 cdm::AudioFrames* audio_frames) {
395 DVLOG(1) << "DecryptAndDecodeSamples()";
396
397 scoped_refptr<media::DecoderBuffer> buffer;
398 cdm::Status status = DecryptToMediaDecoderBuffer(encrypted_buffer, &buffer);
399
400 if (status != cdm::kSuccess)
401 return status;
402
403 #if defined(CLEAR_KEY_CDM_USE_FFMPEG_DECODER)
404 DCHECK(status == cdm::kSuccess);
405 DCHECK(buffer);
406 return audio_decoder_->DecodeBuffer(buffer.get()->GetData(),
407 buffer->GetDataSize(),
408 encrypted_buffer.timestamp,
409 audio_frames);
410 #elif defined(CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER)
411 if (buffer->IsEndOfStream()) {
412 // Upon the first EOS frame, return a frame with |last_duration_|.
413 if (last_duration_ != media::kInfiniteDuration()) {
414 DCHECK(last_timestamp_ != media::kNoTimestamp());
415 GenerateFakeAudioFrames(audio_frames);
416 last_timestamp_ = media::kNoTimestamp();
417 last_duration_ = media::kInfiniteDuration();
418 return cdm::kSuccess;
419 }
420
421 last_timestamp_ = media::kNoTimestamp();
422 return cdm::kNeedMoreData;
423 }
424
425 base::TimeDelta cur_timestamp = buffer->GetTimestamp();
426 DCHECK(cur_timestamp != media::kNoTimestamp());
427
428 // Return kNeedMoreData for the first frame because duration is unknown.
429 if (last_timestamp_ == media::kNoTimestamp()) {
430 last_timestamp_ = cur_timestamp;
431 return cdm::kNeedMoreData;
432 }
433
434 DCHECK(cur_timestamp > last_timestamp_);
435 last_duration_ = cur_timestamp - last_timestamp_;
436 last_timestamp_ = cur_timestamp;
437
438 GenerateFakeAudioFrames(audio_frames);
439 return cdm::kSuccess;
440 #endif // CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER
441 }
442
335 cdm::Status ClearKeyCdm::DecryptToMediaDecoderBuffer( 443 cdm::Status ClearKeyCdm::DecryptToMediaDecoderBuffer(
336 const cdm::InputBuffer& encrypted_buffer, 444 const cdm::InputBuffer& encrypted_buffer,
337 scoped_refptr<media::DecoderBuffer>* decrypted_buffer) { 445 scoped_refptr<media::DecoderBuffer>* decrypted_buffer) {
338 DCHECK(decrypted_buffer); 446 DCHECK(decrypted_buffer);
339 scoped_refptr<media::DecoderBuffer> buffer = 447 scoped_refptr<media::DecoderBuffer> buffer =
340 CopyDecoderBufferFrom(encrypted_buffer); 448 CopyDecoderBufferFrom(encrypted_buffer);
341 449
342 if (buffer->IsEndOfStream()) { 450 if (buffer->IsEndOfStream()) {
343 *decrypted_buffer = buffer; 451 *decrypted_buffer = buffer;
344 return cdm::kSuccess; 452 return cdm::kSuccess;
(...skipping 11 matching lines...) Expand all
356 if (status == media::Decryptor::kError) 464 if (status == media::Decryptor::kError)
357 return cdm::kDecryptError; 465 return cdm::kDecryptError;
358 466
359 if (status == media::Decryptor::kNoKey) 467 if (status == media::Decryptor::kNoKey)
360 return cdm::kNoKey; 468 return cdm::kNoKey;
361 469
362 DCHECK_EQ(status, media::Decryptor::kSuccess); 470 DCHECK_EQ(status, media::Decryptor::kSuccess);
363 return cdm::kSuccess; 471 return cdm::kSuccess;
364 } 472 }
365 473
474 #if defined(CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER)
475 void ClearKeyCdm::GenerateFakeAudioFrames(cdm::AudioFrames* audio_frames) {
476 DCHECK(last_duration_ != media::kInfiniteDuration());
477 int64 duration_in_microseconds = last_duration_.InMicroseconds();
478 DCHECK_GT(duration_in_microseconds, 0);
479
480 int64 timestamp = last_timestamp_.InMicroseconds();
481 int64 bytes_per_sample = channel_count_ * bits_per_channel_ / 8;
482 int64 frame_size = bytes_per_sample * samples_per_second_ *
483 duration_in_microseconds / base::Time::kMicrosecondsPerSecond;
484
485 const int kHeaderSize = sizeof(timestamp) + sizeof(frame_size);
486 audio_frames->set_buffer(allocator_->Allocate(kHeaderSize + frame_size));
487 int64* data = reinterpret_cast<int64*>(audio_frames->buffer()->data());
488 *(data++) = timestamp;
489 *(data++) = frame_size;
490 // You won't hear anything because we have all zeros here. But the video
491 // should play just fine!
492 memset(data, 0, frame_size);
493 }
494 #endif // CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER
495
366 #if defined(CLEAR_KEY_CDM_USE_FAKE_VIDEO_DECODER) 496 #if defined(CLEAR_KEY_CDM_USE_FAKE_VIDEO_DECODER)
367 void ClearKeyCdm::GenerateFakeVideoFrame(base::TimeDelta timestamp, 497 void ClearKeyCdm::GenerateFakeVideoFrame(base::TimeDelta timestamp,
368 cdm::VideoFrame* video_frame) { 498 cdm::VideoFrame* video_frame) {
369 // Choose non-zero alignment and padding on purpose for testing. 499 // Choose non-zero alignment and padding on purpose for testing.
370 const int kAlignment = 8; 500 const int kAlignment = 8;
371 const int kPadding = 16; 501 const int kPadding = 16;
372 const int kPlanePadding = 128; 502 const int kPlanePadding = 128;
373 503
374 int width = video_size_.width; 504 int width = video_size_.width;
375 int height = video_size_.height; 505 int height = video_size_.height;
(...skipping 22 matching lines...) Expand all
398 video_frame->set_timestamp(timestamp.InMicroseconds()); 528 video_frame->set_timestamp(timestamp.InMicroseconds());
399 529
400 static unsigned char color = 0; 530 static unsigned char color = 0;
401 color += 10; 531 color += 10;
402 532
403 memset(reinterpret_cast<void*>(video_frame->frame_buffer()->data()), 533 memset(reinterpret_cast<void*>(video_frame->frame_buffer()->data()),
404 color, frame_size); 534 color, frame_size);
405 } 535 }
406 #endif // CLEAR_KEY_CDM_USE_FAKE_VIDEO_DECODER 536 #endif // CLEAR_KEY_CDM_USE_FAKE_VIDEO_DECODER
407 537
408 cdm::Status ClearKeyCdm::DecryptAndDecodeSamples(
409 const cdm::InputBuffer& encrypted_buffer,
410 cdm::Buffer* sample_buffer) {
411 NOTIMPLEMENTED();
412 return cdm::kDecryptError;
413 }
414
415 } // namespace webkit_media 538 } // namespace webkit_media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698