Refactor ProgramMapTableWriter

To make it easier to support more codecs.

Change-Id: Ifcde0f3d7d6f74015d723a0b74401a86c8e65a72
This commit is contained in:
KongQun Yang 2017-10-18 13:25:20 -07:00
parent d66d307fc2
commit b5a8185543
7 changed files with 212 additions and 229 deletions

View File

@ -147,6 +147,7 @@ enum FourCC : uint32_t {
FOURCC_zaac = 0x7A616163,
FOURCC_zach = 0x7A616368,
FOURCC_zacp = 0x7A616370,
FOURCC_zavc = 0x7A617663,
};
const FourCC kAppleSampleAesProtectionScheme = FOURCC_cbca;

View File

@ -12,7 +12,6 @@
#include "packager/media/base/buffer_writer.h"
#include "packager/media/base/fourccs.h"
#include "packager/media/codecs/aac_audio_specific_config.h"
#include "packager/media/formats/mp2t/continuity_counter.h"
#include "packager/media/formats/mp2t/ts_packet_writer_util.h"
namespace shaka {
@ -119,65 +118,6 @@ uint32_t Crc32Mpeg2(const uint8_t* data, size_t data_size) {
return crc;
}
// For all the pointer fields in the PMTs, they are not really part of the PMT
// but it's there so that an extra buffer isn't required to prepend the 0x00
// byte.
// PMT for H264 clear segments.
// Note that this is version 0, so it only works for clear lead or clear stream.
const uint8_t kPmtH264[] = {
0x00, // pointer field
kProgramMapTableId,
0xB0, // assumes length is <= 256 bytes.
0x12, // length of the rest of this array.
0x00, kProgramNumber,
0xC1, // version 0, current next indicator 1.
0x00, // section number
0x00, // last section number.
0xE0, // first 3 bits reserved.
// PCR PID is the elementary streams PID.
ProgramMapTableWriter::kElementaryPid,
0xF0, // first 4 bits reserved.
0x00, // No descriptor at this level.
// stream_type -> PID.
kStreamTypeH264, 0xE0, ProgramMapTableWriter::kElementaryPid,
0xF0, 0x00, // Es_info_length is 0.
// CRC32.
0x43, 0x49, 0x97, 0xBE,
};
// PMT for AAC clear segments.
// Note that this is version 0, so it only works for clear lead or clear stream.
const uint8_t kPmtAac[] = {
0x00, // pointer field
0x02, // table id must be 0x02.
0xB0, // assumes length is <= 256 bytes.
0x12, // length of the rest of this array.
0x00, kProgramNumber,
0xC1, // version 0, current next indicator 1.
0x00, // section number
0x00, // last section number.
0xE0, // first 3 bits reserved.
// PCR PID is the elementary streams PID.
ProgramMapTableWriter::kElementaryPid,
0xF0, // first 4 bits reserved.
0x00, // No descriptor at this level.
// stream_type -> PID.
kStreamTypeAdtsAac, 0xE0, ProgramMapTableWriter::kElementaryPid,
0xF0, 0x00, // Es_info_length is 0.
// CRC32.
0xE0, 0x6F, 0x1A, 0x31,
};
// private_data_indicator for SAMPLE-AES H264. This is the same for all H264
// streams.
const uint8_t kPrivateDataIndicatorDescriptorEncryptedH264[] = {
0x0F, // descriptor_tag.
0x04, // Length of the rest of this descriptor.
// 'zavc'.
0x7A, 0x61, 0x76, 0x63,
};
void WritePmtToBuffer(const uint8_t* pmt,
size_t pmt_size,
ContinuityCounter* continuity_counter,
@ -261,8 +201,7 @@ void WritePmtWithParameters(uint8_t stream_type,
int current_next_indicator,
const uint8_t* descriptors,
size_t descriptors_size,
ContinuityCounter* continuity_counter,
BufferWriter* output) {
BufferWriter* pmt) {
DCHECK(current_next_indicator == kCurrent || current_next_indicator == kNext);
// Body starting from program number.
BufferWriter pmt_body;
@ -291,106 +230,135 @@ void WritePmtWithParameters(uint8_t stream_type,
// 4 reserved bits followed by ES_info_length.
pmt_body.AppendInt(static_cast<uint16_t>(0xF000 | descriptors_size));
pmt_body.AppendArray(descriptors, descriptors_size);
if (descriptors_size > 0) {
DCHECK(descriptors);
pmt_body.AppendArray(descriptors, descriptors_size);
}
// The whole PMT has 3 bytes before the body and 4 more bytes for CRC. This
// also includes pointer field (1 byte) so + 8 in total.
BufferWriter pmt(pmt_body.Size() + 8);
// Pointer field.
pmt.AppendInt(static_cast<uint8_t>(0x00));
// PMT table ID is always 2.
pmt.AppendInt(static_cast<uint8_t>(0x02));
pmt->Clear();
// Pointer field is not really part of the PMT but it's there so that an extra
// buffer isn't required to prepend the 0x00 byte.
const uint8_t kPointerField = 0;
pmt->AppendInt(kPointerField);
pmt->AppendInt(kProgramMapTableId);
// First four bits must be '1011'. +4 for CRC.
pmt.AppendInt(static_cast<uint16_t>(0xB000 | (pmt_body.Size() + 4)));
pmt.AppendBuffer(pmt_body);
pmt->AppendInt(static_cast<uint16_t>(0xB000 | (pmt_body.Size() + 4)));
pmt->AppendBuffer(pmt_body);
// Don't include the pointer field.
const uint32_t crc = Crc32Mpeg2(pmt.Buffer() + 1, pmt.Size() - 1);
pmt.AppendInt(crc);
WritePmtToBuffer(pmt.Buffer(), pmt.Size(), continuity_counter, output);
const uint32_t crc = Crc32Mpeg2(pmt->Buffer() + 1, pmt->Size() - 1);
pmt->AppendInt(crc);
}
} // namespace
ProgramMapTableWriter::ProgramMapTableWriter() {}
ProgramMapTableWriter::~ProgramMapTableWriter() {}
ProgramMapTableWriter::ProgramMapTableWriter(Codec codec) : codec_(codec) {}
H264ProgramMapTableWriter::H264ProgramMapTableWriter(
ContinuityCounter* continuity_counter)
: continuity_counter_(continuity_counter) {
DCHECK(continuity_counter);
}
bool ProgramMapTableWriter::EncryptedSegmentPmt(BufferWriter* writer) {
uint8_t stream_type;
switch (codec_) {
case kCodecH264:
stream_type = kStreamTypeEncryptedH264;
break;
case kCodecAAC:
stream_type = kStreamTypeEncryptedAdtsAac;
break;
default:
LOG(ERROR) << "Codec " << codec_ << " is not supported in TS yet.";
return false;
}
H264ProgramMapTableWriter::~H264ProgramMapTableWriter() {}
if (encrypted_pmt_.Size() == 0) {
BufferWriter descriptors;
if (!WriteDescriptors(&descriptors))
return false;
bool H264ProgramMapTableWriter::EncryptedSegmentPmt(BufferWriter* writer) {
WritePmtWithParameters(
kStreamTypeEncryptedH264, has_clear_lead_ ? kVersion1 : kVersion0,
kCurrent, kPrivateDataIndicatorDescriptorEncryptedH264,
arraysize(kPrivateDataIndicatorDescriptorEncryptedH264),
continuity_counter_, writer);
const bool has_clear_lead = clear_pmt_.Size() > 0;
WritePmtWithParameters(stream_type, has_clear_lead ? kVersion1 : kVersion0,
kCurrent, descriptors.Buffer(), descriptors.Size(),
&encrypted_pmt_);
DCHECK_NE(encrypted_pmt_.Size(), 0u);
}
WritePmtToBuffer(encrypted_pmt_.Buffer(), encrypted_pmt_.Size(),
&continuity_counter_, writer);
return true;
}
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.
bool ProgramMapTableWriter::ClearSegmentPmt(BufferWriter* writer) {
uint8_t stream_type;
switch (codec_) {
case kCodecH264:
stream_type = kStreamTypeH264;
break;
case kCodecAAC:
stream_type = kStreamTypeAdtsAac;
break;
default:
LOG(ERROR) << "Codec " << codec_ << " is not supported in TS yet.";
return false;
}
if (clear_pmt_.Size() == 0) {
WritePmtWithParameters(stream_type, kVersion0, kCurrent, nullptr, 0,
&clear_pmt_);
DCHECK_NE(clear_pmt_.Size(), 0u);
}
WritePmtToBuffer(clear_pmt_.Buffer(), clear_pmt_.Size(), &continuity_counter_,
writer);
return true;
}
AacProgramMapTableWriter::AacProgramMapTableWriter(
const std::vector<uint8_t>& aac_audio_specific_config,
ContinuityCounter* continuity_counter)
: aac_audio_specific_config_(aac_audio_specific_config),
continuity_counter_(continuity_counter) {
DCHECK(!aac_audio_specific_config.empty());
DCHECK(continuity_counter_);
}
VideoProgramMapTableWriter::VideoProgramMapTableWriter(Codec codec)
: ProgramMapTableWriter(codec) {}
AacProgramMapTableWriter::~AacProgramMapTableWriter() {}
// TODO(rkuroiwa): Cache the PMT for encrypted segments, it doesn't need to
// be recalculated.
bool AacProgramMapTableWriter::EncryptedSegmentPmt(BufferWriter* writer) {
// Version 1 and current.
return EncryptedSegmentPmtWithParameters(
has_clear_lead_ ? kVersion1 : kVersion0, kCurrent, writer);
}
bool AacProgramMapTableWriter::ClearSegmentPmt(BufferWriter* writer) {
has_clear_lead_ = true;
WritePmtToBuffer(kPmtAac, arraysize(kPmtAac), continuity_counter_, writer);
bool VideoProgramMapTableWriter::WriteDescriptors(
BufferWriter* descriptors) const {
FourCC fourcc;
switch (codec()) {
case kCodecH264:
fourcc = FOURCC_zavc;
break;
default:
LOG(ERROR) << "Codec " << codec() << " is not supported in TS yet.";
return false;
}
WritePrivateDataIndicatorDescriptor(fourcc, descriptors);
return true;
}
bool AacProgramMapTableWriter::EncryptedSegmentPmtWithParameters(
int version,
int current_next_indicator,
BufferWriter* writer) {
AudioProgramMapTableWriter::AudioProgramMapTableWriter(
Codec codec,
const std::vector<uint8_t>& audio_specific_config)
: ProgramMapTableWriter(codec),
audio_specific_config_(audio_specific_config) {
DCHECK(!audio_specific_config.empty());
}
bool AudioProgramMapTableWriter::WriteDescriptors(
BufferWriter* descriptors) const {
FourCC fourcc;
switch (codec()) {
case kCodecAAC:
fourcc = FOURCC_aacd;
break;
default:
LOG(ERROR) << "Codec " << codec() << " is not supported in TS yet.";
return false;
}
WritePrivateDataIndicatorDescriptor(fourcc, descriptors);
// -12 because there are 12 bytes between 'descriptor_length' in
// registration_descriptor and 'setup_data_length' in audio_setup_information.
if (aac_audio_specific_config_.size() >
if (audio_specific_config_.size() >
std::numeric_limits<uint8_t>::max() - 12U) {
LOG(ERROR) << "AACAudioSpecificConfig of size: "
<< aac_audio_specific_config_.size()
<< audio_specific_config_.size()
<< " will not fit in the descriptor.";
return false;
}
BufferWriter descriptors;
WritePrivateDataIndicatorDescriptor(FOURCC_aacd, &descriptors);
if (!WriteRegistrationDescriptorForEncryptedAudio(
aac_audio_specific_config_.data(), aac_audio_specific_config_.size(),
&descriptors)) {
return false;
}
WritePmtWithParameters(
kStreamTypeEncryptedAdtsAac, version, current_next_indicator,
descriptors.Buffer(), descriptors.Size(), continuity_counter_, writer);
return true;
return WriteRegistrationDescriptorForEncryptedAudio(
audio_specific_config_.data(), audio_specific_config_.size(),
descriptors);
}
} // namespace mp2t

View File

@ -11,7 +11,10 @@
#include <vector>
#include "packager/base/macros.h"
#include "packager/media/base/buffer_writer.h"
// TODO(kqyang): Move codec to codec.h.
#include "packager/media/base/stream_info.h"
#include "packager/media/formats/mp2t/continuity_counter.h"
namespace shaka {
namespace media {
@ -20,20 +23,19 @@ class BufferWriter;
namespace mp2t {
class ContinuityCounter;
/// Puts PMT into TS packets and writes them to buffer.
/// Note that this does not currently allow encryption without clear lead.
class ProgramMapTableWriter {
public:
ProgramMapTableWriter();
virtual ~ProgramMapTableWriter();
explicit ProgramMapTableWriter(Codec codec);
virtual ~ProgramMapTableWriter() = default;
/// Writes TS packets with PMT for encrypted segments.
virtual bool EncryptedSegmentPmt(BufferWriter* writer) = 0;
// Virtual for testing.
virtual bool EncryptedSegmentPmt(BufferWriter* writer);
/// Writes TS packets with PMT for clear segments.
virtual bool ClearSegmentPmt(BufferWriter* writer) = 0;
// Virtual for testing.
virtual bool ClearSegmentPmt(BufferWriter* writer);
// The pid can be 13 bits long but 8 bits is sufficient for this library.
// This is the minimum PID that can be used for PMT.
@ -41,53 +43,54 @@ class ProgramMapTableWriter {
// This is arbitrary number that is not reserved by the spec.
static const uint8_t kElementaryPid = 0x50;
};
/// <em>This is not a general purpose PMT writer. This is intended to be used by
/// TsWriter.</em>
class H264ProgramMapTableWriter : public ProgramMapTableWriter {
public:
explicit H264ProgramMapTableWriter(ContinuityCounter* continuity_counter);
~H264ProgramMapTableWriter() override;
bool EncryptedSegmentPmt(BufferWriter* writer) override;
bool ClearSegmentPmt(BufferWriter* writer) override;
protected:
/// @return the underlying codec.
Codec codec() const { return codec_; }
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;
ProgramMapTableWriter(const ProgramMapTableWriter&) = delete;
ProgramMapTableWriter& operator=(const ProgramMapTableWriter&) = delete;
DISALLOW_COPY_AND_ASSIGN(H264ProgramMapTableWriter);
// Writes descriptors for PMT (only needed for encrypted PMT).
virtual bool WriteDescriptors(BufferWriter* writer) const = 0;
const Codec codec_;
ContinuityCounter continuity_counter_;
BufferWriter clear_pmt_;
BufferWriter encrypted_pmt_;
};
// TODO(rkuroiwa): For now just handle AAC, we would want AudioProgramMapTable
// later when we support other audio codecs.
/// <em>This is not a general purpose PMT writer. This is intended to be used by
/// TsWriter.</em>
class AacProgramMapTableWriter : public ProgramMapTableWriter {
/// ProgramMapTableWriter for video codecs.
class VideoProgramMapTableWriter : public ProgramMapTableWriter {
public:
AacProgramMapTableWriter(
const std::vector<uint8_t>& aac_audio_specific_config,
ContinuityCounter* continuity_counter);
~AacProgramMapTableWriter() override;
bool EncryptedSegmentPmt(BufferWriter* writer) override;
bool ClearSegmentPmt(BufferWriter* writer) override;
explicit VideoProgramMapTableWriter(Codec codec);
~VideoProgramMapTableWriter() override = default;
private:
bool EncryptedSegmentPmtWithParameters(int version,
int current_next_indicator,
BufferWriter* writer);
VideoProgramMapTableWriter(const VideoProgramMapTableWriter&) = delete;
VideoProgramMapTableWriter& operator=(const VideoProgramMapTableWriter&) =
delete;
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;
bool WriteDescriptors(BufferWriter* writer) const override;
};
DISALLOW_COPY_AND_ASSIGN(AacProgramMapTableWriter);
/// ProgramMapTableWriter for video codecs.
class AudioProgramMapTableWriter : public ProgramMapTableWriter {
public:
AudioProgramMapTableWriter(Codec codec,
const std::vector<uint8_t>& audio_specific_config);
~AudioProgramMapTableWriter() override = default;
private:
AudioProgramMapTableWriter(const AudioProgramMapTableWriter&) = delete;
AudioProgramMapTableWriter& operator=(const AudioProgramMapTableWriter&) =
delete;
// Writers descriptors for PMT (only needed for encrypted PMT).
bool WriteDescriptors(BufferWriter* descriptors) const override;
const std::vector<uint8_t> audio_specific_config_;
};
} // namespace mp2t

View File

@ -49,8 +49,7 @@ class ProgramMapTableWriterTest : public ::testing::Test {
};
TEST_F(ProgramMapTableWriterTest, ClearH264) {
ContinuityCounter counter;
H264ProgramMapTableWriter writer(&counter);
VideoProgramMapTableWriter writer(kCodecH264);
BufferWriter buffer;
writer.ClearSegmentPmt(&buffer);
@ -91,8 +90,7 @@ TEST_F(ProgramMapTableWriterTest, ClearH264) {
// Verify that PSI for encrypted segments after clear lead is generated
// correctly.
TEST_F(ProgramMapTableWriterTest, EncryptedSegmentsAfterClearLeadH264) {
ContinuityCounter counter;
H264ProgramMapTableWriter writer(&counter);
VideoProgramMapTableWriter writer(kCodecH264);
BufferWriter buffer;
writer.ClearSegmentPmt(&buffer);
buffer.Clear();
@ -136,8 +134,7 @@ TEST_F(ProgramMapTableWriterTest, EncryptedSegmentsAfterClearLeadH264) {
// Verify that PMT for encrypted segments can be generated (without clear lead).
TEST_F(ProgramMapTableWriterTest, EncryptedSegmentsH264Pmt) {
ContinuityCounter counter;
H264ProgramMapTableWriter writer(&counter);
VideoProgramMapTableWriter writer(kCodecH264);
BufferWriter buffer;
writer.EncryptedSegmentPmt(&buffer);
@ -179,11 +176,10 @@ TEST_F(ProgramMapTableWriterTest, EncryptedSegmentsH264Pmt) {
}
TEST_F(ProgramMapTableWriterTest, ClearAac) {
ContinuityCounter counter;
const std::vector<uint8_t> aac_audio_specific_config(
kAacBasicProfileExtraData,
kAacBasicProfileExtraData + arraysize(kAacBasicProfileExtraData));
AacProgramMapTableWriter writer(aac_audio_specific_config, &counter);
std::begin(kAacBasicProfileExtraData),
std::end(kAacBasicProfileExtraData));
AudioProgramMapTableWriter writer(kCodecAAC, aac_audio_specific_config);
BufferWriter buffer;
writer.ClearSegmentPmt(&buffer);
@ -222,11 +218,10 @@ TEST_F(ProgramMapTableWriterTest, ClearAac) {
// 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);
std::begin(kAacBasicProfileExtraData),
std::end(kAacBasicProfileExtraData));
AudioProgramMapTableWriter writer(kCodecAAC, aac_audio_specific_config);
BufferWriter buffer;
writer.ClearSegmentPmt(&buffer);
@ -283,11 +278,10 @@ TEST_F(ProgramMapTableWriterTest, EncryptedSegmentsAfterClearLeadAac) {
// 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);
std::begin(kAacBasicProfileExtraData),
std::end(kAacBasicProfileExtraData));
AudioProgramMapTableWriter writer(kCodecAAC, aac_audio_specific_config);
BufferWriter buffer;
writer.EncryptedSegmentPmt(&buffer);

View File

@ -173,23 +173,14 @@ bool TsWriter::Initialize(const StreamInfo& stream_info) {
if (stream_info.stream_type() == StreamType::kStreamVideo) {
const VideoStreamInfo& video_stream_info =
static_cast<const VideoStreamInfo&>(stream_info);
if (video_stream_info.codec() != Codec::kCodecH264) {
LOG(ERROR) << "TsWriter cannot handle video codec "
<< video_stream_info.codec() << " yet.";
return false;
}
pmt_writer_.reset(new H264ProgramMapTableWriter(&pmt_continuity_counter_));
pmt_writer_.reset(
new VideoProgramMapTableWriter(video_stream_info.codec()));
} else {
DCHECK_EQ(stream_type, StreamType::kStreamAudio);
const AudioStreamInfo& audio_stream_info =
static_cast<const AudioStreamInfo&>(stream_info);
if (audio_stream_info.codec() != Codec::kCodecAAC) {
LOG(ERROR) << "TsWriter cannot handle audio codec "
<< audio_stream_info.codec() << " yet.";
return false;
}
pmt_writer_.reset(new AacProgramMapTableWriter(
audio_stream_info.codec_config(), &pmt_continuity_counter_));
pmt_writer_.reset(new AudioProgramMapTableWriter(
audio_stream_info.codec(), audio_stream_info.codec_config()));
}
return true;

View File

@ -65,7 +65,6 @@ class TsWriter {
// True if further segments generated by this instance should be encrypted.
bool encrypted_ = false;
ContinuityCounter pmt_continuity_counter_;
ContinuityCounter pat_continuity_counter_;
ContinuityCounter elementary_stream_continuity_counter_;

View File

@ -58,11 +58,18 @@ const uint8_t kAacBasicProfileExtraData[] = {0x12, 0x10};
class MockProgramMapTableWriter : public ProgramMapTableWriter {
public:
MockProgramMapTableWriter() {}
MockProgramMapTableWriter() : ProgramMapTableWriter(kUnknownCodec) {}
~MockProgramMapTableWriter() override {}
MOCK_METHOD1(EncryptedSegmentPmt, bool(BufferWriter* writer));
MOCK_METHOD1(ClearSegmentPmt, bool(BufferWriter* writer));
private:
MockProgramMapTableWriter(const MockProgramMapTableWriter&) = delete;
MockProgramMapTableWriter& operator=(const MockProgramMapTableWriter&) =
delete;
bool WriteDescriptors(BufferWriter* writer) const override { return true; }
};
// This is not a real TS Packet. But is used to check that the result from the
@ -165,15 +172,6 @@ TEST_F(TsWriterTest, InitializeVideoH264) {
EXPECT_TRUE(ts_writer_.Initialize(*stream_info));
}
TEST_F(TsWriterTest, InitializeVideoNonH264) {
std::shared_ptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
kTrackId, kTimeScale, kDuration, Codec::kCodecVP9,
H26xStreamFormat::kUnSpecified, kCodecString, kExtraData,
arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
kTrickPlayFactor, kNaluLengthSize, kLanguage, kIsEncrypted));
EXPECT_FALSE(ts_writer_.Initialize(*stream_info));
}
TEST_F(TsWriterTest, InitializeAudioAac) {
std::shared_ptr<AudioStreamInfo> stream_info(new AudioStreamInfo(
kTrackId, kTimeScale, kDuration, kAacCodec, kCodecString, kExtraData,
@ -183,15 +181,6 @@ TEST_F(TsWriterTest, InitializeAudioAac) {
EXPECT_TRUE(ts_writer_.Initialize(*stream_info));
}
TEST_F(TsWriterTest, InitializeAudioNonAac) {
std::shared_ptr<AudioStreamInfo> stream_info(new AudioStreamInfo(
kTrackId, kTimeScale, kDuration, Codec::kCodecOpus, kCodecString,
kExtraData, arraysize(kExtraData), kSampleBits, kNumChannels,
kSamplingFrequency, kSeekPreroll, kCodecDelay, kMaxBitrate,
kAverageBitrate, kLanguage, kIsEncrypted));
EXPECT_FALSE(ts_writer_.Initialize(*stream_info));
}
// Verify that PAT and PMT are correct for clear segment.
// This test covers verifies the PAT, and since it doesn't change, other tests
// shouldn't have to check this.
@ -305,6 +294,22 @@ TEST_F(TsWriterTest, ClearLeadH264Pmt) {
kTsPacketSize));
}
TEST_F(TsWriterTest, ClearSegmentPmtFailure) {
std::unique_ptr<MockProgramMapTableWriter> mock_pmt_writer(
new MockProgramMapTableWriter());
EXPECT_CALL(*mock_pmt_writer, ClearSegmentPmt(_)).WillOnce(Return(false));
std::shared_ptr<AudioStreamInfo> stream_info(new AudioStreamInfo(
kTrackId, kTimeScale, kDuration, kAacCodec, kCodecString,
kAacBasicProfileExtraData, arraysize(kAacBasicProfileExtraData),
kSampleBits, kNumChannels, kSamplingFrequency, kSeekPreroll, kCodecDelay,
kMaxBitrate, kAverageBitrate, kLanguage, kIsEncrypted));
EXPECT_TRUE(ts_writer_.Initialize(*stream_info));
ts_writer_.SetProgramMapTableWriterForTesting(std::move(mock_pmt_writer));
EXPECT_FALSE(ts_writer_.NewSegment(test_file_name_));
}
// Check the encrypted segments' PMT (after clear lead).
TEST_F(TsWriterTest, EncryptedSegmentsH264Pmt) {
std::unique_ptr<MockProgramMapTableWriter> mock_pmt_writer(
@ -338,6 +343,28 @@ TEST_F(TsWriterTest, EncryptedSegmentsH264Pmt) {
kTsPacketSize));
}
TEST_F(TsWriterTest, EncryptedSegmentPmtFailure) {
std::unique_ptr<MockProgramMapTableWriter> mock_pmt_writer(
new MockProgramMapTableWriter());
InSequence s;
EXPECT_CALL(*mock_pmt_writer, ClearSegmentPmt(_)).WillOnce(Return(true));
EXPECT_CALL(*mock_pmt_writer, EncryptedSegmentPmt(_)).WillOnce(Return(false));
std::shared_ptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
kTrackId, kTimeScale, kDuration, kH264Codec,
H26xStreamFormat::kAnnexbByteStream, kCodecString, kExtraData,
arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
kTrickPlayFactor, kNaluLengthSize, kLanguage, kIsEncrypted));
EXPECT_TRUE(ts_writer_.Initialize(*stream_info));
ts_writer_.SetProgramMapTableWriterForTesting(std::move(mock_pmt_writer));
EXPECT_TRUE(ts_writer_.NewSegment(test_file_name_));
EXPECT_TRUE(ts_writer_.FinalizeSegment());
ts_writer_.SignalEncrypted();
EXPECT_FALSE(ts_writer_.NewSegment(test_file_name_));
}
// Same as ClearLeadH264Pmt but for AAC.
TEST_F(TsWriterTest, ClearLeadAacPmt) {
std::unique_ptr<MockProgramMapTableWriter> mock_pmt_writer(