OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "media/formats/mp4/mp4_stream_parser.h" | 5 #include "media/formats/mp4/mp4_stream_parser.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 | 8 |
9 #include <limits> | 9 #include <limits> |
10 #include <memory> | 10 #include <memory> |
11 #include <utility> | 11 #include <utility> |
12 #include <vector> | 12 #include <vector> |
13 | 13 |
14 #include "base/callback_helpers.h" | 14 #include "base/callback_helpers.h" |
15 #include "base/logging.h" | 15 #include "base/logging.h" |
16 #include "base/strings/string_number_conversions.h" | 16 #include "base/strings/string_number_conversions.h" |
17 #include "base/time/time.h" | 17 #include "base/time/time.h" |
18 #include "build/build_config.h" | 18 #include "build/build_config.h" |
19 #include "media/base/audio_decoder_config.h" | 19 #include "media/base/audio_decoder_config.h" |
| 20 #include "media/base/encryption_scheme.h" |
20 #include "media/base/media_tracks.h" | 21 #include "media/base/media_tracks.h" |
21 #include "media/base/media_util.h" | 22 #include "media/base/media_util.h" |
22 #include "media/base/stream_parser_buffer.h" | 23 #include "media/base/stream_parser_buffer.h" |
23 #include "media/base/text_track_config.h" | 24 #include "media/base/text_track_config.h" |
24 #include "media/base/timestamp_constants.h" | 25 #include "media/base/timestamp_constants.h" |
25 #include "media/base/video_decoder_config.h" | 26 #include "media/base/video_decoder_config.h" |
26 #include "media/base/video_util.h" | 27 #include "media/base/video_util.h" |
27 #include "media/formats/mp4/box_definitions.h" | 28 #include "media/formats/mp4/box_definitions.h" |
28 #include "media/formats/mp4/box_reader.h" | 29 #include "media/formats/mp4/box_reader.h" |
29 #include "media/formats/mp4/es_descriptor.h" | 30 #include "media/formats/mp4/es_descriptor.h" |
30 #include "media/formats/mp4/rcheck.h" | 31 #include "media/formats/mp4/rcheck.h" |
31 #include "media/formats/mpeg/adts_constants.h" | 32 #include "media/formats/mpeg/adts_constants.h" |
32 | 33 |
33 namespace media { | 34 namespace media { |
34 namespace mp4 { | 35 namespace mp4 { |
35 | 36 |
36 namespace { | 37 namespace { |
37 const int kMaxEmptySampleLogs = 20; | 38 const int kMaxEmptySampleLogs = 20; |
| 39 |
| 40 // Caller should be prepared to handle return of Unencrypted() in case of |
| 41 // unsupported scheme. |
| 42 EncryptionScheme GetEncryptionScheme(const ProtectionSchemeInfo& sinf) { |
| 43 if (!sinf.HasSupportedScheme()) |
| 44 return Unencrypted(); |
| 45 FourCC fourcc = sinf.type.type; |
| 46 EncryptionScheme::CipherMode mode = EncryptionScheme::CIPHER_MODE_UNENCRYPTED; |
| 47 EncryptionScheme::Pattern pattern; |
| 48 #if BUILDFLAG(ENABLE_CBCS_ENCRYPTION_SCHEME) |
| 49 bool uses_pattern_encryption = false; |
| 50 #endif |
| 51 switch (fourcc) { |
| 52 case FOURCC_CENC: |
| 53 mode = EncryptionScheme::CIPHER_MODE_AES_CTR; |
| 54 break; |
| 55 #if BUILDFLAG(ENABLE_CBCS_ENCRYPTION_SCHEME) |
| 56 case FOURCC_CBCS: |
| 57 mode = EncryptionScheme::CIPHER_MODE_AES_CBC; |
| 58 uses_pattern_encryption = true; |
| 59 break; |
| 60 #endif |
| 61 default: |
| 62 NOTREACHED(); |
| 63 break; |
| 64 } |
| 65 #if BUILDFLAG(ENABLE_CBCS_ENCRYPTION_SCHEME) |
| 66 if (uses_pattern_encryption) { |
| 67 uint8_t crypt = sinf.info.track_encryption.default_crypt_byte_block; |
| 68 uint8_t skip = sinf.info.track_encryption.default_skip_byte_block; |
| 69 pattern = EncryptionScheme::Pattern(crypt, skip); |
| 70 } |
| 71 #endif |
| 72 return EncryptionScheme(mode, pattern); |
| 73 } |
38 } // namespace | 74 } // namespace |
39 | 75 |
40 MP4StreamParser::MP4StreamParser(const std::set<int>& audio_object_types, | 76 MP4StreamParser::MP4StreamParser(const std::set<int>& audio_object_types, |
41 bool has_sbr) | 77 bool has_sbr) |
42 : state_(kWaitingForInit), | 78 : state_(kWaitingForInit), |
43 moof_head_(0), | 79 moof_head_(0), |
44 mdat_tail_(0), | 80 mdat_tail_(0), |
45 highest_end_offset_(0), | 81 highest_end_offset_(0), |
46 has_audio_(false), | 82 has_audio_(false), |
47 has_video_(false), | 83 has_video_(false), |
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
310 | 346 |
311 uint32_t audio_track_id = track->header.track_id; | 347 uint32_t audio_track_id = track->header.track_id; |
312 if (audio_track_ids_.find(audio_track_id) != audio_track_ids_.end()) { | 348 if (audio_track_ids_.find(audio_track_id) != audio_track_ids_.end()) { |
313 MEDIA_LOG(ERROR, media_log_) | 349 MEDIA_LOG(ERROR, media_log_) |
314 << "Audio track with track_id=" << audio_track_id | 350 << "Audio track with track_id=" << audio_track_id |
315 << " already present."; | 351 << " already present."; |
316 return false; | 352 return false; |
317 } | 353 } |
318 bool is_track_encrypted = entry.sinf.info.track_encryption.is_encrypted; | 354 bool is_track_encrypted = entry.sinf.info.track_encryption.is_encrypted; |
319 is_track_encrypted_[audio_track_id] = is_track_encrypted; | 355 is_track_encrypted_[audio_track_id] = is_track_encrypted; |
320 audio_config.Initialize( | 356 EncryptionScheme scheme = Unencrypted(); |
321 codec, sample_format, channel_layout, sample_per_second, extra_data, | 357 if (is_track_encrypted) { |
322 is_track_encrypted ? AesCtrEncryptionScheme() : Unencrypted(), | 358 scheme = GetEncryptionScheme(entry.sinf); |
323 base::TimeDelta(), 0); | 359 if (!scheme.is_encrypted()) |
| 360 return false; |
| 361 } |
| 362 audio_config.Initialize(codec, sample_format, channel_layout, |
| 363 sample_per_second, extra_data, scheme, |
| 364 base::TimeDelta(), 0); |
324 DVLOG(1) << "audio_track_id=" << audio_track_id | 365 DVLOG(1) << "audio_track_id=" << audio_track_id |
325 << " config=" << audio_config.AsHumanReadableString(); | 366 << " config=" << audio_config.AsHumanReadableString(); |
326 if (!audio_config.IsValidConfig()) { | 367 if (!audio_config.IsValidConfig()) { |
327 MEDIA_LOG(ERROR, media_log_) << "Invalid audio decoder config: " | 368 MEDIA_LOG(ERROR, media_log_) << "Invalid audio decoder config: " |
328 << audio_config.AsHumanReadableString(); | 369 << audio_config.AsHumanReadableString(); |
329 return false; | 370 return false; |
330 } | 371 } |
331 has_audio_ = true; | 372 has_audio_ = true; |
332 audio_track_ids_.insert(audio_track_id); | 373 audio_track_ids_.insert(audio_track_id); |
333 const char* track_kind = (audio_track_ids_.size() == 1 ? "main" : ""); | 374 const char* track_kind = (audio_track_ids_.size() == 1 ? "main" : ""); |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
371 | 412 |
372 uint32_t video_track_id = track->header.track_id; | 413 uint32_t video_track_id = track->header.track_id; |
373 if (video_track_ids_.find(video_track_id) != video_track_ids_.end()) { | 414 if (video_track_ids_.find(video_track_id) != video_track_ids_.end()) { |
374 MEDIA_LOG(ERROR, media_log_) | 415 MEDIA_LOG(ERROR, media_log_) |
375 << "Video track with track_id=" << video_track_id | 416 << "Video track with track_id=" << video_track_id |
376 << " already present."; | 417 << " already present."; |
377 return false; | 418 return false; |
378 } | 419 } |
379 bool is_track_encrypted = entry.sinf.info.track_encryption.is_encrypted; | 420 bool is_track_encrypted = entry.sinf.info.track_encryption.is_encrypted; |
380 is_track_encrypted_[video_track_id] = is_track_encrypted; | 421 is_track_encrypted_[video_track_id] = is_track_encrypted; |
381 video_config.Initialize( | 422 EncryptionScheme scheme = Unencrypted(); |
382 entry.video_codec, entry.video_codec_profile, PIXEL_FORMAT_YV12, | 423 if (is_track_encrypted) { |
383 COLOR_SPACE_HD_REC709, coded_size, visible_rect, natural_size, | 424 scheme = GetEncryptionScheme(entry.sinf); |
384 // No decoder-specific buffer needed for AVC; | 425 if (!scheme.is_encrypted()) |
385 // SPS/PPS are embedded in the video stream | 426 return false; |
386 EmptyExtraData(), | 427 } |
387 is_track_encrypted ? AesCtrEncryptionScheme() : Unencrypted()); | 428 video_config.Initialize(entry.video_codec, entry.video_codec_profile, |
| 429 PIXEL_FORMAT_YV12, COLOR_SPACE_HD_REC709, |
| 430 coded_size, visible_rect, natural_size, |
| 431 // No decoder-specific buffer needed for AVC; |
| 432 // SPS/PPS are embedded in the video stream |
| 433 EmptyExtraData(), scheme); |
388 DVLOG(1) << "video_track_id=" << video_track_id | 434 DVLOG(1) << "video_track_id=" << video_track_id |
389 << " config=" << video_config.AsHumanReadableString(); | 435 << " config=" << video_config.AsHumanReadableString(); |
390 if (!video_config.IsValidConfig()) { | 436 if (!video_config.IsValidConfig()) { |
391 MEDIA_LOG(ERROR, media_log_) << "Invalid video decoder config: " | 437 MEDIA_LOG(ERROR, media_log_) << "Invalid video decoder config: " |
392 << video_config.AsHumanReadableString(); | 438 << video_config.AsHumanReadableString(); |
393 return false; | 439 return false; |
394 } | 440 } |
395 has_video_ = true; | 441 has_video_ = true; |
396 video_track_ids_.insert(video_track_id); | 442 video_track_ids_.insert(video_track_id); |
397 const char* track_kind = (video_track_ids_.size() == 1 ? "main" : ""); | 443 const char* track_kind = (video_track_ids_.size() == 1 ? "main" : ""); |
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
615 !PrepareAACBuffer(runs_->audio_description().esds.aac, | 661 !PrepareAACBuffer(runs_->audio_description().esds.aac, |
616 &frame_buf, &subsamples)) { | 662 &frame_buf, &subsamples)) { |
617 MEDIA_LOG(ERROR, media_log_) << "Failed to prepare AAC sample for decode"; | 663 MEDIA_LOG(ERROR, media_log_) << "Failed to prepare AAC sample for decode"; |
618 *err = true; | 664 *err = true; |
619 return false; | 665 return false; |
620 } | 666 } |
621 } | 667 } |
622 | 668 |
623 if (decrypt_config) { | 669 if (decrypt_config) { |
624 if (!subsamples.empty()) { | 670 if (!subsamples.empty()) { |
625 // Create a new config with the updated subsamples. | 671 // Create a new config with the updated subsamples. |
626 decrypt_config.reset(new DecryptConfig( | 672 decrypt_config.reset(new DecryptConfig(decrypt_config->key_id(), |
627 decrypt_config->key_id(), | 673 decrypt_config->iv(), subsamples)); |
628 decrypt_config->iv(), | |
629 subsamples)); | |
630 } | 674 } |
631 // else, use the existing config. | 675 // else, use the existing config. |
632 } else if (is_track_encrypted_[runs_->track_id()]) { | 676 } else if (is_track_encrypted_[runs_->track_id()]) { |
633 // The media pipeline requires a DecryptConfig with an empty |iv|. | 677 // The media pipeline requires a DecryptConfig with an empty |iv|. |
634 // TODO(ddorwin): Refactor so we do not need a fake key ID ("1"); | 678 // TODO(ddorwin): Refactor so we do not need a fake key ID ("1"); |
635 decrypt_config.reset( | 679 decrypt_config.reset( |
636 new DecryptConfig("1", "", std::vector<SubsampleEntry>())); | 680 new DecryptConfig("1", "", std::vector<SubsampleEntry>())); |
637 } | 681 } |
638 | 682 |
639 StreamParserBuffer::Type buffer_type = audio ? DemuxerStream::AUDIO : | 683 StreamParserBuffer::Type buffer_type = audio ? DemuxerStream::AUDIO : |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
731 runs.AdvanceSample(); | 775 runs.AdvanceSample(); |
732 } | 776 } |
733 runs.AdvanceRun(); | 777 runs.AdvanceRun(); |
734 } | 778 } |
735 | 779 |
736 return true; | 780 return true; |
737 } | 781 } |
738 | 782 |
739 } // namespace mp4 | 783 } // namespace mp4 |
740 } // namespace media | 784 } // namespace media |
OLD | NEW |