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

Side by Side Diff: content/browser/renderer_host/media/video_capture_device_client.cc

Issue 1064963002: VideoCapture: add support for GpuMemoryBuffer allocation and lifetime mgmt in VideoCaptureBufferPool (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 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
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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 "content/browser/renderer_host/media/video_capture_device_client.h" 5 #include "content/browser/renderer_host/media/video_capture_device_client.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/strings/stringprintf.h" 8 #include "base/strings/stringprintf.h"
9 #include "base/trace_event/trace_event.h" 9 #include "base/trace_event/trace_event.h"
10 #include "content/browser/compositor/image_transport_factory.h"
11 #include "content/browser/gpu/browser_gpu_channel_host_factory.h"
12 #include "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
13 #include "content/browser/gpu/gpu_data_manager_impl.h"
10 #include "content/browser/renderer_host/media/video_capture_buffer_pool.h" 14 #include "content/browser/renderer_host/media/video_capture_buffer_pool.h"
11 #include "content/browser/renderer_host/media/video_capture_controller.h" 15 #include "content/browser/renderer_host/media/video_capture_controller.h"
16 #include "content/common/gpu/client/context_provider_command_buffer.h"
17 #include "content/common/gpu/client/gl_helper.h"
18 #include "content/common/gpu/client/gpu_channel_host.h"
19 #include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
20 #include "content/common/gpu/gpu_process_launch_causes.h"
12 #include "content/public/browser/browser_thread.h" 21 #include "content/public/browser/browser_thread.h"
22 #include "gpu/command_buffer/common/mailbox_holder.h"
13 #include "media/base/bind_to_current_loop.h" 23 #include "media/base/bind_to_current_loop.h"
14 #include "media/base/video_capture_types.h" 24 #include "media/base/video_capture_types.h"
15 #include "media/base/video_frame.h" 25 #include "media/base/video_frame.h"
26 #include "third_party/khronos/GLES2/gl2ext.h"
16 #include "third_party/libyuv/include/libyuv.h" 27 #include "third_party/libyuv/include/libyuv.h"
17 28
18 using media::VideoCaptureFormat; 29 using media::VideoCaptureFormat;
19 using media::VideoFrame; 30 using media::VideoFrame;
20 31
21 namespace content { 32 namespace content {
22 33
34 namespace {
35
36 #if !defined(OS_ANDROID)
37 // Modelled after GpuProcessTransportFactory::CreateContextCommon().
38 scoped_ptr<content::WebGraphicsContext3DCommandBufferImpl> CreateContextCommon(
39 scoped_refptr<content::GpuChannelHost> gpu_channel_host,
40 int surface_id) {
41 if (!content::GpuDataManagerImpl::GetInstance()->
42 CanUseGpuBrowserCompositor()) {
43 DLOG(ERROR) << "No accelerated graphics found. Check chrome://gpu";
44 return scoped_ptr<content::WebGraphicsContext3DCommandBufferImpl>();
45 }
46 blink::WebGraphicsContext3D::Attributes attrs;
47 attrs.shareResources = true;
48 attrs.depth = false;
49 attrs.stencil = false;
50 attrs.antialias = false;
51 attrs.noAutomaticFlushes = true;
52
53 if (!gpu_channel_host.get()) {
54 DLOG(ERROR) << "Failed to establish GPU channel.";
55 return scoped_ptr<content::WebGraphicsContext3DCommandBufferImpl>();
56 }
57 GURL url("chrome://gpu/GpuProcessTransportFactory::CreateCaptureContext");
58 return make_scoped_ptr(
59 new WebGraphicsContext3DCommandBufferImpl(
60 surface_id,
61 url,
62 gpu_channel_host.get(),
63 attrs,
64 true /* lose_context_when_out_of_memory */,
65 content::WebGraphicsContext3DCommandBufferImpl::SharedMemoryLimits(),
66 NULL));
67 }
68
69 // Modelled after
70 // GpuProcessTransportFactory::CreateOffscreenCommandBufferContext().
71 scoped_ptr<content::WebGraphicsContext3DCommandBufferImpl>
72 CreateOffscreenCommandBufferContext() {
73 content::CauseForGpuLaunch cause = content::CAUSE_FOR_GPU_LAUNCH_CANVAS_2D;
74 // Android does not support synchronous opening of GPU channels. Should use
75 // EstablishGpuChannel() instead.
76 scoped_refptr<content::GpuChannelHost> gpu_channel_host(
77 content::BrowserGpuChannelHostFactory::instance()->
78 EstablishGpuChannelSync(cause));
79 DCHECK(gpu_channel_host);
80 return CreateContextCommon(gpu_channel_host, 0);
81 }
82 #endif
83
84 typedef base::Callback<void(scoped_refptr<ContextProviderCommandBuffer>)>
85 ProcessContextCallback;
86
87 void CreateContextOnUIThread(ProcessContextCallback bottom_half) {
88 DCHECK_CURRENTLY_ON(BrowserThread::UI);
89 #if !defined(OS_ANDROID)
90 bottom_half.Run(ContextProviderCommandBuffer::Create(
91 CreateOffscreenCommandBufferContext(), "Offscreen-CaptureThread"));
92 return;
93 #endif
94 }
95
96 void ResetLostContextCallback(
97 const scoped_refptr<ContextProviderCommandBuffer>& capture_thread_context) {
98 capture_thread_context->SetLostContextCallback(
99 cc::ContextProvider::LostContextCallback());
100 }
101
102 } // anonymous namespace
103
23 // Class combining a Client::Buffer interface implementation and a pool buffer 104 // Class combining a Client::Buffer interface implementation and a pool buffer
24 // implementation to guarantee proper cleanup on destruction on our side. 105 // implementation to guarantee proper cleanup on destruction on our side.
25 class AutoReleaseBuffer : public media::VideoCaptureDevice::Client::Buffer { 106 class AutoReleaseBuffer : public media::VideoCaptureDevice::Client::Buffer {
26 public: 107 public:
27 AutoReleaseBuffer(const scoped_refptr<VideoCaptureBufferPool>& pool, 108 AutoReleaseBuffer(const scoped_refptr<VideoCaptureBufferPool>& pool,
28 int buffer_id, 109 int buffer_id)
29 void* data,
30 size_t size)
31 : pool_(pool), 110 : pool_(pool),
32 id_(buffer_id), 111 id_(buffer_id),
33 data_(data), 112 buffer_handle_(pool_->GetBufferHandle(buffer_id).Pass()) {
34 size_(size) {
35 DCHECK(pool_.get()); 113 DCHECK(pool_.get());
36 } 114 }
37 int id() const override { return id_; } 115 int id() const override { return id_; }
38 void* data() const override { return data_; } 116 size_t size() const override { return buffer_handle_->size(); }
39 size_t size() const override { return size_; } 117 scoped_ptr<media::DataHandle> GetDataHandle() override {
118 return buffer_handle_->GetDataHandle();
119 }
120 ClientBuffer AsClientBuffer() override {
121 return buffer_handle_->AsClientBuffer();
122 }
40 123
41 private: 124 private:
42 ~AutoReleaseBuffer() override { pool_->RelinquishProducerReservation(id_); } 125 ~AutoReleaseBuffer() override { pool_->RelinquishProducerReservation(id_); }
43 126
44 const scoped_refptr<VideoCaptureBufferPool> pool_; 127 const scoped_refptr<VideoCaptureBufferPool> pool_;
45 const int id_; 128 const int id_;
46 void* const data_; 129 const scoped_ptr<VideoCaptureBufferPool::BufferHandle> buffer_handle_;
47 const size_t size_; 130 };
131
132 // Internal ref-counted class wrap an incoming GpuMemoryBuffer into a Texture
133 // backed VideoFrame. This VideoFrame creation is balanced by a waiting on the
134 // associated |sync_point|. After VideoFrame consumption the inserted
135 // ReleaseCallback() will be called, where the GpuMemoryBuffer is recycled.
136 //
137 // This class jumps between threads due to GPU-related thread limitations, i.e.
138 // some objects cannot be accessed from IO Thread, where we are constructed,
139 // others need to be constructed on UI Thread. For this reason most of the
140 // operations are carried out on Capture Thread (|capture_task_runner_|).
141 class VideoCaptureDeviceClient::TextureWrapperDelegate final
142 : public base::RefCountedThreadSafe<TextureWrapperDelegate> {
143 public:
144 TextureWrapperDelegate(
145 const base::WeakPtr<VideoCaptureController>& controller,
146 const scoped_refptr<base::SingleThreadTaskRunner>& capture_task_runner,
147 const media::VideoCaptureFormat& capture_format);
148
149 // Wraps the GpuMemoryBuffer-backed |buffer| into a Texture, and sends it to
150 // |controller_| wrapped in a VideoFrame.
151 void OnIncomingCapturedGpuMemoryBuffer(
152 const scoped_refptr<media::VideoCaptureDevice::Client::Buffer>& buffer,
153 const gfx::Size& frame_size,
154 const base::TimeTicks& timestamp);
155
156 private:
157 friend class base::RefCountedThreadSafe<TextureWrapperDelegate>;
158 ~TextureWrapperDelegate();
159
160 // Creates some necessary members in |capture_task_runner_|.
161 void Init(const media::VideoCaptureFormat& capture_format);
162 // Runs the bottom half of the GlHelper creation.
163 void CreateGlHelper(
164 scoped_refptr<ContextProviderCommandBuffer> capture_thread_context);
165
166 // Recycles |memory_buffer|, deletes Image and Texture on VideoFrame release.
167 void ReleaseCallback(GLuint image_id,
168 GLuint texture_id,
169 //linked_ptr<gfx::GpuMemoryBuffer> memory_buffer,
170 uint32 sync_point);
171
172 // The Command Buffer lost the GL context, f.i. GPU process crashed. Signal
173 // error to our owner so the capture can be torn down.
174 void LostContextCallback();
175
176 // Prints the error |message| and notifies |controller_| of an error.
177 void OnError(const std::string& message);
178
179 const base::WeakPtr<VideoCaptureController> controller_;
180 const scoped_refptr<base::SingleThreadTaskRunner> capture_task_runner_;
181
182 // Command buffer reference, needs to be destroyed when unused. It is created
183 // on UI Thread and bound to Capture Thread. In particular, it cannot be used
184 // from IO Thread.
185 scoped_refptr<ContextProviderCommandBuffer> capture_thread_context_;
186 // Created and used from Capture Thread. Cannot be used from IO Thread.
187 scoped_ptr<GLHelper> gl_helper_;
188
189 DISALLOW_COPY_AND_ASSIGN(TextureWrapperDelegate);
48 }; 190 };
49 191
50 VideoCaptureDeviceClient::VideoCaptureDeviceClient( 192 VideoCaptureDeviceClient::VideoCaptureDeviceClient(
51 const base::WeakPtr<VideoCaptureController>& controller, 193 const base::WeakPtr<VideoCaptureController>& controller,
52 const scoped_refptr<VideoCaptureBufferPool>& buffer_pool) 194 const scoped_refptr<VideoCaptureBufferPool>& buffer_pool,
195 const scoped_refptr<base::SingleThreadTaskRunner>& capture_task_runner,
196 const media::VideoCaptureFormat& capture_format)
53 : controller_(controller), 197 : controller_(controller),
54 buffer_pool_(buffer_pool), 198 buffer_pool_(buffer_pool),
55 last_captured_pixel_format_(media::PIXEL_FORMAT_UNKNOWN) {} 199 wrapper_delegate_(
200 (capture_format.pixel_format == media::PIXEL_FORMAT_GPUMEMORYBUFFER)
201 ? new TextureWrapperDelegate(controller,
202 capture_task_runner,
203 capture_format)
204 : nullptr),
205 capture_task_runner_(capture_task_runner),
206 last_captured_pixel_format_(media::PIXEL_FORMAT_UNKNOWN) {
207 DCHECK_CURRENTLY_ON(BrowserThread::IO);
208 }
56 209
57 VideoCaptureDeviceClient::~VideoCaptureDeviceClient() {} 210 VideoCaptureDeviceClient::~VideoCaptureDeviceClient() {}
58 211
59 void VideoCaptureDeviceClient::OnIncomingCapturedData( 212 void VideoCaptureDeviceClient::OnIncomingCapturedData(
60 const uint8* data, 213 const uint8* data,
61 int length, 214 int length,
62 const VideoCaptureFormat& frame_format, 215 const VideoCaptureFormat& frame_format,
63 int rotation, 216 int rotation,
64 const base::TimeTicks& timestamp) { 217 const base::TimeTicks& timestamp) {
65 TRACE_EVENT0("video", "VideoCaptureDeviceClient::OnIncomingCapturedData"); 218 TRACE_EVENT0("video", "VideoCaptureDeviceClient::OnIncomingCapturedData");
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
103 gfx::Rect(dimensions), 256 gfx::Rect(dimensions),
104 dimensions)) { 257 dimensions)) {
105 return; 258 return;
106 } 259 }
107 260
108 scoped_refptr<Buffer> buffer = 261 scoped_refptr<Buffer> buffer =
109 ReserveOutputBuffer(media::PIXEL_FORMAT_I420, dimensions); 262 ReserveOutputBuffer(media::PIXEL_FORMAT_I420, dimensions);
110 if (!buffer.get()) 263 if (!buffer.get())
111 return; 264 return;
112 265
113 uint8* const yplane = reinterpret_cast<uint8*>(buffer->data()); 266 const scoped_ptr<media::DataHandle> scoped_data_handle =
267 buffer->GetDataHandle().Pass();
268 uint8* const yplane = reinterpret_cast<uint8*>(scoped_data_handle->data());
114 uint8* const uplane = 269 uint8* const uplane =
115 yplane + VideoFrame::PlaneAllocationSize(VideoFrame::I420, 270 yplane + VideoFrame::PlaneAllocationSize(VideoFrame::I420,
116 VideoFrame::kYPlane, dimensions); 271 VideoFrame::kYPlane, dimensions);
117 uint8* const vplane = 272 uint8* const vplane =
118 uplane + VideoFrame::PlaneAllocationSize(VideoFrame::I420, 273 uplane + VideoFrame::PlaneAllocationSize(VideoFrame::I420,
119 VideoFrame::kUPlane, dimensions); 274 VideoFrame::kUPlane, dimensions);
120 int yplane_stride = dimensions.width(); 275 int yplane_stride = dimensions.width();
121 int uv_plane_stride = yplane_stride / 2; 276 int uv_plane_stride = yplane_stride / 2;
122 int crop_x = 0; 277 int crop_x = 0;
123 int crop_y = 0; 278 int crop_y = 0;
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
194 (flip ? -1 : 1) * frame_format.frame_size.height(), 349 (flip ? -1 : 1) * frame_format.frame_size.height(),
195 new_unrotated_width, 350 new_unrotated_width,
196 new_unrotated_height, 351 new_unrotated_height,
197 rotation_mode, 352 rotation_mode,
198 origin_colorspace) != 0) { 353 origin_colorspace) != 0) {
199 DLOG(WARNING) << "Failed to convert buffer's pixel format to I420 from " 354 DLOG(WARNING) << "Failed to convert buffer's pixel format to I420 from "
200 << media::VideoCaptureFormat::PixelFormatToString( 355 << media::VideoCaptureFormat::PixelFormatToString(
201 frame_format.pixel_format); 356 frame_format.pixel_format);
202 return; 357 return;
203 } 358 }
204 scoped_refptr<VideoFrame> frame =
205 VideoFrame::WrapExternalPackedMemory(
206 VideoFrame::I420,
207 dimensions,
208 gfx::Rect(dimensions),
209 dimensions,
210 yplane,
211 VideoFrame::AllocationSize(VideoFrame::I420, dimensions),
212 base::SharedMemory::NULLHandle(),
213 0,
214 base::TimeDelta(),
215 base::Closure());
216 DCHECK(frame.get());
217 frame->metadata()->SetDouble(media::VideoFrameMetadata::FRAME_RATE,
218 frame_format.frame_rate);
219 359
220 BrowserThread::PostTask( 360 OnIncomingCapturedBuffer(buffer,
221 BrowserThread::IO, 361 media::VideoCaptureFormat(dimensions,
222 FROM_HERE, 362 frame_format.frame_rate,
223 base::Bind( 363 media::PIXEL_FORMAT_I420),
224 &VideoCaptureController::DoIncomingCapturedVideoFrameOnIOThread, 364 timestamp);
225 controller_,
226 buffer,
227 frame,
228 timestamp));
229 } 365 }
230 366
231 void 367 void
232 VideoCaptureDeviceClient::OnIncomingCapturedYuvData( 368 VideoCaptureDeviceClient::OnIncomingCapturedYuvData(
233 const uint8* y_data, 369 const uint8* y_data,
234 const uint8* u_data, 370 const uint8* u_data,
235 const uint8* v_data, 371 const uint8* v_data,
236 size_t y_stride, 372 size_t y_stride,
237 size_t u_stride, 373 size_t u_stride,
238 size_t v_stride, 374 size_t v_stride,
239 const VideoCaptureFormat& frame_format, 375 const VideoCaptureFormat& frame_format,
240 int clockwise_rotation, 376 int clockwise_rotation,
241 const base::TimeTicks& timestamp) { 377 const base::TimeTicks& timestamp) {
242 TRACE_EVENT0("video", "VideoCaptureDeviceClient::OnIncomingCapturedYuvData"); 378 TRACE_EVENT0("video", "VideoCaptureDeviceClient::OnIncomingCapturedYuvData");
243 DCHECK_EQ(frame_format.pixel_format, media::PIXEL_FORMAT_I420); 379 DCHECK_EQ(frame_format.pixel_format, media::PIXEL_FORMAT_I420);
244 DCHECK_EQ(clockwise_rotation, 0) << "Rotation not supported"; 380 DCHECK_EQ(clockwise_rotation, 0) << "Rotation not supported";
245 381
246 scoped_refptr<Buffer> buffer = 382 scoped_refptr<Buffer> buffer =
247 ReserveOutputBuffer(frame_format.pixel_format, frame_format.frame_size); 383 ReserveOutputBuffer(frame_format.pixel_format, frame_format.frame_size);
248 if (!buffer.get()) 384 if (!buffer.get())
249 return; 385 return;
386 const scoped_ptr<media::DataHandle> scoped_data_handle =
387 buffer->GetDataHandle().Pass();
250 388
251 // Blit (copy) here from y,u,v into buffer.data()). Needed so we can return 389 // Blit (copy) here from y,u,v into buffer.data()). Needed so we can return
252 // the parameter buffer synchronously to the driver. 390 // the parameter buffer synchronously to the driver.
253 const size_t y_plane_size = VideoFrame::PlaneAllocationSize(VideoFrame::I420, 391 const size_t y_plane_size = VideoFrame::PlaneAllocationSize(VideoFrame::I420,
254 VideoFrame::kYPlane, frame_format.frame_size); 392 VideoFrame::kYPlane, frame_format.frame_size);
255 const size_t u_plane_size = VideoFrame::PlaneAllocationSize( 393 const size_t u_plane_size = VideoFrame::PlaneAllocationSize(
256 VideoFrame::I420, VideoFrame::kUPlane, frame_format.frame_size); 394 VideoFrame::I420, VideoFrame::kUPlane, frame_format.frame_size);
257 uint8* const dst_y = reinterpret_cast<uint8*>(buffer->data()); 395 uint8* const dst_y = reinterpret_cast<uint8*>(scoped_data_handle->data());
258 uint8* const dst_u = dst_y + y_plane_size; 396 uint8* const dst_u = dst_y + y_plane_size;
259 uint8* const dst_v = dst_u + u_plane_size; 397 uint8* const dst_v = dst_u + u_plane_size;
260 398
261 const size_t dst_y_stride = VideoFrame::RowBytes( 399 const size_t dst_y_stride = VideoFrame::RowBytes(
262 VideoFrame::kYPlane, VideoFrame::I420, frame_format.frame_size.width()); 400 VideoFrame::kYPlane, VideoFrame::I420, frame_format.frame_size.width());
263 const size_t dst_u_stride = VideoFrame::RowBytes( 401 const size_t dst_u_stride = VideoFrame::RowBytes(
264 VideoFrame::kUPlane, VideoFrame::I420, frame_format.frame_size.width()); 402 VideoFrame::kUPlane, VideoFrame::I420, frame_format.frame_size.width());
265 const size_t dst_v_stride = VideoFrame::RowBytes( 403 const size_t dst_v_stride = VideoFrame::RowBytes(
266 VideoFrame::kVPlane, VideoFrame::I420, frame_format.frame_size.width()); 404 VideoFrame::kVPlane, VideoFrame::I420, frame_format.frame_size.width());
267 DCHECK_GE(y_stride, dst_y_stride); 405 DCHECK_GE(y_stride, dst_y_stride);
268 DCHECK_GE(u_stride, dst_u_stride); 406 DCHECK_GE(u_stride, dst_u_stride);
269 DCHECK_GE(v_stride, dst_v_stride); 407 DCHECK_GE(v_stride, dst_v_stride);
270 408
271 if (libyuv::I420Copy(y_data, y_stride, 409 if (libyuv::I420Copy(y_data, y_stride,
272 u_data, u_stride, 410 u_data, u_stride,
273 v_data, v_stride, 411 v_data, v_stride,
274 dst_y, dst_y_stride, 412 dst_y, dst_y_stride,
275 dst_u, dst_u_stride, 413 dst_u, dst_u_stride,
276 dst_v, dst_v_stride, 414 dst_v, dst_v_stride,
277 frame_format.frame_size.width(), 415 frame_format.frame_size.width(),
278 frame_format.frame_size.height())) { 416 frame_format.frame_size.height())) {
279 DLOG(WARNING) << "Failed to copy buffer"; 417 DLOG(WARNING) << "Failed to copy buffer";
280 return; 418 return;
281 } 419 }
282 420
283 scoped_refptr<VideoFrame> video_frame = VideoFrame::WrapExternalYuvData( 421 OnIncomingCapturedBuffer(buffer, frame_format, timestamp);
284 VideoFrame::I420, frame_format.frame_size,
285 gfx::Rect(frame_format.frame_size), frame_format.frame_size, y_stride,
286 u_stride, v_stride, dst_y, dst_u, dst_v, base::TimeDelta(),
287 base::Closure());
288 DCHECK(video_frame.get());
289 video_frame->metadata()->SetDouble(media::VideoFrameMetadata::FRAME_RATE,
290 frame_format.frame_rate);
291
292 BrowserThread::PostTask(
293 BrowserThread::IO,
294 FROM_HERE,
295 base::Bind(
296 &VideoCaptureController::DoIncomingCapturedVideoFrameOnIOThread,
297 controller_,
298 buffer,
299 video_frame,
300 timestamp));
301 }; 422 };
302 423
303 scoped_refptr<media::VideoCaptureDevice::Client::Buffer> 424 scoped_refptr<media::VideoCaptureDevice::Client::Buffer>
304 VideoCaptureDeviceClient::ReserveOutputBuffer(media::VideoPixelFormat format, 425 VideoCaptureDeviceClient::ReserveOutputBuffer(media::VideoPixelFormat format,
305 const gfx::Size& dimensions) { 426 const gfx::Size& dimensions) {
306 DCHECK(format == media::PIXEL_FORMAT_TEXTURE || 427 DCHECK(format == media::PIXEL_FORMAT_I420 ||
307 format == media::PIXEL_FORMAT_I420 || 428 format == media::PIXEL_FORMAT_TEXTURE ||
308 format == media::PIXEL_FORMAT_ARGB); 429 format == media::PIXEL_FORMAT_GPUMEMORYBUFFER);
309 DCHECK_GT(dimensions.width(), 0); 430 DCHECK_GT(dimensions.width(), 0);
310 DCHECK_GT(dimensions.height(), 0); 431 DCHECK_GT(dimensions.height(), 0);
311 432
312 int buffer_id_to_drop = VideoCaptureBufferPool::kInvalidId; 433 int buffer_id_to_drop = VideoCaptureBufferPool::kInvalidId;
313 const int buffer_id = 434 const int buffer_id =
314 buffer_pool_->ReserveForProducer(format, dimensions, &buffer_id_to_drop); 435 buffer_pool_->ReserveForProducer(format, dimensions, &buffer_id_to_drop);
315 if (buffer_id == VideoCaptureBufferPool::kInvalidId) 436 if (buffer_id == VideoCaptureBufferPool::kInvalidId)
316 return NULL; 437 return NULL;
317 void* data;
318 size_t size;
319 buffer_pool_->GetBufferInfo(buffer_id, &data, &size);
320 438
321 scoped_refptr<media::VideoCaptureDevice::Client::Buffer> output_buffer( 439 scoped_refptr<media::VideoCaptureDevice::Client::Buffer> output_buffer(
322 new AutoReleaseBuffer(buffer_pool_, buffer_id, data, size)); 440 new AutoReleaseBuffer(buffer_pool_, buffer_id));
323 441
324 if (buffer_id_to_drop != VideoCaptureBufferPool::kInvalidId) { 442 if (buffer_id_to_drop != VideoCaptureBufferPool::kInvalidId) {
325 BrowserThread::PostTask(BrowserThread::IO, 443 BrowserThread::PostTask(BrowserThread::IO,
326 FROM_HERE, 444 FROM_HERE,
327 base::Bind(&VideoCaptureController::DoBufferDestroyedOnIOThread, 445 base::Bind(&VideoCaptureController::DoBufferDestroyedOnIOThread,
328 controller_, buffer_id_to_drop)); 446 controller_, buffer_id_to_drop));
329 } 447 }
330 448
331 return output_buffer; 449 return output_buffer;
332 } 450 }
333 451
334 void 452 void VideoCaptureDeviceClient::OnIncomingCapturedBuffer(
335 VideoCaptureDeviceClient::OnIncomingCapturedVideoFrame( 453 const scoped_refptr<Buffer>& buffer,
454 const media::VideoCaptureFormat& frame_format,
455 const base::TimeTicks& timestamp) {
456 if (frame_format.pixel_format == media::PIXEL_FORMAT_GPUMEMORYBUFFER) {
457 capture_task_runner_->PostTask(
458 FROM_HERE,
459 base::Bind(
460 &TextureWrapperDelegate::OnIncomingCapturedGpuMemoryBuffer,
461 wrapper_delegate_,
462 buffer,
463 frame_format.frame_size,
464 timestamp));
465 } else {
466 const scoped_ptr<media::DataHandle> scoped_data_handle =
467 buffer->GetDataHandle().Pass();
468
469 scoped_refptr<VideoFrame> video_frame =
470 VideoFrame::WrapExternalPackedMemory(
471 VideoFrame::I420,
472 frame_format.frame_size,
473 gfx::Rect(frame_format.frame_size),
474 frame_format.frame_size,
475 reinterpret_cast<uint8*>(scoped_data_handle->data()),
476 VideoFrame::AllocationSize(VideoFrame::I420,
477 frame_format.frame_size),
478 base::SharedMemory::NULLHandle(),
479 0 /* shared_memory_offset */,
480 base::TimeDelta(),
481 base::Closure());
482 DCHECK(video_frame.get());
483 video_frame->metadata()->SetDouble(media::VideoFrameMetadata::FRAME_RATE,
484 frame_format.frame_rate);
485
486 OnIncomingCapturedVideoFrame(buffer,
487 video_frame,
488 timestamp);
489 }
490 }
491
492 void VideoCaptureDeviceClient::OnIncomingCapturedVideoFrame(
336 const scoped_refptr<Buffer>& buffer, 493 const scoped_refptr<Buffer>& buffer,
337 const scoped_refptr<VideoFrame>& frame, 494 const scoped_refptr<VideoFrame>& frame,
338 const base::TimeTicks& timestamp) { 495 const base::TimeTicks& timestamp) {
339 BrowserThread::PostTask( 496 BrowserThread::PostTask(
340 BrowserThread::IO, 497 BrowserThread::IO,
341 FROM_HERE, 498 FROM_HERE,
342 base::Bind( 499 base::Bind(
343 &VideoCaptureController::DoIncomingCapturedVideoFrameOnIOThread, 500 &VideoCaptureController::DoIncomingCapturedVideoFrameOnIOThread,
344 controller_, 501 controller_,
345 buffer, 502 buffer,
(...skipping 15 matching lines...) Expand all
361 base::Bind(&VideoCaptureController::DoErrorOnIOThread, controller_)); 518 base::Bind(&VideoCaptureController::DoErrorOnIOThread, controller_));
362 } 519 }
363 520
364 void VideoCaptureDeviceClient::OnLog( 521 void VideoCaptureDeviceClient::OnLog(
365 const std::string& message) { 522 const std::string& message) {
366 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, 523 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
367 base::Bind(&VideoCaptureController::DoLogOnIOThread, 524 base::Bind(&VideoCaptureController::DoLogOnIOThread,
368 controller_, message)); 525 controller_, message));
369 } 526 }
370 527
528 VideoCaptureDeviceClient::TextureWrapperDelegate::TextureWrapperDelegate(
529 const base::WeakPtr<VideoCaptureController>& controller,
530 const scoped_refptr<base::SingleThreadTaskRunner>& capture_task_runner,
531 const media::VideoCaptureFormat& capture_format)
532 : controller_(controller),
533 capture_task_runner_(capture_task_runner) {
534 DCHECK_CURRENTLY_ON(BrowserThread::IO);
535 capture_task_runner_->PostTask(FROM_HERE,
536 base::Bind(&TextureWrapperDelegate::Init, this, capture_format));
537 }
538
539 void VideoCaptureDeviceClient::TextureWrapperDelegate::
540 OnIncomingCapturedGpuMemoryBuffer(
541 const scoped_refptr<media::VideoCaptureDevice::Client::Buffer>& buffer,
542 const gfx::Size& frame_size,
543 const base::TimeTicks& timestamp) {
544 DCHECK(capture_task_runner_->BelongsToCurrentThread());
545 DVLOG_IF(1, !gl_helper_) << " Skipping ingress frame, no GL context.";
546 if (!gl_helper_)
547 return;
548
549 gpu::gles2::GLES2Interface* gl = capture_thread_context_->ContextGL();
550 GLuint image_id = gl->CreateImageCHROMIUM(buffer->AsClientBuffer(),
551 frame_size.width(),
552 frame_size.height(), GL_BGRA_EXT);
553 DCHECK(image_id);
554
555 GLuint texture_id = gl_helper_->CreateTexture();
556 DCHECK(texture_id);
557 {
558 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl, texture_id);
559 gl->BindTexImage2DCHROMIUM(GL_TEXTURE_2D, image_id);
560 }
561
562 scoped_ptr<gpu::MailboxHolder> mailbox_holder(new gpu::MailboxHolder(
563 gl_helper_->ProduceMailboxHolderFromTexture(texture_id)));
564 DCHECK(!mailbox_holder->mailbox.IsZero());
565 DCHECK(mailbox_holder->mailbox.Verify());
566 DCHECK(mailbox_holder->texture_target);
567 DCHECK(mailbox_holder->sync_point);
568
569 scoped_refptr<media::VideoFrame> video_frame =
570 media::VideoFrame::WrapNativeTexture(
571 mailbox_holder.Pass(),
572 media::BindToCurrentLoop(
573 base::Bind(&VideoCaptureDeviceClient::TextureWrapperDelegate::
574 ReleaseCallback,
575 this, image_id, texture_id /* gpu_memory_buffer */ )),
576 frame_size,
577 gfx::Rect(frame_size),
578 frame_size,
579 base::TimeDelta(),
580 true /* allow_overlay */);
581
582 BrowserThread::PostTask(
583 BrowserThread::IO, FROM_HERE,
584 base::Bind(
585 &VideoCaptureController::DoIncomingCapturedVideoFrameOnIOThread,
586 controller_, buffer, video_frame, timestamp));
587 }
588
589 VideoCaptureDeviceClient::TextureWrapperDelegate::~TextureWrapperDelegate() {
590 // Might not be running on capture_task_runner_'s thread. Ensure owned objects
591 // are destroyed on the correct threads.
592 if (gl_helper_)
593 capture_task_runner_->DeleteSoon(FROM_HERE, gl_helper_.release());
594
595 if (capture_thread_context_) {
596 capture_task_runner_->PostTask(
597 FROM_HERE,
598 base::Bind(&ResetLostContextCallback, capture_thread_context_));
599 capture_thread_context_->AddRef();
600 ContextProviderCommandBuffer* raw_capture_thread_context =
601 capture_thread_context_.get();
602 capture_thread_context_ = nullptr;
603 capture_task_runner_->ReleaseSoon(FROM_HERE, raw_capture_thread_context);
604 }
605 }
606
607 void VideoCaptureDeviceClient::TextureWrapperDelegate::Init(
608 const media::VideoCaptureFormat& capture_format) {
609 DCHECK(capture_task_runner_->BelongsToCurrentThread());
610
611 // In threaded compositing mode, we have to create our own context for Capture
612 // to avoid using the GPU command queue from multiple threads. Context
613 // creation must happen on UI thread; then the context needs to be bound to
614 // the appropriate thread, which is done in CreateGlHelper().
615 BrowserThread::PostTask(
616 BrowserThread::UI, FROM_HERE,
617 base::Bind(&CreateContextOnUIThread,
618 media::BindToCurrentLoop(
619 base::Bind(&VideoCaptureDeviceClient::
620 TextureWrapperDelegate::CreateGlHelper,
621 this))));
622 }
623
624 void VideoCaptureDeviceClient::TextureWrapperDelegate::CreateGlHelper(
625 scoped_refptr<ContextProviderCommandBuffer> capture_thread_context) {
626 DCHECK(capture_task_runner_->BelongsToCurrentThread());
627
628 if (!capture_thread_context.get()) {
629 DLOG(ERROR) << "No offscreen GL Context!";
630 return;
631 }
632 // This may not happen in IO Thread. The destructor resets the context lost
633 // callback, so base::Unretained is safe; otherwise it'd be a circular ref
634 // counted dependency.
635 capture_thread_context->SetLostContextCallback(media::BindToCurrentLoop(
636 base::Bind(
637 &VideoCaptureDeviceClient::TextureWrapperDelegate::
638 LostContextCallback,
639 base::Unretained(this))));
640 if (!capture_thread_context->BindToCurrentThread()) {
641 capture_thread_context = NULL;
642 DLOG(ERROR) << "Couldn't bind the Capture Context to the Capture Thread.";
643 return;
644 }
645 DCHECK(capture_thread_context);
646 capture_thread_context_ = capture_thread_context;
647
648 // At this point, |capture_thread_context| is a cc::ContextProvider. Creation
649 // of our GLHelper should happen on Capture Thread.
650 gl_helper_.reset(new GLHelper(capture_thread_context->ContextGL(),
651 capture_thread_context->ContextSupport()));
652 DCHECK(gl_helper_);
653 }
654
655 void VideoCaptureDeviceClient::TextureWrapperDelegate::ReleaseCallback(
656 GLuint image_id,
657 GLuint texture_id,
658 uint32 sync_point) {
659 DCHECK(capture_task_runner_->BelongsToCurrentThread());
660
661 if (gl_helper_) {
662 gl_helper_->DeleteTexture(texture_id);
663 capture_thread_context_->ContextGL()->DestroyImageCHROMIUM(image_id);
664 }
665 }
666
667 void VideoCaptureDeviceClient::TextureWrapperDelegate::LostContextCallback() {
668 DCHECK(capture_task_runner_->BelongsToCurrentThread());
669 // Prevent incoming frames from being processed while OnError gets groked.
670 gl_helper_.reset();
671 OnError("GLContext lost");
672 }
673
674 void VideoCaptureDeviceClient::TextureWrapperDelegate::OnError(
675 const std::string& message) {
676 DCHECK(capture_task_runner_->BelongsToCurrentThread());
677 DLOG(ERROR) << message;
678 BrowserThread::PostTask(
679 BrowserThread::IO, FROM_HERE,
680 base::Bind(&VideoCaptureController::DoErrorOnIOThread, controller_));
681 }
682
371 } // namespace content 683 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698