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
This commit is contained in:
Rintaro Kuroiwa 2016-06-29 14:24:40 -07:00
parent 50fe17fa9f
commit 1095b73a44
10 changed files with 89 additions and 251 deletions

View File

@ -280,10 +280,21 @@ bool MediaPlaylist::WriteToFile(media::File* file) {
if (type_ == MediaPlaylistType::kVod) {
header += "#EXT-X-PLAYLIST-TYPE:VOD\n";
}
std::string body;
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;

View File

@ -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_));

View File

@ -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;
}

View File

@ -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;

View File

@ -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<uint8_t> 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.
};

View File

@ -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,

View File

@ -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));

View File

@ -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;
}

View File

@ -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_;

View File

@ -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<MockProgramMapTableWriter> mock_pmt_writer(
new MockProgramMapTableWriter());
EXPECT_CALL(*mock_pmt_writer, ClearLeadSegmentPmt(_))
EXPECT_CALL(*mock_pmt_writer, ClearSegmentPmt(_))
.WillOnce(WriteTwoPmts());
scoped_refptr<VideoStreamInfo> 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<MockProgramMapTableWriter> 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<VideoStreamInfo> 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<MockProgramMapTableWriter> mock_pmt_writer(
new MockProgramMapTableWriter());
EXPECT_CALL(*mock_pmt_writer, ClearLeadSegmentPmt(_))
EXPECT_CALL(*mock_pmt_writer, ClearSegmentPmt(_))
.WillOnce(WriteTwoPmts());
scoped_refptr<AudioStreamInfo> 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<MockProgramMapTableWriter> 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<AudioStreamInfo> 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<PesPacket> 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<PesPacket> 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<PesPacket> 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<PesPacket> pes(new PesPacket());