Chromium Code Reviews| 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. |
| 11 | 11 |
| 12 #include <iomanip> | 12 #include <iomanip> |
| 13 #include <iostream> | 13 #include <iostream> |
| 14 #include <string> | 14 #include <string> |
| 15 | 15 |
| 16 #include "base/at_exit.h" | 16 #include "base/at_exit.h" |
| 17 #include "base/basictypes.h" | 17 #include "base/basictypes.h" |
| 18 #include "base/command_line.h" | 18 #include "base/command_line.h" |
| 19 #include "base/file_path.h" | 19 #include "base/file_path.h" |
| 20 #include "base/file_util.h" | |
| 20 #include "base/logging.h" | 21 #include "base/logging.h" |
| 21 #include "base/string_util.h" | 22 #include "base/string_util.h" |
| 22 #include "base/time.h" | 23 #include "base/time.h" |
| 23 #include "media/base/media.h" | 24 #include "media/base/media.h" |
| 24 #include "media/filters/ffmpeg_common.h" | 25 #include "media/filters/ffmpeg_common.h" |
| 26 #include "media/filters/ffmpeg_video_decoder.h" | |
|
scherkus (not reviewing)
2009/09/03 22:03:36
hmm.. don't think you need to include this
| |
| 25 | 27 |
| 26 namespace switches { | 28 namespace switches { |
| 27 const wchar_t kStream[] = L"stream"; | 29 const wchar_t kStream[] = L"stream"; |
| 28 const wchar_t kVideoThreads[] = L"video-threads"; | 30 const wchar_t kVideoThreads[] = L"video-threads"; |
| 29 const wchar_t kFast2[] = L"fast2"; | 31 const wchar_t kFast2[] = L"fast2"; |
| 30 const wchar_t kSkip[] = L"skip"; | 32 const wchar_t kSkip[] = L"skip"; |
| 31 const wchar_t kFlush[] = L"flush"; | 33 const wchar_t kFlush[] = L"flush"; |
| 32 } // namespace switches | 34 } // namespace switches |
| 33 | 35 |
| 34 int main(int argc, const char** argv) { | 36 int main(int argc, const char** argv) { |
| 35 base::AtExitManager exit_manager; | 37 base::AtExitManager exit_manager; |
| 36 | 38 |
| 37 CommandLine::Init(argc, argv); | 39 CommandLine::Init(argc, argv); |
| 38 const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); | 40 const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); |
| 39 | 41 |
| 40 std::vector<std::wstring> filenames(cmd_line->GetLooseValues()); | 42 std::vector<std::wstring> filenames(cmd_line->GetLooseValues()); |
| 41 if (filenames.empty()) { | 43 if (filenames.empty()) { |
| 42 std::cerr << "Usage: media_bench [OPTIONS] FILE\n" | 44 std::cerr << "Usage: media_bench [OPTIONS] FILE [DUMPFILE]\n" |
| 43 << " --stream=[audio|video] " | 45 << " --stream=[audio|video] " |
| 44 << "Benchmark either the audio or video stream\n" | 46 << "Benchmark either the audio or video stream\n" |
| 45 << " --video-threads=N " | 47 << " --video-threads=N " |
| 46 << "Decode video using N threads\n" | 48 << "Decode video using N threads\n" |
| 47 << " --fast2 " | 49 << " --fast2 " |
| 48 << "Enable fast2 flag\n" | 50 << "Enable fast2 flag\n" |
| 49 << " --flush " | 51 << " --flush " |
| 50 << "Flush last frame\n" | 52 << "Flush last frame\n" |
| 51 << " --skip=[1|2|3] " | 53 << " --skip=[1|2|3] " |
| 52 << "1=loop nonref, 2=loop, 3= frame nonref\n" << std::endl; | 54 << "1=loop nonref, 2=loop, 3= frame nonref\n" << std::endl; |
| 53 return 1; | 55 return 1; |
| 54 } | 56 } |
| 55 | 57 |
| 56 // Initialize our media library (try loading DLLs, etc.) before continuing. | 58 // Initialize our media library (try loading DLLs, etc.) before continuing. |
| 57 // We use an empty file path as the parameter to force searching of the | 59 // We use an empty file path as the parameter to force searching of the |
| 58 // default locations for necessary DLLs and DSOs. | 60 // default locations for necessary DLLs and DSOs. |
| 59 if (media::InitializeMediaLibrary(FilePath()) == false) { | 61 if (media::InitializeMediaLibrary(FilePath()) == false) { |
| 60 std::cerr << "Unable to initialize the media library."; | 62 std::cerr << "Unable to initialize the media library."; |
| 61 return 1; | 63 return 1; |
| 62 } | 64 } |
| 63 | 65 |
| 64 // Retrieve command line options. | 66 // Retrieve command line options. |
| 65 std::string path(WideToUTF8(filenames[0])); | 67 std::string in_path(WideToUTF8(filenames[0])); |
| 68 std::string out_path; | |
| 69 if (filenames.size() > 1) { | |
| 70 out_path = WideToUTF8(filenames[1]); | |
| 71 } | |
| 66 CodecType target_codec = CODEC_TYPE_UNKNOWN; | 72 CodecType target_codec = CODEC_TYPE_UNKNOWN; |
| 67 int video_threads = 0; | 73 int video_threads = 0; |
| 68 | 74 |
| 69 // Determine whether to benchmark audio or video decoding. | 75 // Determine whether to benchmark audio or video decoding. |
| 70 std::wstring stream(cmd_line->GetSwitchValue(switches::kStream)); | 76 std::wstring stream(cmd_line->GetSwitchValue(switches::kStream)); |
| 71 if (!stream.empty()) { | 77 if (!stream.empty()) { |
| 72 if (stream.compare(L"audio") == 0) { | 78 if (stream.compare(L"audio") == 0) { |
| 73 target_codec = CODEC_TYPE_AUDIO; | 79 target_codec = CODEC_TYPE_AUDIO; |
| 74 } else if (stream.compare(L"video") == 0) { | 80 } else if (stream.compare(L"video") == 0) { |
| 75 target_codec = CODEC_TYPE_VIDEO; | 81 target_codec = CODEC_TYPE_VIDEO; |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 101 std::wstring skip_opt(cmd_line->GetSwitchValue(switches::kSkip)); | 107 std::wstring skip_opt(cmd_line->GetSwitchValue(switches::kSkip)); |
| 102 if (!StringToInt(WideToUTF16Hack(skip_opt), &skip)) { | 108 if (!StringToInt(WideToUTF16Hack(skip_opt), &skip)) { |
| 103 skip = 0; | 109 skip = 0; |
| 104 } | 110 } |
| 105 } | 111 } |
| 106 | 112 |
| 107 // Register FFmpeg and attempt to open file. | 113 // Register FFmpeg and attempt to open file. |
| 108 avcodec_init(); | 114 avcodec_init(); |
| 109 av_register_all(); | 115 av_register_all(); |
| 110 AVFormatContext* format_context = NULL; | 116 AVFormatContext* format_context = NULL; |
| 111 if (av_open_input_file(&format_context, path.c_str(), NULL, 0, NULL) < 0) { | 117 if (av_open_input_file(&format_context, in_path.c_str(), NULL, 0, NULL) < 0) { |
| 112 std::cerr << "Could not open " << path << std::endl; | 118 std::cerr << "Could not open " << in_path << std::endl; |
| 113 return 1; | 119 return 1; |
| 114 } | 120 } |
| 115 | 121 |
| 122 // Open output file. | |
| 123 FILE *output = NULL; | |
|
scherkus (not reviewing)
2009/09/03 22:03:36
pointer goes with typename
| |
| 124 if (!out_path.empty()) { | |
| 125 output = file_util::OpenFile(out_path.c_str(), "wb"); | |
| 126 if (!output) { | |
| 127 LOG(ERROR) << "could not open output"; | |
| 128 return 1; | |
| 129 } | |
| 130 } | |
| 131 | |
| 116 // Parse a little bit of the stream to fill out the format context. | 132 // Parse a little bit of the stream to fill out the format context. |
| 117 if (av_find_stream_info(format_context) < 0) { | 133 if (av_find_stream_info(format_context) < 0) { |
| 118 std::cerr << "Could not find stream info for " << path << std::endl; | 134 std::cerr << "Could not find stream info for " << in_path << std::endl; |
| 119 return 1; | 135 return 1; |
| 120 } | 136 } |
| 121 | 137 |
| 122 // Find our target stream. | 138 // Find our target stream. |
| 123 int target_stream = -1; | 139 int target_stream = -1; |
| 124 for (size_t i = 0; i < format_context->nb_streams; ++i) { | 140 for (size_t i = 0; i < format_context->nb_streams; ++i) { |
| 125 AVCodecContext* codec_context = format_context->streams[i]->codec; | 141 AVCodecContext* codec_context = format_context->streams[i]->codec; |
| 126 AVCodec* codec = avcodec_find_decoder(codec_context->codec_id); | 142 AVCodec* codec = avcodec_find_decoder(codec_context->codec_id); |
| 127 | 143 |
| 128 // See if we found our target codec. | 144 // See if we found our target codec. |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 213 if (packet.stream_index == target_stream) { | 229 if (packet.stream_index == target_stream) { |
| 214 int result = -1; | 230 int result = -1; |
| 215 base::TimeTicks decode_start = base::TimeTicks::HighResNow(); | 231 base::TimeTicks decode_start = base::TimeTicks::HighResNow(); |
| 216 if (target_codec == CODEC_TYPE_AUDIO) { | 232 if (target_codec == CODEC_TYPE_AUDIO) { |
| 217 int size_out = AVCODEC_MAX_AUDIO_FRAME_SIZE; | 233 int size_out = AVCODEC_MAX_AUDIO_FRAME_SIZE; |
| 218 result = avcodec_decode_audio3(codec_context, samples, &size_out, | 234 result = avcodec_decode_audio3(codec_context, samples, &size_out, |
| 219 &packet); | 235 &packet); |
| 220 if (size_out) { | 236 if (size_out) { |
| 221 ++frames; | 237 ++frames; |
| 222 read_result = 0; // Force continuation. | 238 read_result = 0; // Force continuation. |
| 239 | |
| 240 if (output) { | |
| 241 if (fwrite(samples, 1, size_out, output) != | |
| 242 static_cast<size_t>(size_out)) { | |
| 243 std::cerr << "could not write data after " << size_out; | |
| 244 return 1; | |
| 245 } | |
| 246 } | |
| 223 } | 247 } |
| 224 } else if (target_codec == CODEC_TYPE_VIDEO) { | 248 } else if (target_codec == CODEC_TYPE_VIDEO) { |
| 225 int got_picture = 0; | 249 int got_picture = 0; |
| 226 result = avcodec_decode_video2(codec_context, frame, &got_picture, | 250 result = avcodec_decode_video2(codec_context, frame, &got_picture, |
| 227 &packet); | 251 &packet); |
| 228 if (got_picture) { | 252 if (got_picture) { |
| 229 ++frames; | 253 ++frames; |
| 230 read_result = 0; // Force continuation. | 254 read_result = 0; // Force continuation. |
| 255 | |
| 256 // TODO(fbarchard): support formats other than YV12. | |
|
scherkus (not reviewing)
2009/09/03 22:03:36
this comment is out of date
| |
| 257 if (output) { | |
| 258 for (int plane = 0; plane < 3; ++plane) { | |
| 259 const uint8* source = frame->data[plane]; | |
| 260 const size_t source_stride = frame->linesize[plane]; | |
| 261 size_t bytes_per_line = codec_context->width; | |
| 262 size_t copy_lines = codec_context->height; | |
| 263 if (plane != 0) { | |
| 264 switch (codec_context->pix_fmt) { | |
| 265 case PIX_FMT_YUV420P: | |
| 266 case PIX_FMT_YUVJ420P: | |
| 267 bytes_per_line /= 2; | |
| 268 copy_lines = (copy_lines + 1) / 2; | |
| 269 break; | |
| 270 case PIX_FMT_YUV422P: | |
| 271 case PIX_FMT_YUVJ422P: | |
| 272 bytes_per_line /= 2; | |
| 273 copy_lines = copy_lines; | |
|
scherkus (not reviewing)
2009/09/03 22:03:36
redundant?
| |
| 274 break; | |
| 275 case PIX_FMT_YUV444P: | |
| 276 case PIX_FMT_YUVJ444P: | |
| 277 copy_lines = copy_lines; | |
|
scherkus (not reviewing)
2009/09/03 22:03:36
redundant?
| |
| 278 break; | |
| 279 default: | |
| 280 std::cerr << "unknown video format: " | |
| 281 << codec_context->pix_fmt; | |
| 282 return 1; | |
| 283 } | |
| 284 } | |
| 285 for (size_t i = 0; i < copy_lines; ++i) { | |
| 286 if (fwrite(source, 1, bytes_per_line, output) != | |
| 287 bytes_per_line) { | |
| 288 std::cerr << "could not write data after " | |
| 289 << bytes_per_line; | |
| 290 return 1; | |
| 291 } | |
| 292 source += source_stride; | |
| 293 } | |
| 294 } | |
| 295 } | |
| 231 } | 296 } |
| 232 } else { | 297 } else { |
| 233 NOTREACHED(); | 298 NOTREACHED(); |
| 234 } | 299 } |
| 235 base::TimeDelta delta = base::TimeTicks::HighResNow() - decode_start; | 300 base::TimeDelta delta = base::TimeTicks::HighResNow() - decode_start; |
| 236 | 301 |
| 237 decode_times.push_back(delta.InMillisecondsF()); | 302 decode_times.push_back(delta.InMillisecondsF()); |
| 238 | 303 |
| 239 // Make sure our decoding went OK. | 304 // Make sure our decoding went OK. |
| 240 if (result < 0) { | 305 if (result < 0) { |
| 241 std::cerr << "Error while decoding" << std::endl; | 306 std::cerr << "Error while decoding" << std::endl; |
| 242 return 1; | 307 return 1; |
| 243 } | 308 } |
| 244 } | 309 } |
| 245 // Free our packet. | 310 // Free our packet. |
| 246 av_free_packet(&packet); | 311 av_free_packet(&packet); |
| 247 } while (read_result >= 0); | 312 } while (read_result >= 0); |
| 248 base::TimeDelta total = base::TimeTicks::HighResNow() - start; | 313 base::TimeDelta total = base::TimeTicks::HighResNow() - start; |
| 249 | 314 |
| 315 if (output) | |
| 316 file_util::CloseFile(output); | |
| 317 | |
| 250 // Calculate the sum of times. Note that some of these may be zero. | 318 // Calculate the sum of times. Note that some of these may be zero. |
| 251 double sum = 0; | 319 double sum = 0; |
| 252 for (size_t i = 0; i < decode_times.size(); ++i) { | 320 for (size_t i = 0; i < decode_times.size(); ++i) { |
| 253 sum += decode_times[i]; | 321 sum += decode_times[i]; |
| 254 } | 322 } |
| 255 | 323 |
| 256 // Print our results. | 324 // Print our results. |
| 257 std::cout.setf(std::ios::fixed); | 325 std::cout.setf(std::ios::fixed); |
| 258 std::cout.precision(2); | 326 std::cout.precision(2); |
| 259 std::cout << std::endl; | 327 std::cout << std::endl; |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 280 // Calculate the standard deviation (jitter). | 348 // Calculate the standard deviation (jitter). |
| 281 double stddev = sqrt(squared_sum / frames); | 349 double stddev = sqrt(squared_sum / frames); |
| 282 | 350 |
| 283 std::cout << " Average:" << std::setw(10) << average | 351 std::cout << " Average:" << std::setw(10) << average |
| 284 << " ms" << std::endl; | 352 << " ms" << std::endl; |
| 285 std::cout << " StdDev:" << std::setw(10) << stddev | 353 std::cout << " StdDev:" << std::setw(10) << stddev |
| 286 << " ms" << std::endl; | 354 << " ms" << std::endl; |
| 287 } | 355 } |
| 288 return 0; | 356 return 0; |
| 289 } | 357 } |
| OLD | NEW |