diff --git a/media/parsers/h265_parser_unittest.cc b/media/parsers/h265_parser_unittest.cc index 62e00608e5492..640fa08f0574d 100644 --- a/media/parsers/h265_parser_unittest.cc +++ b/media/parsers/h265_parser_unittest.cc @@ -634,4 +634,79 @@ TEST_F(H265ParserTest, ValidSubLayerCount) { EXPECT_NE(H265Parser::kOk, parser.ParseVPS(&unused_vps_id)); } +// POC: H265Parser accepts CtbLog2SizeY=30 (spec max 6) and derived +// max_transform_hierarchy_depth_{inter,intra}=28 (spec max 4), +// diff_cu_qp_delta_depth=27 (spec max 3), +// log2_parallel_merge_level_minus2=28 (spec max 4). These reach the +// VAAPI/V4L2 driver verbatim with no re-clamp (CWE-1284). +TEST_F(H265ParserTest, AcceptsOutOfSpecCtbLog2SizeY) { + constexpr auto kStream = std::to_array({ + // VPS + 0x00, 0x00, 0x00, 0x01, 0x40, 0x01, 0x0c, 0x01, 0xff, 0xff, 0x01, 0x60, + 0x00, 0x00, 0x03, 0x00, 0x80, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, + 0x5d, 0xac, 0x09, + // SPS: log2_diff_max_min_luma_coding_block_size=27 -> CtbLog2SizeY=30 + 0x00, 0x00, 0x00, 0x01, 0x42, 0x01, 0x01, 0x01, 0x60, 0x00, 0x00, 0x03, + 0x00, 0x80, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x5d, 0xa0, 0x0a, + 0x08, 0x0f, 0x17, 0xae, 0x1c, 0x90, 0x3a, 0x1d, 0x08, 0x20, + // PPS: diff_cu_qp_delta_depth=27, log2_parallel_merge_level_minus2=28 + 0x00, 0x00, 0x00, 0x01, 0x44, 0x01, 0xc0, 0x72, 0x1c, 0xc0, 0x00, 0xe9, + // IDR_W_RADL + 0x00, 0x00, 0x00, 0x01, 0x26, 0x01, 0xaf, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + }); + H265Parser parser; + parser.SetStream(kStream); + + H265NALU nalu; + ASSERT_EQ(H265Parser::kOk, parser.AdvanceToNextNALU(&nalu)); + ASSERT_EQ(nalu.nal_unit_type, H265NALU::VPS_NUT); + int vps_id; + ASSERT_EQ(H265Parser::kOk, parser.ParseVPS(&vps_id)); + + ASSERT_EQ(H265Parser::kOk, parser.AdvanceToNextNALU(&nalu)); + ASSERT_EQ(nalu.nal_unit_type, H265NALU::SPS_NUT); + int sps_id; + // BUG: ParseSPS accepts CtbLog2SizeY=30. H.265 7.4.3.2.1 / Annex A + // require CtbLog2SizeY in [4,6]; ffmpeg rejects >6. + ASSERT_EQ(H265Parser::kOk, parser.ParseSPS(&sps_id)); + const H265SPS* sps = parser.GetSPS(sps_id); + ASSERT_TRUE(sps); + EXPECT_EQ(0, sps->log2_min_luma_coding_block_size_minus3); + EXPECT_EQ(27, sps->log2_diff_max_min_luma_coding_block_size); // spec max 3 + EXPECT_EQ(30, sps->ctb_log2_size_y); // spec max 6 + EXPECT_EQ(28, sps->max_transform_hierarchy_depth_inter); // spec max 4 + EXPECT_EQ(28, sps->max_transform_hierarchy_depth_intra); // spec max 4 + + ASSERT_EQ(H265Parser::kOk, parser.AdvanceToNextNALU(&nalu)); + ASSERT_EQ(nalu.nal_unit_type, H265NALU::PPS_NUT); + int pps_id; + ASSERT_EQ(H265Parser::kOk, parser.ParsePPS(nalu, &pps_id)); + const H265PPS* pps = parser.GetPPS(pps_id); + ASSERT_TRUE(pps); + EXPECT_EQ(27, pps->diff_cu_qp_delta_depth); // spec max 3 + EXPECT_EQ(28, pps->log2_parallel_merge_level_minus2); // spec max 4 + + ASSERT_EQ(H265Parser::kOk, parser.AdvanceToNextNALU(&nalu)); + ASSERT_EQ(nalu.nal_unit_type, H265NALU::IDR_W_RADL); + H265SliceHeader shdr; + // The slice header also parses cleanly -> H265Decoder would call + // SubmitFrameMetadata() with these out-of-spec values, which the VAAPI/V4L2 + // delegates copy verbatim into uint8_t/__u8 driver fields. + ASSERT_EQ(H265Parser::kOk, parser.ParseSliceHeader(nalu, &shdr, nullptr)); + + fprintf(stderr, + "[POC] H265Parser accepted out-of-spec values:\n" + " ctb_log2_size_y=%d (spec max 6)\n" + " log2_diff_max_min_luma_coding_block_size=%d (spec max 3)\n" + " max_transform_hierarchy_depth_inter=%d (spec max 4)\n" + " max_transform_hierarchy_depth_intra=%d (spec max 4)\n" + " diff_cu_qp_delta_depth=%d (spec max 3)\n" + " log2_parallel_merge_level_minus2=%d (spec max 4)\n", + sps->ctb_log2_size_y, sps->log2_diff_max_min_luma_coding_block_size, + sps->max_transform_hierarchy_depth_inter, + sps->max_transform_hierarchy_depth_intra, + pps->diff_cu_qp_delta_depth, pps->log2_parallel_merge_level_minus2); +} + } // namespace media