(61d00a474) v0.9.7.1

This commit is contained in:
Regalis
2020-03-04 13:04:10 +01:00
parent 3c50efa5c9
commit 3c09ebe02f
5086 changed files with 786063 additions and 295871 deletions
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,823 @@
// 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 "gtest/gtest.h"
#include <array>
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <iomanip>
#include <string>
#include "common/hdr_util.h"
#include "mkvparser/mkvparser.h"
#include "mkvparser/mkvreader.h"
#include "testing/test_util.h"
using mkvparser::AudioTrack;
using mkvparser::Block;
using mkvparser::BlockEntry;
using mkvparser::BlockGroup;
using mkvparser::Cluster;
using mkvparser::CuePoint;
using mkvparser::Cues;
using mkvparser::MkvReader;
using mkvparser::Segment;
using mkvparser::SegmentInfo;
using mkvparser::Track;
using mkvparser::Tracks;
using mkvparser::VideoTrack;
namespace test {
// Base class containing boiler plate stuff.
class ParserTest : public testing::Test {
public:
ParserTest() : is_reader_open_(false), segment_(NULL) {
memset(dummy_data_, -1, kFrameLength);
memset(gold_frame_, 0, kFrameLength);
}
virtual ~ParserTest() {
CloseReader();
if (segment_ != NULL) {
delete segment_;
segment_ = NULL;
}
}
void CloseReader() {
if (is_reader_open_) {
reader_.Close();
}
is_reader_open_ = false;
}
bool CreateAndLoadSegment(const std::string& filename,
int expected_doc_type_ver) {
filename_ = GetTestFilePath(filename);
if (reader_.Open(filename_.c_str())) {
return false;
}
is_reader_open_ = true;
pos_ = 0;
mkvparser::EBMLHeader ebml_header;
ebml_header.Parse(&reader_, pos_);
EXPECT_EQ(1, ebml_header.m_version);
EXPECT_EQ(1, ebml_header.m_readVersion);
EXPECT_STREQ("webm", ebml_header.m_docType);
EXPECT_EQ(expected_doc_type_ver, ebml_header.m_docTypeVersion);
EXPECT_EQ(2, ebml_header.m_docTypeReadVersion);
if (mkvparser::Segment::CreateInstance(&reader_, pos_, segment_)) {
return false;
}
return !HasFailure() && segment_->Load() >= 0;
}
bool CreateAndLoadSegment(const std::string& filename) {
return CreateAndLoadSegment(filename, 4);
}
void CreateSegmentNoHeaderChecks(const std::string& filename) {
filename_ = GetTestFilePath(filename);
ASSERT_NE(0u, filename_.length());
ASSERT_EQ(0, reader_.Open(filename_.c_str()));
mkvparser::EBMLHeader ebml_header;
ASSERT_EQ(0, ebml_header.Parse(&reader_, pos_));
ASSERT_EQ(0, mkvparser::Segment::CreateInstance(&reader_, pos_, segment_));
}
void CompareBlockContents(const Cluster* const cluster,
const Block* const block, std::uint64_t timestamp,
int track_number, bool is_key, int frame_count) {
ASSERT_TRUE(block != NULL);
EXPECT_EQ(track_number, block->GetTrackNumber());
EXPECT_EQ(static_cast<long long>(timestamp), block->GetTime(cluster));
EXPECT_EQ(is_key, block->IsKey());
EXPECT_EQ(frame_count, block->GetFrameCount());
const Block::Frame& frame = block->GetFrame(0);
EXPECT_EQ(kFrameLength, frame.len);
std::memset(dummy_data_, -1, kFrameLength);
frame.Read(&reader_, dummy_data_);
EXPECT_EQ(0, std::memcmp(gold_frame_, dummy_data_, kFrameLength));
}
void CompareCuePointContents(const Track* const track,
const CuePoint* const cue_point,
std::uint64_t timestamp, int track_number,
std::uint64_t pos) {
ASSERT_TRUE(cue_point != NULL);
EXPECT_EQ(static_cast<long long>(timestamp), cue_point->GetTime(segment_));
const CuePoint::TrackPosition* const track_position =
cue_point->Find(track);
EXPECT_EQ(track_number, track_position->m_track);
EXPECT_EQ(static_cast<long long>(pos), track_position->m_pos);
}
protected:
MkvReader reader_;
bool is_reader_open_;
Segment* segment_;
std::string filename_;
long long pos_;
std::uint8_t dummy_data_[kFrameLength];
std::uint8_t gold_frame_[kFrameLength];
};
TEST_F(ParserTest, SegmentInfo) {
ASSERT_TRUE(CreateAndLoadSegment("segment_info.webm"));
const SegmentInfo* const info = segment_->GetInfo();
EXPECT_EQ(kTimeCodeScale, info->GetTimeCodeScale());
EXPECT_STREQ(kAppString, info->GetMuxingAppAsUTF8());
EXPECT_STREQ(kAppString, info->GetWritingAppAsUTF8());
}
TEST_F(ParserTest, TrackEntries) {
ASSERT_TRUE(CreateAndLoadSegment("tracks.webm"));
const Tracks* const tracks = segment_->GetTracks();
const unsigned int kTracksCount = 2;
EXPECT_EQ(kTracksCount, tracks->GetTracksCount());
for (int i = 0; i < 2; ++i) {
const Track* const track = tracks->GetTrackByIndex(i);
ASSERT_TRUE(track != NULL);
EXPECT_STREQ(kTrackName, track->GetNameAsUTF8());
if (track->GetType() == Track::kVideo) {
const VideoTrack* const video_track =
dynamic_cast<const VideoTrack*>(track);
EXPECT_EQ(kWidth, static_cast<int>(video_track->GetWidth()));
EXPECT_EQ(kHeight, static_cast<int>(video_track->GetHeight()));
EXPECT_STREQ(kVP8CodecId, video_track->GetCodecId());
EXPECT_DOUBLE_EQ(kVideoFrameRate, video_track->GetFrameRate());
const unsigned int kTrackUid = 1;
EXPECT_EQ(kTrackUid, video_track->GetUid());
} else if (track->GetType() == Track::kAudio) {
const AudioTrack* const audio_track =
dynamic_cast<const AudioTrack*>(track);
EXPECT_EQ(kSampleRate, audio_track->GetSamplingRate());
EXPECT_EQ(kChannels, audio_track->GetChannels());
EXPECT_EQ(kBitDepth, audio_track->GetBitDepth());
EXPECT_STREQ(kVorbisCodecId, audio_track->GetCodecId());
const unsigned int kTrackUid = 2;
EXPECT_EQ(kTrackUid, audio_track->GetUid());
}
}
}
TEST_F(ParserTest, SimpleBlock) {
ASSERT_TRUE(CreateAndLoadSegment("simple_block.webm"));
const unsigned int kTracksCount = 1;
EXPECT_EQ(kTracksCount, segment_->GetTracks()->GetTracksCount());
// Get the cluster
const Cluster* cluster = segment_->GetFirst();
ASSERT_TRUE(cluster != NULL);
EXPECT_FALSE(cluster->EOS());
// Get the first block
const BlockEntry* block_entry;
EXPECT_EQ(0, cluster->GetFirst(block_entry));
ASSERT_TRUE(block_entry != NULL);
EXPECT_FALSE(block_entry->EOS());
CompareBlockContents(cluster, block_entry->GetBlock(), 0, kVideoTrackNumber,
false, 1);
// Get the second block
EXPECT_EQ(0, cluster->GetNext(block_entry, block_entry));
ASSERT_TRUE(block_entry != NULL);
EXPECT_FALSE(block_entry->EOS());
CompareBlockContents(cluster, block_entry->GetBlock(), 2000000,
kVideoTrackNumber, false, 1);
// End of Stream
EXPECT_EQ(0, cluster->GetNext(block_entry, block_entry));
ASSERT_EQ(NULL, block_entry);
cluster = segment_->GetNext(cluster);
EXPECT_TRUE(cluster->EOS());
}
TEST_F(ParserTest, MultipleClusters) {
ASSERT_TRUE(CreateAndLoadSegment("force_new_cluster.webm"));
const unsigned int kTracksCount = 1;
EXPECT_EQ(kTracksCount, segment_->GetTracks()->GetTracksCount());
// Get the first cluster
const Cluster* cluster = segment_->GetFirst();
ASSERT_TRUE(cluster != NULL);
EXPECT_FALSE(cluster->EOS());
// Get the first block
const BlockEntry* block_entry;
EXPECT_EQ(0, cluster->GetFirst(block_entry));
ASSERT_TRUE(block_entry != NULL);
EXPECT_FALSE(block_entry->EOS());
CompareBlockContents(cluster, block_entry->GetBlock(), 0, kVideoTrackNumber,
false, 1);
// Get the second cluster
EXPECT_EQ(0, cluster->GetNext(block_entry, block_entry));
EXPECT_EQ(NULL, block_entry);
cluster = segment_->GetNext(cluster);
ASSERT_TRUE(cluster != NULL);
EXPECT_FALSE(cluster->EOS());
// Get the second block
EXPECT_EQ(0, cluster->GetFirst(block_entry));
ASSERT_TRUE(block_entry != NULL);
EXPECT_FALSE(block_entry->EOS());
CompareBlockContents(cluster, block_entry->GetBlock(), 2000000,
kVideoTrackNumber, false, 1);
// Get the third block
EXPECT_EQ(0, cluster->GetNext(block_entry, block_entry));
ASSERT_TRUE(block_entry != NULL);
EXPECT_FALSE(block_entry->EOS());
CompareBlockContents(cluster, block_entry->GetBlock(), 4000000,
kVideoTrackNumber, false, 1);
// Get the third cluster
EXPECT_EQ(0, cluster->GetNext(block_entry, block_entry));
EXPECT_EQ(NULL, block_entry);
cluster = segment_->GetNext(cluster);
ASSERT_TRUE(cluster != NULL);
EXPECT_FALSE(cluster->EOS());
// Get the fourth block
EXPECT_EQ(0, cluster->GetFirst(block_entry));
ASSERT_TRUE(block_entry != NULL);
EXPECT_FALSE(block_entry->EOS());
CompareBlockContents(cluster, block_entry->GetBlock(), 6000000,
kVideoTrackNumber, false, 1);
// End of Stream
EXPECT_EQ(0, cluster->GetNext(block_entry, block_entry));
EXPECT_EQ(NULL, block_entry);
cluster = segment_->GetNext(cluster);
EXPECT_TRUE(cluster->EOS());
}
TEST_F(ParserTest, BlockGroup) {
ASSERT_TRUE(CreateAndLoadSegment("metadata_block.webm"));
const unsigned int kTracksCount = 1;
EXPECT_EQ(kTracksCount, segment_->GetTracks()->GetTracksCount());
// Get the cluster
const Cluster* cluster = segment_->GetFirst();
ASSERT_TRUE(cluster != NULL);
EXPECT_FALSE(cluster->EOS());
// Get the first block
const BlockEntry* block_entry;
EXPECT_EQ(0, cluster->GetFirst(block_entry));
ASSERT_TRUE(block_entry != NULL);
EXPECT_FALSE(block_entry->EOS());
EXPECT_EQ(BlockEntry::Kind::kBlockGroup, block_entry->GetKind());
const BlockGroup* block_group = static_cast<const BlockGroup*>(block_entry);
EXPECT_EQ(2, block_group->GetDurationTimeCode());
CompareBlockContents(cluster, block_group->GetBlock(), 0,
kMetadataTrackNumber, true, 1);
// Get the second block
EXPECT_EQ(0, cluster->GetNext(block_entry, block_entry));
ASSERT_TRUE(block_entry != NULL);
EXPECT_FALSE(block_entry->EOS());
EXPECT_EQ(BlockEntry::Kind::kBlockGroup, block_entry->GetKind());
block_group = static_cast<const BlockGroup*>(block_entry);
EXPECT_EQ(6, block_group->GetDurationTimeCode());
CompareBlockContents(cluster, block_group->GetBlock(), 2000000,
kMetadataTrackNumber, true, 1);
// End of Stream
EXPECT_EQ(0, cluster->GetNext(block_entry, block_entry));
EXPECT_EQ(NULL, block_entry);
cluster = segment_->GetNext(cluster);
EXPECT_TRUE(cluster->EOS());
}
TEST_F(ParserTest, Cues) {
ASSERT_TRUE(CreateAndLoadSegment("output_cues.webm"));
const unsigned int kTracksCount = 1;
EXPECT_EQ(kTracksCount, segment_->GetTracks()->GetTracksCount());
const Track* const track = segment_->GetTracks()->GetTrackByIndex(0);
const Cues* const cues = segment_->GetCues();
ASSERT_TRUE(cues != NULL);
while (!cues->DoneParsing()) {
cues->LoadCuePoint();
}
EXPECT_EQ(3, cues->GetCount());
// Get first Cue Point
const CuePoint* cue_point = cues->GetFirst();
CompareCuePointContents(track, cue_point, 0, kVideoTrackNumber, 206);
// Get second Cue Point
cue_point = cues->GetNext(cue_point);
CompareCuePointContents(track, cue_point, 6000000, kVideoTrackNumber, 269);
// Get third (also last) Cue Point
cue_point = cues->GetNext(cue_point);
const CuePoint* last_cue_point = cues->GetLast();
EXPECT_TRUE(cue_point == last_cue_point);
CompareCuePointContents(track, cue_point, 4000000, kVideoTrackNumber, 269);
EXPECT_TRUE(ValidateCues(segment_, &reader_));
}
TEST_F(ParserTest, CuesBeforeClusters) {
ASSERT_TRUE(CreateAndLoadSegment("cues_before_clusters.webm"));
const unsigned int kTracksCount = 1;
EXPECT_EQ(kTracksCount, segment_->GetTracks()->GetTracksCount());
const Track* const track = segment_->GetTracks()->GetTrackByIndex(0);
const Cues* const cues = segment_->GetCues();
ASSERT_TRUE(cues != NULL);
while (!cues->DoneParsing()) {
cues->LoadCuePoint();
}
EXPECT_EQ(2, cues->GetCount());
// Get first Cue Point
const CuePoint* cue_point = cues->GetFirst();
CompareCuePointContents(track, cue_point, 0, kVideoTrackNumber, 238);
// Get second (also last) Cue Point
cue_point = cues->GetNext(cue_point);
const CuePoint* last_cue_point = cues->GetLast();
EXPECT_TRUE(cue_point == last_cue_point);
CompareCuePointContents(track, cue_point, 6000000, kVideoTrackNumber, 301);
EXPECT_TRUE(ValidateCues(segment_, &reader_));
}
TEST_F(ParserTest, CuesTrackNumber) {
ASSERT_TRUE(CreateAndLoadSegment("set_cues_track_number.webm"));
const unsigned int kTracksCount = 1;
EXPECT_EQ(kTracksCount, segment_->GetTracks()->GetTracksCount());
const Track* const track = segment_->GetTracks()->GetTrackByIndex(0);
const Cues* const cues = segment_->GetCues();
ASSERT_TRUE(cues != NULL);
while (!cues->DoneParsing()) {
cues->LoadCuePoint();
}
EXPECT_EQ(2, cues->GetCount());
// Get first Cue Point
const CuePoint* cue_point = cues->GetFirst();
CompareCuePointContents(track, cue_point, 0, 10, 206);
// Get second (also last) Cue Point
cue_point = cues->GetNext(cue_point);
const CuePoint* last_cue_point = cues->GetLast();
EXPECT_TRUE(cue_point == last_cue_point);
CompareCuePointContents(track, cue_point, 6000000, 10, 269);
EXPECT_TRUE(ValidateCues(segment_, &reader_));
}
TEST_F(ParserTest, Opus) {
ASSERT_TRUE(CreateAndLoadSegment("bbb_480p_vp9_opus_1second.webm", 4));
const unsigned int kTracksCount = 2;
EXPECT_EQ(kTracksCount, segment_->GetTracks()->GetTracksCount());
// --------------------------------------------------------------------------
// Track Header validation.
const Tracks* const tracks = segment_->GetTracks();
EXPECT_EQ(kTracksCount, tracks->GetTracksCount());
for (int i = 0; i < 2; ++i) {
const Track* const track = tracks->GetTrackByIndex(i);
ASSERT_TRUE(track != NULL);
EXPECT_EQ(NULL, track->GetNameAsUTF8());
EXPECT_STREQ("und", track->GetLanguage());
EXPECT_EQ(i + 1, track->GetNumber());
EXPECT_FALSE(track->GetLacing());
if (track->GetType() == Track::kVideo) {
const VideoTrack* const video_track =
dynamic_cast<const VideoTrack*>(track);
EXPECT_EQ(854, static_cast<int>(video_track->GetWidth()));
EXPECT_EQ(480, static_cast<int>(video_track->GetHeight()));
EXPECT_STREQ(kVP9CodecId, video_track->GetCodecId());
EXPECT_DOUBLE_EQ(0., video_track->GetFrameRate());
EXPECT_EQ(41666666,
static_cast<int>(video_track->GetDefaultDuration())); // 24.000
const unsigned int kVideoUid = kVideoTrackNumber;
EXPECT_EQ(kVideoUid, video_track->GetUid());
const unsigned int kCodecDelay = 0;
EXPECT_EQ(kCodecDelay, video_track->GetCodecDelay());
const unsigned int kSeekPreRoll = 0;
EXPECT_EQ(kSeekPreRoll, video_track->GetSeekPreRoll());
size_t video_codec_private_size;
EXPECT_EQ(NULL, video_track->GetCodecPrivate(video_codec_private_size));
const unsigned int kPrivateSize = 0;
EXPECT_EQ(kPrivateSize, video_codec_private_size);
} else if (track->GetType() == Track::kAudio) {
const AudioTrack* const audio_track =
dynamic_cast<const AudioTrack*>(track);
EXPECT_EQ(48000, audio_track->GetSamplingRate());
EXPECT_EQ(6, audio_track->GetChannels());
EXPECT_EQ(32, audio_track->GetBitDepth());
EXPECT_STREQ(kOpusCodecId, audio_track->GetCodecId());
EXPECT_EQ(kAudioTrackNumber, static_cast<int>(audio_track->GetUid()));
const unsigned int kDefaultDuration = 0;
EXPECT_EQ(kDefaultDuration, audio_track->GetDefaultDuration());
EXPECT_EQ(kOpusCodecDelay, audio_track->GetCodecDelay());
EXPECT_EQ(kOpusSeekPreroll, audio_track->GetSeekPreRoll());
size_t audio_codec_private_size;
EXPECT_TRUE(audio_track->GetCodecPrivate(audio_codec_private_size) !=
NULL);
EXPECT_GE(audio_codec_private_size, kOpusPrivateDataSizeMinimum);
}
}
// --------------------------------------------------------------------------
// Parse the file to do block-level validation.
const Cluster* cluster = segment_->GetFirst();
ASSERT_TRUE(cluster != NULL);
EXPECT_FALSE(cluster->EOS());
for (; cluster != NULL && !cluster->EOS();
cluster = segment_->GetNext(cluster)) {
// Get the first block
const BlockEntry* block_entry;
EXPECT_EQ(0, cluster->GetFirst(block_entry));
ASSERT_TRUE(block_entry != NULL);
EXPECT_FALSE(block_entry->EOS());
while (block_entry != NULL && !block_entry->EOS()) {
const Block* const block = block_entry->GetBlock();
ASSERT_TRUE(block != NULL);
EXPECT_FALSE(block->IsInvisible());
EXPECT_EQ(Block::kLacingNone, block->GetLacing());
const std::uint32_t track_number =
static_cast<std::uint32_t>(block->GetTrackNumber());
const Track* const track = tracks->GetTrackByNumber(track_number);
ASSERT_TRUE(track != NULL);
EXPECT_EQ(track->GetNumber(), block->GetTrackNumber());
const unsigned int kContentEncodingCount = 0;
EXPECT_EQ(kContentEncodingCount,
track->GetContentEncodingCount()); // no encryption
const std::int64_t track_type = track->GetType();
EXPECT_TRUE(track_type == Track::kVideo || track_type == Track::kAudio);
if (track_type == Track::kVideo) {
EXPECT_EQ(BlockEntry::kBlockSimple, block_entry->GetKind());
EXPECT_EQ(0, block->GetDiscardPadding());
} else {
EXPECT_TRUE(block->IsKey());
const std::int64_t kLastAudioTimecode = 1001;
const std::int64_t timecode = block->GetTimeCode(cluster);
// Only the final Opus block should have discard padding.
if (timecode == kLastAudioTimecode) {
EXPECT_EQ(BlockEntry::kBlockGroup, block_entry->GetKind());
EXPECT_EQ(13500000, block->GetDiscardPadding());
} else {
EXPECT_EQ(BlockEntry::kBlockSimple, block_entry->GetKind());
EXPECT_EQ(0, block->GetDiscardPadding());
}
}
const int frame_count = block->GetFrameCount();
const Block::Frame& frame = block->GetFrame(0);
EXPECT_EQ(1, frame_count);
EXPECT_GT(frame.len, 0);
EXPECT_EQ(0, cluster->GetNext(block_entry, block_entry));
}
}
ASSERT_TRUE(cluster != NULL);
EXPECT_TRUE(cluster->EOS());
}
TEST_F(ParserTest, DiscardPadding) {
// Test an artificial file with some extreme DiscardPadding values.
const std::string file = "discard_padding.webm";
ASSERT_TRUE(CreateAndLoadSegment(file, 4));
const unsigned int kTracksCount = 1;
EXPECT_EQ(kTracksCount, segment_->GetTracks()->GetTracksCount());
// --------------------------------------------------------------------------
// Track Header validation.
const Tracks* const tracks = segment_->GetTracks();
EXPECT_EQ(kTracksCount, tracks->GetTracksCount());
const Track* const track = tracks->GetTrackByIndex(0);
ASSERT_TRUE(track != NULL);
EXPECT_STREQ(NULL, track->GetNameAsUTF8());
EXPECT_EQ(NULL, track->GetLanguage());
EXPECT_EQ(kAudioTrackNumber, track->GetNumber());
EXPECT_TRUE(track->GetLacing());
EXPECT_EQ(Track::kAudio, track->GetType());
const AudioTrack* const audio_track = dynamic_cast<const AudioTrack*>(track);
EXPECT_EQ(30, audio_track->GetSamplingRate());
EXPECT_EQ(2, audio_track->GetChannels());
EXPECT_STREQ(kOpusCodecId, audio_track->GetCodecId());
EXPECT_EQ(kAudioTrackNumber, static_cast<int>(audio_track->GetUid()));
const unsigned int kDefaultDuration = 0;
EXPECT_EQ(kDefaultDuration, audio_track->GetDefaultDuration());
const unsigned int kCodecDelay = 0;
EXPECT_EQ(kCodecDelay, audio_track->GetCodecDelay());
const unsigned int kSeekPreRoll = 0;
EXPECT_EQ(kSeekPreRoll, audio_track->GetSeekPreRoll());
size_t audio_codec_private_size;
EXPECT_EQ(NULL, audio_track->GetCodecPrivate(audio_codec_private_size));
const unsigned int kPrivateSize = 0;
EXPECT_EQ(kPrivateSize, audio_codec_private_size);
// --------------------------------------------------------------------------
// Parse the file to do block-level validation.
const Cluster* cluster = segment_->GetFirst();
ASSERT_TRUE(cluster != NULL);
EXPECT_FALSE(cluster->EOS());
const unsigned int kSegmentCount = 1;
EXPECT_EQ(kSegmentCount, segment_->GetCount());
// Get the first block
const BlockEntry* block_entry;
EXPECT_EQ(0, cluster->GetFirst(block_entry));
ASSERT_TRUE(block_entry != NULL);
EXPECT_FALSE(block_entry->EOS());
const std::array<int, 3> discard_padding = {{12810000, 127, -128}};
int index = 0;
while (block_entry != NULL && !block_entry->EOS()) {
const Block* const block = block_entry->GetBlock();
ASSERT_TRUE(block != NULL);
EXPECT_FALSE(block->IsInvisible());
EXPECT_EQ(Block::kLacingNone, block->GetLacing());
const std::uint32_t track_number =
static_cast<std::uint32_t>(block->GetTrackNumber());
const Track* const track = tracks->GetTrackByNumber(track_number);
ASSERT_TRUE(track != NULL);
EXPECT_EQ(track->GetNumber(), block->GetTrackNumber());
const unsigned int kContentEncodingCount = 0;
EXPECT_EQ(kContentEncodingCount,
track->GetContentEncodingCount()); // no encryption
const std::int64_t track_type = track->GetType();
EXPECT_EQ(Track::kAudio, track_type);
EXPECT_TRUE(block->IsKey());
// All blocks have DiscardPadding.
EXPECT_EQ(BlockEntry::kBlockGroup, block_entry->GetKind());
ASSERT_LT(index, static_cast<int>(discard_padding.size()));
EXPECT_EQ(discard_padding[index], block->GetDiscardPadding());
++index;
const int frame_count = block->GetFrameCount();
const Block::Frame& frame = block->GetFrame(0);
EXPECT_EQ(1, frame_count);
EXPECT_GT(frame.len, 0);
EXPECT_EQ(0, cluster->GetNext(block_entry, block_entry));
}
cluster = segment_->GetNext(cluster);
ASSERT_TRUE(cluster != NULL);
EXPECT_TRUE(cluster->EOS());
}
TEST_F(ParserTest, StereoModeParsedCorrectly) {
ASSERT_TRUE(CreateAndLoadSegment("test_stereo_left_right.webm"));
const unsigned int kTracksCount = 1;
EXPECT_EQ(kTracksCount, segment_->GetTracks()->GetTracksCount());
const VideoTrack* const video_track = dynamic_cast<const VideoTrack*>(
segment_->GetTracks()->GetTrackByIndex(0));
EXPECT_EQ(1, video_track->GetStereoMode());
EXPECT_EQ(256, video_track->GetWidth());
EXPECT_EQ(144, video_track->GetHeight());
EXPECT_EQ(128, video_track->GetDisplayWidth());
EXPECT_EQ(144, video_track->GetDisplayHeight());
}
TEST_F(ParserTest, CanParseColour) {
ASSERT_TRUE(CreateAndLoadSegment("colour.webm"));
const unsigned int kTracksCount = 1;
EXPECT_EQ(kTracksCount, segment_->GetTracks()->GetTracksCount());
const VideoTrack* const video_track = dynamic_cast<const VideoTrack*>(
segment_->GetTracks()->GetTrackByIndex(0));
const mkvparser::Colour* const colour = video_track->GetColour();
ASSERT_TRUE(colour != nullptr);
EXPECT_EQ(0u, colour->matrix_coefficients);
EXPECT_EQ(1u, colour->bits_per_channel);
EXPECT_EQ(2u, colour->chroma_subsampling_horz);
EXPECT_EQ(3u, colour->chroma_subsampling_vert);
EXPECT_EQ(4u, colour->cb_subsampling_horz);
EXPECT_EQ(5u, colour->cb_subsampling_vert);
EXPECT_EQ(1u, colour->chroma_siting_horz);
EXPECT_EQ(1u, colour->chroma_siting_vert);
EXPECT_EQ(2u, colour->range);
EXPECT_EQ(9u, colour->transfer_characteristics);
EXPECT_EQ(10u, colour->primaries);
EXPECT_EQ(11u, colour->max_cll);
EXPECT_EQ(12u, colour->max_fall);
const mkvparser::MasteringMetadata* const mm =
video_track->GetColour()->mastering_metadata;
ASSERT_TRUE(mm != nullptr);
ASSERT_TRUE(mm->r != nullptr);
ASSERT_TRUE(mm->g != nullptr);
ASSERT_TRUE(mm->b != nullptr);
ASSERT_TRUE(mm->white_point != nullptr);
EXPECT_FLOAT_EQ(.1, mm->r->x);
EXPECT_FLOAT_EQ(.2, mm->r->y);
EXPECT_FLOAT_EQ(.1, mm->g->x);
EXPECT_FLOAT_EQ(.2, mm->g->y);
EXPECT_FLOAT_EQ(.1, mm->b->x);
EXPECT_FLOAT_EQ(.2, mm->b->y);
EXPECT_FLOAT_EQ(.1, mm->white_point->x);
EXPECT_FLOAT_EQ(.2, mm->white_point->y);
EXPECT_FLOAT_EQ(30.0, mm->luminance_min);
EXPECT_FLOAT_EQ(40.0, mm->luminance_max);
}
TEST_F(ParserTest, CanParseProjection) {
ASSERT_TRUE(CreateAndLoadSegment("projection.webm"));
const unsigned int kTracksCount = 1;
EXPECT_EQ(kTracksCount, segment_->GetTracks()->GetTracksCount());
const VideoTrack* const video_track =
static_cast<const VideoTrack*>(segment_->GetTracks()->GetTrackByIndex(0));
const mkvparser::Projection* const projection = video_track->GetProjection();
ASSERT_TRUE(projection != nullptr);
EXPECT_EQ(mkvparser::Projection::kRectangular, projection->type);
EXPECT_FLOAT_EQ(1, projection->pose_yaw);
EXPECT_FLOAT_EQ(2, projection->pose_pitch);
EXPECT_FLOAT_EQ(3, projection->pose_roll);
EXPECT_EQ(1u, projection->private_data_length);
ASSERT_TRUE(projection->private_data != nullptr);
EXPECT_EQ(4u, projection->private_data[0]);
}
TEST_F(ParserTest, Vp9CodecLevelTest) {
const int kCodecPrivateLength = 3;
const uint8_t good_codec_private_level[kCodecPrivateLength] = {2, 1, 11};
libwebm::Vp9CodecFeatures features;
EXPECT_TRUE(libwebm::ParseVpxCodecPrivate(&good_codec_private_level[0],
kCodecPrivateLength, &features));
EXPECT_EQ(libwebm::Vp9CodecFeatures::kValueNotPresent, features.profile);
EXPECT_EQ(11, features.level);
EXPECT_EQ(libwebm::Vp9CodecFeatures::kValueNotPresent, features.bit_depth);
EXPECT_EQ(libwebm::Vp9CodecFeatures::kValueNotPresent,
features.chroma_subsampling);
}
TEST_F(ParserTest, Vp9CodecProfileTest) {
const int kCodecPrivateLength = 3;
const uint8_t good_codec_private_profile[kCodecPrivateLength] = {1, 1, 1};
libwebm::Vp9CodecFeatures features;
EXPECT_TRUE(libwebm::ParseVpxCodecPrivate(&good_codec_private_profile[0],
kCodecPrivateLength, &features));
EXPECT_EQ(1, features.profile);
EXPECT_EQ(libwebm::Vp9CodecFeatures::kValueNotPresent, features.level);
EXPECT_EQ(libwebm::Vp9CodecFeatures::kValueNotPresent, features.bit_depth);
EXPECT_EQ(libwebm::Vp9CodecFeatures::kValueNotPresent,
features.chroma_subsampling);
}
TEST_F(ParserTest, Vp9CodecBitDepthTest) {
const int kCodecPrivateLength = 3;
const uint8_t good_codec_private_profile[kCodecPrivateLength] = {3, 1, 8};
libwebm::Vp9CodecFeatures features;
EXPECT_TRUE(libwebm::ParseVpxCodecPrivate(&good_codec_private_profile[0],
kCodecPrivateLength, &features));
EXPECT_EQ(libwebm::Vp9CodecFeatures::kValueNotPresent, features.profile);
EXPECT_EQ(libwebm::Vp9CodecFeatures::kValueNotPresent, features.level);
EXPECT_EQ(8, features.bit_depth);
EXPECT_EQ(libwebm::Vp9CodecFeatures::kValueNotPresent,
features.chroma_subsampling);
}
TEST_F(ParserTest, Vp9CodecChromaSubsamplingTest) {
const int kCodecPrivateLength = 3;
const uint8_t good_codec_private_profile[kCodecPrivateLength] = {4, 1, 0};
libwebm::Vp9CodecFeatures features;
EXPECT_TRUE(libwebm::ParseVpxCodecPrivate(&good_codec_private_profile[0],
kCodecPrivateLength, &features));
EXPECT_EQ(libwebm::Vp9CodecFeatures::kValueNotPresent, features.profile);
EXPECT_EQ(libwebm::Vp9CodecFeatures::kValueNotPresent, features.level);
EXPECT_EQ(libwebm::Vp9CodecFeatures::kValueNotPresent, features.bit_depth);
EXPECT_EQ(0, features.chroma_subsampling);
}
TEST_F(ParserTest, Vp9CodecProfileLevelTest) {
const int kCodecPrivateLength = 6;
const uint8_t codec_private[kCodecPrivateLength] = {1, 1, 1, 2, 1, 11};
libwebm::Vp9CodecFeatures features;
EXPECT_TRUE(libwebm::ParseVpxCodecPrivate(&codec_private[0],
kCodecPrivateLength, &features));
EXPECT_EQ(1, features.profile);
EXPECT_EQ(11, features.level);
}
TEST_F(ParserTest, Vp9CodecAllTest) {
const int kCodecPrivateLength = 12;
const uint8_t codec_private[kCodecPrivateLength] = {1, 1, 1, 2, 1, 11,
3, 1, 8, 4, 1, 0};
libwebm::Vp9CodecFeatures features;
EXPECT_TRUE(libwebm::ParseVpxCodecPrivate(&codec_private[0],
kCodecPrivateLength, &features));
EXPECT_EQ(1, features.profile);
EXPECT_EQ(11, features.level);
EXPECT_EQ(8, features.bit_depth);
EXPECT_EQ(0, features.chroma_subsampling);
}
TEST_F(ParserTest, Vp9CodecPrivateBadTest) {
const int kCodecPrivateLength = 3;
libwebm::Vp9CodecFeatures features;
// Test invalid codec private data; all of these should return false.
const uint8_t bad_codec_private[kCodecPrivateLength] = {0, 0, 0};
EXPECT_FALSE(
libwebm::ParseVpxCodecPrivate(NULL, kCodecPrivateLength, &features));
EXPECT_FALSE(
libwebm::ParseVpxCodecPrivate(&bad_codec_private[0], 0, &features));
EXPECT_FALSE(libwebm::ParseVpxCodecPrivate(&bad_codec_private[0],
kCodecPrivateLength, &features));
const uint8_t good_codec_private_level[kCodecPrivateLength] = {2, 1, 11};
// Test parse of codec private chunks, but lie about length.
EXPECT_FALSE(
libwebm::ParseVpxCodecPrivate(&bad_codec_private[0], 0, &features));
EXPECT_FALSE(libwebm::ParseVpxCodecPrivate(&good_codec_private_level[0], 0,
&features));
EXPECT_FALSE(libwebm::ParseVpxCodecPrivate(&good_codec_private_level[0],
kCodecPrivateLength, NULL));
}
TEST_F(ParserTest, InvalidTruncatedChapterString) {
ASSERT_NO_FATAL_FAILURE(CreateSegmentNoHeaderChecks(
"invalid/chapters_truncated_chapter_string.mkv"));
EXPECT_EQ(mkvparser::E_PARSE_FAILED, segment_->Load());
}
TEST_F(ParserTest, InvalidTruncatedChapterString2) {
ASSERT_NO_FATAL_FAILURE(CreateSegmentNoHeaderChecks(
"invalid/chapters_truncated_chapter_string_2.mkv"));
EXPECT_EQ(mkvparser::E_FILE_FORMAT_INVALID, segment_->Load());
}
TEST_F(ParserTest, InvalidFixedLacingSize) {
ASSERT_NO_FATAL_FAILURE(
CreateSegmentNoHeaderChecks("invalid/fixed_lacing_bad_lace_size.mkv"));
ASSERT_EQ(0, segment_->Load());
const mkvparser::BlockEntry* block_entry = NULL;
EXPECT_EQ(mkvparser::E_FILE_FORMAT_INVALID,
segment_->GetFirst()->GetFirst(block_entry));
}
TEST_F(ParserTest, InvalidBlockEndsBeyondCluster) {
ASSERT_NO_FATAL_FAILURE(
CreateSegmentNoHeaderChecks("invalid/block_ends_beyond_cluster.mkv"));
ASSERT_EQ(0, segment_->Load());
const mkvparser::BlockEntry* block_entry = NULL;
EXPECT_EQ(0, segment_->GetFirst()->GetFirst(block_entry));
EXPECT_EQ(mkvparser::E_FILE_FORMAT_INVALID,
segment_->GetFirst()->GetNext(block_entry, block_entry));
}
TEST_F(ParserTest, InvalidBlockGroupBlockEndsBlockGroup) {
ASSERT_NO_FATAL_FAILURE(CreateSegmentNoHeaderChecks(
"invalid/blockgroup_block_ends_beyond_blockgroup.mkv"));
ASSERT_EQ(0, segment_->Load());
const mkvparser::BlockEntry* block_entry = NULL;
EXPECT_EQ(0, segment_->GetFirst()->GetFirst(block_entry));
EXPECT_EQ(mkvparser::E_FILE_FORMAT_INVALID,
segment_->GetFirst()->GetNext(block_entry, block_entry));
}
TEST_F(ParserTest, InvalidProjectionFloatOverflow) {
ASSERT_NO_FATAL_FAILURE(
CreateSegmentNoHeaderChecks("invalid/projection_float_overflow.webm"));
EXPECT_EQ(mkvparser::E_FILE_FORMAT_INVALID, segment_->Load());
}
TEST_F(ParserTest, InvalidPrimaryChromaticityParseFail) {
ASSERT_NO_FATAL_FAILURE(CreateSegmentNoHeaderChecks(
"invalid/primarychromaticity_fieldtoolarge.webm"));
EXPECT_EQ(mkvparser::E_FILE_FORMAT_INVALID, segment_->Load());
}
} // namespace test
int main(int argc, char* argv[]) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
@@ -0,0 +1,215 @@
// 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 "testing/test_util.h"
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ios>
#include <string>
#include "common/libwebm_util.h"
#include "common/webmids.h"
#include "mkvparser/mkvparser.h"
#include "mkvparser/mkvreader.h"
namespace test {
std::string GetTestDataDir() {
const char* test_data_path = std::getenv("LIBWEBM_TEST_DATA_PATH");
return test_data_path ? std::string(test_data_path) : std::string();
}
std::string GetTestFilePath(const std::string& name) {
const std::string libwebm_testdata_dir = GetTestDataDir();
return libwebm_testdata_dir + "/" + name;
}
bool CompareFiles(const std::string& file1, const std::string& file2) {
const std::size_t kBlockSize = 4096;
std::uint8_t buf1[kBlockSize] = {0};
std::uint8_t buf2[kBlockSize] = {0};
libwebm::FilePtr f1 =
libwebm::FilePtr(std::fopen(file1.c_str(), "rb"), libwebm::FILEDeleter());
libwebm::FilePtr f2 =
libwebm::FilePtr(std::fopen(file2.c_str(), "rb"), libwebm::FILEDeleter());
if (!f1.get() || !f2.get()) {
// Files cannot match if one or both couldn't be opened.
return false;
}
do {
const std::size_t r1 = std::fread(buf1, 1, kBlockSize, f1.get());
const std::size_t r2 = std::fread(buf2, 1, kBlockSize, f2.get());
// TODO(fgalligan): Add output of which byte differs.
if (r1 != r2 || std::memcmp(buf1, buf2, r1)) {
return 0; // Files are not equal
}
} while (!std::feof(f1.get()) && !std::feof(f2.get()));
return std::feof(f1.get()) && std::feof(f2.get());
}
bool HasCuePoints(const mkvparser::Segment* segment,
std::int64_t* cues_offset) {
if (!segment || !cues_offset) {
return false;
}
using mkvparser::SeekHead;
const SeekHead* const seek_head = segment->GetSeekHead();
if (!seek_head) {
return false;
}
std::int64_t offset = 0;
for (int i = 0; i < seek_head->GetCount(); ++i) {
const SeekHead::Entry* const entry = seek_head->GetEntry(i);
if (entry->id == libwebm::kMkvCues) {
offset = entry->pos;
}
}
if (offset <= 0) {
// No Cues found.
return false;
}
*cues_offset = offset;
return true;
}
bool ValidateCues(mkvparser::Segment* segment, mkvparser::IMkvReader* reader) {
if (!segment) {
return false;
}
std::int64_t cues_offset = 0;
if (!HasCuePoints(segment, &cues_offset)) {
// No cues to validate, everything is OK.
return true;
}
// Parse Cues.
long long cues_pos = 0; // NOLINT
long cues_len = 0; // NOLINT
if (segment->ParseCues(cues_offset, cues_pos, cues_len)) {
return false;
}
// Get a pointer to the video track if it exists. Otherwise, we assume
// that Cues are based on the first track (which is true for all our test
// files).
const mkvparser::Tracks* const tracks = segment->GetTracks();
const mkvparser::Track* cues_track = tracks->GetTrackByIndex(0);
for (int i = 1; i < static_cast<int>(tracks->GetTracksCount()); ++i) {
const mkvparser::Track* const track = tracks->GetTrackByIndex(i);
if (track->GetType() == mkvparser::Track::kVideo) {
cues_track = track;
break;
}
}
// Iterate through Cues and verify if they are pointing to the correct
// Cluster position.
const mkvparser::Cues* const cues = segment->GetCues();
const mkvparser::CuePoint* cue_point = NULL;
while (cues->LoadCuePoint()) {
if (!cue_point) {
cue_point = cues->GetFirst();
} else {
cue_point = cues->GetNext(cue_point);
}
const mkvparser::CuePoint::TrackPosition* const track_position =
cue_point->Find(cues_track);
const long long cluster_pos = track_position->m_pos + // NOLINT
segment->m_start;
// If a cluster does not begin at |cluster_pos|, then the file is
// incorrect.
long length; // NOLINT
const std::int64_t id = mkvparser::ReadID(reader, cluster_pos, length);
if (id != libwebm::kMkvCluster) {
return false;
}
}
return true;
}
MkvParser::~MkvParser() {
delete segment;
delete reader;
}
bool ParseMkvFileReleaseParser(const std::string& webm_file,
MkvParser* parser_out) {
parser_out->reader = new (std::nothrow) mkvparser::MkvReader;
mkvparser::MkvReader& reader = *parser_out->reader;
if (!parser_out->reader || reader.Open(webm_file.c_str()) < 0) {
return false;
}
long long pos = 0; // NOLINT
mkvparser::EBMLHeader ebml_header;
if (ebml_header.Parse(&reader, pos)) {
return false;
}
using mkvparser::Segment;
Segment* segment_ptr = nullptr;
if (Segment::CreateInstance(&reader, pos, segment_ptr)) {
return false;
}
std::unique_ptr<Segment> segment(segment_ptr);
long result;
if ((result = segment->Load()) < 0) {
return false;
}
const mkvparser::Cluster* cluster = segment->GetFirst();
if (!cluster || cluster->EOS()) {
return false;
}
while (cluster && cluster->EOS() == false) {
if (cluster->GetTimeCode() < 0) {
return false;
}
const mkvparser::BlockEntry* block = nullptr;
if (cluster->GetFirst(block) < 0) {
return false;
}
while (block != NULL && block->EOS() == false) {
if (cluster->GetNext(block, block) < 0) {
return false;
}
}
cluster = segment->GetNext(cluster);
}
parser_out->segment = segment.release();
return true;
}
bool ParseMkvFile(const std::string& webm_file) {
MkvParser parser;
const bool result = ParseMkvFileReleaseParser(webm_file, &parser);
delete parser.segment;
delete parser.reader;
return result;
}
} // namespace test
@@ -0,0 +1,88 @@
// 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.
#ifndef LIBWEBM_TESTING_TEST_UTIL_H_
#define LIBWEBM_TESTING_TEST_UTIL_H_
#include <stdint.h>
#include <cstddef>
#include <string>
namespace mkvparser {
class IMkvReader;
class MkvReader;
class Segment;
} // namespace mkvparser
namespace test {
// constants for muxer and parser tests
const char kAppString[] = "mkvmuxer_unit_tests";
const char kOpusCodecId[] = "A_OPUS";
const char kVorbisCodecId[] = "A_VORBIS";
const int kAudioTrackNumber = 2;
const int kBitDepth = 2;
const int kChannels = 2;
const double kDuration = 2.345;
const int kFrameLength = 10;
const int kHeight = 180;
const int kInvalidTrackNumber = 100;
const std::uint64_t kOpusCodecDelay = 6500000;
const std::size_t kOpusPrivateDataSizeMinimum = 19;
const std::uint64_t kOpusSeekPreroll = 80000000;
const char kMetadataCodecId[] = "D_WEBVTT/METADATA";
const int kMetadataTrackNumber = 3;
const int kMetadataTrackType = 0x21;
const int kSampleRate = 30;
const int kTimeCodeScale = 1000;
const char kTrackName[] = "unit_test";
const char kVP8CodecId[] = "V_VP8";
const char kVP9CodecId[] = "V_VP9";
const double kVideoFrameRate = 0.5;
const int kVideoTrackNumber = 1;
const int kWidth = 320;
// Returns the path to the test data directory by reading and returning the
// contents the LIBWEBM_TESTDATA_DIR environment variable.
std::string GetTestDataDir();
// Returns the absolute path to the file of |name| in LIBWEBM_TESTDATA_DIR.
std::string GetTestFilePath(const std::string& name);
// Byte-wise comparison of two files |file1| and |file2|. Returns true if the
// files match exactly, false otherwise.
bool CompareFiles(const std::string& file1, const std::string& file2);
// Returns true and sets |cues_offset| to the cues location within the MKV file
// parsed by |segment| when the MKV file has cue points.
bool HasCuePoints(const mkvparser::Segment* segment, std::int64_t* cues_offset);
// Validates cue points. Assumes caller has already called Load() on |segment|.
// Returns true when:
// All cue points point at clusters, OR
// Data parsed by |segment| has no cue points.
bool ValidateCues(mkvparser::Segment* segment, mkvparser::IMkvReader* reader);
// Parses |webm_file| using mkvparser and returns true when file parses
// successfully (all clusters and blocks can be successfully walked). Second
// variant allows further interaction with the parsed file via transferring
// ownership of the mkvparser Segment and MkvReader to the caller via
// |parser_out|.
struct MkvParser {
MkvParser() = default;
~MkvParser();
mkvparser::Segment* segment = nullptr;
mkvparser::MkvReader* reader = nullptr;
};
bool ParseMkvFile(const std::string& webm_file);
bool ParseMkvFileReleaseParser(const std::string& webm_file,
MkvParser* parser_out);
} // namespace test
#endif // LIBWEBM_TESTING_TEST_UTIL_H_
Binary file not shown.
@@ -0,0 +1,24 @@
Why the files in this directory are considered invalid:
block_ends_beyond_cluster.mkv -
File containing a single cluster with two simple blocks. One valid, and the
second reporting a size that would cause the block to end far beyond the end
of its parent cluster.
blockgroup_block_ends_beyond_blockgroup.mkv -
File containing a single cluster and two blockgroups. The first blockgroup is
valid. The second blockgroup contains a block reporting a size that spans well
past the block and the end of the file.
chapters_truncated_chapter_string.mkv -
File with a Chapters element that ends with a ChapterAtom whose ChapterDisplay
element contains a truncated ChapterString.
chapters_truncated_chapter_string_2.mkv -
Nearly identical to chapters_truncated_chapter_string.mkv, but with a void
element and a partial cluster. Causes mkvparser to fail in a slightly
different manner.
fixed_lacing_bad_lace_size.mkv -
File containing a BlockGroup with fixed lacing, but reports a total laced size
that is not evenly divisible by the number of laced frames.
@@ -0,0 +1 @@
EߣŸB00B00B00B00B‚„webmB00B00S€g0000000»‹00000000000»Œ000000000000ì¼000000000000000000000000000000000000000000000000000000000000€“0000000000000000000W0“0000000000000000000T®k@ž®@›×0s0†…00000à@‡°‚00º0U°ýU¸0U¹0Uº0U»0U¼0U½0UÐÆUÙ„0000UÚ„0000UÑ„0000UÒ000000000000000000000000000000000000000000000000000000000000000000000000000
Binary file not shown.
@@ -0,0 +1,75 @@
// 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/video_frame.h"
#include "gtest/gtest.h"
namespace {
const libwebm::VideoFrame::Codec kCodec = libwebm::VideoFrame::kVP8;
const std::int64_t kPts = 12345;
const std::size_t kSize = 1;
const std::size_t kEmptySize = 0;
TEST(VideoFrameTests, DefaultsTest) {
libwebm::VideoFrame frame;
EXPECT_EQ(kEmptySize, frame.buffer().capacity);
EXPECT_EQ(kEmptySize, frame.buffer().length);
EXPECT_EQ(nullptr, frame.buffer().data.get());
EXPECT_FALSE(frame.keyframe());
EXPECT_EQ(0, frame.nanosecond_pts());
EXPECT_EQ(libwebm::VideoFrame::kVP9, frame.codec());
}
TEST(VideoFrameTests, SizeTest) {
libwebm::VideoFrame frame;
EXPECT_TRUE(frame.Init(kSize));
// Buffer inits empty, length should be 0, aka |kEmpty|.
EXPECT_GT(kSize, frame.buffer().length);
EXPECT_EQ(kEmptySize, frame.buffer().length);
// Capacity should be equal to |kSize|.
EXPECT_EQ(kSize, frame.buffer().capacity);
EXPECT_FALSE(frame.SetBufferLength(kSize + 1));
// Write a byte into the buffer via the raw data pointer, update length, and
// verify expected behavior.
uint8_t* write_ptr = reinterpret_cast<uint8_t*>(frame.buffer().data.get());
*write_ptr = 0xFF;
EXPECT_TRUE(frame.SetBufferLength(1));
EXPECT_EQ(frame.buffer().length, frame.buffer().capacity);
}
TEST(VideoFrameTests, OverloadsTest) {
const bool kKeyframe = true;
// Test VideoFrame::VideoFrame(bool keyframe, int64_t nano_pts, Codec c).
libwebm::VideoFrame keyframe(kKeyframe, kPts, kCodec);
EXPECT_EQ(kKeyframe, keyframe.keyframe());
EXPECT_EQ(kPts, keyframe.nanosecond_pts());
EXPECT_EQ(kCodec, keyframe.codec());
EXPECT_EQ(kEmptySize, keyframe.buffer().capacity);
EXPECT_EQ(kEmptySize, keyframe.buffer().length);
EXPECT_EQ(nullptr, keyframe.buffer().data.get());
// Test VideoFrame::Init(std::size_t length).
EXPECT_TRUE(keyframe.Init(kSize));
EXPECT_EQ(kKeyframe, keyframe.keyframe());
EXPECT_EQ(kPts, keyframe.nanosecond_pts());
EXPECT_EQ(kCodec, keyframe.codec());
EXPECT_NE(nullptr, keyframe.buffer().data.get());
// Test VideoFrame::Init(size_t length, int64_t nano_pts, Codec c).
EXPECT_TRUE(keyframe.Init(kSize, kPts + 1, libwebm::VideoFrame::kVP9));
EXPECT_EQ(kSize, keyframe.buffer().capacity);
EXPECT_GT(kSize, keyframe.buffer().length);
EXPECT_NE(kPts, keyframe.nanosecond_pts());
EXPECT_NE(kCodec, keyframe.codec());
}
} // namespace