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/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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |