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

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: rebase Created 4 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 <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
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
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
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), &timestamp_unroller_)); 462 new TsSectionPes(std::move(es_parser), &timestamp_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
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
OLDNEW
« no previous file with comments | « media/formats/mp2t/mp2t_stream_parser.h ('k') | media/formats/mp2t/mp2t_stream_parser_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698