blob: dc01d68e083de095bb3331e817aa64be357533d0 [file] [log] [blame]
// Copyright 2018 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_player/video.h"
#include <memory>
#include <utility>
#include "base/files/file_util.h"
#include "base/json/json_reader.h"
#include "base/numerics/safe_conversions.h"
#include "base/values.h"
#include "media/gpu/test/video_decode_accelerator_unittest_helpers.h"
#define VLOGF(level) VLOG(level) << __func__ << "(): "
namespace media {
namespace test {
// Suffix to append to the video file path to get the metadata file path.
constexpr const base::FilePath::CharType* kMetadataSuffix =
FILE_PATH_LITERAL(".json");
// Suffix to append to the video file path to get the checksums file path.
constexpr const base::FilePath::CharType* kFrameChecksumSuffix =
FILE_PATH_LITERAL(".frames.md5");
base::FilePath Video::test_data_path_ = base::FilePath();
Video::Video(const base::FilePath& file_path) : file_path_(file_path) {}
Video::~Video() {}
bool Video::Load() {
// TODO(dstaessens@) Investigate reusing existing infrastructure such as
// DecoderBuffer.
DCHECK(!file_path_.empty());
DCHECK(data_.empty());
// The specified path can be either an absolute path, a path relative to the
// current directory, or relative to the test data path.
if (!file_path_.IsAbsolute()) {
if (!PathExists(file_path_))
file_path_ = test_data_path_.Append(file_path_);
file_path_ = base::MakeAbsoluteFilePath(file_path_);
}
VLOGF(2) << "File path: " << file_path_;
int64_t file_size;
if (!base::GetFileSize(file_path_, &file_size) || (file_size < 0)) {
VLOGF(1) << "Failed to read file size: " << file_path_;
return false;
}
std::vector<uint8_t> data(file_size);
if (base::ReadFile(file_path_, reinterpret_cast<char*>(data.data()),
base::checked_cast<int>(file_size)) != file_size) {
VLOGF(1) << "Failed to read file: " << file_path_;
return false;
}
data_ = std::move(data);
if (!LoadMetadata()) {
VLOGF(1) << "Failed to load metadata";
return false;
}
if (!LoadFrameChecksums()) {
VLOGF(1) << "Failed to load frame checksums";
return false;
}
return true;
}
bool Video::IsLoaded() const {
return data_.size() > 0;
}
const std::vector<uint8_t>& Video::Data() const {
return data_;
}
VideoCodecProfile Video::Profile() const {
return profile_;
}
uint32_t Video::NumFrames() const {
return num_frames_;
}
const std::vector<std::string>& Video::FrameChecksums() const {
return frame_checksums_;
}
// static
void Video::SetTestDataPath(const base::FilePath& test_data_path) {
test_data_path_ = test_data_path;
}
bool Video::LoadMetadata() {
if (IsMetadataLoaded()) {
VLOGF(1) << "Video metadata is already loaded";
return false;
}
const base::FilePath json_path = file_path_.AddExtension(kMetadataSuffix);
VLOGF(2) << "File path: " << json_path;
if (!base::PathExists(json_path)) {
VLOGF(1) << "Video metadata file not found: " << json_path;
return false;
}
std::string json_data;
if (!base::ReadFileToString(json_path, &json_data)) {
VLOGF(1) << "Failed to read video metadata file: " << json_path;
return false;
}
base::JSONReader reader;
std::unique_ptr<base::Value> metadata(reader.ReadToValue(json_data));
if (!metadata) {
VLOGF(1) << "Failed to parse video metadata: " << json_path << ": "
<< reader.GetErrorMessage();
return false;
}
const base::Value* profile =
metadata->FindKeyOfType("profile", base::Value::Type::STRING);
if (!profile) {
VLOGF(1) << "Key \"profile\" is not found in " << json_path;
return false;
}
profile_ = ConvertStringtoProfile(profile->GetString());
if (profile_ == VIDEO_CODEC_PROFILE_UNKNOWN) {
VLOGF(1) << profile->GetString() << " is not supported";
return false;
}
const base::Value* num_frames =
metadata->FindKeyOfType("num_frames", base::Value::Type::INTEGER);
if (!num_frames) {
VLOGF(1) << "Key \"num_frames\" is not found in " << json_path;
return false;
}
num_frames_ = static_cast<uint32_t>(num_frames->GetInt());
return true;
}
bool Video::IsMetadataLoaded() const {
return profile_ != VIDEO_CODEC_PROFILE_UNKNOWN || num_frames_ != 0;
}
bool Video::LoadFrameChecksums() {
if (FrameChecksumsLoaded()) {
VLOGF(1) << "Frame checksums are already loaded";
return false;
}
frame_checksums_ =
ReadGoldenThumbnailMD5s(file_path_.AddExtension(kFrameChecksumSuffix));
LOG_ASSERT(frame_checksums_.size() == num_frames_)
<< "Video frame checksum count does not match number of video frames";
return frame_checksums_.size() == num_frames_;
}
bool Video::FrameChecksumsLoaded() const {
return frame_checksums_.size() == num_frames_;
}
// static
VideoCodecProfile Video::ConvertStringtoProfile(const std::string& profile) {
if (profile == "H264PROFILE_MAIN") {
return H264PROFILE_MAIN;
} else if (profile == "VP8PROFILE_ANY") {
return VP8PROFILE_ANY;
} else if (profile == "VP9PROFILE_PROFILE0") {
return VP9PROFILE_PROFILE0;
} else if (profile == "VP9PROFILE_PROFILE2") {
return VP9PROFILE_PROFILE2;
} else {
VLOG(2) << profile << " is not supported.";
return VIDEO_CODEC_PROFILE_UNKNOWN;
}
}
} // namespace test
} // namespace media