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/mp2t/mp2t_stream_parser.h" | 5 #include "media/formats/mp2t/mp2t_stream_parser.h" |
6 | 6 |
7 #include <memory> | 7 #include <memory> |
8 #include <utility> | 8 #include <utility> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "base/callback_helpers.h" | 11 #include "base/callback_helpers.h" |
12 #include "media/base/media_tracks.h" | 12 #include "media/base/media_tracks.h" |
13 #include "media/base/stream_parser_buffer.h" | 13 #include "media/base/stream_parser_buffer.h" |
14 #include "media/base/text_track_config.h" | 14 #include "media/base/text_track_config.h" |
15 #include "media/base/timestamp_constants.h" | 15 #include "media/base/timestamp_constants.h" |
16 #include "media/formats/mp2t/descriptors.h" | |
16 #include "media/formats/mp2t/es_parser.h" | 17 #include "media/formats/mp2t/es_parser.h" |
17 #include "media/formats/mp2t/es_parser_adts.h" | 18 #include "media/formats/mp2t/es_parser_adts.h" |
18 #include "media/formats/mp2t/es_parser_h264.h" | 19 #include "media/formats/mp2t/es_parser_h264.h" |
19 #include "media/formats/mp2t/es_parser_mpeg1audio.h" | 20 #include "media/formats/mp2t/es_parser_mpeg1audio.h" |
20 #include "media/formats/mp2t/mp2t_common.h" | 21 #include "media/formats/mp2t/mp2t_common.h" |
21 #include "media/formats/mp2t/ts_packet.h" | 22 #include "media/formats/mp2t/ts_packet.h" |
22 #include "media/formats/mp2t/ts_section.h" | 23 #include "media/formats/mp2t/ts_section.h" |
23 #include "media/formats/mp2t/ts_section_pat.h" | 24 #include "media/formats/mp2t/ts_section_pat.h" |
24 #include "media/formats/mp2t/ts_section_pes.h" | 25 #include "media/formats/mp2t/ts_section_pes.h" |
25 #include "media/formats/mp2t/ts_section_pmt.h" | 26 #include "media/formats/mp2t/ts_section_pmt.h" |
(...skipping 335 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
361 PidState* pid_state = pid_pair.second.get(); | 362 PidState* pid_state = pid_pair.second.get(); |
362 if (pid_state->pid_type() == PidState::kPidPmt) { | 363 if (pid_state->pid_type() == PidState::kPidPmt) { |
363 DVLOG_IF(1, pmt_pid != pid_pair.first) | 364 DVLOG_IF(1, pmt_pid != pid_pair.first) |
364 << "More than one program is defined"; | 365 << "More than one program is defined"; |
365 return; | 366 return; |
366 } | 367 } |
367 } | 368 } |
368 | 369 |
369 // Create the PMT state here if needed. | 370 // Create the PMT state here if needed. |
370 DVLOG(1) << "Create a new PMT parser"; | 371 DVLOG(1) << "Create a new PMT parser"; |
371 std::unique_ptr<TsSection> pmt_section_parser(new TsSectionPmt(base::Bind( | 372 std::unique_ptr<TsSection> pmt_section_parser(new TsSectionPmt( |
372 &Mp2tStreamParser::RegisterPes, base::Unretained(this), pmt_pid))); | 373 base::Bind(&Mp2tStreamParser::RegisterPes, base::Unretained(this)))); |
373 std::unique_ptr<PidState> pmt_pid_state( | 374 std::unique_ptr<PidState> pmt_pid_state( |
374 new PidState(pmt_pid, PidState::kPidPmt, std::move(pmt_section_parser))); | 375 new PidState(pmt_pid, PidState::kPidPmt, std::move(pmt_section_parser))); |
375 pmt_pid_state->Enable(); | 376 pmt_pid_state->Enable(); |
376 pids_.insert(std::make_pair(pmt_pid, std::move(pmt_pid_state))); | 377 pids_.insert(std::make_pair(pmt_pid, std::move(pmt_pid_state))); |
377 | 378 |
378 #if BUILDFLAG(ENABLE_HLS_SAMPLE_AES) | 379 #if BUILDFLAG(ENABLE_HLS_SAMPLE_AES) |
379 // Take the opportunity to clean up any PIDs that were involved in importing | 380 // Take the opportunity to clean up any PIDs that were involved in importing |
380 // encryption metadata for HLS with SampleAES. This prevents the possibility | 381 // encryption metadata for HLS with SampleAES. This prevents the possibility |
381 // of interference with actual PIDs that might be declared in the PMT. | 382 // of interference with actual PIDs that might be declared in the PMT. |
382 // TODO(dougsteed): if in the future the appropriate PIDs are embedded in the | 383 // TODO(dougsteed): if in the future the appropriate PIDs are embedded in the |
383 // source stream, this will not be necessary. | 384 // source stream, this will not be necessary. |
384 UnregisterCat(); | 385 UnregisterCat(); |
385 UnregisterCencPids(); | 386 UnregisterCencPids(); |
386 #endif | 387 #endif |
387 } | 388 } |
388 | 389 |
389 void Mp2tStreamParser::RegisterPes(int pmt_pid, | 390 std::unique_ptr<EsParser> Mp2tStreamParser::MaybeCreateH264Parser( |
390 int pes_pid, | 391 int pes_pid, |
392 int stream_type, | |
393 const Descriptors& descriptors) { | |
394 bool is_h264 = stream_type == kStreamTypeAVC; | |
395 bool enable_hls = false; | |
396 std::unique_ptr<EsParser> es_parser; | |
397 | |
398 #if BUILDFLAG(ENABLE_HLS_SAMPLE_AES) | |
399 if (is_h264 && !is_initialized_ && initial_scheme_.is_encrypted()) { | |
400 enable_hls = true; | |
401 } else if (stream_type == kStreamTypeAVCWithSampleAES && | |
402 descriptors.HasPrivateDataIndicator( | |
403 kSampleAESPrivateDataIndicatorAVC)) { | |
404 is_h264 = true; | |
405 enable_hls = true; | |
406 } | |
407 #endif | |
408 | |
409 if (!is_h264) | |
410 return nullptr; | |
411 | |
412 auto on_video_config_changed = base::Bind( | |
413 &Mp2tStreamParser::OnVideoConfigChanged, base::Unretained(this), pes_pid); | |
414 auto on_emit_video_buffer = base::Bind(&Mp2tStreamParser::OnEmitVideoBuffer, | |
415 base::Unretained(this), pes_pid); | |
416 if (!enable_hls) { | |
417 es_parser.reset( | |
418 new EsParserH264(on_video_config_changed, on_emit_video_buffer)); | |
419 } | |
420 #if BUILDFLAG(ENABLE_HLS_SAMPLE_AES) | |
421 else { | |
422 auto get_decrypt_config = | |
423 base::Bind(&Mp2tStreamParser::GetDecryptConfig, base::Unretained(this)); | |
424 es_parser.reset(new EsParserH264(on_video_config_changed, | |
425 on_emit_video_buffer, true, | |
426 get_decrypt_config)); | |
427 } | |
428 #endif | |
429 return es_parser; | |
430 } | |
431 | |
432 std::unique_ptr<EsParser> Mp2tStreamParser::MaybeCreateAACParser( | |
433 int pes_pid, | |
434 int stream_type, | |
435 const Descriptors& descriptors) { | |
436 bool is_AAC = stream_type == kStreamTypeAAC; | |
437 bool enable_hls = false; | |
438 std::unique_ptr<EsParser> es_parser; | |
439 #if BUILDFLAG(ENABLE_HLS_SAMPLE_AES) | |
440 if (is_AAC && !is_initialized_ && initial_scheme_.is_encrypted()) { | |
kqyang
2017/04/07 23:33:43
I understand that Marvel does not support switchin
dougsteed
2017/04/26 20:34:14
On this platform, we always need to initialize a d
kqyang
2017/05/06 00:06:12
Is this a limitation of Chromium media pipeline or
| |
441 enable_hls = true; | |
442 } else if (stream_type == kStreamTypeAACWithSampleAES && | |
443 descriptors.HasPrivateDataIndicator( | |
444 kSampleAESPrivateDataIndicatorAAC)) { | |
445 is_AAC = true; | |
446 enable_hls = true; | |
447 } | |
448 #endif | |
449 | |
450 if (!is_AAC) | |
451 return nullptr; | |
452 | |
453 auto on_audio_config_changed = base::Bind( | |
454 &Mp2tStreamParser::OnAudioConfigChanged, base::Unretained(this), pes_pid); | |
455 auto on_emit_audio_buffer = base::Bind(&Mp2tStreamParser::OnEmitAudioBuffer, | |
456 base::Unretained(this), pes_pid); | |
457 if (!enable_hls) { | |
458 es_parser.reset(new EsParserAdts(on_audio_config_changed, | |
459 on_emit_audio_buffer, sbr_in_mimetype_)); | |
460 } | |
461 #if BUILDFLAG(ENABLE_HLS_SAMPLE_AES) | |
462 else { | |
463 auto get_decrypt_config = | |
464 base::Bind(&Mp2tStreamParser::GetDecryptConfig, base::Unretained(this)); | |
465 es_parser.reset(new EsParserAdts(on_audio_config_changed, | |
466 on_emit_audio_buffer, get_decrypt_config, | |
467 true, sbr_in_mimetype_)); | |
468 } | |
469 #endif | |
470 return es_parser; | |
471 } | |
472 | |
473 std::unique_ptr<EsParser> Mp2tStreamParser::MaybeCreateMpeg1AudioParser( | |
474 int pes_pid, | |
475 int stream_type) { | |
476 if (stream_type != kStreamTypeMpeg1Audio) | |
servolk
2017/04/04 20:08:18
&& stream_type != kStreamTypeMpeg2Audio
dougsteed
2017/04/26 20:34:14
Done.
| |
477 return nullptr; | |
478 auto on_audio_config_changed = base::Bind( | |
479 &Mp2tStreamParser::OnAudioConfigChanged, base::Unretained(this), pes_pid); | |
480 auto on_emit_audio_buffer = base::Bind(&Mp2tStreamParser::OnEmitAudioBuffer, | |
481 base::Unretained(this), pes_pid); | |
482 std::unique_ptr<EsParser> es_parser(new EsParserMpeg1Audio( | |
483 on_audio_config_changed, on_emit_audio_buffer, media_log_)); | |
484 return es_parser; | |
485 } | |
486 | |
487 void Mp2tStreamParser::RegisterPes(int pes_pid, | |
391 int stream_type, | 488 int stream_type, |
392 const Descriptors& descriptors) { | 489 const Descriptors& descriptors) { |
393 // TODO(damienv): check there is no mismatch if the entry already exists. | 490 // TODO(damienv): check there is no mismatch if the entry already exists. |
394 DVLOG(1) << "RegisterPes:" | 491 DVLOG(1) << "RegisterPes:" |
395 << " pes_pid=" << pes_pid | 492 << " pes_pid=" << pes_pid |
396 << " stream_type=" << std::hex << stream_type << std::dec; | 493 << " stream_type=" << std::hex << stream_type << std::dec; |
397 auto it = pids_.find(pes_pid); | 494 auto it = pids_.find(pes_pid); |
398 if (it != pids_.end()) | 495 if (it != pids_.end()) |
399 return; | 496 return; |
400 | 497 |
401 // Create a stream parser corresponding to the stream type. | 498 // Create a stream parser corresponding to the stream type. |
402 bool is_audio = false; | 499 bool is_audio = true; |
403 std::unique_ptr<EsParser> es_parser; | 500 std::unique_ptr<EsParser> es_parser; |
404 if (stream_type == kStreamTypeAVC) { | 501 |
405 es_parser.reset( | 502 es_parser = MaybeCreateH264Parser(pes_pid, stream_type, descriptors); |
406 new EsParserH264( | 503 if (es_parser) |
407 base::Bind(&Mp2tStreamParser::OnVideoConfigChanged, | 504 is_audio = false; |
408 base::Unretained(this), | 505 else |
409 pes_pid), | 506 es_parser = MaybeCreateAACParser(pes_pid, stream_type, descriptors); |
410 base::Bind(&Mp2tStreamParser::OnEmitVideoBuffer, | 507 |
411 base::Unretained(this), | 508 if (!es_parser) |
412 pes_pid))); | 509 es_parser = MaybeCreateMpeg1AudioParser(pes_pid, stream_type); |
413 } else if (stream_type == kStreamTypeAAC) { | 510 |
414 es_parser.reset( | 511 if (!es_parser) |
kqyang
2017/04/07 23:33:43
I think the code would be cleaner and easier to ma
dougsteed
2017/04/26 20:34:14
Adopted this general approach, but with some varia
| |
415 new EsParserAdts( | |
416 base::Bind(&Mp2tStreamParser::OnAudioConfigChanged, | |
417 base::Unretained(this), | |
418 pes_pid), | |
419 base::Bind(&Mp2tStreamParser::OnEmitAudioBuffer, | |
420 base::Unretained(this), | |
421 pes_pid), | |
422 sbr_in_mimetype_)); | |
423 is_audio = true; | |
424 } else if (stream_type == kStreamTypeMpeg1Audio) { | |
425 es_parser.reset(new EsParserMpeg1Audio( | |
426 base::Bind(&Mp2tStreamParser::OnAudioConfigChanged, | |
427 base::Unretained(this), pes_pid), | |
428 base::Bind(&Mp2tStreamParser::OnEmitAudioBuffer, base::Unretained(this), | |
429 pes_pid), | |
430 media_log_)); | |
431 is_audio = true; | |
432 #if BUILDFLAG(ENABLE_HLS_SAMPLE_AES) | |
433 } else if (stream_type == kStreamTypeAVCWithSampleAES && | |
434 descriptors.HasPrivateDataIndicator( | |
435 kSampleAESPrivateDataIndicatorAVC)) { | |
436 es_parser.reset( | |
437 new EsParserH264(base::Bind(&Mp2tStreamParser::OnVideoConfigChanged, | |
438 base::Unretained(this), pes_pid), | |
439 base::Bind(&Mp2tStreamParser::OnEmitVideoBuffer, | |
440 base::Unretained(this), pes_pid), | |
441 true, base::Bind(&Mp2tStreamParser::GetDecryptConfig, | |
442 base::Unretained(this)))); | |
443 } else if (stream_type == kStreamTypeAACWithSampleAES && | |
444 descriptors.HasPrivateDataIndicator( | |
445 kSampleAESPrivateDataIndicatorAAC)) { | |
446 es_parser.reset(new EsParserAdts( | |
447 base::Bind(&Mp2tStreamParser::OnAudioConfigChanged, | |
448 base::Unretained(this), pes_pid), | |
449 base::Bind(&Mp2tStreamParser::OnEmitAudioBuffer, base::Unretained(this), | |
450 pes_pid), | |
451 base::Bind(&Mp2tStreamParser::GetDecryptConfig, base::Unretained(this)), | |
452 true, sbr_in_mimetype_)); | |
453 is_audio = true; | |
454 #endif | |
455 } else { | |
456 return; | 512 return; |
457 } | |
458 | 513 |
459 // Create the PES state here. | 514 // Create the PES state here. |
460 DVLOG(1) << "Create a new PES state"; | 515 DVLOG(1) << "Create a new PES state"; |
461 std::unique_ptr<TsSection> pes_section_parser( | 516 std::unique_ptr<TsSection> pes_section_parser( |
462 new TsSectionPes(std::move(es_parser), ×tamp_unroller_)); | 517 new TsSectionPes(std::move(es_parser), ×tamp_unroller_)); |
463 PidState::PidType pid_type = | 518 PidState::PidType pid_type = |
464 is_audio ? PidState::kPidAudioPes : PidState::kPidVideoPes; | 519 is_audio ? PidState::kPidAudioPes : PidState::kPidVideoPes; |
465 std::unique_ptr<PidState> pes_pid_state( | 520 std::unique_ptr<PidState> pes_pid_state( |
466 new PidState(pes_pid, pid_type, std::move(pes_section_parser))); | 521 new PidState(pes_pid, pid_type, std::move(pes_section_parser))); |
467 pids_.insert(std::make_pair(pes_pid, std::move(pes_pid_state))); | 522 pids_.insert(std::make_pair(pes_pid, std::move(pes_pid_state))); |
(...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
745 BufferQueueWithConfig queue_with_config( | 800 BufferQueueWithConfig queue_with_config( |
746 true, last_audio_config, last_video_config); | 801 true, last_audio_config, last_video_config); |
747 buffer_queue_chain_.push_back(queue_with_config); | 802 buffer_queue_chain_.push_back(queue_with_config); |
748 | 803 |
749 return true; | 804 return true; |
750 } | 805 } |
751 | 806 |
752 #if BUILDFLAG(ENABLE_HLS_SAMPLE_AES) | 807 #if BUILDFLAG(ENABLE_HLS_SAMPLE_AES) |
753 std::unique_ptr<PidState> Mp2tStreamParser::MakeCatPidState() { | 808 std::unique_ptr<PidState> Mp2tStreamParser::MakeCatPidState() { |
754 std::unique_ptr<TsSection> cat_section_parser(new TsSectionCat( | 809 std::unique_ptr<TsSection> cat_section_parser(new TsSectionCat( |
755 base::Bind(&Mp2tStreamParser::RegisterCencPids, base::Unretained(this)))); | 810 base::Bind(&Mp2tStreamParser::RegisterCencPids, base::Unretained(this)), |
811 base::Bind(&Mp2tStreamParser::RegisterEncryptionScheme, | |
812 base::Unretained(this)))); | |
756 std::unique_ptr<PidState> cat_pid_state(new PidState( | 813 std::unique_ptr<PidState> cat_pid_state(new PidState( |
757 TsSection::kPidCat, PidState::kPidCat, std::move(cat_section_parser))); | 814 TsSection::kPidCat, PidState::kPidCat, std::move(cat_section_parser))); |
758 cat_pid_state->Enable(); | 815 cat_pid_state->Enable(); |
759 return cat_pid_state; | 816 return cat_pid_state; |
760 } | 817 } |
761 | 818 |
762 void Mp2tStreamParser::UnregisterCat() { | 819 void Mp2tStreamParser::UnregisterCat() { |
763 for (auto& pid : pids_) { | 820 for (auto& pid : pids_) { |
764 if (pid.second->pid_type() == PidState::kPidCat) { | 821 if (pid.second->pid_type() == PidState::kPidCat) { |
765 pids_.erase(pid.first); | 822 pids_.erase(pid.first); |
(...skipping 27 matching lines...) Expand all Loading... | |
793 } | 850 } |
794 } | 851 } |
795 for (auto& pid : pids_) { | 852 for (auto& pid : pids_) { |
796 if (pid.second->pid_type() == PidState::kPidCetsPssh) { | 853 if (pid.second->pid_type() == PidState::kPidCetsPssh) { |
797 pids_.erase(pid.first); | 854 pids_.erase(pid.first); |
798 break; | 855 break; |
799 } | 856 } |
800 } | 857 } |
801 } | 858 } |
802 | 859 |
860 void Mp2tStreamParser::RegisterEncryptionScheme( | |
861 const EncryptionScheme& scheme) { | |
862 // We only need to record this for the initial decoder config. | |
863 if (!is_initialized_) { | |
864 initial_scheme_ = scheme; | |
865 } | |
866 // Reset the DecryptConfig, so that unless and until a CENC-ECM (containing | |
867 // key id and IV) is seen, media data will be considered unencrypted. This is | |
868 // similar to the way clear leaders can occur in MP4 containers. | |
869 decrypt_config_.reset(nullptr); | |
870 } | |
871 | |
803 void Mp2tStreamParser::RegisterDecryptConfig(const DecryptConfig& config) { | 872 void Mp2tStreamParser::RegisterDecryptConfig(const DecryptConfig& config) { |
804 decrypt_config_.reset( | 873 decrypt_config_.reset( |
805 new DecryptConfig(config.key_id(), config.iv(), config.subsamples())); | 874 new DecryptConfig(config.key_id(), config.iv(), config.subsamples())); |
806 } | 875 } |
807 | 876 |
808 void Mp2tStreamParser::RegisterPsshBoxes( | 877 void Mp2tStreamParser::RegisterPsshBoxes( |
809 const std::vector<uint8_t>& init_data) { | 878 const std::vector<uint8_t>& init_data) { |
810 encrypted_media_init_data_cb_.Run(EmeInitDataType::CENC, init_data); | 879 encrypted_media_init_data_cb_.Run(EmeInitDataType::CENC, init_data); |
811 } | 880 } |
812 | 881 |
813 #endif | 882 #endif |
814 | 883 |
815 } // namespace mp2t | 884 } // namespace mp2t |
816 } // namespace media | 885 } // namespace media |
OLD | NEW |