xref: /aosp_15_r20/external/libwebm/testing/test_util.cc (revision 103e46e4cd4b6efcf6001f23fa8665fb110abf8d)
1*103e46e4SHarish Mahendrakar // Copyright (c) 2016 The WebM project authors. All Rights Reserved.
2*103e46e4SHarish Mahendrakar //
3*103e46e4SHarish Mahendrakar // Use of this source code is governed by a BSD-style license
4*103e46e4SHarish Mahendrakar // that can be found in the LICENSE file in the root of the source
5*103e46e4SHarish Mahendrakar // tree. An additional intellectual property rights grant can be found
6*103e46e4SHarish Mahendrakar // in the file PATENTS.  All contributing project authors may
7*103e46e4SHarish Mahendrakar // be found in the AUTHORS file in the root of the source tree.
8*103e46e4SHarish Mahendrakar #include "testing/test_util.h"
9*103e46e4SHarish Mahendrakar 
10*103e46e4SHarish Mahendrakar #include <cstdint>
11*103e46e4SHarish Mahendrakar #include <cstdio>
12*103e46e4SHarish Mahendrakar #include <cstdlib>
13*103e46e4SHarish Mahendrakar #include <cstring>
14*103e46e4SHarish Mahendrakar #include <ios>
15*103e46e4SHarish Mahendrakar #include <string>
16*103e46e4SHarish Mahendrakar 
17*103e46e4SHarish Mahendrakar #include "common/libwebm_util.h"
18*103e46e4SHarish Mahendrakar #include "common/webmids.h"
19*103e46e4SHarish Mahendrakar 
20*103e46e4SHarish Mahendrakar #include "mkvparser/mkvparser.h"
21*103e46e4SHarish Mahendrakar #include "mkvparser/mkvreader.h"
22*103e46e4SHarish Mahendrakar 
23*103e46e4SHarish Mahendrakar namespace test {
24*103e46e4SHarish Mahendrakar 
GetTestDataDir()25*103e46e4SHarish Mahendrakar std::string GetTestDataDir() {
26*103e46e4SHarish Mahendrakar   const char* test_data_path = std::getenv("LIBWEBM_TEST_DATA_PATH");
27*103e46e4SHarish Mahendrakar   return test_data_path ? std::string(test_data_path) : std::string();
28*103e46e4SHarish Mahendrakar }
29*103e46e4SHarish Mahendrakar 
GetTestFilePath(const std::string & name)30*103e46e4SHarish Mahendrakar std::string GetTestFilePath(const std::string& name) {
31*103e46e4SHarish Mahendrakar   const std::string libwebm_testdata_dir = GetTestDataDir();
32*103e46e4SHarish Mahendrakar   return libwebm_testdata_dir + "/" + name;
33*103e46e4SHarish Mahendrakar }
34*103e46e4SHarish Mahendrakar 
CompareFiles(const std::string & file1,const std::string & file2)35*103e46e4SHarish Mahendrakar bool CompareFiles(const std::string& file1, const std::string& file2) {
36*103e46e4SHarish Mahendrakar   const std::size_t kBlockSize = 4096;
37*103e46e4SHarish Mahendrakar   std::uint8_t buf1[kBlockSize] = {0};
38*103e46e4SHarish Mahendrakar   std::uint8_t buf2[kBlockSize] = {0};
39*103e46e4SHarish Mahendrakar 
40*103e46e4SHarish Mahendrakar   libwebm::FilePtr f1 =
41*103e46e4SHarish Mahendrakar       libwebm::FilePtr(std::fopen(file1.c_str(), "rb"), libwebm::FILEDeleter());
42*103e46e4SHarish Mahendrakar   libwebm::FilePtr f2 =
43*103e46e4SHarish Mahendrakar       libwebm::FilePtr(std::fopen(file2.c_str(), "rb"), libwebm::FILEDeleter());
44*103e46e4SHarish Mahendrakar 
45*103e46e4SHarish Mahendrakar   if (!f1.get() || !f2.get()) {
46*103e46e4SHarish Mahendrakar     // Files cannot match if one or both couldn't be opened.
47*103e46e4SHarish Mahendrakar     return false;
48*103e46e4SHarish Mahendrakar   }
49*103e46e4SHarish Mahendrakar 
50*103e46e4SHarish Mahendrakar   do {
51*103e46e4SHarish Mahendrakar     const std::size_t r1 = std::fread(buf1, 1, kBlockSize, f1.get());
52*103e46e4SHarish Mahendrakar     const std::size_t r2 = std::fread(buf2, 1, kBlockSize, f2.get());
53*103e46e4SHarish Mahendrakar 
54*103e46e4SHarish Mahendrakar     // TODO(fgalligan): Add output of which byte differs.
55*103e46e4SHarish Mahendrakar     if (r1 != r2 || std::memcmp(buf1, buf2, r1)) {
56*103e46e4SHarish Mahendrakar       return 0;  // Files are not equal
57*103e46e4SHarish Mahendrakar     }
58*103e46e4SHarish Mahendrakar   } while (!std::feof(f1.get()) && !std::feof(f2.get()));
59*103e46e4SHarish Mahendrakar 
60*103e46e4SHarish Mahendrakar   return std::feof(f1.get()) && std::feof(f2.get());
61*103e46e4SHarish Mahendrakar }
62*103e46e4SHarish Mahendrakar 
HasCuePoints(const mkvparser::Segment * segment,std::int64_t * cues_offset)63*103e46e4SHarish Mahendrakar bool HasCuePoints(const mkvparser::Segment* segment,
64*103e46e4SHarish Mahendrakar                   std::int64_t* cues_offset) {
65*103e46e4SHarish Mahendrakar   if (!segment || !cues_offset) {
66*103e46e4SHarish Mahendrakar     return false;
67*103e46e4SHarish Mahendrakar   }
68*103e46e4SHarish Mahendrakar   using mkvparser::SeekHead;
69*103e46e4SHarish Mahendrakar   const SeekHead* const seek_head = segment->GetSeekHead();
70*103e46e4SHarish Mahendrakar   if (!seek_head) {
71*103e46e4SHarish Mahendrakar     return false;
72*103e46e4SHarish Mahendrakar   }
73*103e46e4SHarish Mahendrakar 
74*103e46e4SHarish Mahendrakar   std::int64_t offset = 0;
75*103e46e4SHarish Mahendrakar   for (int i = 0; i < seek_head->GetCount(); ++i) {
76*103e46e4SHarish Mahendrakar     const SeekHead::Entry* const entry = seek_head->GetEntry(i);
77*103e46e4SHarish Mahendrakar     if (entry->id == libwebm::kMkvCues) {
78*103e46e4SHarish Mahendrakar       offset = entry->pos;
79*103e46e4SHarish Mahendrakar     }
80*103e46e4SHarish Mahendrakar   }
81*103e46e4SHarish Mahendrakar 
82*103e46e4SHarish Mahendrakar   if (offset <= 0) {
83*103e46e4SHarish Mahendrakar     // No Cues found.
84*103e46e4SHarish Mahendrakar     return false;
85*103e46e4SHarish Mahendrakar   }
86*103e46e4SHarish Mahendrakar 
87*103e46e4SHarish Mahendrakar   *cues_offset = offset;
88*103e46e4SHarish Mahendrakar   return true;
89*103e46e4SHarish Mahendrakar }
90*103e46e4SHarish Mahendrakar 
ValidateCues(mkvparser::Segment * segment,mkvparser::IMkvReader * reader)91*103e46e4SHarish Mahendrakar bool ValidateCues(mkvparser::Segment* segment, mkvparser::IMkvReader* reader) {
92*103e46e4SHarish Mahendrakar   if (!segment) {
93*103e46e4SHarish Mahendrakar     return false;
94*103e46e4SHarish Mahendrakar   }
95*103e46e4SHarish Mahendrakar 
96*103e46e4SHarish Mahendrakar   std::int64_t cues_offset = 0;
97*103e46e4SHarish Mahendrakar   if (!HasCuePoints(segment, &cues_offset)) {
98*103e46e4SHarish Mahendrakar     // No cues to validate, everything is OK.
99*103e46e4SHarish Mahendrakar     return true;
100*103e46e4SHarish Mahendrakar   }
101*103e46e4SHarish Mahendrakar 
102*103e46e4SHarish Mahendrakar   // Parse Cues.
103*103e46e4SHarish Mahendrakar   long long cues_pos = 0;  // NOLINT
104*103e46e4SHarish Mahendrakar   long cues_len = 0;  // NOLINT
105*103e46e4SHarish Mahendrakar   if (segment->ParseCues(cues_offset, cues_pos, cues_len)) {
106*103e46e4SHarish Mahendrakar     return false;
107*103e46e4SHarish Mahendrakar   }
108*103e46e4SHarish Mahendrakar 
109*103e46e4SHarish Mahendrakar   // Get a pointer to the video track if it exists. Otherwise, we assume
110*103e46e4SHarish Mahendrakar   // that Cues are based on the first track (which is true for all our test
111*103e46e4SHarish Mahendrakar   // files).
112*103e46e4SHarish Mahendrakar   const mkvparser::Tracks* const tracks = segment->GetTracks();
113*103e46e4SHarish Mahendrakar   const mkvparser::Track* cues_track = tracks->GetTrackByIndex(0);
114*103e46e4SHarish Mahendrakar   for (int i = 1; i < static_cast<int>(tracks->GetTracksCount()); ++i) {
115*103e46e4SHarish Mahendrakar     const mkvparser::Track* const track = tracks->GetTrackByIndex(i);
116*103e46e4SHarish Mahendrakar     if (track->GetType() == mkvparser::Track::kVideo) {
117*103e46e4SHarish Mahendrakar       cues_track = track;
118*103e46e4SHarish Mahendrakar       break;
119*103e46e4SHarish Mahendrakar     }
120*103e46e4SHarish Mahendrakar   }
121*103e46e4SHarish Mahendrakar 
122*103e46e4SHarish Mahendrakar   // Iterate through Cues and verify if they are pointing to the correct
123*103e46e4SHarish Mahendrakar   // Cluster position.
124*103e46e4SHarish Mahendrakar   const mkvparser::Cues* const cues = segment->GetCues();
125*103e46e4SHarish Mahendrakar   const mkvparser::CuePoint* cue_point = NULL;
126*103e46e4SHarish Mahendrakar   while (cues->LoadCuePoint()) {
127*103e46e4SHarish Mahendrakar     if (!cue_point) {
128*103e46e4SHarish Mahendrakar       cue_point = cues->GetFirst();
129*103e46e4SHarish Mahendrakar     } else {
130*103e46e4SHarish Mahendrakar       cue_point = cues->GetNext(cue_point);
131*103e46e4SHarish Mahendrakar     }
132*103e46e4SHarish Mahendrakar     const mkvparser::CuePoint::TrackPosition* const track_position =
133*103e46e4SHarish Mahendrakar         cue_point->Find(cues_track);
134*103e46e4SHarish Mahendrakar     const long long cluster_pos = track_position->m_pos +  // NOLINT
135*103e46e4SHarish Mahendrakar                                   segment->m_start;
136*103e46e4SHarish Mahendrakar 
137*103e46e4SHarish Mahendrakar     // If a cluster does not begin at |cluster_pos|, then the file is
138*103e46e4SHarish Mahendrakar     // incorrect.
139*103e46e4SHarish Mahendrakar     long length;  // NOLINT
140*103e46e4SHarish Mahendrakar     const std::int64_t id = mkvparser::ReadID(reader, cluster_pos, length);
141*103e46e4SHarish Mahendrakar     if (id != libwebm::kMkvCluster) {
142*103e46e4SHarish Mahendrakar       return false;
143*103e46e4SHarish Mahendrakar     }
144*103e46e4SHarish Mahendrakar   }
145*103e46e4SHarish Mahendrakar   return true;
146*103e46e4SHarish Mahendrakar }
147*103e46e4SHarish Mahendrakar 
~MkvParser()148*103e46e4SHarish Mahendrakar MkvParser::~MkvParser() {
149*103e46e4SHarish Mahendrakar   delete segment;
150*103e46e4SHarish Mahendrakar   delete reader;
151*103e46e4SHarish Mahendrakar }
152*103e46e4SHarish Mahendrakar 
ParseMkvFileReleaseParser(const std::string & webm_file,MkvParser * parser_out)153*103e46e4SHarish Mahendrakar bool ParseMkvFileReleaseParser(const std::string& webm_file,
154*103e46e4SHarish Mahendrakar                                MkvParser* parser_out) {
155*103e46e4SHarish Mahendrakar   parser_out->reader = new (std::nothrow) mkvparser::MkvReader;
156*103e46e4SHarish Mahendrakar   mkvparser::MkvReader& reader = *parser_out->reader;
157*103e46e4SHarish Mahendrakar   if (!parser_out->reader || reader.Open(webm_file.c_str()) < 0) {
158*103e46e4SHarish Mahendrakar     return false;
159*103e46e4SHarish Mahendrakar   }
160*103e46e4SHarish Mahendrakar 
161*103e46e4SHarish Mahendrakar   long long pos = 0;  // NOLINT
162*103e46e4SHarish Mahendrakar   mkvparser::EBMLHeader ebml_header;
163*103e46e4SHarish Mahendrakar   if (ebml_header.Parse(&reader, pos)) {
164*103e46e4SHarish Mahendrakar     return false;
165*103e46e4SHarish Mahendrakar   }
166*103e46e4SHarish Mahendrakar 
167*103e46e4SHarish Mahendrakar   using mkvparser::Segment;
168*103e46e4SHarish Mahendrakar   Segment* segment_ptr = nullptr;
169*103e46e4SHarish Mahendrakar   if (Segment::CreateInstance(&reader, pos, segment_ptr)) {
170*103e46e4SHarish Mahendrakar     return false;
171*103e46e4SHarish Mahendrakar   }
172*103e46e4SHarish Mahendrakar 
173*103e46e4SHarish Mahendrakar   std::unique_ptr<Segment> segment(segment_ptr);
174*103e46e4SHarish Mahendrakar   long result;
175*103e46e4SHarish Mahendrakar   if ((result = segment->Load()) < 0) {
176*103e46e4SHarish Mahendrakar     return false;
177*103e46e4SHarish Mahendrakar   }
178*103e46e4SHarish Mahendrakar 
179*103e46e4SHarish Mahendrakar   const mkvparser::Cluster* cluster = segment->GetFirst();
180*103e46e4SHarish Mahendrakar   if (!cluster || cluster->EOS()) {
181*103e46e4SHarish Mahendrakar     return false;
182*103e46e4SHarish Mahendrakar   }
183*103e46e4SHarish Mahendrakar 
184*103e46e4SHarish Mahendrakar   while (cluster && cluster->EOS() == false) {
185*103e46e4SHarish Mahendrakar     if (cluster->GetTimeCode() < 0) {
186*103e46e4SHarish Mahendrakar       return false;
187*103e46e4SHarish Mahendrakar     }
188*103e46e4SHarish Mahendrakar 
189*103e46e4SHarish Mahendrakar     const mkvparser::BlockEntry* block = nullptr;
190*103e46e4SHarish Mahendrakar     if (cluster->GetFirst(block) < 0) {
191*103e46e4SHarish Mahendrakar       return false;
192*103e46e4SHarish Mahendrakar     }
193*103e46e4SHarish Mahendrakar 
194*103e46e4SHarish Mahendrakar     while (block != NULL && block->EOS() == false) {
195*103e46e4SHarish Mahendrakar       if (cluster->GetNext(block, block) < 0) {
196*103e46e4SHarish Mahendrakar         return false;
197*103e46e4SHarish Mahendrakar       }
198*103e46e4SHarish Mahendrakar     }
199*103e46e4SHarish Mahendrakar 
200*103e46e4SHarish Mahendrakar     cluster = segment->GetNext(cluster);
201*103e46e4SHarish Mahendrakar   }
202*103e46e4SHarish Mahendrakar 
203*103e46e4SHarish Mahendrakar   parser_out->segment = segment.release();
204*103e46e4SHarish Mahendrakar   return true;
205*103e46e4SHarish Mahendrakar }
206*103e46e4SHarish Mahendrakar 
ParseMkvFile(const std::string & webm_file)207*103e46e4SHarish Mahendrakar bool ParseMkvFile(const std::string& webm_file) {
208*103e46e4SHarish Mahendrakar   MkvParser parser;
209*103e46e4SHarish Mahendrakar   const bool result = ParseMkvFileReleaseParser(webm_file, &parser);
210*103e46e4SHarish Mahendrakar   delete parser.segment;
211*103e46e4SHarish Mahendrakar   delete parser.reader;
212*103e46e4SHarish Mahendrakar   return result;
213*103e46e4SHarish Mahendrakar }
214*103e46e4SHarish Mahendrakar 
215*103e46e4SHarish Mahendrakar }  // namespace test
216