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

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: fix coded size, shm handle Created 5 years, 9 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/synchronization/waitable_event.h"
9 #include "base/trace_event/trace_event.h" 10 #include "base/trace_event/trace_event.h"
11 #include "content/browser/gpu/browser_gpu_channel_host_factory.h"
10 #include "content/browser/renderer_host/media/video_capture_buffer_pool.h" 12 #include "content/browser/renderer_host/media/video_capture_buffer_pool.h"
11 #include "content/browser/renderer_host/media/video_capture_controller.h" 13 #include "content/browser/renderer_host/media/video_capture_controller.h"
14 #include "content/common/gpu/client/gpu_jpeg_decode_accelerator_host.h"
12 #include "content/public/browser/browser_thread.h" 15 #include "content/public/browser/browser_thread.h"
13 #include "media/base/bind_to_current_loop.h" 16 #include "media/base/bind_to_current_loop.h"
14 #include "media/base/video_capture_types.h" 17 #include "media/base/video_capture_types.h"
15 #include "media/base/video_frame.h" 18 #include "media/base/video_frame.h"
19 #include "media/base/video_util.h"
20 #include "media/base/yuv_convert.h"
16 #include "third_party/libyuv/include/libyuv.h" 21 #include "third_party/libyuv/include/libyuv.h"
17 22
18 using media::VideoCaptureFormat; 23 using media::VideoCaptureFormat;
19 using media::VideoFrame; 24 using media::VideoFrame;
20 25
21 namespace content { 26 namespace content {
22 27
23 // Class combining a Client::Buffer interface implementation and a pool buffer 28 // Class combining a Client::Buffer interface implementation and a pool buffer
24 // implementation to guarantee proper cleanup on destruction on our side. 29 // implementation to guarantee proper cleanup on destruction on our side.
25 class AutoReleaseBuffer : public media::VideoCaptureDevice::Client::Buffer { 30 class AutoReleaseBuffer : public media::VideoCaptureDevice::Client::Buffer {
(...skipping 18 matching lines...) Expand all
44 const scoped_refptr<VideoCaptureBufferPool> pool_; 49 const scoped_refptr<VideoCaptureBufferPool> pool_;
45 const int id_; 50 const int id_;
46 void* const data_; 51 void* const data_;
47 const size_t size_; 52 const size_t size_;
48 }; 53 };
49 54
50 VideoCaptureDeviceClient::VideoCaptureDeviceClient( 55 VideoCaptureDeviceClient::VideoCaptureDeviceClient(
51 const base::WeakPtr<VideoCaptureController>& controller, 56 const base::WeakPtr<VideoCaptureController>& controller,
52 const scoped_refptr<VideoCaptureBufferPool>& buffer_pool) 57 const scoped_refptr<VideoCaptureBufferPool>& buffer_pool)
53 : controller_(controller), 58 : controller_(controller),
59 jpeg_decode_event_(nullptr),
54 buffer_pool_(buffer_pool), 60 buffer_pool_(buffer_pool),
55 last_captured_pixel_format_(media::PIXEL_FORMAT_UNKNOWN) {} 61 last_captured_pixel_format_(media::PIXEL_FORMAT_UNKNOWN),
62 next_bitstream_buffer_id_(0) {}
56 63
57 VideoCaptureDeviceClient::~VideoCaptureDeviceClient() {} 64 VideoCaptureDeviceClient::~VideoCaptureDeviceClient() {
65 if (jpeg_decoder_.get())
mcasas 2015/03/23 19:29:51 If |jpeg_decoder_| is created from the VCD, then i
kcwu 2015/03/30 18:12:14 jpeg_decoder_ is scoped_ptr(with DefaultDeleter),
66 jpeg_decoder_->Destroy();
67 }
68
69 bool VideoCaptureDeviceClient::InitializeJpegDecoder() {
mcasas 2015/03/23 19:29:51 This method looks convoluted and exposes too much
kcwu 2015/03/30 18:12:14 Using MJPEG or YUV formats is determined in VideoC
70 LOG(ERROR) << __func__;
mcasas 2015/03/23 19:29:51 Suggest s/LOG(ERROR)/DVLOG(1)/
kcwu 2015/04/16 14:38:26 Done.
71 GpuChannelHost* host =
mcasas 2015/03/23 19:29:51 GpuChannelHost* const
kcwu 2015/04/14 20:02:34 Done.
72 BrowserGpuChannelHostFactory::instance()->GetGpuChannel();
73 LOG(ERROR) << "host =" << host;
74 GpuJpegDecodeAcceleratorHost* decoder = host->CreateJpegDecoder();
mcasas 2015/03/23 19:29:50 * const
kcwu 2015/04/14 20:02:33 Done.
75 if (!decoder->Initialize(this)) {
76 decoder->Destroy();
77 return false;
78 }
79 jpeg_decoder_.reset(decoder);
80
81 return true;
82 }
83
84 void VideoCaptureDeviceClient::VideoFrameReady(
85 int32_t bitstream_buffer_id) {
wuchengli 2015/03/23 06:30:14 Add DCHECK to make sure this runs on IO thread. Th
kcwu 2015/03/30 18:12:14 DCHECK added. But still PostTask because I want to
86 auto map_it = jpeg_decode_task_map_.find(bitstream_buffer_id);
wuchengli 2015/03/23 06:30:14 Like you said, since you are blocking the v4l2 thr
kcwu 2015/03/30 18:12:14 This is refactored to async code.
87 if (map_it == jpeg_decode_task_map_.end()) {
88 LOG(ERROR) << "VideoFrameReady unknown bitstream_buffer_id "
89 << bitstream_buffer_id;
90 return;
91 }
92 auto captured_data = map_it->second;
93 auto frame_format = captured_data.frame_format;
94
95 BrowserThread::PostTask(
96 BrowserThread::IO,
97 FROM_HERE,
98 base::Bind(
99 &VideoCaptureController::DoIncomingCapturedVideoFrameOnIOThread,
100 controller_,
101 captured_data.buffer,
102 captured_data.frame,
103 captured_data.timestamp));
104
105 jpeg_decode_task_map_.erase(map_it);
106
107 CHECK(jpeg_decode_event_);
108 jpeg_decode_event_->Signal();
109 }
110
111 void VideoCaptureDeviceClient::NotifyError(
112 int32_t bitstream_buffer_id,
113 media::JpegDecodeAccelerator::Error error) {
114 LOG(ERROR) << "NotifyError";
115
116 auto map_it = jpeg_decode_task_map_.find(bitstream_buffer_id);
117 if (map_it != jpeg_decode_task_map_.end()) {
118 auto captured_data = map_it->second;
119 LOG(ERROR) << "fallback to software decode *******************************";
120 OnIncomingCapturedData2(captured_data);
121 jpeg_decode_task_map_.erase(map_it);
122 CHECK(jpeg_decode_event_);
123 jpeg_decode_event_->Signal();
124 return;
125 }
126
127 // TODO(kcwu)
128 LOG(ERROR) << "give up???";
129 CHECK(jpeg_decode_event_);
130 jpeg_decode_event_->Signal();
131 }
58 132
59 void VideoCaptureDeviceClient::OnIncomingCapturedData( 133 void VideoCaptureDeviceClient::OnIncomingCapturedData(
60 const uint8* data, 134 const uint8* data,
61 int length, 135 int length,
62 const VideoCaptureFormat& frame_format, 136 const VideoCaptureFormat& frame_format,
63 int rotation, 137 int rotation,
64 const base::TimeTicks& timestamp) { 138 const base::TimeTicks& timestamp) {
65 TRACE_EVENT0("video", "VideoCaptureController::OnIncomingCapturedData"); 139 TRACE_EVENT0("video", "VideoCaptureController::OnIncomingCapturedData");
66 140
141 CapturedData captured_data;
142 captured_data.data = data;
143 captured_data.length = length;
144 captured_data.frame_format = frame_format;
145 captured_data.rotation = rotation;
146 captured_data.timestamp = timestamp;
147
67 if (last_captured_pixel_format_ != frame_format.pixel_format) { 148 if (last_captured_pixel_format_ != frame_format.pixel_format) {
68 OnLog("Pixel format: " + media::VideoCaptureFormat::PixelFormatToString( 149 OnLog("Pixel format: " + media::VideoCaptureFormat::PixelFormatToString(
69 frame_format.pixel_format)); 150 frame_format.pixel_format));
70 last_captured_pixel_format_ = frame_format.pixel_format; 151 last_captured_pixel_format_ = frame_format.pixel_format;
71 } 152 }
72 153
73 if (!frame_format.IsValid()) 154 if (!frame_format.IsValid())
74 return; 155 return;
75 156
157 const gfx::Size size = frame_format.frame_size;
158 if (rotation != 0 || frame_format.pixel_format != media::PIXEL_FORMAT_MJPEG ||
159 size.width() % 2 != 0 || size.height() % 2 != 0) {
160 OnIncomingCapturedData2(captured_data);
wuchengli 2015/03/23 06:30:14 Please measure the decode time of both cases and p
kcwu 2015/04/14 20:02:34 Acknowledged.
161 return;
162 }
163
164 base::SharedMemory in_memory;
165 gfx::Size dimensions = frame_format.frame_size;
166 size_t in_buffer_size = length;
167 scoped_refptr<Buffer> out_buffer =
168 ReserveOutputBuffer(media::VideoFrame::I420, dimensions);
169 captured_data.buffer = out_buffer;
170
171 if (in_memory.CreateAnonymous(in_buffer_size) &&
172 in_memory.Map(in_buffer_size)) {
173 media::BitstreamBuffer in_buffer(next_bitstream_buffer_id_,
174 in_memory.handle(),
175 in_buffer_size);
176 // Mask against 30 bits, to avoid (undefined) wraparound on signed integer.
177 next_bitstream_buffer_id_ = (next_bitstream_buffer_id_ + 1) & 0x3FFFFFFF;
178
179 base::SharedMemoryHandle buffer_handle =
180 buffer_pool_->GetBufferSharedMemory(out_buffer->id());
181
182 uint8* shm_memory = reinterpret_cast<uint8*>(in_memory.memory());
183 memcpy(shm_memory, data, length);
184
mcasas 2015/03/23 19:29:50 There's a lot of extra code to just maintain the i
kcwu 2015/03/30 18:12:14 Done.
185 scoped_refptr<media::VideoFrame> out_frame =
186 media::VideoFrame::WrapExternalPackedMemory(
187 media::VideoFrame::I420,
188 dimensions,
189 gfx::Rect(dimensions),
190 dimensions,
191 reinterpret_cast<uint8*>(out_buffer->data()),
192 out_buffer->size(),
193 buffer_handle,
194 0,
195 base::TimeDelta(),
196 base::Closure());
wuchengli 2015/03/23 06:30:14 Set framerate like line 387. frame->metadata()->Se
kcwu 2015/03/30 18:12:14 Done.
197 DCHECK(out_frame.get());
198
199 captured_data.frame = out_frame;
200 jpeg_decode_task_map_[in_buffer.id()] = captured_data;
201
202 CHECK(!jpeg_decode_event_);
203 jpeg_decode_event_ = new base::WaitableEvent(false, false);
wuchengli 2015/03/23 06:30:14 Use scoped_ptr
kcwu 2015/03/30 18:12:14 Code removed.
204
205 BrowserThread::PostTask(
206 BrowserThread::IO,
207 FROM_HERE,
208 base::Bind(
209 &VideoCaptureDeviceClient::DecodeJpegOnIOThread,
wuchengli 2015/03/23 06:30:14 Post to JpegDecodeAccelerator::Decode directly.
kcwu 2015/03/30 18:12:14 Modified to call Decode() directly.
210 base::Unretained(this),
211 in_buffer,
212 out_frame));
213
214 jpeg_decode_event_->Wait();
215 delete jpeg_decode_event_;
216 jpeg_decode_event_ = nullptr;
217 }
218 }
219
220 void VideoCaptureDeviceClient::DecodeJpegOnIOThread(
221 media::BitstreamBuffer in_buffer,
222 scoped_refptr<media::VideoFrame> out_frame) {
223 DCHECK(jpeg_decoder_);
224
225 jpeg_decoder_->Decode(in_buffer, out_frame);
226 }
227
228 // TODO(kcwu): need better name
229 void VideoCaptureDeviceClient::OnIncomingCapturedData2(
230 const CapturedData& captured_data) {
231
232 const uint8* data = captured_data.data;
233 int length = captured_data.length;
234 const VideoCaptureFormat& frame_format = captured_data.frame_format;
235 int rotation = captured_data.rotation;
236 base::TimeTicks timestamp = captured_data.timestamp;
237
238 if (last_captured_pixel_format_ != frame_format.pixel_format) {
239 OnLog("Pixel format: " + media::VideoCaptureFormat::PixelFormatToString(
240 frame_format.pixel_format));
241 last_captured_pixel_format_ = frame_format.pixel_format;
242 }
243
76 // Chopped pixels in width/height in case video capture device has odd 244 // Chopped pixels in width/height in case video capture device has odd
77 // numbers for width/height. 245 // numbers for width/height.
246 // XXX kcwu: why crop??
78 int chopped_width = 0; 247 int chopped_width = 0;
79 int chopped_height = 0; 248 int chopped_height = 0;
80 int new_unrotated_width = frame_format.frame_size.width(); 249 int new_unrotated_width = frame_format.frame_size.width();
81 int new_unrotated_height = frame_format.frame_size.height(); 250 int new_unrotated_height = frame_format.frame_size.height();
82 251
83 if (new_unrotated_width & 1) { 252 if (new_unrotated_width & 1) {
84 --new_unrotated_width; 253 --new_unrotated_width;
85 chopped_width = 1; 254 chopped_width = 1;
86 } 255 }
87 if (new_unrotated_height & 1) { 256 if (new_unrotated_height & 1) {
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after
293 } 462 }
294 463
295 void VideoCaptureDeviceClient::OnLog( 464 void VideoCaptureDeviceClient::OnLog(
296 const std::string& message) { 465 const std::string& message) {
297 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, 466 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
298 base::Bind(&VideoCaptureController::DoLogOnIOThread, 467 base::Bind(&VideoCaptureController::DoLogOnIOThread,
299 controller_, message)); 468 controller_, message));
300 } 469 }
301 470
302 } // namespace content 471 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698