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 "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/callback_helpers.h" | 8 #include "base/callback_helpers.h" |
9 #include "base/stl_util.h" | 9 #include "base/stl_util.h" |
10 #include "media/base/stream_parser_buffer.h" | 10 #include "media/base/stream_parser_buffer.h" |
11 #include "media/base/text_track_config.h" | 11 #include "media/base/text_track_config.h" |
12 #include "media/base/timestamp_constants.h" | 12 #include "media/base/timestamp_constants.h" |
13 #include "media/formats/mp2t/es_parser.h" | 13 #include "media/formats/mp2t/es_parser.h" |
14 #include "media/formats/mp2t/es_parser_adts.h" | 14 #include "media/formats/mp2t/es_parser_adts.h" |
15 #include "media/formats/mp2t/es_parser_h264.h" | 15 #include "media/formats/mp2t/es_parser_h264.h" |
16 #include "media/formats/mp2t/es_parser_mpeg1audio.h" | 16 #include "media/formats/mp2t/es_parser_mpeg1audio.h" |
17 #include "media/formats/mp2t/mp2t_common.h" | 17 #include "media/formats/mp2t/mp2t_common.h" |
18 #include "media/formats/mp2t/ts_packet.h" | 18 #include "media/formats/mp2t/ts_packet.h" |
19 #include "media/formats/mp2t/ts_section.h" | 19 #include "media/formats/mp2t/ts_section.h" |
| 20 #ifdef ENABLE_HLS_SAMPLE_AES |
| 21 #include "media/formats/mp2t/ts_section_cat.h" |
| 22 #include "media/formats/mp2t/ts_section_cets_ecm.h" |
| 23 #include "media/formats/mp2t/ts_section_cets_pssh.h" |
| 24 #endif |
20 #include "media/formats/mp2t/ts_section_pat.h" | 25 #include "media/formats/mp2t/ts_section_pat.h" |
21 #include "media/formats/mp2t/ts_section_pes.h" | 26 #include "media/formats/mp2t/ts_section_pes.h" |
22 #include "media/formats/mp2t/ts_section_pmt.h" | 27 #include "media/formats/mp2t/ts_section_pmt.h" |
23 | 28 |
24 namespace media { | 29 namespace media { |
25 namespace mp2t { | 30 namespace mp2t { |
26 | 31 |
| 32 namespace { |
| 33 |
| 34 #ifdef ENABLE_HLS_SAMPLE_AES |
| 35 const int64 kSampleAESPrivateDataIndicatorAVC = 0x7a617663; |
| 36 const int64 kSampleAESPrivateDataIndicatorAAC = 0x61616364; |
| 37 // const int64 kSampleAESPrivateDataIndicatorAC3 = 0x61633364; |
| 38 // const int64 kSampleAESPrivateDataIndicatorEAC3 = 0x65633364; |
| 39 #endif |
| 40 |
| 41 } // namespace |
| 42 |
27 enum StreamType { | 43 enum StreamType { |
28 // ISO-13818.1 / ITU H.222 Table 2.34 "Stream type assignments" | 44 // ISO-13818.1 / ITU H.222 Table 2.34 "Stream type assignments" |
29 kStreamTypeMpeg1Audio = 0x3, | 45 kStreamTypeMpeg1Audio = 0x3, |
30 kStreamTypeAAC = 0xf, | 46 kStreamTypeAAC = 0xf, |
31 kStreamTypeAVC = 0x1b, | 47 kStreamTypeAVC = 0x1b, |
| 48 #ifdef ENABLE_HLS_SAMPLE_AES |
| 49 // kStreamTypeAC3WithSampleAES = 0xc1, |
| 50 // kStreamTypeEAC3WithSampleAES = 0xc2, |
| 51 kStreamTypeAACWithSampleAES = 0xcf, |
| 52 kStreamTypeAVCWithSampleAES = 0xdb, |
| 53 #endif |
32 }; | 54 }; |
33 | 55 |
34 class PidState { | 56 class PidState { |
35 public: | 57 public: |
36 enum PidType { | 58 enum PidType { |
37 kPidPat, | 59 kPidPat, |
38 kPidPmt, | 60 kPidPmt, |
39 kPidAudioPes, | 61 kPidAudioPes, |
40 kPidVideoPes, | 62 kPidVideoPes, |
| 63 #ifdef ENABLE_HLS_SAMPLE_AES |
| 64 kPidCat, |
| 65 kPidCetsEcm, |
| 66 kPidCetsPssh, |
| 67 #endif |
41 }; | 68 }; |
42 | 69 |
43 PidState(int pid, PidType pid_tyoe, | 70 PidState(int pid, PidType pid_tyoe, |
44 scoped_ptr<TsSection> section_parser); | 71 scoped_ptr<TsSection> section_parser); |
45 | 72 |
46 // Extract the content of the TS packet and parse it. | 73 // Extract the content of the TS packet and parse it. |
47 // Return true if successful. | 74 // Return true if successful. |
48 bool PushTsPacket(const TsPacket& ts_packet); | 75 bool PushTsPacket(const TsPacket& ts_packet); |
49 | 76 |
50 // Flush the PID state (possibly emitting some pending frames) | 77 // Flush the PID state (possibly emitting some pending frames) |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
185 encrypted_media_init_data_cb_ = encrypted_media_init_data_cb; | 212 encrypted_media_init_data_cb_ = encrypted_media_init_data_cb; |
186 new_segment_cb_ = new_segment_cb; | 213 new_segment_cb_ = new_segment_cb; |
187 end_of_segment_cb_ = end_of_segment_cb; | 214 end_of_segment_cb_ = end_of_segment_cb; |
188 media_log_ = media_log; | 215 media_log_ = media_log; |
189 } | 216 } |
190 | 217 |
191 void Mp2tStreamParser::Flush() { | 218 void Mp2tStreamParser::Flush() { |
192 DVLOG(1) << "Mp2tStreamParser::Flush"; | 219 DVLOG(1) << "Mp2tStreamParser::Flush"; |
193 | 220 |
194 // Flush the buffers and reset the pids. | 221 // Flush the buffers and reset the pids. |
195 for (std::map<int, PidState*>::iterator it = pids_.begin(); | 222 for (const auto& pid : pids_) { |
196 it != pids_.end(); ++it) { | 223 DVLOG(1) << "Flushing PID: " << pid.first; |
197 DVLOG(1) << "Flushing PID: " << it->first; | 224 PidState* pid_state = pid.second; |
198 PidState* pid_state = it->second; | |
199 pid_state->Flush(); | 225 pid_state->Flush(); |
200 delete pid_state; | 226 delete pid_state; |
201 } | 227 } |
202 pids_.clear(); | 228 pids_.clear(); |
203 | 229 |
204 // Flush is invoked from SourceBuffer.abort/SourceState::ResetParserState, and | 230 // Flush is invoked from SourceBuffer.abort/SourceState::ResetParserState, and |
205 // MSE spec prohibits emitting new configs in ResetParserState algorithm (see | 231 // MSE spec prohibits emitting new configs in ResetParserState algorithm (see |
206 // https://w3c.github.io/media-source/#sourcebuffer-reset-parser-state, | 232 // https://w3c.github.io/media-source/#sourcebuffer-reset-parser-state, |
207 // 3.5.2 Reset Parser State states that new frames might be processed only in | 233 // 3.5.2 Reset Parser State states that new frames might be processed only in |
208 // PARSING_MEDIA_SEGMENT and therefore doesn't allow emitting new configs, | 234 // PARSING_MEDIA_SEGMENT and therefore doesn't allow emitting new configs, |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
266 if (!ts_packet) { | 292 if (!ts_packet) { |
267 DVLOG(1) << "Error: invalid TS packet"; | 293 DVLOG(1) << "Error: invalid TS packet"; |
268 ts_byte_queue_.Pop(1); | 294 ts_byte_queue_.Pop(1); |
269 continue; | 295 continue; |
270 } | 296 } |
271 DVLOG(LOG_LEVEL_TS) | 297 DVLOG(LOG_LEVEL_TS) |
272 << "Processing PID=" << ts_packet->pid() | 298 << "Processing PID=" << ts_packet->pid() |
273 << " start_unit=" << ts_packet->payload_unit_start_indicator(); | 299 << " start_unit=" << ts_packet->payload_unit_start_indicator(); |
274 | 300 |
275 // Parse the section. | 301 // Parse the section. |
276 std::map<int, PidState*>::iterator it = pids_.find(ts_packet->pid()); | 302 auto it = pids_.find(ts_packet->pid()); |
277 if (it == pids_.end() && | 303 if (it == pids_.end() && |
278 ts_packet->pid() == TsSection::kPidPat) { | 304 ts_packet->pid() == TsSection::kPidPat) { |
279 // Create the PAT state here if needed. | 305 // Create the PAT state here if needed. |
280 scoped_ptr<TsSection> pat_section_parser( | 306 scoped_ptr<TsSection> pat_section_parser( |
281 new TsSectionPat( | 307 new TsSectionPat( |
282 base::Bind(&Mp2tStreamParser::RegisterPmt, | 308 base::Bind(&Mp2tStreamParser::RegisterPmt, |
283 base::Unretained(this)))); | 309 base::Unretained(this)))); |
284 scoped_ptr<PidState> pat_pid_state( | 310 scoped_ptr<PidState> pat_pid_state( |
285 new PidState(ts_packet->pid(), PidState::kPidPat, | 311 new PidState(ts_packet->pid(), PidState::kPidPat, |
286 pat_section_parser.Pass())); | 312 pat_section_parser.Pass())); |
287 pat_pid_state->Enable(); | 313 pat_pid_state->Enable(); |
288 it = pids_.insert( | 314 it = |
289 std::pair<int, PidState*>(ts_packet->pid(), | 315 pids_.insert(PidMapElement(ts_packet->pid(), pat_pid_state.release())) |
290 pat_pid_state.release())).first; | 316 .first; |
291 } | 317 } |
| 318 #ifdef ENABLE_HLS_SAMPLE_AES |
| 319 // We allow a CAT to appear as the first packet in the TS. This allows us to |
| 320 // specify encryption metadata for HLS by injecting it as an extra TS packet |
| 321 // at the front of the stream. |
| 322 else if (it == pids_.end() && ts_packet->pid() == TsSection::kPidCat) { |
| 323 it = RegisterCat(); |
| 324 } |
| 325 #endif |
292 | 326 |
293 if (it != pids_.end()) { | 327 if (it != pids_.end()) { |
294 if (!it->second->PushTsPacket(*ts_packet)) | 328 if (!it->second->PushTsPacket(*ts_packet)) |
295 return false; | 329 return false; |
296 } else { | 330 } else { |
297 DVLOG(LOG_LEVEL_TS) << "Ignoring TS packet for pid: " << ts_packet->pid(); | 331 DVLOG(LOG_LEVEL_TS) << "Ignoring TS packet for pid: " << ts_packet->pid(); |
298 } | 332 } |
299 | 333 |
300 // Go to the next packet. | 334 // Go to the next packet. |
301 ts_byte_queue_.Pop(TsPacket::kPacketSize); | 335 ts_byte_queue_.Pop(TsPacket::kPacketSize); |
302 } | 336 } |
303 | 337 |
304 RCHECK(FinishInitializationIfNeeded()); | 338 RCHECK(FinishInitializationIfNeeded()); |
305 | 339 |
306 // Emit the A/V buffers that kept accumulating during TS parsing. | 340 // Emit the A/V buffers that kept accumulating during TS parsing. |
307 return EmitRemainingBuffers(); | 341 return EmitRemainingBuffers(); |
308 } | 342 } |
309 | 343 |
310 void Mp2tStreamParser::RegisterPmt(int program_number, int pmt_pid) { | 344 void Mp2tStreamParser::RegisterPmt(int program_number, int pmt_pid) { |
311 DVLOG(1) << "RegisterPmt:" | 345 DVLOG(1) << "RegisterPmt:" |
312 << " program_number=" << program_number | 346 << " program_number=" << program_number |
313 << " pmt_pid=" << pmt_pid; | 347 << " pmt_pid=" << pmt_pid; |
314 | 348 |
315 // Only one TS program is allowed. Ignore the incoming program map table, | 349 // Only one TS program is allowed. Ignore the incoming program map table, |
316 // if there is already one registered. | 350 // if there is already one registered. |
317 for (std::map<int, PidState*>::iterator it = pids_.begin(); | 351 for (const auto& pid : pids_) { |
318 it != pids_.end(); ++it) { | 352 PidState* pid_state = pid.second; |
319 PidState* pid_state = it->second; | |
320 if (pid_state->pid_type() == PidState::kPidPmt) { | 353 if (pid_state->pid_type() == PidState::kPidPmt) { |
321 DVLOG_IF(1, pmt_pid != it->first) << "More than one program is defined"; | 354 DVLOG_IF(1, pmt_pid != pid.first) << "More than one program is defined"; |
322 return; | 355 return; |
323 } | 356 } |
324 } | 357 } |
325 | 358 |
326 // Create the PMT state here if needed. | 359 // Create the PMT state here if needed. |
327 DVLOG(1) << "Create a new PMT parser"; | 360 DVLOG(1) << "Create a new PMT parser"; |
328 scoped_ptr<TsSection> pmt_section_parser( | 361 scoped_ptr<TsSection> pmt_section_parser( |
329 new TsSectionPmt( | 362 new TsSectionPmt( |
330 base::Bind(&Mp2tStreamParser::RegisterPes, | 363 base::Bind(&Mp2tStreamParser::RegisterPes, |
331 base::Unretained(this), pmt_pid))); | 364 base::Unretained(this), pmt_pid))); |
332 scoped_ptr<PidState> pmt_pid_state( | 365 scoped_ptr<PidState> pmt_pid_state( |
333 new PidState(pmt_pid, PidState::kPidPmt, pmt_section_parser.Pass())); | 366 new PidState(pmt_pid, PidState::kPidPmt, pmt_section_parser.Pass())); |
334 pmt_pid_state->Enable(); | 367 pmt_pid_state->Enable(); |
335 pids_.insert(std::pair<int, PidState*>(pmt_pid, pmt_pid_state.release())); | 368 pids_.insert(std::pair<int, PidState*>(pmt_pid, pmt_pid_state.release())); |
| 369 |
| 370 #ifdef ENABLE_HLS_SAMPLE_AES |
| 371 // Take the opportunity to clean up any PIDs that were involved in importing |
| 372 // encryption metadata for HLS with SampleAES. This prevents the possibility |
| 373 // of interference with actual PIDs that might be declared in the PMT. |
| 374 // TODO(dougsteed): if in the future the appropriate PIDs are embedded in the |
| 375 // source stream, this will not be necessary. |
| 376 UnregisterCat(); |
| 377 UnregisterCencPids(); |
| 378 #endif |
336 } | 379 } |
337 | 380 |
338 void Mp2tStreamParser::RegisterPes(int pmt_pid, | 381 void Mp2tStreamParser::RegisterPes(int pmt_pid, |
339 int pes_pid, | 382 int pes_pid, |
340 int stream_type) { | 383 int stream_type, |
| 384 const Descriptors& descriptors) { |
341 // TODO(damienv): check there is no mismatch if the entry already exists. | 385 // TODO(damienv): check there is no mismatch if the entry already exists. |
342 DVLOG(1) << "RegisterPes:" | 386 DVLOG(1) << "RegisterPes:" |
343 << " pes_pid=" << pes_pid | 387 << " pes_pid=" << pes_pid |
344 << " stream_type=" << std::hex << stream_type << std::dec; | 388 << " stream_type=" << std::hex << stream_type << std::dec; |
345 std::map<int, PidState*>::iterator it = pids_.find(pes_pid); | 389 std::map<int, PidState*>::iterator it = pids_.find(pes_pid); |
346 if (it != pids_.end()) | 390 if (it != pids_.end()) |
347 return; | 391 return; |
348 | 392 |
349 // Create a stream parser corresponding to the stream type. | 393 // Create a stream parser corresponding to the stream type. |
350 bool is_audio = false; | 394 bool is_audio = false; |
(...skipping 19 matching lines...) Expand all Loading... |
370 sbr_in_mimetype_)); | 414 sbr_in_mimetype_)); |
371 is_audio = true; | 415 is_audio = true; |
372 } else if (stream_type == kStreamTypeMpeg1Audio) { | 416 } else if (stream_type == kStreamTypeMpeg1Audio) { |
373 es_parser.reset(new EsParserMpeg1Audio( | 417 es_parser.reset(new EsParserMpeg1Audio( |
374 base::Bind(&Mp2tStreamParser::OnAudioConfigChanged, | 418 base::Bind(&Mp2tStreamParser::OnAudioConfigChanged, |
375 base::Unretained(this), pes_pid), | 419 base::Unretained(this), pes_pid), |
376 base::Bind(&Mp2tStreamParser::OnEmitAudioBuffer, base::Unretained(this), | 420 base::Bind(&Mp2tStreamParser::OnEmitAudioBuffer, base::Unretained(this), |
377 pes_pid), | 421 pes_pid), |
378 media_log_)); | 422 media_log_)); |
379 is_audio = true; | 423 is_audio = true; |
| 424 #ifdef ENABLE_HLS_SAMPLE_AES |
| 425 } else if (stream_type == kStreamTypeAVCWithSampleAES && |
| 426 descriptors.HasPrivateDataIndicator( |
| 427 kSampleAESPrivateDataIndicatorAVC)) { |
| 428 es_parser.reset(new EsParserH264( |
| 429 base::Bind(&Mp2tStreamParser::OnVideoConfigChanged, |
| 430 base::Unretained(this), pes_pid), |
| 431 base::Bind(&Mp2tStreamParser::OnEmitVideoBuffer, base::Unretained(this), |
| 432 pes_pid), |
| 433 base::Bind(&Mp2tStreamParser::GetDecryptConfig, base::Unretained(this)), |
| 434 true)); |
| 435 } else if (stream_type == kStreamTypeAACWithSampleAES && |
| 436 descriptors.HasPrivateDataIndicator( |
| 437 kSampleAESPrivateDataIndicatorAAC)) { |
| 438 es_parser.reset(new EsParserAdts( |
| 439 base::Bind(&Mp2tStreamParser::OnAudioConfigChanged, |
| 440 base::Unretained(this), pes_pid), |
| 441 base::Bind(&Mp2tStreamParser::OnEmitAudioBuffer, base::Unretained(this), |
| 442 pes_pid), |
| 443 base::Bind(&Mp2tStreamParser::GetDecryptConfig, base::Unretained(this)), |
| 444 true, sbr_in_mimetype_)); |
| 445 is_audio = true; |
| 446 #endif |
380 } else { | 447 } else { |
381 return; | 448 return; |
382 } | 449 } |
383 | 450 |
384 // Create the PES state here. | 451 // Create the PES state here. |
385 DVLOG(1) << "Create a new PES state"; | 452 DVLOG(1) << "Create a new PES state"; |
386 scoped_ptr<TsSection> pes_section_parser( | 453 scoped_ptr<TsSection> pes_section_parser( |
387 new TsSectionPes(es_parser.Pass(), ×tamp_unroller_)); | 454 new TsSectionPes(es_parser.Pass(), ×tamp_unroller_)); |
388 PidState::PidType pid_type = | 455 PidState::PidType pid_type = |
389 is_audio ? PidState::kPidAudioPes : PidState::kPidVideoPes; | 456 is_audio ? PidState::kPidAudioPes : PidState::kPidVideoPes; |
(...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
640 | 707 |
641 // Push an empty queue with the last audio/video config | 708 // Push an empty queue with the last audio/video config |
642 // so that buffers with the same config can be added later on. | 709 // so that buffers with the same config can be added later on. |
643 BufferQueueWithConfig queue_with_config( | 710 BufferQueueWithConfig queue_with_config( |
644 true, last_audio_config, last_video_config); | 711 true, last_audio_config, last_video_config); |
645 buffer_queue_chain_.push_back(queue_with_config); | 712 buffer_queue_chain_.push_back(queue_with_config); |
646 | 713 |
647 return true; | 714 return true; |
648 } | 715 } |
649 | 716 |
| 717 #ifdef ENABLE_HLS_SAMPLE_AES |
| 718 std::map<int, PidState*>::iterator Mp2tStreamParser::RegisterCat() { |
| 719 scoped_ptr<TsSection> cat_section_parser(new TsSectionCat( |
| 720 base::Bind(&Mp2tStreamParser::RegisterCencPids, base::Unretained(this)))); |
| 721 scoped_ptr<PidState> cat_pid_state(new PidState( |
| 722 TsSection::kPidCat, PidState::kPidCat, cat_section_parser.Pass())); |
| 723 cat_pid_state->Enable(); |
| 724 return pids_.insert( |
| 725 PidMapElement(TsSection::kPidCat, cat_pid_state.release())) |
| 726 .first; |
| 727 } |
| 728 |
| 729 void Mp2tStreamParser::UnregisterCat() { |
| 730 for (auto& pid : pids_) { |
| 731 if (pid.second->pid_type() == PidState::kPidCat) { |
| 732 delete pid.second; |
| 733 pids_.erase(pid.first); |
| 734 break; |
| 735 } |
| 736 } |
| 737 } |
| 738 |
| 739 void Mp2tStreamParser::RegisterCencPids(int ca_pid, int pssh_pid) { |
| 740 scoped_ptr<TsSectionCetsEcm> ecm_parser(new TsSectionCetsEcm(base::Bind( |
| 741 &Mp2tStreamParser::RegisterDecryptConfig, base::Unretained(this)))); |
| 742 scoped_ptr<PidState> ecm_pid_state( |
| 743 new PidState(ca_pid, PidState::kPidCetsEcm, ecm_parser.Pass())); |
| 744 ecm_pid_state->Enable(); |
| 745 pids_.insert(PidMapElement(ca_pid, ecm_pid_state.release())); |
| 746 |
| 747 scoped_ptr<TsSectionCetsPssh> pssh_parser(new TsSectionCetsPssh(base::Bind( |
| 748 &Mp2tStreamParser::RegisterPsshBoxes, base::Unretained(this)))); |
| 749 scoped_ptr<PidState> pssh_pid_state( |
| 750 new PidState(pssh_pid, PidState::kPidCetsPssh, pssh_parser.Pass())); |
| 751 pssh_pid_state->Enable(); |
| 752 pids_.insert(PidMapElement(pssh_pid, pssh_pid_state.release())); |
| 753 } |
| 754 |
| 755 void Mp2tStreamParser::UnregisterCencPids() { |
| 756 for (auto& pid : pids_) { |
| 757 if (pid.second->pid_type() == PidState::kPidCetsEcm) { |
| 758 delete pid.second; |
| 759 pids_.erase(pid.first); |
| 760 break; |
| 761 } |
| 762 } |
| 763 for (auto& pid : pids_) { |
| 764 if (pid.second->pid_type() == PidState::kPidCetsPssh) { |
| 765 delete pid.second; |
| 766 pids_.erase(pid.first); |
| 767 break; |
| 768 } |
| 769 } |
| 770 } |
| 771 |
| 772 void Mp2tStreamParser::RegisterDecryptConfig(const DecryptConfig& config) { |
| 773 decrypt_config_.reset( |
| 774 new DecryptConfig(config.key_id(), config.iv(), config.subsamples())); |
| 775 } |
| 776 |
| 777 void Mp2tStreamParser::RegisterPsshBoxes(const std::vector<uint8> init_data) { |
| 778 encrypted_media_init_data_cb_.Run(EmeInitDataType::CENC, init_data); |
| 779 } |
| 780 |
| 781 #endif |
| 782 |
650 } // namespace mp2t | 783 } // namespace mp2t |
651 } // namespace media | 784 } // namespace media |
OLD | NEW |