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; | |
kqyang
2016/10/12 22:16:52
s/fourCC/fourcc/
variable name should not be capi
dougsteed
2016/10/14 21:24:35
Done.
| |
46 EncryptionScheme::CipherMode mode = EncryptionScheme::CIPHER_MODE_UNENCRYPTED; | |
47 EncryptionScheme::Pattern pattern; | |
48 bool uses_pattern_encryption = false; | |
49 switch (fourCC) { | |
50 case FOURCC_CENC: | |
51 mode = EncryptionScheme::CIPHER_MODE_AES_CTR; | |
52 break; | |
53 #if BUILDFLAG(ENABLE_CBCS_ENCRYPTION_SCHEME) | |
54 case FOURCC_CBCS: | |
55 mode = EncryptionScheme::CIPHER_MODE_AES_CBC; | |
56 uses_pattern_encryption = true; | |
57 break; | |
58 #endif | |
59 default: | |
60 NOTREACHED(); | |
61 break; | |
62 } | |
63 #if BUILDFLAG(ENABLE_CBCS_ENCRYPTION_SCHEME) | |
64 if (uses_pattern_encryption) { | |
65 uint8_t crypt = sinf.info.track_encryption.default_crypt_byte_block; | |
66 uint8_t skip = sinf.info.track_encryption.default_skip_byte_block; | |
67 pattern = EncryptionScheme::Pattern(crypt, skip); | |
68 } | |
69 #endif | |
70 return EncryptionScheme(mode, pattern); | |
71 } | |
38 } // namespace | 72 } // namespace |
39 | 73 |
40 MP4StreamParser::MP4StreamParser(const std::set<int>& audio_object_types, | 74 MP4StreamParser::MP4StreamParser(const std::set<int>& audio_object_types, |
41 bool has_sbr) | 75 bool has_sbr) |
42 : state_(kWaitingForInit), | 76 : state_(kWaitingForInit), |
43 moof_head_(0), | 77 moof_head_(0), |
44 mdat_tail_(0), | 78 mdat_tail_(0), |
45 highest_end_offset_(0), | 79 highest_end_offset_(0), |
46 has_audio_(false), | 80 has_audio_(false), |
47 has_video_(false), | 81 has_video_(false), |
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
310 | 344 |
311 uint32_t audio_track_id = track->header.track_id; | 345 uint32_t audio_track_id = track->header.track_id; |
312 if (audio_track_ids_.find(audio_track_id) != audio_track_ids_.end()) { | 346 if (audio_track_ids_.find(audio_track_id) != audio_track_ids_.end()) { |
313 MEDIA_LOG(ERROR, media_log_) | 347 MEDIA_LOG(ERROR, media_log_) |
314 << "Audio track with track_id=" << audio_track_id | 348 << "Audio track with track_id=" << audio_track_id |
315 << " already present."; | 349 << " already present."; |
316 return false; | 350 return false; |
317 } | 351 } |
318 bool is_track_encrypted = entry.sinf.info.track_encryption.is_encrypted; | 352 bool is_track_encrypted = entry.sinf.info.track_encryption.is_encrypted; |
319 is_track_encrypted_[audio_track_id] = is_track_encrypted; | 353 is_track_encrypted_[audio_track_id] = is_track_encrypted; |
320 audio_config.Initialize( | 354 EncryptionScheme scheme = Unencrypted(); |
321 codec, sample_format, channel_layout, sample_per_second, extra_data, | 355 if (is_track_encrypted) { |
322 is_track_encrypted ? AesCtrEncryptionScheme() : Unencrypted(), | 356 scheme = GetEncryptionScheme(entry.sinf); |
323 base::TimeDelta(), 0); | 357 if (!scheme.is_encrypted()) |
358 return false; | |
359 } | |
360 audio_config.Initialize(codec, sample_format, channel_layout, | |
361 sample_per_second, extra_data, scheme, | |
kqyang
2016/10/12 22:16:52
I don't think it is a good idea to pass encryption
dougsteed
2016/10/14 21:24:35
Let's discuss further. I'm not sure I agree that s
| |
362 base::TimeDelta(), 0); | |
324 DVLOG(1) << "audio_track_id=" << audio_track_id | 363 DVLOG(1) << "audio_track_id=" << audio_track_id |
325 << " config=" << audio_config.AsHumanReadableString(); | 364 << " config=" << audio_config.AsHumanReadableString(); |
326 if (!audio_config.IsValidConfig()) { | 365 if (!audio_config.IsValidConfig()) { |
327 MEDIA_LOG(ERROR, media_log_) << "Invalid audio decoder config: " | 366 MEDIA_LOG(ERROR, media_log_) << "Invalid audio decoder config: " |
328 << audio_config.AsHumanReadableString(); | 367 << audio_config.AsHumanReadableString(); |
329 return false; | 368 return false; |
330 } | 369 } |
331 has_audio_ = true; | 370 has_audio_ = true; |
332 audio_track_ids_.insert(audio_track_id); | 371 audio_track_ids_.insert(audio_track_id); |
333 const char* track_kind = (audio_track_ids_.size() == 1 ? "main" : ""); | 372 const char* track_kind = (audio_track_ids_.size() == 1 ? "main" : ""); |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
371 | 410 |
372 uint32_t video_track_id = track->header.track_id; | 411 uint32_t video_track_id = track->header.track_id; |
373 if (video_track_ids_.find(video_track_id) != video_track_ids_.end()) { | 412 if (video_track_ids_.find(video_track_id) != video_track_ids_.end()) { |
374 MEDIA_LOG(ERROR, media_log_) | 413 MEDIA_LOG(ERROR, media_log_) |
375 << "Video track with track_id=" << video_track_id | 414 << "Video track with track_id=" << video_track_id |
376 << " already present."; | 415 << " already present."; |
377 return false; | 416 return false; |
378 } | 417 } |
379 bool is_track_encrypted = entry.sinf.info.track_encryption.is_encrypted; | 418 bool is_track_encrypted = entry.sinf.info.track_encryption.is_encrypted; |
380 is_track_encrypted_[video_track_id] = is_track_encrypted; | 419 is_track_encrypted_[video_track_id] = is_track_encrypted; |
381 video_config.Initialize( | 420 EncryptionScheme scheme = Unencrypted(); |
382 entry.video_codec, entry.video_codec_profile, PIXEL_FORMAT_YV12, | 421 if (is_track_encrypted) { |
383 COLOR_SPACE_HD_REC709, coded_size, visible_rect, natural_size, | 422 scheme = GetEncryptionScheme(entry.sinf); |
384 // No decoder-specific buffer needed for AVC; | 423 if (!scheme.is_encrypted()) |
385 // SPS/PPS are embedded in the video stream | 424 return false; |
386 EmptyExtraData(), | 425 } |
387 is_track_encrypted ? AesCtrEncryptionScheme() : Unencrypted()); | 426 video_config.Initialize(entry.video_codec, entry.video_codec_profile, |
427 PIXEL_FORMAT_YV12, COLOR_SPACE_HD_REC709, | |
428 coded_size, visible_rect, natural_size, | |
429 // No decoder-specific buffer needed for AVC; | |
430 // SPS/PPS are embedded in the video stream | |
431 EmptyExtraData(), scheme); | |
388 DVLOG(1) << "video_track_id=" << video_track_id | 432 DVLOG(1) << "video_track_id=" << video_track_id |
389 << " config=" << video_config.AsHumanReadableString(); | 433 << " config=" << video_config.AsHumanReadableString(); |
390 if (!video_config.IsValidConfig()) { | 434 if (!video_config.IsValidConfig()) { |
391 MEDIA_LOG(ERROR, media_log_) << "Invalid video decoder config: " | 435 MEDIA_LOG(ERROR, media_log_) << "Invalid video decoder config: " |
392 << video_config.AsHumanReadableString(); | 436 << video_config.AsHumanReadableString(); |
393 return false; | 437 return false; |
394 } | 438 } |
395 has_video_ = true; | 439 has_video_ = true; |
396 video_track_ids_.insert(video_track_id); | 440 video_track_ids_.insert(video_track_id); |
397 const char* track_kind = (video_track_ids_.size() == 1 ? "main" : ""); | 441 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, | 659 !PrepareAACBuffer(runs_->audio_description().esds.aac, |
616 &frame_buf, &subsamples)) { | 660 &frame_buf, &subsamples)) { |
617 MEDIA_LOG(ERROR, media_log_) << "Failed to prepare AAC sample for decode"; | 661 MEDIA_LOG(ERROR, media_log_) << "Failed to prepare AAC sample for decode"; |
618 *err = true; | 662 *err = true; |
619 return false; | 663 return false; |
620 } | 664 } |
621 } | 665 } |
622 | 666 |
623 if (decrypt_config) { | 667 if (decrypt_config) { |
624 if (!subsamples.empty()) { | 668 if (!subsamples.empty()) { |
625 // Create a new config with the updated subsamples. | 669 // Create a new config with the updated subsamples. |
626 decrypt_config.reset(new DecryptConfig( | 670 decrypt_config.reset(new DecryptConfig(decrypt_config->key_id(), |
627 decrypt_config->key_id(), | 671 decrypt_config->iv(), subsamples)); |
628 decrypt_config->iv(), | |
629 subsamples)); | |
630 } | 672 } |
631 // else, use the existing config. | 673 // else, use the existing config. |
632 } else if (is_track_encrypted_[runs_->track_id()]) { | 674 } else if (is_track_encrypted_[runs_->track_id()]) { |
633 // The media pipeline requires a DecryptConfig with an empty |iv|. | 675 // The media pipeline requires a DecryptConfig with an empty |iv|. |
634 // TODO(ddorwin): Refactor so we do not need a fake key ID ("1"); | 676 // TODO(ddorwin): Refactor so we do not need a fake key ID ("1"); |
635 decrypt_config.reset( | 677 decrypt_config.reset( |
636 new DecryptConfig("1", "", std::vector<SubsampleEntry>())); | 678 new DecryptConfig("1", "", std::vector<SubsampleEntry>())); |
637 } | 679 } |
638 | 680 |
639 StreamParserBuffer::Type buffer_type = audio ? DemuxerStream::AUDIO : | 681 StreamParserBuffer::Type buffer_type = audio ? DemuxerStream::AUDIO : |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
731 runs.AdvanceSample(); | 773 runs.AdvanceSample(); |
732 } | 774 } |
733 runs.AdvanceRun(); | 775 runs.AdvanceRun(); |
734 } | 776 } |
735 | 777 |
736 return true; | 778 return true; |
737 } | 779 } |
738 | 780 |
739 } // namespace mp4 | 781 } // namespace mp4 |
740 } // namespace media | 782 } // namespace media |
OLD | NEW |