OLD | NEW |
---|---|
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 <algorithm> | 7 #include <algorithm> |
8 #include <utility> | 8 #include <utility> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "base/command_line.h" | 11 #include "base/command_line.h" |
12 #include "base/location.h" | 12 #include "base/location.h" |
13 #include "base/memory/ptr_util.h" | 13 #include "base/memory/ptr_util.h" |
14 #include "base/strings/stringprintf.h" | 14 #include "base/strings/stringprintf.h" |
15 #include "base/trace_event/trace_event.h" | 15 #include "base/trace_event/trace_event.h" |
16 #include "build/build_config.h" | 16 #include "build/build_config.h" |
17 #include "content/browser/renderer_host/media/video_capture_buffer_pool.h" | 17 #include "content/browser/renderer_host/media/video_capture_buffer_pool.h" |
18 #include "content/browser/renderer_host/media/video_capture_controller.h" | 18 #include "content/browser/renderer_host/media/video_capture_controller.h" |
19 #include "content/browser/renderer_host/media/video_capture_gpu_jpeg_decoder.h" | 19 #include "content/browser/renderer_host/media/video_capture_gpu_jpeg_decoder.h" |
20 #include "content/public/browser/browser_thread.h" | |
21 #include "media/base/bind_to_current_loop.h" | 20 #include "media/base/bind_to_current_loop.h" |
22 #include "media/base/media_switches.h" | 21 #include "media/base/media_switches.h" |
23 #include "media/base/video_capture_types.h" | 22 #include "media/base/video_capture_types.h" |
24 #include "media/base/video_frame.h" | 23 #include "media/base/video_frame.h" |
25 #include "third_party/libyuv/include/libyuv.h" | 24 #include "third_party/libyuv/include/libyuv.h" |
26 | 25 |
27 using media::VideoCaptureFormat; | 26 using media::VideoCaptureFormat; |
28 using media::VideoFrame; | 27 using media::VideoFrame; |
29 using media::VideoFrameMetadata; | 28 using media::VideoFrameMetadata; |
30 | 29 |
31 namespace content { | 30 namespace content { |
32 | 31 |
33 // Class combining a Client::Buffer interface implementation and a pool buffer | 32 // Class combining a Client::Buffer interface implementation and a pool buffer |
34 // implementation to guarantee proper cleanup on destruction on our side. | 33 // implementation to guarantee proper cleanup on destruction on our side. |
35 class AutoReleaseBuffer : public media::VideoCaptureDevice::Client::Buffer { | 34 class AutoReleaseBuffer : public media::VideoCaptureDevice::Client::Buffer { |
36 public: | 35 public: |
37 AutoReleaseBuffer(const scoped_refptr<VideoCaptureBufferPool>& pool, | 36 AutoReleaseBuffer(const scoped_refptr<VideoCaptureBufferPoolInterface>& pool, |
38 int buffer_id) | 37 int buffer_id) |
39 : id_(buffer_id), | 38 : id_(buffer_id), |
40 pool_(pool), | 39 pool_(pool), |
41 buffer_handle_(pool_->GetBufferHandle(buffer_id)) { | 40 buffer_handle_(pool_->GetBufferHandle(buffer_id)) { |
42 DCHECK(pool_.get()); | 41 DCHECK(pool_.get()); |
43 } | 42 } |
44 int id() const override { return id_; } | 43 int id() const override { return id_; } |
45 gfx::Size dimensions() const override { return buffer_handle_->dimensions(); } | 44 gfx::Size dimensions() const override { return buffer_handle_->dimensions(); } |
46 size_t mapped_size() const override { return buffer_handle_->mapped_size(); } | 45 size_t mapped_size() const override { return buffer_handle_->mapped_size(); } |
47 void* data(int plane) override { return buffer_handle_->data(plane); } | 46 void* data(int plane) override { return buffer_handle_->data(plane); } |
48 ClientBuffer AsClientBuffer(int plane) override { | 47 ClientBuffer AsClientBuffer(int plane) override { |
49 return buffer_handle_->AsClientBuffer(plane); | 48 return buffer_handle_->AsClientBuffer(plane); |
50 } | 49 } |
51 #if defined(OS_POSIX) && !defined(OS_MACOSX) | 50 #if defined(OS_POSIX) && !defined(OS_MACOSX) |
52 base::FileDescriptor AsPlatformFile() override { | 51 base::FileDescriptor AsPlatformFile() override { |
53 return buffer_handle_->AsPlatformFile(); | 52 return buffer_handle_->AsPlatformFile(); |
54 } | 53 } |
55 #endif | 54 #endif |
56 | 55 |
57 private: | 56 private: |
58 ~AutoReleaseBuffer() override { pool_->RelinquishProducerReservation(id_); } | 57 ~AutoReleaseBuffer() override { pool_->RelinquishProducerReservation(id_); } |
59 | 58 |
60 const int id_; | 59 const int id_; |
61 const scoped_refptr<VideoCaptureBufferPool> pool_; | 60 const scoped_refptr<VideoCaptureBufferPoolInterface> pool_; |
62 const std::unique_ptr<VideoCaptureBufferPool::BufferHandle> buffer_handle_; | 61 const std::unique_ptr<VideoCaptureBufferPoolBufferHandle> buffer_handle_; |
63 }; | 62 }; |
64 | 63 |
65 VideoCaptureDeviceClient::VideoCaptureDeviceClient( | 64 VideoCaptureDeviceClient::VideoCaptureDeviceClient( |
66 const base::WeakPtr<VideoCaptureController>& controller, | 65 std::unique_ptr<VideoFrameReceiver> receiver, |
67 const scoped_refptr<VideoCaptureBufferPool>& buffer_pool) | 66 const scoped_refptr<VideoCaptureBufferPoolInterface>& buffer_pool, |
68 : controller_(controller), | 67 std::unique_ptr<VideoCaptureJpegDecoderFactory> jpeg_decoder_factory, |
68 const base::Closure& check_thread_closure) | |
69 : receiver_(std::move(receiver)), | |
70 jpeg_decoder_factory_(std::move(jpeg_decoder_factory)), | |
69 external_jpeg_decoder_initialized_(false), | 71 external_jpeg_decoder_initialized_(false), |
70 buffer_pool_(buffer_pool), | 72 buffer_pool_(buffer_pool), |
71 use_gpu_memory_buffers_(base::CommandLine::ForCurrentProcess()->HasSwitch( | 73 use_gpu_memory_buffers_(base::CommandLine::ForCurrentProcess()->HasSwitch( |
72 switches::kUseGpuMemoryBuffersForCapture)), | 74 switches::kUseGpuMemoryBuffersForCapture)), |
73 last_captured_pixel_format_(media::PIXEL_FORMAT_UNKNOWN) { | 75 last_captured_pixel_format_(media::PIXEL_FORMAT_UNKNOWN) { |
74 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 76 check_thread_closure.Run(); |
mcasas
2016/09/07 22:43:40
I'd rather pass a const SingleThreadTaskRunner& wh
chfremer
2016/09/08 17:28:51
Please explain why you would prefer doing that.
I
mcasas
2016/09/08 20:25:45
But SingleThreadTaskRunners are pervasively passed
chfremer
2016/09/09 00:55:37
Being more opaque here is actually a good thing, s
chfremer
2016/09/09 16:48:06
After looking at it one more time, I decided to si
| |
75 } | 77 } |
76 | 78 |
77 VideoCaptureDeviceClient::~VideoCaptureDeviceClient() { | 79 VideoCaptureDeviceClient::~VideoCaptureDeviceClient() { |
78 // This should be on the platform auxiliary thread since | 80 // This should be on the platform auxiliary thread since |
79 // |external_jpeg_decoder_| need to be destructed on the same thread as | 81 // |external_jpeg_decoder_| need to be destructed on the same thread as |
80 // OnIncomingCapturedData. | 82 // OnIncomingCapturedData. |
81 } | 83 } |
82 | 84 |
83 void VideoCaptureDeviceClient::OnIncomingCapturedData( | 85 void VideoCaptureDeviceClient::OnIncomingCapturedData( |
84 const uint8_t* data, | 86 const uint8_t* data, |
85 int length, | 87 int length, |
86 const VideoCaptureFormat& frame_format, | 88 const VideoCaptureFormat& frame_format, |
87 int rotation, | 89 int rotation, |
88 base::TimeTicks reference_time, | 90 base::TimeTicks reference_time, |
89 base::TimeDelta timestamp) { | 91 base::TimeDelta timestamp) { |
90 TRACE_EVENT0("video", "VideoCaptureDeviceClient::OnIncomingCapturedData"); | 92 TRACE_EVENT0("video", "VideoCaptureDeviceClient::OnIncomingCapturedData"); |
91 DCHECK_EQ(media::PIXEL_STORAGE_CPU, frame_format.pixel_storage); | 93 DCHECK_EQ(media::PIXEL_STORAGE_CPU, frame_format.pixel_storage); |
92 | 94 |
93 if (last_captured_pixel_format_ != frame_format.pixel_format) { | 95 if (last_captured_pixel_format_ != frame_format.pixel_format) { |
94 OnLog("Pixel format: " + | 96 OnLog("Pixel format: " + |
95 media::VideoPixelFormatToString(frame_format.pixel_format)); | 97 media::VideoPixelFormatToString(frame_format.pixel_format)); |
96 last_captured_pixel_format_ = frame_format.pixel_format; | 98 last_captured_pixel_format_ = frame_format.pixel_format; |
97 | 99 |
98 if (frame_format.pixel_format == media::PIXEL_FORMAT_MJPEG && | 100 if (frame_format.pixel_format == media::PIXEL_FORMAT_MJPEG && |
99 !external_jpeg_decoder_initialized_) { | 101 !external_jpeg_decoder_initialized_) { |
100 external_jpeg_decoder_initialized_ = true; | 102 external_jpeg_decoder_initialized_ = true; |
mcasas
2016/09/07 22:43:40
I think we can remove this flag and test
|external
chfremer
2016/09/08 17:28:51
Not sure we can do that without changing behavior.
mcasas
2016/09/08 20:25:45
I see, forget it then.
chfremer
2016/09/09 00:55:37
Acknowledged.
| |
101 external_jpeg_decoder_.reset(new VideoCaptureGpuJpegDecoder(base::Bind( | 103 external_jpeg_decoder_ = jpeg_decoder_factory_->CreateJpegDecoder(); |
102 &VideoCaptureController::DoIncomingCapturedVideoFrameOnIOThread, | |
103 controller_))); | |
104 external_jpeg_decoder_->Initialize(); | 104 external_jpeg_decoder_->Initialize(); |
105 } | 105 } |
106 } | 106 } |
107 | 107 |
108 if (!frame_format.IsValid()) | 108 if (!frame_format.IsValid()) |
109 return; | 109 return; |
110 | 110 |
111 // |chopped_{width,height} and |new_unrotated_{width,height}| are the lowest | 111 // |chopped_{width,height} and |new_unrotated_{width,height}| are the lowest |
112 // bit decomposition of {width, height}, grabbing the odd and even parts. | 112 // bit decomposition of {width, height}, grabbing the odd and even parts. |
113 const int chopped_width = frame_format.frame_size.width() & 1; | 113 const int chopped_width = frame_format.frame_size.width() & 1; |
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
269 const gfx::Size& frame_size, | 269 const gfx::Size& frame_size, |
270 media::VideoPixelFormat pixel_format, | 270 media::VideoPixelFormat pixel_format, |
271 media::VideoPixelStorage pixel_storage) { | 271 media::VideoPixelStorage pixel_storage) { |
272 DCHECK_GT(frame_size.width(), 0); | 272 DCHECK_GT(frame_size.width(), 0); |
273 DCHECK_GT(frame_size.height(), 0); | 273 DCHECK_GT(frame_size.height(), 0); |
274 // Currently, only I420 pixel format is supported. | 274 // Currently, only I420 pixel format is supported. |
275 DCHECK_EQ(media::PIXEL_FORMAT_I420, pixel_format); | 275 DCHECK_EQ(media::PIXEL_FORMAT_I420, pixel_format); |
276 | 276 |
277 // TODO(mcasas): For PIXEL_STORAGE_GPUMEMORYBUFFER, find a way to indicate if | 277 // TODO(mcasas): For PIXEL_STORAGE_GPUMEMORYBUFFER, find a way to indicate if |
278 // it's a ShMem GMB or a DmaBuf GMB. | 278 // it's a ShMem GMB or a DmaBuf GMB. |
279 int buffer_id_to_drop = VideoCaptureBufferPool::kInvalidId; | 279 int buffer_id_to_drop = VideoCaptureBufferPoolInterface::kInvalidId; |
280 const int buffer_id = buffer_pool_->ReserveForProducer( | 280 const int buffer_id = buffer_pool_->ReserveForProducer( |
281 frame_size, pixel_format, pixel_storage, &buffer_id_to_drop); | 281 frame_size, pixel_format, pixel_storage, &buffer_id_to_drop); |
282 if (buffer_id_to_drop != VideoCaptureBufferPool::kInvalidId) { | 282 if (buffer_id_to_drop != VideoCaptureBufferPoolInterface::kInvalidId) { |
283 BrowserThread::PostTask(BrowserThread::IO, | 283 receiver_->OnBufferDestroyed(buffer_id_to_drop); |
284 FROM_HERE, | |
285 base::Bind(&VideoCaptureController::DoBufferDestroyedOnIOThread, | |
286 controller_, buffer_id_to_drop)); | |
287 } | 284 } |
mcasas
2016/09/07 22:43:40
nit: Remove {}
chfremer
2016/09/08 17:28:51
Done.
| |
288 if (buffer_id == VideoCaptureBufferPool::kInvalidId) | 285 if (buffer_id == VideoCaptureBufferPoolInterface::kInvalidId) |
289 return nullptr; | 286 return nullptr; |
290 return base::WrapUnique<Buffer>( | 287 return base::WrapUnique<Buffer>( |
291 new AutoReleaseBuffer(buffer_pool_, buffer_id)); | 288 new AutoReleaseBuffer(buffer_pool_, buffer_id)); |
292 } | 289 } |
293 | 290 |
294 void VideoCaptureDeviceClient::OnIncomingCapturedBuffer( | 291 void VideoCaptureDeviceClient::OnIncomingCapturedBuffer( |
295 std::unique_ptr<Buffer> buffer, | 292 std::unique_ptr<Buffer> buffer, |
296 const VideoCaptureFormat& frame_format, | 293 const VideoCaptureFormat& frame_format, |
297 base::TimeTicks reference_time, | 294 base::TimeTicks reference_time, |
298 base::TimeDelta timestamp) { | 295 base::TimeDelta timestamp) { |
(...skipping 29 matching lines...) Expand all Loading... | |
328 frame->metadata()->SetDouble(media::VideoFrameMetadata::FRAME_RATE, | 325 frame->metadata()->SetDouble(media::VideoFrameMetadata::FRAME_RATE, |
329 frame_format.frame_rate); | 326 frame_format.frame_rate); |
330 frame->metadata()->SetTimeTicks(media::VideoFrameMetadata::REFERENCE_TIME, | 327 frame->metadata()->SetTimeTicks(media::VideoFrameMetadata::REFERENCE_TIME, |
331 reference_time); | 328 reference_time); |
332 OnIncomingCapturedVideoFrame(std::move(buffer), frame); | 329 OnIncomingCapturedVideoFrame(std::move(buffer), frame); |
333 } | 330 } |
334 | 331 |
335 void VideoCaptureDeviceClient::OnIncomingCapturedVideoFrame( | 332 void VideoCaptureDeviceClient::OnIncomingCapturedVideoFrame( |
336 std::unique_ptr<Buffer> buffer, | 333 std::unique_ptr<Buffer> buffer, |
337 const scoped_refptr<VideoFrame>& frame) { | 334 const scoped_refptr<VideoFrame>& frame) { |
338 BrowserThread::PostTask( | 335 receiver_->OnIncomingCapturedVideoFrame(std::move(buffer), frame); |
339 BrowserThread::IO, FROM_HERE, | |
340 base::Bind( | |
341 &VideoCaptureController::DoIncomingCapturedVideoFrameOnIOThread, | |
342 controller_, base::Passed(&buffer), frame)); | |
343 } | 336 } |
344 | 337 |
345 std::unique_ptr<media::VideoCaptureDevice::Client::Buffer> | 338 std::unique_ptr<media::VideoCaptureDevice::Client::Buffer> |
346 VideoCaptureDeviceClient::ResurrectLastOutputBuffer( | 339 VideoCaptureDeviceClient::ResurrectLastOutputBuffer( |
347 const gfx::Size& dimensions, | 340 const gfx::Size& dimensions, |
348 media::VideoPixelFormat format, | 341 media::VideoPixelFormat format, |
349 media::VideoPixelStorage storage) { | 342 media::VideoPixelStorage storage) { |
350 const int buffer_id = | 343 const int buffer_id = |
351 buffer_pool_->ResurrectLastForProducer(dimensions, format, storage); | 344 buffer_pool_->ResurrectLastForProducer(dimensions, format, storage); |
352 if (buffer_id == VideoCaptureBufferPool::kInvalidId) | 345 if (buffer_id == VideoCaptureBufferPoolInterface::kInvalidId) |
353 return nullptr; | 346 return nullptr; |
354 return base::WrapUnique<Buffer>( | 347 return base::WrapUnique<Buffer>( |
355 new AutoReleaseBuffer(buffer_pool_, buffer_id)); | 348 new AutoReleaseBuffer(buffer_pool_, buffer_id)); |
356 } | 349 } |
357 | 350 |
358 void VideoCaptureDeviceClient::OnError( | 351 void VideoCaptureDeviceClient::OnError( |
359 const tracked_objects::Location& from_here, | 352 const tracked_objects::Location& from_here, |
360 const std::string& reason) { | 353 const std::string& reason) { |
361 const std::string log_message = base::StringPrintf( | 354 const std::string log_message = base::StringPrintf( |
362 "error@ %s, %s, OS message: %s", from_here.ToString().c_str(), | 355 "error@ %s, %s, OS message: %s", from_here.ToString().c_str(), |
363 reason.c_str(), | 356 reason.c_str(), |
364 logging::SystemErrorCodeToString(logging::GetLastSystemErrorCode()) | 357 logging::SystemErrorCodeToString(logging::GetLastSystemErrorCode()) |
365 .c_str()); | 358 .c_str()); |
366 DLOG(ERROR) << log_message; | 359 DLOG(ERROR) << log_message; |
367 OnLog(log_message); | 360 OnLog(log_message); |
368 BrowserThread::PostTask(BrowserThread::IO, | 361 receiver_->OnError(); |
369 FROM_HERE, | |
370 base::Bind(&VideoCaptureController::DoErrorOnIOThread, controller_)); | |
371 } | 362 } |
372 | 363 |
373 void VideoCaptureDeviceClient::OnLog( | 364 void VideoCaptureDeviceClient::OnLog( |
374 const std::string& message) { | 365 const std::string& message) { |
375 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | 366 receiver_->OnLog(message); |
376 base::Bind(&VideoCaptureController::DoLogOnIOThread, | |
377 controller_, message)); | |
378 } | 367 } |
379 | 368 |
380 double VideoCaptureDeviceClient::GetBufferPoolUtilization() const { | 369 double VideoCaptureDeviceClient::GetBufferPoolUtilization() const { |
381 // VideoCaptureBufferPool::GetBufferPoolUtilization() is thread-safe. | 370 // VideoCaptureBufferPoolInterface::GetBufferPoolUtilization() is thread-safe. |
382 return buffer_pool_->GetBufferPoolUtilization(); | 371 return buffer_pool_->GetBufferPoolUtilization(); |
383 } | 372 } |
384 | 373 |
385 std::unique_ptr<media::VideoCaptureDevice::Client::Buffer> | 374 std::unique_ptr<media::VideoCaptureDevice::Client::Buffer> |
386 VideoCaptureDeviceClient::ReserveI420OutputBuffer( | 375 VideoCaptureDeviceClient::ReserveI420OutputBuffer( |
387 const gfx::Size& dimensions, | 376 const gfx::Size& dimensions, |
388 media::VideoPixelStorage storage, | 377 media::VideoPixelStorage storage, |
389 uint8_t** y_plane_data, | 378 uint8_t** y_plane_data, |
390 uint8_t** u_plane_data, | 379 uint8_t** u_plane_data, |
391 uint8_t** v_plane_data) { | 380 uint8_t** v_plane_data) { |
(...skipping 29 matching lines...) Expand all Loading... | |
421 reinterpret_cast<uint8_t*>(buffer->data(VideoFrame::kUPlane)); | 410 reinterpret_cast<uint8_t*>(buffer->data(VideoFrame::kUPlane)); |
422 *v_plane_data = | 411 *v_plane_data = |
423 reinterpret_cast<uint8_t*>(buffer->data(VideoFrame::kVPlane)); | 412 reinterpret_cast<uint8_t*>(buffer->data(VideoFrame::kVPlane)); |
424 return buffer; | 413 return buffer; |
425 } | 414 } |
426 NOTREACHED(); | 415 NOTREACHED(); |
427 return std::unique_ptr<Buffer>(); | 416 return std::unique_ptr<Buffer>(); |
428 } | 417 } |
429 | 418 |
430 } // namespace content | 419 } // namespace content |
OLD | NEW |