Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(90)

Side by Side Diff: webrtc/tools/frame_analyzer/video_quality_analysis.cc

Issue 2553693002: Comparison of videos with reference frame not starting from zero (Closed)
Patch Set: Updated PrintMaxRepeatedAndSkippedFrames() for two stat files. Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license 4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source 5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found 6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may 7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree. 8 * be found in the AUTHORS file in the root of the source tree.
9 */ 9 */
10 10
11 #include "webrtc/tools/frame_analyzer/video_quality_analysis.h" 11 #include "webrtc/tools/frame_analyzer/video_quality_analysis.h"
12 12
13 #include <assert.h> 13 #include <assert.h>
14 #include <stdio.h> 14 #include <stdio.h>
15 #include <stdlib.h> 15 #include <stdlib.h>
16 #include <algorithm>
16 #include <string> 17 #include <string>
18 #include <map>
19 #include <utility>
17 20
18 #define STATS_LINE_LENGTH 32 21 #define STATS_LINE_LENGTH 32
19 #define Y4M_FILE_HEADER_MAX_SIZE 200 22 #define Y4M_FILE_HEADER_MAX_SIZE 200
20 #define Y4M_FRAME_DELIMITER "FRAME" 23 #define Y4M_FRAME_DELIMITER "FRAME"
21 #define Y4M_FRAME_HEADER_SIZE 6 24 #define Y4M_FRAME_HEADER_SIZE 6
22 25
23 namespace webrtc { 26 namespace webrtc {
24 namespace test { 27 namespace test {
25 28
26 using std::string; 29 using std::string;
(...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after
217 src_u_b, stride_uv, src_v_b, stride_uv, 220 src_u_b, stride_uv, src_v_b, stride_uv,
218 width, height); 221 width, height);
219 break; 222 break;
220 default: 223 default:
221 assert(false); 224 assert(false);
222 } 225 }
223 226
224 return result; 227 return result;
225 } 228 }
226 229
227 void RunAnalysis(const char* reference_file_name, const char* test_file_name, 230 void RunAnalysis(const char* reference_file_name,
228 const char* stats_file_name, int width, int height, 231 const char* test_file_name,
232 const char* stats_file_reference_name,
233 const char* stats_file_test_name,
234 int width,
235 int height,
229 ResultsContainer* results) { 236 ResultsContainer* results) {
230 // Check if the reference_file_name ends with "y4m". 237 // Check if the reference_file_name ends with "y4m".
231 bool y4m_mode = false; 238 bool y4m_mode = false;
232 if (std::string(reference_file_name).find("y4m") != std::string::npos) { 239 if (std::string(reference_file_name).find("y4m") != std::string::npos) {
233 y4m_mode = true; 240 y4m_mode = true;
234 } 241 }
235 242
236 int size = GetI420FrameSize(width, height); 243 int size = GetI420FrameSize(width, height);
237 FILE* stats_file = fopen(stats_file_name, "r"); 244 FILE* stats_file_ref = fopen(stats_file_reference_name, "r");
245 FILE* stats_file_test = fopen(stats_file_test_name, "r");
238 246
239 // String buffer for the lines in the stats file. 247 // String buffer for the lines in the stats file.
240 char line[STATS_LINE_LENGTH]; 248 char line[STATS_LINE_LENGTH];
241 249
242 // Allocate buffers for test and reference frames. 250 // Allocate buffers for test and reference frames.
243 uint8_t* test_frame = new uint8_t[size]; 251 uint8_t* test_frame = new uint8_t[size];
244 uint8_t* reference_frame = new uint8_t[size]; 252 uint8_t* reference_frame = new uint8_t[size];
245 int previous_frame_number = -1; 253 int previous_frame_number = -1;
246 254
255 // Maps barcode id to the frame id for the reference video.
256 // 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
257 std::map<int, int> ref_barcode_to_frame;
247 // While there are entries in the stats file. 258 // While there are entries in the stats file.
248 while (GetNextStatsLine(stats_file, line)) { 259 while (GetNextStatsLine(stats_file_ref, line)) {
260 int extracted_ref_frame = ExtractFrameSequenceNumber(line);
261 int decoded_frame_number = ExtractDecodedFrameNumber(line);
262
263 // 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.
264 ref_barcode_to_frame.insert(
265 std::make_pair(decoded_frame_number, extracted_ref_frame));
266 }
267
268 while (GetNextStatsLine(stats_file_test, line)) {
249 int extracted_test_frame = ExtractFrameSequenceNumber(line); 269 int extracted_test_frame = ExtractFrameSequenceNumber(line);
250 int decoded_frame_number = ExtractDecodedFrameNumber(line); 270 int decoded_frame_number = ExtractDecodedFrameNumber(line);
271 auto it = ref_barcode_to_frame.find(decoded_frame_number);
272 if (it == ref_barcode_to_frame.end()) {
273 // Not found in the reference video.
274 // 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
275 continue;
276 }
277 int extracted_ref_frame = it->second;
251 278
252 // If there was problem decoding the barcode in this frame or the frame has 279 // If there was problem decoding the barcode in this frame or the frame has
253 // been duplicated, continue. 280 // been duplicated, continue.
254 if (IsThereBarcodeError(line) || 281 if (IsThereBarcodeError(line) ||
255 decoded_frame_number == previous_frame_number) { 282 decoded_frame_number == previous_frame_number) {
256 continue; 283 continue;
257 } 284 }
258 285
259 assert(extracted_test_frame != -1); 286 assert(extracted_test_frame != -1);
260 assert(decoded_frame_number != -1); 287 assert(decoded_frame_number != -1);
261 288
262 ExtractFrameFromYuvFile(test_file_name, width, height, extracted_test_frame, 289 ExtractFrameFromYuvFile(test_file_name, width, height, extracted_test_frame,
263 test_frame); 290 test_frame);
264 if (y4m_mode) { 291 if (y4m_mode) {
265 ExtractFrameFromY4mFile(reference_file_name, width, height, 292 ExtractFrameFromY4mFile(reference_file_name, width, height,
266 decoded_frame_number, reference_frame); 293 extracted_ref_frame, reference_frame);
267 } else { 294 } else {
268 ExtractFrameFromYuvFile(reference_file_name, width, height, 295 ExtractFrameFromYuvFile(reference_file_name, width, height,
269 decoded_frame_number, reference_frame); 296 extracted_ref_frame, reference_frame);
270 } 297 }
271 298
272 // Calculate the PSNR and SSIM. 299 // Calculate the PSNR and SSIM.
273 double result_psnr = CalculateMetrics(kPSNR, reference_frame, test_frame, 300 double result_psnr =
274 width, height); 301 CalculateMetrics(kPSNR, reference_frame, test_frame, width, height);
275 double result_ssim = CalculateMetrics(kSSIM, reference_frame, test_frame, 302 double result_ssim =
276 width, height); 303 CalculateMetrics(kSSIM, reference_frame, test_frame, width, height);
277 304
278 previous_frame_number = decoded_frame_number; 305 previous_frame_number = decoded_frame_number;
279 306
280 // Fill in the result struct. 307 // Fill in the result struct.
281 AnalysisResult result; 308 AnalysisResult result;
282 result.frame_number = decoded_frame_number; 309 result.frame_number = decoded_frame_number;
283 result.psnr_value = result_psnr; 310 result.psnr_value = result_psnr;
284 result.ssim_value = result_ssim; 311 result.ssim_value = result_ssim;
285 312
286 results->frames.push_back(result); 313 results->frames.push_back(result);
287 } 314 }
288 315
289 // Cleanup. 316 // Cleanup.
290 fclose(stats_file); 317 fclose(stats_file_ref);
318 fclose(stats_file_test);
291 delete[] test_frame; 319 delete[] test_frame;
292 delete[] reference_frame; 320 delete[] reference_frame;
293 } 321 }
294 322
295 void PrintMaxRepeatedAndSkippedFrames(const std::string& label, 323 void PrintMaxRepeatedAndSkippedFrames(const std::string& label,
296 const std::string& stats_file_name) { 324 const std::string& stats_file_ref_name,
297 PrintMaxRepeatedAndSkippedFrames(stdout, label, stats_file_name); 325 const std::string& stats_file_test_name) {
326 PrintMaxRepeatedAndSkippedFrames(stdout, label, stats_file_ref_name,
327 stats_file_test_name);
298 } 328 }
299 329
300 void PrintMaxRepeatedAndSkippedFrames(FILE* output, const std::string& label, 330 namespace {
301 const std::string& stats_file_name) { 331 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
302 FILE* stats_file = fopen(stats_file_name.c_str(), "r"); 332 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
303 if (stats_file == NULL) { 333 char line[STATS_LINE_LENGTH];
304 fprintf(stderr, "Couldn't open stats file for reading: %s\n", 334 while (GetNextStatsLine(file, line)) {
305 stats_file_name.c_str()); 335 int decoded_frame_number = ExtractDecodedFrameNumber(line);
336 if (frame_cnt.empty() || frame_cnt.back().first != decoded_frame_number) {
337 frame_cnt.push_back(std::make_pair(decoded_frame_number, 1));
338 } else {
339 ++frame_cnt.back().second;
340 }
341 }
342 return frame_cnt;
343 }
344 } // namespace
345
346 void PrintMaxRepeatedAndSkippedFrames(FILE* output,
347 const std::string& label,
348 const std::string& stats_file_ref_name,
349 const std::string& stats_file_test_name) {
350 FILE* stats_file_ref = fopen(stats_file_ref_name.c_str(), "r");
351 FILE* stats_file_test = fopen(stats_file_test_name.c_str(), "r");
352 if (stats_file_ref == NULL) {
353 fprintf(stderr, "Couldn't open reference stats file for reading: %s\n",
354 stats_file_ref_name.c_str());
306 return; 355 return;
307 } 356 }
308 char line[STATS_LINE_LENGTH]; 357 if (stats_file_test == NULL) {
358 fprintf(stderr, "Couldn't open test stats file for reading: %s\n",
359 stats_file_test_name.c_str());
360 fclose(stats_file_ref);
361 return;
362 }
309 363
310 int repeated_frames = 1;
311 int max_repeated_frames = 1; 364 int max_repeated_frames = 1;
312 int max_skipped_frames = 1; 365 int max_skipped_frames = 1;
313 int previous_frame_number = -1;
314 366
315 while (GetNextStatsLine(stats_file, line)) { 367 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
316 int decoded_frame_number = ExtractDecodedFrameNumber(line); 368 GetBarcodeNrToFrequency(stats_file_ref);
317 369
318 if (decoded_frame_number == -1) { 370 std::vector<std::pair<int, int> > frame_cnt_test =
319 continue; 371 GetBarcodeNrToFrequency(stats_file_test);
372
373 fclose(stats_file_ref);
374 fclose(stats_file_test);
375
376 auto it_ref = frame_cnt_ref.begin();
377 auto it_test = frame_cnt_test.begin();
378 auto end_ref = frame_cnt_ref.end();
379 auto end_test = frame_cnt_test.end();
380
381 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
382 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
383 ++it_ref;
320 } 384 }
385 if (it_ref == end_ref) {
386 fprintf(stderr,
387 "The barcode in the test videos first frame is not in the "
388 "reference video.");
389 return;
390 }
391 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.
392 std::max(max_repeated_frames, it_test->second - it_ref->second + 1);
393 }
321 394
322 // Calculate how many frames a cluster of repeated frames contains. 395 for (;;) {
323 if (decoded_frame_number == previous_frame_number) { 396 ++it_test;
324 ++repeated_frames; 397 if (it_test == end_test) {
325 if (repeated_frames > max_repeated_frames) { 398 break;
326 max_repeated_frames = repeated_frames;
327 }
328 } else {
329 repeated_frames = 1;
330 } 399 }
400 int skipped_frames = 0;
401 ++it_ref;
402 while (it_ref != end_ref && it_ref->first != it_test->first) {
403 skipped_frames += it_ref->second;
404 ++it_ref;
405 }
406 if (it_ref == end_ref) {
407 fprintf(stderr,
408 "The barcode in the test video is not in the reference video.");
409 return;
410 }
411 if (skipped_frames > max_skipped_frames) {
412 max_skipped_frames = skipped_frames;
413 }
414 max_repeated_frames =
415 std::max(max_repeated_frames, it_test->second - it_ref->second + 1);
416 }
331 417
332 // Calculate how much frames have been skipped.
333 if (decoded_frame_number != 0 && previous_frame_number != -1) {
334 int skipped_frames = decoded_frame_number - previous_frame_number - 1;
335 if (skipped_frames > max_skipped_frames) {
336 max_skipped_frames = skipped_frames;
337 }
338 }
339 previous_frame_number = decoded_frame_number;
340 }
341 fprintf(output, "RESULT Max_repeated: %s= %d\n", label.c_str(), 418 fprintf(output, "RESULT Max_repeated: %s= %d\n", label.c_str(),
342 max_repeated_frames); 419 max_repeated_frames);
343 fprintf(output, "RESULT Max_skipped: %s= %d\n", label.c_str(), 420 fprintf(output, "RESULT Max_skipped: %s= %d\n", label.c_str(),
344 max_skipped_frames); 421 max_skipped_frames);
345 fclose(stats_file);
346 } 422 }
347 423
348 void PrintAnalysisResults(const std::string& label, ResultsContainer* results) { 424 void PrintAnalysisResults(const std::string& label, ResultsContainer* results) {
349 PrintAnalysisResults(stdout, label, results); 425 PrintAnalysisResults(stdout, label, results);
350 } 426 }
351 427
352 void PrintAnalysisResults(FILE* output, const std::string& label, 428 void PrintAnalysisResults(FILE* output, const std::string& label,
353 ResultsContainer* results) { 429 ResultsContainer* results) {
354 std::vector<AnalysisResult>::iterator iter; 430 std::vector<AnalysisResult>::iterator iter;
355 431
(...skipping 12 matching lines...) Expand all
368 for (iter = results->frames.begin(); iter != results->frames.end() - 1; 444 for (iter = results->frames.begin(); iter != results->frames.end() - 1;
369 ++iter) { 445 ++iter) {
370 fprintf(output, "%f,", iter->ssim_value); 446 fprintf(output, "%f,", iter->ssim_value);
371 } 447 }
372 fprintf(output, "%f] score\n", iter->ssim_value); 448 fprintf(output, "%f] score\n", iter->ssim_value);
373 } 449 }
374 } 450 }
375 451
376 } // namespace test 452 } // namespace test
377 } // namespace webrtc 453 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698