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

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

Issue 1016773002: MJPEG acceleration for video capture using VAAPI (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: address most comments 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/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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698