149 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			149 lines
		
	
	
		
			4.5 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 "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());
 | 
						|
 | 
						|
    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);
 | 
						|
    // TODO(tomfinegan): Cues ID is really 0x1C53BB6B, aka kMkvCues, but
 | 
						|
    // mkvparser reads IDs as EBML unsigned ints in some cases, yielding magic
 | 
						|
    // numbers like the following. Investigate fixing this behavior.
 | 
						|
    if (entry->id == 0xC53BB6B) {  // Cues ID as stored in Entry class.
 | 
						|
      offset = entry->pos;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (offset == -1) {
 | 
						|
    // 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;
 | 
						|
}
 | 
						|
 | 
						|
}  // namespace test
 |