Commit 43106f33 authored by Hirokazu Honda's avatar Hirokazu Honda Committed by Commit Bot

Reland "media/gpu/test: Add BitstreamFileWriter for video_encode_accelerator_tests"

This is a reland of 91f3b4a4

Original change's description:
> media/gpu/test: Add BitstreamFileWriter for video_encode_accelerator_tests
> 
> This adds BitstreamFileWriter, which saves given bitstream in
> H264 AnnexB format for h264 and ivf format for vp8 and vp9. It
> enables saving the bitstream encoded by VideoEncodeAccelerator with
> --output_bitstream option in video_encode_accelerator_tests.
> 
> Bug: 1045825
> Test: video_encode_accelerator_tests --dump_bitstream on eve
> Change-Id: I78da9b53791599b9672c683afbe29b3f8cf8787a
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2214870
> Commit-Queue: Hirokazu Honda <hiroh@chromium.org>
> Reviewed-by: David Staessens <dstaessens@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#779157}

Bug: 1045825
Change-Id: Ic3df2b161c0bbe5db38446e2eb9452f354eed463
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2247951
Auto-Submit: Hirokazu Honda <hiroh@chromium.org>
Commit-Queue: David Staessens <dstaessens@chromium.org>
Reviewed-by: default avatarDavid Staessens <dstaessens@chromium.org>
Cr-Commit-Position: refs/heads/master@{#779615}
parent f3ef59a4
......@@ -69,7 +69,10 @@ source_set("test_helpers") {
"video_test_helpers.cc",
"video_test_helpers.h",
]
public_deps = [ ":helpers" ]
public_deps = [
":helpers",
"//media:test_support",
]
deps = [
"//media/gpu",
"//testing/gtest",
......@@ -136,6 +139,8 @@ static_library("video_encoder") {
sources = [
"bitstream_helpers.cc",
"bitstream_helpers.h",
"video_encoder/bitstream_file_writer.cc",
"video_encoder/bitstream_file_writer.h",
"video_encoder/bitstream_validator.cc",
"video_encoder/bitstream_validator.h",
"video_encoder/decoder_buffer_validator.cc",
......
// 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 "media/gpu/test/video_encoder/bitstream_file_writer.h"
#include "base/bind.h"
#include "base/files/file_util.h"
#include "base/memory/ptr_util.h"
#include "media/gpu/test/video_test_helpers.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace media {
namespace test {
// A helper class to write each frame to disk.
class BitstreamFileWriter::FrameFileWriter {
public:
FrameFileWriter(std::unique_ptr<IvfWriter> ivf_writer)
: ivf_writer_(std::move(ivf_writer)) {}
FrameFileWriter(base::File output_file)
: output_file_(std::move(output_file)) {}
bool WriteFrame(uint32_t data_size, uint64_t timestamp, const uint8_t* data) {
if (ivf_writer_) {
return ivf_writer_->WriteFrame(data_size, timestamp, data);
}
// For H.264.
LOG_ASSERT(output_file_.IsValid());
return output_file_.WriteAtCurrentPos(reinterpret_cast<const char*>(data),
data_size) ==
static_cast<int>(data_size);
}
private:
const std::unique_ptr<IvfWriter> ivf_writer_;
base::File output_file_;
};
BitstreamFileWriter::BitstreamFileWriter(
std::unique_ptr<FrameFileWriter> frame_file_writer)
: frame_file_writer_(std::move(frame_file_writer)),
num_buffers_writing_(0),
num_errors_(0),
writer_thread_("BitstreamFileWriterThread"),
writer_cv_(&writer_lock_) {}
BitstreamFileWriter::~BitstreamFileWriter() {
base::AutoLock auto_lock(writer_lock_);
DCHECK_EQ(0u, num_buffers_writing_);
writer_thread_.Stop();
}
// static
std::unique_ptr<BitstreamFileWriter> BitstreamFileWriter::Create(
const base::FilePath& output_filepath,
VideoCodec codec,
const gfx::Size& resolution,
uint32_t frame_rate,
uint32_t num_frames) {
std::unique_ptr<FrameFileWriter> frame_file_writer;
if (!base::DirectoryExists(output_filepath.DirName()))
base::CreateDirectory(output_filepath.DirName());
if (codec == kCodecH264) {
base::File output_file(output_filepath, base::File::FLAG_CREATE_ALWAYS |
base::File::FLAG_WRITE);
LOG_ASSERT(output_file.IsValid());
frame_file_writer =
std::make_unique<FrameFileWriter>(std::move(output_file));
} else {
auto ivf_writer = std::make_unique<IvfWriter>(output_filepath);
if (!ivf_writer->WriteFileHeader(codec, resolution, frame_rate,
num_frames)) {
LOG(ERROR) << "Failed writing ivf header";
return nullptr;
}
frame_file_writer =
std::make_unique<FrameFileWriter>(std::move(ivf_writer));
}
auto bitstream_file_writer =
base::WrapUnique(new BitstreamFileWriter(std::move(frame_file_writer)));
if (!bitstream_file_writer->writer_thread_.Start()) {
LOG(ERROR) << "Failed to start file writer thread";
return nullptr;
}
return bitstream_file_writer;
}
void BitstreamFileWriter::ProcessBitstream(
scoped_refptr<BitstreamRef> bitstream,
size_t frame_index) {
base::AutoLock auto_lock(writer_lock_);
num_buffers_writing_++;
writer_thread_.task_runner()->PostTask(
FROM_HERE, base::BindOnce(&BitstreamFileWriter::WriteBitstreamTask,
base::Unretained(this), std::move(bitstream),
frame_index));
}
void BitstreamFileWriter::WriteBitstreamTask(
scoped_refptr<BitstreamRef> bitstream,
size_t frame_index) {
DCHECK_CALLED_ON_VALID_SEQUENCE(writer_thread_sequence_checker_);
const DecoderBuffer& buffer = *bitstream->buffer.get();
bool success = frame_file_writer_->WriteFrame(
static_cast<uint32_t>(buffer.data_size()),
static_cast<uint64_t>(frame_index), buffer.data());
base::AutoLock auto_lock(writer_lock_);
num_errors_ += !success;
num_buffers_writing_--;
writer_cv_.Signal();
}
bool BitstreamFileWriter::WaitUntilDone() {
base::AutoLock auto_lock(writer_lock_);
while (num_buffers_writing_ > 0u)
writer_cv_.Wait();
LOG_IF(ERROR, num_errors_ > 0u) << "Detected error count: " << num_errors_;
return num_errors_ == 0;
}
} // namespace test
} // namespace media
// 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.
#ifndef MEDIA_GPU_TEST_VIDEO_ENCODER_BITSTREAM_FILE_WRITER_H_
#define MEDIA_GPU_TEST_VIDEO_ENCODER_BITSTREAM_FILE_WRITER_H_
#include <stdint.h>
#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/sequence_checker.h"
#include "base/synchronization/condition_variable.h"
#include "base/synchronization/lock.h"
#include "base/threading/thread.h"
#include "media/gpu/test/bitstream_helpers.h"
namespace media {
namespace test {
// This class writes a given bitstream to |output_filepath|. The output file
// format is H264 AnnexB format if the bitstream is H264 and IVF if VP8 and VP9.
class BitstreamFileWriter : public BitstreamProcessor {
public:
static std::unique_ptr<BitstreamFileWriter> Create(
const base::FilePath& output_filepath,
VideoCodec codec,
const gfx::Size& resolution,
uint32_t frame_rate,
uint32_t num_frames);
BitstreamFileWriter(const BitstreamFileWriter&) = delete;
BitstreamFileWriter operator=(const BitstreamFileWriter&) = delete;
~BitstreamFileWriter() override;
void ProcessBitstream(scoped_refptr<BitstreamRef> bitstream,
size_t frame_index) override;
bool WaitUntilDone() override;
private:
class FrameFileWriter;
BitstreamFileWriter(std::unique_ptr<FrameFileWriter> frame_file_writer);
void WriteBitstreamTask(scoped_refptr<BitstreamRef> bitstream,
size_t frame_index);
const std::unique_ptr<FrameFileWriter> frame_file_writer_;
// The number of buffers currently queued for writing.
size_t num_buffers_writing_ GUARDED_BY(writer_lock_);
// The number of encountered errors.
size_t num_errors_ GUARDED_BY(writer_lock_);
// Thread on which bitstream buffer writing is done.
base::Thread writer_thread_;
mutable base::ConditionVariable writer_cv_;
mutable base::Lock writer_lock_;
SEQUENCE_CHECKER(writer_thread_sequence_checker_);
};
} // namespace test
} // namespace media
#endif // MEDIA_GPU_TEST_VIDEO_ENCODER_BITSTREAM_FILE_WRITER_H_
......@@ -52,7 +52,8 @@ VideoEncoderTestEnvironment* VideoEncoderTestEnvironment::Create(
const base::FilePath& video_metadata_path,
bool enable_bitstream_validator,
const base::FilePath& output_folder,
const std::string& codec) {
const std::string& codec,
bool output_bitstream) {
if (video_path.empty()) {
LOG(ERROR) << "No video specified";
return nullptr;
......@@ -82,6 +83,14 @@ VideoEncoderTestEnvironment* VideoEncoderTestEnvironment::Create(
return nullptr;
}
base::Optional<base::FilePath> bitstream_filename;
if (output_bitstream) {
base::FilePath::StringPieceType extension =
codec.find("h264") != std::string::npos ? FILE_PATH_LITERAL("h264")
: FILE_PATH_LITERAL("ivf");
bitstream_filename = video_path.BaseName().ReplaceExtension(extension);
}
const auto* it = std::find_if(
std::begin(kCodecParamToProfile), std::end(kCodecParamToProfile),
[codec](const auto& cp) { return cp.codec == codec; });
......@@ -89,22 +98,26 @@ VideoEncoderTestEnvironment* VideoEncoderTestEnvironment::Create(
LOG(ERROR) << "Unknown codec: " << codec;
return nullptr;
}
VideoCodecProfile profile = it->profile;
return new VideoEncoderTestEnvironment(
std::move(video), enable_bitstream_validator, output_folder, profile);
std::move(video), enable_bitstream_validator, output_folder, profile,
bitstream_filename);
}
VideoEncoderTestEnvironment::VideoEncoderTestEnvironment(
std::unique_ptr<media::test::Video> video,
bool enable_bitstream_validator,
const base::FilePath& output_folder,
VideoCodecProfile profile)
VideoCodecProfile profile,
const base::Optional<base::FilePath>& bitstream_filename)
: VideoTestEnvironment(kEnabledFeaturesForVideoEncoderTest,
kDisabledFeaturesForVideoEncoderTest),
video_(std::move(video)),
enable_bitstream_validator_(enable_bitstream_validator),
output_folder_(output_folder),
profile_(profile),
bitstream_filename_(bitstream_filename),
gpu_memory_buffer_factory_(
gpu::GpuMemoryBufferFactory::CreateNativeType(nullptr)) {}
......@@ -126,6 +139,15 @@ VideoCodecProfile VideoEncoderTestEnvironment::Profile() const {
return profile_;
}
base::Optional<base::FilePath>
VideoEncoderTestEnvironment::OutputBitstreamFilePath() const {
if (!bitstream_filename_)
return base::nullopt;
return output_folder_.Append(GetTestOutputFilePath())
.Append(*bitstream_filename_);
}
gpu::GpuMemoryBufferFactory*
VideoEncoderTestEnvironment::GetGpuMemoryBufferFactory() const {
return gpu_memory_buffer_factory_.get();
......
......@@ -31,7 +31,8 @@ class VideoEncoderTestEnvironment : public VideoTestEnvironment {
const base::FilePath& video_metadata_path,
bool enable_bitstream_validator,
const base::FilePath& output_folder,
const std::string& codec);
const std::string& codec,
bool output_bitstream);
~VideoEncoderTestEnvironment() override;
// Get the video the tests will be ran on.
......@@ -42,6 +43,9 @@ class VideoEncoderTestEnvironment : public VideoTestEnvironment {
const base::FilePath& OutputFolder() const;
// Get the output codec profile.
VideoCodecProfile Profile() const;
// Get the file path the output bitstream file is saved. If output bitstream
// is not saved, returns base::nullopt.
base::Optional<base::FilePath> OutputBitstreamFilePath() const;
// Get the GpuMemoryBufferFactory for doing buffer allocations. This needs to
// survive as long as the process is alive just like in production which is
......@@ -50,10 +54,12 @@ class VideoEncoderTestEnvironment : public VideoTestEnvironment {
gpu::GpuMemoryBufferFactory* GetGpuMemoryBufferFactory() const;
private:
VideoEncoderTestEnvironment(std::unique_ptr<media::test::Video> video,
bool enable_bitstream_validator,
const base::FilePath& output_folder,
VideoCodecProfile profile);
VideoEncoderTestEnvironment(
std::unique_ptr<media::test::Video> video,
bool enable_bitstream_validator,
const base::FilePath& output_folder,
VideoCodecProfile profile,
const base::Optional<base::FilePath>& output_bitstream_filepath);
// Video file to be used for testing.
const std::unique_ptr<media::test::Video> video_;
......@@ -63,6 +69,8 @@ class VideoEncoderTestEnvironment : public VideoTestEnvironment {
const base::FilePath output_folder_;
// VideoCodecProfile to be produced by VideoEncoder.
const VideoCodecProfile profile_;
// File name to be used to save bitstream encoded by VideoEncoder.
const base::Optional<base::FilePath> bitstream_filename_;
std::unique_ptr<gpu::GpuMemoryBufferFactory> gpu_memory_buffer_factory_;
};
......
......@@ -18,20 +18,86 @@
namespace media {
namespace test {
namespace {
constexpr uint16_t kIvfFileHeaderSize = 32;
constexpr size_t kIvfFrameHeaderSize = 12;
} // namespace
IvfFileHeader GetIvfFileHeader(const base::span<const uint8_t>& data) {
LOG_ASSERT(data.size_bytes() == 32u);
IvfFileHeader file_header;
memcpy(&file_header, data.data(), sizeof(IvfFileHeader));
file_header.ByteSwap();
return file_header;
}
IvfFrameHeader GetIvfFrameHeader(const base::span<const uint8_t>& data) {
LOG_ASSERT(data.size_bytes() == 12u);
IvfFrameHeader frame_header{};
memcpy(&frame_header.frame_size, data.data(), 4);
memcpy(&frame_header.timestamp, &data[4], 8);
return frame_header;
}
IvfWriter::IvfWriter(base::FilePath output_filepath) {
output_file_ = base::File(
output_filepath, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
LOG_ASSERT(output_file_.IsValid());
}
bool IvfWriter::WriteFileHeader(VideoCodec codec,
const gfx::Size& resolution,
uint32_t frame_rate,
uint32_t num_frames) {
char ivf_header[kIvfFileHeaderSize] = {};
// Bytes 0-3 of an IVF file header always contain the signature 'DKIF'.
strcpy(&ivf_header[0], "DKIF");
constexpr uint16_t kVersion = 0;
auto write16 = [&ivf_header](int i, uint16_t v) {
memcpy(&ivf_header[i], &v, sizeof(v));
};
auto write32 = [&ivf_header](int i, uint32_t v) {
memcpy(&ivf_header[i], &v, sizeof(v));
};
write16(4, kVersion);
write16(6, kIvfFileHeaderSize);
switch (codec) {
case kCodecVP8:
strcpy(&ivf_header[8], "VP80");
break;
case kCodecVP9:
strcpy(&ivf_header[8], "VP90");
break;
default:
LOG(ERROR) << "Unknown codec: " << GetCodecName(codec);
return false;
}
// The structure for IVF frame header. IVF is a video file format.
// The helpful description is in https://wiki.multimedia.cx/index.php/IVF.
struct EncodedDataHelper::IVFHeader {
uint32_t frame_size;
uint64_t timestamp;
};
write16(12, resolution.width());
write16(14, resolution.height());
write32(16, frame_rate);
write32(20, 1);
write32(24, num_frames);
// Reserved.
write32(28, 0);
return output_file_.WriteAtCurrentPos(ivf_header, kIvfFileHeaderSize) ==
static_cast<int>(kIvfFileHeaderSize);
}
// The structure for IVF frame data and header.
// The data to be read is |header.frame_size| bytes from |data|.
struct EncodedDataHelper::IVFFrame {
const char* data;
IVFHeader header;
};
bool IvfWriter::WriteFrame(uint32_t data_size,
uint64_t timestamp,
const uint8_t* data) {
char ivf_frame_header[kIvfFrameHeaderSize] = {};
memcpy(&ivf_frame_header[0], &data_size, sizeof(data_size));
memcpy(&ivf_frame_header[4], &timestamp, sizeof(timestamp));
bool success =
output_file_.WriteAtCurrentPos(ivf_frame_header, kIvfFrameHeaderSize) ==
static_cast<int>(kIvfFrameHeaderSize) &&
output_file_.WriteAtCurrentPos(reinterpret_cast<const char*>(data),
data_size) == static_cast<int>(data_size);
return success;
}
EncodedDataHelper::EncodedDataHelper(const std::vector<uint8_t>& stream,
VideoCodecProfile profile)
......@@ -112,15 +178,20 @@ bool EncodedDataHelper::LookForSPS(size_t* skipped_fragments_count) {
scoped_refptr<DecoderBuffer> EncodedDataHelper::GetNextFrame() {
// Helpful description: http://wiki.multimedia.cx/index.php?title=IVF
constexpr size_t kIVFHeaderSize = 32;
// Only IVF video files are supported. The first 4bytes of an IVF video file's
// header should be "DKIF".
if (next_pos_to_decode_ == 0) {
if ((data_.size() < kIVFHeaderSize) || strncmp(&data_[0], "DKIF", 4) != 0) {
if (data_.size() < kIvfFileHeaderSize) {
LOG(ERROR) << "data is too small";
return nullptr;
}
auto ivf_header = GetIvfFileHeader(base::span<const uint8_t>(
reinterpret_cast<const uint8_t*>(&data_[0]), kIvfFileHeaderSize));
if (strncmp(ivf_header.signature, "DKIF", 4) != 0) {
LOG(ERROR) << "Unexpected data encountered while parsing IVF header";
return nullptr;
}
next_pos_to_decode_ = kIVFHeaderSize; // Skip IVF header.
next_pos_to_decode_ = kIvfFileHeaderSize; // Skip IVF header.
}
// Group IVF data whose timestamps are the same. Spatial layers in a
......@@ -128,9 +199,9 @@ scoped_refptr<DecoderBuffer> EncodedDataHelper::GetNextFrame() {
// timestamps of the IVF frame headers are the same. However, it is necessary
// for VD(A) to feed the spatial layers by a single DecoderBuffer. So this
// grouping is required.
std::vector<IVFFrame> ivf_frames;
std::vector<IvfFrame> ivf_frames;
while (!ReachEndOfStream()) {
auto frame_header = GetNextIVFFrameHeader();
auto frame_header = GetNextIvfFrameHeader();
if (!frame_header)
return nullptr;
......@@ -141,7 +212,7 @@ scoped_refptr<DecoderBuffer> EncodedDataHelper::GetNextFrame() {
break;
}
auto frame_data = ReadNextIVFFrame();
auto frame_data = ReadNextIvfFrame();
if (!frame_data)
return nullptr;
......@@ -169,8 +240,8 @@ scoped_refptr<DecoderBuffer> EncodedDataHelper::GetNextFrame() {
std::string data;
std::vector<uint32_t> frame_sizes;
frame_sizes.reserve(ivf_frames.size());
for (const IVFFrame& ivf : ivf_frames) {
data.append(ivf.data, ivf.header.frame_size);
for (const IvfFrame& ivf : ivf_frames) {
data.append(reinterpret_cast<char*>(ivf.data), ivf.header.frame_size);
frame_sizes.push_back(ivf.header.frame_size);
}
......@@ -186,34 +257,25 @@ scoped_refptr<DecoderBuffer> EncodedDataHelper::GetNextFrame() {
data.size(), side_data, side_data_size);
}
base::Optional<EncodedDataHelper::IVFHeader>
EncodedDataHelper::GetNextIVFFrameHeader() const {
constexpr size_t kIVFFrameHeaderSize = 12;
base::Optional<IvfFrameHeader> EncodedDataHelper::GetNextIvfFrameHeader()
const {
const size_t pos = next_pos_to_decode_;
// Read VP8/9 frame size from IVF header.
if (pos + kIVFFrameHeaderSize > data_.size()) {
if (pos + kIvfFrameHeaderSize > data_.size()) {
LOG(ERROR) << "Unexpected data encountered while parsing IVF frame header";
return base::nullopt;
}
uint32_t frame_size = 0;
uint64_t timestamp = 0;
memcpy(&frame_size, &data_[pos], 4);
memcpy(&timestamp, &data_[pos + 4], 8);
return IVFHeader{frame_size, timestamp};
return GetIvfFrameHeader(base::span<const uint8_t>(
reinterpret_cast<const uint8_t*>(data_[pos]), kIvfFrameHeaderSize));
}
base::Optional<EncodedDataHelper::IVFFrame>
EncodedDataHelper::ReadNextIVFFrame() {
constexpr size_t kIVFFrameHeaderSize = 12;
auto frame_header = GetNextIVFFrameHeader();
base::Optional<IvfFrame> EncodedDataHelper::ReadNextIvfFrame() {
auto frame_header = GetNextIvfFrameHeader();
if (!frame_header)
return base::nullopt;
// Skip IVF frame header.
const size_t pos = next_pos_to_decode_ + kIVFFrameHeaderSize;
const size_t pos = next_pos_to_decode_ + kIvfFrameHeaderSize;
// Make sure we are not reading out of bounds.
if (pos + frame_header->frame_size > data_.size()) {
......@@ -225,7 +287,7 @@ EncodedDataHelper::ReadNextIVFFrame() {
// Update next_pos_to_decode_.
next_pos_to_decode_ = pos + frame_header->frame_size;
return IVFFrame{&data_[pos], *frame_header};
return IvfFrame{*frame_header, reinterpret_cast<uint8_t*>(&data_[pos])};
}
// static
......
......@@ -11,6 +11,8 @@
#include "base/bits.h"
#include "base/containers/queue.h"
#include "base/containers/span.h"
#include "base/files/file.h"
#include "base/memory/aligned_memory.h"
#include "base/memory/scoped_refptr.h"
#include "base/optional.h"
......@@ -22,6 +24,7 @@
#include "media/base/video_frame.h"
#include "media/base/video_frame_layout.h"
#include "media/base/video_types.h"
#include "media/filters/ivf_parser.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
......@@ -73,6 +76,30 @@ StateEnum ClientStateNotification<StateEnum>::Wait() {
return ret;
}
struct IvfFrame {
IvfFrameHeader header;
uint8_t* data = nullptr;
};
// Read functions to fill IVF file header and IVF frame header from |data|.
// |data| must have sufficient length.
IvfFileHeader GetIvfFileHeader(const base::span<const uint8_t>& data);
IvfFrameHeader GetIvfFrameHeader(const base::span<const uint8_t>& data);
// The helper class to save data as ivf format.
class IvfWriter {
public:
IvfWriter(base::FilePath output_filepath);
bool WriteFileHeader(VideoCodec codec,
const gfx::Size& resolution,
uint32_t frame_rate,
uint32_t num_frames);
bool WriteFrame(uint32_t data_size, uint64_t timestamp, const uint8_t* data);
private:
base::File output_file_;
};
// Helper to extract fragments from encoded video stream.
class EncodedDataHelper {
public:
......@@ -95,15 +122,13 @@ class EncodedDataHelper {
size_t num_skipped_fragments() { return num_skipped_fragments_; }
private:
struct IVFHeader;
struct IVFFrame;
// For h.264.
scoped_refptr<DecoderBuffer> GetNextFragment();
// For VP8/9.
scoped_refptr<DecoderBuffer> GetNextFrame();
base::Optional<IVFHeader> GetNextIVFFrameHeader() const;
base::Optional<IVFFrame> ReadNextIVFFrame();
base::Optional<IvfFrameHeader> GetNextIvfFrameHeader() const;
base::Optional<IvfFrame> ReadNextIvfFrame();
// Helpers for GetBytesForNextFragment above.
size_t GetBytesForNextNALU(size_t pos);
......
......@@ -367,7 +367,7 @@ int main(int argc, char** argv) {
media::test::VideoEncoderTestEnvironment* test_environment =
media::test::VideoEncoderTestEnvironment::Create(
video_path, video_metadata_path, false, base::FilePath(output_folder),
codec);
codec, false /* output_bitstream */);
if (!test_environment)
return EXIT_FAILURE;
......
......@@ -7,11 +7,13 @@
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "media/base/media_util.h"
#include "media/base/test_data_util.h"
#include "media/base/video_bitrate_allocation.h"
#include "media/base/video_decoder_config.h"
#include "media/gpu/test/video.h"
#include "media/gpu/test/video_encoder/bitstream_file_writer.h"
#include "media/gpu/test/video_encoder/bitstream_validator.h"
#include "media/gpu/test/video_encoder/decoder_buffer_validator.h"
#include "media/gpu/test/video_encoder/video_encoder.h"
......@@ -33,6 +35,7 @@ namespace {
constexpr const char* usage_msg =
"usage: video_encode_accelerator_tests\n"
" [--codec=<codec>] [--disable_validator]\n"
" [--output_bitstream] [--output_folder=<filepath>]\n"
" [-v=<level>] [--vmodule=<config>] [--gtest_help] [--help]\n"
" [<video path>] [<video metadata path>]\n";
......@@ -45,9 +48,16 @@ constexpr const char* help_msg =
"containing the video's metadata, such as frame checksums. By default\n"
"<video path>.json will be used.\n"
"\nThe following arguments are supported:\n"
" --codec codec profile to encode, \"h264 (baseline)\",\n"
" \"h264main, \"h264high\", \"vp8\" and \"vp9\"\n"
" --codec codec profile to encode, \"h264\" (baseline),\n"
" \"h264main, \"h264high\", \"vp8\" and \"vp9\".\n"
" H264 Baseline is selected if unspecified.\n"
" --disable_validator disable validation of encoded bitstream.\n\n"
" --output_bitstream save the output bitstream in either H264 AnnexB\n"
" format (for H264) or IVF format (for vp8 and vp9)\n"
" to <output_folder>/<testname>/<filename> +\n"
" .(h264|ivf).\n"
" --output_folder set the basic folder used to store the output\n"
" stream. The default is the current directory.\n"
" -v enable verbose mode, e.g. -v=2.\n"
" --vmodule enable verbose mode for the specified module,\n"
" e.g. --vmodule=*media/gpu*=2.\n\n"
......@@ -71,7 +81,7 @@ class VideoEncoderTest : public ::testing::Test {
public:
std::unique_ptr<VideoEncoder> CreateVideoEncoder(
Video* video,
const VideoEncoderClientConfig& config) {
VideoEncoderClientConfig config) {
LOG_ASSERT(video);
auto video_encoder =
......@@ -143,6 +153,15 @@ class VideoEncoderTest : public ::testing::Test {
LOG_ASSERT(bitstream_validator);
bitstream_processors.emplace_back(std::move(bitstream_validator));
auto output_bitstream_filepath = g_env->OutputBitstreamFilePath();
if (output_bitstream_filepath) {
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));
}
return bitstream_processors;
}
......@@ -206,6 +225,8 @@ TEST_F(VideoEncoderTest, FlushAtEndOfStream_MultipleConcurrentEncodes) {
VideoEncoderClientConfig config = VideoEncoderClientConfig();
config.framerate = g_env->Video()->FrameRate();
config.output_profile = g_env->Profile();
config.num_frames_to_encode = g_env->Video()->NumFrames();
std::vector<std::unique_ptr<VideoEncoder>> encoders(
kMinSupportedConcurrentEncoders);
......@@ -326,6 +347,9 @@ int main(int argc, char** argv) {
base::FilePath video_metadata_path =
(args.size() >= 2) ? base::FilePath(args[1]) : base::FilePath();
std::string codec = "h264";
bool output_bitstream = false;
base::FilePath output_folder =
base::FilePath(base::FilePath::kCurrentDirectory);
// Parse command line arguments.
bool enable_bitstream_validator = true;
......@@ -341,6 +365,10 @@ int main(int argc, char** argv) {
codec = it->second;
} else if (it->first == "disable_validator") {
enable_bitstream_validator = false;
} else if (it->first == "output_bitstream") {
output_bitstream = true;
} else if (it->first == "output_folder") {
output_folder = base::FilePath(it->second);
} else {
std::cout << "unknown option: --" << it->first << "\n"
<< media::test::usage_msg;
......@@ -354,7 +382,7 @@ int main(int argc, char** argv) {
media::test::VideoEncoderTestEnvironment* test_environment =
media::test::VideoEncoderTestEnvironment::Create(
video_path, video_metadata_path, enable_bitstream_validator,
base::FilePath(), codec);
output_folder, codec, output_bitstream);
if (!test_environment)
return EXIT_FAILURE;
......
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