a5837e4dd0
and call it from ParseUncompressedHeader. this avoids attempts to parse a stale buffer should SetFrame fail. BUG=webm:1493 Change-Id: I441ae9d0db3f0a01d73902a8f5b06812e2e93422
182 lines
5.7 KiB
C++
182 lines
5.7 KiB
C++
// Copyright (c) 2016 The WebM project authors. All Rights Reserved.
|
|
//
|
|
// Use of this source code is governed by a BSD-style license
|
|
// that can be found in the LICENSE file in the root of the source
|
|
// tree. An additional intellectual property rights grant can be found
|
|
// in the file PATENTS. All contributing project authors may
|
|
// be found in the AUTHORS file in the root of the source tree.
|
|
#include "common/vp9_header_parser.h"
|
|
|
|
#include <string>
|
|
|
|
#include "gtest/gtest.h"
|
|
|
|
#include "common/hdr_util.h"
|
|
#include "mkvparser/mkvparser.h"
|
|
#include "mkvparser/mkvreader.h"
|
|
#include "testing/test_util.h"
|
|
|
|
namespace {
|
|
|
|
class Vp9HeaderParserTests : public ::testing::Test {
|
|
public:
|
|
Vp9HeaderParserTests() : is_reader_open_(false), segment_(NULL) {}
|
|
|
|
~Vp9HeaderParserTests() override {
|
|
CloseReader();
|
|
if (segment_ != NULL) {
|
|
delete segment_;
|
|
segment_ = NULL;
|
|
}
|
|
}
|
|
|
|
void CloseReader() {
|
|
if (is_reader_open_) {
|
|
reader_.Close();
|
|
}
|
|
is_reader_open_ = false;
|
|
}
|
|
|
|
void CreateAndLoadSegment(const std::string& filename,
|
|
int expected_doc_type_ver) {
|
|
filename_ = test::GetTestFilePath(filename);
|
|
ASSERT_EQ(0, reader_.Open(filename_.c_str()));
|
|
is_reader_open_ = true;
|
|
pos_ = 0;
|
|
mkvparser::EBMLHeader ebml_header;
|
|
ebml_header.Parse(&reader_, pos_);
|
|
ASSERT_EQ(1, ebml_header.m_version);
|
|
ASSERT_EQ(1, ebml_header.m_readVersion);
|
|
ASSERT_STREQ("webm", ebml_header.m_docType);
|
|
ASSERT_EQ(expected_doc_type_ver, ebml_header.m_docTypeVersion);
|
|
ASSERT_EQ(2, ebml_header.m_docTypeReadVersion);
|
|
ASSERT_EQ(0, mkvparser::Segment::CreateInstance(&reader_, pos_, segment_));
|
|
ASSERT_FALSE(HasFailure());
|
|
ASSERT_GE(0, segment_->Load());
|
|
}
|
|
|
|
void CreateAndLoadSegment(const std::string& filename) {
|
|
CreateAndLoadSegment(filename, 4);
|
|
}
|
|
|
|
// Load a corrupted segment with no expectation of correctness.
|
|
void CreateAndLoadInvalidSegment(const std::string& filename) {
|
|
filename_ = test::GetTestFilePath(filename);
|
|
ASSERT_EQ(0, reader_.Open(filename_.c_str()));
|
|
is_reader_open_ = true;
|
|
pos_ = 0;
|
|
mkvparser::EBMLHeader ebml_header;
|
|
ebml_header.Parse(&reader_, pos_);
|
|
ASSERT_EQ(0, mkvparser::Segment::CreateInstance(&reader_, pos_, segment_));
|
|
ASSERT_GE(0, segment_->Load());
|
|
}
|
|
|
|
void ProcessTheFrames(bool invalid_bitstream) {
|
|
unsigned char* data = NULL;
|
|
size_t data_len = 0;
|
|
const mkvparser::Tracks* const parser_tracks = segment_->GetTracks();
|
|
ASSERT_TRUE(parser_tracks != NULL);
|
|
const mkvparser::Cluster* cluster = segment_->GetFirst();
|
|
ASSERT_TRUE(cluster != NULL);
|
|
|
|
while ((cluster != NULL) && !cluster->EOS()) {
|
|
const mkvparser::BlockEntry* block_entry;
|
|
long status = cluster->GetFirst(block_entry); // NOLINT
|
|
ASSERT_EQ(0, status);
|
|
|
|
while ((block_entry != NULL) && !block_entry->EOS()) {
|
|
const mkvparser::Block* const block = block_entry->GetBlock();
|
|
ASSERT_TRUE(block != NULL);
|
|
const long long trackNum = block->GetTrackNumber(); // NOLINT
|
|
const mkvparser::Track* const parser_track =
|
|
parser_tracks->GetTrackByNumber(
|
|
static_cast<unsigned long>(trackNum)); // NOLINT
|
|
ASSERT_TRUE(parser_track != NULL);
|
|
const long long track_type = parser_track->GetType(); // NOLINT
|
|
|
|
if (track_type == mkvparser::Track::kVideo) {
|
|
const int frame_count = block->GetFrameCount();
|
|
|
|
for (int i = 0; i < frame_count; ++i) {
|
|
const mkvparser::Block::Frame& frame = block->GetFrame(i);
|
|
|
|
if (static_cast<size_t>(frame.len) > data_len) {
|
|
delete[] data;
|
|
data = new unsigned char[frame.len];
|
|
ASSERT_TRUE(data != NULL);
|
|
data_len = static_cast<size_t>(frame.len);
|
|
}
|
|
ASSERT_FALSE(frame.Read(&reader_, data));
|
|
ASSERT_EQ(parser_.ParseUncompressedHeader(data, data_len),
|
|
!invalid_bitstream);
|
|
}
|
|
}
|
|
|
|
status = cluster->GetNext(block_entry, block_entry);
|
|
ASSERT_EQ(0, status);
|
|
}
|
|
|
|
cluster = segment_->GetNext(cluster);
|
|
}
|
|
delete[] data;
|
|
}
|
|
|
|
protected:
|
|
mkvparser::MkvReader reader_;
|
|
bool is_reader_open_;
|
|
mkvparser::Segment* segment_;
|
|
std::string filename_;
|
|
long long pos_; // NOLINT
|
|
vp9_parser::Vp9HeaderParser parser_;
|
|
};
|
|
|
|
TEST_F(Vp9HeaderParserTests, VideoOnlyFile) {
|
|
ASSERT_NO_FATAL_FAILURE(CreateAndLoadSegment("test_stereo_left_right.webm"));
|
|
ProcessTheFrames(false);
|
|
EXPECT_EQ(256, parser_.width());
|
|
EXPECT_EQ(144, parser_.height());
|
|
EXPECT_EQ(1, parser_.column_tiles());
|
|
EXPECT_EQ(0, parser_.frame_parallel_mode());
|
|
}
|
|
|
|
TEST_F(Vp9HeaderParserTests, Muxed) {
|
|
ASSERT_NO_FATAL_FAILURE(
|
|
CreateAndLoadSegment("bbb_480p_vp9_opus_1second.webm", 4));
|
|
ProcessTheFrames(false);
|
|
EXPECT_EQ(854, parser_.width());
|
|
EXPECT_EQ(480, parser_.height());
|
|
EXPECT_EQ(2, parser_.column_tiles());
|
|
EXPECT_EQ(1, parser_.frame_parallel_mode());
|
|
}
|
|
|
|
TEST_F(Vp9HeaderParserTests, Invalid) {
|
|
const char* files[] = {
|
|
"invalid/invalid_vp9_bitstream-bug_1416.webm",
|
|
"invalid/invalid_vp9_bitstream-bug_1417.webm",
|
|
};
|
|
|
|
for (int i = 0; i < static_cast<int>(sizeof(files) / sizeof(files[0])); ++i) {
|
|
SCOPED_TRACE(files[i]);
|
|
ASSERT_NO_FATAL_FAILURE(CreateAndLoadInvalidSegment(files[i]));
|
|
ProcessTheFrames(true);
|
|
CloseReader();
|
|
delete segment_;
|
|
segment_ = NULL;
|
|
}
|
|
}
|
|
|
|
TEST_F(Vp9HeaderParserTests, API) {
|
|
vp9_parser::Vp9HeaderParser parser;
|
|
uint8_t data;
|
|
EXPECT_FALSE(parser.ParseUncompressedHeader(NULL, 0));
|
|
EXPECT_FALSE(parser.ParseUncompressedHeader(NULL, 10));
|
|
EXPECT_FALSE(parser.ParseUncompressedHeader(&data, 0));
|
|
}
|
|
|
|
} // namespace
|
|
|
|
int main(int argc, char* argv[]) {
|
|
::testing::InitGoogleTest(&argc, argv);
|
|
return RUN_ALL_TESTS();
|
|
}
|