Commit c224fbc5 authored by Jeffrey Kardatzke's avatar Jeffrey Kardatzke Committed by Commit Bot

Expand testing for H265Parser

Expands testing in a few ways:
1. Adds an additional test file to fully parse.
2. Checks validity of parsed fields in SPS.
3. Adds a fuzzer (it even found a bug already).

BUG=chromium:1141237,b:153111783
TEST=media_unittests pass, fuzzer builds/runs

Change-Id: I3036c2e28466e460ba35647bea38fd53d491b844
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2495344Reviewed-by: default avatarDale Curtis <dalecurtis@chromium.org>
Commit-Queue: Jeffrey Kardatzke <jkardatzke@google.com>
Cr-Commit-Position: refs/heads/master@{#820455}
parent ad67ec1e
......@@ -880,6 +880,15 @@ Created using "avconv -i bear-vp9.webm -vcodec copy -an -f ivf bear-vp9.ivf".
Manually dumped from libvpx with bear-vp9.ivf and test-25fps.vp9. See
vp9_parser_unittest.cc for description of their format.
### HEVC parser test files:
#### bear.hevc
Used by h265_parser_unittest.cc.
#### bbb.hevc
Used by h265_parser_unittest.cc. Copied from bbb_hevc_176x144_176kbps_60fps.hevc
in Android repo.
### WebM files for testing multiple tracks.
#### green-a300hz.webm
......
......@@ -154,3 +154,15 @@ fuzzer_test("media_h264_parser_fuzzer") {
"//ui/gfx/geometry",
]
}
# TODO(jkardatzke): Get the fuzzer build config updated so this target will
# be included.
if (proprietary_codecs && enable_platform_hevc) {
fuzzer_test("media_h265_parser_fuzzer") {
sources = [ "h265_parser_fuzzertest.cc" ]
deps = [
"//base",
"//media",
]
}
}
......@@ -699,11 +699,11 @@ H265Parser::Result H265Parser::ParseScalingListData(
dst = scaling_list_data->scaling_list_8x8[matrix_id];
break;
case 2:
dst = scaling_list_data->scaling_list_16x16[ref_matrix_id];
src = scaling_list_data->scaling_list_16x16[ref_matrix_id];
dst = scaling_list_data->scaling_list_16x16[matrix_id];
break;
case 3:
dst = scaling_list_data->scaling_list_32x32[ref_matrix_id];
src = scaling_list_data->scaling_list_32x32[ref_matrix_id];
dst = scaling_list_data->scaling_list_32x32[matrix_id];
break;
}
......
......@@ -10,9 +10,9 @@
#include <stdint.h>
#include <sys/types.h>
#include <map>
#include <vector>
#include "base/containers/flat_map.h"
#include "base/macros.h"
#include "media/base/media_export.h"
#include "media/base/ranges.h"
......@@ -181,7 +181,6 @@ struct MEDIA_EXPORT H265SPS {
// Syntax elements.
int sps_max_sub_layers_minus1;
bool sps_temporal_id_nesting_flag;
H265ProfileTierLevel profile_tier_level;
int sps_seq_parameter_set_id;
int chroma_format_idc;
......@@ -321,7 +320,7 @@ class MEDIA_EXPORT H265Parser {
H264BitReader br_;
// SPSes stored for future reference.
std::map<int, std::unique_ptr<H265SPS>> active_sps_;
base::flat_map<int, std::unique_ptr<H265SPS>> active_sps_;
// Ranges of encrypted bytes in the buffer passed to SetEncryptedStream().
Ranges<const uint8_t*> encrypted_ranges_;
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stddef.h>
#include "base/numerics/safe_conversions.h"
#include "base/optional.h"
#include "media/video/h265_parser.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
// Entry point for LibFuzzer.
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
if (!size)
return 0;
media::H265Parser parser;
parser.SetStream(data, base::checked_cast<off_t>(size));
// Parse until the end of stream/unsupported stream/error in stream is
// found.
while (true) {
media::H265NALU nalu;
media::H265Parser::Result res = parser.AdvanceToNextNALU(&nalu);
if (res != media::H265Parser::kOk)
break;
switch (nalu.nal_unit_type) {
case media::H265NALU::SPS_NUT:
int sps_id;
res = parser.ParseSPS(&sps_id);
break;
default:
// Skip any other NALU.
break;
}
if (res != media::H265Parser::kOk)
break;
}
return 0;
}
......@@ -2,53 +2,147 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "media/video/h265_parser.h"
#include <memory>
#include <string>
#include "base/files/file_path.h"
#include "base/files/memory_mapped_file.h"
#include "base/logging.h"
#include "media/base/test_data_util.h"
#include "media/video/h265_parser.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace media {
TEST(H265ParserTest, RawHevcStreamFileParsing) {
base::FilePath file_path = GetTestDataFilePath("bear.hevc");
namespace {
struct HevcTestData {
std::string file_name;
// Number of NALUs in the test stream to be parsed.
const int num_nalus = 35;
base::MemoryMappedFile stream;
ASSERT_TRUE(stream.Initialize(file_path))
<< "Couldn't open stream file: " << file_path.MaybeAsASCII();
H265Parser parser;
parser.SetStream(stream.data(), stream.length());
// Parse until the end of stream/unsupported stream/error in stream is found.
int num_parsed_nalus = 0;
while (true) {
H265NALU nalu;
H265Parser::Result res = parser.AdvanceToNextNALU(&nalu);
if (res == H265Parser::kEOStream) {
DVLOG(1) << "Number of successfully parsed NALUs before EOS: "
<< num_parsed_nalus;
ASSERT_EQ(num_nalus, num_parsed_nalus);
return;
int num_nalus;
};
} // namespace
class H265ParserTest : public ::testing::Test {
protected:
void LoadParserFile(std::string file_name) {
parser_.Reset();
base::FilePath file_path = GetTestDataFilePath(file_name);
stream_ = std::make_unique<base::MemoryMappedFile>();
ASSERT_TRUE(stream_->Initialize(file_path))
<< "Couldn't open stream file: " << file_path.MaybeAsASCII();
parser_.SetStream(stream_->data(), stream_->length());
}
bool ParseNalusUntilNut(H265NALU::Type nalu_type) {
while (true) {
H265NALU nalu;
H265Parser::Result res = parser_.AdvanceToNextNALU(&nalu);
if (res == H265Parser::kEOStream) {
return false;
}
EXPECT_EQ(res, H265Parser::kOk);
if (nalu.nal_unit_type == nalu_type)
return true;
}
ASSERT_EQ(res, H265Parser::kOk);
}
++num_parsed_nalus;
DVLOG(4) << "Found NALU " << nalu.nal_unit_type;
H265Parser parser_;
std::unique_ptr<base::MemoryMappedFile> stream_;
};
switch (nalu.nal_unit_type) {
case H265NALU::SPS_NUT:
int sps_id;
res = parser.ParseSPS(&sps_id);
ASSERT_TRUE(!!parser.GetSPS(sps_id));
break;
default:
TEST_F(H265ParserTest, RawHevcStreamFileParsing) {
HevcTestData test_data[] = {
{"bear.hevc", 35},
{"bbb.hevc", 64},
};
for (auto& data : test_data) {
LoadParserFile(data.file_name);
// Parse until the end of stream/unsupported stream/error in stream is
// found.
int num_parsed_nalus = 0;
while (true) {
H265NALU nalu;
H265Parser::Result res = parser_.AdvanceToNextNALU(&nalu);
if (res == H265Parser::kEOStream) {
DVLOG(1) << "Number of successfully parsed NALUs before EOS: "
<< num_parsed_nalus;
EXPECT_EQ(data.num_nalus, num_parsed_nalus);
break;
}
EXPECT_EQ(res, H265Parser::kOk);
++num_parsed_nalus;
DVLOG(4) << "Found NALU " << nalu.nal_unit_type;
switch (nalu.nal_unit_type) {
case H265NALU::SPS_NUT:
int sps_id;
res = parser_.ParseSPS(&sps_id);
EXPECT_TRUE(!!parser_.GetSPS(sps_id));
break;
default:
break;
}
EXPECT_EQ(res, H265Parser::kOk);
}
ASSERT_EQ(res, H265Parser::kOk);
}
}
TEST_F(H265ParserTest, SpsParsing) {
LoadParserFile("bear.hevc");
EXPECT_TRUE(ParseNalusUntilNut(H265NALU::SPS_NUT));
int sps_id;
EXPECT_EQ(H265Parser::kOk, parser_.ParseSPS(&sps_id));
const H265SPS* sps = parser_.GetSPS(sps_id);
EXPECT_TRUE(!!sps);
EXPECT_EQ(sps->sps_max_sub_layers_minus1, 0);
EXPECT_EQ(sps->profile_tier_level.general_profile_idc, 1);
EXPECT_EQ(sps->profile_tier_level.general_level_idc, 60);
EXPECT_EQ(sps->sps_seq_parameter_set_id, 0);
EXPECT_EQ(sps->chroma_format_idc, 1);
EXPECT_FALSE(sps->separate_colour_plane_flag);
EXPECT_EQ(sps->pic_width_in_luma_samples, 320);
EXPECT_EQ(sps->pic_height_in_luma_samples, 184);
EXPECT_EQ(sps->conf_win_left_offset, 0);
EXPECT_EQ(sps->conf_win_right_offset, 0);
EXPECT_EQ(sps->conf_win_top_offset, 0);
EXPECT_EQ(sps->conf_win_bottom_offset, 2);
EXPECT_EQ(sps->bit_depth_luma_minus8, 0);
EXPECT_EQ(sps->bit_depth_chroma_minus8, 0);
EXPECT_EQ(sps->log2_max_pic_order_cnt_lsb_minus4, 4);
EXPECT_EQ(sps->sps_max_dec_pic_buffering_minus1[0], 4);
EXPECT_EQ(sps->sps_max_num_reorder_pics[0], 2);
EXPECT_EQ(sps->sps_max_latency_increase_plus1[0], 0);
for (int i = 1; i < kMaxSubLayers; ++i) {
EXPECT_EQ(sps->sps_max_dec_pic_buffering_minus1[i], 0);
EXPECT_EQ(sps->sps_max_num_reorder_pics[i], 0);
EXPECT_EQ(sps->sps_max_latency_increase_plus1[i], 0);
}
EXPECT_EQ(sps->log2_min_luma_coding_block_size_minus3, 0);
EXPECT_EQ(sps->log2_diff_max_min_luma_coding_block_size, 3);
EXPECT_EQ(sps->log2_min_luma_transform_block_size_minus2, 0);
EXPECT_EQ(sps->log2_diff_max_min_luma_transform_block_size, 3);
EXPECT_EQ(sps->max_transform_hierarchy_depth_inter, 0);
EXPECT_EQ(sps->max_transform_hierarchy_depth_intra, 0);
EXPECT_FALSE(sps->scaling_list_enabled_flag);
EXPECT_FALSE(sps->sps_scaling_list_data_present_flag);
EXPECT_FALSE(sps->amp_enabled_flag);
EXPECT_TRUE(sps->sample_adaptive_offset_enabled_flag);
EXPECT_FALSE(sps->pcm_enabled_flag);
EXPECT_EQ(sps->pcm_sample_bit_depth_luma_minus1, 0);
EXPECT_EQ(sps->pcm_sample_bit_depth_chroma_minus1, 0);
EXPECT_EQ(sps->log2_min_pcm_luma_coding_block_size_minus3, 0);
EXPECT_EQ(sps->log2_diff_max_min_pcm_luma_coding_block_size, 0);
EXPECT_FALSE(sps->pcm_loop_filter_disabled_flag);
EXPECT_EQ(sps->num_short_term_ref_pic_sets, 0);
EXPECT_FALSE(sps->long_term_ref_pics_present_flag);
EXPECT_EQ(sps->num_long_term_ref_pics_sps, 0);
EXPECT_TRUE(sps->sps_temporal_mvp_enabled_flag);
EXPECT_TRUE(sps->strong_intra_smoothing_enabled_flag);
}
} // namespace media
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment