int main()

in vireo/tools/viddiff/main.cpp [66:229]


int main(int argc, const char* argv[]) {
  // Parse arguments
  if (argc < 3) {
    print_usage(common::Path::Filename(argv[0]));
    return 1;
  }
  Config config;
  if (parse_arguments(argc, argv, config)) {
    return 1;
  }

  __try {
    // Demux video files
    demux::Movie movie1(common::Path::MakeAbsolute(config.ref));
    demux::Movie movie2(common::Path::MakeAbsolute(config.test));

    // Compare file types
    if (movie1.file_type() != movie2.file_type()) {
      print_diff("File types do not match", config.ref, config.test,
                 kFileTypeToString[movie1.file_type()],
                 kFileTypeToString[movie2.file_type()]);
      return 1;
    }

    // Compare video settings
    const auto video_settings1 = movie1.video_track.settings();
    const auto video_settings2 = movie2.video_track.settings();
    if (video_settings1.codec != video_settings2.codec) {
      print_diff("Video codecs do not match", config.ref, config.test,
                 settings::kVideoCodecToString[video_settings1.codec],
                 settings::kVideoCodecToString[video_settings2.codec]);
      return 1;
    }
    if (video_settings1.width != video_settings2.width ||
        video_settings1.height != video_settings2.height) {
      stringstream res1; res1 << video_settings1.width << "x" << video_settings1.height;
      stringstream res2; res2 << video_settings2.width << "x" << video_settings2.height;
      print_diff("Video resolutions do not match", config.ref, config.test, res1.str(), res2.str());
      return 1;
    }
    if (video_settings1.timescale != video_settings2.timescale) {
      print_diff("Timescales of videos do not match", config.ref, config.test,
                 video_settings1.timescale,
                 video_settings2.timescale);
      return 1;
    }
    if (video_settings1.orientation != video_settings2.orientation) {
      print_diff("Orientations of videos do not match", config.ref, config.test,
                 settings::kOrientationToString[video_settings1.orientation],
                 settings::kOrientationToString[video_settings2.orientation]);
      return 1;
    }
    if (video_settings1.codec == settings::Video::Codec::H264) {
      if (video_settings1.sps_pps.nalu_length_size != video_settings2.sps_pps.nalu_length_size ||
          video_settings1.sps_pps.sps != video_settings2.sps_pps.sps ||
          video_settings1.sps_pps.pps != video_settings2.sps_pps.pps) {
        cout << "SPS and PPS videos do not match" << endl;
        return 1;
      }
    }

    // Compare audio settings
    const auto audio_settings1 = movie1.audio_track.settings();
    const auto audio_settings2 = movie2.audio_track.settings();

    if (audio_settings1.channels != audio_settings2.channels) {
      print_diff("Audio channels do not match", config.ref, config.test,
                 (uint16_t)audio_settings1.channels,
                 (uint16_t)audio_settings2.channels);
      return 1;
    }
    if (audio_settings1.timescale != audio_settings2.timescale) {
      print_diff("Audio timescales do not match", config.ref, config.test,
                 audio_settings1.timescale,
                 audio_settings2.timescale);
      return 1;
    }
    if (audio_settings1.sample_rate != audio_settings2.sample_rate) {
      print_diff("Audio frequencies do not match", config.ref, config.test,
                 audio_settings1.sample_rate,
                 audio_settings2.sample_rate);
      return 1;
    }
    if (audio_settings1.codec != audio_settings2.codec) {
      print_diff("Audio codecs do not match", config.ref, config.test,
                 settings::kAudioCodecToString[audio_settings1.codec],
                 settings::kAudioCodecToString[audio_settings2.codec]);
      return 1;
    }

    // Compare video sample count
    if (movie1.video_track.count() != movie2.video_track.count()) {
      print_diff("Number of video samples do not match", config.ref, config.test,
                 movie1.video_track.count(),
                 movie2.video_track.count());
      return 1;
    }

    // Compare audio sample count
    if (movie1.audio_track.count() != movie2.audio_track.count()) {
      print_diff("Number of audio samples do not match", config.ref, config.test,
                 movie1.audio_track.count(),
                 movie2.audio_track.count());
      return 1;
    }

    // Create a list of ordered samples
    vector<decode::Sample> samples1;
    vector<decode::Sample> samples2;
    for (const auto& sample: movie1.video_track) {
      samples1.push_back(sample);
    }
    for (const auto& sample: movie1.audio_track) {
      samples1.push_back(sample);
    }
    for (const auto& sample: movie2.video_track) {
      samples2.push_back(sample);
    }
    for (const auto& sample: movie2.audio_track) {
      samples2.push_back(sample);
    }
    auto sample_compare = [](const decode::Sample& a, const decode::Sample& b) {
      return a.byte_range.pos < b.byte_range.pos;
    };
    sort(samples1.begin(), samples1.end(), sample_compare);
    sort(samples2.begin(), samples2.end(), sample_compare);

    // Compare sample order and samples
    for (uint32_t i = 0; i < samples1.size(); ++i) {
      const auto& sample1 = samples1[i];
      const auto& sample2 = samples2[i];
      if (sample1 != sample2) {
        cout << "Sample " << i << " in the files do not match" << endl;
        return 1;
      }
    }

    // Compare sample payloads - do separately to fail fast for metadata mismatches
    for (uint32_t i = 0; i < samples1.size(); ++i) {
      const auto& nal1 = samples1[i].nal();
      const auto& nal2 = samples2[i].nal();
      if (nal1 != nal2) {
        cout << "Payloads of sample " << i << " do not match" << endl;
        return 1;
      }
    }
    cout << "Files are functionally identical" << endl;
  } __catch (std::exception& e) {
    cout << "Unsupported video files, comparing binaries" << endl;
    __try {
      auto ref = common::Data32(common::Path::MakeAbsolute(config.ref));
      auto test = common::Data32(common::Path::MakeAbsolute(config.test));
      if (ref != test) {
        cout << "Binary files differ" << endl;
        return 1;
      }
    } __catch(std::exception& e) {
      cerr << "Error comparing files: " << e.what() << endl;
      return 1;
    }
    cout << "Files are identical" << endl;
  }
  return 0;
}