OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 // The bulk of this file is support code; sorry about that. Here's an overview | 5 // The bulk of this file is support code; sorry about that. Here's an overview |
6 // to hopefully help readers of this code: | 6 // to hopefully help readers of this code: |
7 // - RenderingHelper is charged with interacting with X11/{EGL/GLES2,GLX/GL} or | 7 // - RenderingHelper is charged with interacting with X11/{EGL/GLES2,GLX/GL} or |
8 // Win/EGL. | 8 // Win/EGL. |
9 // - ClientState is an enum for the state of the decode client used by the test. | 9 // - ClientState is an enum for the state of the decode client used by the test. |
10 // - ClientStateNotification is a barrier abstraction that allows the test code | 10 // - ClientStateNotification is a barrier abstraction that allows the test code |
(...skipping 12 matching lines...) Expand all Loading... | |
23 // gtest uses as struct names (inside a namespace). This means that | 23 // gtest uses as struct names (inside a namespace). This means that |
24 // #include'ing gtest after anything that pulls in X.h fails to compile. | 24 // #include'ing gtest after anything that pulls in X.h fails to compile. |
25 // This is http://code.google.com/p/googletest/issues/detail?id=371 | 25 // This is http://code.google.com/p/googletest/issues/detail?id=371 |
26 #include "testing/gtest/include/gtest/gtest.h" | 26 #include "testing/gtest/include/gtest/gtest.h" |
27 | 27 |
28 #include "base/at_exit.h" | 28 #include "base/at_exit.h" |
29 #include "base/bind.h" | 29 #include "base/bind.h" |
30 #include "base/command_line.h" | 30 #include "base/command_line.h" |
31 #include "base/file_util.h" | 31 #include "base/file_util.h" |
32 #include "base/format_macros.h" | 32 #include "base/format_macros.h" |
33 #include "base/md5.h" | 33 #include "base/md5.h" |
Ami GONE FROM CHROMIUM
2013/08/02 00:33:22
Please don't rebase while there are outstanding co
Owen Lin
2013/08/02 05:38:19
I see. Sorry for the inconvenience.
| |
34 #include "base/platform_file.h" | 34 #include "base/platform_file.h" |
35 #include "base/process_util.h" | 35 #include "base/process_util.h" |
36 #include "base/stl_util.h" | 36 #include "base/stl_util.h" |
37 #include "base/strings/string_number_conversions.h" | 37 #include "base/strings/string_number_conversions.h" |
38 #include "base/strings/string_split.h" | 38 #include "base/strings/string_split.h" |
39 #include "base/strings/stringize_macros.h" | 39 #include "base/strings/stringize_macros.h" |
40 #include "base/strings/stringprintf.h" | 40 #include "base/strings/stringprintf.h" |
41 #include "base/strings/utf_string_conversions.h" | 41 #include "base/strings/utf_string_conversions.h" |
42 #include "base/synchronization/condition_variable.h" | 42 #include "base/synchronization/condition_variable.h" |
43 #include "base/synchronization/lock.h" | 43 #include "base/synchronization/lock.h" |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
83 // - |profile| is the media::VideoCodecProfile set during Initialization. | 83 // - |profile| is the media::VideoCodecProfile set during Initialization. |
84 // An empty value for a numeric field means "ignore". | 84 // An empty value for a numeric field means "ignore". |
85 const base::FilePath::CharType* test_video_data = | 85 const base::FilePath::CharType* test_video_data = |
86 // FILE_PATH_LITERAL("test-25fps.vp8:320:240:250:250:50:175:11"); | 86 // FILE_PATH_LITERAL("test-25fps.vp8:320:240:250:250:50:175:11"); |
87 FILE_PATH_LITERAL("test-25fps.h264:320:240:250:258:50:175:1"); | 87 FILE_PATH_LITERAL("test-25fps.h264:320:240:250:258:50:175:1"); |
88 | 88 |
89 // The path of the frame delivery time log. We can enable the log and specify | 89 // The path of the frame delivery time log. We can enable the log and specify |
90 // the filename by the "--frame_delivery_log" switch. | 90 // the filename by the "--frame_delivery_log" switch. |
91 const base::FilePath::CharType* frame_delivery_log = NULL; | 91 const base::FilePath::CharType* frame_delivery_log = NULL; |
92 | 92 |
93 // The value is set by the switch "--rendering_fps". | |
94 double rendering_fps = 0; | |
Ami GONE FROM CHROMIUM
2013/08/02 00:33:22
global vars should be prefixed with g_ to avoid co
Owen Lin
2013/08/02 05:38:19
Done.
| |
95 | |
96 // Disable rendering, the value is set by the switch "--disable_rendering". | |
97 bool disable_rendering = false; | |
98 | |
93 // Magic constants for differentiating the reasons for NotifyResetDone being | 99 // Magic constants for differentiating the reasons for NotifyResetDone being |
94 // called. | 100 // called. |
95 enum ResetPoint { | 101 enum ResetPoint { |
96 MID_STREAM_RESET = -2, | 102 MID_STREAM_RESET = -2, |
97 END_OF_STREAM_RESET = -1 | 103 END_OF_STREAM_RESET = -1 |
98 }; | 104 }; |
99 | 105 |
100 const int kMaxResetAfterFrameNum = 100; | 106 const int kMaxResetAfterFrameNum = 100; |
101 const int kMaxFramesToDelayReuse = 64; | 107 const int kMaxFramesToDelayReuse = 64; |
102 const int kReuseDelayMs = 1000; | 108 const base::TimeDelta kReuseDelay = base::TimeDelta::FromSeconds(1); |
109 const base::TimeDelta kFrameDelayTolerance = | |
110 base::TimeDelta::FromMilliseconds(1); | |
103 | 111 |
104 struct TestVideoFile { | 112 struct TestVideoFile { |
105 explicit TestVideoFile(base::FilePath::StringType file_name) | 113 explicit TestVideoFile(base::FilePath::StringType file_name) |
106 : file_name(file_name), | 114 : file_name(file_name), |
107 width(-1), | 115 width(-1), |
108 height(-1), | 116 height(-1), |
109 num_frames(-1), | 117 num_frames(-1), |
110 num_fragments(-1), | 118 num_fragments(-1), |
111 min_fps_render(-1), | 119 min_fps_render(-1), |
112 min_fps_no_render(-1), | 120 min_fps_no_render(-1), |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
213 } | 221 } |
214 | 222 |
215 // State of the GLRenderingVDAClient below. Order matters here as the test | 223 // State of the GLRenderingVDAClient below. Order matters here as the test |
216 // makes assumptions about it. | 224 // makes assumptions about it. |
217 enum ClientState { | 225 enum ClientState { |
218 CS_CREATED = 0, | 226 CS_CREATED = 0, |
219 CS_DECODER_SET = 1, | 227 CS_DECODER_SET = 1, |
220 CS_INITIALIZED = 2, | 228 CS_INITIALIZED = 2, |
221 CS_FLUSHING = 3, | 229 CS_FLUSHING = 3, |
222 CS_FLUSHED = 4, | 230 CS_FLUSHED = 4, |
223 CS_DONE = 5, | 231 CS_RESETTING = 5, |
224 CS_RESETTING = 6, | 232 CS_RESET = 6, |
225 CS_RESET = 7, | 233 CS_ERROR = 7, |
226 CS_ERROR = 8, | 234 CS_DESTROYED = 8, |
227 CS_DESTROYED = 9, | |
228 CS_MAX, // Must be last entry. | 235 CS_MAX, // Must be last entry. |
229 }; | 236 }; |
230 | 237 |
231 // Helper class allowing one thread to wait on a notification from another. | 238 // Helper class allowing one thread to wait on a notification from another. |
232 // If notifications come in faster than they are Wait()'d for, they are | 239 // If notifications come in faster than they are Wait()'d for, they are |
233 // accumulated (so exactly as many Wait() calls will unblock as Notify() calls | 240 // accumulated (so exactly as many Wait() calls will unblock as Notify() calls |
234 // were made, regardless of order). | 241 // were made, regardless of order). |
235 class ClientStateNotification { | 242 class ClientStateNotification { |
236 public: | 243 public: |
237 ClientStateNotification(); | 244 ClientStateNotification(); |
(...skipping 21 matching lines...) Expand all Loading... | |
259 | 266 |
260 ClientState ClientStateNotification::Wait() { | 267 ClientState ClientStateNotification::Wait() { |
261 base::AutoLock auto_lock(lock_); | 268 base::AutoLock auto_lock(lock_); |
262 while (pending_states_for_notification_.empty()) | 269 while (pending_states_for_notification_.empty()) |
263 cv_.Wait(); | 270 cv_.Wait(); |
264 ClientState ret = pending_states_for_notification_.front(); | 271 ClientState ret = pending_states_for_notification_.front(); |
265 pending_states_for_notification_.pop(); | 272 pending_states_for_notification_.pop(); |
266 return ret; | 273 return ret; |
267 } | 274 } |
268 | 275 |
276 // A wrapper client that throttles the PictureReady callbacks to a given rate. | |
277 // It may drops or queues frame to deliver them on time. | |
278 class ThrottlingVDAClient : public VideoDecodeAccelerator::Client, | |
279 public base::SupportsWeakPtr<ThrottlingVDAClient> { | |
280 public: | |
281 // Callback invoked whan the picture is dropped and should be reused for | |
282 // the decoder again. | |
283 typedef base::Callback<void(int32 picture_buffer_id)> ReusePictureCB; | |
284 | |
285 ThrottlingVDAClient(VideoDecodeAccelerator::Client* client, | |
286 double fps, | |
287 ReusePictureCB reuse_picture_cb); | |
288 virtual ~ThrottlingVDAClient(); | |
289 | |
290 // VideoDecodeAccelerator::Client implementation | |
291 virtual void ProvidePictureBuffers(uint32 requested_num_of_buffers, | |
292 const gfx::Size& dimensions, | |
293 uint32 texture_target) OVERRIDE; | |
294 virtual void DismissPictureBuffer(int32 picture_buffer_id) OVERRIDE; | |
295 virtual void PictureReady(const media::Picture& picture) OVERRIDE; | |
296 virtual void NotifyInitializeDone() OVERRIDE; | |
297 virtual void NotifyEndOfBitstreamBuffer(int32 bitstream_buffer_id) OVERRIDE; | |
298 virtual void NotifyFlushDone() OVERRIDE; | |
299 virtual void NotifyResetDone() OVERRIDE; | |
300 virtual void NotifyError(VideoDecodeAccelerator::Error error) OVERRIDE; | |
301 | |
302 int num_decoded_frames() { return num_decoded_frames_; } | |
303 | |
304 private: | |
305 | |
306 void CallClientPictureReady(int version); | |
307 | |
308 VideoDecodeAccelerator::Client* client_; | |
309 ReusePictureCB reuse_picture_cb_; | |
310 base::TimeTicks next_frame_delivered_time_; | |
311 base::TimeDelta frame_duration_; | |
312 | |
313 int num_decoded_frames_; | |
314 int stream_version_; | |
315 std::deque<media::Picture> pending_pictures_; | |
316 | |
317 DISALLOW_IMPLICIT_CONSTRUCTORS(ThrottlingVDAClient); | |
318 }; | |
319 | |
320 ThrottlingVDAClient::ThrottlingVDAClient( | |
321 VideoDecodeAccelerator::Client* client, | |
322 double fps, | |
323 ReusePictureCB reuse_picture_cb) | |
324 : client_(client), | |
325 reuse_picture_cb_(reuse_picture_cb), | |
326 num_decoded_frames_(0), | |
327 stream_version_(0) { | |
328 CHECK(client_); | |
329 CHECK_GT(fps, 0); | |
330 frame_duration_ = base::TimeDelta::FromSeconds(1) / fps; | |
331 } | |
332 | |
333 ThrottlingVDAClient::~ThrottlingVDAClient() {} | |
334 | |
335 void ThrottlingVDAClient::ProvidePictureBuffers( | |
336 uint32 requested_num_of_buffers, | |
337 const gfx::Size& dimensions, | |
338 uint32 texture_target) { | |
339 client_->ProvidePictureBuffers(requested_num_of_buffers, | |
340 dimensions, | |
341 texture_target); | |
342 } | |
343 | |
344 void ThrottlingVDAClient::DismissPictureBuffer(int32 picture_buffer_id) { | |
345 client_->DismissPictureBuffer(picture_buffer_id); | |
346 } | |
347 | |
348 void ThrottlingVDAClient::PictureReady(const media::Picture& picture) { | |
349 ++num_decoded_frames_; | |
350 | |
351 if (pending_pictures_.empty()) { | |
352 base::TimeDelta delay = next_frame_delivered_time_.is_null() | |
353 ? base::TimeDelta() | |
354 : next_frame_delivered_time_ - base::TimeTicks::Now(); | |
355 base::MessageLoop::current()->PostDelayedTask( | |
356 FROM_HERE, | |
357 base::Bind(&ThrottlingVDAClient::CallClientPictureReady, | |
358 AsWeakPtr(), | |
359 stream_version_), | |
360 delay); | |
361 } | |
362 pending_pictures_.push_back(picture); | |
363 } | |
364 | |
365 void ThrottlingVDAClient::CallClientPictureReady(int version) { | |
366 // Just return if we have reset the decoder | |
367 if (version != stream_version_) | |
368 return; | |
369 | |
370 base::TimeTicks now = base::TimeTicks::Now(); | |
371 | |
372 if (next_frame_delivered_time_.is_null()) | |
373 next_frame_delivered_time_ = now; | |
374 | |
375 if (next_frame_delivered_time_ + kFrameDelayTolerance < now) { | |
Ami GONE FROM CHROMIUM
2013/08/02 00:33:22
Shouldn't kFrameDelayTolerance always be equal to
Owen Lin
2013/08/02 05:38:19
Good point. Thanks.
| |
376 // Too late, drop the frame | |
377 reuse_picture_cb_.Run(pending_pictures_.front().picture_buffer_id()); | |
378 } else { | |
379 client_->PictureReady(pending_pictures_.front()); | |
380 } | |
381 | |
382 pending_pictures_.pop_front(); | |
383 next_frame_delivered_time_ += frame_duration_; | |
384 if (!pending_pictures_.empty()) { | |
385 base::MessageLoop::current()->PostDelayedTask( | |
386 FROM_HERE, | |
387 base::Bind(&ThrottlingVDAClient::CallClientPictureReady, | |
388 AsWeakPtr(), | |
389 stream_version_), | |
390 next_frame_delivered_time_ - base::TimeTicks::Now()); | |
391 } | |
392 } | |
393 | |
394 void ThrottlingVDAClient::NotifyInitializeDone() { | |
395 client_->NotifyInitializeDone(); | |
396 } | |
397 | |
398 void ThrottlingVDAClient::NotifyEndOfBitstreamBuffer( | |
399 int32 bitstream_buffer_id) { | |
400 client_->NotifyEndOfBitstreamBuffer(bitstream_buffer_id); | |
401 } | |
402 | |
403 void ThrottlingVDAClient::NotifyFlushDone() { | |
404 if (!pending_pictures_.empty()) { | |
405 base::MessageLoop::current()->PostDelayedTask( | |
406 FROM_HERE, | |
407 base::Bind(&ThrottlingVDAClient::NotifyFlushDone, | |
408 base::Unretained(this)), | |
409 next_frame_delivered_time_ - base::TimeTicks::Now()); | |
410 return; | |
411 } | |
412 client_->NotifyFlushDone(); | |
413 } | |
414 | |
415 void ThrottlingVDAClient::NotifyResetDone() { | |
416 ++stream_version_; | |
417 while (!pending_pictures_.empty()) { | |
418 reuse_picture_cb_.Run(pending_pictures_.front().picture_buffer_id()); | |
Ami GONE FROM CHROMIUM
2013/08/02 00:33:22
indent is off here and elsewhere.
why not give [gi
Owen Lin
2013/08/02 05:38:19
Done. I tried "git cl format" but it changed the c
| |
419 pending_pictures_.pop_front(); | |
420 } | |
421 next_frame_delivered_time_ = base::TimeTicks(); | |
422 client_->NotifyResetDone(); | |
423 } | |
424 | |
425 void ThrottlingVDAClient::NotifyError(VideoDecodeAccelerator::Error error) { | |
426 client_->NotifyError(error); | |
427 } | |
428 | |
269 // Client that can accept callbacks from a VideoDecodeAccelerator and is used by | 429 // Client that can accept callbacks from a VideoDecodeAccelerator and is used by |
270 // the TESTs below. | 430 // the TESTs below. |
271 class GLRenderingVDAClient : public VideoDecodeAccelerator::Client { | 431 class GLRenderingVDAClient : public VideoDecodeAccelerator::Client { |
272 public: | 432 public: |
273 // Doesn't take ownership of |rendering_helper| or |note|, which must outlive | 433 // Doesn't take ownership of |rendering_helper| or |note|, which must outlive |
274 // |*this|. | 434 // |*this|. |
275 // |num_fragments_per_decode| counts NALUs for h264 and frames for VP8. | 435 // |num_fragments_per_decode| counts NALUs for h264 and frames for VP8. |
276 // |num_play_throughs| indicates how many times to play through the video. | 436 // |num_play_throughs| indicates how many times to play through the video. |
277 // |reset_after_frame_num| can be a frame number >=0 indicating a mid-stream | 437 // |reset_after_frame_num| can be a frame number >=0 indicating a mid-stream |
278 // Reset() should be done after that frame number is delivered, or | 438 // Reset() should be done after that frame number is delivered, or |
279 // END_OF_STREAM_RESET to indicate no mid-stream Reset(). | 439 // END_OF_STREAM_RESET to indicate no mid-stream Reset(). |
280 // |delete_decoder_state| indicates when the underlying decoder should be | 440 // |delete_decoder_state| indicates when the underlying decoder should be |
281 // Destroy()'d and deleted and can take values: N<0: delete after -N Decode() | 441 // Destroy()'d and deleted and can take values: N<0: delete after -N Decode() |
282 // calls have been made, N>=0 means interpret as ClientState. | 442 // calls have been made, N>=0 means interpret as ClientState. |
283 // Both |reset_after_frame_num| & |delete_decoder_state| apply only to the | 443 // Both |reset_after_frame_num| & |delete_decoder_state| apply only to the |
284 // last play-through (governed by |num_play_throughs|). | 444 // last play-through (governed by |num_play_throughs|). |
445 // |rendering_fps| indicates the target rendering fps. 0 means no target fps | |
446 // and it would render as fast as possible. | |
447 // |suppress_rendering| indicates GL rendering is suppressed or not. | |
285 // After |delay_reuse_after_frame_num| frame has been delivered, the client | 448 // After |delay_reuse_after_frame_num| frame has been delivered, the client |
286 // will start delaying the call to ReusePictureBuffer() for kReuseDelayMs. | 449 // will start delaying the call to ReusePictureBuffer() for kReuseDelay. |
287 GLRenderingVDAClient(RenderingHelper* rendering_helper, | 450 GLRenderingVDAClient(RenderingHelper* rendering_helper, |
288 int rendering_window_id, | 451 int rendering_window_id, |
289 ClientStateNotification* note, | 452 ClientStateNotification* note, |
290 const std::string& encoded_data, | 453 const std::string& encoded_data, |
291 int num_fragments_per_decode, | 454 int num_fragments_per_decode, |
292 int num_in_flight_decodes, | 455 int num_in_flight_decodes, |
293 int num_play_throughs, | 456 int num_play_throughs, |
294 int reset_after_frame_num, | 457 int reset_after_frame_num, |
295 int delete_decoder_state, | 458 int delete_decoder_state, |
296 int frame_width, | 459 int frame_width, |
297 int frame_height, | 460 int frame_height, |
298 int profile, | 461 int profile, |
462 double rendering_fps, | |
299 bool suppress_rendering, | 463 bool suppress_rendering, |
300 int delay_reuse_after_frame_num); | 464 int delay_reuse_after_frame_num); |
301 virtual ~GLRenderingVDAClient(); | 465 virtual ~GLRenderingVDAClient(); |
302 void CreateDecoder(); | 466 void CreateDecoder(); |
303 | 467 |
304 // VideoDecodeAccelerator::Client implementation. | 468 // VideoDecodeAccelerator::Client implementation. |
305 // The heart of the Client. | 469 // The heart of the Client. |
306 virtual void ProvidePictureBuffers(uint32 requested_num_of_buffers, | 470 virtual void ProvidePictureBuffers(uint32 requested_num_of_buffers, |
307 const gfx::Size& dimensions, | 471 const gfx::Size& dimensions, |
308 uint32 texture_target) OVERRIDE; | 472 uint32 texture_target) OVERRIDE; |
309 virtual void DismissPictureBuffer(int32 picture_buffer_id) OVERRIDE; | 473 virtual void DismissPictureBuffer(int32 picture_buffer_id) OVERRIDE; |
310 virtual void PictureReady(const media::Picture& picture) OVERRIDE; | 474 virtual void PictureReady(const media::Picture& picture) OVERRIDE; |
311 // Simple state changes. | 475 // Simple state changes. |
312 virtual void NotifyInitializeDone() OVERRIDE; | 476 virtual void NotifyInitializeDone() OVERRIDE; |
313 virtual void NotifyEndOfBitstreamBuffer(int32 bitstream_buffer_id) OVERRIDE; | 477 virtual void NotifyEndOfBitstreamBuffer(int32 bitstream_buffer_id) OVERRIDE; |
314 virtual void NotifyFlushDone() OVERRIDE; | 478 virtual void NotifyFlushDone() OVERRIDE; |
315 virtual void NotifyResetDone() OVERRIDE; | 479 virtual void NotifyResetDone() OVERRIDE; |
316 virtual void NotifyError(VideoDecodeAccelerator::Error error) OVERRIDE; | 480 virtual void NotifyError(VideoDecodeAccelerator::Error error) OVERRIDE; |
317 | 481 |
318 void OutputFrameDeliveryTimes(base::PlatformFile output); | 482 void OutputFrameDeliveryTimes(base::PlatformFile output); |
319 | 483 |
484 void NotifyFrameDropped(int32 picture_buffer_id); | |
485 | |
320 // Simple getters for inspecting the state of the Client. | 486 // Simple getters for inspecting the state of the Client. |
321 int num_done_bitstream_buffers() { return num_done_bitstream_buffers_; } | 487 int num_done_bitstream_buffers() { return num_done_bitstream_buffers_; } |
322 int num_skipped_fragments() { return num_skipped_fragments_; } | 488 int num_skipped_fragments() { return num_skipped_fragments_; } |
323 int num_queued_fragments() { return num_queued_fragments_; } | 489 int num_queued_fragments() { return num_queued_fragments_; } |
324 int num_decoded_frames() { return num_decoded_frames_; } | 490 int num_decoded_frames() { return num_decoded_frames_; } |
325 double frames_per_second(); | 491 double frames_per_second(); |
326 bool decoder_deleted() { return !decoder_.get(); } | 492 bool decoder_deleted() { return !decoder_.get(); } |
327 | 493 |
328 private: | 494 private: |
329 typedef std::map<int, media::PictureBuffer*> PictureBufferById; | 495 typedef std::map<int, media::PictureBuffer*> PictureBufferById; |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
366 int num_skipped_fragments_; | 532 int num_skipped_fragments_; |
367 int num_queued_fragments_; | 533 int num_queued_fragments_; |
368 int num_decoded_frames_; | 534 int num_decoded_frames_; |
369 int num_done_bitstream_buffers_; | 535 int num_done_bitstream_buffers_; |
370 PictureBufferById picture_buffers_by_id_; | 536 PictureBufferById picture_buffers_by_id_; |
371 base::TimeTicks initialize_done_ticks_; | 537 base::TimeTicks initialize_done_ticks_; |
372 int profile_; | 538 int profile_; |
373 bool suppress_rendering_; | 539 bool suppress_rendering_; |
374 std::vector<base::TimeTicks> frame_delivery_times_; | 540 std::vector<base::TimeTicks> frame_delivery_times_; |
375 int delay_reuse_after_frame_num_; | 541 int delay_reuse_after_frame_num_; |
542 scoped_ptr<ThrottlingVDAClient> throttling_client_; | |
543 | |
544 DISALLOW_IMPLICIT_CONSTRUCTORS(GLRenderingVDAClient); | |
376 }; | 545 }; |
377 | 546 |
378 GLRenderingVDAClient::GLRenderingVDAClient( | 547 GLRenderingVDAClient::GLRenderingVDAClient( |
379 RenderingHelper* rendering_helper, | 548 RenderingHelper* rendering_helper, |
380 int rendering_window_id, | 549 int rendering_window_id, |
381 ClientStateNotification* note, | 550 ClientStateNotification* note, |
382 const std::string& encoded_data, | 551 const std::string& encoded_data, |
383 int num_fragments_per_decode, | 552 int num_fragments_per_decode, |
384 int num_in_flight_decodes, | 553 int num_in_flight_decodes, |
385 int num_play_throughs, | 554 int num_play_throughs, |
386 int reset_after_frame_num, | 555 int reset_after_frame_num, |
387 int delete_decoder_state, | 556 int delete_decoder_state, |
388 int frame_width, | 557 int frame_width, |
389 int frame_height, | 558 int frame_height, |
390 int profile, | 559 int profile, |
560 double rendering_fps, | |
391 bool suppress_rendering, | 561 bool suppress_rendering, |
392 int delay_reuse_after_frame_num) | 562 int delay_reuse_after_frame_num) |
393 : rendering_helper_(rendering_helper), | 563 : rendering_helper_(rendering_helper), |
394 rendering_window_id_(rendering_window_id), | 564 rendering_window_id_(rendering_window_id), |
395 encoded_data_(encoded_data), | 565 encoded_data_(encoded_data), |
396 num_fragments_per_decode_(num_fragments_per_decode), | 566 num_fragments_per_decode_(num_fragments_per_decode), |
397 num_in_flight_decodes_(num_in_flight_decodes), outstanding_decodes_(0), | 567 num_in_flight_decodes_(num_in_flight_decodes), outstanding_decodes_(0), |
398 encoded_data_next_pos_to_decode_(0), next_bitstream_buffer_id_(0), | 568 encoded_data_next_pos_to_decode_(0), next_bitstream_buffer_id_(0), |
399 note_(note), | 569 note_(note), |
400 remaining_play_throughs_(num_play_throughs), | 570 remaining_play_throughs_(num_play_throughs), |
401 reset_after_frame_num_(reset_after_frame_num), | 571 reset_after_frame_num_(reset_after_frame_num), |
402 delete_decoder_state_(delete_decoder_state), | 572 delete_decoder_state_(delete_decoder_state), |
403 state_(CS_CREATED), | 573 state_(CS_CREATED), |
404 num_skipped_fragments_(0), num_queued_fragments_(0), | 574 num_skipped_fragments_(0), num_queued_fragments_(0), |
405 num_decoded_frames_(0), num_done_bitstream_buffers_(0), | 575 num_decoded_frames_(0), num_done_bitstream_buffers_(0), |
406 profile_(profile), | 576 profile_(profile), |
407 suppress_rendering_(suppress_rendering), | 577 suppress_rendering_(suppress_rendering), |
408 delay_reuse_after_frame_num_(delay_reuse_after_frame_num) { | 578 delay_reuse_after_frame_num_(delay_reuse_after_frame_num) { |
409 CHECK_GT(num_fragments_per_decode, 0); | 579 CHECK_GT(num_fragments_per_decode, 0); |
410 CHECK_GT(num_in_flight_decodes, 0); | 580 CHECK_GT(num_in_flight_decodes, 0); |
411 CHECK_GT(num_play_throughs, 0); | 581 CHECK_GT(num_play_throughs, 0); |
582 CHECK_GE(rendering_fps, 0); | |
583 if (rendering_fps > 0) | |
584 throttling_client_.reset(new ThrottlingVDAClient( | |
585 this, | |
586 rendering_fps, | |
587 base::Bind(&GLRenderingVDAClient::NotifyFrameDropped, | |
588 base::Unretained(this)))); | |
412 } | 589 } |
413 | 590 |
414 GLRenderingVDAClient::~GLRenderingVDAClient() { | 591 GLRenderingVDAClient::~GLRenderingVDAClient() { |
415 DeleteDecoder(); // Clean up in case of expected error. | 592 DeleteDecoder(); // Clean up in case of expected error. |
416 CHECK(decoder_deleted()); | 593 CHECK(decoder_deleted()); |
417 STLDeleteValues(&picture_buffers_by_id_); | 594 STLDeleteValues(&picture_buffers_by_id_); |
418 SetState(CS_DESTROYED); | 595 SetState(CS_DESTROYED); |
419 } | 596 } |
420 | 597 |
421 static bool DoNothingReturnTrue() { return true; } | 598 static bool DoNothingReturnTrue() { return true; } |
422 | 599 |
423 void GLRenderingVDAClient::CreateDecoder() { | 600 void GLRenderingVDAClient::CreateDecoder() { |
424 CHECK(decoder_deleted()); | 601 CHECK(decoder_deleted()); |
425 CHECK(!decoder_.get()); | 602 CHECK(!decoder_.get()); |
603 | |
604 VideoDecodeAccelerator::Client* client = this; | |
605 if (throttling_client_) | |
606 client = throttling_client_.get(); | |
426 #if defined(OS_WIN) | 607 #if defined(OS_WIN) |
427 decoder_.reset(new DXVAVideoDecodeAccelerator( | 608 decoder_.reset(new DXVAVideoDecodeAccelerator( |
428 this, base::Bind(&DoNothingReturnTrue))); | 609 client, base::Bind(&DoNothingReturnTrue))); |
429 #elif defined(OS_CHROMEOS) | 610 #elif defined(OS_CHROMEOS) |
430 #if defined(ARCH_CPU_ARMEL) | 611 #if defined(ARCH_CPU_ARMEL) |
431 decoder_.reset( | 612 decoder_.reset( |
432 new ExynosVideoDecodeAccelerator( | 613 new ExynosVideoDecodeAccelerator( |
433 static_cast<EGLDisplay>(rendering_helper_->GetGLDisplay()), | 614 static_cast<EGLDisplay>(rendering_helper_->GetGLDisplay()), |
434 static_cast<EGLContext>(rendering_helper_->GetGLContext()), | 615 static_cast<EGLContext>(rendering_helper_->GetGLContext()), |
435 this, base::Bind(&DoNothingReturnTrue))); | 616 client, base::Bind(&DoNothingReturnTrue))); |
436 #elif defined(ARCH_CPU_X86_FAMILY) | 617 #elif defined(ARCH_CPU_X86_FAMILY) |
437 decoder_.reset(new VaapiVideoDecodeAccelerator( | 618 decoder_.reset(new VaapiVideoDecodeAccelerator( |
438 static_cast<Display*>(rendering_helper_->GetGLDisplay()), | 619 static_cast<Display*>(rendering_helper_->GetGLDisplay()), |
439 static_cast<GLXContext>(rendering_helper_->GetGLContext()), | 620 static_cast<GLXContext>(rendering_helper_->GetGLContext()), |
440 this, base::Bind(&DoNothingReturnTrue))); | 621 client, base::Bind(&DoNothingReturnTrue))); |
441 #endif // ARCH_CPU_ARMEL | 622 #endif // ARCH_CPU_ARMEL |
442 #endif // OS_WIN | 623 #endif // OS_WIN |
443 CHECK(decoder_.get()); | 624 CHECK(decoder_.get()); |
444 SetState(CS_DECODER_SET); | 625 SetState(CS_DECODER_SET); |
445 if (decoder_deleted()) | 626 if (decoder_deleted()) |
446 return; | 627 return; |
447 | 628 |
448 // Configure the decoder. | 629 // Configure the decoder. |
449 media::VideoCodecProfile profile = media::H264PROFILE_BASELINE; | 630 media::VideoCodecProfile profile = media::H264PROFILE_BASELINE; |
450 if (profile_ != -1) | 631 if (profile_ != -1) |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
485 delete it->second; | 666 delete it->second; |
486 picture_buffers_by_id_.erase(it); | 667 picture_buffers_by_id_.erase(it); |
487 } | 668 } |
488 | 669 |
489 void GLRenderingVDAClient::PictureReady(const media::Picture& picture) { | 670 void GLRenderingVDAClient::PictureReady(const media::Picture& picture) { |
490 // We shouldn't be getting pictures delivered after Reset has completed. | 671 // We shouldn't be getting pictures delivered after Reset has completed. |
491 CHECK_LT(state_, CS_RESET); | 672 CHECK_LT(state_, CS_RESET); |
492 | 673 |
493 if (decoder_deleted()) | 674 if (decoder_deleted()) |
494 return; | 675 return; |
676 | |
495 frame_delivery_times_.push_back(base::TimeTicks::Now()); | 677 frame_delivery_times_.push_back(base::TimeTicks::Now()); |
496 | 678 |
497 CHECK_LE(picture.bitstream_buffer_id(), next_bitstream_buffer_id_); | 679 CHECK_LE(picture.bitstream_buffer_id(), next_bitstream_buffer_id_); |
498 ++num_decoded_frames_; | 680 ++num_decoded_frames_; |
499 | 681 |
500 // Mid-stream reset applies only to the last play-through per constructor | 682 // Mid-stream reset applies only to the last play-through per constructor |
501 // comment. | 683 // comment. |
502 if (remaining_play_throughs_ == 1 && | 684 if (remaining_play_throughs_ == 1 && |
503 reset_after_frame_num_ == num_decoded_frames_) { | 685 reset_after_frame_num_ == num_decoded_frames_) { |
504 reset_after_frame_num_ = MID_STREAM_RESET; | 686 reset_after_frame_num_ = MID_STREAM_RESET; |
505 decoder_->Reset(); | 687 decoder_->Reset(); |
506 // Re-start decoding from the beginning of the stream to avoid needing to | 688 // Re-start decoding from the beginning of the stream to avoid needing to |
507 // know how to find I-frames and so on in this test. | 689 // know how to find I-frames and so on in this test. |
508 encoded_data_next_pos_to_decode_ = 0; | 690 encoded_data_next_pos_to_decode_ = 0; |
509 } | 691 } |
510 | 692 |
511 media::PictureBuffer* picture_buffer = | 693 media::PictureBuffer* picture_buffer = |
512 picture_buffers_by_id_[picture.picture_buffer_id()]; | 694 picture_buffers_by_id_[picture.picture_buffer_id()]; |
513 CHECK(picture_buffer); | 695 CHECK(picture_buffer); |
514 if (!suppress_rendering_) { | 696 if (!suppress_rendering_) { |
515 rendering_helper_->RenderTexture(picture_buffer->texture_id()); | 697 rendering_helper_->RenderTexture(picture_buffer->texture_id()); |
516 } | 698 } |
517 | 699 |
518 if (num_decoded_frames_ > delay_reuse_after_frame_num_) { | 700 if (num_decoded_frames_ > delay_reuse_after_frame_num_) { |
519 base::MessageLoop::current()->PostDelayedTask(FROM_HERE, base::Bind( | 701 base::MessageLoop::current()->PostDelayedTask(FROM_HERE, base::Bind( |
520 &VideoDecodeAccelerator::ReusePictureBuffer, | 702 &VideoDecodeAccelerator::ReusePictureBuffer, |
521 decoder_->AsWeakPtr(), picture.picture_buffer_id()), | 703 decoder_->AsWeakPtr(), picture.picture_buffer_id()), |
522 base::TimeDelta::FromMilliseconds(kReuseDelayMs)); | 704 kReuseDelay); |
523 } else { | 705 } else { |
524 decoder_->ReusePictureBuffer(picture.picture_buffer_id()); | 706 decoder_->ReusePictureBuffer(picture.picture_buffer_id()); |
525 } | 707 } |
526 } | 708 } |
527 | 709 |
528 void GLRenderingVDAClient::NotifyInitializeDone() { | 710 void GLRenderingVDAClient::NotifyInitializeDone() { |
529 SetState(CS_INITIALIZED); | 711 SetState(CS_INITIALIZED); |
530 initialize_done_ticks_ = base::TimeTicks::Now(); | 712 initialize_done_ticks_ = base::TimeTicks::Now(); |
531 for (int i = 0; i < num_in_flight_decodes_; ++i) | 713 for (int i = 0; i < num_in_flight_decodes_; ++i) |
532 DecodeNextFragments(); | 714 DecodeNextFragments(); |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
588 base::TimeTicks t0 = initialize_done_ticks_; | 770 base::TimeTicks t0 = initialize_done_ticks_; |
589 for (size_t i = 0; i < frame_delivery_times_.size(); ++i) { | 771 for (size_t i = 0; i < frame_delivery_times_.size(); ++i) { |
590 s = base::StringPrintf("frame %04" PRIuS ": %" PRId64 " us\n", | 772 s = base::StringPrintf("frame %04" PRIuS ": %" PRId64 " us\n", |
591 i, | 773 i, |
592 (frame_delivery_times_[i] - t0).InMicroseconds()); | 774 (frame_delivery_times_[i] - t0).InMicroseconds()); |
593 t0 = frame_delivery_times_[i]; | 775 t0 = frame_delivery_times_[i]; |
594 base::WritePlatformFileAtCurrentPos(output, s.data(), s.length()); | 776 base::WritePlatformFileAtCurrentPos(output, s.data(), s.length()); |
595 } | 777 } |
596 } | 778 } |
597 | 779 |
780 void GLRenderingVDAClient::NotifyFrameDropped(int32 picture_buffer_id) { | |
781 decoder_->ReusePictureBuffer(picture_buffer_id); | |
782 } | |
783 | |
598 static bool LookingAtNAL(const std::string& encoded, size_t pos) { | 784 static bool LookingAtNAL(const std::string& encoded, size_t pos) { |
599 return encoded[pos] == 0 && encoded[pos + 1] == 0 && | 785 return encoded[pos] == 0 && encoded[pos + 1] == 0 && |
600 encoded[pos + 2] == 0 && encoded[pos + 3] == 1; | 786 encoded[pos + 2] == 0 && encoded[pos + 3] == 1; |
601 } | 787 } |
602 | 788 |
603 void GLRenderingVDAClient::SetState(ClientState new_state) { | 789 void GLRenderingVDAClient::SetState(ClientState new_state) { |
604 note_->Notify(new_state); | 790 note_->Notify(new_state); |
605 state_ = new_state; | 791 state_ = new_state; |
606 if (!remaining_play_throughs_ && new_state == delete_decoder_state_) { | 792 if (!remaining_play_throughs_ && new_state == delete_decoder_state_) { |
607 CHECK(!decoder_deleted()); | 793 CHECK(!decoder_deleted()); |
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
777 } | 963 } |
778 | 964 |
779 // We assert a minimal number of concurrent decoders we expect to succeed. | 965 // We assert a minimal number of concurrent decoders we expect to succeed. |
780 // Different platforms can support more concurrent decoders, so we don't assert | 966 // Different platforms can support more concurrent decoders, so we don't assert |
781 // failure above this. | 967 // failure above this. |
782 enum { kMinSupportedNumConcurrentDecoders = 3 }; | 968 enum { kMinSupportedNumConcurrentDecoders = 3 }; |
783 | 969 |
784 // Test the most straightforward case possible: data is decoded from a single | 970 // Test the most straightforward case possible: data is decoded from a single |
785 // chunk and rendered to the screen. | 971 // chunk and rendered to the screen. |
786 TEST_P(VideoDecodeAcceleratorTest, TestSimpleDecode) { | 972 TEST_P(VideoDecodeAcceleratorTest, TestSimpleDecode) { |
787 // Can be useful for debugging VLOGs from OVDA. | |
788 // logging::SetMinLogLevel(-1); | |
789 | |
790 // Required for Thread to work. Not used otherwise. | 973 // Required for Thread to work. Not used otherwise. |
791 base::ShadowingAtExitManager at_exit_manager; | 974 base::ShadowingAtExitManager at_exit_manager; |
792 | 975 |
793 const int num_fragments_per_decode = GetParam().a; | 976 const int num_fragments_per_decode = GetParam().a; |
794 const size_t num_concurrent_decoders = GetParam().b; | 977 const size_t num_concurrent_decoders = GetParam().b; |
795 const size_t num_in_flight_decodes = GetParam().c; | 978 const size_t num_in_flight_decodes = GetParam().c; |
796 const int num_play_throughs = GetParam().d; | 979 const int num_play_throughs = GetParam().d; |
797 const int reset_point = GetParam().e; | 980 const int reset_point = GetParam().e; |
798 const int delete_decoder_state = GetParam().f; | 981 const int delete_decoder_state = GetParam().f; |
799 bool test_reuse_delay = GetParam().g; | 982 bool test_reuse_delay = GetParam().g; |
800 const bool render_as_thumbnails = GetParam().h; | 983 const bool render_as_thumbnails = GetParam().h; |
801 | 984 |
802 std::vector<TestVideoFile*> test_video_files; | 985 std::vector<TestVideoFile*> test_video_files; |
803 ParseAndReadTestVideoData(test_video_data, num_concurrent_decoders, | 986 ParseAndReadTestVideoData(test_video_data, num_concurrent_decoders, |
804 reset_point, &test_video_files); | 987 reset_point, &test_video_files); |
805 | 988 |
806 // Suppress GL rendering when we are logging the frame delivery time and a | 989 // Suppress GL rendering for all tests when the "--disable_rendering" is set. |
807 // few other tests, to cut down overall test runtime. | 990 // Otherwise, suppress rendering in all but a few tests, to cut down overall |
991 // test runtime. | |
808 const bool suppress_rendering = num_fragments_per_decode > 1 || | 992 const bool suppress_rendering = num_fragments_per_decode > 1 || |
809 frame_delivery_log != NULL; | 993 content::disable_rendering; |
810 | 994 |
811 std::vector<ClientStateNotification*> notes(num_concurrent_decoders, NULL); | 995 std::vector<ClientStateNotification*> notes(num_concurrent_decoders, NULL); |
812 std::vector<GLRenderingVDAClient*> clients(num_concurrent_decoders, NULL); | 996 std::vector<GLRenderingVDAClient*> clients(num_concurrent_decoders, NULL); |
813 | 997 |
814 // Initialize the rendering helper. | 998 // Initialize the rendering helper. |
815 base::Thread rendering_thread("GLRenderingVDAClientThread"); | 999 base::Thread rendering_thread("GLRenderingVDAClientThread"); |
816 base::Thread::Options options; | 1000 base::Thread::Options options; |
817 options.message_loop_type = base::MessageLoop::TYPE_DEFAULT; | 1001 options.message_loop_type = base::MessageLoop::TYPE_DEFAULT; |
818 #if defined(OS_WIN) | 1002 #if defined(OS_WIN) |
819 // For windows the decoding thread initializes the media foundation decoder | 1003 // For windows the decoding thread initializes the media foundation decoder |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
864 if (test_reuse_delay && | 1048 if (test_reuse_delay && |
865 kMaxFramesToDelayReuse * 2 < video_file->num_frames) { | 1049 kMaxFramesToDelayReuse * 2 < video_file->num_frames) { |
866 delay_after_frame_num = video_file->num_frames - kMaxFramesToDelayReuse; | 1050 delay_after_frame_num = video_file->num_frames - kMaxFramesToDelayReuse; |
867 } | 1051 } |
868 | 1052 |
869 GLRenderingVDAClient* client = new GLRenderingVDAClient( | 1053 GLRenderingVDAClient* client = new GLRenderingVDAClient( |
870 rendering_helper.get(), index, note, video_file->data_str, | 1054 rendering_helper.get(), index, note, video_file->data_str, |
871 num_fragments_per_decode, num_in_flight_decodes, num_play_throughs, | 1055 num_fragments_per_decode, num_in_flight_decodes, num_play_throughs, |
872 video_file->reset_after_frame_num, delete_decoder_state, | 1056 video_file->reset_after_frame_num, delete_decoder_state, |
873 video_file->width, video_file->height, video_file->profile, | 1057 video_file->width, video_file->height, video_file->profile, |
874 suppress_rendering, delay_after_frame_num); | 1058 rendering_fps, suppress_rendering, delay_after_frame_num); |
875 clients[index] = client; | 1059 clients[index] = client; |
876 | 1060 |
877 rendering_thread.message_loop()->PostTask( | 1061 rendering_thread.message_loop()->PostTask( |
878 FROM_HERE, | 1062 FROM_HERE, |
879 base::Bind(&GLRenderingVDAClient::CreateDecoder, | 1063 base::Bind(&GLRenderingVDAClient::CreateDecoder, |
880 base::Unretained(client))); | 1064 base::Unretained(client))); |
881 | 1065 |
882 ASSERT_EQ(note->Wait(), CS_DECODER_SET); | 1066 ASSERT_EQ(note->Wait(), CS_DECODER_SET); |
883 } | 1067 } |
884 // Then wait for all the decodes to finish. | 1068 // Then wait for all the decodes to finish. |
(...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1133 for (CommandLine::SwitchMap::const_iterator it = switches.begin(); | 1317 for (CommandLine::SwitchMap::const_iterator it = switches.begin(); |
1134 it != switches.end(); ++it) { | 1318 it != switches.end(); ++it) { |
1135 if (it->first == "test_video_data") { | 1319 if (it->first == "test_video_data") { |
1136 content::test_video_data = it->second.c_str(); | 1320 content::test_video_data = it->second.c_str(); |
1137 continue; | 1321 continue; |
1138 } | 1322 } |
1139 if (it->first == "frame_delivery_log") { | 1323 if (it->first == "frame_delivery_log") { |
1140 content::frame_delivery_log = it->second.c_str(); | 1324 content::frame_delivery_log = it->second.c_str(); |
1141 continue; | 1325 continue; |
1142 } | 1326 } |
1327 if (it->first == "rendering_fps") { | |
1328 CHECK(base::StringToDouble(it->second, &content::rendering_fps)); | |
1329 continue; | |
1330 } | |
1331 if (it->first == "disable_rendering") { | |
1332 content::disable_rendering = true; | |
1333 continue; | |
1334 } | |
1143 if (it->first == "v" || it->first == "vmodule") | 1335 if (it->first == "v" || it->first == "vmodule") |
1144 continue; | 1336 continue; |
1145 LOG(FATAL) << "Unexpected switch: " << it->first << ":" << it->second; | 1337 LOG(FATAL) << "Unexpected switch: " << it->first << ":" << it->second; |
1146 } | 1338 } |
1147 | 1339 |
1148 base::ShadowingAtExitManager at_exit_manager; | 1340 base::ShadowingAtExitManager at_exit_manager; |
1149 | 1341 |
1150 #if defined(OS_WIN) | 1342 #if defined(OS_WIN) |
1151 content::DXVAVideoDecodeAccelerator::PreSandboxInitialization(); | 1343 content::DXVAVideoDecodeAccelerator::PreSandboxInitialization(); |
1152 #elif defined(OS_CHROMEOS) | 1344 #elif defined(OS_CHROMEOS) |
1153 #if defined(ARCH_CPU_ARMEL) | 1345 #if defined(ARCH_CPU_ARMEL) |
1154 content::ExynosVideoDecodeAccelerator::PreSandboxInitialization(); | 1346 content::ExynosVideoDecodeAccelerator::PreSandboxInitialization(); |
1155 #elif defined(ARCH_CPU_X86_FAMILY) | 1347 #elif defined(ARCH_CPU_X86_FAMILY) |
1156 content::VaapiWrapper::PreSandboxInitialization(); | 1348 content::VaapiWrapper::PreSandboxInitialization(); |
1157 #endif // ARCH_CPU_ARMEL | 1349 #endif // ARCH_CPU_ARMEL |
1158 #endif // OS_CHROMEOS | 1350 #endif // OS_CHROMEOS |
1159 | 1351 |
1160 return RUN_ALL_TESTS(); | 1352 return RUN_ALL_TESTS(); |
1161 } | 1353 } |
OLD | NEW |