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 3 // found in the LICENSE file. 4 // 5 // The bulk of this file is support code; sorry about that. Here's an overview 6 // to hopefully help readers of this code: 7 // - RenderingHelper is charged with interacting with X11/{EGL/GLES2,GLX/GL} or 8 // Win/EGL. 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 11 // to be written sequentially and wait for the decode client to see certain 12 // state transitions. 13 // - GLRenderingVDAClient is a VideoDecodeAccelerator::Client implementation 14 // - Finally actual TEST cases are at the bottom of this file, using the above 15 // infrastructure. 16 17 #include <fcntl.h> 18 #include <math.h> 19 #include <sys/stat.h> 20 #include <sys/types.h> 21 #include <deque> 22 23 // Include gtest.h out of order because <X11/X.h> #define's Bool & None, which 24 // gtest uses as struct names (inside a namespace). This means that 25 // #include'ing gtest after anything that pulls in X.h fails to compile. 26 // This is http://code.google.com/p/googletest/issues/detail?id=371 27 #include "testing/gtest/include/gtest/gtest.h" 28 29 #include "base/at_exit.h" 30 #include "base/bind.h" 31 #include "base/command_line.h" 32 #include "base/file_util.h" 33 #include "base/format_macros.h" 34 #include "base/md5.h" 35 #include "base/platform_file.h" 36 #include "base/process/process.h" 37 #include "base/stl_util.h" 38 #include "base/strings/string_number_conversions.h" 39 #include "base/strings/string_split.h" 40 #include "base/strings/stringize_macros.h" 41 #include "base/strings/stringprintf.h" 42 #include "base/strings/utf_string_conversions.h" 43 #include "base/synchronization/condition_variable.h" 44 #include "base/synchronization/lock.h" 45 #include "base/synchronization/waitable_event.h" 46 #include "base/threading/thread.h" 47 #include "content/common/gpu/media/rendering_helper.h" 48 #include "content/public/common/content_switches.h" 49 #include "ui/gfx/codec/png_codec.h" 50 51 #if defined(OS_WIN) 52 #include "content/common/gpu/media/dxva_video_decode_accelerator.h" 53 #elif defined(OS_CHROMEOS) 54 #if defined(ARCH_CPU_ARMEL) 55 #include "content/common/gpu/media/exynos_video_decode_accelerator.h" 56 #elif defined(ARCH_CPU_X86_FAMILY) 57 #include "content/common/gpu/media/vaapi_video_decode_accelerator.h" 58 #include "content/common/gpu/media/vaapi_wrapper.h" 59 #endif // ARCH_CPU_ARMEL 60 #else 61 #error The VideoAccelerator tests are not supported on this platform. 62 #endif // OS_WIN 63 64 using media::VideoDecodeAccelerator; 65 66 namespace content { 67 namespace { 68 69 // Values optionally filled in from flags; see main() below. 70 // The syntax of multiple test videos is: 71 // test-video1;test-video2;test-video3 72 // where only the first video is required and other optional videos would be 73 // decoded by concurrent decoders. 74 // The syntax of each test-video is: 75 // filename:width:height:numframes:numfragments:minFPSwithRender:minFPSnoRender 76 // where only the first field is required. Value details: 77 // - |filename| must be an h264 Annex B (NAL) stream or an IVF VP8 stream. 78 // - |width| and |height| are in pixels. 79 // - |numframes| is the number of picture frames in the file. 80 // - |numfragments| NALU (h264) or frame (VP8) count in the stream. 81 // - |minFPSwithRender| and |minFPSnoRender| are minimum frames/second speeds 82 // expected to be achieved with and without rendering to the screen, resp. 83 // (the latter tests just decode speed). 84 // - |profile| is the media::VideoCodecProfile set during Initialization. 85 // An empty value for a numeric field means "ignore". 86 const base::FilePath::CharType* g_test_video_data = 87 // FILE_PATH_LITERAL("test-25fps.vp8:320:240:250:250:50:175:11"); 88 FILE_PATH_LITERAL("test-25fps.h264:320:240:250:258:50:175:1"); 89 90 // The path of the frame delivery time log. We can enable the log and specify 91 // the filename by the "--frame_delivery_log" switch. 92 const base::FilePath::CharType* g_frame_delivery_log = NULL; 93 94 // The value is set by the switch "--rendering_fps". 95 double g_rendering_fps = 0; 96 97 // Disable rendering, the value is set by the switch "--disable_rendering". 98 bool g_disable_rendering = false; 99 100 // Magic constants for differentiating the reasons for NotifyResetDone being 101 // called. 102 enum ResetPoint { 103 START_OF_STREAM_RESET = -3, 104 MID_STREAM_RESET = -2, 105 END_OF_STREAM_RESET = -1 106 }; 107 108 const int kMaxResetAfterFrameNum = 100; 109 const int kMaxFramesToDelayReuse = 64; 110 const base::TimeDelta kReuseDelay = base::TimeDelta::FromSeconds(1); 111 112 struct TestVideoFile { 113 explicit TestVideoFile(base::FilePath::StringType file_name) 114 : file_name(file_name), 115 width(-1), 116 height(-1), 117 num_frames(-1), 118 num_fragments(-1), 119 min_fps_render(-1), 120 min_fps_no_render(-1), 121 profile(-1), 122 reset_after_frame_num(END_OF_STREAM_RESET) { 123 } 124 125 base::FilePath::StringType file_name; 126 int width; 127 int height; 128 int num_frames; 129 int num_fragments; 130 int min_fps_render; 131 int min_fps_no_render; 132 int profile; 133 int reset_after_frame_num; 134 std::string data_str; 135 }; 136 137 // Presumed minimal display size. 138 const gfx::Size kThumbnailsDisplaySize(1366, 768); 139 const gfx::Size kThumbnailsPageSize(1600, 1200); 140 const gfx::Size kThumbnailSize(160, 120); 141 const int kMD5StringLength = 32; 142 143 // Parse |data| into its constituent parts, set the various output fields 144 // accordingly, and read in video stream. CHECK-fails on unexpected or 145 // missing required data. Unspecified optional fields are set to -1. 146 void ParseAndReadTestVideoData(base::FilePath::StringType data, 147 size_t num_concurrent_decoders, 148 int reset_point, 149 std::vector<TestVideoFile*>* test_video_files) { 150 std::vector<base::FilePath::StringType> entries; 151 base::SplitString(data, ';', &entries); 152 CHECK_GE(entries.size(), 1U) << data; 153 for (size_t index = 0; index < entries.size(); ++index) { 154 std::vector<base::FilePath::StringType> fields; 155 base::SplitString(entries[index], ':', &fields); 156 CHECK_GE(fields.size(), 1U) << entries[index]; 157 CHECK_LE(fields.size(), 8U) << entries[index]; 158 TestVideoFile* video_file = new TestVideoFile(fields[0]); 159 if (!fields[1].empty()) 160 CHECK(base::StringToInt(fields[1], &video_file->width)); 161 if (!fields[2].empty()) 162 CHECK(base::StringToInt(fields[2], &video_file->height)); 163 if (!fields[3].empty()) { 164 CHECK(base::StringToInt(fields[3], &video_file->num_frames)); 165 // If we reset mid-stream and start playback over, account for frames 166 // that are decoded twice in our expectations. 167 if (video_file->num_frames > 0 && reset_point == MID_STREAM_RESET) { 168 // Reset should not go beyond the last frame; reset after the first 169 // frame for short videos. 170 video_file->reset_after_frame_num = kMaxResetAfterFrameNum; 171 if (video_file->num_frames <= kMaxResetAfterFrameNum) 172 video_file->reset_after_frame_num = 1; 173 video_file->num_frames += video_file->reset_after_frame_num; 174 } else { 175 video_file->reset_after_frame_num = reset_point; 176 } 177 } 178 if (!fields[4].empty()) 179 CHECK(base::StringToInt(fields[4], &video_file->num_fragments)); 180 if (!fields[5].empty()) { 181 CHECK(base::StringToInt(fields[5], &video_file->min_fps_render)); 182 video_file->min_fps_render /= num_concurrent_decoders; 183 } 184 if (!fields[6].empty()) { 185 CHECK(base::StringToInt(fields[6], &video_file->min_fps_no_render)); 186 video_file->min_fps_no_render /= num_concurrent_decoders; 187 } 188 if (!fields[7].empty()) 189 CHECK(base::StringToInt(fields[7], &video_file->profile)); 190 191 // Read in the video data. 192 base::FilePath filepath(video_file->file_name); 193 CHECK(file_util::ReadFileToString(filepath, &video_file->data_str)) 194 << "test_video_file: " << filepath.MaybeAsASCII(); 195 196 test_video_files->push_back(video_file); 197 } 198 } 199 200 // Read in golden MD5s for the thumbnailed rendering of this video 201 void ReadGoldenThumbnailMD5s(const TestVideoFile* video_file, 202 std::vector<std::string>* md5_strings) { 203 base::FilePath filepath(video_file->file_name); 204 filepath = filepath.AddExtension(FILE_PATH_LITERAL(".md5")); 205 std::string all_md5s; 206 file_util::ReadFileToString(filepath, &all_md5s); 207 base::SplitString(all_md5s, '\n', md5_strings); 208 // Check these are legitimate MD5s. 209 for (std::vector<std::string>::iterator md5_string = md5_strings->begin(); 210 md5_string != md5_strings->end(); ++md5_string) { 211 // Ignore the empty string added by SplitString 212 if (!md5_string->length()) 213 continue; 214 215 CHECK_EQ(static_cast<int>(md5_string->length()), 216 kMD5StringLength) << *md5_string; 217 bool hex_only = std::count_if(md5_string->begin(), 218 md5_string->end(), isxdigit) == 219 kMD5StringLength; 220 CHECK(hex_only) << *md5_string; 221 } 222 CHECK_GE(md5_strings->size(), 1U) << all_md5s; 223 } 224 225 // State of the GLRenderingVDAClient below. Order matters here as the test 226 // makes assumptions about it. 227 enum ClientState { 228 CS_CREATED = 0, 229 CS_DECODER_SET = 1, 230 CS_INITIALIZED = 2, 231 CS_FLUSHING = 3, 232 CS_FLUSHED = 4, 233 CS_RESETTING = 5, 234 CS_RESET = 6, 235 CS_ERROR = 7, 236 CS_DESTROYED = 8, 237 CS_MAX, // Must be last entry. 238 }; 239 240 // Helper class allowing one thread to wait on a notification from another. 241 // If notifications come in faster than they are Wait()'d for, they are 242 // accumulated (so exactly as many Wait() calls will unblock as Notify() calls 243 // were made, regardless of order). 244 class ClientStateNotification { 245 public: 246 ClientStateNotification(); 247 ~ClientStateNotification(); 248 249 // Used to notify a single waiter of a ClientState. 250 void Notify(ClientState state); 251 // Used by waiters to wait for the next ClientState Notification. 252 ClientState Wait(); 253 private: 254 base::Lock lock_; 255 base::ConditionVariable cv_; 256 std::queue<ClientState> pending_states_for_notification_; 257 }; 258 259 ClientStateNotification::ClientStateNotification() : cv_(&lock_) {} 260 261 ClientStateNotification::~ClientStateNotification() {} 262 263 void ClientStateNotification::Notify(ClientState state) { 264 base::AutoLock auto_lock(lock_); 265 pending_states_for_notification_.push(state); 266 cv_.Signal(); 267 } 268 269 ClientState ClientStateNotification::Wait() { 270 base::AutoLock auto_lock(lock_); 271 while (pending_states_for_notification_.empty()) 272 cv_.Wait(); 273 ClientState ret = pending_states_for_notification_.front(); 274 pending_states_for_notification_.pop(); 275 return ret; 276 } 277 278 // A wrapper client that throttles the PictureReady callbacks to a given rate. 279 // It may drops or queues frame to deliver them on time. 280 class ThrottlingVDAClient : public VideoDecodeAccelerator::Client, 281 public base::SupportsWeakPtr<ThrottlingVDAClient> { 282 public: 283 // Callback invoked whan the picture is dropped and should be reused for 284 // the decoder again. 285 typedef base::Callback<void(int32 picture_buffer_id)> ReusePictureCB; 286 287 ThrottlingVDAClient(VideoDecodeAccelerator::Client* client, 288 double fps, 289 ReusePictureCB reuse_picture_cb); 290 virtual ~ThrottlingVDAClient(); 291 292 // VideoDecodeAccelerator::Client implementation 293 virtual void ProvidePictureBuffers(uint32 requested_num_of_buffers, 294 const gfx::Size& dimensions, 295 uint32 texture_target) OVERRIDE; 296 virtual void DismissPictureBuffer(int32 picture_buffer_id) OVERRIDE; 297 virtual void PictureReady(const media::Picture& picture) OVERRIDE; 298 virtual void NotifyInitializeDone() OVERRIDE; 299 virtual void NotifyEndOfBitstreamBuffer(int32 bitstream_buffer_id) OVERRIDE; 300 virtual void NotifyFlushDone() OVERRIDE; 301 virtual void NotifyResetDone() OVERRIDE; 302 virtual void NotifyError(VideoDecodeAccelerator::Error error) OVERRIDE; 303 304 int num_decoded_frames() { return num_decoded_frames_; } 305 306 private: 307 308 void CallClientPictureReady(int version); 309 310 VideoDecodeAccelerator::Client* client_; 311 ReusePictureCB reuse_picture_cb_; 312 base::TimeTicks next_frame_delivered_time_; 313 base::TimeDelta frame_duration_; 314 315 int num_decoded_frames_; 316 int stream_version_; 317 std::deque<media::Picture> pending_pictures_; 318 319 DISALLOW_IMPLICIT_CONSTRUCTORS(ThrottlingVDAClient); 320 }; 321 322 ThrottlingVDAClient::ThrottlingVDAClient(VideoDecodeAccelerator::Client* client, 323 double fps, 324 ReusePictureCB reuse_picture_cb) 325 : client_(client), 326 reuse_picture_cb_(reuse_picture_cb), 327 num_decoded_frames_(0), 328 stream_version_(0) { 329 CHECK(client_); 330 CHECK_GT(fps, 0); 331 frame_duration_ = base::TimeDelta::FromSeconds(1) / fps; 332 } 333 334 ThrottlingVDAClient::~ThrottlingVDAClient() {} 335 336 void ThrottlingVDAClient::ProvidePictureBuffers(uint32 requested_num_of_buffers, 337 const gfx::Size& dimensions, 338 uint32 texture_target) { 339 client_->ProvidePictureBuffers( 340 requested_num_of_buffers, dimensions, texture_target); 341 } 342 343 void ThrottlingVDAClient::DismissPictureBuffer(int32 picture_buffer_id) { 344 client_->DismissPictureBuffer(picture_buffer_id); 345 } 346 347 void ThrottlingVDAClient::PictureReady(const media::Picture& picture) { 348 ++num_decoded_frames_; 349 350 if (pending_pictures_.empty()) { 351 base::TimeDelta delay = 352 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_ + frame_duration_ < now) { 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()); 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 429 // Client that can accept callbacks from a VideoDecodeAccelerator and is used by 430 // the TESTs below. 431 class GLRenderingVDAClient : public VideoDecodeAccelerator::Client { 432 public: 433 // Doesn't take ownership of |rendering_helper| or |note|, which must outlive 434 // |*this|. 435 // |num_fragments_per_decode| counts NALUs for h264 and frames for VP8. 436 // |num_play_throughs| indicates how many times to play through the video. 437 // |reset_after_frame_num| can be a frame number >=0 indicating a mid-stream 438 // Reset() should be done after that frame number is delivered, or 439 // END_OF_STREAM_RESET to indicate no mid-stream Reset(). 440 // |delete_decoder_state| indicates when the underlying decoder should be 441 // Destroy()'d and deleted and can take values: N<0: delete after -N Decode() 442 // calls have been made, N>=0 means interpret as ClientState. 443 // Both |reset_after_frame_num| & |delete_decoder_state| apply only to the 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. 448 // After |delay_reuse_after_frame_num| frame has been delivered, the client 449 // will start delaying the call to ReusePictureBuffer() for kReuseDelay. 450 GLRenderingVDAClient(RenderingHelper* rendering_helper, 451 int rendering_window_id, 452 ClientStateNotification* note, 453 const std::string& encoded_data, 454 int num_fragments_per_decode, 455 int num_in_flight_decodes, 456 int num_play_throughs, 457 int reset_after_frame_num, 458 int delete_decoder_state, 459 int frame_width, 460 int frame_height, 461 int profile, 462 double rendering_fps, 463 bool suppress_rendering, 464 int delay_reuse_after_frame_num); 465 virtual ~GLRenderingVDAClient(); 466 void CreateDecoder(); 467 468 // VideoDecodeAccelerator::Client implementation. 469 // The heart of the Client. 470 virtual void ProvidePictureBuffers(uint32 requested_num_of_buffers, 471 const gfx::Size& dimensions, 472 uint32 texture_target) OVERRIDE; 473 virtual void DismissPictureBuffer(int32 picture_buffer_id) OVERRIDE; 474 virtual void PictureReady(const media::Picture& picture) OVERRIDE; 475 // Simple state changes. 476 virtual void NotifyInitializeDone() OVERRIDE; 477 virtual void NotifyEndOfBitstreamBuffer(int32 bitstream_buffer_id) OVERRIDE; 478 virtual void NotifyFlushDone() OVERRIDE; 479 virtual void NotifyResetDone() OVERRIDE; 480 virtual void NotifyError(VideoDecodeAccelerator::Error error) OVERRIDE; 481 482 void OutputFrameDeliveryTimes(base::PlatformFile output); 483 484 void NotifyFrameDropped(int32 picture_buffer_id); 485 486 // Simple getters for inspecting the state of the Client. 487 int num_done_bitstream_buffers() { return num_done_bitstream_buffers_; } 488 int num_skipped_fragments() { return num_skipped_fragments_; } 489 int num_queued_fragments() { return num_queued_fragments_; } 490 int num_decoded_frames(); 491 double frames_per_second(); 492 bool decoder_deleted() { return !decoder_.get(); } 493 494 private: 495 typedef std::map<int, media::PictureBuffer*> PictureBufferById; 496 497 void SetState(ClientState new_state); 498 499 // Delete the associated decoder helper. 500 void DeleteDecoder(); 501 502 // Compute & return the first encoded bytes (including a start frame) to send 503 // to the decoder, starting at |start_pos| and returning 504 // |num_fragments_per_decode| units. Skips to the first decodable position. 505 std::string GetBytesForFirstFragments(size_t start_pos, size_t* end_pos); 506 // Compute & return the next encoded bytes to send to the decoder (based on 507 // |start_pos| & |num_fragments_per_decode_|). 508 std::string GetBytesForNextFragments(size_t start_pos, size_t* end_pos); 509 // Helpers for GetRangeForNextFragments above. 510 void GetBytesForNextNALU(size_t start_pos, size_t* end_pos); // For h.264. 511 std::string GetBytesForNextFrames( 512 size_t start_pos, size_t* end_pos); // For VP8. 513 514 // Request decode of the next batch of fragments in the encoded data. 515 void DecodeNextFragments(); 516 517 RenderingHelper* rendering_helper_; 518 int rendering_window_id_; 519 std::string encoded_data_; 520 const int num_fragments_per_decode_; 521 const int num_in_flight_decodes_; 522 int outstanding_decodes_; 523 size_t encoded_data_next_pos_to_decode_; 524 int next_bitstream_buffer_id_; 525 ClientStateNotification* note_; 526 scoped_ptr<VideoDecodeAccelerator> decoder_; 527 std::set<int> outstanding_texture_ids_; 528 int remaining_play_throughs_; 529 int reset_after_frame_num_; 530 int delete_decoder_state_; 531 ClientState state_; 532 int num_skipped_fragments_; 533 int num_queued_fragments_; 534 int num_decoded_frames_; 535 int num_done_bitstream_buffers_; 536 PictureBufferById picture_buffers_by_id_; 537 base::TimeTicks initialize_done_ticks_; 538 int profile_; 539 bool suppress_rendering_; 540 std::vector<base::TimeTicks> frame_delivery_times_; 541 int delay_reuse_after_frame_num_; 542 scoped_ptr<ThrottlingVDAClient> throttling_client_; 543 544 DISALLOW_IMPLICIT_CONSTRUCTORS(GLRenderingVDAClient); 545 }; 546 547 GLRenderingVDAClient::GLRenderingVDAClient(RenderingHelper* rendering_helper, 548 int rendering_window_id, 549 ClientStateNotification* note, 550 const std::string& encoded_data, 551 int num_fragments_per_decode, 552 int num_in_flight_decodes, 553 int num_play_throughs, 554 int reset_after_frame_num, 555 int delete_decoder_state, 556 int frame_width, 557 int frame_height, 558 int profile, 559 double rendering_fps, 560 bool suppress_rendering, 561 int delay_reuse_after_frame_num) 562 : rendering_helper_(rendering_helper), 563 rendering_window_id_(rendering_window_id), 564 encoded_data_(encoded_data), 565 num_fragments_per_decode_(num_fragments_per_decode), 566 num_in_flight_decodes_(num_in_flight_decodes), 567 outstanding_decodes_(0), 568 encoded_data_next_pos_to_decode_(0), 569 next_bitstream_buffer_id_(0), 570 note_(note), 571 remaining_play_throughs_(num_play_throughs), 572 reset_after_frame_num_(reset_after_frame_num), 573 delete_decoder_state_(delete_decoder_state), 574 state_(CS_CREATED), 575 num_skipped_fragments_(0), 576 num_queued_fragments_(0), 577 num_decoded_frames_(0), 578 num_done_bitstream_buffers_(0), 579 profile_(profile), 580 suppress_rendering_(suppress_rendering), 581 delay_reuse_after_frame_num_(delay_reuse_after_frame_num) { 582 CHECK_GT(num_fragments_per_decode, 0); 583 CHECK_GT(num_in_flight_decodes, 0); 584 CHECK_GT(num_play_throughs, 0); 585 CHECK_GE(rendering_fps, 0); 586 if (rendering_fps > 0) 587 throttling_client_.reset(new ThrottlingVDAClient( 588 this, 589 rendering_fps, 590 base::Bind(&GLRenderingVDAClient::NotifyFrameDropped, 591 base::Unretained(this)))); 592 } 593 594 GLRenderingVDAClient::~GLRenderingVDAClient() { 595 DeleteDecoder(); // Clean up in case of expected error. 596 CHECK(decoder_deleted()); 597 STLDeleteValues(&picture_buffers_by_id_); 598 SetState(CS_DESTROYED); 599 } 600 601 static bool DoNothingReturnTrue() { return true; } 602 603 void GLRenderingVDAClient::CreateDecoder() { 604 CHECK(decoder_deleted()); 605 CHECK(!decoder_.get()); 606 607 VideoDecodeAccelerator::Client* client = this; 608 if (throttling_client_) 609 client = throttling_client_.get(); 610 #if defined(OS_WIN) 611 decoder_.reset( 612 new DXVAVideoDecodeAccelerator(client, base::Bind(&DoNothingReturnTrue))); 613 #elif defined(OS_CHROMEOS) 614 #if defined(ARCH_CPU_ARMEL) 615 decoder_.reset(new ExynosVideoDecodeAccelerator( 616 static_cast<EGLDisplay>(rendering_helper_->GetGLDisplay()), 617 static_cast<EGLContext>(rendering_helper_->GetGLContext()), 618 client, 619 base::Bind(&DoNothingReturnTrue))); 620 #elif defined(ARCH_CPU_X86_FAMILY) 621 decoder_.reset(new VaapiVideoDecodeAccelerator( 622 static_cast<Display*>(rendering_helper_->GetGLDisplay()), 623 static_cast<GLXContext>(rendering_helper_->GetGLContext()), 624 client, 625 base::Bind(&DoNothingReturnTrue))); 626 #endif // ARCH_CPU_ARMEL 627 #endif // OS_WIN 628 CHECK(decoder_.get()); 629 SetState(CS_DECODER_SET); 630 if (decoder_deleted()) 631 return; 632 633 // Configure the decoder. 634 media::VideoCodecProfile profile = media::H264PROFILE_BASELINE; 635 if (profile_ != -1) 636 profile = static_cast<media::VideoCodecProfile>(profile_); 637 CHECK(decoder_->Initialize(profile)); 638 } 639 640 void GLRenderingVDAClient::ProvidePictureBuffers( 641 uint32 requested_num_of_buffers, 642 const gfx::Size& dimensions, 643 uint32 texture_target) { 644 if (decoder_deleted()) 645 return; 646 std::vector<media::PictureBuffer> buffers; 647 648 for (uint32 i = 0; i < requested_num_of_buffers; ++i) { 649 uint32 id = picture_buffers_by_id_.size(); 650 uint32 texture_id; 651 base::WaitableEvent done(false, false); 652 rendering_helper_->CreateTexture( 653 rendering_window_id_, texture_target, &texture_id, &done); 654 done.Wait(); 655 CHECK(outstanding_texture_ids_.insert(texture_id).second); 656 media::PictureBuffer* buffer = 657 new media::PictureBuffer(id, dimensions, texture_id); 658 CHECK(picture_buffers_by_id_.insert(std::make_pair(id, buffer)).second); 659 buffers.push_back(*buffer); 660 } 661 decoder_->AssignPictureBuffers(buffers); 662 } 663 664 void GLRenderingVDAClient::DismissPictureBuffer(int32 picture_buffer_id) { 665 PictureBufferById::iterator it = 666 picture_buffers_by_id_.find(picture_buffer_id); 667 CHECK(it != picture_buffers_by_id_.end()); 668 CHECK_EQ(outstanding_texture_ids_.erase(it->second->texture_id()), 1U); 669 rendering_helper_->DeleteTexture(it->second->texture_id()); 670 delete it->second; 671 picture_buffers_by_id_.erase(it); 672 } 673 674 void GLRenderingVDAClient::PictureReady(const media::Picture& picture) { 675 // We shouldn't be getting pictures delivered after Reset has completed. 676 CHECK_LT(state_, CS_RESET); 677 678 if (decoder_deleted()) 679 return; 680 681 frame_delivery_times_.push_back(base::TimeTicks::Now()); 682 683 CHECK_LE(picture.bitstream_buffer_id(), next_bitstream_buffer_id_); 684 ++num_decoded_frames_; 685 686 // Mid-stream reset applies only to the last play-through per constructor 687 // comment. 688 if (remaining_play_throughs_ == 1 && 689 reset_after_frame_num_ == num_decoded_frames()) { 690 reset_after_frame_num_ = MID_STREAM_RESET; 691 decoder_->Reset(); 692 // Re-start decoding from the beginning of the stream to avoid needing to 693 // know how to find I-frames and so on in this test. 694 encoded_data_next_pos_to_decode_ = 0; 695 } 696 697 media::PictureBuffer* picture_buffer = 698 picture_buffers_by_id_[picture.picture_buffer_id()]; 699 CHECK(picture_buffer); 700 if (!suppress_rendering_) { 701 rendering_helper_->RenderTexture(picture_buffer->texture_id()); 702 } 703 704 if (num_decoded_frames() > delay_reuse_after_frame_num_) { 705 base::MessageLoop::current()->PostDelayedTask( 706 FROM_HERE, 707 base::Bind(&VideoDecodeAccelerator::ReusePictureBuffer, 708 decoder_->AsWeakPtr(), 709 picture.picture_buffer_id()), 710 kReuseDelay); 711 } else { 712 decoder_->ReusePictureBuffer(picture.picture_buffer_id()); 713 } 714 } 715 716 void GLRenderingVDAClient::NotifyInitializeDone() { 717 SetState(CS_INITIALIZED); 718 initialize_done_ticks_ = base::TimeTicks::Now(); 719 720 if (reset_after_frame_num_ == START_OF_STREAM_RESET) { 721 decoder_->Reset(); 722 return; 723 } 724 725 for (int i = 0; i < num_in_flight_decodes_; ++i) 726 DecodeNextFragments(); 727 DCHECK_EQ(outstanding_decodes_, num_in_flight_decodes_); 728 } 729 730 void GLRenderingVDAClient::NotifyEndOfBitstreamBuffer( 731 int32 bitstream_buffer_id) { 732 // TODO(fischman): this test currently relies on this notification to make 733 // forward progress during a Reset(). But the VDA::Reset() API doesn't 734 // guarantee this, so stop relying on it (and remove the notifications from 735 // VaapiVideoDecodeAccelerator::FinishReset()). 736 ++num_done_bitstream_buffers_; 737 --outstanding_decodes_; 738 DecodeNextFragments(); 739 } 740 741 void GLRenderingVDAClient::NotifyFlushDone() { 742 if (decoder_deleted()) 743 return; 744 SetState(CS_FLUSHED); 745 --remaining_play_throughs_; 746 DCHECK_GE(remaining_play_throughs_, 0); 747 if (decoder_deleted()) 748 return; 749 decoder_->Reset(); 750 SetState(CS_RESETTING); 751 } 752 753 void GLRenderingVDAClient::NotifyResetDone() { 754 if (decoder_deleted()) 755 return; 756 757 if (reset_after_frame_num_ == MID_STREAM_RESET) { 758 reset_after_frame_num_ = END_OF_STREAM_RESET; 759 DecodeNextFragments(); 760 return; 761 } else if (reset_after_frame_num_ == START_OF_STREAM_RESET) { 762 reset_after_frame_num_ = END_OF_STREAM_RESET; 763 for (int i = 0; i < num_in_flight_decodes_; ++i) 764 DecodeNextFragments(); 765 return; 766 } 767 768 if (remaining_play_throughs_) { 769 encoded_data_next_pos_to_decode_ = 0; 770 NotifyInitializeDone(); 771 return; 772 } 773 774 SetState(CS_RESET); 775 if (!decoder_deleted()) 776 DeleteDecoder(); 777 } 778 779 void GLRenderingVDAClient::NotifyError(VideoDecodeAccelerator::Error error) { 780 SetState(CS_ERROR); 781 } 782 783 void GLRenderingVDAClient::OutputFrameDeliveryTimes(base::PlatformFile output) { 784 std::string s = base::StringPrintf("frame count: %" PRIuS "\n", 785 frame_delivery_times_.size()); 786 base::WritePlatformFileAtCurrentPos(output, s.data(), s.length()); 787 base::TimeTicks t0 = initialize_done_ticks_; 788 for (size_t i = 0; i < frame_delivery_times_.size(); ++i) { 789 s = base::StringPrintf("frame %04" PRIuS ": %" PRId64 " us\n", 790 i, 791 (frame_delivery_times_[i] - t0).InMicroseconds()); 792 t0 = frame_delivery_times_[i]; 793 base::WritePlatformFileAtCurrentPos(output, s.data(), s.length()); 794 } 795 } 796 797 void GLRenderingVDAClient::NotifyFrameDropped(int32 picture_buffer_id) { 798 decoder_->ReusePictureBuffer(picture_buffer_id); 799 } 800 801 static bool LookingAtNAL(const std::string& encoded, size_t pos) { 802 return encoded[pos] == 0 && encoded[pos + 1] == 0 && 803 encoded[pos + 2] == 0 && encoded[pos + 3] == 1; 804 } 805 806 void GLRenderingVDAClient::SetState(ClientState new_state) { 807 note_->Notify(new_state); 808 state_ = new_state; 809 if (!remaining_play_throughs_ && new_state == delete_decoder_state_) { 810 CHECK(!decoder_deleted()); 811 DeleteDecoder(); 812 } 813 } 814 815 void GLRenderingVDAClient::DeleteDecoder() { 816 if (decoder_deleted()) 817 return; 818 decoder_.release()->Destroy(); 819 STLClearObject(&encoded_data_); 820 for (std::set<int>::iterator it = outstanding_texture_ids_.begin(); 821 it != outstanding_texture_ids_.end(); ++it) { 822 rendering_helper_->DeleteTexture(*it); 823 } 824 outstanding_texture_ids_.clear(); 825 // Cascade through the rest of the states to simplify test code below. 826 for (int i = state_ + 1; i < CS_MAX; ++i) 827 SetState(static_cast<ClientState>(i)); 828 } 829 830 std::string GLRenderingVDAClient::GetBytesForFirstFragments( 831 size_t start_pos, size_t* end_pos) { 832 if (profile_ < media::H264PROFILE_MAX) { 833 *end_pos = start_pos; 834 while (*end_pos + 4 < encoded_data_.size()) { 835 if ((encoded_data_[*end_pos + 4] & 0x1f) == 0x7) // SPS start frame 836 return GetBytesForNextFragments(*end_pos, end_pos); 837 GetBytesForNextNALU(*end_pos, end_pos); 838 num_skipped_fragments_++; 839 } 840 *end_pos = start_pos; 841 return std::string(); 842 } 843 DCHECK_LE(profile_, media::VP8PROFILE_MAX); 844 return GetBytesForNextFragments(start_pos, end_pos); 845 } 846 847 std::string GLRenderingVDAClient::GetBytesForNextFragments( 848 size_t start_pos, size_t* end_pos) { 849 if (profile_ < media::H264PROFILE_MAX) { 850 size_t new_end_pos = start_pos; 851 *end_pos = start_pos; 852 for (int i = 0; i < num_fragments_per_decode_; ++i) { 853 GetBytesForNextNALU(*end_pos, &new_end_pos); 854 if (*end_pos == new_end_pos) 855 break; 856 *end_pos = new_end_pos; 857 num_queued_fragments_++; 858 } 859 return encoded_data_.substr(start_pos, *end_pos - start_pos); 860 } 861 DCHECK_LE(profile_, media::VP8PROFILE_MAX); 862 return GetBytesForNextFrames(start_pos, end_pos); 863 } 864 865 void GLRenderingVDAClient::GetBytesForNextNALU( 866 size_t start_pos, size_t* end_pos) { 867 *end_pos = start_pos; 868 if (*end_pos + 4 > encoded_data_.size()) 869 return; 870 CHECK(LookingAtNAL(encoded_data_, start_pos)); 871 *end_pos += 4; 872 while (*end_pos + 4 <= encoded_data_.size() && 873 !LookingAtNAL(encoded_data_, *end_pos)) { 874 ++*end_pos; 875 } 876 if (*end_pos + 3 >= encoded_data_.size()) 877 *end_pos = encoded_data_.size(); 878 } 879 880 std::string GLRenderingVDAClient::GetBytesForNextFrames( 881 size_t start_pos, size_t* end_pos) { 882 // Helpful description: http://wiki.multimedia.cx/index.php?title=IVF 883 std::string bytes; 884 if (start_pos == 0) 885 start_pos = 32; // Skip IVF header. 886 *end_pos = start_pos; 887 for (int i = 0; i < num_fragments_per_decode_; ++i) { 888 uint32 frame_size = *reinterpret_cast<uint32*>(&encoded_data_[*end_pos]); 889 *end_pos += 12; // Skip frame header. 890 bytes.append(encoded_data_.substr(*end_pos, frame_size)); 891 *end_pos += frame_size; 892 num_queued_fragments_++; 893 if (*end_pos + 12 >= encoded_data_.size()) 894 return bytes; 895 } 896 return bytes; 897 } 898 899 void GLRenderingVDAClient::DecodeNextFragments() { 900 if (decoder_deleted()) 901 return; 902 if (encoded_data_next_pos_to_decode_ == encoded_data_.size()) { 903 if (outstanding_decodes_ == 0) { 904 decoder_->Flush(); 905 SetState(CS_FLUSHING); 906 } 907 return; 908 } 909 size_t end_pos; 910 std::string next_fragment_bytes; 911 if (encoded_data_next_pos_to_decode_ == 0) { 912 next_fragment_bytes = GetBytesForFirstFragments(0, &end_pos); 913 } else { 914 next_fragment_bytes = 915 GetBytesForNextFragments(encoded_data_next_pos_to_decode_, &end_pos); 916 } 917 size_t next_fragment_size = next_fragment_bytes.size(); 918 919 // Populate the shared memory buffer w/ the fragments, duplicate its handle, 920 // and hand it off to the decoder. 921 base::SharedMemory shm; 922 CHECK(shm.CreateAndMapAnonymous(next_fragment_size)); 923 memcpy(shm.memory(), next_fragment_bytes.data(), next_fragment_size); 924 base::SharedMemoryHandle dup_handle; 925 CHECK(shm.ShareToProcess(base::Process::Current().handle(), &dup_handle)); 926 media::BitstreamBuffer bitstream_buffer( 927 next_bitstream_buffer_id_, dup_handle, next_fragment_size); 928 // Mask against 30 bits, to avoid (undefined) wraparound on signed integer. 929 next_bitstream_buffer_id_ = (next_bitstream_buffer_id_ + 1) & 0x3FFFFFFF; 930 decoder_->Decode(bitstream_buffer); 931 ++outstanding_decodes_; 932 encoded_data_next_pos_to_decode_ = end_pos; 933 934 if (!remaining_play_throughs_ && 935 -delete_decoder_state_ == next_bitstream_buffer_id_) { 936 DeleteDecoder(); 937 } 938 } 939 940 int GLRenderingVDAClient::num_decoded_frames() { 941 return throttling_client_ ? throttling_client_->num_decoded_frames() 942 : num_decoded_frames_; 943 } 944 945 double GLRenderingVDAClient::frames_per_second() { 946 base::TimeDelta delta = frame_delivery_times_.back() - initialize_done_ticks_; 947 if (delta.InSecondsF() == 0) 948 return 0; 949 return num_decoded_frames() / delta.InSecondsF(); 950 } 951 952 // Test parameters: 953 // - Number of fragments per Decode() call. 954 // - Number of concurrent decoders. 955 // - Number of concurrent in-flight Decode() calls per decoder. 956 // - Number of play-throughs. 957 // - reset_after_frame_num: see GLRenderingVDAClient ctor. 958 // - delete_decoder_phase: see GLRenderingVDAClient ctor. 959 // - whether to test slow rendering by delaying ReusePictureBuffer(). 960 // - whether the video frames are rendered as thumbnails. 961 class VideoDecodeAcceleratorTest 962 : public ::testing::TestWithParam< 963 Tuple8<int, int, int, int, ResetPoint, ClientState, bool, bool> > { 964 }; 965 966 // Helper so that gtest failures emit a more readable version of the tuple than 967 // its byte representation. 968 ::std::ostream& operator<<( 969 ::std::ostream& os, 970 const Tuple8<int, int, int, int, ResetPoint, ClientState, bool, bool>& t) { 971 return os << t.a << ", " << t.b << ", " << t.c << ", " << t.d << ", " << t.e 972 << ", " << t.f << ", " << t.g << ", " << t.h; 973 } 974 975 // Wait for |note| to report a state and if it's not |expected_state| then 976 // assert |client| has deleted its decoder. 977 static void AssertWaitForStateOrDeleted(ClientStateNotification* note, 978 GLRenderingVDAClient* client, 979 ClientState expected_state) { 980 ClientState state = note->Wait(); 981 if (state == expected_state) return; 982 ASSERT_TRUE(client->decoder_deleted()) 983 << "Decoder not deleted but Wait() returned " << state 984 << ", instead of " << expected_state; 985 } 986 987 // We assert a minimal number of concurrent decoders we expect to succeed. 988 // Different platforms can support more concurrent decoders, so we don't assert 989 // failure above this. 990 enum { kMinSupportedNumConcurrentDecoders = 3 }; 991 992 // Test the most straightforward case possible: data is decoded from a single 993 // chunk and rendered to the screen. 994 TEST_P(VideoDecodeAcceleratorTest, TestSimpleDecode) { 995 // Required for Thread to work. Not used otherwise. 996 base::ShadowingAtExitManager at_exit_manager; 997 998 const int num_fragments_per_decode = GetParam().a; 999 const size_t num_concurrent_decoders = GetParam().b; 1000 const size_t num_in_flight_decodes = GetParam().c; 1001 const int num_play_throughs = GetParam().d; 1002 const int reset_point = GetParam().e; 1003 const int delete_decoder_state = GetParam().f; 1004 bool test_reuse_delay = GetParam().g; 1005 const bool render_as_thumbnails = GetParam().h; 1006 1007 std::vector<TestVideoFile*> test_video_files; 1008 ParseAndReadTestVideoData(g_test_video_data, 1009 num_concurrent_decoders, 1010 reset_point, 1011 &test_video_files); 1012 1013 // Suppress GL rendering for all tests when the "--disable_rendering" is set. 1014 // Otherwise, suppress rendering in all but a few tests, to cut down overall 1015 // test runtime. 1016 const bool suppress_rendering = 1017 num_fragments_per_decode > 1 || g_disable_rendering; 1018 1019 std::vector<ClientStateNotification*> notes(num_concurrent_decoders, NULL); 1020 std::vector<GLRenderingVDAClient*> clients(num_concurrent_decoders, NULL); 1021 1022 // Initialize the rendering helper. 1023 base::Thread rendering_thread("GLRenderingVDAClientThread"); 1024 base::Thread::Options options; 1025 options.message_loop_type = base::MessageLoop::TYPE_DEFAULT; 1026 #if defined(OS_WIN) 1027 // For windows the decoding thread initializes the media foundation decoder 1028 // which uses COM. We need the thread to be a UI thread. 1029 options.message_loop_type = base::MessageLoop::TYPE_UI; 1030 #endif // OS_WIN 1031 1032 rendering_thread.StartWithOptions(options); 1033 scoped_ptr<RenderingHelper> rendering_helper(RenderingHelper::Create()); 1034 1035 base::WaitableEvent done(false, false); 1036 RenderingHelperParams helper_params; 1037 helper_params.num_windows = num_concurrent_decoders; 1038 helper_params.render_as_thumbnails = render_as_thumbnails; 1039 if (render_as_thumbnails) { 1040 // Only one decoder is supported with thumbnail rendering 1041 CHECK_EQ(num_concurrent_decoders, 1U); 1042 gfx::Size frame_size(test_video_files[0]->width, 1043 test_video_files[0]->height); 1044 helper_params.frame_dimensions.push_back(frame_size); 1045 helper_params.window_dimensions.push_back(kThumbnailsDisplaySize); 1046 helper_params.thumbnails_page_size = kThumbnailsPageSize; 1047 helper_params.thumbnail_size = kThumbnailSize; 1048 } else { 1049 for (size_t index = 0; index < test_video_files.size(); ++index) { 1050 gfx::Size frame_size(test_video_files[index]->width, 1051 test_video_files[index]->height); 1052 helper_params.frame_dimensions.push_back(frame_size); 1053 helper_params.window_dimensions.push_back(frame_size); 1054 } 1055 } 1056 rendering_thread.message_loop()->PostTask( 1057 FROM_HERE, 1058 base::Bind(&RenderingHelper::Initialize, 1059 base::Unretained(rendering_helper.get()), 1060 helper_params, 1061 &done)); 1062 done.Wait(); 1063 1064 // First kick off all the decoders. 1065 for (size_t index = 0; index < num_concurrent_decoders; ++index) { 1066 TestVideoFile* video_file = 1067 test_video_files[index % test_video_files.size()]; 1068 ClientStateNotification* note = new ClientStateNotification(); 1069 notes[index] = note; 1070 1071 int delay_after_frame_num = std::numeric_limits<int>::max(); 1072 if (test_reuse_delay && 1073 kMaxFramesToDelayReuse * 2 < video_file->num_frames) { 1074 delay_after_frame_num = video_file->num_frames - kMaxFramesToDelayReuse; 1075 } 1076 1077 GLRenderingVDAClient* client = 1078 new GLRenderingVDAClient(rendering_helper.get(), 1079 index, 1080 note, 1081 video_file->data_str, 1082 num_fragments_per_decode, 1083 num_in_flight_decodes, 1084 num_play_throughs, 1085 video_file->reset_after_frame_num, 1086 delete_decoder_state, 1087 video_file->width, 1088 video_file->height, 1089 video_file->profile, 1090 g_rendering_fps, 1091 suppress_rendering, 1092 delay_after_frame_num); 1093 clients[index] = client; 1094 1095 rendering_thread.message_loop()->PostTask( 1096 FROM_HERE, 1097 base::Bind(&GLRenderingVDAClient::CreateDecoder, 1098 base::Unretained(client))); 1099 1100 ASSERT_EQ(note->Wait(), CS_DECODER_SET); 1101 } 1102 // Then wait for all the decodes to finish. 1103 // Only check performance & correctness later if we play through only once. 1104 bool skip_performance_and_correctness_checks = num_play_throughs > 1; 1105 for (size_t i = 0; i < num_concurrent_decoders; ++i) { 1106 ClientStateNotification* note = notes[i]; 1107 ClientState state = note->Wait(); 1108 if (state != CS_INITIALIZED) { 1109 skip_performance_and_correctness_checks = true; 1110 // We expect initialization to fail only when more than the supported 1111 // number of decoders is instantiated. Assert here that something else 1112 // didn't trigger failure. 1113 ASSERT_GT(num_concurrent_decoders, 1114 static_cast<size_t>(kMinSupportedNumConcurrentDecoders)); 1115 continue; 1116 } 1117 ASSERT_EQ(state, CS_INITIALIZED); 1118 for (int n = 0; n < num_play_throughs; ++n) { 1119 // For play-throughs other than the first, we expect initialization to 1120 // succeed unconditionally. 1121 if (n > 0) { 1122 ASSERT_NO_FATAL_FAILURE( 1123 AssertWaitForStateOrDeleted(note, clients[i], CS_INITIALIZED)); 1124 } 1125 // InitializeDone kicks off decoding inside the client, so we just need to 1126 // wait for Flush. 1127 ASSERT_NO_FATAL_FAILURE( 1128 AssertWaitForStateOrDeleted(note, clients[i], CS_FLUSHING)); 1129 ASSERT_NO_FATAL_FAILURE( 1130 AssertWaitForStateOrDeleted(note, clients[i], CS_FLUSHED)); 1131 // FlushDone requests Reset(). 1132 ASSERT_NO_FATAL_FAILURE( 1133 AssertWaitForStateOrDeleted(note, clients[i], CS_RESETTING)); 1134 } 1135 ASSERT_NO_FATAL_FAILURE( 1136 AssertWaitForStateOrDeleted(note, clients[i], CS_RESET)); 1137 // ResetDone requests Destroy(). 1138 ASSERT_NO_FATAL_FAILURE( 1139 AssertWaitForStateOrDeleted(note, clients[i], CS_DESTROYED)); 1140 } 1141 // Finally assert that decoding went as expected. 1142 for (size_t i = 0; i < num_concurrent_decoders && 1143 !skip_performance_and_correctness_checks; ++i) { 1144 // We can only make performance/correctness assertions if the decoder was 1145 // allowed to finish. 1146 if (delete_decoder_state < CS_FLUSHED) 1147 continue; 1148 GLRenderingVDAClient* client = clients[i]; 1149 TestVideoFile* video_file = test_video_files[i % test_video_files.size()]; 1150 if (video_file->num_frames > 0) { 1151 // Expect the decoded frames may be more than the video frames as frames 1152 // could still be returned until resetting done. 1153 if (video_file->reset_after_frame_num > 0) 1154 EXPECT_GE(client->num_decoded_frames(), video_file->num_frames); 1155 else 1156 EXPECT_EQ(client->num_decoded_frames(), video_file->num_frames); 1157 } 1158 if (reset_point == END_OF_STREAM_RESET) { 1159 EXPECT_EQ(video_file->num_fragments, client->num_skipped_fragments() + 1160 client->num_queued_fragments()); 1161 EXPECT_EQ(client->num_done_bitstream_buffers(), 1162 ceil(static_cast<double>(client->num_queued_fragments()) / 1163 num_fragments_per_decode)); 1164 } 1165 LOG(INFO) << "Decoder " << i << " fps: " << client->frames_per_second(); 1166 if (!render_as_thumbnails) { 1167 int min_fps = suppress_rendering ? 1168 video_file->min_fps_no_render : video_file->min_fps_render; 1169 if (min_fps > 0 && !test_reuse_delay) 1170 EXPECT_GT(client->frames_per_second(), min_fps); 1171 } 1172 } 1173 1174 if (render_as_thumbnails) { 1175 std::vector<unsigned char> rgb; 1176 bool alpha_solid; 1177 rendering_thread.message_loop()->PostTask( 1178 FROM_HERE, 1179 base::Bind(&RenderingHelper::GetThumbnailsAsRGB, 1180 base::Unretained(rendering_helper.get()), 1181 &rgb, &alpha_solid, &done)); 1182 done.Wait(); 1183 1184 std::vector<std::string> golden_md5s; 1185 std::string md5_string = base::MD5String( 1186 base::StringPiece(reinterpret_cast<char*>(&rgb[0]), rgb.size())); 1187 ReadGoldenThumbnailMD5s(test_video_files[0], &golden_md5s); 1188 std::vector<std::string>::iterator match = 1189 find(golden_md5s.begin(), golden_md5s.end(), md5_string); 1190 if (match == golden_md5s.end()) { 1191 // Convert raw RGB into PNG for export. 1192 std::vector<unsigned char> png; 1193 gfx::PNGCodec::Encode(&rgb[0], 1194 gfx::PNGCodec::FORMAT_RGB, 1195 kThumbnailsPageSize, 1196 kThumbnailsPageSize.width() * 3, 1197 true, 1198 std::vector<gfx::PNGCodec::Comment>(), 1199 &png); 1200 1201 LOG(ERROR) << "Unknown thumbnails MD5: " << md5_string; 1202 1203 base::FilePath filepath(test_video_files[0]->file_name); 1204 filepath = filepath.AddExtension(FILE_PATH_LITERAL(".bad_thumbnails")); 1205 filepath = filepath.AddExtension(FILE_PATH_LITERAL(".png")); 1206 int num_bytes = file_util::WriteFile(filepath, 1207 reinterpret_cast<char*>(&png[0]), 1208 png.size()); 1209 ASSERT_EQ(num_bytes, static_cast<int>(png.size())); 1210 } 1211 ASSERT_NE(match, golden_md5s.end()); 1212 EXPECT_EQ(alpha_solid, true) << "RGBA frame had incorrect alpha"; 1213 } 1214 1215 // Output the frame delivery time to file 1216 // We can only make performance/correctness assertions if the decoder was 1217 // allowed to finish. 1218 if (g_frame_delivery_log != NULL && delete_decoder_state >= CS_FLUSHED) { 1219 base::PlatformFile output_file = base::CreatePlatformFile( 1220 base::FilePath(g_frame_delivery_log), 1221 base::PLATFORM_FILE_CREATE_ALWAYS | base::PLATFORM_FILE_WRITE, 1222 NULL, 1223 NULL); 1224 for (size_t i = 0; i < num_concurrent_decoders; ++i) { 1225 clients[i]->OutputFrameDeliveryTimes(output_file); 1226 } 1227 base::ClosePlatformFile(output_file); 1228 } 1229 1230 rendering_thread.message_loop()->PostTask( 1231 FROM_HERE, 1232 base::Bind(&STLDeleteElements<std::vector<GLRenderingVDAClient*> >, 1233 &clients)); 1234 rendering_thread.message_loop()->PostTask( 1235 FROM_HERE, 1236 base::Bind(&STLDeleteElements<std::vector<ClientStateNotification*> >, 1237 ¬es)); 1238 rendering_thread.message_loop()->PostTask( 1239 FROM_HERE, 1240 base::Bind(&STLDeleteElements<std::vector<TestVideoFile*> >, 1241 &test_video_files)); 1242 rendering_thread.message_loop()->PostTask( 1243 FROM_HERE, 1244 base::Bind(&RenderingHelper::UnInitialize, 1245 base::Unretained(rendering_helper.get()), 1246 &done)); 1247 done.Wait(); 1248 rendering_thread.Stop(); 1249 }; 1250 1251 // Test that replay after EOS works fine. 1252 INSTANTIATE_TEST_CASE_P( 1253 ReplayAfterEOS, VideoDecodeAcceleratorTest, 1254 ::testing::Values( 1255 MakeTuple(1, 1, 1, 4, END_OF_STREAM_RESET, CS_RESET, false, false))); 1256 1257 // This hangs on Exynos, preventing further testing and wasting test machine 1258 // time. 1259 // TODO(ihf): Enable again once http://crbug.com/269754 is fixed. 1260 #if defined(ARCH_CPU_X86_FAMILY) 1261 // Test that Reset() before the first Decode() works fine. 1262 INSTANTIATE_TEST_CASE_P( 1263 ResetBeforeDecode, VideoDecodeAcceleratorTest, 1264 ::testing::Values( 1265 MakeTuple(1, 1, 1, 1, START_OF_STREAM_RESET, CS_RESET, false, false))); 1266 #endif // ARCH_CPU_X86_FAMILY 1267 1268 // Test that Reset() mid-stream works fine and doesn't affect decoding even when 1269 // Decode() calls are made during the reset. 1270 INSTANTIATE_TEST_CASE_P( 1271 MidStreamReset, VideoDecodeAcceleratorTest, 1272 ::testing::Values( 1273 MakeTuple(1, 1, 1, 1, MID_STREAM_RESET, CS_RESET, false, false))); 1274 1275 INSTANTIATE_TEST_CASE_P( 1276 SlowRendering, VideoDecodeAcceleratorTest, 1277 ::testing::Values( 1278 MakeTuple(1, 1, 1, 1, END_OF_STREAM_RESET, CS_RESET, true, false))); 1279 1280 // Test that Destroy() mid-stream works fine (primarily this is testing that no 1281 // crashes occur). 1282 INSTANTIATE_TEST_CASE_P( 1283 TearDownTiming, VideoDecodeAcceleratorTest, 1284 ::testing::Values( 1285 MakeTuple(1, 1, 1, 1, END_OF_STREAM_RESET, CS_DECODER_SET, false, 1286 false), 1287 MakeTuple(1, 1, 1, 1, END_OF_STREAM_RESET, CS_INITIALIZED, false, 1288 false), 1289 MakeTuple(1, 1, 1, 1, END_OF_STREAM_RESET, CS_FLUSHING, false, false), 1290 MakeTuple(1, 1, 1, 1, END_OF_STREAM_RESET, CS_FLUSHED, false, false), 1291 MakeTuple(1, 1, 1, 1, END_OF_STREAM_RESET, CS_RESETTING, false, false), 1292 MakeTuple(1, 1, 1, 1, END_OF_STREAM_RESET, CS_RESET, false, false), 1293 MakeTuple(1, 1, 1, 1, END_OF_STREAM_RESET, 1294 static_cast<ClientState>(-1), false, false), 1295 MakeTuple(1, 1, 1, 1, END_OF_STREAM_RESET, 1296 static_cast<ClientState>(-10), false, false), 1297 MakeTuple(1, 1, 1, 1, END_OF_STREAM_RESET, 1298 static_cast<ClientState>(-100), false, false))); 1299 1300 // Test that decoding various variation works: multiple fragments per Decode() 1301 // call and multiple in-flight decodes. 1302 INSTANTIATE_TEST_CASE_P( 1303 DecodeVariations, VideoDecodeAcceleratorTest, 1304 ::testing::Values( 1305 MakeTuple(1, 1, 1, 1, END_OF_STREAM_RESET, CS_RESET, false, false), 1306 MakeTuple(1, 1, 10, 1, END_OF_STREAM_RESET, CS_RESET, false, false), 1307 // Tests queuing. 1308 MakeTuple(1, 1, 15, 1, END_OF_STREAM_RESET, CS_RESET, false, false), 1309 MakeTuple(2, 1, 1, 1, END_OF_STREAM_RESET, CS_RESET, false, false), 1310 MakeTuple(3, 1, 1, 1, END_OF_STREAM_RESET, CS_RESET, false, false), 1311 MakeTuple(5, 1, 1, 1, END_OF_STREAM_RESET, CS_RESET, false, false), 1312 MakeTuple(8, 1, 1, 1, END_OF_STREAM_RESET, CS_RESET, false, false), 1313 // TODO(fischman): decoding more than 15 NALUs at once breaks decode - 1314 // visual artifacts are introduced as well as spurious frames are 1315 // delivered (more pictures are returned than NALUs are fed to the 1316 // decoder). Increase the "15" below when 1317 // http://code.google.com/p/chrome-os-partner/issues/detail?id=4378 is 1318 // fixed. 1319 MakeTuple(15, 1, 1, 1, END_OF_STREAM_RESET, CS_RESET, false, false))); 1320 1321 // Find out how many concurrent decoders can go before we exhaust system 1322 // resources. 1323 INSTANTIATE_TEST_CASE_P( 1324 ResourceExhaustion, VideoDecodeAcceleratorTest, 1325 ::testing::Values( 1326 // +0 hack below to promote enum to int. 1327 MakeTuple(1, kMinSupportedNumConcurrentDecoders + 0, 1, 1, 1328 END_OF_STREAM_RESET, CS_RESET, false, false), 1329 MakeTuple(1, kMinSupportedNumConcurrentDecoders + 1, 1, 1, 1330 END_OF_STREAM_RESET, CS_RESET, false, false))); 1331 1332 // Thumbnailing test 1333 INSTANTIATE_TEST_CASE_P( 1334 Thumbnail, VideoDecodeAcceleratorTest, 1335 ::testing::Values( 1336 MakeTuple(1, 1, 1, 1, END_OF_STREAM_RESET, CS_RESET, false, true))); 1337 1338 // TODO(fischman, vrk): add more tests! In particular: 1339 // - Test life-cycle: Seek/Stop/Pause/Play for a single decoder. 1340 // - Test alternate configurations 1341 // - Test failure conditions. 1342 // - Test frame size changes mid-stream 1343 1344 } // namespace 1345 } // namespace content 1346 1347 int main(int argc, char **argv) { 1348 testing::InitGoogleTest(&argc, argv); // Removes gtest-specific args. 1349 CommandLine::Init(argc, argv); 1350 1351 // Needed to enable DVLOG through --vmodule. 1352 logging::LoggingSettings settings; 1353 settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG; 1354 settings.dcheck_state = 1355 logging::ENABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS; 1356 CHECK(logging::InitLogging(settings)); 1357 1358 CommandLine* cmd_line = CommandLine::ForCurrentProcess(); 1359 DCHECK(cmd_line); 1360 1361 CommandLine::SwitchMap switches = cmd_line->GetSwitches(); 1362 for (CommandLine::SwitchMap::const_iterator it = switches.begin(); 1363 it != switches.end(); ++it) { 1364 if (it->first == "test_video_data") { 1365 content::g_test_video_data = it->second.c_str(); 1366 continue; 1367 } 1368 if (it->first == "frame_delivery_log") { 1369 content::g_frame_delivery_log = it->second.c_str(); 1370 continue; 1371 } 1372 if (it->first == "rendering_fps") { 1373 // On Windows, CommandLine::StringType is wstring. We need to convert 1374 // it to std::string first 1375 std::string input(it->second.begin(), it->second.end()); 1376 CHECK(base::StringToDouble(input, &content::g_rendering_fps)); 1377 continue; 1378 } 1379 if (it->first == "disable_rendering") { 1380 content::g_disable_rendering = true; 1381 continue; 1382 } 1383 if (it->first == "v" || it->first == "vmodule") 1384 continue; 1385 LOG(FATAL) << "Unexpected switch: " << it->first << ":" << it->second; 1386 } 1387 1388 base::ShadowingAtExitManager at_exit_manager; 1389 1390 #if defined(OS_WIN) 1391 content::DXVAVideoDecodeAccelerator::PreSandboxInitialization(); 1392 #elif defined(OS_CHROMEOS) 1393 #if defined(ARCH_CPU_ARMEL) 1394 content::ExynosVideoDecodeAccelerator::PreSandboxInitialization(); 1395 #elif defined(ARCH_CPU_X86_FAMILY) 1396 content::VaapiWrapper::PreSandboxInitialization(); 1397 #endif // ARCH_CPU_ARMEL 1398 #endif // OS_CHROMEOS 1399 1400 return RUN_ALL_TESTS(); 1401 } 1402