Allow encrypted TS without clear lead

Change-Id: Icc4268af94c11b004f020cfb4dd9f5f16a9169af
This commit is contained in:
Rintaro Kuroiwa 2016-06-07 10:58:41 -07:00
parent cb3b277575
commit d06a9cd17c
3 changed files with 135 additions and 13 deletions

View File

@ -22,6 +22,7 @@ namespace mp2t {
namespace {
// Values for version. Only 0 and 1 are necessary for the implementation.
const int kVersion0 = 0;
const int kVersion1 = 1;
// Values for current_next_indicator.
@ -328,6 +329,7 @@ H264ProgramMapTableWriter::H264ProgramMapTableWriter(
H264ProgramMapTableWriter::~H264ProgramMapTableWriter() {}
bool H264ProgramMapTableWriter::ClearLeadSegmentPmt(BufferWriter* writer) {
has_clear_lead_ = true;
WritePmtToBuffer(kPmtH264, arraysize(kPmtH264), continuity_counter_, writer);
WritePmtWithParameters(
kStreamTypeEncryptedH264, kVersion1, kNext,
@ -339,8 +341,8 @@ bool H264ProgramMapTableWriter::ClearLeadSegmentPmt(BufferWriter* writer) {
bool H264ProgramMapTableWriter::EncryptedSegmentPmt(BufferWriter* writer) {
WritePmtWithParameters(
kStreamTypeEncryptedH264, kVersion1, kCurrent,
kPrivateDataIndicatorDescriptorEncryptedH264,
kStreamTypeEncryptedH264, has_clear_lead_ ? kVersion1 : kVersion0,
kCurrent, kPrivateDataIndicatorDescriptorEncryptedH264,
arraysize(kPrivateDataIndicatorDescriptorEncryptedH264),
continuity_counter_, writer);
return true;
@ -365,6 +367,7 @@ 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);
@ -372,7 +375,8 @@ bool AacProgramMapTableWriter::ClearLeadSegmentPmt(BufferWriter* writer) {
bool AacProgramMapTableWriter::EncryptedSegmentPmt(BufferWriter* writer) {
// Version 1 and current.
return EncryptedSegmentPmtWithParameters(kVersion1, kCurrent, writer);
return EncryptedSegmentPmtWithParameters(
has_clear_lead_ ? kVersion1 : kVersion0, kCurrent, writer);
}
bool AacProgramMapTableWriter::ClearSegmentPmt(BufferWriter* writer) {

View File

@ -63,6 +63,9 @@ class H264ProgramMapTableWriter : public ProgramMapTableWriter {
private:
ContinuityCounter* const continuity_counter_;
// Set to true if ClearLeadSegmentPmt() has been called. This determines the
// version number set in EncryptedSegmentPmt().
bool has_clear_lead_ = false;
DISALLOW_COPY_AND_ASSIGN(H264ProgramMapTableWriter);
};
@ -89,6 +92,9 @@ class AacProgramMapTableWriter : public ProgramMapTableWriter {
const std::vector<uint8_t> aac_audio_specific_config_;
ContinuityCounter* const continuity_counter_;
// Set to true if ClearLeadSegmentPmt() has been called. This determines the
// version number set in EncryptedSegmentPmt().
bool has_clear_lead_ = false;
DISALLOW_COPY_AND_ASSIGN(AacProgramMapTableWriter);
};

View File

@ -40,8 +40,11 @@ class ProgramMapTableWriterTest : public ::testing::Test {
std::vector<uint8_t> actual_suffix(actual + prefix_size + padding_length,
actual + kTsPacketSize);
EXPECT_EQ(std::vector<uint8_t>(suffix, suffix + suffix_size),
actual_suffix);
ASSERT_EQ(suffix_size, actual_suffix.size());
for (size_t i = 0; i < suffix_size; ++i) {
EXPECT_EQ(suffix[i], actual_suffix[i]) << "at index " << i;
}
}
};
@ -161,20 +164,22 @@ TEST_F(ProgramMapTableWriterTest, ClearLeadH264) {
buffer.Buffer() + kTsPacketSize));
}
TEST_F(ProgramMapTableWriterTest, EncryptedSegmentsH264Pmt) {
// 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);
buffer.Clear();
writer.EncryptedSegmentPmt(&buffer);
EXPECT_EQ(kTsPacketSize, buffer.Size());
const uint8_t kPmtEncryptedH264Prefix[] = {
0x47, // Sync byte.
0x40, // payload_unit_start_indicator set.
0x20, // pid.
0x30, // Adaptation field and payload are both present. counter = 0.
0x32, // Adaptation field and payload are both present. counter = 2.
0x9B, // Adaptation Field length.
0x00, // All adaptation field flags 0.
};
@ -205,6 +210,50 @@ TEST_F(ProgramMapTableWriterTest, EncryptedSegmentsH264Pmt) {
kPmtEncryptedH264, arraysize(kPmtEncryptedH264), buffer.Buffer()));
}
// Verify that PMT for encrypted segments can be generated (without clear lead).
TEST_F(ProgramMapTableWriterTest, EncryptedSegmentsH264Pmt) {
ContinuityCounter counter;
H264ProgramMapTableWriter writer(&counter);
BufferWriter buffer;
writer.EncryptedSegmentPmt(&buffer);
EXPECT_EQ(kTsPacketSize, buffer.Size());
const uint8_t kPmtEncryptedH264Prefix[] = {
0x47, // Sync byte.
0x40, // payload_unit_start_indicator set.
0x20, // pid.
0x30, // Adaptation field and payload are both present. counter = 0.
0x9B, // Adaptation Field length.
0x00, // All adaptation field flags 0.
};
const uint8_t kPmtEncryptedH264[] = {
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.
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.
0xDB, 0xE0, 0x50, // stream_type -> PID.
0xF0, 0x06, // Es_info_length is 6 for private_data_indicator
0x0F, // descriptor_tag.
0x04, // Length of the rest of this descriptor
0x7A, 0x61, 0x76, 0x63, // 'zavc'.
// CRC32.
0xA9, 0xC2, 0x95, 0x7C,
};
EXPECT_NO_FATAL_FAILURE(ExpectTsPacketEqual(
kPmtEncryptedH264Prefix, arraysize(kPmtEncryptedH264Prefix), 154,
kPmtEncryptedH264, arraysize(kPmtEncryptedH264), buffer.Buffer()));
}
TEST_F(ProgramMapTableWriterTest, ClearAac) {
ContinuityCounter counter;
const std::vector<uint8_t> aac_audio_specific_config(
@ -338,23 +387,26 @@ TEST_F(ProgramMapTableWriterTest, ClearLeadAac) {
buffer.Buffer() + kTsPacketSize));
}
TEST_F(ProgramMapTableWriterTest, EncryptedSegmentsAacPmt) {
// Verify that PSI for encrypted segments after clear lead is generated
// correctly.
TEST_F(ProgramMapTableWriterTest, EncryptedSegmentsAfterClearLeadAac) {
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.EncryptedSegmentPmt(&buffer);
writer.ClearLeadSegmentPmt(&buffer);
buffer.Clear();
writer.EncryptedSegmentPmt(&buffer);
EXPECT_EQ(kTsPacketSize, buffer.Size());
// Second PMT is for the encrypted segments after clear lead.
const uint8_t kPmtEncryptedAacPrefix[] = {
0x47, // Sync byte.
0x40, // payload_unit_start_indicator set.
0x20, // pid.
0x30, // Adaptation field and payload are both present. counter = 0.
0x32, // Adaptation field and payload are both present. counter = 2.
0x8B, // Adaptation Field length.
0x00, // All adaptation field flags 0.
};
@ -397,6 +449,66 @@ TEST_F(ProgramMapTableWriterTest, EncryptedSegmentsAacPmt) {
buffer.Buffer()));
}
// Verify that PMT for encrypted segments can be generated (without clear lead).
TEST_F(ProgramMapTableWriterTest, EncryptedSegmentsAacPmt) {
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.EncryptedSegmentPmt(&buffer);
EXPECT_EQ(kTsPacketSize, buffer.Size());
// Second PMT is for the encrypted segments after clear lead.
const uint8_t kPmtEncryptedAacPrefix[] = {
0x47, // Sync byte.
0x40, // payload_unit_start_indicator set.
0x20, // pid.
0x30, // Adaptation field and payload are both present. counter = 0.
0x8B, // Adaptation Field length.
0x00, // All adaptation field flags 0.
};
const uint8_t kPmtEncryptedAac[] = {
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.
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.
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.
0xF7, 0xD5, 0x2A, 0x53,
};
EXPECT_NO_FATAL_FAILURE(ExpectTsPacketEqual(
kPmtEncryptedAacPrefix, arraysize(kPmtEncryptedAacPrefix), 138,
kPmtEncryptedAac, arraysize(kPmtEncryptedAac),
buffer.Buffer()));
}
} // namespace mp2t
} // namespace media
} // namespace shaka