Commit 5a3ffeb6 authored by Hirokazu Honda's avatar Hirokazu Honda Committed by Chromium LUCI CQ

media/gpu/video_encode_accelerator_tests: Validates each temporal layer stream

The test originally validates the entire bitstream. This CL
enables the test to validate each temporal layer stream. For
instance, when --num_temporal_layers=3, the test validates three
streams, TL0, TL0+TL1 and TL0+TL1+TL2.
BitstreamFileWriter and VideoFrameFileWriter ignore bitstreams
and frames in upper layers than to be processed by them.
VideoFrameFileWriter also writes a file with a different prefix
from other VideoFrameFileWriter, so that multiple instances don't
write to the same file names.

Bug: b:174318867
Test: video_encode_accelerator_tests --codec=vp9 --num_temporal_layers=3 w/o output_bitstream --output_images=all
Change-Id: Idf2a1e4d2a50e11ca359435ec4495a43b61139f9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2562801Reviewed-by: default avatarDavid Staessens <dstaessens@chromium.org>
Commit-Queue: Hirokazu Honda <hiroh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#833103}
parent c4f0c4ff
......@@ -39,8 +39,10 @@ class BitstreamFileWriter::FrameFileWriter {
};
BitstreamFileWriter::BitstreamFileWriter(
std::unique_ptr<FrameFileWriter> frame_file_writer)
std::unique_ptr<FrameFileWriter> frame_file_writer,
base::Optional<size_t> num_vp9_temporal_layers_to_write)
: frame_file_writer_(std::move(frame_file_writer)),
num_vp9_temporal_layers_to_write_(num_vp9_temporal_layers_to_write),
num_buffers_writing_(0),
num_errors_(0),
writer_thread_("BitstreamFileWriterThread"),
......@@ -59,7 +61,8 @@ std::unique_ptr<BitstreamFileWriter> BitstreamFileWriter::Create(
VideoCodec codec,
const gfx::Size& resolution,
uint32_t frame_rate,
uint32_t num_frames) {
uint32_t num_frames,
base::Optional<size_t> num_vp9_temporal_layers_to_write) {
std::unique_ptr<FrameFileWriter> frame_file_writer;
if (!base::DirectoryExists(output_filepath.DirName()))
base::CreateDirectory(output_filepath.DirName());
......@@ -82,8 +85,8 @@ std::unique_ptr<BitstreamFileWriter> BitstreamFileWriter::Create(
std::make_unique<FrameFileWriter>(std::move(ivf_writer));
}
auto bitstream_file_writer =
base::WrapUnique(new BitstreamFileWriter(std::move(frame_file_writer)));
auto bitstream_file_writer = base::WrapUnique(new BitstreamFileWriter(
std::move(frame_file_writer), num_vp9_temporal_layers_to_write));
if (!bitstream_file_writer->writer_thread_.Start()) {
LOG(ERROR) << "Failed to start file writer thread";
return nullptr;
......@@ -95,6 +98,14 @@ std::unique_ptr<BitstreamFileWriter> BitstreamFileWriter::Create(
void BitstreamFileWriter::ProcessBitstream(
scoped_refptr<BitstreamRef> bitstream,
size_t frame_index) {
if (num_vp9_temporal_layers_to_write_ &&
bitstream->metadata.vp9->temporal_idx >=
*num_vp9_temporal_layers_to_write_) {
// Skip |bitstream| because it contains a frame in upper layers than layers
// to be saved.
return;
}
base::AutoLock auto_lock(writer_lock_);
num_buffers_writing_++;
writer_thread_.task_runner()->PostTask(
......
......@@ -26,7 +26,8 @@ class BitstreamFileWriter : public BitstreamProcessor {
VideoCodec codec,
const gfx::Size& resolution,
uint32_t frame_rate,
uint32_t num_frames);
uint32_t num_frames,
base::Optional<size_t> num_vp9_temporal_layers_to_write = base::nullopt);
BitstreamFileWriter(const BitstreamFileWriter&) = delete;
BitstreamFileWriter operator=(const BitstreamFileWriter&) = delete;
~BitstreamFileWriter() override;
......@@ -37,11 +38,13 @@ class BitstreamFileWriter : public BitstreamProcessor {
private:
class FrameFileWriter;
BitstreamFileWriter(std::unique_ptr<FrameFileWriter> frame_file_writer);
BitstreamFileWriter(std::unique_ptr<FrameFileWriter> frame_file_writer,
base::Optional<size_t> num_vp9_temporal_layers_to_write_);
void WriteBitstreamTask(scoped_refptr<BitstreamRef> bitstream,
size_t frame_index);
const std::unique_ptr<FrameFileWriter> frame_file_writer_;
const base::Optional<size_t> num_vp9_temporal_layers_to_write_;
// The number of buffers currently queued for writing.
size_t num_buffers_writing_ GUARDED_BY(writer_lock_);
......
......@@ -49,14 +49,16 @@ std::unique_ptr<VideoDecoder> CreateDecoder(VideoCodec codec) {
std::unique_ptr<BitstreamValidator> BitstreamValidator::Create(
const VideoDecoderConfig& decoder_config,
size_t last_frame_index,
std::vector<std::unique_ptr<VideoFrameProcessor>> video_frame_processors) {
std::vector<std::unique_ptr<VideoFrameProcessor>> video_frame_processors,
base::Optional<size_t> num_vp9_temporal_layers_to_decode) {
std::unique_ptr<VideoDecoder> decoder;
decoder = CreateDecoder(decoder_config.codec());
if (!decoder)
return nullptr;
auto validator = base::WrapUnique(new BitstreamValidator(
std::move(decoder), last_frame_index, std::move(video_frame_processors)));
std::move(decoder), last_frame_index, num_vp9_temporal_layers_to_decode,
std::move(video_frame_processors)));
if (!validator->Initialize(decoder_config))
return nullptr;
return validator;
......@@ -104,9 +106,11 @@ void BitstreamValidator::InitializeVideoDecoder(
BitstreamValidator::BitstreamValidator(
std::unique_ptr<VideoDecoder> decoder,
size_t last_frame_index,
base::Optional<size_t> num_vp9_temporal_layers_to_decode,
std::vector<std::unique_ptr<VideoFrameProcessor>> video_frame_processors)
: decoder_(std::move(decoder)),
last_frame_index_(last_frame_index),
num_vp9_temporal_layers_to_decode_(num_vp9_temporal_layers_to_decode),
video_frame_processors_(std::move(video_frame_processors)),
validator_thread_("BitstreamValidatorThread"),
validator_cv_(&validator_lock_),
......@@ -133,16 +137,26 @@ void BitstreamValidator::ProcessBitstreamTask(
scoped_refptr<BitstreamRef> bitstream,
size_t frame_index) {
SEQUENCE_CHECKER(validator_thread_sequence_checker_);
scoped_refptr<DecoderBuffer> buffer = bitstream->buffer;
int64_t timestamp = buffer->timestamp().InMicroseconds();
decoding_buffers_.Put(timestamp,
std::make_pair(frame_index, std::move(bitstream)));
// Validate the encoded bitstream buffer by decoding its contents using a
// software decoder.
decoder_->Decode(std::move(buffer),
base::BindOnce(&BitstreamValidator::DecodeDone,
base::Unretained(this), timestamp));
const bool should_decode = !num_vp9_temporal_layers_to_decode_ ||
(bitstream->metadata.vp9->temporal_idx <
*num_vp9_temporal_layers_to_decode_);
if (should_decode) {
scoped_refptr<DecoderBuffer> buffer = bitstream->buffer;
int64_t timestamp = buffer->timestamp().InMicroseconds();
decoding_buffers_.Put(timestamp,
std::make_pair(frame_index, std::move(bitstream)));
// Validate the encoded bitstream buffer by decoding its contents using a
// software decoder.
decoder_->Decode(std::move(buffer),
base::BindOnce(&BitstreamValidator::DecodeDone,
base::Unretained(this), timestamp));
} else {
// Skip |bitstream| because it contains a frame in upper layers than layers
// to be validated.
base::AutoLock lock(validator_lock_);
num_buffers_validating_--;
validator_cv_.Signal();
}
if (frame_index == last_frame_index_) {
// Flush pending buffers.
decoder_->Decode(DecoderBuffer::CreateEOSBuffer(),
......
......@@ -44,7 +44,9 @@ class BitstreamValidator : public BitstreamProcessor {
const VideoDecoderConfig& decoder_config,
size_t last_frame_index,
std::vector<std::unique_ptr<VideoFrameProcessor>> video_frame_processors =
{});
{},
base::Optional<size_t> num_vp9_temporal_layers_to_decode = base::nullopt);
~BitstreamValidator() override;
// BitstreamProcessor implementation.
......@@ -56,6 +58,7 @@ class BitstreamValidator : public BitstreamProcessor {
BitstreamValidator(
std::unique_ptr<VideoDecoder> decoder,
size_t last_frame_index,
base::Optional<size_t> num_vp9_temporal_layers_to_decode,
std::vector<std::unique_ptr<VideoFrameProcessor>> video_frame_processors);
BitstreamValidator(const BitstreamValidator&) = delete;
BitstreamValidator& operator=(const BitstreamValidator&) = delete;
......@@ -73,6 +76,7 @@ class BitstreamValidator : public BitstreamProcessor {
// Validator components touched by validator_thread_ only.
std::unique_ptr<VideoDecoder> decoder_;
const size_t last_frame_index_;
const base::Optional<size_t> num_vp9_temporal_layers_to_decode_;
const std::vector<std::unique_ptr<VideoFrameProcessor>>
video_frame_processors_;
// The key is timestamp, and the value is BitstreamRef that is being processed
......
......@@ -24,12 +24,15 @@
namespace media {
namespace test {
VideoFrameFileWriter::VideoFrameFileWriter(const base::FilePath& output_folder,
OutputFormat output_format,
size_t output_limit)
VideoFrameFileWriter::VideoFrameFileWriter(
const base::FilePath& output_folder,
OutputFormat output_format,
size_t output_limit,
const base::FilePath::StringType& output_file_prefix)
: output_folder_(output_folder),
output_format_(output_format),
output_limit_(output_limit),
output_file_prefix_(output_file_prefix),
num_frames_writing_(0),
frame_writer_thread_("FrameWriterThread"),
frame_writer_cv_(&frame_writer_lock_) {
......@@ -48,7 +51,8 @@ VideoFrameFileWriter::~VideoFrameFileWriter() {
std::unique_ptr<VideoFrameFileWriter> VideoFrameFileWriter::Create(
const base::FilePath& output_folder,
OutputFormat output_format,
size_t output_limit) {
size_t output_limit,
const base::FilePath::StringType& output_file_prefix) {
// If the directory is not absolute, consider it relative to our working dir.
base::FilePath resolved_output_folder(output_folder);
if (!resolved_output_folder.IsAbsolute()) {
......@@ -67,7 +71,7 @@ std::unique_ptr<VideoFrameFileWriter> VideoFrameFileWriter::Create(
}
auto frame_file_writer = base::WrapUnique(new VideoFrameFileWriter(
resolved_output_folder, output_format, output_limit));
resolved_output_folder, output_format, output_limit, output_file_prefix));
if (!frame_file_writer->Initialize()) {
LOG(ERROR) << "Failed to initialize VideoFrameFileWriter";
return nullptr;
......@@ -129,6 +133,9 @@ void VideoFrameFileWriter::ProcessVideoFrameTask(
const gfx::Size& visible_size = video_frame->visible_rect().size();
base::SStringPrintf(&filename, FILE_PATH_LITERAL("frame_%04zu_%dx%d"),
frame_index, visible_size.width(), visible_size.height());
if (!output_file_prefix_.empty())
filename = output_file_prefix_ + "_" + filename;
// Copies to |frame| in this function so that |video_frame| stays alive until
// in the end of function.
auto frame = video_frame;
......
......@@ -41,7 +41,9 @@ class VideoFrameFileWriter : public VideoFrameProcessor {
static std::unique_ptr<VideoFrameFileWriter> Create(
const base::FilePath& output_folder,
OutputFormat output_format = OutputFormat::kPNG,
size_t output_limit = std::numeric_limits<size_t>::max());
size_t output_limit = std::numeric_limits<size_t>::max(),
const base::FilePath::StringType& output_file_prefix =
base::FilePath::StringType());
// Interface VideoFrameProcessor
void ProcessVideoFrame(scoped_refptr<const VideoFrame> video_frame,
......@@ -52,7 +54,8 @@ class VideoFrameFileWriter : public VideoFrameProcessor {
private:
VideoFrameFileWriter(const base::FilePath& output_folder,
OutputFormat output_format,
size_t output_limit);
size_t output_limit,
const base::FilePath::StringType& output_prefix);
// Initialize the video frame file writer.
bool Initialize();
......@@ -74,6 +77,8 @@ class VideoFrameFileWriter : public VideoFrameProcessor {
const OutputFormat output_format_;
// The maximum number of frames that can be written.
const size_t output_limit_;
// The prefix of the output file.
const base::FilePath::StringType output_file_prefix_;
// The video frame mapper used to gain access to the raw video frame memory.
std::unique_ptr<VideoFrameMapper> video_frame_mapper_;
......
......@@ -122,6 +122,40 @@ class VideoEncoderTest : public ::testing::Test {
}
private:
std::unique_ptr<BitstreamProcessor> CreateBitstreamValidator(
const VideoDecoderConfig& decoder_config,
const size_t last_frame_index,
VideoFrameValidator::GetModelFrameCB get_model_frame_cb,
base::Optional<size_t> num_vp9_temporal_layers_to_decode) {
std::vector<std::unique_ptr<VideoFrameProcessor>> video_frame_processors;
// Attach a video frame writer to store individual frames to disk if
// requested.
std::unique_ptr<VideoFrameProcessor> image_writer;
auto frame_output_config = g_env->ImageOutputConfig();
base::FilePath output_folder = base::FilePath(g_env->OutputFolder())
.Append(g_env->GetTestOutputFilePath());
if (frame_output_config.output_mode != FrameOutputMode::kNone) {
image_writer = VideoFrameFileWriter::Create(
output_folder, frame_output_config.output_format,
frame_output_config.output_limit,
num_vp9_temporal_layers_to_decode
? base::NumberToString(*num_vp9_temporal_layers_to_decode)
: "");
LOG_ASSERT(image_writer);
if (frame_output_config.output_mode == FrameOutputMode::kAll)
video_frame_processors.push_back(std::move(image_writer));
}
auto ssim_validator = SSIMVideoFrameValidator::Create(
get_model_frame_cb, std::move(image_writer),
VideoFrameValidator::ValidationMode::kAverage);
LOG_ASSERT(ssim_validator);
video_frame_processors.push_back(std::move(ssim_validator));
return BitstreamValidator::Create(decoder_config, last_frame_index,
std::move(video_frame_processors),
num_vp9_temporal_layers_to_decode);
}
std::vector<std::unique_ptr<BitstreamProcessor>> CreateBitstreamProcessors(
Video* video,
const VideoEncoderClientConfig& config) {
......@@ -137,11 +171,24 @@ class VideoEncoderTest : public ::testing::Test {
g_env->OutputFolder()
.Append(g_env->GetTestOutputFilePath())
.Append(video->FilePath().BaseName().ReplaceExtension(extension));
auto bitstream_writer = BitstreamFileWriter::Create(
output_bitstream_filepath, codec, visible_rect.size(),
config.framerate, config.num_frames_to_encode);
LOG_ASSERT(bitstream_writer);
bitstream_processors.emplace_back(std::move(bitstream_writer));
if (config.num_temporal_layers > 1) {
for (size_t num_vp9_temporal_layers_to_write = 1;
num_vp9_temporal_layers_to_write <= config.num_temporal_layers;
++num_vp9_temporal_layers_to_write) {
bitstream_processors.emplace_back(BitstreamFileWriter::Create(
output_bitstream_filepath.InsertBeforeExtensionASCII(
FILE_PATH_LITERAL(".TL") +
base::NumberToString(num_vp9_temporal_layers_to_write)),
codec, visible_rect.size(), config.framerate,
config.num_frames_to_encode, num_vp9_temporal_layers_to_write));
LOG_ASSERT(bitstream_processors.back());
}
} else {
bitstream_processors.emplace_back(BitstreamFileWriter::Create(
output_bitstream_filepath, codec, visible_rect.size(),
config.framerate, config.num_frames_to_encode));
LOG_ASSERT(bitstream_processors.back());
}
}
if (!g_env->IsBitstreamValidatorEnabled()) {
......@@ -174,7 +221,6 @@ class VideoEncoderTest : public ::testing::Test {
codec, config.output_profile, VideoDecoderConfig::AlphaMode::kIsOpaque,
VideoColorSpace(), kNoTransformation, visible_rect.size(), visible_rect,
visible_rect.size(), EmptyExtraData(), EncryptionScheme::kUnencrypted);
std::vector<std::unique_ptr<VideoFrameProcessor>> video_frame_processors;
raw_data_helper_ = RawDataHelper::Create(video);
if (!raw_data_helper_) {
LOG(ERROR) << "Failed to create raw data helper";
......@@ -184,31 +230,21 @@ class VideoEncoderTest : public ::testing::Test {
VideoFrameValidator::GetModelFrameCB get_model_frame_cb =
base::BindRepeating(&VideoEncoderTest::GetModelFrame,
base::Unretained(this), visible_rect);
// Attach a video frame writer to store individual frames to disk if
// requested.
std::unique_ptr<VideoFrameProcessor> image_writer;
auto frame_output_config = g_env->ImageOutputConfig();
base::FilePath output_folder = base::FilePath(g_env->OutputFolder())
.Append(g_env->GetTestOutputFilePath());
if (frame_output_config.output_mode != FrameOutputMode::kNone) {
image_writer = VideoFrameFileWriter::Create(
output_folder, frame_output_config.output_format,
frame_output_config.output_limit);
LOG_ASSERT(image_writer);
if (frame_output_config.output_mode == FrameOutputMode::kAll)
video_frame_processors.push_back(std::move(image_writer));
if (config.num_temporal_layers > 1) {
for (size_t num_temporal_layers_to_decode = 1;
num_temporal_layers_to_decode <= config.num_temporal_layers;
++num_temporal_layers_to_decode) {
bitstream_processors.emplace_back(CreateBitstreamValidator(
decoder_config, config.num_frames_to_encode - 1, get_model_frame_cb,
num_temporal_layers_to_decode));
LOG_ASSERT(bitstream_processors.back());
}
} else {
bitstream_processors.emplace_back(CreateBitstreamValidator(
decoder_config, config.num_frames_to_encode - 1, get_model_frame_cb,
base::nullopt));
LOG_ASSERT(bitstream_processors.back());
}
auto ssim_validator = SSIMVideoFrameValidator::Create(
get_model_frame_cb, std::move(image_writer),
VideoFrameValidator::ValidationMode::kAverage);
LOG_ASSERT(ssim_validator);
video_frame_processors.push_back(std::move(ssim_validator));
auto bitstream_validator = BitstreamValidator::Create(
decoder_config, config.num_frames_to_encode - 1,
std::move(video_frame_processors));
LOG_ASSERT(bitstream_validator);
bitstream_processors.emplace_back(std::move(bitstream_validator));
return bitstream_processors;
}
......
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