Chromium Code Reviews| Index: webrtc/tools/frame_analyzer/video_quality_analysis.cc |
| diff --git a/webrtc/tools/frame_analyzer/video_quality_analysis.cc b/webrtc/tools/frame_analyzer/video_quality_analysis.cc |
| index c1911ca81c7033e3e063d11338f5d5461d674f18..25de981e754c32ccb414333e73d8ae8abae72683 100644 |
| --- a/webrtc/tools/frame_analyzer/video_quality_analysis.cc |
| +++ b/webrtc/tools/frame_analyzer/video_quality_analysis.cc |
| @@ -13,7 +13,10 @@ |
| #include <assert.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| +#include <algorithm> |
| #include <string> |
| +#include <map> |
| +#include <utility> |
| #define STATS_LINE_LENGTH 32 |
| #define Y4M_FILE_HEADER_MAX_SIZE 200 |
| @@ -224,8 +227,12 @@ double CalculateMetrics(VideoAnalysisMetricsType video_metrics_type, |
| return result; |
| } |
| -void RunAnalysis(const char* reference_file_name, const char* test_file_name, |
| - const char* stats_file_name, int width, int height, |
| +void RunAnalysis(const char* reference_file_name, |
| + const char* test_file_name, |
| + const char* stats_file_reference_name, |
| + const char* stats_file_test_name, |
| + int width, |
| + int height, |
| ResultsContainer* results) { |
| // Check if the reference_file_name ends with "y4m". |
| bool y4m_mode = false; |
| @@ -234,7 +241,8 @@ void RunAnalysis(const char* reference_file_name, const char* test_file_name, |
| } |
| int size = GetI420FrameSize(width, height); |
| - FILE* stats_file = fopen(stats_file_name, "r"); |
| + FILE* stats_file_ref = fopen(stats_file_reference_name, "r"); |
| + FILE* stats_file_test = fopen(stats_file_test_name, "r"); |
| // String buffer for the lines in the stats file. |
| char line[STATS_LINE_LENGTH]; |
| @@ -244,10 +252,29 @@ void RunAnalysis(const char* reference_file_name, const char* test_file_name, |
| uint8_t* reference_frame = new uint8_t[size]; |
| int previous_frame_number = -1; |
| + // Maps barcode id to the frame id for the reference video. |
| + // In case two frames have same id, then we only save the first one. |
|
phoglund
2016/12/08 09:55:44
Add: "This can happen if there are freezes in the
mandermo
2016/12/08 18:08:31
It can also happen that the camera captures two fr
phoglund
2016/12/12 12:46:20
I don't understand when you say the frames have th
|
| + std::map<int, int> ref_barcode_to_frame; |
| // While there are entries in the stats file. |
| - while (GetNextStatsLine(stats_file, line)) { |
| + while (GetNextStatsLine(stats_file_ref, line)) { |
| + int extracted_ref_frame = ExtractFrameSequenceNumber(line); |
| + int decoded_frame_number = ExtractDecodedFrameNumber(line); |
| + |
| + // Insert will only add if it is not in map already, so we only keep first. |
|
phoglund
2016/12/08 09:55:44
nit: End this sentence at the ,
mandermo
2016/12/08 18:08:31
Done.
|
| + ref_barcode_to_frame.insert( |
| + std::make_pair(decoded_frame_number, extracted_ref_frame)); |
| + } |
| + |
| + while (GetNextStatsLine(stats_file_test, line)) { |
| int extracted_test_frame = ExtractFrameSequenceNumber(line); |
| int decoded_frame_number = ExtractDecodedFrameNumber(line); |
| + auto it = ref_barcode_to_frame.find(decoded_frame_number); |
| + if (it == ref_barcode_to_frame.end()) { |
| + // Not found in the reference video. |
| + // TODO(mandermo) print |
|
phoglund
2016/12/08 09:55:44
Yeah, print an error here and continue. You'll hav
phoglund
2016/12/12 12:46:20
Please address
|
| + continue; |
| + } |
| + int extracted_ref_frame = it->second; |
| // If there was problem decoding the barcode in this frame or the frame has |
| // been duplicated, continue. |
| @@ -263,17 +290,17 @@ void RunAnalysis(const char* reference_file_name, const char* test_file_name, |
| test_frame); |
| if (y4m_mode) { |
| ExtractFrameFromY4mFile(reference_file_name, width, height, |
| - decoded_frame_number, reference_frame); |
| + extracted_ref_frame, reference_frame); |
| } else { |
| ExtractFrameFromYuvFile(reference_file_name, width, height, |
| - decoded_frame_number, reference_frame); |
| + extracted_ref_frame, reference_frame); |
| } |
| // Calculate the PSNR and SSIM. |
| - double result_psnr = CalculateMetrics(kPSNR, reference_frame, test_frame, |
| - width, height); |
| - double result_ssim = CalculateMetrics(kSSIM, reference_frame, test_frame, |
| - width, height); |
| + double result_psnr = |
| + CalculateMetrics(kPSNR, reference_frame, test_frame, width, height); |
| + double result_ssim = |
| + CalculateMetrics(kSSIM, reference_frame, test_frame, width, height); |
| previous_frame_number = decoded_frame_number; |
| @@ -287,62 +314,111 @@ void RunAnalysis(const char* reference_file_name, const char* test_file_name, |
| } |
| // Cleanup. |
| - fclose(stats_file); |
| + fclose(stats_file_ref); |
| + fclose(stats_file_test); |
| delete[] test_frame; |
| delete[] reference_frame; |
| } |
| void PrintMaxRepeatedAndSkippedFrames(const std::string& label, |
| - const std::string& stats_file_name) { |
| - PrintMaxRepeatedAndSkippedFrames(stdout, label, stats_file_name); |
| + const std::string& stats_file_ref_name, |
| + const std::string& stats_file_test_name) { |
| + PrintMaxRepeatedAndSkippedFrames(stdout, label, stats_file_ref_name, |
| + stats_file_test_name); |
| } |
| -void PrintMaxRepeatedAndSkippedFrames(FILE* output, const std::string& label, |
| - const std::string& stats_file_name) { |
| - FILE* stats_file = fopen(stats_file_name.c_str(), "r"); |
| - if (stats_file == NULL) { |
| - fprintf(stderr, "Couldn't open stats file for reading: %s\n", |
| - stats_file_name.c_str()); |
| +namespace { |
| +std::vector<std::pair<int, int> > GetBarcodeNrToFrequency(FILE* file) { |
|
phoglund
2016/12/08 09:55:44
Number
phoglund
2016/12/08 09:55:44
I would love to have unit tests for these guys sin
mandermo
2016/12/08 18:08:31
I agree the code needs to be easier to test. Maybe
phoglund
2016/12/12 12:46:20
Errors are not returned up the chain today, and I
|
| + std::vector<std::pair<int, int> > frame_cnt; |
|
phoglund
2016/12/08 09:55:44
It feels a lot more natural to make this a map. Fr
phoglund
2016/12/08 09:55:44
frame_frequency?
mandermo
2016/12/08 18:08:30
frame_frequency.insert(std::pair<int, int>(decoded
mandermo
2016/12/08 18:08:31
Maybe it is more of a frame count than a frequency
phoglund
2016/12/12 12:46:20
Right, it's actually a vector of frame "clusters",
mandermo
2016/12/21 16:42:06
I have renamed the function now and added a commen
|
| + char line[STATS_LINE_LENGTH]; |
| + while (GetNextStatsLine(file, line)) { |
| + int decoded_frame_number = ExtractDecodedFrameNumber(line); |
| + if (frame_cnt.empty() || frame_cnt.back().first != decoded_frame_number) { |
| + frame_cnt.push_back(std::make_pair(decoded_frame_number, 1)); |
| + } else { |
| + ++frame_cnt.back().second; |
| + } |
| + } |
| + return frame_cnt; |
| +} |
| +} // namespace |
| + |
| +void PrintMaxRepeatedAndSkippedFrames(FILE* output, |
| + const std::string& label, |
| + const std::string& stats_file_ref_name, |
| + const std::string& stats_file_test_name) { |
| + FILE* stats_file_ref = fopen(stats_file_ref_name.c_str(), "r"); |
| + FILE* stats_file_test = fopen(stats_file_test_name.c_str(), "r"); |
| + if (stats_file_ref == NULL) { |
| + fprintf(stderr, "Couldn't open reference stats file for reading: %s\n", |
| + stats_file_ref_name.c_str()); |
| + return; |
| + } |
| + if (stats_file_test == NULL) { |
| + fprintf(stderr, "Couldn't open test stats file for reading: %s\n", |
| + stats_file_test_name.c_str()); |
| + fclose(stats_file_ref); |
| return; |
| } |
| - char line[STATS_LINE_LENGTH]; |
| - int repeated_frames = 1; |
| int max_repeated_frames = 1; |
| int max_skipped_frames = 1; |
| - int previous_frame_number = -1; |
| - while (GetNextStatsLine(stats_file, line)) { |
| - int decoded_frame_number = ExtractDecodedFrameNumber(line); |
| + std::vector<std::pair<int, int> > frame_cnt_ref = |
|
phoglund
2016/12/08 09:55:44
frame_frequency_ref
mandermo
2016/12/08 18:08:30
Maybe it is more of a frame count than a frequency
|
| + GetBarcodeNrToFrequency(stats_file_ref); |
| - if (decoded_frame_number == -1) { |
| - continue; |
| - } |
| + std::vector<std::pair<int, int> > frame_cnt_test = |
| + GetBarcodeNrToFrequency(stats_file_test); |
| - // Calculate how many frames a cluster of repeated frames contains. |
| - if (decoded_frame_number == previous_frame_number) { |
| - ++repeated_frames; |
| - if (repeated_frames > max_repeated_frames) { |
| - max_repeated_frames = repeated_frames; |
| - } |
| - } else { |
| - repeated_frames = 1; |
| + fclose(stats_file_ref); |
| + fclose(stats_file_test); |
| + |
| + auto it_ref = frame_cnt_ref.begin(); |
| + auto it_test = frame_cnt_test.begin(); |
| + auto end_ref = frame_cnt_ref.end(); |
| + auto end_test = frame_cnt_test.end(); |
| + |
| + if (it_test != end_test) { |
|
phoglund
2016/12/08 09:55:44
if (it_test == end_test) the test file is empty, w
mandermo
2016/12/08 18:08:31
Done. Should I print to output or to stderr like t
|
| + while (it_ref != end_ref && it_ref->first != it_test->first) { |
|
phoglund
2016/12/08 09:55:44
It's hard to read what happens here. Maybe extract
mandermo
2016/12/08 18:08:31
Commented the code better.
mandermo
2016/12/08 18:08:31
Done. Should I print to output or to stderr like t
|
| + ++it_ref; |
| + } |
| + if (it_ref == end_ref) { |
| + fprintf(stderr, |
| + "The barcode in the test videos first frame is not in the " |
| + "reference video."); |
| + return; |
| } |
| + max_repeated_frames = |
|
phoglund
2016/12/08 09:55:44
Also not sure if this algorithm is correct. To com
mandermo
2016/12/08 18:08:30
Lets make the unittests and see what output we get
phoglund
2016/12/12 12:46:20
Ok, I think counting the frame clusters like your
mandermo
2016/12/21 16:42:06
Done.
|
| + std::max(max_repeated_frames, it_test->second - it_ref->second + 1); |
| + } |
| - // Calculate how much frames have been skipped. |
| - if (decoded_frame_number != 0 && previous_frame_number != -1) { |
| - int skipped_frames = decoded_frame_number - previous_frame_number - 1; |
| - if (skipped_frames > max_skipped_frames) { |
| - max_skipped_frames = skipped_frames; |
| - } |
| + for (;;) { |
| + ++it_test; |
| + if (it_test == end_test) { |
| + break; |
| } |
| - previous_frame_number = decoded_frame_number; |
| + int skipped_frames = 0; |
| + ++it_ref; |
| + while (it_ref != end_ref && it_ref->first != it_test->first) { |
| + skipped_frames += it_ref->second; |
| + ++it_ref; |
| + } |
| + if (it_ref == end_ref) { |
| + fprintf(stderr, |
| + "The barcode in the test video is not in the reference video."); |
| + return; |
| + } |
| + if (skipped_frames > max_skipped_frames) { |
| + max_skipped_frames = skipped_frames; |
| + } |
| + max_repeated_frames = |
| + std::max(max_repeated_frames, it_test->second - it_ref->second + 1); |
| } |
| + |
| fprintf(output, "RESULT Max_repeated: %s= %d\n", label.c_str(), |
| max_repeated_frames); |
| fprintf(output, "RESULT Max_skipped: %s= %d\n", label.c_str(), |
| max_skipped_frames); |
| - fclose(stats_file); |
| } |
| void PrintAnalysisResults(const std::string& label, ResultsContainer* results) { |