| Index: content/common/gpu/media/rendering_helper.cc
|
| diff --git a/content/common/gpu/media/rendering_helper.cc b/content/common/gpu/media/rendering_helper.cc
|
| index 7ee940148d2d2f9e741fd38f0b3c1d798fad37df..ce2f94b16d405a18034c4b9e2fa4fe49276fad03 100644
|
| --- a/content/common/gpu/media/rendering_helper.cc
|
| +++ b/content/common/gpu/media/rendering_helper.cc
|
| @@ -9,6 +9,7 @@
|
| #include <vector>
|
|
|
| #include "base/bind.h"
|
| +#include "base/callback_helpers.h"
|
| #include "base/command_line.h"
|
| #include "base/mac/scoped_nsautorelease_pool.h"
|
| #include "base/message_loop/message_loop.h"
|
| @@ -60,6 +61,25 @@ RenderingHelperParams::RenderingHelperParams() {}
|
|
|
| RenderingHelperParams::~RenderingHelperParams() {}
|
|
|
| +VideoFrameTexture::VideoFrameTexture(uint32 texture_target,
|
| + uint32 texture_id,
|
| + const base::Closure& no_longer_needed_cb)
|
| + : texture_target_(texture_target),
|
| + texture_id_(texture_id),
|
| + no_longer_needed_cb_(no_longer_needed_cb) {
|
| + DCHECK(!no_longer_needed_cb_.is_null());
|
| +}
|
| +
|
| +VideoFrameTexture::~VideoFrameTexture() {
|
| + base::ResetAndReturn(&no_longer_needed_cb_).Run();
|
| +}
|
| +
|
| +RenderingHelper::RenderedVideo::RenderedVideo() : last_frame_rendered(false) {
|
| +}
|
| +
|
| +RenderingHelper::RenderedVideo::~RenderedVideo() {
|
| +}
|
| +
|
| // static
|
| bool RenderingHelper::InitializeOneOff() {
|
| base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
|
| @@ -78,15 +98,15 @@ RenderingHelper::RenderingHelper() {
|
| }
|
|
|
| RenderingHelper::~RenderingHelper() {
|
| - CHECK_EQ(clients_.size(), 0U) << "Must call UnInitialize before dtor.";
|
| + CHECK_EQ(videos_.size(), 0U) << "Must call UnInitialize before dtor.";
|
| Clear();
|
| }
|
|
|
| void RenderingHelper::Initialize(const RenderingHelperParams& params,
|
| base::WaitableEvent* done) {
|
| - // Use cients_.size() != 0 as a proxy for the class having already been
|
| + // Use videos_.size() != 0 as a proxy for the class having already been
|
| // Initialize()'d, and UnInitialize() before continuing.
|
| - if (clients_.size()) {
|
| + if (videos_.size()) {
|
| base::WaitableEvent done(false, false);
|
| UnInitialize(&done);
|
| done.Wait();
|
| @@ -153,12 +173,12 @@ void RenderingHelper::Initialize(const RenderingHelperParams& params,
|
| NULL, gl_surface_, gfx::PreferIntegratedGpu);
|
| gl_context_->MakeCurrent(gl_surface_);
|
|
|
| - clients_ = params.clients;
|
| - CHECK_GT(clients_.size(), 0U);
|
| - LayoutRenderingAreas();
|
| + CHECK_GT(params.window_sizes.size(), 0U);
|
| + videos_.resize(params.window_sizes.size());
|
| + LayoutRenderingAreas(params.window_sizes);
|
|
|
| if (render_as_thumbnails_) {
|
| - CHECK_EQ(clients_.size(), 1U);
|
| + CHECK_EQ(videos_.size(), 1U);
|
|
|
| GLint max_texture_size;
|
| glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
|
| @@ -370,6 +390,31 @@ void RenderingHelper::RenderThumbnail(uint32 texture_target,
|
| ++frame_count_;
|
| }
|
|
|
| +void RenderingHelper::QueueVideoFrame(
|
| + size_t window_id,
|
| + scoped_refptr<VideoFrameTexture> video_frame) {
|
| + CHECK_EQ(base::MessageLoop::current(), message_loop_);
|
| + RenderedVideo* video = &videos_[window_id];
|
| +
|
| + // Pop the last frame if it has been rendered.
|
| + if (video->last_frame_rendered) {
|
| + // When last_frame_rendered is true, we should have only one pending frame.
|
| + // Since we are going to have a new frame, we can release the pending one.
|
| + DCHECK(video->pending_frames.size() == 1);
|
| + video->pending_frames.pop();
|
| + video->last_frame_rendered = false;
|
| + }
|
| +
|
| + video->pending_frames.push(video_frame);
|
| +}
|
| +
|
| +void RenderingHelper::DropPendingFrames(size_t window_id) {
|
| + CHECK_EQ(base::MessageLoop::current(), message_loop_);
|
| + RenderedVideo* video = &videos_[window_id];
|
| + video->pending_frames = std::queue<scoped_refptr<VideoFrameTexture> >();
|
| + video->last_frame_rendered = false;
|
| +}
|
| +
|
| void RenderingHelper::RenderTexture(uint32 texture_target, uint32 texture_id) {
|
| // The ExternalOES sampler is bound to GL_TEXTURE1 and the Texture2D sampler
|
| // is bound to GL_TEXTURE0.
|
| @@ -385,6 +430,7 @@ void RenderingHelper::RenderTexture(uint32 texture_target, uint32 texture_id) {
|
| }
|
|
|
| void RenderingHelper::DeleteTexture(uint32 texture_id) {
|
| + CHECK_EQ(base::MessageLoop::current(), message_loop_);
|
| glDeleteTextures(1, &texture_id);
|
| CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR);
|
| }
|
| @@ -398,7 +444,7 @@ void* RenderingHelper::GetGLDisplay() {
|
| }
|
|
|
| void RenderingHelper::Clear() {
|
| - clients_.clear();
|
| + videos_.clear();
|
| message_loop_ = NULL;
|
| gl_context_ = NULL;
|
| gl_surface_ = NULL;
|
| @@ -461,16 +507,30 @@ void RenderingHelper::RenderContent() {
|
| CHECK_EQ(base::MessageLoop::current(), message_loop_);
|
| glUniform1i(glGetUniformLocation(program_, "tex_flip"), 1);
|
|
|
| + // Frames that will be returned to the client (via the no_longer_needed_cb)
|
| + // after this vector falls out of scope at the end of this method. We need
|
| + // to keep references to them until after SwapBuffers() call below.
|
| + std::vector<scoped_refptr<VideoFrameTexture> > frames_to_be_returned;
|
| +
|
| if (render_as_thumbnails_) {
|
| // In render_as_thumbnails_ mode, we render the FBO content on the
|
| // screen instead of the decoded textures.
|
| - GLSetViewPort(render_areas_[0]);
|
| + GLSetViewPort(videos_[0].render_area);
|
| RenderTexture(GL_TEXTURE_2D, thumbnails_texture_id_);
|
| } else {
|
| - for (size_t i = 0; i < clients_.size(); ++i) {
|
| - if (clients_[i]) {
|
| - GLSetViewPort(render_areas_[i]);
|
| - clients_[i]->RenderContent(this);
|
| + for (size_t i = 0; i < videos_.size(); ++i) {
|
| + RenderedVideo* video = &videos_[i];
|
| + if (video->pending_frames.empty())
|
| + continue;
|
| + scoped_refptr<VideoFrameTexture> frame = video->pending_frames.front();
|
| + GLSetViewPort(video->render_area);
|
| + RenderTexture(frame->texture_target(), frame->texture_id());
|
| +
|
| + if (video->pending_frames.size() > 1) {
|
| + frames_to_be_returned.push_back(video->pending_frames.front());
|
| + video->pending_frames.pop();
|
| + } else {
|
| + video->last_frame_rendered = true;
|
| }
|
| }
|
| }
|
| @@ -492,11 +552,12 @@ static void ScaleAndCalculateOffsets(std::vector<int>* lengths,
|
| }
|
| }
|
|
|
| -void RenderingHelper::LayoutRenderingAreas() {
|
| +void RenderingHelper::LayoutRenderingAreas(
|
| + const std::vector<gfx::Size>& window_sizes) {
|
| // Find the number of colums and rows.
|
| - // The smallest n * n or n * (n + 1) > number of clients.
|
| - size_t cols = sqrt(clients_.size() - 1) + 1;
|
| - size_t rows = (clients_.size() + cols - 1) / cols;
|
| + // The smallest n * n or n * (n + 1) > number of windows.
|
| + size_t cols = sqrt(videos_.size() - 1) + 1;
|
| + size_t rows = (videos_.size() + cols - 1) / cols;
|
|
|
| // Find the widths and heights of the grid.
|
| std::vector<int> widths(cols);
|
| @@ -504,31 +565,30 @@ void RenderingHelper::LayoutRenderingAreas() {
|
| std::vector<int> offset_x(cols);
|
| std::vector<int> offset_y(rows);
|
|
|
| - for (size_t i = 0; i < clients_.size(); ++i) {
|
| - const gfx::Size& window_size = clients_[i]->GetWindowSize();
|
| - widths[i % cols] = std::max(widths[i % cols], window_size.width());
|
| - heights[i / cols] = std::max(heights[i / cols], window_size.height());
|
| + for (size_t i = 0; i < window_sizes.size(); ++i) {
|
| + const gfx::Size& size = window_sizes[i];
|
| + widths[i % cols] = std::max(widths[i % cols], size.width());
|
| + heights[i / cols] = std::max(heights[i / cols], size.height());
|
| }
|
|
|
| ScaleAndCalculateOffsets(&widths, &offset_x, screen_size_.width());
|
| ScaleAndCalculateOffsets(&heights, &offset_y, screen_size_.height());
|
|
|
| // Put each render_area_ in the center of each cell.
|
| - render_areas_.clear();
|
| - for (size_t i = 0; i < clients_.size(); ++i) {
|
| - const gfx::Size& window_size = clients_[i]->GetWindowSize();
|
| + for (size_t i = 0; i < window_sizes.size(); ++i) {
|
| + const gfx::Size& size = window_sizes[i];
|
| float scale =
|
| - std::min(static_cast<float>(widths[i % cols]) / window_size.width(),
|
| - static_cast<float>(heights[i / cols]) / window_size.height());
|
| + std::min(static_cast<float>(widths[i % cols]) / size.width(),
|
| + static_cast<float>(heights[i / cols]) / size.height());
|
|
|
| // Don't scale up the texture.
|
| scale = std::min(1.0f, scale);
|
|
|
| - size_t w = scale * window_size.width();
|
| - size_t h = scale * window_size.height();
|
| + size_t w = scale * size.width();
|
| + size_t h = scale * size.height();
|
| size_t x = offset_x[i % cols] + (widths[i % cols] - w) / 2;
|
| size_t y = offset_y[i / cols] + (heights[i / cols] - h) / 2;
|
| - render_areas_.push_back(gfx::Rect(x, y, w, h));
|
| + videos_[i].render_area = gfx::Rect(x, y, w, h);
|
| }
|
| }
|
| } // namespace content
|
|
|