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

Side by Side Diff: cc/resources/video_resource_updater.cc

Issue 13445009: cc: Move video upload to VideoResourceUpdater. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: consume textures that were produced Created 7 years, 8 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
« no previous file with comments | « cc/resources/video_resource_updater.h ('k') | cc/test/render_pass_test_common.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "cc/resources/video_resource_updater.h"
6
7 #include "base/bind.h"
8 #include "cc/output/gl_renderer.h"
9 #include "cc/resources/resource_provider.h"
10 #include "gpu/GLES2/gl2extchromium.h"
11 #include "media/base/video_frame.h"
12 #include "media/filters/skcanvas_video_renderer.h"
13 #include "third_party/khronos/GLES2/gl2.h"
14 #include "third_party/khronos/GLES2/gl2ext.h"
15 #include "ui/gfx/size_conversions.h"
16
17 const unsigned kYUVResourceFormat = GL_LUMINANCE;
18 const unsigned kRGBResourceFormat = GL_RGBA;
19
20 namespace cc {
21
22 VideoFrameExternalResources::VideoFrameExternalResources() : type(NONE) {}
23
24 VideoFrameExternalResources::~VideoFrameExternalResources() {}
25
26 VideoResourceUpdater::VideoResourceUpdater(ResourceProvider* resource_provider)
27 : resource_provider_(resource_provider) {
28 }
29
30 VideoResourceUpdater::~VideoResourceUpdater() {}
31
32 bool VideoResourceUpdater::VerifyFrame(
33 const scoped_refptr<media::VideoFrame>& video_frame) {
34 // If these fail, we'll have to add logic that handles offset bitmap/texture
35 // UVs. For now, just expect (0, 0) offset, since all our decoders so far
36 // don't offset.
37 DCHECK_EQ(video_frame->visible_rect().x(), 0);
38 DCHECK_EQ(video_frame->visible_rect().y(), 0);
39
40 switch (video_frame->format()) {
41 // Acceptable inputs.
42 case media::VideoFrame::YV12:
43 case media::VideoFrame::YV16:
44 case media::VideoFrame::NATIVE_TEXTURE:
45 #if defined(GOOGLE_TV)
46 case media::VideoFrame::HOLE:
47 #endif
48 return true;
49
50 // Unacceptable inputs. ¯\(°_o)/¯
51 case media::VideoFrame::INVALID:
52 case media::VideoFrame::RGB32:
53 case media::VideoFrame::EMPTY:
54 case media::VideoFrame::I420:
55 break;
56 }
57 return false;
58 }
59
60 // For frames that we receive in software format, determine the dimensions of
61 // each plane in the frame.
62 static gfx::Size SoftwarePlaneDimension(
63 media::VideoFrame::Format input_frame_format,
64 gfx::Size coded_size,
65 GLenum output_resource_format,
66 int plane_index) {
67 if (output_resource_format == kYUVResourceFormat) {
68 if (plane_index == media::VideoFrame::kYPlane)
69 return coded_size;
70
71 switch (input_frame_format) {
72 case media::VideoFrame::YV12:
73 return gfx::ToFlooredSize(gfx::ScaleSize(coded_size, 0.5f, 0.5f));
74 case media::VideoFrame::YV16:
75 return gfx::ToFlooredSize(gfx::ScaleSize(coded_size, 0.5f, 1.f));
76
77 case media::VideoFrame::INVALID:
78 case media::VideoFrame::RGB32:
79 case media::VideoFrame::EMPTY:
80 case media::VideoFrame::I420:
81 case media::VideoFrame::NATIVE_TEXTURE:
82 #if defined(GOOGLE_TV)
83 case media::VideoFrame::HOLE:
84 #endif
85 NOTREACHED();
86 }
87 }
88
89 DCHECK_EQ(output_resource_format, static_cast<unsigned>(kRGBResourceFormat));
90 return coded_size;
91 }
92
93 static void ReleaseResource(ResourceProvider* resource_provider,
94 ResourceProvider::ResourceId resource_id,
95 unsigned sync_point) {
96 resource_provider->DeleteResource(resource_id);
97 }
98
99 VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes(
100 const scoped_refptr<media::VideoFrame>& video_frame) {
101 if (!VerifyFrame(video_frame))
102 return VideoFrameExternalResources();
103
104 media::VideoFrame::Format input_frame_format = video_frame->format();
105
106 #if defined(GOOGLE_TV)
107 if (input_frame_format == media::VideoFrame::HOLE) {
108 VideoFrameExternalResources external_resources;
109 external_resources.type = VideoFrameExternalResources::HOLE;
110 return external_resources;
111 }
112 #endif
113
114 // Only YUV software video frames are supported.
115 DCHECK(input_frame_format == media::VideoFrame::YV12 ||
116 input_frame_format == media::VideoFrame::YV16);
117 if (input_frame_format != media::VideoFrame::YV12 &&
118 input_frame_format != media::VideoFrame::YV16)
119 return VideoFrameExternalResources();
120
121 bool software_compositor = !resource_provider_->GraphicsContext3D();
122
123 GLenum output_resource_format = kYUVResourceFormat;
124 size_t output_plane_count = 3;
125
126 // TODO(skaslev): If we're in software compositing mode, we do the YUV -> RGB
127 // conversion here. That involves an extra copy of each frame to a bitmap.
128 // Obviously, this is suboptimal and should be addressed once ubercompositor
129 // starts shaping up.
130 if (software_compositor) {
131 output_resource_format = kRGBResourceFormat;
132 output_plane_count = 1;
133 }
134
135 int max_resource_size = resource_provider_->max_texture_size();
136 gfx::Size coded_frame_size = video_frame->coded_size();
137
138 ResourceProvider::ResourceIdArray plane_resources;
139 bool allocation_success = true;
140
141 for (size_t i = 0; i < output_plane_count; ++i) {
142 gfx::Size plane_size =
143 SoftwarePlaneDimension(input_frame_format,
144 coded_frame_size,
145 output_resource_format,
146 i);
147 if (plane_size.IsEmpty() ||
148 plane_size.width() > max_resource_size ||
149 plane_size.height() > max_resource_size) {
150 allocation_success = false;
151 break;
152 }
153
154 // TODO(danakj): Could recycle resources that we previously allocated and
155 // were returned to us.
156 ResourceProvider::ResourceId resource_id =
157 resource_provider_->CreateResource(plane_size,
158 output_resource_format,
159 ResourceProvider::TextureUsageAny);
160 if (resource_id == 0) {
161 allocation_success = false;
162 break;
163 }
164
165 plane_resources.push_back(resource_id);
166 }
167
168 if (!allocation_success) {
169 for (size_t i = 0; i < plane_resources.size(); ++i)
170 resource_provider_->DeleteResource(plane_resources[i]);
171 return VideoFrameExternalResources();
172 }
173
174 VideoFrameExternalResources external_resources;
175
176 if (software_compositor) {
177 DCHECK_EQ(output_resource_format, kRGBResourceFormat);
178 DCHECK_EQ(plane_resources.size(), 1u);
179
180 if (!video_renderer_)
181 video_renderer_.reset(new media::SkCanvasVideoRenderer);
182
183 {
184 ResourceProvider::ScopedWriteLockSoftware lock(
185 resource_provider_, plane_resources[0]);
186 video_renderer_->Paint(video_frame,
187 lock.sk_canvas(),
188 video_frame->visible_rect(),
189 0xff);
190 }
191
192 // In software mode, the resource provider won't be lost. Soon this callback
193 // will be called directly from the resource provider, same as 3d
194 // compositing mode, so this raw unretained resource_provider will always
195 // be valid when the callback is fired.
196 TextureMailbox::ReleaseCallback callback_to_free_resource =
197 base::Bind(&ReleaseResource,
198 base::Unretained(resource_provider_),
199 plane_resources[0]);
200 external_resources.software_resources.push_back(plane_resources[0]);
201 external_resources.software_release_callback = callback_to_free_resource;
202
203 external_resources.type = VideoFrameExternalResources::SOFTWARE_RESOURCE;
204 return external_resources;
205 }
206
207 DCHECK_EQ(output_resource_format,
208 static_cast<unsigned>(kYUVResourceFormat));
209
210 WebKit::WebGraphicsContext3D* context =
211 resource_provider_->GraphicsContext3D();
212 DCHECK(context);
213
214 for (size_t plane = 0; plane < plane_resources.size(); ++plane) {
215 // Update each plane's resource id with its content.
216 ResourceProvider::ResourceId output_plane_resource_id =
217 plane_resources[plane];
218 gfx::Size plane_size =
219 SoftwarePlaneDimension(input_frame_format,
220 coded_frame_size,
221 output_resource_format,
222 plane);
223 const uint8_t* input_plane_pixels = video_frame->data(plane);
224
225 gfx::Rect image_rect(
226 0, 0, video_frame->stride(plane), plane_size.height());
227 gfx::Rect source_rect(plane_size);
228 resource_provider_->SetPixels(output_plane_resource_id,
229 input_plane_pixels,
230 image_rect,
231 source_rect,
232 gfx::Vector2d());
233
234 gpu::Mailbox mailbox;
235 {
236 ResourceProvider::ScopedWriteLockGL lock(
237 resource_provider_, output_plane_resource_id);
238
239 GLC(context, context->genMailboxCHROMIUM(mailbox.name));
240 GLC(context, context->bindTexture(GL_TEXTURE_2D, lock.texture_id()));
241 GLC(context, context->produceTextureCHROMIUM(GL_TEXTURE_2D,
242 mailbox.name));
243 GLC(context, context->bindTexture(GL_TEXTURE_2D, 0));
244 }
245
246 // This callback is called by the resource provider itself, so it's okay to
247 // use an unretained raw pointer here.
248 TextureMailbox::ReleaseCallback callback_to_free_resource =
249 base::Bind(&ReleaseResource,
250 base::Unretained(resource_provider_),
251 output_plane_resource_id);
252 external_resources.mailboxes.push_back(
253 TextureMailbox(mailbox, callback_to_free_resource));
254 }
255
256 external_resources.type = VideoFrameExternalResources::YUV_RESOURCE;
257 return external_resources;
258 }
259
260 VideoFrameExternalResources VideoResourceUpdater::CreateForHardwarePlanes(
261 const scoped_refptr<media::VideoFrame>& video_frame,
262 const TextureMailbox::ReleaseCallback& release_callback) {
263 if (!VerifyFrame(video_frame))
264 return VideoFrameExternalResources();
265
266 media::VideoFrame::Format frame_format = video_frame->format();
267
268 DCHECK_EQ(frame_format, media::VideoFrame::NATIVE_TEXTURE);
269 if (frame_format != media::VideoFrame::NATIVE_TEXTURE)
270 return VideoFrameExternalResources();
271
272 WebKit::WebGraphicsContext3D* context =
273 resource_provider_->GraphicsContext3D();
274 if (!context)
275 return VideoFrameExternalResources();
276
277 VideoFrameExternalResources external_resources;
278 switch (video_frame->texture_target()) {
279 case GL_TEXTURE_2D:
280 external_resources.type = VideoFrameExternalResources::RGB_RESOURCE;
281 break;
282 case GL_TEXTURE_EXTERNAL_OES:
283 external_resources.type =
284 VideoFrameExternalResources::STREAM_TEXTURE_RESOURCE;
285 break;
286 case GL_TEXTURE_RECTANGLE_ARB:
287 external_resources.type = VideoFrameExternalResources::IO_SURFACE;
288 break;
289 default:
290 NOTREACHED();
291 return VideoFrameExternalResources();
292 }
293
294 gpu::Mailbox mailbox;
295 GLC(context, context->genMailboxCHROMIUM(mailbox.name));
296 GLC(context, context->bindTexture(GL_TEXTURE_2D, video_frame->texture_id()));
297 GLC(context, context->produceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name));
298 GLC(context, context->bindTexture(GL_TEXTURE_2D, 0));
299
300 TextureMailbox::ReleaseCallback callback_to_return_resource =
301 base::Bind(&ReturnTexture,
302 base::Unretained(resource_provider_),
303 release_callback,
304 video_frame->texture_id(),
305 mailbox);
306 external_resources.mailboxes.push_back(
307 TextureMailbox(mailbox, callback_to_return_resource));
308 return external_resources;
309 }
310
311 // static
312 void VideoResourceUpdater::ReturnTexture(
313 ResourceProvider* resource_provider,
314 TextureMailbox::ReleaseCallback callback,
315 unsigned texture_id,
316 gpu::Mailbox mailbox,
317 unsigned sync_point) {
318 WebKit::WebGraphicsContext3D* context =
319 resource_provider->GraphicsContext3D();
320 GLC(context, context->bindTexture(GL_TEXTURE_2D, texture_id));
321 GLC(context, context->consumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name));
322 GLC(context, context->bindTexture(GL_TEXTURE_2D, 0));
323 callback.Run(sync_point);
324 }
325
326 } // namespace cc
OLDNEW
« no previous file with comments | « cc/resources/video_resource_updater.h ('k') | cc/test/render_pass_test_common.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698