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

Side by Side Diff: media/bench/bench.cc

Issue 113888: mediabench change to decode one extra frame, flushing ffmpeg-mt for the last ... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 6 months 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 //
10 // This tool requires FFMPeg DLL's built with --enable-protocol=file.
9 11
10 #include <iomanip> 12 #include <iomanip>
11 #include <iostream> 13 #include <iostream>
12 #include <string> 14 #include <string>
13 15
14 #include "base/at_exit.h" 16 #include "base/at_exit.h"
15 #include "base/basictypes.h" 17 #include "base/basictypes.h"
16 #include "base/command_line.h" 18 #include "base/command_line.h"
17 #include "base/file_path.h" 19 #include "base/file_path.h"
18 #include "base/logging.h" 20 #include "base/logging.h"
19 #include "base/string_util.h" 21 #include "base/string_util.h"
20 #include "base/time.h" 22 #include "base/time.h"
21 #include "media/base/media.h" 23 #include "media/base/media.h"
22 #include "media/filters/ffmpeg_common.h" 24 #include "media/filters/ffmpeg_common.h"
23 25
24 namespace switches { 26 namespace switches {
25 const wchar_t kStream[] = L"stream"; 27 const wchar_t kStream[] = L"stream";
26 const wchar_t kVideoThreads[] = L"video-threads"; 28 const wchar_t kVideoThreads[] = L"video-threads";
27 const wchar_t kFast2[] = L"fast2"; 29 const wchar_t kFast2[] = L"fast2";
28 const wchar_t kSkip[] = L"skip"; 30 const wchar_t kSkip[] = L"skip";
31 const wchar_t kFlush[] = L"flush";
29 } // namespace switches 32 } // namespace switches
30 33
31 int main(int argc, const char** argv) { 34 int main(int argc, const char** argv) {
32 base::AtExitManager exit_manager; 35 base::AtExitManager exit_manager;
33 36
34 CommandLine::Init(argc, argv); 37 CommandLine::Init(argc, argv);
35 const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); 38 const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
36 39
37 std::vector<std::wstring> filenames(cmd_line->GetLooseValues()); 40 std::vector<std::wstring> filenames(cmd_line->GetLooseValues());
38 if (filenames.empty()) { 41 if (filenames.empty()) {
39 std::cerr << "Usage: media_bench [OPTIONS] FILE\n" 42 std::cerr << "Usage: media_bench [OPTIONS] FILE\n"
40 << " --stream=[audio|video] " 43 << " --stream=[audio|video] "
41 << "Benchmark either the audio or video stream\n" 44 << "Benchmark either the audio or video stream\n"
42 << " --video-threads=N " 45 << " --video-threads=N "
43 << "Decode video using N threads\n" 46 << "Decode video using N threads\n"
44 << " --fast2 " 47 << " --fast2 "
45 << "Enable fast2 flag\n" 48 << "Enable fast2 flag\n"
49 << " --flush "
50 << "Flush last frame\n"
46 << " --skip=[1|2|3] " 51 << " --skip=[1|2|3] "
47 << "1=loop nonref, 2=loop, 3= frame nonref" << std::endl; 52 << "1=loop nonref, 2=loop, 3= frame nonref\n" << std::endl;
48 return 1; 53 return 1;
49 } 54 }
50 55
51 // Initialize our media library (try loading DLLs, etc.) before continuing. 56 // Initialize our media library (try loading DLLs, etc.) before continuing.
52 // We use an empty file path as the parameter to force searching of the 57 // We use an empty file path as the parameter to force searching of the
53 // default locations for necessary DLLs and DSOs. 58 // default locations for necessary DLLs and DSOs.
54 if (media::InitializeMediaLibrary(FilePath()) == false) { 59 if (media::InitializeMediaLibrary(FilePath()) == false) {
55 std::cerr << "Unable to initialize the media library."; 60 std::cerr << "Unable to initialize the media library.";
56 return 1; 61 return 1;
57 } 62 }
(...skipping 21 matching lines...) Expand all
79 if (!threads.empty() && 84 if (!threads.empty() &&
80 !StringToInt(WideToUTF16Hack(threads), &video_threads)) { 85 !StringToInt(WideToUTF16Hack(threads), &video_threads)) {
81 video_threads = 0; 86 video_threads = 0;
82 } 87 }
83 88
84 bool fast2 = false; 89 bool fast2 = false;
85 if (cmd_line->HasSwitch(switches::kFast2)) { 90 if (cmd_line->HasSwitch(switches::kFast2)) {
86 fast2 = true; 91 fast2 = true;
87 } 92 }
88 93
94 bool flush = false;
95 if (cmd_line->HasSwitch(switches::kFlush)) {
96 flush = true;
97 }
98
89 int skip = 0; 99 int skip = 0;
90 if (cmd_line->HasSwitch(switches::kSkip)) { 100 if (cmd_line->HasSwitch(switches::kSkip)) {
91 std::wstring skip_opt(cmd_line->GetSwitchValue(switches::kSkip)); 101 std::wstring skip_opt(cmd_line->GetSwitchValue(switches::kSkip));
92 if (!StringToInt(WideToUTF16Hack(skip_opt), &skip)) { 102 if (!StringToInt(WideToUTF16Hack(skip_opt), &skip)) {
93 skip = 0; 103 skip = 0;
94 } 104 }
95 } 105 }
96 106
97 // Register FFmpeg and attempt to open file. 107 // Register FFmpeg and attempt to open file.
98 avcodec_init(); 108 avcodec_init();
(...skipping 17 matching lines...) Expand all
116 AVCodec* codec = avcodec_find_decoder(codec_context->codec_id); 126 AVCodec* codec = avcodec_find_decoder(codec_context->codec_id);
117 127
118 // See if we found our target codec. 128 // See if we found our target codec.
119 if (codec_context->codec_type == target_codec && target_stream < 0) { 129 if (codec_context->codec_type == target_codec && target_stream < 0) {
120 std::cout << "* "; 130 std::cout << "* ";
121 target_stream = i; 131 target_stream = i;
122 } else { 132 } else {
123 std::cout << " "; 133 std::cout << " ";
124 } 134 }
125 135
126 // Print out stream information 136 if (codec_context->codec_type == CODEC_TYPE_UNKNOWN) {
127 std::cout << "Stream #" << i << ": " << codec->name << " (" 137 std::cout << "Stream #" << i << ": Unknown" << std::endl;
128 << codec->long_name << ")" << std::endl; 138 } else {
139 // Print out stream information
140 std::cout << "Stream #" << i << ": " << codec->name << " ("
141 << codec->long_name << ")" << std::endl;
142 }
129 } 143 }
130 144
131 // Only continue if we found our target stream. 145 // Only continue if we found our target stream.
132 if (target_stream < 0) { 146 if (target_stream < 0) {
133 return 1; 147 return 1;
134 } 148 }
135 149
136 // Prepare FFmpeg structures. 150 // Prepare FFmpeg structures.
137 AVPacket packet; 151 AVPacket packet;
138 AVCodecContext* codec_context = format_context->streams[target_stream]->codec; 152 AVCodecContext* codec_context = format_context->streams[target_stream]->codec;
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
172 // Buffer used for video decoding. 186 // Buffer used for video decoding.
173 AVFrame* frame = avcodec_alloc_frame(); 187 AVFrame* frame = avcodec_alloc_frame();
174 if (!frame) { 188 if (!frame) {
175 std::cerr << "Could not allocate an AVFrame" << std::endl; 189 std::cerr << "Could not allocate an AVFrame" << std::endl;
176 return 1; 190 return 1;
177 } 191 }
178 192
179 // Stats collector. 193 // Stats collector.
180 std::vector<double> decode_times; 194 std::vector<double> decode_times;
181 decode_times.reserve(4096); 195 decode_times.reserve(4096);
182
183 // Parse through the entire stream until we hit EOF. 196 // Parse through the entire stream until we hit EOF.
184 base::TimeTicks start = base::TimeTicks::HighResNow(); 197 base::TimeTicks start = base::TimeTicks::HighResNow();
185 while (av_read_frame(format_context, &packet) >= 0) { 198 size_t frames = 0;
199 int read_result = 0;
200 do {
201 read_result = av_read_frame(format_context, &packet);
202
203 if (read_result < 0) {
204 if (flush) {
205 packet.stream_index = target_stream;
206 packet.size = 0;
207 } else {
208 break;
209 }
210 }
211
186 // Only decode packets from our target stream. 212 // Only decode packets from our target stream.
187 if (packet.stream_index == target_stream) { 213 if (packet.stream_index == target_stream) {
188 int result = -1; 214 int result = -1;
189 base::TimeTicks decode_start = base::TimeTicks::HighResNow(); 215 base::TimeTicks decode_start = base::TimeTicks::HighResNow();
190 if (target_codec == CODEC_TYPE_AUDIO) { 216 if (target_codec == CODEC_TYPE_AUDIO) {
191 int size_out = AVCODEC_MAX_AUDIO_FRAME_SIZE; 217 int size_out = AVCODEC_MAX_AUDIO_FRAME_SIZE;
192 result = avcodec_decode_audio3(codec_context, samples, &size_out, 218 result = avcodec_decode_audio3(codec_context, samples, &size_out,
193 &packet); 219 &packet);
220 if (size_out) {
221 ++frames;
222 read_result = 0; // Force continuation.
223 }
194 } else if (target_codec == CODEC_TYPE_VIDEO) { 224 } else if (target_codec == CODEC_TYPE_VIDEO) {
195 int got_picture = 0; 225 int got_picture = 0;
196 result = avcodec_decode_video2(codec_context, frame, &got_picture, 226 result = avcodec_decode_video2(codec_context, frame, &got_picture,
197 &packet); 227 &packet);
228 if (got_picture) {
229 ++frames;
230 read_result = 0; // Force continuation.
231 }
198 } else { 232 } else {
199 NOTREACHED(); 233 NOTREACHED();
200 } 234 }
201 base::TimeDelta delta = base::TimeTicks::HighResNow() - decode_start; 235 base::TimeDelta delta = base::TimeTicks::HighResNow() - decode_start;
236
202 decode_times.push_back(delta.InMillisecondsF()); 237 decode_times.push_back(delta.InMillisecondsF());
203 238
204 // Make sure our decoding went OK. 239 // Make sure our decoding went OK.
205 if (result < 0) { 240 if (result < 0) {
206 std::cerr << "Error while decoding" << std::endl; 241 std::cerr << "Error while decoding" << std::endl;
207 return 1; 242 return 1;
208 } 243 }
209 } 244 }
210
211 // Free our packet. 245 // Free our packet.
212 av_free_packet(&packet); 246 av_free_packet(&packet);
213 } 247 } while (read_result >= 0);
214 base::TimeDelta total = base::TimeTicks::HighResNow() - start; 248 base::TimeDelta total = base::TimeTicks::HighResNow() - start;
215 249
216 // Calculate the sum. The numbers are very consistent and the we're not too 250 // Calculate the sum of times. Note that some of these may be zero.
217 // worried about floating point error here.
218 double sum = 0; 251 double sum = 0;
219 for (size_t i = 0; i < decode_times.size(); ++i) { 252 for (size_t i = 0; i < decode_times.size(); ++i) {
220 sum += decode_times[i]; 253 sum += decode_times[i];
221 } 254 }
222 255
223 // Calculate the average. 256 // Print our results.
224 double average = sum / decode_times.size();
225
226 // Calculate the sum of the squared differences.
227 double squared_sum = 0;
228 for (size_t i = 0; i < decode_times.size(); ++i) {
229 double difference = decode_times[i] - average;
230 squared_sum += difference * difference;
231 }
232
233 // Calculate the standard deviation (jitter).
234 double stddev = sqrt(squared_sum / decode_times.size());
235
236 // Print our results.
237 std::cout.setf(std::ios::fixed); 257 std::cout.setf(std::ios::fixed);
238 std::cout.precision(3); 258 std::cout.precision(3);
239 std::cout << std::endl; 259 std::cout << std::endl;
240 std::cout << " Frames:" << std::setw(10) << decode_times.size() 260 std::cout << " Frames:" << std::setw(10) << frames
241 << std::endl; 261 << std::endl;
242 std::cout << " Total:" << std::setw(10) << total.InMillisecondsF() 262 std::cout << " Total:" << std::setw(10) << total.InMillisecondsF()
243 << " ms" << std::endl; 263 << " ms" << std::endl;
244 std::cout << " Summation:" << std::setw(10) << sum 264 std::cout << " Summation:" << std::setw(10) << sum
245 << " ms" << std::endl; 265 << " ms" << std::endl;
246 std::cout << " Average:" << std::setw(10) << average 266
247 << " ms" << std::endl; 267 if (frames > 0u) {
248 std::cout << " StdDev:" << std::setw(10) << stddev 268 // Calculate the average time per frame.
249 << " ms" << std::endl; 269 double average = sum / frames;
270
271 // Calculate the sum of the squared differences.
272 // Standard deviation will only be accurate if no threads are used.
273 // TODO(fbarchard): Rethink standard deviation calculation.
274 double squared_sum = 0;
275 for (size_t i = 0; i < frames; ++i) {
276 double difference = decode_times[i] - average;
277 squared_sum += difference * difference;
278 }
279
280 // Calculate the standard deviation (jitter).
281 double stddev = sqrt(squared_sum / frames);
282
283 std::cout << " Average:" << std::setw(10) << average
284 << " ms" << std::endl;
285 std::cout << " StdDev:" << std::setw(10) << stddev
286 << " ms" << std::endl;
287 }
250 return 0; 288 return 0;
251 } 289 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698