Add support for YUV4MPEG file reading to tools files.

This CL adds support for reading .y4m files to the infra in
video_quality_analysis.cc, adding new functions 
ExtractFrameFromYuvFile() and ExtractFrameFromY4mFile(),
instad of the previous ExtractFrameFromI420(). The decision
as to which one to use is taken from the file extension,
if it is .y4m then is considered a YUV4MPEG file, otherwise
is taken as a raw .yuv file.

It also removes the pseudo duplicated function 
GetNextI420Frame(), that is used from psnr_ssim_analyzer.c,
and adds support for y4m files there.

Tested/validated via local compile-run.

YUV4MPEG is a trivial container with a file header
and a per-frame header, see [1]

[1]
http://wiki.multimedia.cx/index.php?title=YUV4MPEG2

BUG=https://code.google.com/p/chromium/issues/detail?id=343504



git-svn-id: http://webrtc.googlecode.com/svn/trunk@5702 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
mcasas@webrtc.org 2014-03-14 12:45:45 +00:00
parent 24779fe7cc
commit 6e2d012b58
3 changed files with 100 additions and 37 deletions

View File

@ -17,6 +17,9 @@
#include <string>
#define STATS_LINE_LENGTH 32
#define Y4M_FILE_HEADER_MAX_SIZE 200
#define Y4M_FRAME_DELIMITER "FRAME"
#define Y4M_FRAME_HEADER_SIZE 6
namespace webrtc {
namespace test {
@ -84,25 +87,8 @@ bool GetNextStatsLine(FILE* stats_file, char* line) {
return true;
}
bool GetNextI420Frame(FILE* input_file, int width, int height,
uint8* result_frame) {
int frame_size = GetI420FrameSize(width, height);
bool errors = false;
size_t bytes_read = fread(result_frame, 1, frame_size, input_file);
if (bytes_read != static_cast<size_t>(frame_size)) {
// If end-of-file is reached, don't print an error.
if (feof(input_file)) {
return false;
}
fprintf(stdout, "Error while reading frame from file\n");
errors = true;
}
return !errors;
}
bool ExtractFrameFromI420(const char* i420_file_name, int width, int height,
int frame_number, uint8* result_frame) {
bool ExtractFrameFromYuvFile(const char* i420_file_name, int width, int height,
int frame_number, uint8* result_frame) {
int frame_size = GetI420FrameSize(width, height);
int offset = frame_number * frame_size; // Calculate offset for the frame.
bool errors = false;
@ -128,6 +114,58 @@ bool ExtractFrameFromI420(const char* i420_file_name, int width, int height,
return !errors;
}
bool ExtractFrameFromY4mFile(const char* y4m_file_name, int width, int height,
int frame_number, uint8* result_frame) {
int frame_size = GetI420FrameSize(width, height);
int frame_offset = frame_number * frame_size
bool errors = false;
FILE* input_file = fopen(y4m_file_name, "rb");
if (input_file == NULL) {
fprintf(stderr, "Couldn't open input file for reading: %s\n",
y4m_file_name);
return false;
}
// YUV4MPEG2, a.k.a. Y4M File format has a file header and a frame header. The
// file header has the aspect: "YUV4MPEG2 C420 W640 H360 Ip F30:1 A1:1".
// Skip the header if this is the first frame of the file.
if (frame_number == 0) {
char frame_header[Y4M_FILE_HEADER_MAX_SIZE];
size_t bytes_read =
fread(frame_header, 1, Y4M_FILE_HEADER_MAX_SIZE, input_file);
if (bytes_read != static_cast<size_t>(frame_size) && ferror(input_file)) {
fprintf(stdout, "Error while reading first frame from file %s\n",
y4m_file_name);
fclose(input_file);
return false;
}
std::string header_contents(frame_header);
std::size_t found = header_contents.find(Y4M_FRAME_DELIMITER);
if (found == std::string::npos) {
fprintf(stdout, "Corrupted Y4M header, could not find \"FRAME\" in %s\n",
header_contents.c_str());
fclose(input_file);
return false;
}
frame_offset = static_cast<int>(found);
}
// Change stream pointer to new offset, skipping the frame header as well.
fseek(input_file, frame_offset + Y4M_FRAME_HEADER_SIZE, SEEK_SET);
size_t bytes_read = fread(result_frame, 1, frame_size, input_file);
if (bytes_read != static_cast<size_t>(frame_size) &&
ferror(input_file)) {
fprintf(stdout, "Error while reading frame no %d from file %s\n",
frame_number, y4m_file_name);
errors = true;
}
fclose(input_file);
return !errors;
}
double CalculateMetrics(VideoAnalysisMetricsType video_metrics_type,
const uint8* ref_frame, const uint8* test_frame,
int width, int height) {
@ -176,6 +214,12 @@ double CalculateMetrics(VideoAnalysisMetricsType video_metrics_type,
void RunAnalysis(const char* reference_file_name, const char* test_file_name,
const char* stats_file_name, int width, int height,
ResultsContainer* results) {
// Check if the reference_file_name ends with "y4m".
bool y4m_mode = false;
if (std::string(reference_file_name).find("y4m") != std::string::npos){
y4m_mode = true;
}
int size = GetI420FrameSize(width, height);
FILE* stats_file = fopen(stats_file_name, "r");
@ -202,10 +246,15 @@ void RunAnalysis(const char* reference_file_name, const char* test_file_name,
assert(extracted_test_frame != -1);
assert(decoded_frame_number != -1);
ExtractFrameFromI420(test_file_name, width, height, extracted_test_frame,
test_frame);
ExtractFrameFromI420(reference_file_name, width, height,
decoded_frame_number, reference_frame);
ExtractFrameFromYuvFile(test_file_name, width, height, extracted_test_frame,
test_frame);
if (y4m_mode) {
ExtractFrameFromY4mFile(reference_file_name, width, height,
decoded_frame_number, reference_frame);
} else {
ExtractFrameFromYuvFile(reference_file_name, width, height,
decoded_frame_number, reference_frame);
}
// Calculate the PSNR and SSIM.
double result_psnr = CalculateMetrics(kPSNR, reference_frame, test_frame,

View File

@ -97,13 +97,14 @@ bool IsThereBarcodeError(std::string line);
// frame_0023 0284, we will get 284.
int ExtractDecodedFrameNumber(std::string line);
// Gets the next frame from an open I420 file.
bool GetNextI420Frame(FILE* input_file, int width, int height,
uint8* result_frame);
// Extracts an I420 frame at position frame_number from the raw YUV file.
bool ExtractFrameFromYuvFile(const char* i420_file_name, int width, int height,
int frame_number, uint8* result_frame);
// Extracts an I420 frame at position frame_number from the file.
bool ExtractFrameFromI420(const char* i420_file_name, int width, int height,
int frame_number, uint8* result_frame);
// Extracts an I420 frame at position frame_number from the Y4M file. The first
// frame has corresponded |frame_number| 0.
bool ExtractFrameFromY4mFile(const char* i420_file_name, int width, int height,
int frame_number, uint8* result_frame);
} // namespace test

View File

@ -8,6 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
@ -18,10 +19,16 @@
#include "webrtc/tools/frame_analyzer/video_quality_analysis.h"
#include "webrtc/tools/simple_command_line_parser.h"
#define MAX_NUM_FRAMES_PER_FILE INT_MAX
void CompareFiles(const char* reference_file_name, const char* test_file_name,
const char* results_file_name, int width, int height) {
FILE* ref_file = fopen(reference_file_name, "rb");
FILE* test_file = fopen(test_file_name, "rb");
// Check if the reference_file_name ends with "y4m".
bool y4m_mode = false;
if (std::string(reference_file_name).find("y4m") != std::string::npos){
y4m_mode = true;
}
FILE* results_file = fopen(results_file_name, "w");
int size = webrtc::test::GetI420FrameSize(width, height);
@ -30,10 +37,19 @@ void CompareFiles(const char* reference_file_name, const char* test_file_name,
uint8* test_frame = new uint8[size];
uint8* ref_frame = new uint8[size];
int frame_counter = 0;
bool read_result = true;
for(int frame_counter = 0; frame_counter < MAX_NUM_FRAMES_PER_FILE;
++frame_counter){
read_result &= (y4m_mode) ? webrtc::test::ExtractFrameFromY4mFile(
reference_file_name, width, height, frame_counter, ref_frame):
webrtc::test::ExtractFrameFromYuvFile(reference_file_name, width,
height, frame_counter, ref_frame);
read_result &= webrtc::test::ExtractFrameFromYuvFile(test_file_name, width,
height, frame_counter, test_frame);
if (!read_result)
break;
while (webrtc::test::GetNextI420Frame(ref_file, width, height, ref_frame) &&
webrtc::test::GetNextI420Frame(test_file, width, height, test_frame)) {
// Calculate the PSNR and SSIM.
double result_psnr = webrtc::test::CalculateMetrics(
webrtc::test::kPSNR, ref_frame, test_frame, width, height);
@ -41,13 +57,10 @@ void CompareFiles(const char* reference_file_name, const char* test_file_name,
webrtc::test::kSSIM, ref_frame, test_frame, width, height);
fprintf(results_file, "Frame: %d, PSNR: %f, SSIM: %f\n", frame_counter,
result_psnr, result_ssim);
++frame_counter;
}
delete[] test_frame;
delete[] ref_frame;
fclose(ref_file);
fclose(test_file);
fclose(results_file);
}