webrtc/rtc_tools/frame_analyzer/reference_less_video_analysis_lib.cc
Sami Kalliomäki 0673bc9204 Revert CLs affecting video quality toolchain.
Speculatively fixes Chromium test for cut: crbug.com/877968

Reverts CLs:
https://webrtc-review.googlesource.com/c/src/+/94772
https://webrtc-review.googlesource.com/c/src/+/95648
https://webrtc-review.googlesource.com/c/src/+/94773
https://webrtc-review.googlesource.com/c/src/+/96000
https://webrtc-review.googlesource.com/c/src/+/95949

Revert "Add Y4mFileReader"

This reverts commit 404be7f302.

Revert "Remove SequencedTaskChecker from Y4mFileReader"

This reverts commit 1b5e5db842.

Revert "Add tool for aliging video files"

This reverts commit b2c0e8f60f.

Revert "Reland "Update video_quality_analysis to align videos instead of using barcodes""

This reverts commit 9bb55fc09b.

Revert "Fix a bug in barcode_decoder.py"

This reverts commit 5c2de6b3ce.

TBR=magjed@webrtc.org, phoglund@webrtc.org, phensman@webrtc.org

Bug: chromium:877968, webrtc:9642
Change-Id: I784d0598fd0370eec38d758b9fa0b38e4b3423be
Reviewed-on: https://webrtc-review.googlesource.com/96320
Reviewed-by: Sami Kalliomäki <sakal@webrtc.org>
Commit-Queue: Sami Kalliomäki <sakal@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#24458}
2018-08-27 16:50:54 +00:00

200 lines
6.9 KiB
C++

/*
* Copyright (c) 2016 The WebRTC 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <numeric>
#include <vector>
#include "rtc_tools/frame_analyzer/reference_less_video_analysis_lib.h"
#include "rtc_tools/frame_analyzer/video_quality_analysis.h"
#define STATS_LINE_LENGTH 28
#define PSNR_FREEZE_THRESHOLD 47
#define SSIM_FREEZE_THRESHOLD .999
#if defined(_WIN32) || defined(_WIN64)
#define strtok_r strtok_s
#endif
void get_height_width_fps(int* height,
int* width,
int* fps,
const std::string& video_file) {
// File header looks like :
// YUV4MPEG2 W1280 H720 F25:1 Ip A0:0 C420mpeg2 XYSCSS=420MPEG2.
char frame_header[STATS_LINE_LENGTH];
FILE* input_file = fopen(video_file.c_str(), "rb");
size_t bytes_read = fread(frame_header, 1, STATS_LINE_LENGTH - 1, input_file);
frame_header[bytes_read] = '\0';
std::string file_header_stats[5];
int no_of_stats = 0;
char* save_ptr;
char* token = strtok_r(frame_header, " ", &save_ptr);
while (token != NULL) {
file_header_stats[no_of_stats++] = token;
token = strtok_r(NULL, " ", &save_ptr);
}
*width = std::stoi(file_header_stats[1].erase(0, 1));
*height = std::stoi(file_header_stats[2].erase(0, 1));
*fps = std::stoi(file_header_stats[3].erase(0, 1));
printf("Height: %d Width: %d fps:%d \n", *height, *width, *fps);
fclose(input_file);
}
bool frozen_frame(std::vector<double> psnr_per_frame,
std::vector<double> ssim_per_frame,
size_t frame) {
if (psnr_per_frame[frame] >= PSNR_FREEZE_THRESHOLD ||
ssim_per_frame[frame] >= SSIM_FREEZE_THRESHOLD)
return true;
return false;
}
std::vector<int> find_frame_clusters(
const std::vector<double>& psnr_per_frame,
const std::vector<double>& ssim_per_frame) {
std::vector<int> identical_frame_clusters;
int num_frozen = 0;
size_t total_no_of_frames = psnr_per_frame.size();
for (size_t each_frame = 0; each_frame < total_no_of_frames; each_frame++) {
if (frozen_frame(psnr_per_frame, ssim_per_frame, each_frame)) {
num_frozen++;
} else if (num_frozen > 0) {
// Not frozen anymore.
identical_frame_clusters.push_back(num_frozen);
num_frozen = 0;
}
}
return identical_frame_clusters;
}
void print_freezing_metrics(const std::vector<double>& psnr_per_frame,
const std::vector<double>& ssim_per_frame) {
/*
* Prints the different metrics mainly:
* 1) Identical frame number, PSNR and SSIM values.
* 2) Length of continuous frozen frames.
* 3) Max length of continuous freezed frames.
* 4) No of unique frames found.
* 5) Total different identical frames found.
*
* Sample output:
* Printing metrics for file: /src/rtc_tools/test_3.y4m
=============================
Total number of frames received: 74
Total identical frames: 5
Number of unique frames: 69
Printing Identical Frames:
Frame Number: 29 PSNR: 48.000000 SSIM: 0.999618
Frame Number: 30 PSNR: 48.000000 SSIM: 0.999898
Frame Number: 60 PSNR: 48.000000 SSIM: 0.999564
Frame Number: 64 PSNR: 48.000000 SSIM: 0.999651
Frame Number: 69 PSNR: 48.000000 SSIM: 0.999684
Print identical frame which appears in clusters :
2 1 1 1
*
*/
size_t total_no_of_frames = psnr_per_frame.size();
std::vector<int> identical_frame_clusters =
find_frame_clusters(psnr_per_frame, ssim_per_frame);
int total_identical_frames = std::accumulate(
identical_frame_clusters.begin(), identical_frame_clusters.end(), 0);
size_t unique_frames = total_no_of_frames - total_identical_frames;
printf("Total number of frames received: %zu\n", total_no_of_frames);
printf("Total identical frames: %d\n", total_identical_frames);
printf("Number of unique frames: %zu\n", unique_frames);
printf("Printing Identical Frames: \n");
for (size_t frame = 0; frame < total_no_of_frames; frame++) {
if (frozen_frame(psnr_per_frame, ssim_per_frame, frame)) {
printf(" Frame Number: %zu PSNR: %f SSIM: %f \n", frame,
psnr_per_frame[frame], ssim_per_frame[frame]);
}
}
printf("Print identical frame which appears in clusters : \n");
for (int cluster = 0;
cluster < static_cast<int>(identical_frame_clusters.size()); cluster++)
printf("%d ", identical_frame_clusters[cluster]);
printf("\n");
}
void compute_metrics(const std::string& video_file_name,
std::vector<double>* psnr_per_frame,
std::vector<double>* ssim_per_frame) {
int height = 0, width = 0, fps = 0;
get_height_width_fps(&height, &width, &fps, video_file_name);
int no_of_frames = 0;
int size = webrtc::test::GetI420FrameSize(width, height);
// Allocate buffers for test and reference frames.
uint8_t* current_frame = new uint8_t[size];
uint8_t* next_frame = new uint8_t[size];
while (true) {
if (!(webrtc::test::ExtractFrameFromY4mFile(video_file_name.c_str(), width,
height, no_of_frames,
current_frame))) {
break;
}
if (!(webrtc::test::ExtractFrameFromY4mFile(video_file_name.c_str(), width,
height, no_of_frames + 1,
next_frame))) {
break;
}
double result_psnr = webrtc::test::CalculateMetrics(
webrtc::test::kPSNR, current_frame, next_frame, width, height);
double result_ssim = webrtc::test::CalculateMetrics(
webrtc::test::kSSIM, current_frame, next_frame, width, height);
psnr_per_frame->push_back(result_psnr);
ssim_per_frame->push_back(result_ssim);
no_of_frames++;
}
// Cleanup.
delete[] current_frame;
delete[] next_frame;
}
bool check_file_extension(const std::string& video_file_name) {
if (video_file_name.substr(video_file_name.length() - 3, 3) != "y4m") {
printf("Only y4m video file format is supported. Given: %s\n",
video_file_name.c_str());
return false;
}
return true;
}
int run_analysis(const std::string& video_file) {
std::vector<double> psnr_per_frame;
std::vector<double> ssim_per_frame;
if (check_file_extension(video_file)) {
compute_metrics(video_file, &psnr_per_frame, &ssim_per_frame);
} else {
return -1;
}
printf("=============================\n");
printf("Printing metrics for file: %s\n", video_file.c_str());
printf("=============================\n");
print_freezing_metrics(psnr_per_frame, ssim_per_frame);
return 0;
}