Fix potential slice header size off by one byte in H265

In H265Parser::ParseSliceHeader, the parser does not handle
byte_alignment() from the spec. byte_alignment() reportedly contains
at least one bit, which is not handled right now.

See Section 7.3.2.12 Rec. ITU-T H.265 v3 (04/2015).

Also added a few size sanity checks in H265Parser to make sure the
code does not crash if an invalid input is provided.

Fixes #383.

Change-Id: I33b31396058fc5ba67a0fc119be5fe56ec9443b0
This commit is contained in:
KongQun Yang 2018-04-24 14:28:38 -07:00
parent 764c7077a2
commit 8767d20f38
5 changed files with 18 additions and 2 deletions

View File

@ -236,6 +236,8 @@ H265Parser::Result H265Parser::ParseSliceHeader(const Nalu& nalu,
TRUE_OR_RETURN( TRUE_OR_RETURN(
br->ReadBits(ceil(log2(sps->num_short_term_ref_pic_sets)), br->ReadBits(ceil(log2(sps->num_short_term_ref_pic_sets)),
&slice_header->short_term_ref_pic_set_idx)); &slice_header->short_term_ref_pic_set_idx));
TRUE_OR_RETURN(slice_header->short_term_ref_pic_set_idx <
sps->num_short_term_ref_pic_sets);
} }
if (sps->long_term_ref_pic_present_flag) { if (sps->long_term_ref_pic_present_flag) {
@ -390,6 +392,8 @@ H265Parser::Result H265Parser::ParseSliceHeader(const Nalu& nalu,
TRUE_OR_RETURN(br->SkipBits(extension_length * 8)); TRUE_OR_RETURN(br->SkipBits(extension_length * 8));
} }
OK_OR_RETURN(ByteAlignment(br));
slice_header->header_bit_size = nalu.payload_size() * 8 - br->NumBitsLeft(); slice_header->header_bit_size = nalu.payload_size() * 8 - br->NumBitsLeft();
return kOk; return kOk;
} }
@ -832,7 +836,9 @@ H265Parser::Result H265Parser::ParseReferencePictureSet(
} }
} else { } else {
TRUE_OR_RETURN(br->ReadUE(&out_ref_pic_set->num_negative_pics)); TRUE_OR_RETURN(br->ReadUE(&out_ref_pic_set->num_negative_pics));
TRUE_OR_RETURN(out_ref_pic_set->num_negative_pics <= kMaxRefPicSetCount);
TRUE_OR_RETURN(br->ReadUE(&out_ref_pic_set->num_positive_pics)); TRUE_OR_RETURN(br->ReadUE(&out_ref_pic_set->num_positive_pics));
TRUE_OR_RETURN(out_ref_pic_set->num_positive_pics <= kMaxRefPicSetCount);
int prev_poc = 0; int prev_poc = 0;
for (int i = 0; i < out_ref_pic_set->num_negative_pics; i++) { for (int i = 0; i < out_ref_pic_set->num_negative_pics; i++) {
@ -1107,5 +1113,11 @@ H265Parser::Result H265Parser::SkipSubLayerHrdParameters(
return kOk; return kOk;
} }
H265Parser::Result H265Parser::ByteAlignment(H26xBitReader* br) {
TRUE_OR_RETURN(br->SkipBits(1));
TRUE_OR_RETURN(br->SkipBits(br->NumBitsLeft() % 8));
return kOk;
}
} // namespace media } // namespace media
} // namespace shaka } // namespace shaka

View File

@ -351,6 +351,8 @@ class H265Parser {
bool sub_pic_hdr_params_present_flag, bool sub_pic_hdr_params_present_flag,
H26xBitReader* br); H26xBitReader* br);
Result ByteAlignment(H26xBitReader* br);
typedef std::map<int, std::unique_ptr<H265Sps>> SpsById; typedef std::map<int, std::unique_ptr<H265Sps>> SpsById;
typedef std::map<int, std::unique_ptr<H265Pps>> PpsById; typedef std::map<int, std::unique_ptr<H265Pps>> PpsById;

View File

@ -55,7 +55,7 @@ TEST(H265ParserTest, ParseSliceHeader) {
EXPECT_EQ(8, header.slice_qp_delta); EXPECT_EQ(8, header.slice_qp_delta);
EXPECT_FALSE(header.cu_chroma_qp_offset_enabled_flag); EXPECT_FALSE(header.cu_chroma_qp_offset_enabled_flag);
EXPECT_EQ(5, header.num_entry_point_offsets); EXPECT_EQ(5, header.num_entry_point_offsets);
EXPECT_EQ(85u, header.header_bit_size); EXPECT_EQ(88u, header.header_bit_size);
} }
TEST(H265ParserTest, ParseSliceHeader_NonIDR) { TEST(H265ParserTest, ParseSliceHeader_NonIDR) {
@ -81,7 +81,7 @@ TEST(H265ParserTest, ParseSliceHeader_NonIDR) {
EXPECT_FALSE(header.dependent_slice_segment_flag); EXPECT_FALSE(header.dependent_slice_segment_flag);
EXPECT_EQ(1, header.slice_type); EXPECT_EQ(1, header.slice_type);
EXPECT_EQ(5, header.num_entry_point_offsets); EXPECT_EQ(5, header.num_entry_point_offsets);
EXPECT_EQ(124u, header.header_bit_size); EXPECT_EQ(128u, header.header_bit_size);
} }
TEST(H265ParserTest, ParseSps) { TEST(H265ParserTest, ParseSps) {

View File

@ -95,6 +95,8 @@ TEST(H26xBitReaderTest, SkipBits) {
EXPECT_EQ(0x15, dummy); EXPECT_EQ(0x15, dummy);
EXPECT_EQ(4, reader.NumBitsLeft()); EXPECT_EQ(4, reader.NumBitsLeft());
EXPECT_FALSE(reader.SkipBits(5)); EXPECT_FALSE(reader.SkipBits(5));
EXPECT_TRUE(reader.SkipBits(0));
EXPECT_EQ(4, reader.NumBitsLeft());
} }
TEST(H26xBitReaderTest, StopBitOccupyFullByte) { TEST(H26xBitReaderTest, StopBitOccupyFullByte) {