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/es_parser.h" | 16 #include "media/formats/mp2t/es_parser.h" |
17 #include "media/formats/mp2t/es_parser_adts.h" | 17 #include "media/formats/mp2t/es_parser_adts.h" |
18 #include "media/formats/mp2t/es_parser_h264.h" | 18 #include "media/formats/mp2t/es_parser_h264.h" |
19 #include "media/formats/mp2t/es_parser_mpeg1audio.h" | 19 #include "media/formats/mp2t/es_parser_mpeg1audio.h" |
20 #include "media/formats/mp2t/mp2t_common.h" | 20 #include "media/formats/mp2t/mp2t_common.h" |
21 #include "media/formats/mp2t/ts_packet.h" | 21 #include "media/formats/mp2t/ts_packet.h" |
22 #include "media/formats/mp2t/ts_section.h" | 22 #include "media/formats/mp2t/ts_section.h" |
23 #include "media/formats/mp2t/ts_section_pat.h" | 23 #include "media/formats/mp2t/ts_section_pat.h" |
24 #include "media/formats/mp2t/ts_section_pes.h" | 24 #include "media/formats/mp2t/ts_section_pes.h" |
25 #include "media/formats/mp2t/ts_section_pmt.h" | 25 #include "media/formats/mp2t/ts_section_pmt.h" |
26 | 26 |
| 27 #if BUILDFLAG(ENABLE_HLS_SAMPLE_AES) |
| 28 #include "media/formats/mp2t/ts_section_cat.h" |
| 29 #include "media/formats/mp2t/ts_section_cets_ecm.h" |
| 30 #include "media/formats/mp2t/ts_section_cets_pssh.h" |
| 31 #endif |
| 32 |
27 namespace media { | 33 namespace media { |
28 namespace mp2t { | 34 namespace mp2t { |
29 | 35 |
| 36 namespace { |
| 37 |
| 38 #if BUILDFLAG(ENABLE_HLS_SAMPLE_AES) |
| 39 const int64_t kSampleAESPrivateDataIndicatorAVC = 0x7a617663; |
| 40 const int64_t kSampleAESPrivateDataIndicatorAAC = 0x61616364; |
| 41 // TODO(dougsteed). Consider adding support for the following: |
| 42 // const int64_t kSampleAESPrivateDataIndicatorAC3 = 0x61633364; |
| 43 // const int64_t kSampleAESPrivateDataIndicatorEAC3 = 0x65633364; |
| 44 #endif |
| 45 |
| 46 } // namespace |
| 47 |
30 enum StreamType { | 48 enum StreamType { |
31 // ISO-13818.1 / ITU H.222 Table 2.34 "Stream type assignments" | 49 // ISO-13818.1 / ITU H.222 Table 2.34 "Stream type assignments" |
32 kStreamTypeMpeg1Audio = 0x3, | 50 kStreamTypeMpeg1Audio = 0x3, |
33 kStreamTypeAAC = 0xf, | 51 kStreamTypeAAC = 0xf, |
34 kStreamTypeAVC = 0x1b, | 52 kStreamTypeAVC = 0x1b, |
| 53 #if BUILDFLAG(ENABLE_HLS_SAMPLE_AES) |
| 54 kStreamTypeAACWithSampleAES = 0xcf, |
| 55 kStreamTypeAVCWithSampleAES = 0xdb, |
| 56 // TODO(dougsteed). Consider adding support for the following: |
| 57 // kStreamTypeAC3WithSampleAES = 0xc1, |
| 58 // kStreamTypeEAC3WithSampleAES = 0xc2, |
| 59 #endif |
35 }; | 60 }; |
36 | 61 |
37 class PidState { | 62 class PidState { |
38 public: | 63 public: |
39 enum PidType { | 64 enum PidType { |
40 kPidPat, | 65 kPidPat, |
41 kPidPmt, | 66 kPidPmt, |
42 kPidAudioPes, | 67 kPidAudioPes, |
43 kPidVideoPes, | 68 kPidVideoPes, |
| 69 #if BUILDFLAG(ENABLE_HLS_SAMPLE_AES) |
| 70 kPidCat, |
| 71 kPidCetsEcm, |
| 72 kPidCetsPssh, |
| 73 #endif |
44 }; | 74 }; |
45 | 75 |
46 PidState(int pid, | 76 PidState(int pid, |
47 PidType pid_type, | 77 PidType pid_type, |
48 std::unique_ptr<TsSection> section_parser); | 78 std::unique_ptr<TsSection> section_parser); |
49 | 79 |
50 // Extract the content of the TS packet and parse it. | 80 // Extract the content of the TS packet and parse it. |
51 // Return true if successful. | 81 // Return true if successful. |
52 bool PushTsPacket(const TsPacket& ts_packet); | 82 bool PushTsPacket(const TsPacket& ts_packet); |
53 | 83 |
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
286 std::unique_ptr<TsSection> pat_section_parser(new TsSectionPat( | 316 std::unique_ptr<TsSection> pat_section_parser(new TsSectionPat( |
287 base::Bind(&Mp2tStreamParser::RegisterPmt, base::Unretained(this)))); | 317 base::Bind(&Mp2tStreamParser::RegisterPmt, base::Unretained(this)))); |
288 std::unique_ptr<PidState> pat_pid_state(new PidState( | 318 std::unique_ptr<PidState> pat_pid_state(new PidState( |
289 ts_packet->pid(), PidState::kPidPat, std::move(pat_section_parser))); | 319 ts_packet->pid(), PidState::kPidPat, std::move(pat_section_parser))); |
290 pat_pid_state->Enable(); | 320 pat_pid_state->Enable(); |
291 it = pids_ | 321 it = pids_ |
292 .insert( | 322 .insert( |
293 std::make_pair(ts_packet->pid(), std::move(pat_pid_state))) | 323 std::make_pair(ts_packet->pid(), std::move(pat_pid_state))) |
294 .first; | 324 .first; |
295 } | 325 } |
| 326 #if BUILDFLAG(ENABLE_HLS_SAMPLE_AES) |
| 327 // We allow a CAT to appear as the first packet in the TS. This allows us to |
| 328 // specify encryption metadata for HLS by injecting it as an extra TS packet |
| 329 // at the front of the stream. |
| 330 else if (it == pids_.end() && ts_packet->pid() == TsSection::kPidCat) { |
| 331 it = pids_.insert(std::make_pair(TsSection::kPidCat, MakeCatPidState())) |
| 332 .first; |
| 333 } |
| 334 #endif |
296 | 335 |
297 if (it != pids_.end()) { | 336 if (it != pids_.end()) { |
298 if (!it->second->PushTsPacket(*ts_packet)) | 337 if (!it->second->PushTsPacket(*ts_packet)) |
299 return false; | 338 return false; |
300 } else { | 339 } else { |
301 DVLOG(LOG_LEVEL_TS) << "Ignoring TS packet for pid: " << ts_packet->pid(); | 340 DVLOG(LOG_LEVEL_TS) << "Ignoring TS packet for pid: " << ts_packet->pid(); |
302 } | 341 } |
303 | 342 |
304 // Go to the next packet. | 343 // Go to the next packet. |
305 ts_byte_queue_.Pop(TsPacket::kPacketSize); | 344 ts_byte_queue_.Pop(TsPacket::kPacketSize); |
(...skipping 22 matching lines...) Expand all Loading... |
328 } | 367 } |
329 | 368 |
330 // Create the PMT state here if needed. | 369 // Create the PMT state here if needed. |
331 DVLOG(1) << "Create a new PMT parser"; | 370 DVLOG(1) << "Create a new PMT parser"; |
332 std::unique_ptr<TsSection> pmt_section_parser(new TsSectionPmt(base::Bind( | 371 std::unique_ptr<TsSection> pmt_section_parser(new TsSectionPmt(base::Bind( |
333 &Mp2tStreamParser::RegisterPes, base::Unretained(this), pmt_pid))); | 372 &Mp2tStreamParser::RegisterPes, base::Unretained(this), pmt_pid))); |
334 std::unique_ptr<PidState> pmt_pid_state( | 373 std::unique_ptr<PidState> pmt_pid_state( |
335 new PidState(pmt_pid, PidState::kPidPmt, std::move(pmt_section_parser))); | 374 new PidState(pmt_pid, PidState::kPidPmt, std::move(pmt_section_parser))); |
336 pmt_pid_state->Enable(); | 375 pmt_pid_state->Enable(); |
337 pids_.insert(std::make_pair(pmt_pid, std::move(pmt_pid_state))); | 376 pids_.insert(std::make_pair(pmt_pid, std::move(pmt_pid_state))); |
| 377 |
| 378 #if BUILDFLAG(ENABLE_HLS_SAMPLE_AES) |
| 379 // 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 // 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 // source stream, this will not be necessary. |
| 384 UnregisterCat(); |
| 385 UnregisterCencPids(); |
| 386 #endif |
338 } | 387 } |
339 | 388 |
340 void Mp2tStreamParser::RegisterPes(int pmt_pid, | 389 void Mp2tStreamParser::RegisterPes(int pmt_pid, |
341 int pes_pid, | 390 int pes_pid, |
342 int stream_type) { | 391 int stream_type, |
| 392 const Descriptors& descriptors) { |
343 // TODO(damienv): check there is no mismatch if the entry already exists. | 393 // TODO(damienv): check there is no mismatch if the entry already exists. |
344 DVLOG(1) << "RegisterPes:" | 394 DVLOG(1) << "RegisterPes:" |
345 << " pes_pid=" << pes_pid | 395 << " pes_pid=" << pes_pid |
346 << " stream_type=" << std::hex << stream_type << std::dec; | 396 << " stream_type=" << std::hex << stream_type << std::dec; |
347 auto it = pids_.find(pes_pid); | 397 auto it = pids_.find(pes_pid); |
348 if (it != pids_.end()) | 398 if (it != pids_.end()) |
349 return; | 399 return; |
350 | 400 |
351 // Create a stream parser corresponding to the stream type. | 401 // Create a stream parser corresponding to the stream type. |
352 bool is_audio = false; | 402 bool is_audio = false; |
(...skipping 19 matching lines...) Expand all Loading... |
372 sbr_in_mimetype_)); | 422 sbr_in_mimetype_)); |
373 is_audio = true; | 423 is_audio = true; |
374 } else if (stream_type == kStreamTypeMpeg1Audio) { | 424 } else if (stream_type == kStreamTypeMpeg1Audio) { |
375 es_parser.reset(new EsParserMpeg1Audio( | 425 es_parser.reset(new EsParserMpeg1Audio( |
376 base::Bind(&Mp2tStreamParser::OnAudioConfigChanged, | 426 base::Bind(&Mp2tStreamParser::OnAudioConfigChanged, |
377 base::Unretained(this), pes_pid), | 427 base::Unretained(this), pes_pid), |
378 base::Bind(&Mp2tStreamParser::OnEmitAudioBuffer, base::Unretained(this), | 428 base::Bind(&Mp2tStreamParser::OnEmitAudioBuffer, base::Unretained(this), |
379 pes_pid), | 429 pes_pid), |
380 media_log_)); | 430 media_log_)); |
381 is_audio = true; | 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 |
382 } else { | 455 } else { |
383 return; | 456 return; |
384 } | 457 } |
385 | 458 |
386 // Create the PES state here. | 459 // Create the PES state here. |
387 DVLOG(1) << "Create a new PES state"; | 460 DVLOG(1) << "Create a new PES state"; |
388 std::unique_ptr<TsSection> pes_section_parser( | 461 std::unique_ptr<TsSection> pes_section_parser( |
389 new TsSectionPes(std::move(es_parser), ×tamp_unroller_)); | 462 new TsSectionPes(std::move(es_parser), ×tamp_unroller_)); |
390 PidState::PidType pid_type = | 463 PidState::PidType pid_type = |
391 is_audio ? PidState::kPidAudioPes : PidState::kPidVideoPes; | 464 is_audio ? PidState::kPidAudioPes : PidState::kPidVideoPes; |
(...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
669 | 742 |
670 // Push an empty queue with the last audio/video config | 743 // Push an empty queue with the last audio/video config |
671 // so that buffers with the same config can be added later on. | 744 // so that buffers with the same config can be added later on. |
672 BufferQueueWithConfig queue_with_config( | 745 BufferQueueWithConfig queue_with_config( |
673 true, last_audio_config, last_video_config); | 746 true, last_audio_config, last_video_config); |
674 buffer_queue_chain_.push_back(queue_with_config); | 747 buffer_queue_chain_.push_back(queue_with_config); |
675 | 748 |
676 return true; | 749 return true; |
677 } | 750 } |
678 | 751 |
| 752 #if BUILDFLAG(ENABLE_HLS_SAMPLE_AES) |
| 753 std::unique_ptr<PidState> Mp2tStreamParser::MakeCatPidState() { |
| 754 std::unique_ptr<TsSection> cat_section_parser(new TsSectionCat( |
| 755 base::Bind(&Mp2tStreamParser::RegisterCencPids, base::Unretained(this)))); |
| 756 std::unique_ptr<PidState> cat_pid_state(new PidState( |
| 757 TsSection::kPidCat, PidState::kPidCat, std::move(cat_section_parser))); |
| 758 cat_pid_state->Enable(); |
| 759 return cat_pid_state; |
| 760 } |
| 761 |
| 762 void Mp2tStreamParser::UnregisterCat() { |
| 763 for (auto& pid : pids_) { |
| 764 if (pid.second->pid_type() == PidState::kPidCat) { |
| 765 pids_.erase(pid.first); |
| 766 break; |
| 767 } |
| 768 } |
| 769 } |
| 770 |
| 771 void Mp2tStreamParser::RegisterCencPids(int ca_pid, int pssh_pid) { |
| 772 std::unique_ptr<TsSectionCetsEcm> ecm_parser(new TsSectionCetsEcm(base::Bind( |
| 773 &Mp2tStreamParser::RegisterDecryptConfig, base::Unretained(this)))); |
| 774 std::unique_ptr<PidState> ecm_pid_state( |
| 775 new PidState(ca_pid, PidState::kPidCetsEcm, std::move(ecm_parser))); |
| 776 ecm_pid_state->Enable(); |
| 777 pids_.insert(std::make_pair(ca_pid, std::move(ecm_pid_state))); |
| 778 |
| 779 std::unique_ptr<TsSectionCetsPssh> pssh_parser( |
| 780 new TsSectionCetsPssh(base::Bind(&Mp2tStreamParser::RegisterPsshBoxes, |
| 781 base::Unretained(this)))); |
| 782 std::unique_ptr<PidState> pssh_pid_state( |
| 783 new PidState(pssh_pid, PidState::kPidCetsPssh, std::move(pssh_parser))); |
| 784 pssh_pid_state->Enable(); |
| 785 pids_.insert(std::make_pair(pssh_pid, std::move(pssh_pid_state))); |
| 786 } |
| 787 |
| 788 void Mp2tStreamParser::UnregisterCencPids() { |
| 789 for (auto& pid : pids_) { |
| 790 if (pid.second->pid_type() == PidState::kPidCetsEcm) { |
| 791 pids_.erase(pid.first); |
| 792 break; |
| 793 } |
| 794 } |
| 795 for (auto& pid : pids_) { |
| 796 if (pid.second->pid_type() == PidState::kPidCetsPssh) { |
| 797 pids_.erase(pid.first); |
| 798 break; |
| 799 } |
| 800 } |
| 801 } |
| 802 |
| 803 void Mp2tStreamParser::RegisterDecryptConfig(const DecryptConfig& config) { |
| 804 decrypt_config_.reset( |
| 805 new DecryptConfig(config.key_id(), config.iv(), config.subsamples())); |
| 806 } |
| 807 |
| 808 void Mp2tStreamParser::RegisterPsshBoxes( |
| 809 const std::vector<uint8_t>& init_data) { |
| 810 encrypted_media_init_data_cb_.Run(EmeInitDataType::CENC, init_data); |
| 811 } |
| 812 |
| 813 #endif |
| 814 |
679 } // namespace mp2t | 815 } // namespace mp2t |
680 } // namespace media | 816 } // namespace media |
OLD | NEW |