Commit 6d9f8a44 authored by Hirokazu Honda's avatar Hirokazu Honda Committed by Commit Bot

media/gpu/test VDA: Implement EncodedDataHelper to handle input (encoded) data

GLRenderingVDAClient has several functions to handle input data (i.e. encoded
data), e.g., GetBytesForFirstFragment() and GetBytesNextNALU().
They are not core role of GLRenderingVdaClient.
This introduces EncodedDataHelper as a VDA unittest helper class. It handles
encoded data instead of GLRenderingVDAClient.

BUG=chromium:834170
TEST=VDA unittest on kevin and caroline
TEST=VDA unittest on other platforms in CQ

Cq-Include-Trybots: luci.chromium.try:android_optional_gpu_tests_rel;luci.chromium.try:linux_optional_gpu_tests_rel;luci.chromium.try:mac_optional_gpu_tests_rel;luci.chromium.try:win_optional_gpu_tests_rel
Change-Id: I5116b03172b6a7a80b0473d75d4aeb23868db20d
Reviewed-on: https://chromium-review.googlesource.com/1016822
Commit-Queue: Hirokazu Honda <hiroh@chromium.org>
Reviewed-by: default avatarPawel Osciak <posciak@chromium.org>
Cr-Commit-Position: refs/heads/master@{#555176}
parent ed354063
...@@ -8,8 +8,10 @@ ...@@ -8,8 +8,10 @@
#include "base/files/file_util.h" #include "base/files/file_util.h"
#include "base/strings/string_split.h" #include "base/strings/string_split.h"
#include "base/threading/thread_task_runner_handle.h" #include "base/threading/thread_task_runner_handle.h"
#include "media/base/video_decoder_config.h"
#include "media/gpu/format_utils.h" #include "media/gpu/format_utils.h"
#include "media/gpu/test/rendering_helper.h" #include "media/gpu/test/rendering_helper.h"
#include "media/video/h264_parser.h"
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
#include "ui/gfx/native_pixmap.h" #include "ui/gfx/native_pixmap.h"
...@@ -18,6 +20,8 @@ ...@@ -18,6 +20,8 @@
#include "ui/ozone/public/surface_factory_ozone.h" #include "ui/ozone/public/surface_factory_ozone.h"
#endif #endif
#define VLOGF(level) VLOG(level) << __func__ << "(): "
namespace media { namespace media {
namespace test { namespace test {
...@@ -122,6 +126,115 @@ gfx::GpuMemoryBufferHandle TextureRef::ExportGpuMemoryBufferHandle() const { ...@@ -122,6 +126,115 @@ gfx::GpuMemoryBufferHandle TextureRef::ExportGpuMemoryBufferHandle() const {
return handle; return handle;
} }
EncodedDataHelper::EncodedDataHelper(const std::string& data,
VideoCodecProfile profile)
: data_(data), profile_(profile) {}
EncodedDataHelper::~EncodedDataHelper() {
base::STLClearObject(&data_);
}
bool EncodedDataHelper::IsNALHeader(const std::string& data, size_t pos) {
return data[pos] == 0 && data[pos + 1] == 0 && data[pos + 2] == 0 &&
data[pos + 3] == 1;
}
std::string EncodedDataHelper::GetBytesForNextData() {
switch (VideoCodecProfileToVideoCodec(profile_)) {
case kCodecH264:
return GetBytesForNextFragment();
case kCodecVP8:
case kCodecVP9:
return GetBytesForNextFrame();
default:
NOTREACHED();
return std::string();
}
}
std::string EncodedDataHelper::GetBytesForNextFragment() {
if (next_pos_to_decode_ == 0) {
size_t skipped_fragments_count = 0;
if (!LookForSPS(&skipped_fragments_count)) {
next_pos_to_decode_ = 0;
return std::string();
}
num_skipped_fragments_ += skipped_fragments_count;
}
size_t start_pos = next_pos_to_decode_;
size_t next_nalu_pos = GetBytesForNextNALU(start_pos);
// Update next_pos_to_decode_.
next_pos_to_decode_ = next_nalu_pos;
return data_.substr(start_pos, next_nalu_pos - start_pos);
}
size_t EncodedDataHelper::GetBytesForNextNALU(size_t start_pos) {
size_t pos = start_pos;
if (pos + 4 > data_.size())
return pos;
LOG_ASSERT(IsNALHeader(data_, pos));
pos += 4;
while (pos + 4 <= data_.size() && !IsNALHeader(data_, pos)) {
++pos;
}
if (pos + 3 >= data_.size())
pos = data_.size();
return pos;
}
bool EncodedDataHelper::LookForSPS(size_t* skipped_fragments_count) {
*skipped_fragments_count = 0;
while (next_pos_to_decode_ + 4 < data_.size()) {
if ((data_[next_pos_to_decode_ + 4] & 0x1f) == 0x7) {
return true;
}
*skipped_fragments_count += 1;
next_pos_to_decode_ = GetBytesForNextNALU(next_pos_to_decode_);
}
return false;
}
std::string EncodedDataHelper::GetBytesForNextFrame() {
// Helpful description: http://wiki.multimedia.cx/index.php?title=IVF
size_t pos = next_pos_to_decode_;
std::string bytes;
if (pos == 0)
pos = 32; // Skip IVF header.
uint32_t frame_size = *reinterpret_cast<uint32_t*>(&data_[pos]);
pos += 12; // Skip frame header.
bytes.append(data_.substr(pos, frame_size));
// Update next_pos_to_decode_.
next_pos_to_decode_ = pos + frame_size;
return bytes;
}
// static
bool EncodedDataHelper::HasConfigInfo(const uint8_t* data,
size_t size,
VideoCodecProfile profile) {
if (profile >= H264PROFILE_MIN && profile <= H264PROFILE_MAX) {
H264Parser parser;
parser.SetStream(data, size);
H264NALU nalu;
H264Parser::Result result = parser.AdvanceToNextNALU(&nalu);
if (result != H264Parser::kOk) {
// Let the VDA figure out there's something wrong with the stream.
return false;
}
return nalu.nal_unit_type == H264NALU::kSPS;
} else if (profile >= VP8PROFILE_MIN && profile <= VP9PROFILE_MAX) {
return (size > 0 && !(data[0] & 0x01));
}
// Shouldn't happen at this point.
LOG(FATAL) << "Invalid profile: " << GetProfileName(profile);
return false;
}
// Read in golden MD5s for the thumbnailed rendering of this video // Read in golden MD5s for the thumbnailed rendering of this video
void ReadGoldenThumbnailMD5s(const base::FilePath& md5_file_path, void ReadGoldenThumbnailMD5s(const base::FilePath& md5_file_path,
std::vector<std::string>* md5_strings) { std::vector<std::string>* md5_strings) {
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "base/memory/scoped_refptr.h" #include "base/memory/scoped_refptr.h"
#include "base/single_thread_task_runner.h" #include "base/single_thread_task_runner.h"
#include "base/threading/thread.h" #include "base/threading/thread.h"
#include "media/base/video_codecs.h"
#include "media/base/video_types.h" #include "media/base/video_types.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/size.h" #include "ui/gfx/geometry/size.h"
...@@ -81,6 +82,42 @@ class TextureRef : public base::RefCounted<TextureRef> { ...@@ -81,6 +82,42 @@ class TextureRef : public base::RefCounted<TextureRef> {
#endif #endif
}; };
class EncodedDataHelper {
public:
EncodedDataHelper(const std::string& encoded_data, VideoCodecProfile profile);
~EncodedDataHelper();
// Compute and return the next fragment to be sent to the decoder, starting
// from the current position in the stream, and advance the current position
// to after the returned fragment.
std::string GetBytesForNextData();
static bool HasConfigInfo(const uint8_t* data,
size_t size,
VideoCodecProfile profile);
void Rewind() { next_pos_to_decode_ = 0; }
bool AtHeadOfStream() const { return next_pos_to_decode_ == 0; }
bool ReachEndOfStream() const { return next_pos_to_decode_ == data_.size(); }
size_t num_skipped_fragments() { return num_skipped_fragments_; }
private:
// For h.264.
std::string GetBytesForNextFragment();
// For VP8/9.
std::string GetBytesForNextFrame();
// Helpers for GetBytesForNextFragment above.
size_t GetBytesForNextNALU(size_t pos);
bool IsNALHeader(const std::string& data, size_t pos);
bool LookForSPS(size_t* skipped_fragments_count);
std::string data_;
VideoCodecProfile profile_;
size_t next_pos_to_decode_ = 0;
size_t num_skipped_fragments_ = 0;
};
// Read in golden MD5s for the thumbnailed rendering of this video // Read in golden MD5s for the thumbnailed rendering of this video
void ReadGoldenThumbnailMD5s(const base::FilePath& md5_file_path, void ReadGoldenThumbnailMD5s(const base::FilePath& md5_file_path,
std::vector<std::string>* md5_strings); std::vector<std::string>* md5_strings);
......
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