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 "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/gpu/browser_gpu_channel_host_factory.h" | |
10 #include "content/browser/renderer_host/media/video_capture_buffer_pool.h" | 11 #include "content/browser/renderer_host/media/video_capture_buffer_pool.h" |
11 #include "content/browser/renderer_host/media/video_capture_controller.h" | 12 #include "content/browser/renderer_host/media/video_capture_controller.h" |
13 #include "content/common/gpu/client/gpu_jpeg_decode_accelerator_host.h" | |
12 #include "content/public/browser/browser_thread.h" | 14 #include "content/public/browser/browser_thread.h" |
13 #include "media/base/bind_to_current_loop.h" | 15 #include "media/base/bind_to_current_loop.h" |
14 #include "media/base/video_capture_types.h" | 16 #include "media/base/video_capture_types.h" |
15 #include "media/base/video_frame.h" | 17 #include "media/base/video_frame.h" |
16 #include "third_party/libyuv/include/libyuv.h" | 18 #include "third_party/libyuv/include/libyuv.h" |
17 | 19 |
18 using media::VideoCaptureFormat; | 20 using media::VideoCaptureFormat; |
19 using media::VideoFrame; | 21 using media::VideoFrame; |
20 | 22 |
21 namespace content { | 23 namespace content { |
22 | 24 |
25 struct CapturedData { | |
26 uint8* data; | |
27 int length; | |
28 media::VideoCaptureFormat frame_format; | |
29 int rotation; | |
30 base::TimeTicks timestamp; | |
31 }; | |
32 | |
33 // This class may be accessed by device thread and IO thread. The access is | |
34 // exclusive: device thread can only access members if |decoding_| is false. | |
35 // IO thread can only access if |decoding_| is true. | |
36 class JpegDecodeData { | |
37 public: | |
38 typedef media::VideoCaptureDevice::Client::Buffer ClientBuffer; | |
39 JpegDecodeData() | |
40 : decoding_(false), | |
41 next_bitstream_buffer_id_(0), | |
42 in_buffer_(media::JpegDecodeAccelerator::kInvalidBitstreamBufferId, | |
43 base::SharedMemory::NULLHandle(), | |
44 0) {} | |
45 | |
46 bool decoding() { | |
47 base::AutoLock lock(lock_); | |
48 return decoding_; | |
49 } | |
50 void set_decoding(bool decoding) { | |
51 base::AutoLock lock(lock_); | |
52 DCHECK(decoding_ != decoding); | |
53 decoding_ = decoding; | |
54 } | |
55 | |
56 media::BitstreamBuffer in_buffer() { return in_buffer_; } | |
57 const CapturedData& captured_data() { return captured_data_; } | |
58 void set_captured_data(const CapturedData& data) { | |
59 DCHECK(!decoding()); | |
60 captured_data_ = data; | |
61 } | |
62 scoped_refptr<ClientBuffer> out_buffer() { | |
63 DCHECK(decoding()); | |
64 return out_buffer_; | |
65 } | |
66 scoped_refptr<media::VideoFrame> out_frame() { return out_frame_; } | |
67 | |
68 // Adapt |captured_data| and |out_buffer| to BitstreamBuffer and | |
69 // VideoFrame, which JDA expects. | |
70 bool PrepareDecode(const CapturedData& captured_data, | |
71 const scoped_refptr<ClientBuffer> out_buffer); | |
72 void DecodeDone(); | |
73 | |
74 private: | |
75 base::Lock lock_; | |
76 bool decoding_; // protected by lock_; | |
77 | |
78 CapturedData captured_data_; | |
79 int32 next_bitstream_buffer_id_; | |
80 | |
81 scoped_ptr<base::SharedMemory> in_shared_memory_; | |
82 // |in_buffer_| is backed by |in_shared_memory_|. | |
83 media::BitstreamBuffer in_buffer_; | |
84 | |
85 scoped_refptr<ClientBuffer> out_buffer_; | |
86 // |out_frame_| is backed by |out_buffer_|. | |
87 scoped_refptr<media::VideoFrame> out_frame_; | |
88 | |
89 DISALLOW_COPY_AND_ASSIGN(JpegDecodeData); | |
90 }; | |
91 | |
92 bool JpegDecodeData::PrepareDecode( | |
93 const CapturedData& captured_data, | |
94 const scoped_refptr<ClientBuffer> out_buffer) { | |
95 DVLOG(3) << __func__; | |
96 DCHECK(!decoding()); | |
97 | |
98 captured_data_ = captured_data; | |
99 | |
100 // Enlarge input buffer if necessary. | |
101 size_t in_buffer_size = captured_data.length; | |
102 if (!in_shared_memory_.get() || | |
103 in_buffer_size > in_shared_memory_->mapped_size()) { | |
104 in_shared_memory_.reset(new base::SharedMemory); | |
105 | |
106 if (!in_shared_memory_->CreateAnonymous(in_buffer_size)) { | |
107 DLOG(ERROR) << "CreateAnonymous failed"; | |
108 return false; | |
109 } | |
110 | |
111 if (!in_shared_memory_->Map(in_buffer_size)) { | |
112 DLOG(ERROR) << "Map failed"; | |
113 return false; | |
114 } | |
115 | |
116 captured_data_.data = reinterpret_cast<uint8*>(in_shared_memory_->memory()); | |
117 } | |
118 | |
119 in_buffer_ = media::BitstreamBuffer( | |
120 next_bitstream_buffer_id_, in_shared_memory_->handle(), in_buffer_size); | |
121 // Mask against 30 bits, to avoid (undefined) wraparound on signed integer. | |
122 next_bitstream_buffer_id_ = (next_bitstream_buffer_id_ + 1) & 0x3FFFFFFF; | |
123 | |
124 gfx::Size dimensions = captured_data.frame_format.frame_size; | |
125 | |
126 scoped_refptr<media::VideoFrame> out_frame = | |
127 media::VideoFrame::WrapExternalPackedMemory( | |
128 media::VideoFrame::I420, | |
129 dimensions, | |
130 gfx::Rect(dimensions), | |
131 dimensions, | |
132 reinterpret_cast<uint8*>(out_buffer->data()), | |
133 out_buffer->size(), | |
134 out_buffer->handle(), | |
135 0, | |
136 base::TimeDelta(), | |
137 base::Closure()); | |
138 DCHECK(out_frame.get()); | |
139 | |
140 out_frame->metadata()->SetDouble(media::VideoFrameMetadata::FRAME_RATE, | |
141 captured_data.frame_format.frame_rate); | |
142 | |
143 out_frame_ = out_frame; | |
144 out_buffer_ = out_buffer; | |
145 | |
146 memcpy(in_shared_memory_->memory(), captured_data.data, captured_data.length); | |
147 | |
148 return true; | |
149 } | |
150 | |
151 void JpegDecodeData::DecodeDone() { | |
152 base::AutoLock lock(lock_); | |
153 DCHECK(decoding_); | |
154 out_frame_ = nullptr; | |
155 out_buffer_ = nullptr; | |
156 decoding_ = false; | |
157 } | |
158 | |
23 // Class combining a Client::Buffer interface implementation and a pool buffer | 159 // Class combining a Client::Buffer interface implementation and a pool buffer |
24 // implementation to guarantee proper cleanup on destruction on our side. | 160 // implementation to guarantee proper cleanup on destruction on our side. |
25 class AutoReleaseBuffer : public media::VideoCaptureDevice::Client::Buffer { | 161 class AutoReleaseBuffer : public media::VideoCaptureDevice::Client::Buffer { |
26 public: | 162 public: |
27 AutoReleaseBuffer(const scoped_refptr<VideoCaptureBufferPool>& pool, | 163 AutoReleaseBuffer(const scoped_refptr<VideoCaptureBufferPool>& pool, |
28 int buffer_id, | 164 int buffer_id, |
29 void* data, | 165 void* data, |
30 size_t size) | 166 size_t size, |
31 : pool_(pool), | 167 base::SharedMemoryHandle handle) |
32 id_(buffer_id), | 168 : pool_(pool), id_(buffer_id), data_(data), size_(size), handle_(handle) { |
33 data_(data), | |
34 size_(size) { | |
35 DCHECK(pool_.get()); | 169 DCHECK(pool_.get()); |
36 } | 170 } |
37 int id() const override { return id_; } | 171 int id() const override { return id_; } |
38 void* data() const override { return data_; } | 172 void* data() const override { return data_; } |
39 size_t size() const override { return size_; } | 173 size_t size() const override { return size_; } |
174 base::SharedMemoryHandle handle() const override { return handle_; } | |
40 | 175 |
41 private: | 176 private: |
42 ~AutoReleaseBuffer() override { pool_->RelinquishProducerReservation(id_); } | 177 ~AutoReleaseBuffer() override { pool_->RelinquishProducerReservation(id_); } |
43 | 178 |
44 const scoped_refptr<VideoCaptureBufferPool> pool_; | 179 const scoped_refptr<VideoCaptureBufferPool> pool_; |
45 const int id_; | 180 const int id_; |
46 void* const data_; | 181 void* const data_; |
47 const size_t size_; | 182 const size_t size_; |
183 const base::SharedMemoryHandle handle_; | |
48 }; | 184 }; |
49 | 185 |
50 VideoCaptureDeviceClient::VideoCaptureDeviceClient( | 186 VideoCaptureDeviceClient::VideoCaptureDeviceClient( |
51 const base::WeakPtr<VideoCaptureController>& controller, | 187 const base::WeakPtr<VideoCaptureController>& controller, |
52 const scoped_refptr<VideoCaptureBufferPool>& buffer_pool) | 188 const scoped_refptr<VideoCaptureBufferPool>& buffer_pool) |
53 : controller_(controller), | 189 : controller_(controller), |
190 jpeg_failed_(false), | |
54 buffer_pool_(buffer_pool), | 191 buffer_pool_(buffer_pool), |
55 last_captured_pixel_format_(media::PIXEL_FORMAT_UNKNOWN) {} | 192 last_captured_pixel_format_(media::PIXEL_FORMAT_UNKNOWN) { |
193 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
194 } | |
56 | 195 |
57 VideoCaptureDeviceClient::~VideoCaptureDeviceClient() {} | 196 VideoCaptureDeviceClient::~VideoCaptureDeviceClient() { |
197 } | |
198 | |
199 bool VideoCaptureDeviceClient::InitializeJpegDecoder() { | |
200 // called from device thread | |
201 DVLOG(3) << __func__; | |
202 GpuChannelHost* const host = | |
203 BrowserGpuChannelHostFactory::instance()->GetGpuChannel(); | |
204 jpeg_decoder_ = host->CreateJpegDecoder(); | |
205 if (!jpeg_decoder_->Initialize(this)) { | |
206 jpeg_decoder_.reset(); | |
207 return false; | |
208 } | |
209 return true; | |
210 } | |
211 | |
212 void VideoCaptureDeviceClient::VideoFrameReady(int32_t bitstream_buffer_id) { | |
213 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
214 DVLOG(3) << __func__; | |
215 | |
216 // Verify parameters from GPU thread. | |
wuchengli
2015/04/15 07:11:57
s/thread/process/
kcwu
2015/04/16 14:38:27
Done.
| |
217 if (!jpeg_decode_data_ || !jpeg_decode_data_->decoding()) { | |
218 DLOG(ERROR) << "got VideoFrameReady call but not decoding"; | |
219 return; | |
220 } | |
221 if (bitstream_buffer_id != jpeg_decode_data_->in_buffer().id()) { | |
222 DLOG(ERROR) << "bitstream_buffer_id mismatched, expected " | |
223 << jpeg_decode_data_->in_buffer().id() << ", but got " | |
224 << bitstream_buffer_id; | |
225 return; | |
226 } | |
227 | |
228 const auto& captured_data = jpeg_decode_data_->captured_data(); | |
229 BrowserThread::PostTask( | |
230 BrowserThread::IO, FROM_HERE, | |
231 base::Bind( | |
232 &VideoCaptureController::DoIncomingCapturedVideoFrameOnIOThread, | |
233 controller_, jpeg_decode_data_->out_buffer(), | |
234 jpeg_decode_data_->out_frame(), captured_data.timestamp)); | |
235 | |
236 jpeg_decode_data_->DecodeDone(); | |
237 } | |
238 | |
239 void VideoCaptureDeviceClient::NotifyError( | |
240 int32_t bitstream_buffer_id, | |
241 media::JpegDecodeAccelerator::Error error) { | |
242 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
243 DVLOG(3) << __func__; | |
244 | |
245 // Verify parameters from GPU thread. | |
246 if (!jpeg_decode_data_->decoding()) { | |
247 DLOG(ERROR) << "got VideoFrameReady call but not decoding"; | |
248 return; | |
249 } | |
250 if (bitstream_buffer_id != | |
251 media::JpegDecodeAccelerator::kInvalidBitstreamBufferId && | |
252 bitstream_buffer_id != jpeg_decode_data_->in_buffer().id()) { | |
253 DLOG(ERROR) << "invalid bitstream_buffer_id " << bitstream_buffer_id; | |
254 return; | |
255 } | |
256 | |
257 OnIncomingCapturedData2(jpeg_decode_data_->captured_data()); | |
258 | |
259 jpeg_decode_data_->DecodeDone(); | |
260 } | |
58 | 261 |
59 void VideoCaptureDeviceClient::OnIncomingCapturedData( | 262 void VideoCaptureDeviceClient::OnIncomingCapturedData( |
60 const uint8* data, | 263 const uint8* data, |
61 int length, | 264 int length, |
62 const VideoCaptureFormat& frame_format, | 265 const VideoCaptureFormat& frame_format, |
63 int rotation, | 266 int rotation, |
64 const base::TimeTicks& timestamp) { | 267 const base::TimeTicks& timestamp) { |
65 TRACE_EVENT0("video", "VideoCaptureDeviceClient::OnIncomingCapturedData"); | 268 TRACE_EVENT0("video", "VideoCaptureDeviceClient::OnIncomingCapturedData"); |
269 DVLOG(3) << __func__; | |
270 | |
271 CapturedData captured_data; | |
272 captured_data.data = const_cast<uint8*>(data); | |
273 captured_data.length = length; | |
274 captured_data.frame_format = frame_format; | |
275 captured_data.rotation = rotation; | |
276 captured_data.timestamp = timestamp; | |
66 | 277 |
67 if (last_captured_pixel_format_ != frame_format.pixel_format) { | 278 if (last_captured_pixel_format_ != frame_format.pixel_format) { |
68 OnLog("Pixel format: " + media::VideoCaptureFormat::PixelFormatToString( | 279 OnLog("Pixel format: " + media::VideoCaptureFormat::PixelFormatToString( |
69 frame_format.pixel_format)); | 280 frame_format.pixel_format)); |
70 last_captured_pixel_format_ = frame_format.pixel_format; | 281 last_captured_pixel_format_ = frame_format.pixel_format; |
71 } | 282 } |
72 | 283 |
73 if (!frame_format.IsValid()) | 284 if (!frame_format.IsValid()) |
74 return; | 285 return; |
75 | 286 |
287 const gfx::Size size = frame_format.frame_size; | |
288 if (rotation != 0 || frame_format.pixel_format != media::PIXEL_FORMAT_MJPEG || | |
289 size.width() % 2 != 0 || size.height() % 2 != 0 || jpeg_failed_) { | |
290 OnIncomingCapturedData2(captured_data); | |
291 return; | |
292 } | |
293 | |
294 if (!jpeg_decoder_) { | |
295 if (!InitializeJpegDecoder()) { | |
296 // TODO(kcwu): fallback to software decode | |
297 jpeg_failed_ = true; | |
298 return; | |
299 } | |
300 jpeg_decode_data_.reset(new JpegDecodeData); | |
301 } | |
302 | |
303 gfx::Size dimensions = frame_format.frame_size; | |
304 scoped_refptr<Buffer> out_buffer = | |
305 ReserveOutputBuffer(media::PIXEL_FORMAT_I420, dimensions); | |
306 if (!out_buffer.get()) { | |
307 DVLOG(1) << "Drop captured frame. No available buffers" | |
308 << " (all buffers are still queued to display)"; | |
309 return; | |
310 } | |
311 | |
312 if (jpeg_decode_data_->decoding()) { | |
313 DVLOG(1) << "Drop captured frame. Previous jpeg frame is still decoding"; | |
314 return; | |
315 } | |
316 | |
317 if (!jpeg_decode_data_->PrepareDecode(captured_data, out_buffer)) { | |
318 // TODO(kcwu): fallback to software decode | |
319 return; | |
320 } | |
321 | |
322 jpeg_decode_data_->set_decoding(true); | |
323 jpeg_decoder_->Decode(jpeg_decode_data_->in_buffer(), | |
324 jpeg_decode_data_->out_frame()); | |
325 } | |
326 | |
327 // TODO(kcwu): need better name | |
328 void VideoCaptureDeviceClient::OnIncomingCapturedData2( | |
329 const CapturedData& captured_data) { | |
330 DVLOG(3) << __func__; | |
331 | |
332 const uint8* data = captured_data.data; | |
333 int length = captured_data.length; | |
334 const VideoCaptureFormat& frame_format = captured_data.frame_format; | |
335 int rotation = captured_data.rotation; | |
336 base::TimeTicks timestamp = captured_data.timestamp; | |
337 | |
338 if (last_captured_pixel_format_ != frame_format.pixel_format) { | |
339 OnLog("Pixel format: " + media::VideoCaptureFormat::PixelFormatToString( | |
340 frame_format.pixel_format)); | |
341 last_captured_pixel_format_ = frame_format.pixel_format; | |
342 } | |
343 | |
76 // |chopped_{width,height} and |new_unrotated_{width,height}| are the lowest | 344 // |chopped_{width,height} and |new_unrotated_{width,height}| are the lowest |
77 // bit decomposition of {width, height}, grabbing the odd and even parts. | 345 // bit decomposition of {width, height}, grabbing the odd and even parts. |
78 const int chopped_width = frame_format.frame_size.width() & 1; | 346 const int chopped_width = frame_format.frame_size.width() & 1; |
79 const int chopped_height = frame_format.frame_size.height() & 1; | 347 const int chopped_height = frame_format.frame_size.height() & 1; |
80 const int new_unrotated_width = frame_format.frame_size.width() & ~1; | 348 const int new_unrotated_width = frame_format.frame_size.width() & ~1; |
81 const int new_unrotated_height = frame_format.frame_size.height() & ~1; | 349 const int new_unrotated_height = frame_format.frame_size.height() & ~1; |
82 | 350 |
83 int destination_width = new_unrotated_width; | 351 int destination_width = new_unrotated_width; |
84 int destination_height = new_unrotated_height; | 352 int destination_height = new_unrotated_height; |
85 if (rotation == 90 || rotation == 270) { | 353 if (rotation == 90 || rotation == 270) { |
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
309 DCHECK_GT(dimensions.width(), 0); | 577 DCHECK_GT(dimensions.width(), 0); |
310 DCHECK_GT(dimensions.height(), 0); | 578 DCHECK_GT(dimensions.height(), 0); |
311 | 579 |
312 int buffer_id_to_drop = VideoCaptureBufferPool::kInvalidId; | 580 int buffer_id_to_drop = VideoCaptureBufferPool::kInvalidId; |
313 const int buffer_id = | 581 const int buffer_id = |
314 buffer_pool_->ReserveForProducer(format, dimensions, &buffer_id_to_drop); | 582 buffer_pool_->ReserveForProducer(format, dimensions, &buffer_id_to_drop); |
315 if (buffer_id == VideoCaptureBufferPool::kInvalidId) | 583 if (buffer_id == VideoCaptureBufferPool::kInvalidId) |
316 return NULL; | 584 return NULL; |
317 void* data; | 585 void* data; |
318 size_t size; | 586 size_t size; |
319 buffer_pool_->GetBufferInfo(buffer_id, &data, &size); | 587 base::SharedMemoryHandle handle; |
588 buffer_pool_->GetBufferInfo(buffer_id, &data, &size, &handle); | |
320 | 589 |
321 scoped_refptr<media::VideoCaptureDevice::Client::Buffer> output_buffer( | 590 scoped_refptr<media::VideoCaptureDevice::Client::Buffer> output_buffer( |
322 new AutoReleaseBuffer(buffer_pool_, buffer_id, data, size)); | 591 new AutoReleaseBuffer(buffer_pool_, buffer_id, data, size, handle)); |
323 | 592 |
324 if (buffer_id_to_drop != VideoCaptureBufferPool::kInvalidId) { | 593 if (buffer_id_to_drop != VideoCaptureBufferPool::kInvalidId) { |
325 BrowserThread::PostTask(BrowserThread::IO, | 594 BrowserThread::PostTask(BrowserThread::IO, |
326 FROM_HERE, | 595 FROM_HERE, |
327 base::Bind(&VideoCaptureController::DoBufferDestroyedOnIOThread, | 596 base::Bind(&VideoCaptureController::DoBufferDestroyedOnIOThread, |
328 controller_, buffer_id_to_drop)); | 597 controller_, buffer_id_to_drop)); |
329 } | 598 } |
330 | 599 |
331 return output_buffer; | 600 return output_buffer; |
332 } | 601 } |
(...skipping 29 matching lines...) Expand all Loading... | |
362 } | 631 } |
363 | 632 |
364 void VideoCaptureDeviceClient::OnLog( | 633 void VideoCaptureDeviceClient::OnLog( |
365 const std::string& message) { | 634 const std::string& message) { |
366 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | 635 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
367 base::Bind(&VideoCaptureController::DoLogOnIOThread, | 636 base::Bind(&VideoCaptureController::DoLogOnIOThread, |
368 controller_, message)); | 637 controller_, message)); |
369 } | 638 } |
370 | 639 |
371 } // namespace content | 640 } // namespace content |
OLD | NEW |