| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 #include "media/gpu/rendering_helper.h" | 5 #include "media/gpu/rendering_helper.h" |
| 6 | 6 |
| 7 #include <string.h> | 7 #include <string.h> |
| 8 | 8 |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 #include <memory> | 10 #include <memory> |
| 11 #include <numeric> | 11 #include <numeric> |
| 12 #include <vector> | 12 #include <vector> |
| 13 | 13 |
| 14 #include "base/bind.h" | 14 #include "base/bind.h" |
| 15 #include "base/callback_helpers.h" | 15 #include "base/callback_helpers.h" |
| 16 #include "base/command_line.h" | 16 #include "base/command_line.h" |
| 17 #include "base/mac/scoped_nsautorelease_pool.h" | 17 #include "base/mac/scoped_nsautorelease_pool.h" |
| 18 #include "base/macros.h" | 18 #include "base/macros.h" |
| 19 #include "base/message_loop/message_loop.h" | 19 #include "base/message_loop/message_loop.h" |
| 20 #include "base/run_loop.h" | 20 #include "base/run_loop.h" |
| 21 #include "base/single_thread_task_runner.h" | 21 #include "base/single_thread_task_runner.h" |
| 22 #include "base/strings/stringize_macros.h" | 22 #include "base/strings/stringize_macros.h" |
| 23 #include "base/synchronization/waitable_event.h" | 23 #include "base/synchronization/waitable_event.h" |
| 24 #include "base/threading/thread_task_runner_handle.h" |
| 24 #include "base/time/time.h" | 25 #include "base/time/time.h" |
| 25 #include "build/build_config.h" | 26 #include "build/build_config.h" |
| 26 #include "ui/gl/gl_context.h" | 27 #include "ui/gl/gl_context.h" |
| 27 #include "ui/gl/gl_implementation.h" | 28 #include "ui/gl/gl_implementation.h" |
| 28 #include "ui/gl/gl_surface.h" | 29 #include "ui/gl/gl_surface.h" |
| 29 #include "ui/gl/init/gl_factory.h" | 30 #include "ui/gl/init/gl_factory.h" |
| 30 | 31 |
| 31 #if defined(OS_WIN) | 32 #if defined(OS_WIN) |
| 32 #include <windows.h> | 33 #include <windows.h> |
| 33 #endif | 34 #endif |
| (...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 333 } | 334 } |
| 334 | 335 |
| 335 render_task_.Reset( | 336 render_task_.Reset( |
| 336 base::Bind(&RenderingHelper::RenderContent, base::Unretained(this))); | 337 base::Bind(&RenderingHelper::RenderContent, base::Unretained(this))); |
| 337 | 338 |
| 338 frame_duration_ = params.rendering_fps > 0 | 339 frame_duration_ = params.rendering_fps > 0 |
| 339 ? base::TimeDelta::FromSeconds(1) / params.rendering_fps | 340 ? base::TimeDelta::FromSeconds(1) / params.rendering_fps |
| 340 : base::TimeDelta(); | 341 : base::TimeDelta(); |
| 341 | 342 |
| 342 render_as_thumbnails_ = params.render_as_thumbnails; | 343 render_as_thumbnails_ = params.render_as_thumbnails; |
| 343 message_loop_ = base::MessageLoop::current(); | 344 task_runner_ = base::ThreadTaskRunnerHandle::Get(); |
| 344 | 345 |
| 345 gl_surface_ = gl::init::CreateViewGLSurface(window_); | 346 gl_surface_ = gl::init::CreateViewGLSurface(window_); |
| 346 #if defined(USE_OZONE) | 347 #if defined(USE_OZONE) |
| 347 gl_surface_->Resize(platform_window_delegate_->GetSize(), 1.f, true); | 348 gl_surface_->Resize(platform_window_delegate_->GetSize(), 1.f, true); |
| 348 #endif // defined(USE_OZONE) | 349 #endif // defined(USE_OZONE) |
| 349 screen_size_ = gl_surface_->GetSize(); | 350 screen_size_ = gl_surface_->GetSize(); |
| 350 | 351 |
| 351 gl_context_ = gl::init::CreateGLContext(nullptr, gl_surface_.get(), | 352 gl_context_ = gl::init::CreateGLContext(nullptr, gl_surface_.get(), |
| 352 gl::PreferIntegratedGpu); | 353 gl::PreferIntegratedGpu); |
| 353 CHECK(gl_context_->MakeCurrent(gl_surface_.get())); | 354 CHECK(gl_context_->MakeCurrent(gl_surface_.get())); |
| (...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 532 base::Bind(&WaitForSwapAck, wait_for_swap_ack.QuitClosure())); | 533 base::Bind(&WaitForSwapAck, wait_for_swap_ack.QuitClosure())); |
| 533 wait_for_swap_ack.Run(); | 534 wait_for_swap_ack.Run(); |
| 534 } else { | 535 } else { |
| 535 gl_surface_->SwapBuffers(); | 536 gl_surface_->SwapBuffers(); |
| 536 } | 537 } |
| 537 } | 538 } |
| 538 glDeleteTextures(1, &texture_id); | 539 glDeleteTextures(1, &texture_id); |
| 539 } | 540 } |
| 540 | 541 |
| 541 void RenderingHelper::UnInitialize(base::WaitableEvent* done) { | 542 void RenderingHelper::UnInitialize(base::WaitableEvent* done) { |
| 542 CHECK_EQ(base::MessageLoop::current(), message_loop_); | 543 CHECK(task_runner_->BelongsToCurrentThread()); |
| 543 | 544 |
| 544 render_task_.Cancel(); | 545 render_task_.Cancel(); |
| 545 | 546 |
| 546 if (render_as_thumbnails_) { | 547 if (render_as_thumbnails_) { |
| 547 glDeleteTextures(1, &thumbnails_texture_id_); | 548 glDeleteTextures(1, &thumbnails_texture_id_); |
| 548 glDeleteFramebuffersEXT(1, &thumbnails_fbo_id_); | 549 glDeleteFramebuffersEXT(1, &thumbnails_fbo_id_); |
| 549 } | 550 } |
| 550 | 551 |
| 551 gl_context_->ReleaseCurrent(gl_surface_.get()); | 552 gl_context_->ReleaseCurrent(gl_surface_.get()); |
| 552 gl_context_ = NULL; | 553 gl_context_ = NULL; |
| 553 gl_surface_ = NULL; | 554 gl_surface_ = NULL; |
| 554 | 555 |
| 555 Clear(); | 556 Clear(); |
| 556 done->Signal(); | 557 done->Signal(); |
| 557 } | 558 } |
| 558 | 559 |
| 559 void RenderingHelper::CreateTexture(uint32_t texture_target, | 560 void RenderingHelper::CreateTexture(uint32_t texture_target, |
| 560 uint32_t* texture_id, | 561 uint32_t* texture_id, |
| 561 const gfx::Size& size, | 562 const gfx::Size& size, |
| 562 base::WaitableEvent* done) { | 563 base::WaitableEvent* done) { |
| 563 if (base::MessageLoop::current() != message_loop_) { | 564 if (!task_runner_->BelongsToCurrentThread()) { |
| 564 message_loop_->task_runner()->PostTask( | 565 task_runner_->PostTask( |
| 565 FROM_HERE, | 566 FROM_HERE, |
| 566 base::Bind(&RenderingHelper::CreateTexture, base::Unretained(this), | 567 base::Bind(&RenderingHelper::CreateTexture, base::Unretained(this), |
| 567 texture_target, texture_id, size, done)); | 568 texture_target, texture_id, size, done)); |
| 568 return; | 569 return; |
| 569 } | 570 } |
| 570 glGenTextures(1, texture_id); | 571 glGenTextures(1, texture_id); |
| 571 glBindTexture(texture_target, *texture_id); | 572 glBindTexture(texture_target, *texture_id); |
| 572 if (texture_target == GL_TEXTURE_2D) { | 573 if (texture_target == GL_TEXTURE_2D) { |
| 573 glTexImage2D(GL_TEXTURE_2D, | 574 glTexImage2D(GL_TEXTURE_2D, |
| 574 0, | 575 0, |
| (...skipping 14 matching lines...) Expand all Loading... |
| 589 } | 590 } |
| 590 | 591 |
| 591 // Helper function to set GL viewport. | 592 // Helper function to set GL viewport. |
| 592 static inline void GLSetViewPort(const gfx::Rect& area) { | 593 static inline void GLSetViewPort(const gfx::Rect& area) { |
| 593 glViewport(area.x(), area.y(), area.width(), area.height()); | 594 glViewport(area.x(), area.y(), area.width(), area.height()); |
| 594 glScissor(area.x(), area.y(), area.width(), area.height()); | 595 glScissor(area.x(), area.y(), area.width(), area.height()); |
| 595 } | 596 } |
| 596 | 597 |
| 597 void RenderingHelper::RenderThumbnail(uint32_t texture_target, | 598 void RenderingHelper::RenderThumbnail(uint32_t texture_target, |
| 598 uint32_t texture_id) { | 599 uint32_t texture_id) { |
| 599 CHECK_EQ(base::MessageLoop::current(), message_loop_); | 600 CHECK(task_runner_->BelongsToCurrentThread()); |
| 600 const int width = thumbnail_size_.width(); | 601 const int width = thumbnail_size_.width(); |
| 601 const int height = thumbnail_size_.height(); | 602 const int height = thumbnail_size_.height(); |
| 602 const int thumbnails_in_row = thumbnails_fbo_size_.width() / width; | 603 const int thumbnails_in_row = thumbnails_fbo_size_.width() / width; |
| 603 const int thumbnails_in_column = thumbnails_fbo_size_.height() / height; | 604 const int thumbnails_in_column = thumbnails_fbo_size_.height() / height; |
| 604 const int row = (frame_count_ / thumbnails_in_row) % thumbnails_in_column; | 605 const int row = (frame_count_ / thumbnails_in_row) % thumbnails_in_column; |
| 605 const int col = frame_count_ % thumbnails_in_row; | 606 const int col = frame_count_ % thumbnails_in_row; |
| 606 | 607 |
| 607 gfx::Rect area(col * width, row * height, width, height); | 608 gfx::Rect area(col * width, row * height, width, height); |
| 608 | 609 |
| 609 glUniform1i(glGetUniformLocation(program_, "tex_flip"), 0); | 610 glUniform1i(glGetUniformLocation(program_, "tex_flip"), 0); |
| 610 glBindFramebufferEXT(GL_FRAMEBUFFER, thumbnails_fbo_id_); | 611 glBindFramebufferEXT(GL_FRAMEBUFFER, thumbnails_fbo_id_); |
| 611 GLSetViewPort(area); | 612 GLSetViewPort(area); |
| 612 RenderTexture(texture_target, texture_id); | 613 RenderTexture(texture_target, texture_id); |
| 613 glBindFramebufferEXT(GL_FRAMEBUFFER, | 614 glBindFramebufferEXT(GL_FRAMEBUFFER, |
| 614 gl_surface_->GetBackingFramebufferObject()); | 615 gl_surface_->GetBackingFramebufferObject()); |
| 615 | 616 |
| 616 // Need to flush the GL commands before we return the tnumbnail texture to | 617 // Need to flush the GL commands before we return the tnumbnail texture to |
| 617 // the decoder. | 618 // the decoder. |
| 618 glFlush(); | 619 glFlush(); |
| 619 ++frame_count_; | 620 ++frame_count_; |
| 620 } | 621 } |
| 621 | 622 |
| 622 void RenderingHelper::QueueVideoFrame( | 623 void RenderingHelper::QueueVideoFrame( |
| 623 size_t window_id, | 624 size_t window_id, |
| 624 scoped_refptr<VideoFrameTexture> video_frame) { | 625 scoped_refptr<VideoFrameTexture> video_frame) { |
| 625 CHECK_EQ(base::MessageLoop::current(), message_loop_); | 626 CHECK(task_runner_->BelongsToCurrentThread()); |
| 626 RenderedVideo* video = &videos_[window_id]; | 627 RenderedVideo* video = &videos_[window_id]; |
| 627 DCHECK(!video->is_flushing); | 628 DCHECK(!video->is_flushing); |
| 628 | 629 |
| 629 video->pending_frames.push(video_frame); | 630 video->pending_frames.push(video_frame); |
| 630 | 631 |
| 631 if (video->frames_to_drop > 0 && video->pending_frames.size() > 1) { | 632 if (video->frames_to_drop > 0 && video->pending_frames.size() > 1) { |
| 632 --video->frames_to_drop; | 633 --video->frames_to_drop; |
| 633 video->pending_frames.pop(); | 634 video->pending_frames.pop(); |
| 634 } | 635 } |
| 635 | 636 |
| 636 // Schedules the first RenderContent() if need. | 637 // Schedules the first RenderContent() if need. |
| 637 if (scheduled_render_time_.is_null()) { | 638 if (scheduled_render_time_.is_null()) { |
| 638 scheduled_render_time_ = base::TimeTicks::Now(); | 639 scheduled_render_time_ = base::TimeTicks::Now(); |
| 639 message_loop_->task_runner()->PostTask(FROM_HERE, render_task_.callback()); | 640 task_runner_->PostTask(FROM_HERE, render_task_.callback()); |
| 640 } | 641 } |
| 641 } | 642 } |
| 642 | 643 |
| 643 void RenderingHelper::RenderTexture(uint32_t texture_target, | 644 void RenderingHelper::RenderTexture(uint32_t texture_target, |
| 644 uint32_t texture_id) { | 645 uint32_t texture_id) { |
| 645 // The ExternalOES sampler is bound to GL_TEXTURE1 and the Texture2D sampler | 646 // The ExternalOES sampler is bound to GL_TEXTURE1 and the Texture2D sampler |
| 646 // is bound to GL_TEXTURE0. | 647 // is bound to GL_TEXTURE0. |
| 647 if (texture_target == GL_TEXTURE_2D) { | 648 if (texture_target == GL_TEXTURE_2D) { |
| 648 glActiveTexture(GL_TEXTURE0 + 0); | 649 glActiveTexture(GL_TEXTURE0 + 0); |
| 649 } else if (texture_target == GL_TEXTURE_EXTERNAL_OES) { | 650 } else if (texture_target == GL_TEXTURE_EXTERNAL_OES) { |
| 650 glActiveTexture(GL_TEXTURE0 + 1); | 651 glActiveTexture(GL_TEXTURE0 + 1); |
| 651 } | 652 } |
| 652 glBindTexture(texture_target, texture_id); | 653 glBindTexture(texture_target, texture_id); |
| 653 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); | 654 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); |
| 654 glBindTexture(texture_target, 0); | 655 glBindTexture(texture_target, 0); |
| 655 CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR); | 656 CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR); |
| 656 } | 657 } |
| 657 | 658 |
| 658 void RenderingHelper::DeleteTexture(uint32_t texture_id) { | 659 void RenderingHelper::DeleteTexture(uint32_t texture_id) { |
| 659 CHECK_EQ(base::MessageLoop::current(), message_loop_); | 660 CHECK(task_runner_->BelongsToCurrentThread()); |
| 660 glDeleteTextures(1, &texture_id); | 661 glDeleteTextures(1, &texture_id); |
| 661 CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR); | 662 CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR); |
| 662 } | 663 } |
| 663 | 664 |
| 664 gl::GLContext* RenderingHelper::GetGLContext() { | 665 gl::GLContext* RenderingHelper::GetGLContext() { |
| 665 return gl_context_.get(); | 666 return gl_context_.get(); |
| 666 } | 667 } |
| 667 | 668 |
| 668 void* RenderingHelper::GetGLDisplay() { | 669 void* RenderingHelper::GetGLDisplay() { |
| 669 return gl_surface_->GetDisplay(); | 670 return gl_surface_->GetDisplay(); |
| 670 } | 671 } |
| 671 | 672 |
| 672 void RenderingHelper::Clear() { | 673 void RenderingHelper::Clear() { |
| 673 videos_.clear(); | 674 videos_.clear(); |
| 674 message_loop_ = NULL; | 675 task_runner_ = nullptr; |
| 675 gl_context_ = NULL; | 676 gl_context_ = NULL; |
| 676 gl_surface_ = NULL; | 677 gl_surface_ = NULL; |
| 677 | 678 |
| 678 render_as_thumbnails_ = false; | 679 render_as_thumbnails_ = false; |
| 679 frame_count_ = 0; | 680 frame_count_ = 0; |
| 680 thumbnails_fbo_id_ = 0; | 681 thumbnails_fbo_id_ = 0; |
| 681 thumbnails_texture_id_ = 0; | 682 thumbnails_texture_id_ = 0; |
| 682 } | 683 } |
| 683 | 684 |
| 684 void RenderingHelper::GetThumbnailsAsRGB(std::vector<unsigned char>* rgb, | 685 void RenderingHelper::GetThumbnailsAsRGB(std::vector<unsigned char>* rgb, |
| (...skipping 29 matching lines...) Expand all Loading... |
| 714 *alpha_solid = solid; | 715 *alpha_solid = solid; |
| 715 | 716 |
| 716 done->Signal(); | 717 done->Signal(); |
| 717 } | 718 } |
| 718 | 719 |
| 719 void RenderingHelper::Flush(size_t window_id) { | 720 void RenderingHelper::Flush(size_t window_id) { |
| 720 videos_[window_id].is_flushing = true; | 721 videos_[window_id].is_flushing = true; |
| 721 } | 722 } |
| 722 | 723 |
| 723 void RenderingHelper::RenderContent() { | 724 void RenderingHelper::RenderContent() { |
| 724 CHECK_EQ(base::MessageLoop::current(), message_loop_); | 725 CHECK(task_runner_->BelongsToCurrentThread()); |
| 725 | 726 |
| 726 // Update the VSync params. | 727 // Update the VSync params. |
| 727 // | 728 // |
| 728 // It's safe to use Unretained here since |rendering_thread_| will be stopped | 729 // It's safe to use Unretained here since |rendering_thread_| will be stopped |
| 729 // in VideoDecodeAcceleratorTest.TearDown(), while the |rendering_helper_| is | 730 // in VideoDecodeAcceleratorTest.TearDown(), while the |rendering_helper_| is |
| 730 // a member of that class. (See video_decode_accelerator_unittest.cc.) | 731 // a member of that class. (See video_decode_accelerator_unittest.cc.) |
| 731 gfx::VSyncProvider* vsync_provider = gl_surface_->GetVSyncProvider(); | 732 gfx::VSyncProvider* vsync_provider = gl_surface_->GetVSyncProvider(); |
| 732 if (vsync_provider && !ignore_vsync_) { | 733 if (vsync_provider && !ignore_vsync_) { |
| 733 vsync_provider->GetVSyncParameters(base::Bind( | 734 vsync_provider->GetVSyncParameters(base::Bind( |
| 734 &RenderingHelper::UpdateVSyncParameters, base::Unretained(this), | 735 &RenderingHelper::UpdateVSyncParameters, base::Unretained(this), |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 879 int64_t intervals = (target - vsync_timebase_) / vsync_interval_; | 880 int64_t intervals = (target - vsync_timebase_) / vsync_interval_; |
| 880 target = vsync_timebase_ + intervals * vsync_interval_; | 881 target = vsync_timebase_ + intervals * vsync_interval_; |
| 881 } | 882 } |
| 882 | 883 |
| 883 // When the rendering falls behind, drops frames. | 884 // When the rendering falls behind, drops frames. |
| 884 while (scheduled_render_time_ < target) { | 885 while (scheduled_render_time_ < target) { |
| 885 scheduled_render_time_ += frame_duration_; | 886 scheduled_render_time_ += frame_duration_; |
| 886 DropOneFrameForAllVideos(); | 887 DropOneFrameForAllVideos(); |
| 887 } | 888 } |
| 888 | 889 |
| 889 message_loop_->task_runner()->PostDelayedTask( | 890 task_runner_->PostDelayedTask(FROM_HERE, render_task_.callback(), |
| 890 FROM_HERE, render_task_.callback(), target - now); | 891 target - now); |
| 891 } | 892 } |
| 892 } // namespace media | 893 } // namespace media |
| OLD | NEW |