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:
parent
764c7077a2
commit
8767d20f38
Binary file not shown.
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Reference in New Issue