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

Side by Side Diff: media/video/capture/win/video_capture_device_pxc_win.cc

Issue 262383003: Add Intel Perceptual Computing SDK based depth video capture for Windows Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 7 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
(Empty)
1 // Copyright (c) 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "media/video/capture/win/video_capture_device_pxc_win.h"
6
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "base/strings/string_split.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/strings/utf_string_conversions.h"
14
15 namespace media {
16 namespace {
17
18 // Release a PXCSession will call CoUninitiliaze which causes calling thread
19 // (Audio Thread) to fail on COM API calling. Hold a global PXCSession to avoid
20 // this.
21 static PXCSmartPtr<PXCSession> g_session;
22
23 const char kDepthCameraName[] = "depth";
24 const char kDepthCameraID[] = "PXCCaptureDepthCamera";
25
26 const char CHROMA_ZERO_LEVEL = 127;
27
28 bool GetFirstDepthDeviceAndStream(
29 PXCCapture::Device** depth_device,
30 PXCCapture::VideoStream** depth_stream) {
31 pxcStatus status;
32 PXCSession::ImplDesc video_capture_desc;
33 memset(&video_capture_desc, 0, sizeof(video_capture_desc));
34 video_capture_desc.group = PXCSession::IMPL_GROUP_SENSOR;
35 video_capture_desc.subgroup = PXCSession::IMPL_SUBGROUP_VIDEO_CAPTURE;
36 for (int module_index = 0; ; module_index++) {
37 PXCSession::ImplDesc desc;
38 status = g_session->QueryImpl(&video_capture_desc, module_index, &desc);
39 if (status < PXC_STATUS_NO_ERROR) {
40 DVLOG(1) << "No more PXC modules.";
41 break;
42 }
43
44 PXCSmartPtr<PXCCapture> capture;
45 status = g_session->CreateImpl<PXCCapture>(&desc, &capture);
46 if (status < PXC_STATUS_NO_ERROR) {
47 DVLOG(2) << "Failed to create PXCCapture instance.";
48 continue;
49 }
50
51 for (int device_index = 0; ; device_index++) {
52 PXCCapture::DeviceInfo device_info;
53 status = capture->QueryDevice(device_index, &device_info);
54 if (status < PXC_STATUS_NO_ERROR) {
55 DVLOG(1) << "No more PXC capture devices.";
56 break;
57 }
58
59 PXCSmartPtr<PXCCapture::Device> device;
60 status = capture->CreateDevice(device_index, &device);
61 if (status < PXC_STATUS_NO_ERROR) {
62 DVLOG(2) << "Failed to create PXCCapture::Device instance.";
63 continue;
64 }
65
66 for (int stream_index = 0; ; stream_index++) {
67 PXCCapture::Device::StreamInfo stream_info;
68 status = device->QueryStream(stream_index, &stream_info);
69 if (status < PXC_STATUS_NO_ERROR) {
70 DVLOG(1) << "No more PXC streams.";
71 break;
72 }
73
74 if (stream_info.cuid == PXCCapture::VideoStream::CUID &&
75 stream_info.imageType == PXCImage::IMAGE_TYPE_DEPTH) {
76 PXCSmartPtr<PXCCapture::VideoStream> stream;
77 status =
78 device->CreateStream<PXCCapture::VideoStream>(
79 stream_index, &stream);
80 if (status < PXC_STATUS_NO_ERROR) {
81 DVLOG(2) << "Failed to create PXCCapture::VideoStream instance.";
82 break;
83 }
84
85 *depth_device = device.ReleasePtr();
86 *depth_stream = stream.ReleasePtr();
87 return true;
88 }
89 } // Enumerate streams.
90 } // Enumerate devices.
91 } // Enumerate modules.
92 return false;
93 }
94
95 } // namespace
96
97 // static
98 bool VideoCaptureDevicePXCWin::PlatformSupported() {
99 if (g_session.IsValid())
100 return true;
101
102 pxcStatus status = PXCSession_Create(&g_session);
103 if (status < PXC_STATUS_NO_ERROR) {
104 DVLOG(2) << "Failed to create a PXC Session.";
105 return false;
106 }
107 return true;
108 }
109
110 // static
111 void VideoCaptureDevicePXCWin::AppendDeviceNames(Names* device_names) {
112 if (!VideoCaptureDevicePXCWin::PlatformSupported())
113 return;
114
115 PXCSmartPtr<PXCCapture::Device> device;
116 PXCSmartPtr<PXCCapture::VideoStream> stream;
117 if (!GetFirstDepthDeviceAndStream(&device, &stream)) {
118 DVLOG(2) << "Failed to get PXC depth device and stream.";
119 return;
120 }
121
122 Name name(kDepthCameraName, kDepthCameraID, Name::PXC_CAPTURE);
123 DVLOG(1) << "PXC depth video capture device, "
124 << name.name() << " : " << name.id();
125 device_names->push_back(name);
126 }
127
128 //static
129 bool VideoCaptureDevicePXCWin::IsDepthDevice(const Name& device_name) {
130 return device_name.name() == kDepthCameraName;
131 }
132
133 //static
134 void VideoCaptureDevicePXCWin::GetDeviceSupportedFormats(
135 const Name& device_name, VideoCaptureFormats* formats) {
136 PXCSmartPtr<PXCCapture::Device> device;
137 PXCSmartPtr<PXCCapture::VideoStream> stream;
138 if (!GetFirstDepthDeviceAndStream(&device, &stream)) {
139 DVLOG(2) << "Failed to get PXC depth device and stream.";
140 return;
141 }
142
143 pxcStatus status;
144 for (int porfile_index = 0; ; porfile_index++) {
145 PXCCapture::VideoStream::ProfileInfo video_profile;
146 status = stream->QueryProfile(porfile_index, &video_profile);
147 if (status < PXC_STATUS_NO_ERROR) {
148 DVLOG(1) << "No more PXC stream profiles.";
149 break;
150 }
151 VideoCaptureFormat format;
152 format.frame_size.SetSize(video_profile.imageInfo.width,
153 video_profile.imageInfo.height);
154 uint32 frame_rate_min =
155 video_profile.frameRateMin.denominator ?
156 video_profile.frameRateMin.numerator /
157 video_profile.frameRateMin.denominator
158 : 0;
159 uint32 frame_rate_max =
160 video_profile.frameRateMax.denominator ?
161 video_profile.frameRateMax.numerator /
162 video_profile.frameRateMax.denominator
163 : 0;
164 format.frame_rate = (frame_rate_min + frame_rate_max) / 2;
165 format.pixel_format = PIXEL_FORMAT_YV12;
166 formats->push_back(format);
167 DVLOG(1) << device_name.name() << " resolution: "
168 << format.frame_size.ToString() << ", fps: " << format.frame_rate
169 << ", pixel format: " << format.pixel_format;
170 }
171 }
172
173 VideoCaptureDevicePXCWin::VideoCaptureDevicePXCWin(const Name& device_name)
174 : state_(kIdle),
175 device_name_(device_name),
176 pxc_capture_thread_("PxcCaptureThread") {
177 }
178
179 VideoCaptureDevicePXCWin::~VideoCaptureDevicePXCWin() {
180 }
181
182 bool VideoCaptureDevicePXCWin::Init() {
183 return true;
184 }
185
186 void VideoCaptureDevicePXCWin::AllocateAndStart(
187 const VideoCaptureParams& params,
188 scoped_ptr<Client> client) {
189 if (pxc_capture_thread_.IsRunning()) {
190 return; // Wrong state.
191 }
192 pxc_capture_thread_.Start();
193 pxc_capture_thread_.message_loop()->PostTask(
194 FROM_HERE,
195 base::Bind(&VideoCaptureDevicePXCWin::OnAllocateAndStart,
196 base::Unretained(this),
197 params.requested_format.frame_size.width(),
198 params.requested_format.frame_size.height(),
199 params.requested_format.frame_rate,
200 base::Passed(&client)));
201 }
202
203 void VideoCaptureDevicePXCWin::StopAndDeAllocate() {
204 if (!pxc_capture_thread_.IsRunning()) {
205 return; // Wrong state.
206 }
207 pxc_capture_thread_.message_loop()->PostTask(
208 FROM_HERE,
209 base::Bind(&VideoCaptureDevicePXCWin::OnStopAndDeAllocate,
210 base::Unretained(this)));
211 pxc_capture_thread_.Stop();
212 }
213
214 void VideoCaptureDevicePXCWin::OnAllocateAndStart(
215 int width, int height, int frame_rate, scoped_ptr<Client> client) {
216 DCHECK_EQ(pxc_capture_thread_.message_loop(), base::MessageLoop::current());
217
218 client_ = client.Pass();
219
220 PXCSmartPtr<PXCCapture::Device> device;
221 PXCSmartPtr<PXCCapture::VideoStream> stream;
222
223 if (!GetFirstDepthDeviceAndStream(&device, &stream)) {
224 SetErrorState("Failed to get PXC depth device and stream.");
225 return;
226 }
227
228 pxcStatus status;
229 // Try to find the best profile.
230 PXCCapture::VideoStream::ProfileInfo best_profile;
231 bool best_profile_found = false;
232 uint32 best = 0xFFFFFFFF;
233 for (int porfile_index = 0; ; porfile_index++) {
234 PXCCapture::VideoStream::ProfileInfo video_profile;
235 status = stream->QueryProfile(porfile_index, &video_profile);
236 if (status < PXC_STATUS_NO_ERROR) {
237 // No more profiles.
238 break;
239 }
240
241 uint32 frame_rate_min =
242 video_profile.frameRateMin.denominator ?
243 video_profile.frameRateMin.numerator /
244 video_profile.frameRateMin.denominator
245 : 0;
246 uint32 frame_rate_max =
247 video_profile.frameRateMax.denominator ?
248 video_profile.frameRateMax.numerator /
249 video_profile.frameRateMax.denominator
250 : 0;
251 uint32 current =
252 abs(static_cast<int>(width - video_profile.imageInfo.width)) +
253 abs(static_cast<int>(height - video_profile.imageInfo.height)) +
254 abs(static_cast<int>(frame_rate - frame_rate_min)) +
255 abs(static_cast<int>(frame_rate - frame_rate_max));
256
257 if (current < best) {
258 best = current;
259 best_profile_found = true;
260 best_profile = video_profile;
261 }
262 } // Enumerate profiles.
263
264 if (!best_profile_found) {
265 SetErrorState("Cannot find appropriate stream.");
266 return;
267 }
268
269 status = stream->SetProfile(&best_profile);
270 if (status < PXC_STATUS_NO_ERROR) {
271 SetErrorState("Failed to set stream profile.");
272 return;
273 }
274 stream_ = stream.ReleasePtr();
275
276 device->QueryProperty(
277 PXCCapture::Device::PROPERTY_DEPTH_SATURATION_VALUE,
278 &depth_saturation_value_);
279 device->QueryProperty(
280 PXCCapture::Device::PROPERTY_DEPTH_LOW_CONFIDENCE_VALUE,
281 &depth_low_confidence_value_);
282 device->QueryProperty(
283 PXCCapture::Device::PROPERTY_DEPTH_UNIT,
284 &depth_unit_in_micrometers_);
285 device->QueryPropertyAsRange(
286 PXCCapture::Device::PROPERTY_DEPTH_SENSOR_RANGE,
287 &depth_range_in_millimeters_);
288 DVLOG(1) << "Depth Device Properties: "
289 << "\nPROPERTY_DEPTH_SATURATION_VALUE: "
290 << depth_saturation_value_
291 << "\nPROPERTY_DEPTH_LOW_CONFIDENCE_VALUE: "
292 << depth_low_confidence_value_
293 << "\nPROPERTY_DEPTH_UNIT: "
294 << depth_unit_in_micrometers_
295 << "\nPROPERTY_DEPTH_SENSOR_RANGE: "
296 << depth_range_in_millimeters_.min << ":"
297 << depth_range_in_millimeters_.max;
298
299 DVLOG(1) << "Allocate PXC Stream: "
300 << " width = " << best_profile.imageInfo.width
301 << " height = " << best_profile.imageInfo.height
302 << " frame_rate = " << frame_rate
303 << " color = " << PIXEL_FORMAT_YV12;
304
305 // Store our current width and height.
306 capture_format_.frame_size.SetSize(best_profile.imageInfo.width,
307 best_profile.imageInfo.height);
308 capture_format_.frame_rate = frame_rate;
309 capture_format_.pixel_format = PIXEL_FORMAT_YV12;
310
311 yv12_image_.reset(
312 new uint8[capture_format_.frame_size.width() *
313 capture_format_.frame_size.height() *
314 3 / 2]);
315
316 // Start capturing.
317 state_ = kCapturing;
318 pxc_capture_thread_.message_loop()->PostTask(
319 FROM_HERE,
320 base::Bind(&VideoCaptureDevicePXCWin::OnCaptureTask,
321 base::Unretained(this)));
322 return;
323 }
324
325 void VideoCaptureDevicePXCWin::OnStopAndDeAllocate() {
326 DCHECK_EQ(pxc_capture_thread_.message_loop(), base::MessageLoop::current());
327
328 state_ = kIdle;
329 stream_.ReleaseRef();
330 client_.reset();
331 yv12_image_.reset();
332 }
333
334 void VideoCaptureDevicePXCWin::OnCaptureTask() {
335 DCHECK_EQ(pxc_capture_thread_.message_loop(), base::MessageLoop::current());
336
337 if (state_ != kCapturing || !stream_.IsValid())
338 return;
339
340 PXCSmartSP sp;
341 PXCSmartPtr<PXCImage> image;
342 pxcStatus status = stream_->ReadStreamAsync(&image, &sp);
343 if (status < PXC_STATUS_NO_ERROR) {
344 SetErrorState("Failed to read stream.");
345 return;
346 }
347
348 status = sp->Synchronize();
349 if (status < PXC_STATUS_NO_ERROR) {
350 SetErrorState("Read synchronization EOF.");
351 return;
352 }
353
354 PXCImage::ImageInfo info;
355 status = image->QueryInfo(&info);
356 if (status < PXC_STATUS_NO_ERROR) {
357 SetErrorState("Failed to get image info.");
358 return;
359 }
360
361 PXCImage::ImageData data;
362 status = image->AcquireAccess(
363 PXCImage::ACCESS_READ, PXCImage::COLOR_FORMAT_DEPTH, &data);
364 if (status < PXC_STATUS_NO_ERROR) {
365 SetErrorState("Failed to acquire access to image data.");
366 return;
367 }
368
369 DCHECK_EQ(data.type, PXCImage::SURFACE_TYPE_SYSTEM_MEMORY);
370
371 unsigned int yv12_data_length = info.width * info.height * 3 / 2;
372 uint8* yv12_data = yv12_image_.get();
373 memset(yv12_data, CHROMA_ZERO_LEVEL, sizeof(uint8) * yv12_data_length);
374 int16* depth_data = reinterpret_cast<int16*>(data.planes[0]);
375 for (unsigned int i = 0; i < info.width * info.height; i++) {
376 if (depth_data[i] == depth_saturation_value_ ||
377 depth_data[i] == depth_low_confidence_value_) {
378 // Discard the invalid depth value.
379 yv12_data[i] = 0xFF;
380 continue;
381 }
382
383 // The depth value is 16bits integer value. Throw away the lowest 4
384 // resolution bits and truncate to 8 bits.
385 // This aligns with VideoCaptureTango.java implemenation for Tango's depth
386 // camera. In this case Chroma components are unused. No need to write them
387 // explicitly since they're filled to 128 on creation.
388 yv12_data[i] = ((depth_data[i] & 0xFFF0) >> 4) & 0xFF;;
389 }
390
391 client_->OnIncomingCapturedData(
392 yv12_data, yv12_data_length, capture_format_, 0, base::TimeTicks::Now());
393
394 image->ReleaseAccess(&data);
395
396 pxc_capture_thread_.message_loop()->PostTask(
397 FROM_HERE,
398 base::Bind(&VideoCaptureDevicePXCWin::OnCaptureTask,
399 base::Unretained(this)));
400 }
401
402 void VideoCaptureDevicePXCWin::SetErrorState(const std::string& reason) {
403 DVLOG(1) << reason;
404 state_ = kError;
405 client_->OnError(reason);
406 }
407
408 } // namespace media
OLDNEW
« no previous file with comments | « media/video/capture/win/video_capture_device_pxc_win.h ('k') | media/video/capture/win/video_capture_device_win.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698