Remove escape parameter in NalUnitToByteStreamConverter
The spec actually requires all NAL units to be escaped, so there is no need to escape it again. NAL byte stream is one demarcation method; NAL unit stream is another demarcation method. Regardless of the demarcation method used, the requirement for NAL unit is the same. See the last paragraph of 7.4.1 NAL unit semantics on the requirement on emulation prevention bytes. Change-Id: Icc63fcc5cf965632e331f5af5f673164c7c1663a
This commit is contained in:
parent
c223bc9144
commit
24ba12c18e
|
@ -29,16 +29,10 @@ const uint8_t kAccessUnitDelimiterRbspAnyPrimaryPicType = 0xF0;
|
|||
|
||||
void AppendNalu(const Nalu& nalu,
|
||||
int nalu_length_size,
|
||||
bool escape_data,
|
||||
BufferWriter* buffer_writer) {
|
||||
if (escape_data) {
|
||||
EscapeNalByteSequence(nalu.data(), nalu.header_size() + nalu.payload_size(),
|
||||
buffer_writer);
|
||||
} else {
|
||||
buffer_writer->AppendArray(nalu.data(),
|
||||
nalu.header_size() + nalu.payload_size());
|
||||
}
|
||||
}
|
||||
|
||||
void AddAccessUnitDelimiter(BufferWriter* buffer_writer) {
|
||||
buffer_writer->AppendInt(static_cast<uint8_t>(Nalu::H264_AUD));
|
||||
|
@ -107,14 +101,12 @@ void EscapeNalByteSequence(const uint8_t* input,
|
|||
}
|
||||
|
||||
NalUnitToByteStreamConverter::NalUnitToByteStreamConverter()
|
||||
: nalu_length_size_(0), escape_data_(false) {}
|
||||
: nalu_length_size_(0) {}
|
||||
NalUnitToByteStreamConverter::~NalUnitToByteStreamConverter() {}
|
||||
|
||||
bool NalUnitToByteStreamConverter::Initialize(
|
||||
const uint8_t* decoder_configuration_data,
|
||||
size_t decoder_configuration_data_size,
|
||||
bool escape_data) {
|
||||
escape_data_ = escape_data;
|
||||
size_t decoder_configuration_data_size) {
|
||||
if (!decoder_configuration_data || decoder_configuration_data_size == 0) {
|
||||
LOG(ERROR) << "Decoder conguration is empty.";
|
||||
return false;
|
||||
|
@ -141,11 +133,11 @@ bool NalUnitToByteStreamConverter::Initialize(
|
|||
const Nalu& nalu = decoder_config.nalu(i);
|
||||
if (nalu.type() == Nalu::H264NaluType::H264_SPS) {
|
||||
buffer_writer.AppendArray(kNaluStartCode, arraysize(kNaluStartCode));
|
||||
AppendNalu(nalu, nalu_length_size_, escape_data, &buffer_writer);
|
||||
AppendNalu(nalu, nalu_length_size_, &buffer_writer);
|
||||
found_sps = true;
|
||||
} else if (nalu.type() == Nalu::H264NaluType::H264_PPS) {
|
||||
buffer_writer.AppendArray(kNaluStartCode, arraysize(kNaluStartCode));
|
||||
AppendNalu(nalu, nalu_length_size_, escape_data, &buffer_writer);
|
||||
AppendNalu(nalu, nalu_length_size_, &buffer_writer);
|
||||
found_pps = true;
|
||||
}
|
||||
}
|
||||
|
@ -183,12 +175,6 @@ bool NalUnitToByteStreamConverter::ConvertUnitToByteStreamWithSubsamples(
|
|||
return true;
|
||||
}
|
||||
|
||||
if (subsamples && escape_data_) {
|
||||
LOG(ERROR) << "escape_data_ should not be set when updating subsamples.";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
BufferWriter buffer_writer(sample_size);
|
||||
buffer_writer.AppendArray(kNaluStartCode, arraysize(kNaluStartCode));
|
||||
AddAccessUnitDelimiter(&buffer_writer);
|
||||
|
@ -230,7 +216,7 @@ bool NalUnitToByteStreamConverter::ConvertUnitToByteStreamWithSubsamples(
|
|||
break;
|
||||
default:
|
||||
buffer_writer.AppendArray(kNaluStartCode, arraysize(kNaluStartCode));
|
||||
AppendNalu(nalu, nalu_length_size_, escape_data_, &buffer_writer);
|
||||
AppendNalu(nalu, nalu_length_size_, &buffer_writer);
|
||||
|
||||
if (subsamples) {
|
||||
const size_t old_nalu_size =
|
||||
|
|
|
@ -40,13 +40,9 @@ class NalUnitToByteStreamConverter {
|
|||
/// @param decoder_configuration_data is the pointer to a decoder config data.
|
||||
/// @param decoder_configuration_data_size is the size of @a
|
||||
/// decoder_configuration_data.
|
||||
/// @param escape_data flags whether the decoder configuration and data
|
||||
/// passed to ConvertUnitToByteStream() should be escaped with
|
||||
/// emulation prevention byte.
|
||||
/// @return true on success, false otherwise.
|
||||
virtual bool Initialize(const uint8_t* decoder_configuration_data,
|
||||
size_t decoder_configuration_data_size,
|
||||
bool escape_data);
|
||||
size_t decoder_configuration_data_size);
|
||||
|
||||
/// Converts unit stream to byte stream using the data passed to Initialize().
|
||||
/// The method will function correctly even if @a sample is encrypted using
|
||||
|
@ -82,7 +78,6 @@ class NalUnitToByteStreamConverter {
|
|||
|
||||
int nalu_length_size_;
|
||||
std::vector<uint8_t> decoder_configuration_in_byte_stream_;
|
||||
bool escape_data_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(NalUnitToByteStreamConverter);
|
||||
};
|
||||
|
|
|
@ -36,7 +36,6 @@ const uint8_t kTestAVCDecoderConfigurationRecord[] = {
|
|||
0x68, 0xFE, 0xFD, 0xFC, 0xFB, 0x11, 0x12, 0x13, 0x14, 0x15,
|
||||
};
|
||||
|
||||
const bool kEscapeData = true;
|
||||
const bool kIsKeyFrame = true;
|
||||
|
||||
} // namespace
|
||||
|
@ -51,20 +50,17 @@ TEST(NalUnitToByteStreamConverterTest, ParseAVCDecoderConfigurationRecord) {
|
|||
NalUnitToByteStreamConverter converter;
|
||||
EXPECT_TRUE(
|
||||
converter.Initialize(kTestAVCDecoderConfigurationRecord,
|
||||
arraysize(kTestAVCDecoderConfigurationRecord),
|
||||
kEscapeData));
|
||||
arraysize(kTestAVCDecoderConfigurationRecord)));
|
||||
EXPECT_TRUE(
|
||||
converter.Initialize(kTestAVCDecoderConfigurationRecord,
|
||||
arraysize(kTestAVCDecoderConfigurationRecord),
|
||||
!kEscapeData));
|
||||
arraysize(kTestAVCDecoderConfigurationRecord)));
|
||||
}
|
||||
|
||||
// Empty AVCDecoderConfigurationRecord should return false.
|
||||
TEST(NalUnitToByteStreamConverterTest, EmptyAVCDecoderConfigurationRecord) {
|
||||
NalUnitToByteStreamConverter converter;
|
||||
EXPECT_FALSE(converter.Initialize(nullptr, 102, kEscapeData));
|
||||
EXPECT_FALSE(
|
||||
converter.Initialize(kTestAVCDecoderConfigurationRecord, 0, kEscapeData));
|
||||
EXPECT_FALSE(converter.Initialize(nullptr, 102));
|
||||
EXPECT_FALSE(converter.Initialize(kTestAVCDecoderConfigurationRecord, 0));
|
||||
}
|
||||
|
||||
// If there is no SPS, Initialize() should fail.
|
||||
|
@ -83,7 +79,7 @@ TEST(NalUnitToByteStreamConverterTest, NoSps) {
|
|||
0x68, 0xFE, 0xFD, 0xFC, 0xFB, 0x11, 0x12, 0x13, 0x14, 0x15,
|
||||
};
|
||||
|
||||
EXPECT_FALSE(converter.Initialize(kNoSps, arraysize(kNoSps), !kEscapeData));
|
||||
EXPECT_FALSE(converter.Initialize(kNoSps, arraysize(kNoSps)));
|
||||
}
|
||||
|
||||
// If there is no PPS, Initialize() should fail.
|
||||
|
@ -105,7 +101,7 @@ TEST(NalUnitToByteStreamConverterTest, NoPps) {
|
|||
0x00, // 0 pps.
|
||||
};
|
||||
|
||||
EXPECT_FALSE(converter.Initialize(kNoPps, arraysize(kNoPps), !kEscapeData));
|
||||
EXPECT_FALSE(converter.Initialize(kNoPps, arraysize(kNoPps)));
|
||||
}
|
||||
|
||||
// If the length of SPS is 0 then Initialize() should fail.
|
||||
|
@ -124,8 +120,7 @@ TEST(NalUnitToByteStreamConverterTest, ZeroLengthSps) {
|
|||
0x68, 0xFE, 0xFD, 0xFC, 0xFB, 0x11, 0x12, 0x13, 0x14, 0x15,
|
||||
};
|
||||
|
||||
EXPECT_FALSE(converter.Initialize(kZeroLengthSps, arraysize(kZeroLengthSps),
|
||||
!kEscapeData));
|
||||
EXPECT_FALSE(converter.Initialize(kZeroLengthSps, arraysize(kZeroLengthSps)));
|
||||
}
|
||||
|
||||
// If the length of PPS is 0 then Initialize() should fail.
|
||||
|
@ -144,8 +139,7 @@ TEST(NalUnitToByteStreamConverterTest, ZeroLengthPps) {
|
|||
0x00, 0x00, // PPS length == 0
|
||||
};
|
||||
|
||||
EXPECT_FALSE(converter.Initialize(kZeroLengthPps, arraysize(kZeroLengthPps),
|
||||
!kEscapeData));
|
||||
EXPECT_FALSE(converter.Initialize(kZeroLengthPps, arraysize(kZeroLengthPps)));
|
||||
}
|
||||
|
||||
TEST(NalUnitToByteStreamConverterTest, ConvertUnitToByteStream) {
|
||||
|
@ -159,8 +153,7 @@ TEST(NalUnitToByteStreamConverterTest, ConvertUnitToByteStream) {
|
|||
NalUnitToByteStreamConverter converter;
|
||||
EXPECT_TRUE(
|
||||
converter.Initialize(kTestAVCDecoderConfigurationRecord,
|
||||
arraysize(kTestAVCDecoderConfigurationRecord),
|
||||
!kEscapeData));
|
||||
arraysize(kTestAVCDecoderConfigurationRecord)));
|
||||
|
||||
std::vector<uint8_t> output;
|
||||
EXPECT_TRUE(converter.ConvertUnitToByteStream(
|
||||
|
@ -190,83 +183,6 @@ TEST(NalUnitToByteStreamConverterTest, ConvertUnitToByteStream) {
|
|||
output);
|
||||
}
|
||||
|
||||
// Verify that escaping works on all data.
|
||||
TEST(NalUnitToByteStreamConverterTest, ConvertUnitToByteStreamWithEscape) {
|
||||
// Only the type of the NAL units are checked.
|
||||
// This does not contain AUD, SPS, nor PPS.
|
||||
const uint8_t kUnitStreamLikeMediaSample[] = {
|
||||
0x00, 0x00, 0x00, 0x0A, // Size 10 NALU.
|
||||
0x06, // NAL unit type.
|
||||
0x06, 0x00, 0x00, 0x00, 0xDF, 0x62, 0x11, 0x29, 0x77,
|
||||
};
|
||||
NalUnitToByteStreamConverter converter;
|
||||
EXPECT_TRUE(
|
||||
converter.Initialize(kTestAVCDecoderConfigurationRecord,
|
||||
arraysize(kTestAVCDecoderConfigurationRecord),
|
||||
kEscapeData));
|
||||
|
||||
std::vector<uint8_t> output;
|
||||
EXPECT_TRUE(converter.ConvertUnitToByteStream(
|
||||
kUnitStreamLikeMediaSample, arraysize(kUnitStreamLikeMediaSample),
|
||||
kIsKeyFrame, &output));
|
||||
|
||||
const uint8_t kExpectedOutput[] = {
|
||||
0x00, 0x00, 0x00, 0x01, // Start code.
|
||||
0x09, // AUD type.
|
||||
0xF0, // primary pic type is anything.
|
||||
0x00, 0x00, 0x00, 0x01, // Start code.
|
||||
// Some valid SPS data.
|
||||
0x67, 0x64, 0x00, 0x1E, 0xAC, 0xD9, 0x40, 0xB4,
|
||||
0x2F, 0xF9, 0x7F, 0xF0, 0x00, 0x80, 0x00, 0x91,
|
||||
// Note that extra 0x03 is added.
|
||||
0x00, 0x00, 0x03, 0x03, 0x03, 0xE9, 0x00, 0x00,
|
||||
0xEA, 0x60, 0x0F, 0x16, 0x2D, 0x96,
|
||||
0x00, 0x00, 0x00, 0x01, // Start code.
|
||||
0x68, 0xFE, 0xFD, 0xFC, 0xFB, 0x11, 0x12, 0x13, 0x14, 0x15, // PPS.
|
||||
0x00, 0x00, 0x00, 0x01, // Start code.
|
||||
// The input NALU.
|
||||
0x06, // NALU type.
|
||||
0x06, 0x00, 0x00, 0x03, 0x00, 0xDF, 0x62, 0x11, 0x29, 0x77,
|
||||
};
|
||||
|
||||
EXPECT_EQ(std::vector<uint8_t>(kExpectedOutput,
|
||||
kExpectedOutput + arraysize(kExpectedOutput)),
|
||||
output);
|
||||
}
|
||||
|
||||
// NALU ending with 0 must have 3 appended.
|
||||
TEST(NalUnitToByteStreamConverterTest, NaluEndingWithZero) {
|
||||
const uint8_t kNaluEndingWithZero[] = {
|
||||
0x00, 0x00, 0x00, 0x03, // Size 3 NALU.
|
||||
0x06, // NAL unit type.
|
||||
0xAA, 0x00, // Ends with 0.
|
||||
};
|
||||
NalUnitToByteStreamConverter converter;
|
||||
EXPECT_TRUE(
|
||||
converter.Initialize(kTestAVCDecoderConfigurationRecord,
|
||||
arraysize(kTestAVCDecoderConfigurationRecord),
|
||||
kEscapeData));
|
||||
|
||||
std::vector<uint8_t> output;
|
||||
EXPECT_TRUE(converter.ConvertUnitToByteStream(kNaluEndingWithZero,
|
||||
arraysize(kNaluEndingWithZero),
|
||||
!kIsKeyFrame, &output));
|
||||
|
||||
const uint8_t kExpectedOutput[] = {
|
||||
0x00, 0x00, 0x00, 0x01, // Start code.
|
||||
0x09, // AUD type.
|
||||
0xF0, // primary pic type is anything.
|
||||
0x00, 0x00, 0x00, 0x01, // Start code.
|
||||
// The input NALU.
|
||||
0x06, // NALU type.
|
||||
0xAA, 0x00, 0x03, // 0x03 at the end because the original ends with 0.
|
||||
};
|
||||
|
||||
EXPECT_EQ(std::vector<uint8_t>(kExpectedOutput,
|
||||
kExpectedOutput + arraysize(kExpectedOutput)),
|
||||
output);
|
||||
}
|
||||
|
||||
// Verify that if it is not a key frame then SPS and PPS from decoder
|
||||
// configuration is not used.
|
||||
TEST(NalUnitToByteStreamConverterTest, NonKeyFrameSample) {
|
||||
|
@ -278,8 +194,7 @@ TEST(NalUnitToByteStreamConverterTest, NonKeyFrameSample) {
|
|||
NalUnitToByteStreamConverter converter;
|
||||
EXPECT_TRUE(
|
||||
converter.Initialize(kTestAVCDecoderConfigurationRecord,
|
||||
arraysize(kTestAVCDecoderConfigurationRecord),
|
||||
kEscapeData));
|
||||
arraysize(kTestAVCDecoderConfigurationRecord)));
|
||||
|
||||
std::vector<uint8_t> output;
|
||||
EXPECT_TRUE(converter.ConvertUnitToByteStream(kNonKeyFrameStream,
|
||||
|
@ -315,8 +230,7 @@ TEST(NalUnitToByteStreamConverterTest, DispersedZeros) {
|
|||
NalUnitToByteStreamConverter converter;
|
||||
EXPECT_TRUE(
|
||||
converter.Initialize(kTestAVCDecoderConfigurationRecord,
|
||||
arraysize(kTestAVCDecoderConfigurationRecord),
|
||||
kEscapeData));
|
||||
arraysize(kTestAVCDecoderConfigurationRecord)));
|
||||
|
||||
std::vector<uint8_t> output;
|
||||
EXPECT_TRUE(converter.ConvertUnitToByteStream(
|
||||
|
@ -349,8 +263,7 @@ TEST(NalUnitToByteStreamConverterTest, DoNotEscape) {
|
|||
NalUnitToByteStreamConverter converter;
|
||||
EXPECT_TRUE(
|
||||
converter.Initialize(kTestAVCDecoderConfigurationRecord,
|
||||
arraysize(kTestAVCDecoderConfigurationRecord),
|
||||
!kEscapeData));
|
||||
arraysize(kTestAVCDecoderConfigurationRecord)));
|
||||
|
||||
std::vector<uint8_t> output;
|
||||
EXPECT_TRUE(converter.ConvertUnitToByteStream(
|
||||
|
@ -388,9 +301,9 @@ TEST(NalUnitToByteStreamConverterTest, NoClearNAL) {
|
|||
SubsampleEntry(5, 7)};
|
||||
|
||||
NalUnitToByteStreamConverter converter;
|
||||
EXPECT_TRUE(converter.Initialize(
|
||||
kTestAVCDecoderConfigurationRecord,
|
||||
arraysize(kTestAVCDecoderConfigurationRecord), !kEscapeData));
|
||||
EXPECT_TRUE(
|
||||
converter.Initialize(kTestAVCDecoderConfigurationRecord,
|
||||
arraysize(kTestAVCDecoderConfigurationRecord)));
|
||||
|
||||
std::vector<uint8_t> output;
|
||||
EXPECT_TRUE(converter.ConvertUnitToByteStreamWithSubsamples(
|
||||
|
@ -444,9 +357,9 @@ TEST(NalUnitToByteStreamConverterTest, WithSomeClearNAL) {
|
|||
std::vector<SubsampleEntry> subsamples{SubsampleEntry(19, 7)};
|
||||
|
||||
NalUnitToByteStreamConverter converter;
|
||||
EXPECT_TRUE(converter.Initialize(
|
||||
kTestAVCDecoderConfigurationRecord,
|
||||
arraysize(kTestAVCDecoderConfigurationRecord), !kEscapeData));
|
||||
EXPECT_TRUE(
|
||||
converter.Initialize(kTestAVCDecoderConfigurationRecord,
|
||||
arraysize(kTestAVCDecoderConfigurationRecord)));
|
||||
|
||||
std::vector<uint8_t> output;
|
||||
EXPECT_TRUE(converter.ConvertUnitToByteStreamWithSubsamples(
|
||||
|
@ -506,9 +419,9 @@ TEST(NalUnitToByteStreamConverterTest, EncryptedPps) {
|
|||
SubsampleEntry(5, 7)};
|
||||
|
||||
NalUnitToByteStreamConverter converter;
|
||||
EXPECT_TRUE(converter.Initialize(
|
||||
kTestAVCDecoderConfigurationRecord,
|
||||
arraysize(kTestAVCDecoderConfigurationRecord), !kEscapeData));
|
||||
EXPECT_TRUE(
|
||||
converter.Initialize(kTestAVCDecoderConfigurationRecord,
|
||||
arraysize(kTestAVCDecoderConfigurationRecord)));
|
||||
|
||||
std::vector<uint8_t> output;
|
||||
EXPECT_TRUE(converter.ConvertUnitToByteStreamWithSubsamples(
|
||||
|
@ -567,9 +480,9 @@ TEST(NalUnitToByteStreamConverterTest, ClearPps) {
|
|||
std::vector<SubsampleEntry> subsamples{SubsampleEntry(34, 7)};
|
||||
|
||||
NalUnitToByteStreamConverter converter;
|
||||
EXPECT_TRUE(converter.Initialize(
|
||||
kTestAVCDecoderConfigurationRecord,
|
||||
arraysize(kTestAVCDecoderConfigurationRecord), !kEscapeData));
|
||||
EXPECT_TRUE(
|
||||
converter.Initialize(kTestAVCDecoderConfigurationRecord,
|
||||
arraysize(kTestAVCDecoderConfigurationRecord)));
|
||||
|
||||
std::vector<uint8_t> output;
|
||||
EXPECT_TRUE(converter.ConvertUnitToByteStreamWithSubsamples(
|
||||
|
|
|
@ -26,7 +26,6 @@ namespace media {
|
|||
namespace mp2t {
|
||||
|
||||
namespace {
|
||||
const bool kEscapeData = true;
|
||||
const uint8_t kVideoStreamId = 0xE0;
|
||||
const uint8_t kAudioStreamId = 0xC0;
|
||||
const double kTsTimescale = 90000.0;
|
||||
|
@ -105,8 +104,7 @@ bool PesPacketGenerator::Initialize(const StreamInfo& stream_info) {
|
|||
timescale_scale_ = kTsTimescale / video_stream_info.time_scale();
|
||||
converter_.reset(new NalUnitToByteStreamConverter());
|
||||
return converter_->Initialize(video_stream_info.codec_config().data(),
|
||||
video_stream_info.codec_config().size(),
|
||||
!kEscapeData);
|
||||
video_stream_info.codec_config().size());
|
||||
} else if (stream_type_ == kStreamAudio) {
|
||||
const AudioStreamInfo& audio_stream_info =
|
||||
static_cast<const AudioStreamInfo&>(stream_info);
|
||||
|
|
|
@ -85,10 +85,9 @@ const uint32_t kAverageBitrate = 256000;
|
|||
|
||||
class MockNalUnitToByteStreamConverter : public NalUnitToByteStreamConverter {
|
||||
public:
|
||||
MOCK_METHOD3(Initialize,
|
||||
MOCK_METHOD2(Initialize,
|
||||
bool(const uint8_t* decoder_configuration_data,
|
||||
size_t decoder_configuration_data_size,
|
||||
bool escape_data));
|
||||
size_t decoder_configuration_data_size));
|
||||
MOCK_METHOD4(ConvertUnitToByteStream,
|
||||
bool(const uint8_t* sample,
|
||||
size_t sample_size,
|
||||
|
|
Loading…
Reference in New Issue