Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(535)

Side by Side Diff: media/formats/mp2t/mp2t_stream_parser.cc

Issue 1517473002: Support HLS MPEG2 TS with SAMPLE-AES encryption. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@encryption_scheme
Patch Set: tidying up prior to review Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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(), &timestamp_unroller_)); 454 new TsSectionPes(es_parser.Pass(), &timestamp_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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698