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

Side by Side Diff: content/common/gpu/media/omx_video_decode_accelerator_unittest.cc

Issue 7361010: Enable fire-and-forget Destroy of HW video decoder, and misc other improvements. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: vrk CR responses. Created 9 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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, and GLES2. 7 // - RenderingHelper is charged with interacting with X11, EGL, and GLES2.
8 // - ClientState is an enum for the state of the decode client used by the test. 8 // - ClientState is an enum for the state of the decode client used by the test.
9 // - ClientStateNotification is a barrier abstraction that allows the test code 9 // - ClientStateNotification is a barrier abstraction that allows the test code
10 // to be written sequentially and wait for the decode client to see certain 10 // to be written sequentially and wait for the decode client to see certain
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after
193 CHECK(eglChooseConfig(egl_display_, rgba8888, &egl_config, 1, &num_configs)) 193 CHECK(eglChooseConfig(egl_display_, rgba8888, &egl_config, 1, &num_configs))
194 << eglGetError(); 194 << eglGetError();
195 CHECK_GE(num_configs, 1); 195 CHECK_GE(num_configs, 1);
196 static EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}; 196 static EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
197 egl_context_ = eglCreateContext( 197 egl_context_ = eglCreateContext(
198 egl_display_, egl_config, EGL_NO_CONTEXT, context_attribs); 198 egl_display_, egl_config, EGL_NO_CONTEXT, context_attribs);
199 CHECK_NE(egl_context_, EGL_NO_CONTEXT) << eglGetError(); 199 CHECK_NE(egl_context_, EGL_NO_CONTEXT) << eglGetError();
200 200
201 // Per-window/surface X11 & EGL initialization. 201 // Per-window/surface X11 & EGL initialization.
202 for (int i = 0; i < num_windows; ++i) { 202 for (int i = 0; i < num_windows; ++i) {
203 // Arrange X windows side by side whimsically. 203 // Arrange X windows whimsically, with some padding.
204 int top_left_x = (width + 50) * i; 204 int top_left_x = (width + 20) * (i % 4);
205 int top_left_y = 100 + (i % 2) * 250; 205 int top_left_y = (height + 12) * (i % 3);
206 Window x_window = XCreateWindow( 206 Window x_window = XCreateWindow(
207 x_display_, DefaultRootWindow(x_display_), 207 x_display_, DefaultRootWindow(x_display_),
208 top_left_x, top_left_y, width_, height_, 208 top_left_x, top_left_y, width_, height_,
209 0 /* border width */, 209 0 /* border width */,
210 depth, CopyFromParent /* class */, CopyFromParent /* visual */, 210 depth, CopyFromParent /* class */, CopyFromParent /* visual */,
211 (CWBackPixel | CWOverrideRedirect), &window_attributes); 211 (CWBackPixel | CWOverrideRedirect), &window_attributes);
212 x_windows_.push_back(x_window); 212 x_windows_.push_back(x_window);
213 XStoreName(x_display_, x_window, "OmxVideoDecodeAcceleratorTest"); 213 XStoreName(x_display_, x_window, "OmxVideoDecodeAcceleratorTest");
214 XSelectInput(x_display_, x_window, ExposureMask); 214 XSelectInput(x_display_, x_window, ExposureMask);
215 XMapWindow(x_display_, x_window); 215 XMapWindow(x_display_, x_window);
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after
414 const gfx::Size& dimensions, 414 const gfx::Size& dimensions,
415 VideoDecodeAccelerator::MemoryType type); 415 VideoDecodeAccelerator::MemoryType type);
416 virtual void DismissPictureBuffer(int32 picture_buffer_id); 416 virtual void DismissPictureBuffer(int32 picture_buffer_id);
417 virtual void PictureReady(const media::Picture& picture); 417 virtual void PictureReady(const media::Picture& picture);
418 // Simple state changes. 418 // Simple state changes.
419 virtual void NotifyInitializeDone(); 419 virtual void NotifyInitializeDone();
420 virtual void NotifyEndOfStream(); 420 virtual void NotifyEndOfStream();
421 virtual void NotifyEndOfBitstreamBuffer(int32 bitstream_buffer_id); 421 virtual void NotifyEndOfBitstreamBuffer(int32 bitstream_buffer_id);
422 virtual void NotifyFlushDone(); 422 virtual void NotifyFlushDone();
423 virtual void NotifyResetDone(); 423 virtual void NotifyResetDone();
424 virtual void NotifyDestroyDone();
425 virtual void NotifyError(VideoDecodeAccelerator::Error error); 424 virtual void NotifyError(VideoDecodeAccelerator::Error error);
426 425
427 // Simple getters for inspecting the state of the Client. 426 // Simple getters for inspecting the state of the Client.
428 ClientState state() { return state_; } 427 ClientState state() { return state_; }
429 VideoDecodeAccelerator::Error error() { return error_; } 428 VideoDecodeAccelerator::Error error() { return error_; }
430 int num_done_bitstream_buffers() { return num_done_bitstream_buffers_; } 429 int num_done_bitstream_buffers() { return num_done_bitstream_buffers_; }
431 int num_decoded_frames() { return num_decoded_frames_; } 430 int num_decoded_frames() { return num_decoded_frames_; }
432 EGLDisplay egl_display() { return rendering_helper_->egl_display(); } 431 EGLDisplay egl_display() { return rendering_helper_->egl_display(); }
433 EGLContext egl_context() { return rendering_helper_->egl_context(); } 432 EGLContext egl_context() { return rendering_helper_->egl_context(); }
434 double frames_per_second(); 433 double frames_per_second();
435 bool decoder_deleted() { return !decoder_.get(); } 434 bool decoder_deleted() { return !decoder_; }
436 435
437 private: 436 private:
438 typedef std::map<int, media::GLESBuffer*> PictureBufferById; 437 typedef std::map<int, media::GLESBuffer*> PictureBufferById;
439 438
440 void SetState(ClientState new_state); 439 void SetState(ClientState new_state);
441 440
442 // Delete the associated OMX decoder helper. 441 // Delete the associated OMX decoder helper.
443 void DeleteDecoder(); 442 void DeleteDecoder();
444 443
445 // Compute & return in |*end_pos| the end position for the next batch of NALUs 444 // Compute & return in |*end_pos| the end position for the next batch of NALUs
446 // to ship to the decoder (based on |start_pos| & |num_NALUs_per_decode_|). 445 // to ship to the decoder (based on |start_pos| & |num_NALUs_per_decode_|).
447 void GetRangeForNextNALUs(size_t start_pos, size_t* end_pos); 446 void GetRangeForNextNALUs(size_t start_pos, size_t* end_pos);
448 447
449 // Request decode of the next batch of NALUs in the encoded data. 448 // Request decode of the next batch of NALUs in the encoded data.
450 void DecodeNextNALUs(); 449 void DecodeNextNALUs();
451 450
452 RenderingHelper* rendering_helper_; 451 RenderingHelper* rendering_helper_;
453 int rendering_window_id_; 452 int rendering_window_id_;
454 const std::string* encoded_data_; 453 const std::string* encoded_data_;
455 const int num_NALUs_per_decode_; 454 const int num_NALUs_per_decode_;
456 size_t encoded_data_next_pos_to_decode_; 455 size_t encoded_data_next_pos_to_decode_;
457 int next_bitstream_buffer_id_; 456 int next_bitstream_buffer_id_;
458 ClientStateNotification* note_; 457 ClientStateNotification* note_;
459 scoped_ptr<OmxVideoDecodeAccelerator> decoder_; 458 scoped_refptr<OmxVideoDecodeAccelerator> decoder_;
460 int delete_decoder_state_; 459 int delete_decoder_state_;
461 ClientState state_; 460 ClientState state_;
462 VideoDecodeAccelerator::Error error_; 461 VideoDecodeAccelerator::Error error_;
463 int num_decoded_frames_; 462 int num_decoded_frames_;
464 int num_done_bitstream_buffers_; 463 int num_done_bitstream_buffers_;
465 PictureBufferById picture_buffers_by_id_; 464 PictureBufferById picture_buffers_by_id_;
466 base::TimeTicks initialize_done_ticks_; 465 base::TimeTicks initialize_done_ticks_;
467 base::TimeTicks last_frame_delivered_ticks_; 466 base::TimeTicks last_frame_delivered_ticks_;
468 }; 467 };
469 468
470 EglRenderingVDAClient::EglRenderingVDAClient(RenderingHelper* rendering_helper, 469 EglRenderingVDAClient::EglRenderingVDAClient(RenderingHelper* rendering_helper,
471 int rendering_window_id, 470 int rendering_window_id,
472 ClientStateNotification* note, 471 ClientStateNotification* note,
473 std::string* encoded_data, 472 std::string* encoded_data,
474 int num_NALUs_per_decode, 473 int num_NALUs_per_decode,
475 int delete_decoder_state) 474 int delete_decoder_state)
476 : rendering_helper_(rendering_helper), 475 : rendering_helper_(rendering_helper),
477 rendering_window_id_(rendering_window_id), 476 rendering_window_id_(rendering_window_id),
478 encoded_data_(encoded_data), num_NALUs_per_decode_(num_NALUs_per_decode), 477 encoded_data_(encoded_data), num_NALUs_per_decode_(num_NALUs_per_decode),
479 encoded_data_next_pos_to_decode_(0), next_bitstream_buffer_id_(0), 478 encoded_data_next_pos_to_decode_(0), next_bitstream_buffer_id_(0),
480 note_(note), delete_decoder_state_(delete_decoder_state), 479 note_(note), delete_decoder_state_(delete_decoder_state),
481 state_(CS_CREATED), 480 state_(CS_CREATED),
482 error_(VideoDecodeAccelerator::VIDEODECODERERROR_NONE), 481 error_(VideoDecodeAccelerator::VIDEODECODERERROR_NONE),
483 num_decoded_frames_(0), num_done_bitstream_buffers_(0) { 482 num_decoded_frames_(0), num_done_bitstream_buffers_(0) {
484 CHECK_GT(num_NALUs_per_decode, 0); 483 CHECK_GT(num_NALUs_per_decode, 0);
485 } 484 }
486 485
487 EglRenderingVDAClient::~EglRenderingVDAClient() { 486 EglRenderingVDAClient::~EglRenderingVDAClient() {
488 CHECK(!decoder_.get()); 487 DeleteDecoder(); // Clean up in case of expected error.
488 CHECK(decoder_deleted());
489 STLDeleteValues(&picture_buffers_by_id_); 489 STLDeleteValues(&picture_buffers_by_id_);
490 SetState(CS_DESTROYED); 490 SetState(CS_DESTROYED);
491 } 491 }
492 492
493 void EglRenderingVDAClient::CreateDecoder() { 493 void EglRenderingVDAClient::CreateDecoder() {
494 CHECK(!decoder_.get()); 494 CHECK(decoder_deleted());
495 decoder_.reset(new OmxVideoDecodeAccelerator(this)); 495 decoder_ = new OmxVideoDecodeAccelerator(this);
496 decoder_->SetEglState(egl_display(), egl_context()); 496 decoder_->SetEglState(egl_display(), egl_context());
497 SetState(CS_DECODER_SET); 497 SetState(CS_DECODER_SET);
498 if (!decoder_.get()) 498 if (decoder_deleted())
499 return; 499 return;
500 500
501 // Configure the decoder. 501 // Configure the decoder.
502 int32 config_array[] = { 502 int32 config_array[] = {
503 media::VIDEOATTRIBUTEKEY_BITSTREAMFORMAT_FOURCC, 503 media::VIDEOATTRIBUTEKEY_BITSTREAMFORMAT_FOURCC,
504 media::VIDEOCODECFOURCC_H264, 504 media::VIDEOCODECFOURCC_H264,
505 media::VIDEOATTRIBUTEKEY_VIDEOCOLORFORMAT, media::VIDEOCOLORFORMAT_RGBA, 505 media::VIDEOATTRIBUTEKEY_VIDEOCOLORFORMAT, media::VIDEOCOLORFORMAT_RGBA,
506 }; 506 };
507 std::vector<uint32> config( 507 std::vector<uint32> config(
508 config_array, config_array + arraysize(config_array)); 508 config_array, config_array + arraysize(config_array));
509 CHECK(decoder_->Initialize(config)); 509 CHECK(decoder_->Initialize(config));
510 } 510 }
511 511
512 512
513 void EglRenderingVDAClient::ProvidePictureBuffers( 513 void EglRenderingVDAClient::ProvidePictureBuffers(
514 uint32 requested_num_of_buffers, 514 uint32 requested_num_of_buffers,
515 const gfx::Size& dimensions, 515 const gfx::Size& dimensions,
516 VideoDecodeAccelerator::MemoryType type) { 516 VideoDecodeAccelerator::MemoryType type) {
517 if (!decoder_.get()) 517 if (decoder_deleted())
518 return; 518 return;
519 CHECK_EQ(type, VideoDecodeAccelerator::PICTUREBUFFER_MEMORYTYPE_GL_TEXTURE); 519 CHECK_EQ(type, VideoDecodeAccelerator::PICTUREBUFFER_MEMORYTYPE_GL_TEXTURE);
520 std::vector<media::GLESBuffer> buffers; 520 std::vector<media::GLESBuffer> buffers;
521 CHECK_EQ(dimensions.width(), kFrameWidth); 521 CHECK_EQ(dimensions.width(), kFrameWidth);
522 CHECK_EQ(dimensions.height(), kFrameHeight); 522 CHECK_EQ(dimensions.height(), kFrameHeight);
523 523
524 for (uint32 i = 0; i < requested_num_of_buffers; ++i) { 524 for (uint32 i = 0; i < requested_num_of_buffers; ++i) {
525 uint32 id = picture_buffers_by_id_.size(); 525 uint32 id = picture_buffers_by_id_.size();
526 GLuint texture_id; 526 GLuint texture_id;
527 base::WaitableEvent done(false, false); 527 base::WaitableEvent done(false, false);
(...skipping 15 matching lines...) Expand all
543 DCHECK(it != picture_buffers_by_id_.end()); 543 DCHECK(it != picture_buffers_by_id_.end());
544 rendering_helper_->DeleteTexture(it->second->texture_id()); 544 rendering_helper_->DeleteTexture(it->second->texture_id());
545 delete it->second; 545 delete it->second;
546 picture_buffers_by_id_.erase(it); 546 picture_buffers_by_id_.erase(it);
547 } 547 }
548 548
549 void EglRenderingVDAClient::PictureReady(const media::Picture& picture) { 549 void EglRenderingVDAClient::PictureReady(const media::Picture& picture) {
550 // We shouldn't be getting pictures delivered after Reset has completed. 550 // We shouldn't be getting pictures delivered after Reset has completed.
551 DCHECK_LT(state_, CS_RESET); 551 DCHECK_LT(state_, CS_RESET);
552 552
553 if (!decoder_.get()) 553 if (decoder_deleted())
554 return; 554 return;
555 last_frame_delivered_ticks_ = base::TimeTicks::Now(); 555 last_frame_delivered_ticks_ = base::TimeTicks::Now();
556 556
557 // Because we feed the decoder a limited number of NALUs at a time, we can be 557 // Because we feed the decoder a limited number of NALUs at a time, we can be
558 // sure that the bitstream buffer from which a frame comes has a limited 558 // sure that the bitstream buffer from which a frame comes has a limited
559 // range. Assert that. 559 // range. Assert that.
560 CHECK_GE((picture.bitstream_buffer_id() + 1) * num_NALUs_per_decode_, 560 CHECK_GE((picture.bitstream_buffer_id() + 1) * num_NALUs_per_decode_,
561 num_decoded_frames_); 561 num_decoded_frames_);
562 CHECK_LE(picture.bitstream_buffer_id(), next_bitstream_buffer_id_); 562 CHECK_LE(picture.bitstream_buffer_id(), next_bitstream_buffer_id_);
563 ++num_decoded_frames_; 563 ++num_decoded_frames_;
(...skipping 16 matching lines...) Expand all
580 SetState(CS_DONE); 580 SetState(CS_DONE);
581 } 581 }
582 582
583 void EglRenderingVDAClient::NotifyEndOfBitstreamBuffer( 583 void EglRenderingVDAClient::NotifyEndOfBitstreamBuffer(
584 int32 bitstream_buffer_id) { 584 int32 bitstream_buffer_id) {
585 ++num_done_bitstream_buffers_; 585 ++num_done_bitstream_buffers_;
586 DecodeNextNALUs(); 586 DecodeNextNALUs();
587 } 587 }
588 588
589 void EglRenderingVDAClient::NotifyFlushDone() { 589 void EglRenderingVDAClient::NotifyFlushDone() {
590 if (!decoder_.get()) 590 if (decoder_deleted())
591 return; 591 return;
592 SetState(CS_FLUSHED); 592 SetState(CS_FLUSHED);
593 if (!decoder_.get()) 593 if (decoder_deleted())
594 return; 594 return;
595 decoder_->Reset(); 595 decoder_->Reset();
596 } 596 }
597 597
598 void EglRenderingVDAClient::NotifyResetDone() { 598 void EglRenderingVDAClient::NotifyResetDone() {
599 if (!decoder_.get()) 599 if (decoder_deleted())
600 return; 600 return;
601 SetState(CS_RESET); 601 SetState(CS_RESET);
602 if (!decoder_.get()) 602 if (!decoder_deleted())
603 return; 603 DeleteDecoder();
604 decoder_->Destroy();
605 }
606
607 void EglRenderingVDAClient::NotifyDestroyDone() {
608 SetState(CS_DESTROYED);
609 } 604 }
610 605
611 void EglRenderingVDAClient::NotifyError(VideoDecodeAccelerator::Error error) { 606 void EglRenderingVDAClient::NotifyError(VideoDecodeAccelerator::Error error) {
612 SetState(CS_ERROR); 607 SetState(CS_ERROR);
613 error_ = error; 608 error_ = error;
614 } 609 }
615 610
616 static bool LookingAtNAL(const std::string& encoded, size_t pos) { 611 static bool LookingAtNAL(const std::string& encoded, size_t pos) {
617 return pos + 3 < encoded.size() && 612 return pos + 3 < encoded.size() &&
618 encoded[pos] == 0 && encoded[pos + 1] == 0 && 613 encoded[pos] == 0 && encoded[pos + 1] == 0 &&
619 encoded[pos + 2] == 0 && encoded[pos + 3] == 1; 614 encoded[pos + 2] == 0 && encoded[pos + 3] == 1;
620 } 615 }
621 616
622 void EglRenderingVDAClient::SetState(ClientState new_state) { 617 void EglRenderingVDAClient::SetState(ClientState new_state) {
623 note_->Notify(new_state); 618 note_->Notify(new_state);
624 state_ = new_state; 619 state_ = new_state;
625 if (new_state == delete_decoder_state_) 620 if (new_state == delete_decoder_state_) {
621 CHECK(!decoder_deleted());
626 DeleteDecoder(); 622 DeleteDecoder();
623 }
627 } 624 }
628 625
629 void EglRenderingVDAClient::DeleteDecoder() { 626 void EglRenderingVDAClient::DeleteDecoder() {
630 decoder_.reset(); 627 if (decoder_deleted())
628 return;
629 decoder_->Destroy();
630 decoder_ = NULL;
631 // Cascade through the rest of the states to simplify test code below. 631 // Cascade through the rest of the states to simplify test code below.
632 for (int i = state_ + 1; i < CS_MAX; ++i) 632 for (int i = state_ + 1; i < CS_MAX; ++i)
633 SetState(static_cast<ClientState>(i)); 633 SetState(static_cast<ClientState>(i));
634 } 634 }
635 635
636 void EglRenderingVDAClient::GetRangeForNextNALUs( 636 void EglRenderingVDAClient::GetRangeForNextNALUs(
637 size_t start_pos, size_t* end_pos) { 637 size_t start_pos, size_t* end_pos) {
638 *end_pos = start_pos; 638 *end_pos = start_pos;
639 CHECK(LookingAtNAL(*encoded_data_, start_pos)); 639 CHECK(LookingAtNAL(*encoded_data_, start_pos));
640 for (int i = 0; i < num_NALUs_per_decode_; ++i) { 640 for (int i = 0; i < num_NALUs_per_decode_; ++i) {
641 *end_pos += 4; 641 *end_pos += 4;
642 while (*end_pos + 3 < encoded_data_->size() && 642 while (*end_pos + 3 < encoded_data_->size() &&
643 !LookingAtNAL(*encoded_data_, *end_pos)) { 643 !LookingAtNAL(*encoded_data_, *end_pos)) {
644 ++*end_pos; 644 ++*end_pos;
645 } 645 }
646 if (*end_pos + 3 >= encoded_data_->size()) { 646 if (*end_pos + 3 >= encoded_data_->size()) {
647 *end_pos = encoded_data_->size(); 647 *end_pos = encoded_data_->size();
648 return; 648 return;
649 } 649 }
650 } 650 }
651 } 651 }
652 652
653 void EglRenderingVDAClient::DecodeNextNALUs() { 653 void EglRenderingVDAClient::DecodeNextNALUs() {
654 if (!decoder_.get()) 654 if (decoder_deleted())
655 return; 655 return;
656 if (encoded_data_next_pos_to_decode_ == encoded_data_->size()) { 656 if (encoded_data_next_pos_to_decode_ == encoded_data_->size()) {
657 decoder_->Flush(); 657 decoder_->Flush();
658 return; 658 return;
659 } 659 }
660 size_t start_pos = encoded_data_next_pos_to_decode_; 660 size_t start_pos = encoded_data_next_pos_to_decode_;
661 size_t end_pos; 661 size_t end_pos;
662 GetRangeForNextNALUs(start_pos, &end_pos); 662 GetRangeForNextNALUs(start_pos, &end_pos);
663 663
664 // Populate the shared memory buffer w/ the NALU, duplicate its handle, and 664 // Populate the shared memory buffer w/ the NALU, duplicate its handle, and
665 // hand it off to the decoder. 665 // hand it off to the decoder.
666 base::SharedMemory shm; 666 base::SharedMemory shm;
667 CHECK(shm.CreateAndMapAnonymous(end_pos - start_pos)) 667 CHECK(shm.CreateAndMapAnonymous(end_pos - start_pos))
668 << start_pos << ", " << end_pos; 668 << start_pos << ", " << end_pos;
669 memcpy(shm.memory(), encoded_data_->data() + start_pos, end_pos - start_pos); 669 memcpy(shm.memory(), encoded_data_->data() + start_pos, end_pos - start_pos);
670 base::SharedMemoryHandle dup_handle; 670 base::SharedMemoryHandle dup_handle;
671 CHECK(shm.ShareToProcess(base::Process::Current().handle(), &dup_handle)); 671 CHECK(shm.ShareToProcess(base::Process::Current().handle(), &dup_handle));
672 media::BitstreamBuffer bitstream_buffer( 672 media::BitstreamBuffer bitstream_buffer(
673 next_bitstream_buffer_id_++, dup_handle, end_pos - start_pos); 673 next_bitstream_buffer_id_++, dup_handle, end_pos - start_pos);
674 decoder_->Decode(bitstream_buffer); 674 decoder_->Decode(bitstream_buffer);
675 encoded_data_next_pos_to_decode_ = end_pos; 675 encoded_data_next_pos_to_decode_ = end_pos;
676 676
677 if (-delete_decoder_state_ == next_bitstream_buffer_id_) 677 if (-delete_decoder_state_ == next_bitstream_buffer_id_)
678 DeleteDecoder(); 678 DeleteDecoder();
679 } 679 }
680 680
681 double EglRenderingVDAClient::frames_per_second() { 681 double EglRenderingVDAClient::frames_per_second() {
682 base::TimeDelta delta = last_frame_delivered_ticks_ - initialize_done_ticks_; 682 base::TimeDelta delta = last_frame_delivered_ticks_ - initialize_done_ticks_;
683 CHECK_GT(delta.InSecondsF(), 0); 683 if (delta.InSecondsF() == 0)
684 return 0;
684 return num_decoded_frames_ / delta.InSecondsF(); 685 return num_decoded_frames_ / delta.InSecondsF();
685 } 686 }
686 687
687 // Test parameters: 688 // Test parameters:
688 // - Number of NALUs per Decode() call. 689 // - Number of NALUs per Decode() call.
689 // - Number of concurrent decoders. 690 // - Number of concurrent decoders.
690 // - When to delete the decoder. N<0 means after -N Decode() calls have been 691 // - When to delete the decoder. N<0 means after -N Decode() calls have been
691 // made, N>=0 means interpret as ClientState. 692 // made, N>=0 means interpret as ClientState.
692 class OmxVideoDecodeAcceleratorTest 693 class OmxVideoDecodeAcceleratorTest
693 : public ::testing::TestWithParam<Tuple3<int, int, ClientState> > { 694 : public ::testing::TestWithParam<Tuple3<int, int, ClientState> > {
694 }; 695 };
695 696
696 // Wait for |note| to report a state and if it's not |expected_state| then 697 // Wait for |note| to report a state and if it's not |expected_state| then
697 // assert |client| has deleted its decoder. 698 // assert |client| has deleted its decoder.
698 static void AssertWaitForStateOrDeleted(ClientStateNotification* note, 699 static void AssertWaitForStateOrDeleted(ClientStateNotification* note,
699 EglRenderingVDAClient* client, 700 EglRenderingVDAClient* client,
700 ClientState expected_state) { 701 ClientState expected_state) {
701 ClientState state = note->Wait(); 702 ClientState state = note->Wait();
702 if (state == expected_state) return; 703 if (state == expected_state) return;
703 ASSERT_TRUE(client->decoder_deleted()) 704 ASSERT_TRUE(client->decoder_deleted())
704 << "Decoder not deleted but Wait() returned " << state 705 << "Decoder not deleted but Wait() returned " << state
705 << ", instead of " << expected_state; 706 << ", instead of " << expected_state;
706 } 707 }
707 708
709 // We assert the exact number of concurrent decoders we expect to succeed and
710 // that one more than that fails initialization.
711 enum { kMaxSupportedNumConcurrentDecoders = 5 };
712
708 // Test the most straightforward case possible: data is decoded from a single 713 // Test the most straightforward case possible: data is decoded from a single
709 // chunk and rendered to the screen. 714 // chunk and rendered to the screen.
710 TEST_P(OmxVideoDecodeAcceleratorTest, TestSimpleDecode) { 715 TEST_P(OmxVideoDecodeAcceleratorTest, TestSimpleDecode) {
711 // Can be useful for debugging VLOGs from OVDA. 716 // Can be useful for debugging VLOGs from OVDA.
712 // logging::SetMinLogLevel(-1); 717 // logging::SetMinLogLevel(-1);
713 718
714 // Required for Thread to work. Not used otherwise. 719 // Required for Thread to work. Not used otherwise.
715 base::ShadowingAtExitManager at_exit_manager; 720 base::ShadowingAtExitManager at_exit_manager;
716 721
717 const int num_NALUs_per_decode = GetParam().a; 722 const int num_NALUs_per_decode = GetParam().a;
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
756 clients[index] = client; 761 clients[index] = client;
757 762
758 rendering_thread.message_loop()->PostTask( 763 rendering_thread.message_loop()->PostTask(
759 FROM_HERE, 764 FROM_HERE,
760 base::Bind(&EglRenderingVDAClient::CreateDecoder, 765 base::Bind(&EglRenderingVDAClient::CreateDecoder,
761 base::Unretained(client))); 766 base::Unretained(client)));
762 767
763 ASSERT_EQ(note->Wait(), CS_DECODER_SET); 768 ASSERT_EQ(note->Wait(), CS_DECODER_SET);
764 } 769 }
765 // Then wait for all the decodes to finish. 770 // Then wait for all the decodes to finish.
771 bool saw_init_failure = false;
766 for (size_t i = 0; i < num_concurrent_decoders; ++i) { 772 for (size_t i = 0; i < num_concurrent_decoders; ++i) {
767 ClientStateNotification* note = notes[i]; 773 ClientStateNotification* note = notes[i];
768 ASSERT_EQ(note->Wait(), CS_INITIALIZED); 774 ClientState state = note->Wait();
775 if (state != CS_INITIALIZED) {
776 saw_init_failure = true;
777 // We expect initialization to fail only when more than the supported
778 // number of decoders is instantiated. Assert here that something else
779 // didn't trigger failure.
780 ASSERT_GT(num_concurrent_decoders, kMaxSupportedNumConcurrentDecoders);
781 continue;
782 }
783 ASSERT_EQ(state, CS_INITIALIZED);
769 // InitializeDone kicks off decoding inside the client, so we just need to 784 // InitializeDone kicks off decoding inside the client, so we just need to
770 // wait for Flush. 785 // wait for Flush.
771 ASSERT_NO_FATAL_FAILURE( 786 ASSERT_NO_FATAL_FAILURE(
772 AssertWaitForStateOrDeleted(note, clients[i], CS_FLUSHED)); 787 AssertWaitForStateOrDeleted(note, clients[i], CS_FLUSHED));
773 // FlushDone requests Reset(). 788 // FlushDone requests Reset().
774 ASSERT_NO_FATAL_FAILURE( 789 ASSERT_NO_FATAL_FAILURE(
775 AssertWaitForStateOrDeleted(note, clients[i], CS_RESET)); 790 AssertWaitForStateOrDeleted(note, clients[i], CS_RESET));
776 // ResetDone requests Destroy(). 791 // ResetDone requests Destroy().
777 ASSERT_NO_FATAL_FAILURE( 792 ASSERT_NO_FATAL_FAILURE(
778 AssertWaitForStateOrDeleted(note, clients[i], CS_DESTROYED)); 793 AssertWaitForStateOrDeleted(note, clients[i], CS_DESTROYED));
779 } 794 }
795 ASSERT_EQ(saw_init_failure,
796 num_concurrent_decoders > kMaxSupportedNumConcurrentDecoders)
797 << num_concurrent_decoders;
780 // Finally assert that decoding went as expected. 798 // Finally assert that decoding went as expected.
781 for (size_t i = 0; i < num_concurrent_decoders; ++i) { 799 for (size_t i = 0; i < num_concurrent_decoders && !saw_init_failure; ++i) {
782 // We can only make performance/correctness assertions if the decoder was 800 // We can only make performance/correctness assertions if the decoder was
783 // allowed to finish. 801 // allowed to finish.
784 if (delete_decoder_state < CS_FLUSHED) 802 if (delete_decoder_state < CS_FLUSHED)
785 continue; 803 continue;
786 EglRenderingVDAClient* client = clients[i]; 804 EglRenderingVDAClient* client = clients[i];
787 EXPECT_EQ(client->num_decoded_frames(), 25 /* fps */ * 10 /* seconds */); 805 EXPECT_EQ(client->num_decoded_frames(), 25 /* fps */ * 10 /* seconds */);
788 // Hard-coded the number of NALUs in the stream. Icky. 806 // Hard-coded the number of NALUs in the stream. Icky.
789 EXPECT_EQ(client->num_done_bitstream_buffers(), 807 EXPECT_EQ(client->num_done_bitstream_buffers(),
790 ceil(258.0 / num_NALUs_per_decode)); 808 ceil(258.0 / num_NALUs_per_decode));
791 // These numbers are pulled out of a hat, but seem to be safe with current 809 // These numbers are pulled out of a hat, but seem to be safe with current
(...skipping 14 matching lines...) Expand all
806 &notes)); 824 &notes));
807 rendering_thread.message_loop()->PostTask( 825 rendering_thread.message_loop()->PostTask(
808 FROM_HERE, 826 FROM_HERE,
809 base::Bind(&RenderingHelper::UnInitialize, 827 base::Bind(&RenderingHelper::UnInitialize,
810 base::Unretained(&rendering_helper), 828 base::Unretained(&rendering_helper),
811 &done)); 829 &done));
812 done.Wait(); 830 done.Wait();
813 rendering_thread.Stop(); 831 rendering_thread.Stop();
814 }; 832 };
815 833
816 // TODO(fischman): Remove DISABLED_ prefix when ~OVDA can tear down OMX
817 // synchronously (http://crosbug.com/p/4869).
818 INSTANTIATE_TEST_CASE_P( 834 INSTANTIATE_TEST_CASE_P(
819 DISABLED_TearDownTiming, OmxVideoDecodeAcceleratorTest, 835 TearDownTiming, OmxVideoDecodeAcceleratorTest,
820 ::testing::Values( 836 ::testing::Values(
821 MakeTuple(1, 1, CS_DECODER_SET), MakeTuple(1, 1, CS_INITIALIZED), 837 MakeTuple(1, 1, CS_DECODER_SET), MakeTuple(1, 1, CS_INITIALIZED),
822 MakeTuple(1, 1, CS_FLUSHED), MakeTuple(1, 1, CS_RESET), 838 MakeTuple(1, 1, CS_FLUSHED), MakeTuple(1, 1, CS_RESET),
823 MakeTuple(1, 1, static_cast<ClientState>(-1)), 839 MakeTuple(1, 1, static_cast<ClientState>(-1)),
824 MakeTuple(1, 1, static_cast<ClientState>(-10)), 840 MakeTuple(1, 1, static_cast<ClientState>(-10)),
825 MakeTuple(1, 1, static_cast<ClientState>(-100)))); 841 MakeTuple(1, 1, static_cast<ClientState>(-100))));
826 842
827 // TODO(fischman): using 2nd param of 16 and higher below breaks decode - visual 843 // TODO(fischman): using 1st param of 16 and higher below breaks decode - visual
828 // artifacts are introduced as well as spurious frames are delivered (more 844 // artifacts are introduced as well as spurious frames are delivered (more
829 // pictures are returned than NALUs are fed to the decoder). Increase the "15" 845 // pictures are returned than NALUs are fed to the decoder). Increase the "15"
830 // below when http://code.google.com/p/chrome-os-partner/issues/detail?id=4378 846 // below when http://code.google.com/p/chrome-os-partner/issues/detail?id=4378
831 // is fixed. 847 // is fixed.
832 INSTANTIATE_TEST_CASE_P( 848 INSTANTIATE_TEST_CASE_P(
833 DecodeVariations, OmxVideoDecodeAcceleratorTest, 849 DecodeVariations, OmxVideoDecodeAcceleratorTest,
834 ::testing::Values( 850 ::testing::Values(
835 MakeTuple(1, 1, CS_DESTROYED), MakeTuple(1, 3, CS_DESTROYED), 851 MakeTuple(1, 1, CS_RESET), MakeTuple(1, 3, CS_RESET),
836 MakeTuple(2, 1, CS_DESTROYED), MakeTuple(3, 1, CS_DESTROYED), 852 MakeTuple(2, 1, CS_RESET), MakeTuple(3, 1, CS_RESET),
837 MakeTuple(5, 1, CS_DESTROYED), MakeTuple(8, 1, CS_DESTROYED), 853 MakeTuple(5, 1, CS_RESET), MakeTuple(8, 1, CS_RESET),
838 MakeTuple(15, 1, CS_DESTROYED))); 854 MakeTuple(15, 1, CS_RESET)));
855
856 // Find out how many concurrent decoders can go before we exhaust system
857 // resources.
858 INSTANTIATE_TEST_CASE_P(
859 ResourceExhaustion, OmxVideoDecodeAcceleratorTest,
860 ::testing::Values(
861 // +0 hack below to promote enum to int.
862 MakeTuple(1, kMaxSupportedNumConcurrentDecoders + 0, CS_RESET),
863 MakeTuple(1, kMaxSupportedNumConcurrentDecoders + 1, CS_RESET)));
839 864
840 // TODO(fischman, vrk): add more tests! In particular: 865 // TODO(fischman, vrk): add more tests! In particular:
841 // - Test life-cycle: Seek/Stop/Pause/Play/RePlay for a single decoder. 866 // - Test life-cycle: Seek/Stop/Pause/Play/RePlay for a single decoder.
842 // - Test alternate configurations 867 // - Test alternate configurations
843 // - Test failure conditions. 868 // - Test failure conditions.
844 // - Test frame size changes mid-stream 869 // - Test frame size changes mid-stream
845 870
846 } // namespace 871 } // namespace
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698