From 1095b73a44002fded24e3d470842cc35acb148a9 Mon Sep 17 00:00:00 2001 From: Rintaro Kuroiwa Date: Wed, 29 Jun 2016 14:24:40 -0700 Subject: [PATCH] Fix TS and Media Playlist with clear lead - Cannot include PMT for following encrypted segments in the clear lead. Some players consider them as conflicting codecs. - Add EXT-X-DISCONTINUITY in front of first EXT-X-KEY to notify that the codec is switching from e.g. "avc1" to "zavc". b/29621230 Change-Id: I45c74813630c229d66245e992eb3a5117326bb14 --- packager/hls/base/media_playlist.cc | 15 +- packager/hls/base/media_playlist_unittest.cc | 34 ++++ .../formats/mp2t/program_map_table_writer.cc | 23 +-- .../formats/mp2t/program_map_table_writer.h | 13 +- .../mp2t/program_map_table_writer_unittest.cc | 176 +----------------- packager/media/formats/mp2t/ts_segmenter.cc | 2 +- .../formats/mp2t/ts_segmenter_unittest.cc | 19 +- packager/media/formats/mp2t/ts_writer.cc | 10 +- packager/media/formats/mp2t/ts_writer.h | 9 +- .../media/formats/mp2t/ts_writer_unittest.cc | 39 ++-- 10 files changed, 89 insertions(+), 251 deletions(-) diff --git a/packager/hls/base/media_playlist.cc b/packager/hls/base/media_playlist.cc index c6b9121db6..7e2d55fc11 100644 --- a/packager/hls/base/media_playlist.cc +++ b/packager/hls/base/media_playlist.cc @@ -280,9 +280,20 @@ bool MediaPlaylist::WriteToFile(media::File* file) { if (type_ == MediaPlaylistType::kVod) { header += "#EXT-X-PLAYLIST-TYPE:VOD\n"; } + std::string body; - for (const auto& entry : entries_) { - body.append(entry->ToString()); + if (!entries_.empty()) { + const bool first_is_ext_key = + entries_.front()->type() == HlsEntry::EntryType::kExtKey; + bool inserted_discontinuity_tag = false; + for (const auto& entry : entries_) { + if (!first_is_ext_key && !inserted_discontinuity_tag && + entry->type() == HlsEntry::EntryType::kExtKey) { + body.append("#EXT-X-DISCONTINUITY\n"); + inserted_discontinuity_tag = true; + } + body.append(entry->ToString()); + } } std::string content = header + body; diff --git a/packager/hls/base/media_playlist_unittest.cc b/packager/hls/base/media_playlist_unittest.cc index 792c5957ca..60efc0f612 100644 --- a/packager/hls/base/media_playlist_unittest.cc +++ b/packager/hls/base/media_playlist_unittest.cc @@ -276,6 +276,40 @@ TEST_F(MediaPlaylistTest, WriteToFileWithEncryptionInfoEmptyIv) { EXPECT_TRUE(media_playlist_.WriteToFile(&file)); } +// Verify that EXT-X-DISCONTINUITY is inserted before EXT-X-KEY. +TEST_F(MediaPlaylistTest, WriteToFileWithClearLead) { + valid_video_media_info_.set_reference_time_scale(90000); + ASSERT_TRUE(media_playlist_.SetMediaInfo(valid_video_media_info_)); + + media_playlist_.AddSegment("file1.ts", 900000, 1000000); + + media_playlist_.AddEncryptionInfo(MediaPlaylist::EncryptionMethod::kSampleAes, + "http://example.com", "0x12345678", + "com.widevine", "1/2/4"); + media_playlist_.AddSegment("file2.ts", 2700000, 5000000); + const std::string kExpectedOutput = + "#EXTM3U\n" + "#EXT-X-VERSION:5\n" + "#EXT-X-TARGETDURATION:30\n" + "#EXT-X-PLAYLIST-TYPE:VOD\n" + "#EXTINF:10.000,\n" + "file1.ts\n" + "#EXT-X-DISCONTINUITY\n" + "#EXT-X-KEY:METHOD=SAMPLE-AES," + "URI=\"http://example.com\",IV=0x12345678,KEYFORMATVERSIONS=\"1/2/4\"," + "KEYFORMAT=\"com.widevine\"\n" + "#EXTINF:30.000,\n" + "file2.ts\n" + "#EXT-X-ENDLIST\n"; + + MockFile file; + EXPECT_CALL(file, + Write(MatchesString(kExpectedOutput), kExpectedOutput.size())) + .WillOnce(ReturnArg<1>()); + EXPECT_TRUE(media_playlist_.WriteToFile(&file)); +} + + TEST_F(MediaPlaylistTest, RemoveOldestSegment) { valid_video_media_info_.set_reference_time_scale(90000); ASSERT_TRUE(media_playlist_.SetMediaInfo(valid_video_media_info_)); diff --git a/packager/media/formats/mp2t/program_map_table_writer.cc b/packager/media/formats/mp2t/program_map_table_writer.cc index b09006b4e0..e91ef28d13 100644 --- a/packager/media/formats/mp2t/program_map_table_writer.cc +++ b/packager/media/formats/mp2t/program_map_table_writer.cc @@ -328,17 +328,6 @@ H264ProgramMapTableWriter::H264ProgramMapTableWriter( H264ProgramMapTableWriter::~H264ProgramMapTableWriter() {} -bool H264ProgramMapTableWriter::ClearLeadSegmentPmt(BufferWriter* writer) { - has_clear_lead_ = true; - WritePmtToBuffer(kPmtH264, arraysize(kPmtH264), continuity_counter_, writer); - WritePmtWithParameters( - kStreamTypeEncryptedH264, kVersion1, kNext, - kPrivateDataIndicatorDescriptorEncryptedH264, - arraysize(kPrivateDataIndicatorDescriptorEncryptedH264), - continuity_counter_, writer); - return true; -} - bool H264ProgramMapTableWriter::EncryptedSegmentPmt(BufferWriter* writer) { WritePmtWithParameters( kStreamTypeEncryptedH264, has_clear_lead_ ? kVersion1 : kVersion0, @@ -349,7 +338,11 @@ bool H264ProgramMapTableWriter::EncryptedSegmentPmt(BufferWriter* writer) { } bool H264ProgramMapTableWriter::ClearSegmentPmt(BufferWriter* writer) { + has_clear_lead_ = true; WritePmtToBuffer(kPmtH264, arraysize(kPmtH264), continuity_counter_, writer); + // Cannot insert PMT for following encrypted segments because + // some players consider encrypted segments as "zavc" codec which is different + // from "avc1" codec, which causes problems. return true; } @@ -366,13 +359,6 @@ AacProgramMapTableWriter::~AacProgramMapTableWriter() {} // TODO(rkuroiwa): Cache the PMT for encrypted segments, it doesn't need to // be recalculated. -bool AacProgramMapTableWriter::ClearLeadSegmentPmt(BufferWriter* writer) { - has_clear_lead_ = true; - WritePmtToBuffer(kPmtAac, arraysize(kPmtAac), continuity_counter_, writer); - // Version 1 and next. - return EncryptedSegmentPmtWithParameters(kVersion1, kNext, writer); -} - bool AacProgramMapTableWriter::EncryptedSegmentPmt(BufferWriter* writer) { // Version 1 and current. return EncryptedSegmentPmtWithParameters( @@ -380,6 +366,7 @@ bool AacProgramMapTableWriter::EncryptedSegmentPmt(BufferWriter* writer) { } bool AacProgramMapTableWriter::ClearSegmentPmt(BufferWriter* writer) { + has_clear_lead_ = true; WritePmtToBuffer(kPmtAac, arraysize(kPmtAac), continuity_counter_, writer); return true; } diff --git a/packager/media/formats/mp2t/program_map_table_writer.h b/packager/media/formats/mp2t/program_map_table_writer.h index a9677d8a1c..fbb920d37b 100644 --- a/packager/media/formats/mp2t/program_map_table_writer.h +++ b/packager/media/formats/mp2t/program_map_table_writer.h @@ -29,17 +29,10 @@ class ProgramMapTableWriter { ProgramMapTableWriter(); virtual ~ProgramMapTableWriter(); - /// Writes TS packets with PMT for clear lead followed by another PMT for - /// encrypted segments. - virtual bool ClearLeadSegmentPmt(BufferWriter* writer) = 0; - - /// Writes TS packets with PMT for encrypted segments, the version number will - /// be 1. + /// Writes TS packets with PMT for encrypted segments. virtual bool EncryptedSegmentPmt(BufferWriter* writer) = 0; - /// This is the same as ClearLeadSegmentPmt() but does not append the extra PMT - /// for encrypted segments that the clear segments. IOW use this if the entire - /// stream is in the clear. + /// Writes TS packets with PMT for clear segments. virtual bool ClearSegmentPmt(BufferWriter* writer) = 0; // The pid can be 13 bits long but 8 bits is sufficient for this library. @@ -57,7 +50,6 @@ class H264ProgramMapTableWriter : public ProgramMapTableWriter { explicit H264ProgramMapTableWriter(ContinuityCounter* continuity_counter); ~H264ProgramMapTableWriter() override; - bool ClearLeadSegmentPmt(BufferWriter* writer) override; bool EncryptedSegmentPmt(BufferWriter* writer) override; bool ClearSegmentPmt(BufferWriter* writer) override; @@ -81,7 +73,6 @@ class AacProgramMapTableWriter : public ProgramMapTableWriter { ContinuityCounter* continuity_counter); ~AacProgramMapTableWriter() override; - bool ClearLeadSegmentPmt(BufferWriter* writer) override; bool EncryptedSegmentPmt(BufferWriter* writer) override; bool ClearSegmentPmt(BufferWriter* writer) override; diff --git a/packager/media/formats/mp2t/program_map_table_writer_unittest.cc b/packager/media/formats/mp2t/program_map_table_writer_unittest.cc index efbf261b36..81c6040f51 100644 --- a/packager/media/formats/mp2t/program_map_table_writer_unittest.cc +++ b/packager/media/formats/mp2t/program_map_table_writer_unittest.cc @@ -88,89 +88,13 @@ TEST_F(ProgramMapTableWriterTest, ClearH264) { kPmtH264, arraysize(kPmtH264), buffer.Buffer())); } -TEST_F(ProgramMapTableWriterTest, ClearLeadH264) { - ContinuityCounter counter; - H264ProgramMapTableWriter writer(&counter); - BufferWriter buffer; - writer.ClearLeadSegmentPmt(&buffer); - - EXPECT_EQ(kTsPacketSize * 2, buffer.Size()); - - // First PMT is for the clear lead segments. - const uint8_t kFirstTsPrefix[] = { - 0x47, // Sync byte. - 0x40, // payload_unit_start_indicator set. - 0x20, // pid. - 0x30, // Adaptation field and payload are both present. counter = 0. - 0xA1, // Adaptation Field length. - 0x00, // All adaptation field flags 0. - }; - const uint8_t kClearPmtH264[] = { - 0x00, // pointer field - 0x02, - 0xB0, // assumes length is <= 256 bytes. - 0x12, // length of the rest of this array. - 0x00, 0x01, // program number. - 0xC1, // version 0, current next indicator 1. - 0x00, // section number - 0x00, // last section number. - 0xE0, // first 3 bits reserved. - 0x50, // PCR PID is the elementary streams PID. - 0xF0, // first 4 bits reserved. - 0x00, // No descriptor at this level. - 0x1B, 0xE0, 0x50, // stream_type -> PID. - 0xF0, 0x00, // Es_info_length is 0. - // CRC32. - 0x43, 0x49, 0x97, 0xbe, - }; - EXPECT_NO_FATAL_FAILURE(ExpectTsPacketEqual( - kFirstTsPrefix, arraysize(kFirstTsPrefix), 160, kClearPmtH264, - arraysize(kClearPmtH264), buffer.Buffer())); - - // Second PMT is for the encrypted segments after clear lead. - const uint8_t kSecondTsPrefix[] = { - 0x47, // Sync byte. - 0x40, // payload_unit_start_indicator set. - 0x20, // pid. - 0x31, // Adaptation field and payload are both present. counter = 1. - 0x9B, // Adaptation Field length. - 0x00, // All adaptation field flags 0. - }; - const uint8_t kPmtForClearLeadEncryptedH264[] = { - 0x00, // pointer field - 0x02, // table id. - 0xB0, // The first 4 bits must be '1011'. - 0x18, // length of the rest of this array. - 0x00, 0x01, // Program number. - 0xC2, // version 1, current next indicator 0. - 0x00, // section number - 0x00, // last section number. - 0xE0, // first 3 bits reserved. - 0x50, // PCR PID is the elementary streams PID. - 0xF0, // first 4 bits reserved. - 0x00, // No descriptor at this level. - 0xDB, 0xE0, 0x50, // stream_type -> PID. - 0xF0, 0x06, // Es_info_length is 6 for private_data_indicator - 0x0F, // private_data_indicator descriptor_tag. - 0x04, // Length of the rest of this descriptor - 0x7A, 0x61, 0x76, 0x63, // 'zavc'. - // CRC32. - 0x2E, 0xAB, 0xF2, 0x54, - }; - - EXPECT_NO_FATAL_FAILURE(ExpectTsPacketEqual( - kSecondTsPrefix, arraysize(kSecondTsPrefix), 154, - kPmtForClearLeadEncryptedH264, arraysize(kPmtForClearLeadEncryptedH264), - buffer.Buffer() + kTsPacketSize)); -} - // Verify that PSI for encrypted segments after clear lead is generated // correctly. TEST_F(ProgramMapTableWriterTest, EncryptedSegmentsAfterClearLeadH264) { ContinuityCounter counter; H264ProgramMapTableWriter writer(&counter); BufferWriter buffer; - writer.ClearLeadSegmentPmt(&buffer); + writer.ClearSegmentPmt(&buffer); buffer.Clear(); writer.EncryptedSegmentPmt(&buffer); EXPECT_EQ(kTsPacketSize, buffer.Size()); @@ -179,7 +103,7 @@ TEST_F(ProgramMapTableWriterTest, EncryptedSegmentsAfterClearLeadH264) { 0x47, // Sync byte. 0x40, // payload_unit_start_indicator set. 0x20, // pid. - 0x32, // Adaptation field and payload are both present. counter = 2. + 0x31, // Adaptation field and payload are both present. counter = 1. 0x9B, // Adaptation Field length. 0x00, // All adaptation field flags 0. }; @@ -295,98 +219,6 @@ TEST_F(ProgramMapTableWriterTest, ClearAac) { 160, kPmtAac, arraysize(kPmtAac), buffer.Buffer())); } -TEST_F(ProgramMapTableWriterTest, ClearLeadAac) { - ContinuityCounter counter; - const std::vector aac_audio_specific_config( - kAacBasicProfileExtraData, - kAacBasicProfileExtraData + arraysize(kAacBasicProfileExtraData)); - AacProgramMapTableWriter writer(aac_audio_specific_config, &counter); - BufferWriter buffer; - writer.ClearLeadSegmentPmt(&buffer); - - EXPECT_EQ(kTsPacketSize * 2, buffer.Size()); - - // First PMT is for the clear lead segments. - const uint8_t kFirstTsPrefix[] = { - 0x47, // Sync byte. - 0x40, // payload_unit_start_indicator set. - 0x20, // pid. - 0x30, // Adaptation field and payload are both present. counter = 0. - 0xA1, // Adaptation Field length. - 0x00, // All adaptation field flags 0. - }; - const uint8_t kClearPmtAac[] = { - 0x00, // pointer field - 0x02, // table id must be 0x02. - 0xB0, // assumes length is <= 256 bytes. - 0x12, // length of the rest of this array. - 0x00, 0x01, // program number. - 0xC1, // version 0, current next indicator 1. - 0x00, // section number - 0x00, // last section number. - 0xE0, // first 3 bits reserved. - 0x50, // PCR PID is the elementary streams PID. - 0xF0, // first 4 bits reserved. - 0x00, // No descriptor at this level. - 0x0F, 0xE0, 0x50, // stream_type -> PID. - 0xF0, 0x00, // Es_info_length is 0. - // CRC32. - 0xE0, 0x6F, 0x1A, 0x31, - }; - - EXPECT_NO_FATAL_FAILURE(ExpectTsPacketEqual( - kFirstTsPrefix, arraysize(kFirstTsPrefix), - 160, kClearPmtAac, arraysize(kClearPmtAac), - buffer.Buffer())); - - // Second PMT is for the encrypted segments after clear lead. - const uint8_t kSecondTsPrefix[] = { - 0x47, // Sync byte. - 0x40, // payload_unit_start_indicator set. - 0x20, // pid. - 0x31, // Adaptation field and payload are both present. counter = 1. - 0x8B, // Adaptation Field length. - 0x00, // All adaptation field flags 0. - }; - const uint8_t kPmtForClearLeadEncryptedAac[] = { - 0x00, // pointer field - 0x02, // table id. - 0xB0, // The first 4 bits must be '1011'. - 0x28, // length of the rest of this array. - 0x00, 0x01, // Program number. - 0xC2, // version 1, current next indicator 0. - 0x00, // section number - 0x00, // last section number. - 0xE0, // first 3 bits reserved. - 0x50, // PCR PID is the elementary streams PID. - 0xF0, // first 4 bits reserved. - 0x00, // No descriptor at this level. - 0xCF, 0xE0, 0x50, // stream_type -> PID. - 0xF0, 0x16, // Es_info_length is 5 for private_data_indicator - 0x0F, // private_data_indicator descriptor_tag. - 0x04, // Length of the rest of this descriptor - 0x61, 0x61, 0x63, 0x64, // 'aacd'. - 0x05, // registration_descriptor tag. - // space for 'zaac' + priming (0x0000) + version (0x01) + - // setup_data_length size + size of kAacBasicProfileExtraData + space for - // 'apad'. Which is 14. - 0x0E, - 0x61, 0x70, 0x61, 0x64, // 'apad'. - 0x7A, 0x61, 0x61, 0x63, // 'zaac'. - 0x00, 0x00, // priming. - 0x01, // version. - 0x02, // setup_data_length == extra data length - 0x12, 0x10, // setup_data == extra data. - // CRC32. - 0x5C, 0x60, 0xB2, 0x55, - }; - - EXPECT_NO_FATAL_FAILURE(ExpectTsPacketEqual( - kSecondTsPrefix, arraysize(kSecondTsPrefix), 138, - kPmtForClearLeadEncryptedAac, arraysize(kPmtForClearLeadEncryptedAac), - buffer.Buffer() + kTsPacketSize)); -} - // Verify that PSI for encrypted segments after clear lead is generated // correctly. TEST_F(ProgramMapTableWriterTest, EncryptedSegmentsAfterClearLeadAac) { @@ -396,7 +228,7 @@ TEST_F(ProgramMapTableWriterTest, EncryptedSegmentsAfterClearLeadAac) { kAacBasicProfileExtraData + arraysize(kAacBasicProfileExtraData)); AacProgramMapTableWriter writer(aac_audio_specific_config, &counter); BufferWriter buffer; - writer.ClearLeadSegmentPmt(&buffer); + writer.ClearSegmentPmt(&buffer); buffer.Clear(); writer.EncryptedSegmentPmt(&buffer); @@ -406,7 +238,7 @@ TEST_F(ProgramMapTableWriterTest, EncryptedSegmentsAfterClearLeadAac) { 0x47, // Sync byte. 0x40, // payload_unit_start_indicator set. 0x20, // pid. - 0x32, // Adaptation field and payload are both present. counter = 2. + 0x31, // Adaptation field and payload are both present. counter = 1. 0x8B, // Adaptation Field length. 0x00, // All adaptation field flags 0. }; diff --git a/packager/media/formats/mp2t/ts_segmenter.cc b/packager/media/formats/mp2t/ts_segmenter.cc index 5c908a1915..1eb80636ec 100644 --- a/packager/media/formats/mp2t/ts_segmenter.cc +++ b/packager/media/formats/mp2t/ts_segmenter.cc @@ -37,7 +37,7 @@ Status TsSegmenter::Initialize(const StreamInfo& stream_info, double clear_lead_in_seconds) { if (muxer_options_.segment_template.empty()) return Status(error::MUXER_FAILURE, "Segment template not specified."); - if (!ts_writer_->Initialize(stream_info, false)) + if (!ts_writer_->Initialize(stream_info)) return Status(error::MUXER_FAILURE, "Failed to initialize TsWriter."); if (!pes_packet_generator_->Initialize(stream_info)) { return Status(error::MUXER_FAILURE, diff --git a/packager/media/formats/mp2t/ts_segmenter_unittest.cc b/packager/media/formats/mp2t/ts_segmenter_unittest.cc index b346505230..77ea659560 100644 --- a/packager/media/formats/mp2t/ts_segmenter_unittest.cc +++ b/packager/media/formats/mp2t/ts_segmenter_unittest.cc @@ -73,8 +73,7 @@ class MockPesPacketGenerator : public PesPacketGenerator { class MockTsWriter : public TsWriter { public: - MOCK_METHOD2(Initialize, - bool(const StreamInfo& stream_info, bool will_be_encrypted)); + MOCK_METHOD1(Initialize, bool(const StreamInfo& stream_info)); MOCK_METHOD1(NewSegment, bool(const std::string& file_name)); MOCK_METHOD0(SignalEncypted, void()); MOCK_METHOD0(FinalizeSegment, bool()); @@ -115,7 +114,7 @@ TEST_F(TsSegmenterTest, Initialize) { options.segment_template = "file$Number$.ts"; TsSegmenter segmenter(options, nullptr); - EXPECT_CALL(*mock_ts_writer_, Initialize(_, _)).WillOnce(Return(true)); + EXPECT_CALL(*mock_ts_writer_, Initialize(_)).WillOnce(Return(true)); EXPECT_CALL(*mock_pes_packet_generator_, Initialize(_)) .WillOnce(Return(true)); @@ -136,7 +135,7 @@ TEST_F(TsSegmenterTest, AddSample) { options.segment_template = "file$Number$.ts"; TsSegmenter segmenter(options, nullptr); - EXPECT_CALL(*mock_ts_writer_, Initialize(_, _)).WillOnce(Return(true)); + EXPECT_CALL(*mock_ts_writer_, Initialize(_)).WillOnce(Return(true)); EXPECT_CALL(*mock_pes_packet_generator_, Initialize(_)) .WillOnce(Return(true)); @@ -195,7 +194,7 @@ TEST_F(TsSegmenterTest, PassedSegmentDuration) { const uint32_t kFirstPts = 1000; - EXPECT_CALL(*mock_ts_writer_, Initialize(_, _)).WillOnce(Return(true)); + EXPECT_CALL(*mock_ts_writer_, Initialize(_)).WillOnce(Return(true)); EXPECT_CALL(*mock_pes_packet_generator_, Initialize(_)) .WillOnce(Return(true)); @@ -290,7 +289,7 @@ TEST_F(TsSegmenterTest, InitializeThenFinalize) { options.segment_template = "file$Number$.ts"; TsSegmenter segmenter(options, nullptr); - EXPECT_CALL(*mock_ts_writer_, Initialize(_, _)).WillOnce(Return(true)); + EXPECT_CALL(*mock_ts_writer_, Initialize(_)).WillOnce(Return(true)); EXPECT_CALL(*mock_pes_packet_generator_, Initialize(_)) .WillOnce(Return(true)); @@ -319,7 +318,7 @@ TEST_F(TsSegmenterTest, Finalize) { options.segment_template = "file$Number$.ts"; TsSegmenter segmenter(options, nullptr); - EXPECT_CALL(*mock_ts_writer_, Initialize(_, _)).WillOnce(Return(true)); + EXPECT_CALL(*mock_ts_writer_, Initialize(_)).WillOnce(Return(true)); EXPECT_CALL(*mock_pes_packet_generator_, Initialize(_)) .WillOnce(Return(true)); @@ -348,7 +347,7 @@ TEST_F(TsSegmenterTest, SegmentOnlyBeforeKeyFrame) { options.segment_template = "file$Number$.ts"; TsSegmenter segmenter(options, nullptr); - EXPECT_CALL(*mock_ts_writer_, Initialize(_, _)).WillOnce(Return(true)); + EXPECT_CALL(*mock_ts_writer_, Initialize(_)).WillOnce(Return(true)); EXPECT_CALL(*mock_pes_packet_generator_, Initialize(_)) .WillOnce(Return(true)); @@ -457,7 +456,7 @@ TEST_F(TsSegmenterTest, WithEncryptionNoClearLead) { EXPECT_CALL(mock_listener, OnEncryptionInfoReady(_, _, _, _, _)); TsSegmenter segmenter(options, &mock_listener); - EXPECT_CALL(*mock_ts_writer_, Initialize(_, _)).WillOnce(Return(true)); + EXPECT_CALL(*mock_ts_writer_, Initialize(_)).WillOnce(Return(true)); EXPECT_CALL(*mock_ts_writer_, SignalEncypted()); EXPECT_CALL(*mock_pes_packet_generator_, Initialize(_)) .WillOnce(Return(true)); @@ -497,7 +496,7 @@ TEST_F(TsSegmenterTest, WithEncryptionWithClearLead) { MockMuxerListener mock_listener; TsSegmenter segmenter(options, &mock_listener); - ON_CALL(*mock_ts_writer_, Initialize(_, _)).WillByDefault(Return(true)); + ON_CALL(*mock_ts_writer_, Initialize(_)).WillByDefault(Return(true)); ON_CALL(*mock_ts_writer_, NewSegment(_)).WillByDefault(Return(true)); ON_CALL(*mock_ts_writer_, FinalizeSegment()).WillByDefault(Return(true)); ON_CALL(*mock_ts_writer_, AddPesPacketMock(_)).WillByDefault(Return(true)); diff --git a/packager/media/formats/mp2t/ts_writer.cc b/packager/media/formats/mp2t/ts_writer.cc index 5f2ba97dde..79f16267a8 100644 --- a/packager/media/formats/mp2t/ts_writer.cc +++ b/packager/media/formats/mp2t/ts_writer.cc @@ -162,8 +162,7 @@ bool WritePesToFile(const PesPacket& pes, TsWriter::TsWriter() {} TsWriter::~TsWriter() {} -bool TsWriter::Initialize(const StreamInfo& stream_info, - bool will_be_encrypted) { +bool TsWriter::Initialize(const StreamInfo& stream_info) { const StreamType stream_type = stream_info.stream_type(); if (stream_type != StreamType::kStreamVideo && stream_type != StreamType::kStreamAudio) { @@ -194,7 +193,6 @@ bool TsWriter::Initialize(const StreamInfo& stream_info, audio_stream_info.codec_config(), &pmt_continuity_counter_)); } - will_be_encrypted_ = will_be_encrypted; return true; } @@ -211,11 +209,7 @@ bool TsWriter::NewSegment(const std::string& file_name) { BufferWriter psi; WritePatToBuffer(kPat, arraysize(kPat), &pat_continuity_counter_, &psi); - if (will_be_encrypted_ && !encrypted_) { - if (!pmt_writer_->ClearLeadSegmentPmt(&psi)) { - return false; - } - } else if (encrypted_) { + if (encrypted_) { if (!pmt_writer_->EncryptedSegmentPmt(&psi)) { return false; } diff --git a/packager/media/formats/mp2t/ts_writer.h b/packager/media/formats/mp2t/ts_writer.h index 07197ee8ab..8811507c16 100644 --- a/packager/media/formats/mp2t/ts_writer.h +++ b/packager/media/formats/mp2t/ts_writer.h @@ -32,12 +32,8 @@ class TsWriter { /// This must be called before calling other methods. /// @param stream_info is the information about this stream. - /// @param will_be_encrypted must be true if some segment would be encrypted. - /// It is ok if the entire stream is not encrypted but have this true - /// e.g. if the clear lead is very long. /// @return true on success, false otherwise. - virtual bool Initialize(const StreamInfo& stream_info, - bool will_be_encrypted); + virtual bool Initialize(const StreamInfo& stream_info); /// This will fail if the current segment is not finalized. /// @param file_name is the output file name. @@ -46,7 +42,6 @@ class TsWriter { virtual bool NewSegment(const std::string& file_name); /// Signals the writer that the rest of the segments are encrypted. - /// |will_be_encrypted| passed to Initialize() should be true. virtual void SignalEncypted(); /// Flush all the pending PesPackets that have not been written to file and @@ -67,8 +62,6 @@ class TsWriter { private: // True if further segments generated by this instance should be encrypted. bool encrypted_ = false; - // The stream will be encrypted some time later. - bool will_be_encrypted_ = false; ContinuityCounter pmt_continuity_counter_; ContinuityCounter pat_continuity_counter_; diff --git a/packager/media/formats/mp2t/ts_writer_unittest.cc b/packager/media/formats/mp2t/ts_writer_unittest.cc index 123956c04d..cc547f6e43 100644 --- a/packager/media/formats/mp2t/ts_writer_unittest.cc +++ b/packager/media/formats/mp2t/ts_writer_unittest.cc @@ -56,14 +56,11 @@ const uint8_t kExtraData[] = {0x01, 0x02}; const uint8_t kAacBasicProfileExtraData[] = {0x12, 0x10}; -const bool kWillBeEncrypted = true; - class MockProgramMapTableWriter : public ProgramMapTableWriter { public: MockProgramMapTableWriter() {} ~MockProgramMapTableWriter() override {} - MOCK_METHOD1(ClearLeadSegmentPmt, bool(BufferWriter* writer)); MOCK_METHOD1(EncryptedSegmentPmt, bool(BufferWriter* writer)); MOCK_METHOD1(ClearSegmentPmt, bool(BufferWriter* writer)); }; @@ -163,7 +160,7 @@ TEST_F(TsWriterTest, InitializeVideoH264) { kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage, kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted)); - EXPECT_TRUE(ts_writer_.Initialize(*stream_info, !kWillBeEncrypted)); + EXPECT_TRUE(ts_writer_.Initialize(*stream_info)); } TEST_F(TsWriterTest, InitializeVideoNonH264) { @@ -171,7 +168,7 @@ TEST_F(TsWriterTest, InitializeVideoNonH264) { kTrackId, kTimeScale, kDuration, VideoCodec::kCodecVP9, kCodecString, kLanguage, kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted)); - EXPECT_FALSE(ts_writer_.Initialize(*stream_info, !kWillBeEncrypted)); + EXPECT_FALSE(ts_writer_.Initialize(*stream_info)); } TEST_F(TsWriterTest, InitializeAudioAac) { @@ -180,7 +177,7 @@ TEST_F(TsWriterTest, InitializeAudioAac) { kSampleBits, kNumChannels, kSamplingFrequency, kSeekPreroll, kCodecDelay, kMaxBitrate, kAverageBitrate, kExtraData, arraysize(kExtraData), kIsEncrypted)); - EXPECT_TRUE(ts_writer_.Initialize(*stream_info, !kWillBeEncrypted)); + EXPECT_TRUE(ts_writer_.Initialize(*stream_info)); } TEST_F(TsWriterTest, InitializeAudioNonAac) { @@ -189,7 +186,7 @@ TEST_F(TsWriterTest, InitializeAudioNonAac) { kLanguage, kSampleBits, kNumChannels, kSamplingFrequency, kSeekPreroll, kCodecDelay, kMaxBitrate, kAverageBitrate, kExtraData, arraysize(kExtraData), kIsEncrypted)); - EXPECT_FALSE(ts_writer_.Initialize(*stream_info, !kWillBeEncrypted)); + EXPECT_FALSE(ts_writer_.Initialize(*stream_info)); } // Verify that PAT and PMT are correct for clear segment. @@ -204,7 +201,7 @@ TEST_F(TsWriterTest, ClearH264Psi) { kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage, kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted)); - EXPECT_TRUE(ts_writer_.Initialize(*stream_info, !kWillBeEncrypted)); + EXPECT_TRUE(ts_writer_.Initialize(*stream_info)); ts_writer_.SetProgramMapTableWriterForTesting(mock_pmt_writer.Pass()); EXPECT_TRUE(ts_writer_.NewSegment(test_file_name_)); @@ -259,7 +256,7 @@ TEST_F(TsWriterTest, ClearAacPmt) { kSampleBits, kNumChannels, kSamplingFrequency, kSeekPreroll, kCodecDelay, kMaxBitrate, kAverageBitrate, kAacBasicProfileExtraData, arraysize(kAacBasicProfileExtraData), kIsEncrypted)); - EXPECT_TRUE(ts_writer_.Initialize(*stream_info, !kWillBeEncrypted)); + EXPECT_TRUE(ts_writer_.Initialize(*stream_info)); ts_writer_.SetProgramMapTableWriterForTesting(mock_pmt_writer.Pass()); EXPECT_TRUE(ts_writer_.NewSegment(test_file_name_)); @@ -279,14 +276,14 @@ TEST_F(TsWriterTest, ClearAacPmt) { TEST_F(TsWriterTest, ClearLeadH264Pmt) { scoped_ptr mock_pmt_writer( new MockProgramMapTableWriter()); - EXPECT_CALL(*mock_pmt_writer, ClearLeadSegmentPmt(_)) + EXPECT_CALL(*mock_pmt_writer, ClearSegmentPmt(_)) .WillOnce(WriteTwoPmts()); scoped_refptr stream_info(new VideoStreamInfo( kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage, kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted)); - EXPECT_TRUE(ts_writer_.Initialize(*stream_info, kWillBeEncrypted)); + EXPECT_TRUE(ts_writer_.Initialize(*stream_info)); ts_writer_.SetProgramMapTableWriterForTesting(mock_pmt_writer.Pass()); EXPECT_TRUE(ts_writer_.NewSegment(test_file_name_)); @@ -308,14 +305,14 @@ TEST_F(TsWriterTest, EncryptedSegmentsH264Pmt) { scoped_ptr mock_pmt_writer( new MockProgramMapTableWriter()); InSequence s; - EXPECT_CALL(*mock_pmt_writer, ClearLeadSegmentPmt(_)).WillOnce(Return(true)); + EXPECT_CALL(*mock_pmt_writer, ClearSegmentPmt(_)).WillOnce(Return(true)); EXPECT_CALL(*mock_pmt_writer, EncryptedSegmentPmt(_)).WillOnce(WriteOnePmt()); scoped_refptr stream_info(new VideoStreamInfo( kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage, kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted)); - EXPECT_TRUE(ts_writer_.Initialize(*stream_info, kWillBeEncrypted)); + EXPECT_TRUE(ts_writer_.Initialize(*stream_info)); ts_writer_.SetProgramMapTableWriterForTesting(mock_pmt_writer.Pass()); EXPECT_TRUE(ts_writer_.NewSegment(test_file_name_)); @@ -339,7 +336,7 @@ TEST_F(TsWriterTest, EncryptedSegmentsH264Pmt) { TEST_F(TsWriterTest, ClearLeadAacPmt) { scoped_ptr mock_pmt_writer( new MockProgramMapTableWriter()); - EXPECT_CALL(*mock_pmt_writer, ClearLeadSegmentPmt(_)) + EXPECT_CALL(*mock_pmt_writer, ClearSegmentPmt(_)) .WillOnce(WriteTwoPmts()); scoped_refptr stream_info(new AudioStreamInfo( @@ -347,7 +344,7 @@ TEST_F(TsWriterTest, ClearLeadAacPmt) { kSampleBits, kNumChannels, kSamplingFrequency, kSeekPreroll, kCodecDelay, kMaxBitrate, kAverageBitrate, kAacBasicProfileExtraData, arraysize(kAacBasicProfileExtraData), kIsEncrypted)); - EXPECT_TRUE(ts_writer_.Initialize(*stream_info, kWillBeEncrypted)); + EXPECT_TRUE(ts_writer_.Initialize(*stream_info)); ts_writer_.SetProgramMapTableWriterForTesting(mock_pmt_writer.Pass()); EXPECT_TRUE(ts_writer_.NewSegment(test_file_name_)); @@ -369,7 +366,7 @@ TEST_F(TsWriterTest, EncryptedSegmentsAacPmt) { scoped_ptr mock_pmt_writer( new MockProgramMapTableWriter()); InSequence s; - EXPECT_CALL(*mock_pmt_writer, ClearLeadSegmentPmt(_)).WillOnce(Return(true)); + EXPECT_CALL(*mock_pmt_writer, ClearSegmentPmt(_)).WillOnce(Return(true)); EXPECT_CALL(*mock_pmt_writer, EncryptedSegmentPmt(_)).WillOnce(WriteOnePmt()); scoped_refptr stream_info(new AudioStreamInfo( @@ -377,7 +374,7 @@ TEST_F(TsWriterTest, EncryptedSegmentsAacPmt) { kSampleBits, kNumChannels, kSamplingFrequency, kSeekPreroll, kCodecDelay, kMaxBitrate, kAverageBitrate, kAacBasicProfileExtraData, arraysize(kAacBasicProfileExtraData), kIsEncrypted)); - EXPECT_TRUE(ts_writer_.Initialize(*stream_info, kWillBeEncrypted)); + EXPECT_TRUE(ts_writer_.Initialize(*stream_info)); ts_writer_.SetProgramMapTableWriterForTesting(mock_pmt_writer.Pass()); EXPECT_TRUE(ts_writer_.NewSegment(test_file_name_)); @@ -403,7 +400,7 @@ TEST_F(TsWriterTest, AddPesPacket) { kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage, kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted)); - EXPECT_TRUE(ts_writer_.Initialize(*stream_info, !kWillBeEncrypted)); + EXPECT_TRUE(ts_writer_.Initialize(*stream_info)); EXPECT_TRUE(ts_writer_.NewSegment(test_file_name_)); scoped_ptr pes(new PesPacket()); @@ -468,7 +465,7 @@ TEST_F(TsWriterTest, BigPesPacket) { kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage, kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted)); - EXPECT_TRUE(ts_writer_.Initialize(*stream_info, !kWillBeEncrypted)); + EXPECT_TRUE(ts_writer_.Initialize(*stream_info)); EXPECT_TRUE(ts_writer_.NewSegment(test_file_name_)); scoped_ptr pes(new PesPacket()); @@ -504,7 +501,7 @@ TEST_F(TsWriterTest, PesPtsZeroNoDts) { kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage, kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted)); - EXPECT_TRUE(ts_writer_.Initialize(*stream_info, !kWillBeEncrypted)); + EXPECT_TRUE(ts_writer_.Initialize(*stream_info)); EXPECT_TRUE(ts_writer_.NewSegment(test_file_name_)); scoped_ptr pes(new PesPacket()); @@ -564,7 +561,7 @@ TEST_F(TsWriterTest, TsPacketPayload183Bytes) { kTrackId, kTimeScale, kDuration, kH264VideoCodec, kCodecString, kLanguage, kWidth, kHeight, kPixelWidth, kPixelHeight, kTrickPlayRate, kNaluLengthSize, kExtraData, arraysize(kExtraData), kIsEncrypted)); - EXPECT_TRUE(ts_writer_.Initialize(*stream_info, !kWillBeEncrypted)); + EXPECT_TRUE(ts_writer_.Initialize(*stream_info)); EXPECT_TRUE(ts_writer_.NewSegment(test_file_name_)); scoped_ptr pes(new PesPacket());