Improve handling of unescaped NAL units in byte stream

The new algorithm will parse NAL unit header and only starts a new
NAL unit if it is valid, otherwise it will be considered part of
the previous NAL unit.

Closes #96

Change-Id: I45f2a0f37d51841ee8345d6d0d38fcda57e0a009
This commit is contained in:
KongQun Yang 2016-03-21 17:39:22 -07:00
parent d5cdd00ba1
commit 0c46943177
7 changed files with 205 additions and 57 deletions

View File

@ -152,7 +152,7 @@ TEST(NalUnitToByteStreamConverterTest, ConvertUnitToByteStream) {
// This does not contain AUD, SPS, nor PPS. // This does not contain AUD, SPS, nor PPS.
const uint8_t kUnitStreamLikeMediaSample[] = { const uint8_t kUnitStreamLikeMediaSample[] = {
0x00, 0x00, 0x00, 0x0A, // Size 10 NALU. 0x00, 0x00, 0x00, 0x0A, // Size 10 NALU.
0x00, // Unspecified NAL unit type. 0x06, // NAL unit type.
0xFD, 0x78, 0xA4, 0xC3, 0x82, 0x62, 0x11, 0x29, 0x77, 0xFD, 0x78, 0xA4, 0xC3, 0x82, 0x62, 0x11, 0x29, 0x77,
}; };
NalUnitToByteStreamConverter converter; NalUnitToByteStreamConverter converter;
@ -180,7 +180,7 @@ TEST(NalUnitToByteStreamConverterTest, ConvertUnitToByteStream) {
0x68, 0xFE, 0xFD, 0xFC, 0xFB, 0x11, 0x12, 0x13, 0x14, 0x15, // PPS. 0x68, 0xFE, 0xFD, 0xFC, 0xFB, 0x11, 0x12, 0x13, 0x14, 0x15, // PPS.
0x00, 0x00, 0x00, 0x01, // Start code. 0x00, 0x00, 0x00, 0x01, // Start code.
// The input NALU. // The input NALU.
0x00, // Unspecified NALU type. 0x06, // NALU type.
0xFD, 0x78, 0xA4, 0xC3, 0x82, 0x62, 0x11, 0x29, 0x77, 0xFD, 0x78, 0xA4, 0xC3, 0x82, 0x62, 0x11, 0x29, 0x77,
}; };
@ -195,7 +195,7 @@ TEST(NalUnitToByteStreamConverterTest, ConvertUnitToByteStreamWithEscape) {
// This does not contain AUD, SPS, nor PPS. // This does not contain AUD, SPS, nor PPS.
const uint8_t kUnitStreamLikeMediaSample[] = { const uint8_t kUnitStreamLikeMediaSample[] = {
0x00, 0x00, 0x00, 0x0A, // Size 10 NALU. 0x00, 0x00, 0x00, 0x0A, // Size 10 NALU.
0x00, // Unspecified NAL unit type. 0x06, // NAL unit type.
0x06, 0x00, 0x00, 0x00, 0xDF, 0x62, 0x11, 0x29, 0x77, 0x06, 0x00, 0x00, 0x00, 0xDF, 0x62, 0x11, 0x29, 0x77,
}; };
NalUnitToByteStreamConverter converter; NalUnitToByteStreamConverter converter;
@ -224,7 +224,7 @@ TEST(NalUnitToByteStreamConverterTest, ConvertUnitToByteStreamWithEscape) {
0x68, 0xFE, 0xFD, 0xFC, 0xFB, 0x11, 0x12, 0x13, 0x14, 0x15, // PPS. 0x68, 0xFE, 0xFD, 0xFC, 0xFB, 0x11, 0x12, 0x13, 0x14, 0x15, // PPS.
0x00, 0x00, 0x00, 0x01, // Start code. 0x00, 0x00, 0x00, 0x01, // Start code.
// The input NALU. // The input NALU.
0x00, // Unspecified NALU type. 0x06, // NALU type.
0x06, 0x00, 0x00, 0x03, 0x00, 0xDF, 0x62, 0x11, 0x29, 0x77, 0x06, 0x00, 0x00, 0x03, 0x00, 0xDF, 0x62, 0x11, 0x29, 0x77,
}; };
@ -237,7 +237,7 @@ TEST(NalUnitToByteStreamConverterTest, ConvertUnitToByteStreamWithEscape) {
TEST(NalUnitToByteStreamConverterTest, NaluEndingWithZero) { TEST(NalUnitToByteStreamConverterTest, NaluEndingWithZero) {
const uint8_t kNaluEndingWithZero[] = { const uint8_t kNaluEndingWithZero[] = {
0x00, 0x00, 0x00, 0x03, // Size 10 NALU. 0x00, 0x00, 0x00, 0x03, // Size 10 NALU.
0x00, // Unspecified NAL unit type. 0x06, // NAL unit type.
0xAA, 0x00, // Ends with 0. 0xAA, 0x00, // Ends with 0.
}; };
NalUnitToByteStreamConverter converter; NalUnitToByteStreamConverter converter;
@ -257,7 +257,7 @@ TEST(NalUnitToByteStreamConverterTest, NaluEndingWithZero) {
0xF0, // primary pic type is anything. 0xF0, // primary pic type is anything.
0x00, 0x00, 0x00, 0x01, // Start code. 0x00, 0x00, 0x00, 0x01, // Start code.
// The input NALU. // The input NALU.
0x00, // Unspecified NALU type. 0x06, // NALU type.
0xAA, 0x00, 0x03, // 0x03 at the end because the original ends with 0. 0xAA, 0x00, 0x03, // 0x03 at the end because the original ends with 0.
}; };
@ -271,7 +271,7 @@ TEST(NalUnitToByteStreamConverterTest, NaluEndingWithZero) {
TEST(NalUnitToByteStreamConverterTest, NonKeyFrameSample) { TEST(NalUnitToByteStreamConverterTest, NonKeyFrameSample) {
const uint8_t kNonKeyFrameStream[] = { const uint8_t kNonKeyFrameStream[] = {
0x00, 0x00, 0x00, 0x03, // Size 10 NALU. 0x00, 0x00, 0x00, 0x03, // Size 10 NALU.
0x00, // Unspecified NAL unit type. 0x06, // NAL unit type.
0x33, 0x88, 0x33, 0x88,
}; };
NalUnitToByteStreamConverter converter; NalUnitToByteStreamConverter converter;
@ -291,7 +291,7 @@ TEST(NalUnitToByteStreamConverterTest, NonKeyFrameSample) {
0xF0, // Anything. 0xF0, // Anything.
0x00, 0x00, 0x00, 0x01, // Start code. 0x00, 0x00, 0x00, 0x01, // Start code.
// The input NALU. // The input NALU.
0x00, // Unspecified NALU type. 0x06, // NALU type.
0x33, 0x88, 0x33, 0x88,
}; };
@ -305,7 +305,7 @@ TEST(NalUnitToByteStreamConverterTest, NonKeyFrameSample) {
TEST(NalUnitToByteStreamConverterTest, DispersedZeros) { TEST(NalUnitToByteStreamConverterTest, DispersedZeros) {
const uint8_t kDispersedZeros[] = { const uint8_t kDispersedZeros[] = {
0x00, 0x00, 0x00, 0x08, // Size 10 NALU. 0x00, 0x00, 0x00, 0x08, // Size 10 NALU.
0x00, // Unspecified NAL unit type. 0x06, // NAL unit type.
// After 2 zeros (including the first byte of the NALU followed by 0, 1, // After 2 zeros (including the first byte of the NALU followed by 0, 1,
// 2, or 3 caused it to insert the escape byte. // 2, or 3 caused it to insert the escape byte.
0x11, 0x00, 0x11, 0x00,
@ -327,7 +327,7 @@ TEST(NalUnitToByteStreamConverterTest, DispersedZeros) {
0xF0, // Anything. 0xF0, // Anything.
0x00, 0x00, 0x00, 0x01, // Start code. 0x00, 0x00, 0x00, 0x01, // Start code.
// The input NALU. // The input NALU.
0x00, // Unspecified NAL unit type. 0x06, // NAL unit type.
0x11, 0x00, 0x01, 0x00, 0x02, 0x00, 0x44, 0x11, 0x00, 0x01, 0x00, 0x02, 0x00, 0x44,
}; };
@ -341,7 +341,7 @@ TEST(NalUnitToByteStreamConverterTest, DoNotEscape) {
// This has sequences that should be escaped if escape_data = true. // This has sequences that should be escaped if escape_data = true.
const uint8_t kNotEscaped[] = { const uint8_t kNotEscaped[] = {
0x00, 0x00, 0x00, 0x0C, // Size 12 NALU. 0x00, 0x00, 0x00, 0x0C, // Size 12 NALU.
0x00, // Unspecified NAL unit type. 0x06, // NAL unit type.
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x03,
}; };
@ -361,7 +361,7 @@ TEST(NalUnitToByteStreamConverterTest, DoNotEscape) {
0xF0, // Anything. 0xF0, // Anything.
0x00, 0x00, 0x00, 0x01, // Start code. 0x00, 0x00, 0x00, 0x01, // Start code.
// Should be the same as the input. // Should be the same as the input.
0x00, 0x06,
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x03,
}; };

View File

@ -6,6 +6,8 @@
#include "packager/media/filters/nalu_reader.h" #include "packager/media/filters/nalu_reader.h"
#include <iostream>
#include "packager/base/logging.h" #include "packager/base/logging.h"
#include "packager/media/base/buffer_reader.h" #include "packager/media/base/buffer_reader.h"
#include "packager/media/filters/h264_parser.h" #include "packager/media/filters/h264_parser.h"
@ -29,31 +31,66 @@ Nalu::Nalu()
type_(0), type_(0),
is_video_slice_(false) {} is_video_slice_(false) {}
// ITU-T H.264 (02/2014) 7.4.1 NAL unit semantics
bool Nalu::InitializeFromH264(const uint8_t* data, uint64_t size) { bool Nalu::InitializeFromH264(const uint8_t* data, uint64_t size) {
DCHECK(data); DCHECK(data);
if (size == 0) if (size == 0)
return false; return false;
uint8_t header = data[0]; const uint8_t header = data[0];
if ((header & 0x80) != 0) if ((header & 0x80) != 0) {
LOG(WARNING) << "forbidden_zero_bit shall be equal to 0 (header 0x"
<< std::hex << static_cast<int>(header) << ").";
return false; return false;
}
data_ = data; data_ = data;
header_size_ = 1; header_size_ = 1;
payload_size_ = size - header_size_; payload_size_ = size - header_size_;
ref_idc_ = (header >> 5) & 0x3; ref_idc_ = (header >> 5) & 0x3;
type_ = header & 0x1F; type_ = header & 0x1F;
// Reserved NAL units are not treated as valid NAL units here.
if (type_ == Nalu::H264_Unspecified || type_ == Nalu::H264_Reserved17 ||
type_ == Nalu::H264_Reserved18 || type_ >= Nalu::H264_Reserved22) {
LOG(WARNING) << "Unspecified or reserved nal_unit_type " << type_
<< " (header 0x" << std::hex << static_cast<int>(header)
<< ").";
return false;
} else if (type_ == Nalu::H264_IDRSlice || type_ == Nalu::H264_SPS ||
type_ == Nalu::H264_SPSExtension || type_ == Nalu::H264_SubsetSPS ||
type_ == Nalu::H264_PPS) {
if (ref_idc_ == 0) {
LOG(WARNING) << "nal_ref_idc shall not be equal to 0 for nalu type "
<< type_ << " (header 0x" << std::hex
<< static_cast<int>(header) << ").";
return false;
}
} else if (type_ == Nalu::H264_SEIMessage ||
(type_ >= Nalu::H264_AUD && type_ <= Nalu::H264_FillerData)) {
if (ref_idc_ != 0) {
LOG(WARNING) << "nal_ref_idc shall be equal to 0 for nalu type " << type_
<< " (header 0x" << std::hex << static_cast<int>(header)
<< ").";
return false;
}
}
is_video_slice_ = (type_ >= Nalu::H264_NonIDRSlice && is_video_slice_ = (type_ >= Nalu::H264_NonIDRSlice &&
type_ <= Nalu::H264_IDRSlice); type_ <= Nalu::H264_IDRSlice);
return true; return true;
} }
// ITU-T H.265 (04/2015) 7.4.2.2 NAL unit header semantics
bool Nalu::InitializeFromH265(const uint8_t* data, uint64_t size) { bool Nalu::InitializeFromH265(const uint8_t* data, uint64_t size) {
DCHECK(data); DCHECK(data);
if (size < 2) if (size < 2)
return false; return false;
uint16_t header = (data[0] << 8) | data[1]; const uint16_t header = (data[0] << 8) | data[1];
if ((header & 0x8000) != 0) if ((header & 0x8000) != 0) {
LOG(WARNING) << "forbidden_zero_bit shall be equal to 0 (header 0x"
<< std::hex << header << ").";
return false; return false;
}
data_ = data; data_ = data;
header_size_ = 2; header_size_ = 2;
@ -61,12 +98,47 @@ bool Nalu::InitializeFromH265(const uint8_t* data, uint64_t size) {
type_ = (header >> 9) & 0x3F; type_ = (header >> 9) & 0x3F;
nuh_layer_id_ = (header >> 3) & 0x3F; nuh_layer_id_ = (header >> 3) & 0x3F;
nuh_temporal_id_ = (header & 0x7) - 1; const int nuh_temporal_id_plus1 = header & 0x7;
if (nuh_temporal_id_plus1 == 0) {
LOG(WARNING) << "nul_temporal_id_plus1 shall not be equal to 0 (header 0x"
<< std::hex << header << ").";
return false;
}
nuh_temporal_id_ = nuh_temporal_id_plus1 - 1;
// Don't treat reserved VCL types as video slices since we cannot parse them. if (type_ == Nalu::H265_EOB && nuh_layer_id_ != 0) {
is_video_slice_ = LOG(WARNING) << "nuh_layer_id shall be equal to 0 for nalu type " << type_
(type_ >= Nalu::H265_TRAIL_N && type_ <= Nalu::H265_RASL_R) || << " (header 0x" << std::hex << header << ").";
(type_ >= Nalu::H265_BLA_W_LP && type_ <= Nalu::H265_CRA_NUT); return false;
}
// Reserved NAL units are not treated as valid NAL units here.
if ((type_ >= Nalu::H265_RSV_VCL_N10 && type_ <= Nalu::H265_RSV_VCL_R15) ||
(type_ >= Nalu::H265_RSV_IRAP_VCL22 && type_ < Nalu::H265_RSV_VCL31) ||
(type_ >= Nalu::H265_RSV_NVCL41)) {
LOG(WARNING) << "Unspecified or reserved nal_unit_type " << type_
<< " (header 0x" << std::hex << header << ").";
return false;
} else if ((type_ >= Nalu::H265_BLA_W_LP &&
type_ <= Nalu::H265_RSV_IRAP_VCL23) ||
type_ == Nalu::H265_VPS || type_ == Nalu::H265_SPS ||
type_ == Nalu::H265_EOS || type_ == Nalu::H265_EOB) {
if (nuh_temporal_id_ != 0) {
LOG(WARNING) << "TemporalId shall be equal to 0 for nalu type " << type_
<< " (header 0x" << std::hex << header << ").";
return false;
}
} else if (type_ == Nalu::H265_TSA_N || type_ == Nalu::H265_TSA_R ||
(nuh_layer_id_ == 0 &&
(type_ == Nalu::H265_STSA_N || type_ == Nalu::H265_STSA_R))) {
if (nuh_temporal_id_ == 0) {
LOG(WARNING) << "TemporalId shall not be equal to 0 for nalu type "
<< type_ << " (header 0x" << std::hex << header << ").";
return false;
}
}
is_video_slice_ = type_ >= Nalu::H265_TRAIL_N && type_ <= Nalu::H265_CRA_NUT;
return true; return true;
} }
@ -218,11 +290,29 @@ bool NaluReader::LocateNaluByStartCode(uint64_t* nalu_size,
// belong to the current NALU. // belong to the current NALU.
uint64_t nalu_size_without_start_code = 0; uint64_t nalu_size_without_start_code = 0;
uint8_t next_start_code_size = 0; uint8_t next_start_code_size = 0;
while (true) {
if (!FindStartCode(nalu_data, max_nalu_data_size, if (!FindStartCode(nalu_data, max_nalu_data_size,
&nalu_size_without_start_code, &next_start_code_size)) { &nalu_size_without_start_code, &next_start_code_size)) {
nalu_size_without_start_code = max_nalu_data_size; nalu_data += max_nalu_data_size;
break;
} }
*nalu_size = nalu_size_without_start_code + annexb_start_code_size;
nalu_data += nalu_size_without_start_code + next_start_code_size;
max_nalu_data_size -= nalu_size_without_start_code + next_start_code_size;
// If it is not a valid NAL unit, we will continue searching. This is to
// handle the case where emulation prevention are not applied.
Nalu nalu;
if (nalu_type_ == kH264
? nalu.InitializeFromH264(nalu_data, max_nalu_data_size)
: nalu.InitializeFromH265(nalu_data, max_nalu_data_size)) {
nalu_data -= next_start_code_size;
break;
}
LOG(WARNING) << "Seeing invalid NAL unit. Emulation prevention may not "
"have been applied properly. Assuming it is part of the "
"previous NAL unit.";
}
*nalu_size = nalu_data - stream_;
*start_code_size = annexb_start_code_size; *start_code_size = annexb_start_code_size;
return true; return true;
} }

View File

@ -34,22 +34,43 @@ class Nalu {
H264_PPS = 8, H264_PPS = 8,
H264_AUD = 9, H264_AUD = 9,
H264_EOSeq = 10, H264_EOSeq = 10,
H264_FillerData = 12,
H264_SPSExtension = 13,
H264_SubsetSPS = 15,
H264_Reserved17 = 17,
H264_Reserved18 = 18,
H264_CodedSliceExtension = 20, H264_CodedSliceExtension = 20,
H264_Reserved22 = 22,
}; };
enum H265NaluType { enum H265NaluType {
H265_TRAIL_N = 0, H265_TRAIL_N = 0,
H265_TSA_N = 2,
H265_TSA_R = 3,
H265_STSA_N = 4,
H265_STSA_R = 5,
H265_RASL_R = 9, H265_RASL_R = 9,
H265_RSV_VCL_N10 = 10,
H265_RSV_VCL_R15 = 15,
H265_BLA_W_LP = 16, H265_BLA_W_LP = 16,
H265_IDR_W_RADL = 19, H265_IDR_W_RADL = 19,
H265_IDR_N_LP = 20, H265_IDR_N_LP = 20,
H265_CRA_NUT = 21, H265_CRA_NUT = 21,
H265_RSV_IRAP_VCL22 = 22,
H265_RSV_IRAP_VCL23 = 23, H265_RSV_IRAP_VCL23 = 23,
H265_RSV_VCL31 = 31,
H265_VPS = 32, H265_VPS = 32,
H265_SPS = 33, H265_SPS = 33,
H265_PPS = 34, H265_PPS = 34,
H265_AUD = 35, H265_AUD = 35,
H265_EOS = 36,
H265_EOB = 37,
H265_RSV_NVCL41 = 41,
}; };
Nalu(); Nalu();

View File

@ -15,9 +15,9 @@ TEST(NaluReaderTest, StartCodeSearch) {
const uint8_t kNaluData[] = { const uint8_t kNaluData[] = {
0x01, 0x00, 0x00, 0x04, 0x23, 0x56, 0x01, 0x00, 0x00, 0x04, 0x23, 0x56,
// First NALU // First NALU
0x00, 0x00, 0x01, 0x12, 0x34, 0x56, 0x78, 0x00, 0x00, 0x01, 0x14, 0x34, 0x56, 0x78,
// Second NALU // Second NALU
0x00, 0x00, 0x00, 0x01, 0x67, 0xbb, 0xcc, 0xdd 0x00, 0x00, 0x00, 0x01, 0x67, 0xbb, 0xcc, 0xdd,
}; };
NaluReader reader(NaluReader::kH264, kIsAnnexbByteStream, kNaluData, NaluReader reader(NaluReader::kH264, kIsAnnexbByteStream, kNaluData,
@ -29,7 +29,7 @@ TEST(NaluReaderTest, StartCodeSearch) {
EXPECT_EQ(3u, nalu.payload_size()); EXPECT_EQ(3u, nalu.payload_size());
EXPECT_EQ(1u, nalu.header_size()); EXPECT_EQ(1u, nalu.header_size());
EXPECT_EQ(0, nalu.ref_idc()); EXPECT_EQ(0, nalu.ref_idc());
EXPECT_EQ(0x12, nalu.type()); EXPECT_EQ(0x14, nalu.type());
ASSERT_EQ(NaluReader::kOk, reader.Advance(&nalu)); ASSERT_EQ(NaluReader::kOk, reader.Advance(&nalu));
EXPECT_EQ(kNaluData + 17, nalu.data()); EXPECT_EQ(kNaluData + 17, nalu.data());
@ -41,12 +41,46 @@ TEST(NaluReaderTest, StartCodeSearch) {
EXPECT_EQ(NaluReader::kEOStream, reader.Advance(&nalu)); EXPECT_EQ(NaluReader::kEOStream, reader.Advance(&nalu));
} }
TEST(NaluReaderTest, StartCodeSearchWithStartCodeInsideNalUnit) {
const uint8_t kNaluData[] = {
0x01, 0x00, 0x00, 0x04, 0x23, 0x56,
// First NALU
0x00, 0x00, 0x01, 0x14, 0x34, 0x56, 0x78,
// This is part of the first NALU as it is not a valid NALU.
0x00, 0x00, 0x00, 0x01, 0x07, 0xbb, 0xcc, 0xdd,
// Second NALU
0x00, 0x00, 0x01, 0x67, 0x03, 0x04,
// This is part of the second NALU.
0x00, 0x00, 0x01,
};
NaluReader reader(NaluReader::kH264, kIsAnnexbByteStream, kNaluData,
arraysize(kNaluData));
Nalu nalu;
ASSERT_EQ(NaluReader::kOk, reader.Advance(&nalu));
EXPECT_EQ(kNaluData + 9, nalu.data());
EXPECT_EQ(11u, nalu.payload_size());
EXPECT_EQ(1u, nalu.header_size());
EXPECT_EQ(0, nalu.ref_idc());
EXPECT_EQ(0x14, nalu.type());
ASSERT_EQ(NaluReader::kOk, reader.Advance(&nalu));
EXPECT_EQ(kNaluData + 24, nalu.data());
EXPECT_EQ(5u, nalu.payload_size());
EXPECT_EQ(1u, nalu.header_size());
EXPECT_EQ(3, nalu.ref_idc());
EXPECT_EQ(7, nalu.type());
EXPECT_EQ(NaluReader::kEOStream, reader.Advance(&nalu));
}
TEST(NaluReaderTest, OneByteNaluLength) { TEST(NaluReaderTest, OneByteNaluLength) {
const uint8_t kNaluData[] = { const uint8_t kNaluData[] = {
// First NALU // First NALU
0x05, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x01, 0x02, 0x03, 0x04,
// Second NALU // Second NALU
0x06, 0x67, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e 0x06, 0x67, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
}; };
NaluReader reader(NaluReader::kH264, 1, kNaluData, arraysize(kNaluData)); NaluReader reader(NaluReader::kH264, 1, kNaluData, arraysize(kNaluData));
@ -57,7 +91,7 @@ TEST(NaluReaderTest, OneByteNaluLength) {
EXPECT_EQ(4u, nalu.payload_size()); EXPECT_EQ(4u, nalu.payload_size());
EXPECT_EQ(1u, nalu.header_size()); EXPECT_EQ(1u, nalu.header_size());
EXPECT_EQ(0, nalu.ref_idc()); EXPECT_EQ(0, nalu.ref_idc());
EXPECT_EQ(8, nalu.type()); EXPECT_EQ(6, nalu.type());
ASSERT_EQ(NaluReader::kOk, reader.Advance(&nalu)); ASSERT_EQ(NaluReader::kOk, reader.Advance(&nalu));
EXPECT_EQ(kNaluData + 7, nalu.data()); EXPECT_EQ(kNaluData + 7, nalu.data());
@ -72,9 +106,9 @@ TEST(NaluReaderTest, OneByteNaluLength) {
TEST(NaluReaderTest, FourByteNaluLength) { TEST(NaluReaderTest, FourByteNaluLength) {
const uint8_t kNaluData[] = { const uint8_t kNaluData[] = {
// First NALU // First NALU
0x00, 0x00, 0x00, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x00, 0x00, 0x00, 0x07, 0x06, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
// Second NALU // Second NALU
0x00, 0x00, 0x00, 0x03, 0x67, 0x0a, 0x0b 0x00, 0x00, 0x00, 0x03, 0x67, 0x0a, 0x0b,
}; };
NaluReader reader(NaluReader::kH264, 4, kNaluData, arraysize(kNaluData)); NaluReader reader(NaluReader::kH264, 4, kNaluData, arraysize(kNaluData));
@ -85,7 +119,7 @@ TEST(NaluReaderTest, FourByteNaluLength) {
EXPECT_EQ(6u, nalu.payload_size()); EXPECT_EQ(6u, nalu.payload_size());
EXPECT_EQ(1u, nalu.header_size()); EXPECT_EQ(1u, nalu.header_size());
EXPECT_EQ(0, nalu.ref_idc()); EXPECT_EQ(0, nalu.ref_idc());
EXPECT_EQ(8, nalu.type()); EXPECT_EQ(6, nalu.type());
ASSERT_EQ(NaluReader::kOk, reader.Advance(&nalu)); ASSERT_EQ(NaluReader::kOk, reader.Advance(&nalu));
EXPECT_EQ(kNaluData + 15, nalu.data()); EXPECT_EQ(kNaluData + 15, nalu.data());
@ -100,7 +134,7 @@ TEST(NaluReaderTest, FourByteNaluLength) {
TEST(NaluReaderTest, ErrorForNotEnoughForNaluLength) { TEST(NaluReaderTest, ErrorForNotEnoughForNaluLength) {
const uint8_t kNaluData[] = { const uint8_t kNaluData[] = {
// First NALU // First NALU
0x00 0x00,
}; };
NaluReader reader(NaluReader::kH264, 3, kNaluData, arraysize(kNaluData)); NaluReader reader(NaluReader::kH264, 3, kNaluData, arraysize(kNaluData));
@ -112,7 +146,7 @@ TEST(NaluReaderTest, ErrorForNotEnoughForNaluLength) {
TEST(NaluReaderTest, ErrorForNaluLengthExceedsRemainingData) { TEST(NaluReaderTest, ErrorForNaluLengthExceedsRemainingData) {
const uint8_t kNaluData[] = { const uint8_t kNaluData[] = {
// First NALU // First NALU
0xFF, 0x08, 0x00 0xFF, 0x08, 0x00,
}; };
NaluReader reader(NaluReader::kH264, 1, kNaluData, arraysize(kNaluData)); NaluReader reader(NaluReader::kH264, 1, kNaluData, arraysize(kNaluData));
@ -123,7 +157,7 @@ TEST(NaluReaderTest, ErrorForNaluLengthExceedsRemainingData) {
// Another test for off by one. // Another test for off by one.
const uint8_t kNaluData2[] = { const uint8_t kNaluData2[] = {
// First NALU // First NALU
0x04, 0x08, 0x00, 0x00 0x04, 0x08, 0x00, 0x00,
}; };
NaluReader reader2(NaluReader::kH264, 1, kNaluData2, arraysize(kNaluData2)); NaluReader reader2(NaluReader::kH264, 1, kNaluData2, arraysize(kNaluData2));
@ -133,7 +167,7 @@ TEST(NaluReaderTest, ErrorForNaluLengthExceedsRemainingData) {
TEST(NaluReaderTest, ErrorForForbiddenBitSet) { TEST(NaluReaderTest, ErrorForForbiddenBitSet) {
const uint8_t kNaluData[] = { const uint8_t kNaluData[] = {
// First NALU // First NALU
0x03, 0x80, 0x00, 0x00 0x03, 0x80, 0x00, 0x00,
}; };
NaluReader reader(NaluReader::kH264, 1, kNaluData, arraysize(kNaluData)); NaluReader reader(NaluReader::kH264, 1, kNaluData, arraysize(kNaluData));
@ -145,7 +179,7 @@ TEST(NaluReaderTest, ErrorForForbiddenBitSet) {
TEST(NaluReaderTest, ErrorForZeroSize) { TEST(NaluReaderTest, ErrorForZeroSize) {
const uint8_t kNaluData[] = { const uint8_t kNaluData[] = {
// First NALU // First NALU
0x03, 0x80, 0x00, 0x00 0x03, 0x80, 0x00, 0x00,
}; };
Nalu nalu; Nalu nalu;

View File

@ -70,15 +70,15 @@ EncryptingFragmenter::EncryptingFragmenter(
info_(info), info_(info),
encryption_key_(encryption_key.Pass()), encryption_key_(encryption_key.Pass()),
nalu_length_size_(GetNaluLengthSize(*info)), nalu_length_size_(GetNaluLengthSize(*info)),
video_codec_(GetVideoCodec(*info)),
clear_time_(clear_time), clear_time_(clear_time),
encryption_mode_(encryption_mode) { encryption_mode_(encryption_mode) {
DCHECK(encryption_key_); DCHECK(encryption_key_);
VideoCodec video_codec = GetVideoCodec(*info); if (video_codec_ == kCodecVP8) {
if (video_codec == kCodecVP8) {
vpx_parser_.reset(new VP8Parser); vpx_parser_.reset(new VP8Parser);
} else if (video_codec == kCodecVP9) { } else if (video_codec_ == kCodecVP9) {
vpx_parser_.reset(new VP9Parser); vpx_parser_.reset(new VP9Parser);
} else if (video_codec == kCodecH264) { } else if (video_codec_ == kCodecH264) {
header_parser_.reset(new H264VideoSliceHeaderParser); header_parser_.reset(new H264VideoSliceHeaderParser);
} }
// TODO(modmaker): Support H.265. // TODO(modmaker): Support H.265.
@ -231,8 +231,10 @@ Status EncryptingFragmenter::EncryptSample(scoped_refptr<MediaSample> sample) {
data += frame.frame_size; data += frame.frame_size;
} }
} else { } else {
// TODO(modmaker): Support H.265. const NaluReader::NaluType nalu_type =
const NaluReader::NaluType nalu_type = NaluReader::kH264; (video_codec_ == kCodecHVC1 || video_codec_ == kCodecHEV1)
? NaluReader::kH265
: NaluReader::kH264;
NaluReader reader(nalu_type, nalu_length_size_, data, NaluReader reader(nalu_type, nalu_length_size_, data,
sample->data_size()); sample->data_size());

View File

@ -78,6 +78,7 @@ class EncryptingFragmenter : public Fragmenter {
// and type of NAL units remain unencrypted. This function returns the size of // and type of NAL units remain unencrypted. This function returns the size of
// the size field in bytes. Can be 1, 2 or 4 bytes. // the size field in bytes. Can be 1, 2 or 4 bytes.
const uint8_t nalu_length_size_; const uint8_t nalu_length_size_;
const VideoCodec video_codec_;
int64_t clear_time_; int64_t clear_time_;
EncryptionMode encryption_mode_; EncryptionMode encryption_mode_;