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:
parent
24779fe7cc
commit
6e2d012b58
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user