Allow encrypted TS without clear lead
Change-Id: Icc4268af94c11b004f020cfb4dd9f5f16a9169af
This commit is contained in:
parent
cb3b277575
commit
d06a9cd17c
|
@ -22,6 +22,7 @@ namespace mp2t {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// Values for version. Only 0 and 1 are necessary for the implementation.
|
// Values for version. Only 0 and 1 are necessary for the implementation.
|
||||||
|
const int kVersion0 = 0;
|
||||||
const int kVersion1 = 1;
|
const int kVersion1 = 1;
|
||||||
|
|
||||||
// Values for current_next_indicator.
|
// Values for current_next_indicator.
|
||||||
|
@ -328,6 +329,7 @@ H264ProgramMapTableWriter::H264ProgramMapTableWriter(
|
||||||
H264ProgramMapTableWriter::~H264ProgramMapTableWriter() {}
|
H264ProgramMapTableWriter::~H264ProgramMapTableWriter() {}
|
||||||
|
|
||||||
bool H264ProgramMapTableWriter::ClearLeadSegmentPmt(BufferWriter* writer) {
|
bool H264ProgramMapTableWriter::ClearLeadSegmentPmt(BufferWriter* writer) {
|
||||||
|
has_clear_lead_ = true;
|
||||||
WritePmtToBuffer(kPmtH264, arraysize(kPmtH264), continuity_counter_, writer);
|
WritePmtToBuffer(kPmtH264, arraysize(kPmtH264), continuity_counter_, writer);
|
||||||
WritePmtWithParameters(
|
WritePmtWithParameters(
|
||||||
kStreamTypeEncryptedH264, kVersion1, kNext,
|
kStreamTypeEncryptedH264, kVersion1, kNext,
|
||||||
|
@ -339,8 +341,8 @@ bool H264ProgramMapTableWriter::ClearLeadSegmentPmt(BufferWriter* writer) {
|
||||||
|
|
||||||
bool H264ProgramMapTableWriter::EncryptedSegmentPmt(BufferWriter* writer) {
|
bool H264ProgramMapTableWriter::EncryptedSegmentPmt(BufferWriter* writer) {
|
||||||
WritePmtWithParameters(
|
WritePmtWithParameters(
|
||||||
kStreamTypeEncryptedH264, kVersion1, kCurrent,
|
kStreamTypeEncryptedH264, has_clear_lead_ ? kVersion1 : kVersion0,
|
||||||
kPrivateDataIndicatorDescriptorEncryptedH264,
|
kCurrent, kPrivateDataIndicatorDescriptorEncryptedH264,
|
||||||
arraysize(kPrivateDataIndicatorDescriptorEncryptedH264),
|
arraysize(kPrivateDataIndicatorDescriptorEncryptedH264),
|
||||||
continuity_counter_, writer);
|
continuity_counter_, writer);
|
||||||
return true;
|
return true;
|
||||||
|
@ -365,6 +367,7 @@ AacProgramMapTableWriter::~AacProgramMapTableWriter() {}
|
||||||
// TODO(rkuroiwa): Cache the PMT for encrypted segments, it doesn't need to
|
// TODO(rkuroiwa): Cache the PMT for encrypted segments, it doesn't need to
|
||||||
// be recalculated.
|
// be recalculated.
|
||||||
bool AacProgramMapTableWriter::ClearLeadSegmentPmt(BufferWriter* writer) {
|
bool AacProgramMapTableWriter::ClearLeadSegmentPmt(BufferWriter* writer) {
|
||||||
|
has_clear_lead_ = true;
|
||||||
WritePmtToBuffer(kPmtAac, arraysize(kPmtAac), continuity_counter_, writer);
|
WritePmtToBuffer(kPmtAac, arraysize(kPmtAac), continuity_counter_, writer);
|
||||||
// Version 1 and next.
|
// Version 1 and next.
|
||||||
return EncryptedSegmentPmtWithParameters(kVersion1, kNext, writer);
|
return EncryptedSegmentPmtWithParameters(kVersion1, kNext, writer);
|
||||||
|
@ -372,7 +375,8 @@ bool AacProgramMapTableWriter::ClearLeadSegmentPmt(BufferWriter* writer) {
|
||||||
|
|
||||||
bool AacProgramMapTableWriter::EncryptedSegmentPmt(BufferWriter* writer) {
|
bool AacProgramMapTableWriter::EncryptedSegmentPmt(BufferWriter* writer) {
|
||||||
// Version 1 and current.
|
// Version 1 and current.
|
||||||
return EncryptedSegmentPmtWithParameters(kVersion1, kCurrent, writer);
|
return EncryptedSegmentPmtWithParameters(
|
||||||
|
has_clear_lead_ ? kVersion1 : kVersion0, kCurrent, writer);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AacProgramMapTableWriter::ClearSegmentPmt(BufferWriter* writer) {
|
bool AacProgramMapTableWriter::ClearSegmentPmt(BufferWriter* writer) {
|
||||||
|
|
|
@ -63,6 +63,9 @@ class H264ProgramMapTableWriter : public ProgramMapTableWriter {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ContinuityCounter* const continuity_counter_;
|
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);
|
DISALLOW_COPY_AND_ASSIGN(H264ProgramMapTableWriter);
|
||||||
};
|
};
|
||||||
|
@ -89,6 +92,9 @@ class AacProgramMapTableWriter : public ProgramMapTableWriter {
|
||||||
|
|
||||||
const std::vector<uint8_t> aac_audio_specific_config_;
|
const std::vector<uint8_t> aac_audio_specific_config_;
|
||||||
ContinuityCounter* const continuity_counter_;
|
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);
|
DISALLOW_COPY_AND_ASSIGN(AacProgramMapTableWriter);
|
||||||
};
|
};
|
||||||
|
|
|
@ -40,8 +40,11 @@ class ProgramMapTableWriterTest : public ::testing::Test {
|
||||||
|
|
||||||
std::vector<uint8_t> actual_suffix(actual + prefix_size + padding_length,
|
std::vector<uint8_t> actual_suffix(actual + prefix_size + padding_length,
|
||||||
actual + kTsPacketSize);
|
actual + kTsPacketSize);
|
||||||
EXPECT_EQ(std::vector<uint8_t>(suffix, suffix + suffix_size),
|
ASSERT_EQ(suffix_size, actual_suffix.size());
|
||||||
actual_suffix);
|
|
||||||
|
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));
|
buffer.Buffer() + kTsPacketSize));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Verify that PSI for encrypted segments after clear lead is generated
|
||||||
TEST_F(ProgramMapTableWriterTest, EncryptedSegmentsH264Pmt) {
|
// correctly.
|
||||||
|
TEST_F(ProgramMapTableWriterTest, EncryptedSegmentsAfterClearLeadH264) {
|
||||||
ContinuityCounter counter;
|
ContinuityCounter counter;
|
||||||
H264ProgramMapTableWriter writer(&counter);
|
H264ProgramMapTableWriter writer(&counter);
|
||||||
BufferWriter buffer;
|
BufferWriter buffer;
|
||||||
|
writer.ClearLeadSegmentPmt(&buffer);
|
||||||
|
buffer.Clear();
|
||||||
writer.EncryptedSegmentPmt(&buffer);
|
writer.EncryptedSegmentPmt(&buffer);
|
||||||
|
|
||||||
EXPECT_EQ(kTsPacketSize, buffer.Size());
|
EXPECT_EQ(kTsPacketSize, buffer.Size());
|
||||||
|
|
||||||
const uint8_t kPmtEncryptedH264Prefix[] = {
|
const uint8_t kPmtEncryptedH264Prefix[] = {
|
||||||
0x47, // Sync byte.
|
0x47, // Sync byte.
|
||||||
0x40, // payload_unit_start_indicator set.
|
0x40, // payload_unit_start_indicator set.
|
||||||
0x20, // pid.
|
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.
|
0x9B, // Adaptation Field length.
|
||||||
0x00, // All adaptation field flags 0.
|
0x00, // All adaptation field flags 0.
|
||||||
};
|
};
|
||||||
|
@ -205,6 +210,50 @@ TEST_F(ProgramMapTableWriterTest, EncryptedSegmentsH264Pmt) {
|
||||||
kPmtEncryptedH264, arraysize(kPmtEncryptedH264), buffer.Buffer()));
|
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) {
|
TEST_F(ProgramMapTableWriterTest, ClearAac) {
|
||||||
ContinuityCounter counter;
|
ContinuityCounter counter;
|
||||||
const std::vector<uint8_t> aac_audio_specific_config(
|
const std::vector<uint8_t> aac_audio_specific_config(
|
||||||
|
@ -338,23 +387,26 @@ TEST_F(ProgramMapTableWriterTest, ClearLeadAac) {
|
||||||
buffer.Buffer() + kTsPacketSize));
|
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;
|
ContinuityCounter counter;
|
||||||
const std::vector<uint8_t> aac_audio_specific_config(
|
const std::vector<uint8_t> aac_audio_specific_config(
|
||||||
kAacBasicProfileExtraData,
|
kAacBasicProfileExtraData,
|
||||||
kAacBasicProfileExtraData + arraysize(kAacBasicProfileExtraData));
|
kAacBasicProfileExtraData + arraysize(kAacBasicProfileExtraData));
|
||||||
AacProgramMapTableWriter writer(aac_audio_specific_config, &counter);
|
AacProgramMapTableWriter writer(aac_audio_specific_config, &counter);
|
||||||
BufferWriter buffer;
|
BufferWriter buffer;
|
||||||
writer.EncryptedSegmentPmt(&buffer);
|
writer.ClearLeadSegmentPmt(&buffer);
|
||||||
|
|
||||||
|
buffer.Clear();
|
||||||
|
writer.EncryptedSegmentPmt(&buffer);
|
||||||
EXPECT_EQ(kTsPacketSize, buffer.Size());
|
EXPECT_EQ(kTsPacketSize, buffer.Size());
|
||||||
|
|
||||||
// Second PMT is for the encrypted segments after clear lead.
|
|
||||||
const uint8_t kPmtEncryptedAacPrefix[] = {
|
const uint8_t kPmtEncryptedAacPrefix[] = {
|
||||||
0x47, // Sync byte.
|
0x47, // Sync byte.
|
||||||
0x40, // payload_unit_start_indicator set.
|
0x40, // payload_unit_start_indicator set.
|
||||||
0x20, // pid.
|
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.
|
0x8B, // Adaptation Field length.
|
||||||
0x00, // All adaptation field flags 0.
|
0x00, // All adaptation field flags 0.
|
||||||
};
|
};
|
||||||
|
@ -397,6 +449,66 @@ TEST_F(ProgramMapTableWriterTest, EncryptedSegmentsAacPmt) {
|
||||||
buffer.Buffer()));
|
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 mp2t
|
||||||
} // namespace media
|
} // namespace media
|
||||||
} // namespace shaka
|
} // namespace shaka
|
||||||
|
|
Loading…
Reference in New Issue