diff options
author | scherkus@chromium.org <scherkus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-04-09 22:04:06 +0000 |
---|---|---|
committer | scherkus@chromium.org <scherkus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-04-09 22:04:06 +0000 |
commit | 9005af1fd8600cb273436977d02d99e01bf118ac (patch) | |
tree | 8e30a625dfed85d3f91f2ab0dfe4f7bcb762e4f2 | |
parent | 4b917eb1d25ac97513749d5120bb4d405da60a1c (diff) | |
download | chromium_src-9005af1fd8600cb273436977d02d99e01bf118ac.zip chromium_src-9005af1fd8600cb273436977d02d99e01bf118ac.tar.gz chromium_src-9005af1fd8600cb273436977d02d99e01bf118ac.tar.bz2 |
Checking in FFmpeg benchmarking application.
We use this to compare different compiler setting, different run-time flags and different branches and revisions of FFmpeg.
Review URL: http://codereview.chromium.org/63068
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@13468 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | media/bench/bench.cc | 198 | ||||
-rw-r--r-- | media/media.gyp | 13 | ||||
-rw-r--r-- | third_party/ffmpeg/avcodec-52.def | 1 |
3 files changed, 212 insertions, 0 deletions
diff --git a/media/bench/bench.cc b/media/bench/bench.cc new file mode 100644 index 0000000..6b519fb --- /dev/null +++ b/media/bench/bench.cc @@ -0,0 +1,198 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Standalone benchmarking application based on FFmpeg. This tool is used to +// measure decoding performance between different FFmpeg compile and run-time +// options. We also use this tool to measure performance regressions when +// testing newer builds of FFmpeg from trunk. + +#include <iostream> +#include <windows.h> + +#include "base/basictypes.h" +#include "base/command_line.h" +#include "base/logging.h" +#include "base/string_util.h" +#include "base/time.h" +#include "media/filters/ffmpeg_common.h" + +namespace switches { +const wchar_t kStream[] = L"stream"; +const wchar_t kVideoThreads[] = L"video-threads"; +} // namespace switches + +int main(int argc, const char** argv) { + CommandLine::Init(argc, argv); + const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); + + std::vector<std::wstring> filenames(cmd_line->GetLooseValues()); + if (filenames.empty()) { + std::cerr << "Usage: media_bench [OPTIONS] FILE\n" + << " --stream=[audio|video] " + << "Benchmark either the audio or video stream\n" + << " --video-threads=N " + << "Decode video using N threads" << std::endl; + return 1; + } + + // Retrieve command line options. + std::string path(WideToUTF8(filenames[0])); + CodecType target_codec = CODEC_TYPE_UNKNOWN; + int video_threads = 0; + + // Determine whether to benchmark audio or video decoding. + std::wstring stream(cmd_line->GetSwitchValue(switches::kStream)); + if (!stream.empty()) { + if (stream.compare(L"audio") == 0) { + target_codec = CODEC_TYPE_AUDIO; + } else if (stream.compare(L"video") == 0) { + target_codec = CODEC_TYPE_VIDEO; + } else { + std::cerr << "Unknown --stream option " << stream << std::endl; + return 1; + } + } + + // Determine number of threads to use for video decoding (optional). + std::wstring threads(cmd_line->GetSwitchValue(switches::kVideoThreads)); + if (!threads.empty() && !StringToInt(threads, &video_threads)) { + video_threads = 0; + } + + // Register FFmpeg and attempt to open file. + avcodec_init(); + av_register_all(); + AVFormatContext* format_context = NULL; + if (av_open_input_file(&format_context, path.c_str(), NULL, 0, NULL) < 0) { + std::cerr << "Could not open " << path << std::endl; + return 1; + } + + // Parse a little bit of the stream to fill out the format context. + if (av_find_stream_info(format_context) < 0) { + std::cerr << "Could not find stream info for " << path << std::endl; + return 1; + } + + // Find our target stream. + int target_stream = -1; + for (size_t i = 0; i < format_context->nb_streams; ++i) { + AVCodecContext* codec_context = format_context->streams[i]->codec; + AVCodec* codec = avcodec_find_decoder(codec_context->codec_id); + + // See if we found our target codec. + if (codec_context->codec_type == target_codec && target_stream < 0) { + std::cout << "* "; + target_stream = i; + } else { + std::cout << " "; + } + + // Print out stream information + std::cout << "Stream #" << i << ": " << codec->name << " (" + << codec->long_name << ")" << std::endl; + } + + // Only continue if we found our target stream. + if (target_stream < 0) { + return 1; + } + + // Prepare FFmpeg structures. + AVPacket packet; + AVCodecContext* codec_context = format_context->streams[target_stream]->codec; + AVCodec* codec = avcodec_find_decoder(codec_context->codec_id); + + // Initialize threaded decode. + if (target_codec == CODEC_TYPE_VIDEO && video_threads > 0) { + if (avcodec_thread_init(codec_context, video_threads) < 0) { + std::cerr << "WARNING: Could not initialize threading!\n" + << "Did you build with pthread/w32thread support?" << std::endl; + } + } + + // Initialize our codec. + if (avcodec_open(codec_context, codec) < 0) { + std::cerr << "Could not open codec " << codec_context->codec->name + << std::endl; + return 1; + } + + // Buffer used for audio decoding. + int16* samples = + reinterpret_cast<int16*>(av_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE)); + + // Buffer used for video decoding. + AVFrame* frame = avcodec_alloc_frame(); + if (!frame) { + std::cerr << "Could not allocate an AVFrame" << std::endl; + return 1; + } + + // Stats collector. + std::vector<double> decode_times; + decode_times.reserve(4096); + + // Parse through the entire stream until we hit EOF. + base::TimeTicks start = base::TimeTicks::HighResNow(); + while (av_read_frame(format_context, &packet) >= 0) { + // Only decode packets from our target stream. + if (packet.stream_index == target_stream) { + int result = -1; + base::TimeTicks decode_start = base::TimeTicks::HighResNow(); + if (target_codec == CODEC_TYPE_AUDIO) { + int size_out = AVCODEC_MAX_AUDIO_FRAME_SIZE; + result = avcodec_decode_audio2(codec_context, samples, &size_out, + packet.data, packet.size); + } else if (target_codec == CODEC_TYPE_VIDEO) { + int got_picture = 0; + result = avcodec_decode_video(codec_context, frame, &got_picture, + packet.data, packet.size); + } else { + NOTREACHED(); + } + base::TimeDelta delta = base::TimeTicks::HighResNow() - decode_start; + decode_times.push_back(delta.InMillisecondsF()); + + // Make sure our decoding went OK. + if (result < 0) { + std::cerr << "Error while decoding" << std::endl; + return 1; + } + } + + // Free our packet. + av_free_packet(&packet); + } + base::TimeDelta total = base::TimeTicks::HighResNow() - start; + + // Calculate the sum. The numbers are very consistent and the we're not too + // worried about floating point error here. + double sum = 0; + for (size_t i = 0; i < decode_times.size(); ++i) { + sum += decode_times[i]; + } + + // Calculate the average. + double average = sum / decode_times.size(); + + // Calculate the sum of the squared differences. + double squared_sum = 0; + for (size_t i = 0; i < decode_times.size(); ++i) { + double difference = decode_times[i] - average; + squared_sum += difference * difference; + } + + // Calculate the standard deviation (jitter). + double stddev = sqrt(squared_sum / decode_times.size()); + + // Print our results. + std::cout << std::endl; + std::cout << " Frames: " << decode_times.size() << std::endl; + std::cout << " Total: " << total.InMillisecondsF() << "ms" << std::endl; + std::cout << " Summation: " << sum << "ms" << std::endl; + std::cout << " Average: " << average << "ms" << std::endl; + std::cout << " StdDev: " << stddev << "ms" << std::endl; + return 0; +} diff --git a/media/media.gyp b/media/media.gyp index f3e59f9..df392ac 100644 --- a/media/media.gyp +++ b/media/media.gyp @@ -178,6 +178,19 @@ 'player/player.cc', ], }, + { + 'target_name': 'media_bench', + 'type': 'executable', + 'msvs_guid': '45BC4F87-4604-4962-A751-7C7B29A080BF', + 'dependencies': [ + 'media', + '../base/base.gyp:base', + '../third_party/ffmpeg/ffmpeg.gyp:ffmpeg', + ], + 'sources': [ + 'bench/bench.cc', + ], + }, ], }], ], diff --git a/third_party/ffmpeg/avcodec-52.def b/third_party/ffmpeg/avcodec-52.def index 13e99ff..7a377304 100644 --- a/third_party/ffmpeg/avcodec-52.def +++ b/third_party/ffmpeg/avcodec-52.def @@ -2,6 +2,7 @@ LIBRARY avcodec-52 EXPORTS av_bitstream_filter_init avcodec_alloc_context + avcodec_alloc_frame avcodec_decode_audio2 avcodec_decode_video avcodec_find_decoder |