| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // Standalone benchmarking application based on FFmpeg. This tool is used to | 5 // Standalone benchmarking application based on FFmpeg. This tool is used to |
| 6 // measure decoding performance between different FFmpeg compile and run-time | 6 // measure decoding performance between different FFmpeg compile and run-time |
| 7 // options. We also use this tool to measure performance regressions when | 7 // options. We also use this tool to measure performance regressions when |
| 8 // testing newer builds of FFmpeg from trunk. | 8 // testing newer builds of FFmpeg from trunk. |
| 9 // | 9 // |
| 10 // This tool requires FFMPeg DLL's built with --enable-protocol=file. | 10 // This tool requires FFMPeg DLL's built with --enable-protocol=file. |
| (...skipping 14 matching lines...) Expand all Loading... |
| 25 #include "media/bench/file_protocol.h" | 25 #include "media/bench/file_protocol.h" |
| 26 #include "media/filters/ffmpeg_common.h" | 26 #include "media/filters/ffmpeg_common.h" |
| 27 #include "media/filters/ffmpeg_video_decoder.h" | 27 #include "media/filters/ffmpeg_video_decoder.h" |
| 28 | 28 |
| 29 namespace switches { | 29 namespace switches { |
| 30 const wchar_t kStream[] = L"stream"; | 30 const wchar_t kStream[] = L"stream"; |
| 31 const wchar_t kVideoThreads[] = L"video-threads"; | 31 const wchar_t kVideoThreads[] = L"video-threads"; |
| 32 const wchar_t kFast2[] = L"fast2"; | 32 const wchar_t kFast2[] = L"fast2"; |
| 33 const wchar_t kSkip[] = L"skip"; | 33 const wchar_t kSkip[] = L"skip"; |
| 34 const wchar_t kFlush[] = L"flush"; | 34 const wchar_t kFlush[] = L"flush"; |
| 35 const wchar_t kHash[] = L"hash"; |
| 35 } // namespace switches | 36 } // namespace switches |
| 36 | 37 |
| 38 namespace { |
| 39 // DJB2 hash |
| 40 unsigned int hash_djb2(const uint8* s, |
| 41 size_t len, unsigned int hash) { |
| 42 while (len--) |
| 43 hash = hash * 33 + *s++; |
| 44 return hash; |
| 45 } |
| 46 } |
| 47 |
| 37 int main(int argc, const char** argv) { | 48 int main(int argc, const char** argv) { |
| 38 base::AtExitManager exit_manager; | 49 base::AtExitManager exit_manager; |
| 39 | 50 |
| 40 CommandLine::Init(argc, argv); | 51 CommandLine::Init(argc, argv); |
| 41 const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); | 52 const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); |
| 42 | 53 |
| 43 std::vector<std::wstring> filenames(cmd_line->GetLooseValues()); | 54 std::vector<std::wstring> filenames(cmd_line->GetLooseValues()); |
| 44 if (filenames.empty()) { | 55 if (filenames.empty()) { |
| 45 std::cerr << "Usage: media_bench [OPTIONS] FILE [DUMPFILE]\n" | 56 std::cerr << "Usage: media_bench [OPTIONS] FILE [DUMPFILE]\n" |
| 46 << " --stream=[audio|video] " | 57 << " --stream=[audio|video] " |
| 47 << "Benchmark either the audio or video stream\n" | 58 << "Benchmark either the audio or video stream\n" |
| 48 << " --video-threads=N " | 59 << " --video-threads=N " |
| 49 << "Decode video using N threads\n" | 60 << "Decode video using N threads\n" |
| 50 << " --fast2 " | 61 << " --fast2 " |
| 51 << "Enable fast2 flag\n" | 62 << "Enable fast2 flag\n" |
| 52 << " --flush " | 63 << " --flush " |
| 53 << "Flush last frame\n" | 64 << "Flush last frame\n" |
| 65 << " --hash " |
| 66 << "Hash decoded buffers\n" |
| 54 << " --skip=[1|2|3] " | 67 << " --skip=[1|2|3] " |
| 55 << "1=loop nonref, 2=loop, 3= frame nonref\n" << std::endl; | 68 << "1=loop nonref, 2=loop, 3= frame nonref\n" << std::endl; |
| 56 return 1; | 69 return 1; |
| 57 } | 70 } |
| 58 | 71 |
| 59 // Initialize our media library (try loading DLLs, etc.) before continuing. | 72 // Initialize our media library (try loading DLLs, etc.) before continuing. |
| 60 // We use an empty file path as the parameter to force searching of the | 73 // We use an empty file path as the parameter to force searching of the |
| 61 // default locations for necessary DLLs and DSOs. | 74 // default locations for necessary DLLs and DSOs. |
| 62 if (media::InitializeMediaLibrary(FilePath()) == false) { | 75 if (media::InitializeMediaLibrary(FilePath()) == false) { |
| 63 std::cerr << "Unable to initialize the media library."; | 76 std::cerr << "Unable to initialize the media library."; |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 96 bool fast2 = false; | 109 bool fast2 = false; |
| 97 if (cmd_line->HasSwitch(switches::kFast2)) { | 110 if (cmd_line->HasSwitch(switches::kFast2)) { |
| 98 fast2 = true; | 111 fast2 = true; |
| 99 } | 112 } |
| 100 | 113 |
| 101 bool flush = false; | 114 bool flush = false; |
| 102 if (cmd_line->HasSwitch(switches::kFlush)) { | 115 if (cmd_line->HasSwitch(switches::kFlush)) { |
| 103 flush = true; | 116 flush = true; |
| 104 } | 117 } |
| 105 | 118 |
| 119 unsigned int hash_value = 5381u; // Seed for DJB2. |
| 120 bool hash = false; |
| 121 if (cmd_line->HasSwitch(switches::kHash)) { |
| 122 hash = true; |
| 123 } |
| 124 |
| 106 int skip = 0; | 125 int skip = 0; |
| 107 if (cmd_line->HasSwitch(switches::kSkip)) { | 126 if (cmd_line->HasSwitch(switches::kSkip)) { |
| 108 std::wstring skip_opt(cmd_line->GetSwitchValue(switches::kSkip)); | 127 std::wstring skip_opt(cmd_line->GetSwitchValue(switches::kSkip)); |
| 109 if (!StringToInt(WideToUTF16Hack(skip_opt), &skip)) { | 128 if (!StringToInt(WideToUTF16Hack(skip_opt), &skip)) { |
| 110 skip = 0; | 129 skip = 0; |
| 111 } | 130 } |
| 112 } | 131 } |
| 113 | 132 |
| 114 // Register FFmpeg and attempt to open file. | 133 // Register FFmpeg and attempt to open file. |
| 115 avcodec_init(); | 134 avcodec_init(); |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 239 ++frames; | 258 ++frames; |
| 240 read_result = 0; // Force continuation. | 259 read_result = 0; // Force continuation. |
| 241 | 260 |
| 242 if (output) { | 261 if (output) { |
| 243 if (fwrite(samples, 1, size_out, output) != | 262 if (fwrite(samples, 1, size_out, output) != |
| 244 static_cast<size_t>(size_out)) { | 263 static_cast<size_t>(size_out)) { |
| 245 std::cerr << "could not write data after " << size_out; | 264 std::cerr << "could not write data after " << size_out; |
| 246 return 1; | 265 return 1; |
| 247 } | 266 } |
| 248 } | 267 } |
| 268 if (hash) { |
| 269 hash_value = hash_djb2(reinterpret_cast<const uint8*>(samples), |
| 270 size_out, hash_value); |
| 271 } |
| 249 } | 272 } |
| 250 } else if (target_codec == CODEC_TYPE_VIDEO) { | 273 } else if (target_codec == CODEC_TYPE_VIDEO) { |
| 251 int got_picture = 0; | 274 int got_picture = 0; |
| 252 result = avcodec_decode_video2(codec_context, frame, &got_picture, | 275 result = avcodec_decode_video2(codec_context, frame, &got_picture, |
| 253 &packet); | 276 &packet); |
| 254 if (got_picture) { | 277 if (got_picture) { |
| 255 ++frames; | 278 ++frames; |
| 256 read_result = 0; // Force continuation. | 279 read_result = 0; // Force continuation. |
| 257 | 280 |
| 258 // TODO(fbarchard): support formats other than YV12. | 281 if (output || hash) { |
| 259 if (output) { | |
| 260 for (int plane = 0; plane < 3; ++plane) { | 282 for (int plane = 0; plane < 3; ++plane) { |
| 261 const uint8* source = frame->data[plane]; | 283 const uint8* source = frame->data[plane]; |
| 262 const size_t source_stride = frame->linesize[plane]; | 284 const size_t source_stride = frame->linesize[plane]; |
| 263 size_t bytes_per_line = codec_context->width; | 285 size_t bytes_per_line = codec_context->width; |
| 264 size_t copy_lines = codec_context->height; | 286 size_t copy_lines = codec_context->height; |
| 265 if (plane != 0) { | 287 if (plane != 0) { |
| 266 switch (codec_context->pix_fmt) { | 288 switch (codec_context->pix_fmt) { |
| 267 case PIX_FMT_YUV420P: | 289 case PIX_FMT_YUV420P: |
| 268 case PIX_FMT_YUVJ420P: | 290 case PIX_FMT_YUVJ420P: |
| 269 bytes_per_line /= 2; | 291 bytes_per_line /= 2; |
| 270 copy_lines = (copy_lines + 1) / 2; | 292 copy_lines = (copy_lines + 1) / 2; |
| 271 break; | 293 break; |
| 272 case PIX_FMT_YUV422P: | 294 case PIX_FMT_YUV422P: |
| 273 case PIX_FMT_YUVJ422P: | 295 case PIX_FMT_YUVJ422P: |
| 274 bytes_per_line /= 2; | 296 bytes_per_line /= 2; |
| 275 copy_lines = copy_lines; | |
| 276 break; | 297 break; |
| 277 case PIX_FMT_YUV444P: | 298 case PIX_FMT_YUV444P: |
| 278 case PIX_FMT_YUVJ444P: | 299 case PIX_FMT_YUVJ444P: |
| 279 copy_lines = copy_lines; | |
| 280 break; | 300 break; |
| 281 default: | 301 default: |
| 282 std::cerr << "unknown video format: " | 302 std::cerr << "unknown video format: " |
| 283 << codec_context->pix_fmt; | 303 << codec_context->pix_fmt; |
| 284 return 1; | 304 return 1; |
| 285 } | 305 } |
| 286 } | 306 } |
| 287 for (size_t i = 0; i < copy_lines; ++i) { | 307 if (output) { |
| 288 if (fwrite(source, 1, bytes_per_line, output) != | 308 for (size_t i = 0; i < copy_lines; ++i) { |
| 289 bytes_per_line) { | 309 if (fwrite(source, 1, bytes_per_line, output) != |
| 290 std::cerr << "could not write data after " | 310 bytes_per_line) { |
| 291 << bytes_per_line; | 311 std::cerr << "could not write data after " |
| 292 return 1; | 312 << bytes_per_line; |
| 313 return 1; |
| 314 } |
| 315 source += source_stride; |
| 293 } | 316 } |
| 294 source += source_stride; | 317 } |
| 318 if (hash) { |
| 319 for (size_t i = 0; i < copy_lines; ++i) { |
| 320 hash_value = hash_djb2(source, bytes_per_line, hash_value); |
| 321 source += source_stride; |
| 322 } |
| 295 } | 323 } |
| 296 } | 324 } |
| 297 } | 325 } |
| 298 } | 326 } |
| 299 } else { | 327 } else { |
| 300 NOTREACHED(); | 328 NOTREACHED(); |
| 301 } | 329 } |
| 302 base::TimeDelta delta = base::TimeTicks::HighResNow() - decode_start; | 330 base::TimeDelta delta = base::TimeTicks::HighResNow() - decode_start; |
| 303 | 331 |
| 304 decode_times.push_back(delta.InMillisecondsF()); | 332 decode_times.push_back(delta.InMillisecondsF()); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 326 // Print our results. | 354 // Print our results. |
| 327 std::cout.setf(std::ios::fixed); | 355 std::cout.setf(std::ios::fixed); |
| 328 std::cout.precision(2); | 356 std::cout.precision(2); |
| 329 std::cout << std::endl; | 357 std::cout << std::endl; |
| 330 std::cout << " Frames:" << std::setw(10) << frames | 358 std::cout << " Frames:" << std::setw(10) << frames |
| 331 << std::endl; | 359 << std::endl; |
| 332 std::cout << " Total:" << std::setw(10) << total.InMillisecondsF() | 360 std::cout << " Total:" << std::setw(10) << total.InMillisecondsF() |
| 333 << " ms" << std::endl; | 361 << " ms" << std::endl; |
| 334 std::cout << " Summation:" << std::setw(10) << sum | 362 std::cout << " Summation:" << std::setw(10) << sum |
| 335 << " ms" << std::endl; | 363 << " ms" << std::endl; |
| 364 if (hash) { |
| 365 std::cout << " Hash:" << std::setw(10) << hash_value |
| 366 << std::endl; |
| 367 } |
| 336 | 368 |
| 337 if (frames > 0u) { | 369 if (frames > 0u) { |
| 338 // Calculate the average time per frame. | 370 // Calculate the average time per frame. |
| 339 double average = sum / frames; | 371 double average = sum / frames; |
| 340 | 372 |
| 341 // Calculate the sum of the squared differences. | 373 // Calculate the sum of the squared differences. |
| 342 // Standard deviation will only be accurate if no threads are used. | 374 // Standard deviation will only be accurate if no threads are used. |
| 343 // TODO(fbarchard): Rethink standard deviation calculation. | 375 // TODO(fbarchard): Rethink standard deviation calculation. |
| 344 double squared_sum = 0; | 376 double squared_sum = 0; |
| 345 for (size_t i = 0; i < frames; ++i) { | 377 for (size_t i = 0; i < frames; ++i) { |
| 346 double difference = decode_times[i] - average; | 378 double difference = decode_times[i] - average; |
| 347 squared_sum += difference * difference; | 379 squared_sum += difference * difference; |
| 348 } | 380 } |
| 349 | 381 |
| 350 // Calculate the standard deviation (jitter). | 382 // Calculate the standard deviation (jitter). |
| 351 double stddev = sqrt(squared_sum / frames); | 383 double stddev = sqrt(squared_sum / frames); |
| 352 | 384 |
| 353 std::cout << " Average:" << std::setw(10) << average | 385 std::cout << " Average:" << std::setw(10) << average |
| 354 << " ms" << std::endl; | 386 << " ms" << std::endl; |
| 355 std::cout << " StdDev:" << std::setw(10) << stddev | 387 std::cout << " StdDev:" << std::setw(10) << stddev |
| 356 << " ms" << std::endl; | 388 << " ms" << std::endl; |
| 357 } | 389 } |
| 358 return 0; | 390 return 0; |
| 359 } | 391 } |
| OLD | NEW |