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

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

Issue 199049: Media Bench file IO redux to address mp4 parsing issue. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 3 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 | media/bench/file_protocol.cc » ('j') | 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 // 9
10 // This tool requires FFMPeg DLL's built with --enable-protocol=file. 10 #include "build/build_config.h"
11
12 // For pipe _setmode to binary
13 #if defined(OS_WIN)
14 #include <fcntl.h>
15 #include <io.h>
16 #endif
11 17
12 #include <iomanip> 18 #include <iomanip>
13 #include <iostream> 19 #include <iostream>
14 #include <string> 20 #include <string>
15 21
16 #include "base/at_exit.h" 22 #include "base/at_exit.h"
17 #include "base/basictypes.h" 23 #include "base/basictypes.h"
18 #include "base/command_line.h" 24 #include "base/command_line.h"
19 #include "base/file_path.h" 25 #include "base/file_path.h"
20 #include "base/file_util.h" 26 #include "base/file_util.h"
21 #include "base/logging.h" 27 #include "base/md5.h"
22 #include "base/string_util.h" 28 #include "base/string_util.h"
23 #include "base/time.h" 29 #include "base/time.h"
24 #include "media/base/media.h" 30 #include "media/base/media.h"
25 #include "media/bench/file_protocol.h" 31 #include "media/bench/file_protocol.h"
26 #include "media/filters/ffmpeg_common.h" 32 #include "media/filters/ffmpeg_common.h"
27 #include "media/filters/ffmpeg_video_decoder.h" 33 #include "media/filters/ffmpeg_video_decoder.h"
28 34
29 namespace switches { 35 namespace switches {
30 const wchar_t kStream[] = L"stream"; 36 const wchar_t kStream[] = L"stream";
31 const wchar_t kVideoThreads[] = L"video-threads"; 37 const wchar_t kVideoThreads[] = L"video-threads";
32 const wchar_t kFast2[] = L"fast2"; 38 const wchar_t kFast2[] = L"fast2";
33 const wchar_t kSkip[] = L"skip"; 39 const wchar_t kSkip[] = L"skip";
34 const wchar_t kFlush[] = L"flush"; 40 const wchar_t kFlush[] = L"flush";
35 const wchar_t kHash[] = L"hash"; 41 const wchar_t kDjb2[] = L"djb2";
42 const wchar_t kMd5[] = L"md5";
43 const wchar_t kFrames[] = L"frames";
36 } // namespace switches 44 } // namespace switches
37 45
38 namespace { 46 namespace {
39 // DJB2 hash 47 // DJB2 hash
40 unsigned int hash_djb2(const uint8* s, 48 unsigned int DJB2Hash(const uint8* s,
41 size_t len, unsigned int hash) { 49 size_t len, unsigned int hash) {
42 while (len--) 50 if (len > 0) {
43 hash = hash * 33 + *s++; 51 do {
52 hash = hash * 33 + *s++;
53 } while (--len);
54 }
44 return hash; 55 return hash;
45 } 56 }
46 } 57 }
47 58
59 #if defined(OS_WIN)
60 // warning: disable warning about exception handler.
61 #pragma warning(disable:4509)
62
63 // Thread priorities to make benchmark more stable.
64
65 void EnterTimingSection() {
66 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
67 }
68
69 void LeaveTimingSection() {
70 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
71 }
72 #else
73 void EnterTimingSection() {
74 pthread_attr_t pta;
75 struct sched_param param;
76
77 pthread_attr_init(&pta);
78 memset(&param, 0, sizeof(param));
79 param.sched_priority = 78;
80 pthread_attr_setschedparam(&pta, &param);
81 pthread_attr_destroy(&pta);
82 }
83
84 void LeaveTimingSection() {
85 }
86 #endif
87
48 int main(int argc, const char** argv) { 88 int main(int argc, const char** argv) {
49 base::AtExitManager exit_manager; 89 base::AtExitManager exit_manager;
50 90
51 CommandLine::Init(argc, argv); 91 CommandLine::Init(argc, argv);
52 const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); 92 const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
53 93
54 std::vector<std::wstring> filenames(cmd_line->GetLooseValues()); 94 std::vector<std::wstring> filenames(cmd_line->GetLooseValues());
55 if (filenames.empty()) { 95 if (filenames.empty()) {
56 std::cerr << "Usage: media_bench [OPTIONS] FILE [DUMPFILE]\n" 96 std::cerr << "Usage: media_bench [OPTIONS] FILE [DUMPFILE]\n"
57 << " --stream=[audio|video] " 97 << " --stream=[audio|video] "
58 << "Benchmark either the audio or video stream\n" 98 << "Benchmark either the audio or video stream\n"
59 << " --video-threads=N " 99 << " --video-threads=N "
60 << "Decode video using N threads\n" 100 << "Decode video using N threads\n"
101 << " --frames=N "
102 << "Decode N frames\n"
61 << " --fast2 " 103 << " --fast2 "
62 << "Enable fast2 flag\n" 104 << "Enable fast2 flag\n"
63 << " --flush " 105 << " --flush "
64 << "Flush last frame\n" 106 << "Flush last frame\n"
65 << " --hash " 107 << " --djb2 "
66 << "Hash decoded buffers\n" 108 << "Hash decoded buffers (DJB2)\n"
109 << " --md5 "
110 << "Hash decoded buffers (MD5)\n"
67 << " --skip=[1|2|3] " 111 << " --skip=[1|2|3] "
68 << "1=loop nonref, 2=loop, 3= frame nonref\n" << std::endl; 112 << "1=loop nonref, 2=loop, 3= frame nonref\n" << std::endl;
69 return 1; 113 return 1;
70 } 114 }
71 115
72 // Initialize our media library (try loading DLLs, etc.) before continuing. 116 // Initialize our media library (try loading DLLs, etc.) before continuing.
73 // We use an empty file path as the parameter to force searching of the 117 // We use an empty file path as the parameter to force searching of the
74 // default locations for necessary DLLs and DSOs. 118 // default locations for necessary DLLs and DSOs.
75 if (media::InitializeMediaLibrary(FilePath()) == false) { 119 if (media::InitializeMediaLibrary(FilePath()) == false) {
76 std::cerr << "Unable to initialize the media library."; 120 std::cerr << "Unable to initialize the media library.";
77 return 1; 121 return 1;
78 } 122 }
79 123
80 // Retrieve command line options. 124 // Retrieve command line options.
81 std::string in_path(WideToUTF8(filenames[0])); 125 std::string in_path(WideToUTF8(filenames[0]));
82 std::string out_path; 126 std::string out_path;
83 if (filenames.size() > 1) { 127 if (filenames.size() > 1) {
84 out_path = WideToUTF8(filenames[1]); 128 out_path = WideToUTF8(filenames[1]);
85 } 129 }
86 CodecType target_codec = CODEC_TYPE_UNKNOWN; 130 CodecType target_codec = CODEC_TYPE_UNKNOWN;
87 int video_threads = 0;
88 131
89 // Determine whether to benchmark audio or video decoding. 132 // Determine whether to benchmark audio or video decoding.
90 std::wstring stream(cmd_line->GetSwitchValue(switches::kStream)); 133 std::wstring stream(cmd_line->GetSwitchValue(switches::kStream));
91 if (!stream.empty()) { 134 if (!stream.empty()) {
92 if (stream.compare(L"audio") == 0) { 135 if (stream.compare(L"audio") == 0) {
93 target_codec = CODEC_TYPE_AUDIO; 136 target_codec = CODEC_TYPE_AUDIO;
94 } else if (stream.compare(L"video") == 0) { 137 } else if (stream.compare(L"video") == 0) {
95 target_codec = CODEC_TYPE_VIDEO; 138 target_codec = CODEC_TYPE_VIDEO;
96 } else { 139 } else {
97 std::cerr << "Unknown --stream option " << stream << std::endl; 140 std::cerr << "Unknown --stream option " << stream << std::endl;
98 return 1; 141 return 1;
99 } 142 }
100 } 143 }
101 144
102 // Determine number of threads to use for video decoding (optional). 145 // Determine number of threads to use for video decoding (optional).
146 int video_threads = 0;
103 std::wstring threads(cmd_line->GetSwitchValue(switches::kVideoThreads)); 147 std::wstring threads(cmd_line->GetSwitchValue(switches::kVideoThreads));
104 if (!threads.empty() && 148 if (!threads.empty() &&
105 !StringToInt(WideToUTF16Hack(threads), &video_threads)) { 149 !StringToInt(WideToUTF16Hack(threads), &video_threads)) {
106 video_threads = 0; 150 video_threads = 0;
107 } 151 }
108 152
153 // Determine number of frames to decode (optional).
154 int max_frames = 0;
155 std::wstring frames_opt(cmd_line->GetSwitchValue(switches::kFrames));
156 if (!frames_opt.empty() &&
157 !StringToInt(WideToUTF16Hack(frames_opt), &max_frames)) {
158 max_frames = 0;
159 }
160
109 bool fast2 = false; 161 bool fast2 = false;
110 if (cmd_line->HasSwitch(switches::kFast2)) { 162 if (cmd_line->HasSwitch(switches::kFast2)) {
111 fast2 = true; 163 fast2 = true;
112 } 164 }
113 165
114 bool flush = false; 166 bool flush = false;
115 if (cmd_line->HasSwitch(switches::kFlush)) { 167 if (cmd_line->HasSwitch(switches::kFlush)) {
116 flush = true; 168 flush = true;
117 } 169 }
118 170
119 unsigned int hash_value = 5381u; // Seed for DJB2. 171 unsigned int hash_value = 5381u; // Seed for DJB2.
120 bool hash = false; 172 bool hash_djb2 = false;
121 if (cmd_line->HasSwitch(switches::kHash)) { 173 if (cmd_line->HasSwitch(switches::kDjb2)) {
122 hash = true; 174 hash_djb2 = true;
175 }
176
177 MD5Context ctx; // intermediate MD5 data: do not use
178 MD5Init(&ctx);
179 bool hash_md5 = false;
180 if (cmd_line->HasSwitch(switches::kMd5)) {
181 hash_md5 = true;
123 } 182 }
124 183
125 int skip = 0; 184 int skip = 0;
126 if (cmd_line->HasSwitch(switches::kSkip)) { 185 if (cmd_line->HasSwitch(switches::kSkip)) {
127 std::wstring skip_opt(cmd_line->GetSwitchValue(switches::kSkip)); 186 std::wstring skip_opt(cmd_line->GetSwitchValue(switches::kSkip));
128 if (!StringToInt(WideToUTF16Hack(skip_opt), &skip)) { 187 if (!StringToInt(WideToUTF16Hack(skip_opt), &skip)) {
129 skip = 0; 188 skip = 0;
130 } 189 }
131 } 190 }
132 191
192 std::ostream* log_out = &std::cout;
193 #if defined(OS_WIN)
194 // Catch exceptions so this tool can be used in automated testing.
195 __try {
196 #endif
197
133 // Register FFmpeg and attempt to open file. 198 // Register FFmpeg and attempt to open file.
134 avcodec_init(); 199 avcodec_init();
135 av_register_all(); 200 av_register_all();
136 av_register_protocol(&kFFmpegFileProtocol); 201 av_register_protocol(&kFFmpegFileProtocol);
137 AVFormatContext* format_context = NULL; 202 AVFormatContext* format_context = NULL;
138 if (av_open_input_file(&format_context, in_path.c_str(), NULL, 0, NULL) < 0) { 203 if (av_open_input_file(&format_context, in_path.c_str(), NULL, 0, NULL) < 0) {
139 std::cerr << "Could not open " << in_path << std::endl; 204 std::cerr << "Error: Could not open input for "
205 << in_path << std::endl;
140 return 1; 206 return 1;
141 } 207 }
142 208
143 // Open output file. 209 // Open output file.
144 FILE *output = NULL; 210 FILE *output = NULL;
145 if (!out_path.empty()) { 211 if (!out_path.empty()) {
146 output = file_util::OpenFile(out_path.c_str(), "wb"); 212 // TODO(fbarchard): Add pipe:1 for piping to stderr.
213 if (!strncmp(out_path.c_str(), "pipe:", 5) ||
214 !strcmp(out_path.c_str(), "-")) {
215 output = stdout;
216 log_out = &std::cerr;
217 #if defined(OS_WIN)
218 _setmode(_fileno(stdout),_O_BINARY);
219 #endif
220 } else {
221 output = file_util::OpenFile(out_path.c_str(), "wb");
222 }
147 if (!output) { 223 if (!output) {
148 LOG(ERROR) << "could not open output"; 224 std::cerr << "Error: Could not open output "
225 << out_path << std::endl;
149 return 1; 226 return 1;
150 } 227 }
151 } 228 }
152 229
153 // Parse a little bit of the stream to fill out the format context. 230 // Parse a little bit of the stream to fill out the format context.
154 if (av_find_stream_info(format_context) < 0) { 231 if (av_find_stream_info(format_context) < 0) {
155 std::cerr << "Could not find stream info for " << in_path << std::endl; 232 std::cerr << "Error: Could not find stream info for "
233 << in_path << std::endl;
156 return 1; 234 return 1;
157 } 235 }
158 236
159 // Find our target stream. 237 // Find our target stream.
160 int target_stream = -1; 238 int target_stream = -1;
161 for (size_t i = 0; i < format_context->nb_streams; ++i) { 239 for (size_t i = 0; i < format_context->nb_streams; ++i) {
162 AVCodecContext* codec_context = format_context->streams[i]->codec; 240 AVCodecContext* codec_context = format_context->streams[i]->codec;
163 AVCodec* codec = avcodec_find_decoder(codec_context->codec_id); 241 AVCodec* codec = avcodec_find_decoder(codec_context->codec_id);
164 242
165 // See if we found our target codec. 243 // See if we found our target codec.
166 if (codec_context->codec_type == target_codec && target_stream < 0) { 244 if (codec_context->codec_type == target_codec && target_stream < 0) {
167 std::cout << "* "; 245 *log_out << "* ";
168 target_stream = i; 246 target_stream = i;
169 } else { 247 } else {
170 std::cout << " "; 248 *log_out << " ";
171 } 249 }
172 250
173 if (codec_context->codec_type == CODEC_TYPE_UNKNOWN) { 251 if (!codec || (codec_context->codec_type == CODEC_TYPE_UNKNOWN)) {
174 std::cout << "Stream #" << i << ": Unknown" << std::endl; 252 *log_out << "Stream #" << i << ": Unknown" << std::endl;
175 } else { 253 } else {
176 // Print out stream information 254 // Print out stream information
177 std::cout << "Stream #" << i << ": " << codec->name << " (" 255 *log_out << "Stream #" << i << ": " << codec->name << " ("
178 << codec->long_name << ")" << std::endl; 256 << codec->long_name << ")" << std::endl;
179 } 257 }
180 } 258 }
181 259
182 // Only continue if we found our target stream. 260 // Only continue if we found our target stream.
183 if (target_stream < 0) { 261 if (target_stream < 0) {
262 std::cerr << "Error: Could not find target stream "
263 << target_stream << " for " << in_path << std::endl;
184 return 1; 264 return 1;
185 } 265 }
186 266
187 // Prepare FFmpeg structures. 267 // Prepare FFmpeg structures.
188 AVPacket packet; 268 AVPacket packet;
189 AVCodecContext* codec_context = format_context->streams[target_stream]->codec; 269 AVCodecContext* codec_context = format_context->streams[target_stream]->codec;
190 AVCodec* codec = avcodec_find_decoder(codec_context->codec_id); 270 AVCodec* codec = avcodec_find_decoder(codec_context->codec_id);
191 271
272 // Only continue if we found our codec.
273 if (!codec) {
274 std::cerr << "Error: Could not find codec for "
275 << in_path << std::endl;
276 return 1;
277 }
278
192 if (skip == 1) { 279 if (skip == 1) {
193 codec_context->skip_loop_filter = AVDISCARD_NONREF; 280 codec_context->skip_loop_filter = AVDISCARD_NONREF;
194 } else if (skip == 2) { 281 } else if (skip == 2) {
195 codec_context->skip_loop_filter = AVDISCARD_ALL; 282 codec_context->skip_loop_filter = AVDISCARD_ALL;
196 } else if (skip == 3) { 283 } else if (skip == 3) {
197 codec_context->skip_loop_filter = AVDISCARD_ALL; 284 codec_context->skip_loop_filter = AVDISCARD_ALL;
198 codec_context->skip_frame = AVDISCARD_NONREF; 285 codec_context->skip_frame = AVDISCARD_NONREF;
199 } 286 }
200 if (fast2) { 287 if (fast2) {
201 codec_context->flags2 |= CODEC_FLAG2_FAST; 288 codec_context->flags2 |= CODEC_FLAG2_FAST;
202 } 289 }
203 290
204 // Initialize threaded decode. 291 // Initialize threaded decode.
205 if (target_codec == CODEC_TYPE_VIDEO && video_threads > 0) { 292 if (target_codec == CODEC_TYPE_VIDEO && video_threads > 0) {
206 if (avcodec_thread_init(codec_context, video_threads) < 0) { 293 if (avcodec_thread_init(codec_context, video_threads) < 0) {
207 std::cerr << "WARNING: Could not initialize threading!\n" 294 std::cerr << "Warning: Could not initialize threading!\n"
208 << "Did you build with pthread/w32thread support?" << std::endl; 295 << "Did you build with pthread/w32thread support?" << std::endl;
209 } 296 }
210 } 297 }
211 298
212 // Initialize our codec. 299 // Initialize our codec.
213 if (avcodec_open(codec_context, codec) < 0) { 300 if (avcodec_open(codec_context, codec) < 0) {
214 std::cerr << "Could not open codec " << codec_context->codec->name 301 std::cerr << "Error: Could not open codec "
215 << std::endl; 302 << codec_context->codec->name << " for "
303 << in_path << std::endl;
216 return 1; 304 return 1;
217 } 305 }
218 306
219 // Buffer used for audio decoding. 307 // Buffer used for audio decoding.
220 int16* samples = 308 int16* samples =
221 reinterpret_cast<int16*>(av_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE)); 309 reinterpret_cast<int16*>(av_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE));
222 310
223 // Buffer used for video decoding. 311 // Buffer used for video decoding.
224 AVFrame* frame = avcodec_alloc_frame(); 312 AVFrame* frame = avcodec_alloc_frame();
225 if (!frame) { 313 if (!frame) {
226 std::cerr << "Could not allocate an AVFrame" << std::endl; 314 std::cerr << "Error: avcodec_alloc_frame for "
315 << in_path << std::endl;
227 return 1; 316 return 1;
228 } 317 }
229 318
230 // Stats collector. 319 // Stats collector.
320 EnterTimingSection();
231 std::vector<double> decode_times; 321 std::vector<double> decode_times;
232 decode_times.reserve(4096); 322 decode_times.reserve(4096);
233 // Parse through the entire stream until we hit EOF. 323 // Parse through the entire stream until we hit EOF.
234 base::TimeTicks start = base::TimeTicks::HighResNow(); 324 base::TimeTicks start = base::TimeTicks::HighResNow();
235 size_t frames = 0; 325 int frames = 0;
236 int read_result = 0; 326 int read_result = 0;
237 do { 327 do {
238 read_result = av_read_frame(format_context, &packet); 328 read_result = av_read_frame(format_context, &packet);
239 329
240 if (read_result < 0) { 330 if (read_result < 0) {
241 if (flush) { 331 if (flush) {
242 packet.stream_index = target_stream; 332 packet.stream_index = target_stream;
243 packet.size = 0; 333 packet.size = 0;
244 } else { 334 } else {
245 break; 335 break;
246 } 336 }
247 } 337 }
248 338
249 // Only decode packets from our target stream. 339 // Only decode packets from our target stream.
250 if (packet.stream_index == target_stream) { 340 if (packet.stream_index == target_stream) {
251 int result = -1; 341 int result = -1;
252 base::TimeTicks decode_start = base::TimeTicks::HighResNow();
253 if (target_codec == CODEC_TYPE_AUDIO) { 342 if (target_codec == CODEC_TYPE_AUDIO) {
254 int size_out = AVCODEC_MAX_AUDIO_FRAME_SIZE; 343 int size_out = AVCODEC_MAX_AUDIO_FRAME_SIZE;
344
345 base::TimeTicks decode_start = base::TimeTicks::HighResNow();
255 result = avcodec_decode_audio3(codec_context, samples, &size_out, 346 result = avcodec_decode_audio3(codec_context, samples, &size_out,
256 &packet); 347 &packet);
348 base::TimeDelta delta = base::TimeTicks::HighResNow() - decode_start;
349
257 if (size_out) { 350 if (size_out) {
351 decode_times.push_back(delta.InMillisecondsF());
258 ++frames; 352 ++frames;
259 read_result = 0; // Force continuation. 353 read_result = 0; // Force continuation.
260 354
261 if (output) { 355 if (output) {
262 if (fwrite(samples, 1, size_out, output) != 356 if (fwrite(samples, 1, size_out, output) !=
263 static_cast<size_t>(size_out)) { 357 static_cast<size_t>(size_out)) {
264 std::cerr << "could not write data after " << size_out; 358 std::cerr << "Error: Could not write "
359 << size_out << " bytes for " << in_path << std::endl;
265 return 1; 360 return 1;
266 } 361 }
267 } 362 }
268 if (hash) { 363 if (hash_djb2) {
269 hash_value = hash_djb2(reinterpret_cast<const uint8*>(samples), 364 hash_value = DJB2Hash(reinterpret_cast<const uint8*>(samples),
270 size_out, hash_value); 365 size_out, hash_value);
366 }
367 if (hash_md5) {
368 MD5Update(&ctx, reinterpret_cast<const uint8*>(samples),
369 size_out);
271 } 370 }
272 } 371 }
273 } else if (target_codec == CODEC_TYPE_VIDEO) { 372 } else if (target_codec == CODEC_TYPE_VIDEO) {
274 int got_picture = 0; 373 int got_picture = 0;
374
375 base::TimeTicks decode_start = base::TimeTicks::HighResNow();
275 result = avcodec_decode_video2(codec_context, frame, &got_picture, 376 result = avcodec_decode_video2(codec_context, frame, &got_picture,
276 &packet); 377 &packet);
378 base::TimeDelta delta = base::TimeTicks::HighResNow() - decode_start;
379
277 if (got_picture) { 380 if (got_picture) {
381 decode_times.push_back(delta.InMillisecondsF());
278 ++frames; 382 ++frames;
279 read_result = 0; // Force continuation. 383 read_result = 0; // Force continuation.
280 384
281 if (output || hash) { 385 for (int plane = 0; plane < 3; ++plane) {
282 for (int plane = 0; plane < 3; ++plane) { 386 const uint8* source = frame->data[plane];
283 const uint8* source = frame->data[plane]; 387 const size_t source_stride = frame->linesize[plane];
284 const size_t source_stride = frame->linesize[plane]; 388 size_t bytes_per_line = codec_context->width;
285 size_t bytes_per_line = codec_context->width; 389 size_t copy_lines = codec_context->height;
286 size_t copy_lines = codec_context->height; 390 if (plane != 0) {
287 if (plane != 0) { 391 switch (codec_context->pix_fmt) {
288 switch (codec_context->pix_fmt) { 392 case PIX_FMT_YUV420P:
289 case PIX_FMT_YUV420P: 393 case PIX_FMT_YUVJ420P:
290 case PIX_FMT_YUVJ420P: 394 bytes_per_line /= 2;
291 bytes_per_line /= 2; 395 copy_lines = (copy_lines + 1) / 2;
292 copy_lines = (copy_lines + 1) / 2; 396 break;
293 break; 397 case PIX_FMT_YUV422P:
294 case PIX_FMT_YUV422P: 398 case PIX_FMT_YUVJ422P:
295 case PIX_FMT_YUVJ422P: 399 bytes_per_line /= 2;
296 bytes_per_line /= 2; 400 break;
297 break; 401 case PIX_FMT_YUV444P:
298 case PIX_FMT_YUV444P: 402 case PIX_FMT_YUVJ444P:
299 case PIX_FMT_YUVJ444P: 403 break;
300 break; 404 default:
301 default: 405 std::cerr << "Error: Unknown video format "
302 std::cerr << "unknown video format: " 406 << codec_context->pix_fmt;
303 << codec_context->pix_fmt; 407 return 1;
304 return 1; 408 }
409 }
410 if (output) {
411 for (size_t i = 0; i < copy_lines; ++i) {
412 if (fwrite(source, 1, bytes_per_line, output) !=
413 bytes_per_line) {
414 std::cerr << "Error: Could not write data after "
415 << copy_lines << " lines for "
416 << in_path << std::endl;
417 return 1;
305 } 418 }
419 source += source_stride;
306 } 420 }
307 if (output) { 421 }
308 for (size_t i = 0; i < copy_lines; ++i) { 422 if (hash_djb2) {
309 if (fwrite(source, 1, bytes_per_line, output) != 423 for (size_t i = 0; i < copy_lines; ++i) {
310 bytes_per_line) { 424 hash_value = DJB2Hash(source, bytes_per_line, hash_value);
311 std::cerr << "could not write data after " 425 source += source_stride;
312 << bytes_per_line;
313 return 1;
314 }
315 source += source_stride;
316 }
317 } 426 }
318 if (hash) { 427 }
319 for (size_t i = 0; i < copy_lines; ++i) { 428 if (hash_md5) {
320 hash_value = hash_djb2(source, bytes_per_line, hash_value); 429 for (size_t i = 0; i < copy_lines; ++i) {
321 source += source_stride; 430 MD5Update(&ctx, reinterpret_cast<const uint8*>(source),
322 } 431 bytes_per_line);
432 source += source_stride;
323 } 433 }
324 } 434 }
325 } 435 }
326 } 436 }
327 } else { 437 } else {
328 NOTREACHED(); 438 NOTREACHED();
329 } 439 }
330 base::TimeDelta delta = base::TimeTicks::HighResNow() - decode_start;
331
332 decode_times.push_back(delta.InMillisecondsF());
333 440
334 // Make sure our decoding went OK. 441 // Make sure our decoding went OK.
335 if (result < 0) { 442 if (result < 0) {
336 std::cerr << "Error while decoding" << std::endl; 443 std::cerr << "Error: avcodec_decode returned "
444 << result << " for " << in_path << std::endl;
337 return 1; 445 return 1;
338 } 446 }
339 } 447 }
340 // Free our packet. 448 // Free our packet.
341 av_free_packet(&packet); 449 av_free_packet(&packet);
450
451 if (max_frames && (frames >= max_frames))
452 break;
342 } while (read_result >= 0); 453 } while (read_result >= 0);
343 base::TimeDelta total = base::TimeTicks::HighResNow() - start; 454 base::TimeDelta total = base::TimeTicks::HighResNow() - start;
344 455 LeaveTimingSection();
345 if (output) 456 if (output)
346 file_util::CloseFile(output); 457 file_util::CloseFile(output);
347 458
348 // Calculate the sum of times. Note that some of these may be zero. 459 // Calculate the sum of times. Note that some of these may be zero.
349 double sum = 0; 460 double sum = 0;
350 for (size_t i = 0; i < decode_times.size(); ++i) { 461 for (size_t i = 0; i < decode_times.size(); ++i) {
351 sum += decode_times[i]; 462 sum += decode_times[i];
352 } 463 }
353 464
354 // Print our results. 465 // Print our results.
355 std::cout.setf(std::ios::fixed); 466 log_out->setf(std::ios::fixed);
356 std::cout.precision(2); 467 log_out->precision(2);
357 std::cout << std::endl; 468 *log_out << std::endl;
358 std::cout << " Frames:" << std::setw(10) << frames 469 *log_out << " Frames:" << std::setw(11) << frames
359 << std::endl; 470 << std::endl;
360 std::cout << " Total:" << std::setw(10) << total.InMillisecondsF() 471 *log_out << " Total:" << std::setw(11) << total.InMillisecondsF()
361 << " ms" << std::endl; 472 << " ms" << std::endl;
362 std::cout << " Summation:" << std::setw(10) << sum 473 *log_out << " Summation:" << std::setw(11) << sum
363 << " ms" << std::endl; 474 << " ms" << std::endl;
364 if (hash) {
365 std::cout << " Hash:" << std::setw(10) << hash_value
366 << std::endl;
367 }
368 475
369 if (frames > 0u) { 476 if (frames > 0) {
370 // Calculate the average time per frame. 477 // Calculate the average time per frame.
371 double average = sum / frames; 478 double average = sum / frames;
372 479
373 // Calculate the sum of the squared differences. 480 // Calculate the sum of the squared differences.
374 // Standard deviation will only be accurate if no threads are used. 481 // Standard deviation will only be accurate if no threads are used.
375 // TODO(fbarchard): Rethink standard deviation calculation. 482 // TODO(fbarchard): Rethink standard deviation calculation.
376 double squared_sum = 0; 483 double squared_sum = 0;
377 for (size_t i = 0; i < frames; ++i) { 484 for (int i = 0; i < frames; ++i) {
378 double difference = decode_times[i] - average; 485 double difference = decode_times[i] - average;
379 squared_sum += difference * difference; 486 squared_sum += difference * difference;
380 } 487 }
381 488
382 // Calculate the standard deviation (jitter). 489 // Calculate the standard deviation (jitter).
383 double stddev = sqrt(squared_sum / frames); 490 double stddev = sqrt(squared_sum / frames);
384 491
385 std::cout << " Average:" << std::setw(10) << average 492 *log_out << " Average:" << std::setw(11) << average
386 << " ms" << std::endl; 493 << " ms" << std::endl;
387 std::cout << " StdDev:" << std::setw(10) << stddev 494 *log_out << " StdDev:" << std::setw(11) << stddev
388 << " ms" << std::endl; 495 << " ms" << std::endl;
389 } 496 }
497 if (hash_djb2) {
498 *log_out << " DJB2:" << std::setw(11) << hash_value
499 << " " << in_path << std::endl;
500 }
501 if (hash_md5) {
502 MD5Digest digest; // The result of the computation.
503 MD5Final(&digest, &ctx);
504 *log_out << " MD5: " << MD5DigestToBase16(digest)
505 << " " << in_path << std::endl;
506 }
507 #if defined(OS_WIN)
508 } __except(EXCEPTION_EXECUTE_HANDLER) {
509 *log_out << " Exception:" << std::setw(11) << GetExceptionCode()
510 << " " << in_path << std::endl;
511 return 1;
512 }
513 #endif
390 return 0; 514 return 0;
391 } 515 }
OLDNEW
« no previous file with comments | « no previous file | media/bench/file_protocol.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698