OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "media/capture/video/win/video_capture_device_win.h" | 5 #include "media/capture/video/win/video_capture_device_win.h" |
6 | 6 |
7 #include <ks.h> | 7 #include <ks.h> |
8 #include <ksmedia.h> | 8 #include <ksmedia.h> |
9 | 9 |
10 #include <algorithm> | 10 #include <algorithm> |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
125 // Finds an IPin on an IBaseFilter given the direction, Category and/or Major | 125 // Finds an IPin on an IBaseFilter given the direction, Category and/or Major |
126 // Type. If either |category| or |major_type| are GUID_NULL, they are ignored. | 126 // Type. If either |category| or |major_type| are GUID_NULL, they are ignored. |
127 // static | 127 // static |
128 ScopedComPtr<IPin> VideoCaptureDeviceWin::GetPin(IBaseFilter* filter, | 128 ScopedComPtr<IPin> VideoCaptureDeviceWin::GetPin(IBaseFilter* filter, |
129 PIN_DIRECTION pin_dir, | 129 PIN_DIRECTION pin_dir, |
130 REFGUID category, | 130 REFGUID category, |
131 REFGUID major_type) { | 131 REFGUID major_type) { |
132 ScopedComPtr<IPin> pin; | 132 ScopedComPtr<IPin> pin; |
133 ScopedComPtr<IEnumPins> pin_enum; | 133 ScopedComPtr<IEnumPins> pin_enum; |
134 HRESULT hr = filter->EnumPins(pin_enum.Receive()); | 134 HRESULT hr = filter->EnumPins(pin_enum.Receive()); |
135 if (pin_enum.get() == NULL) | 135 if (pin_enum.Get() == NULL) |
136 return pin; | 136 return pin; |
137 | 137 |
138 // Get first unconnected pin. | 138 // Get first unconnected pin. |
139 hr = pin_enum->Reset(); // set to first pin | 139 hr = pin_enum->Reset(); // set to first pin |
140 while ((hr = pin_enum->Next(1, pin.Receive(), NULL)) == S_OK) { | 140 while ((hr = pin_enum->Next(1, pin.Receive(), NULL)) == S_OK) { |
141 PIN_DIRECTION this_pin_dir = static_cast<PIN_DIRECTION>(-1); | 141 PIN_DIRECTION this_pin_dir = static_cast<PIN_DIRECTION>(-1); |
142 hr = pin->QueryDirection(&this_pin_dir); | 142 hr = pin->QueryDirection(&this_pin_dir); |
143 if (pin_dir == this_pin_dir) { | 143 if (pin_dir == this_pin_dir) { |
144 if ((category == GUID_NULL || PinMatchesCategory(pin.get(), category)) && | 144 if ((category == GUID_NULL || PinMatchesCategory(pin.Get(), category)) && |
145 (major_type == GUID_NULL || | 145 (major_type == GUID_NULL || |
146 PinMatchesMajorType(pin.get(), major_type))) { | 146 PinMatchesMajorType(pin.Get(), major_type))) { |
147 return pin; | 147 return pin; |
148 } | 148 } |
149 } | 149 } |
150 pin.Reset(); | 150 pin.Reset(); |
151 } | 151 } |
152 | 152 |
153 DCHECK(!pin.get()); | 153 DCHECK(!pin.Get()); |
154 return pin; | 154 return pin; |
155 } | 155 } |
156 | 156 |
157 // static | 157 // static |
158 VideoPixelFormat | 158 VideoPixelFormat |
159 VideoCaptureDeviceWin::TranslateMediaSubtypeToPixelFormat( | 159 VideoCaptureDeviceWin::TranslateMediaSubtypeToPixelFormat( |
160 const GUID& sub_type) { | 160 const GUID& sub_type) { |
161 static struct { | 161 static struct { |
162 const GUID& sub_type; | 162 const GUID& sub_type; |
163 VideoPixelFormat format; | 163 VideoPixelFormat format; |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
227 | 227 |
228 VideoCaptureDeviceWin::VideoCaptureDeviceWin( | 228 VideoCaptureDeviceWin::VideoCaptureDeviceWin( |
229 const VideoCaptureDeviceDescriptor& device_descriptor) | 229 const VideoCaptureDeviceDescriptor& device_descriptor) |
230 : device_descriptor_(device_descriptor), state_(kIdle) { | 230 : device_descriptor_(device_descriptor), state_(kIdle) { |
231 // TODO(mcasas): Check that CoInitializeEx() has been called with the | 231 // TODO(mcasas): Check that CoInitializeEx() has been called with the |
232 // appropriate Apartment model, i.e., Single Threaded. | 232 // appropriate Apartment model, i.e., Single Threaded. |
233 } | 233 } |
234 | 234 |
235 VideoCaptureDeviceWin::~VideoCaptureDeviceWin() { | 235 VideoCaptureDeviceWin::~VideoCaptureDeviceWin() { |
236 DCHECK(thread_checker_.CalledOnValidThread()); | 236 DCHECK(thread_checker_.CalledOnValidThread()); |
237 if (media_control_.get()) | 237 if (media_control_.Get()) |
238 media_control_->Stop(); | 238 media_control_->Stop(); |
239 | 239 |
240 if (graph_builder_.get()) { | 240 if (graph_builder_.Get()) { |
241 if (sink_filter_.get()) { | 241 if (sink_filter_.get()) { |
242 graph_builder_->RemoveFilter(sink_filter_.get()); | 242 graph_builder_->RemoveFilter(sink_filter_.get()); |
243 sink_filter_ = NULL; | 243 sink_filter_ = NULL; |
244 } | 244 } |
245 | 245 |
246 if (capture_filter_.get()) | 246 if (capture_filter_.Get()) |
247 graph_builder_->RemoveFilter(capture_filter_.get()); | 247 graph_builder_->RemoveFilter(capture_filter_.Get()); |
248 } | 248 } |
249 | 249 |
250 if (capture_graph_builder_.get()) | 250 if (capture_graph_builder_.Get()) |
251 capture_graph_builder_.Reset(); | 251 capture_graph_builder_.Reset(); |
252 } | 252 } |
253 | 253 |
254 bool VideoCaptureDeviceWin::Init() { | 254 bool VideoCaptureDeviceWin::Init() { |
255 DCHECK(thread_checker_.CalledOnValidThread()); | 255 DCHECK(thread_checker_.CalledOnValidThread()); |
256 HRESULT hr; | 256 HRESULT hr; |
257 | 257 |
258 hr = GetDeviceFilter(device_descriptor_.device_id, capture_filter_.Receive()); | 258 hr = GetDeviceFilter(device_descriptor_.device_id, capture_filter_.Receive()); |
259 DLOG_IF_FAILED_WITH_HRESULT("Failed to create capture filter", hr); | 259 DLOG_IF_FAILED_WITH_HRESULT("Failed to create capture filter", hr); |
260 if (!capture_filter_.get()) | 260 if (!capture_filter_.Get()) |
261 return false; | 261 return false; |
262 | 262 |
263 output_capture_pin_ = GetPin(capture_filter_.get(), PINDIR_OUTPUT, | 263 output_capture_pin_ = GetPin(capture_filter_.Get(), PINDIR_OUTPUT, |
264 PIN_CATEGORY_CAPTURE, GUID_NULL); | 264 PIN_CATEGORY_CAPTURE, GUID_NULL); |
265 if (!output_capture_pin_.get()) { | 265 if (!output_capture_pin_.Get()) { |
266 DLOG(ERROR) << "Failed to get capture output pin"; | 266 DLOG(ERROR) << "Failed to get capture output pin"; |
267 return false; | 267 return false; |
268 } | 268 } |
269 | 269 |
270 // Create the sink filter used for receiving Captured frames. | 270 // Create the sink filter used for receiving Captured frames. |
271 sink_filter_ = new SinkFilter(this); | 271 sink_filter_ = new SinkFilter(this); |
272 if (sink_filter_.get() == NULL) { | 272 if (sink_filter_.get() == NULL) { |
273 DLOG(ERROR) << "Failed to create sink filter"; | 273 DLOG(ERROR) << "Failed to create sink filter"; |
274 return false; | 274 return false; |
275 } | 275 } |
276 | 276 |
277 input_sink_pin_ = sink_filter_->GetPin(0); | 277 input_sink_pin_ = sink_filter_->GetPin(0); |
278 | 278 |
279 hr = graph_builder_.CreateInstance(CLSID_FilterGraph, NULL, | 279 hr = graph_builder_.CreateInstance(CLSID_FilterGraph, NULL, |
280 CLSCTX_INPROC_SERVER); | 280 CLSCTX_INPROC_SERVER); |
281 DLOG_IF_FAILED_WITH_HRESULT("Failed to create capture filter", hr); | 281 DLOG_IF_FAILED_WITH_HRESULT("Failed to create capture filter", hr); |
282 if (FAILED(hr)) | 282 if (FAILED(hr)) |
283 return false; | 283 return false; |
284 | 284 |
285 hr = capture_graph_builder_.CreateInstance(CLSID_CaptureGraphBuilder2, NULL, | 285 hr = capture_graph_builder_.CreateInstance(CLSID_CaptureGraphBuilder2, NULL, |
286 CLSCTX_INPROC); | 286 CLSCTX_INPROC); |
287 DLOG_IF_FAILED_WITH_HRESULT("Failed to create the Capture Graph Builder", hr); | 287 DLOG_IF_FAILED_WITH_HRESULT("Failed to create the Capture Graph Builder", hr); |
288 if (FAILED(hr)) | 288 if (FAILED(hr)) |
289 return false; | 289 return false; |
290 | 290 |
291 hr = capture_graph_builder_->SetFiltergraph(graph_builder_.get()); | 291 hr = capture_graph_builder_->SetFiltergraph(graph_builder_.Get()); |
292 DLOG_IF_FAILED_WITH_HRESULT("Failed to give graph to capture graph builder", | 292 DLOG_IF_FAILED_WITH_HRESULT("Failed to give graph to capture graph builder", |
293 hr); | 293 hr); |
294 if (FAILED(hr)) | 294 if (FAILED(hr)) |
295 return false; | 295 return false; |
296 | 296 |
297 hr = graph_builder_.QueryInterface(media_control_.Receive()); | 297 hr = graph_builder_.QueryInterface(media_control_.Receive()); |
298 DLOG_IF_FAILED_WITH_HRESULT("Failed to create media control builder", hr); | 298 DLOG_IF_FAILED_WITH_HRESULT("Failed to create media control builder", hr); |
299 if (FAILED(hr)) | 299 if (FAILED(hr)) |
300 return false; | 300 return false; |
301 | 301 |
302 hr = graph_builder_->AddFilter(capture_filter_.get(), NULL); | 302 hr = graph_builder_->AddFilter(capture_filter_.Get(), NULL); |
303 DLOG_IF_FAILED_WITH_HRESULT("Failed to add the capture device to the graph", | 303 DLOG_IF_FAILED_WITH_HRESULT("Failed to add the capture device to the graph", |
304 hr); | 304 hr); |
305 if (FAILED(hr)) | 305 if (FAILED(hr)) |
306 return false; | 306 return false; |
307 | 307 |
308 hr = graph_builder_->AddFilter(sink_filter_.get(), NULL); | 308 hr = graph_builder_->AddFilter(sink_filter_.get(), NULL); |
309 DLOG_IF_FAILED_WITH_HRESULT("Failed to add the sink filter to the graph", hr); | 309 DLOG_IF_FAILED_WITH_HRESULT("Failed to add the sink filter to the graph", hr); |
310 if (FAILED(hr)) | 310 if (FAILED(hr)) |
311 return false; | 311 return false; |
312 | 312 |
313 // The following code builds the upstream portions of the graph, for example | 313 // The following code builds the upstream portions of the graph, for example |
314 // if a capture device uses a Windows Driver Model (WDM) driver, the graph may | 314 // if a capture device uses a Windows Driver Model (WDM) driver, the graph may |
315 // require certain filters upstream from the WDM Video Capture filter, such as | 315 // require certain filters upstream from the WDM Video Capture filter, such as |
316 // a TV Tuner filter or an Analog Video Crossbar filter. We try using the more | 316 // a TV Tuner filter or an Analog Video Crossbar filter. We try using the more |
317 // prevalent MEDIATYPE_Interleaved first. | 317 // prevalent MEDIATYPE_Interleaved first. |
318 base::win::ScopedComPtr<IAMStreamConfig> stream_config; | 318 base::win::ScopedComPtr<IAMStreamConfig> stream_config; |
319 | 319 |
320 hr = capture_graph_builder_->FindInterface( | 320 hr = capture_graph_builder_->FindInterface( |
321 &PIN_CATEGORY_CAPTURE, &MEDIATYPE_Interleaved, capture_filter_.get(), | 321 &PIN_CATEGORY_CAPTURE, &MEDIATYPE_Interleaved, capture_filter_.Get(), |
322 IID_IAMStreamConfig, (void**)stream_config.Receive()); | 322 IID_IAMStreamConfig, (void**)stream_config.Receive()); |
323 if (FAILED(hr)) { | 323 if (FAILED(hr)) { |
324 hr = capture_graph_builder_->FindInterface( | 324 hr = capture_graph_builder_->FindInterface( |
325 &PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, capture_filter_.get(), | 325 &PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, capture_filter_.Get(), |
326 IID_IAMStreamConfig, (void**)stream_config.Receive()); | 326 IID_IAMStreamConfig, (void**)stream_config.Receive()); |
327 DLOG_IF_FAILED_WITH_HRESULT("Failed to find CapFilter:IAMStreamConfig", hr); | 327 DLOG_IF_FAILED_WITH_HRESULT("Failed to find CapFilter:IAMStreamConfig", hr); |
328 } | 328 } |
329 | 329 |
330 return CreateCapabilityMap(); | 330 return CreateCapabilityMap(); |
331 } | 331 } |
332 | 332 |
333 void VideoCaptureDeviceWin::AllocateAndStart( | 333 void VideoCaptureDeviceWin::AllocateAndStart( |
334 const VideoCaptureParams& params, | 334 const VideoCaptureParams& params, |
335 std::unique_ptr<VideoCaptureDevice::Client> client) { | 335 std::unique_ptr<VideoCaptureDevice::Client> client) { |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
390 if (FAILED(hr)) { | 390 if (FAILED(hr)) { |
391 SetErrorState(FROM_HERE, "Failed to set capture device output format", hr); | 391 SetErrorState(FROM_HERE, "Failed to set capture device output format", hr); |
392 return; | 392 return; |
393 } | 393 } |
394 | 394 |
395 SetAntiFlickerInCaptureFilter(params); | 395 SetAntiFlickerInCaptureFilter(params); |
396 | 396 |
397 if (media_type->subtype == kMediaSubTypeHDYC) { | 397 if (media_type->subtype == kMediaSubTypeHDYC) { |
398 // HDYC pixel format, used by the DeckLink capture card, needs an AVI | 398 // HDYC pixel format, used by the DeckLink capture card, needs an AVI |
399 // decompressor filter after source, let |graph_builder_| add it. | 399 // decompressor filter after source, let |graph_builder_| add it. |
400 hr = graph_builder_->Connect(output_capture_pin_.get(), | 400 hr = graph_builder_->Connect(output_capture_pin_.Get(), |
401 input_sink_pin_.get()); | 401 input_sink_pin_.Get()); |
402 } else { | 402 } else { |
403 hr = graph_builder_->ConnectDirect(output_capture_pin_.get(), | 403 hr = graph_builder_->ConnectDirect(output_capture_pin_.Get(), |
404 input_sink_pin_.get(), NULL); | 404 input_sink_pin_.Get(), NULL); |
405 } | 405 } |
406 | 406 |
407 if (FAILED(hr)) { | 407 if (FAILED(hr)) { |
408 SetErrorState(FROM_HERE, "Failed to connect the Capture graph.", hr); | 408 SetErrorState(FROM_HERE, "Failed to connect the Capture graph.", hr); |
409 return; | 409 return; |
410 } | 410 } |
411 | 411 |
412 hr = media_control_->Pause(); | 412 hr = media_control_->Pause(); |
413 if (FAILED(hr)) { | 413 if (FAILED(hr)) { |
414 SetErrorState(FROM_HERE, "Failed to pause the Capture device", hr); | 414 SetErrorState(FROM_HERE, "Failed to pause the Capture device", hr); |
(...skipping 15 matching lines...) Expand all Loading... |
430 DCHECK(thread_checker_.CalledOnValidThread()); | 430 DCHECK(thread_checker_.CalledOnValidThread()); |
431 if (state_ != kCapturing) | 431 if (state_ != kCapturing) |
432 return; | 432 return; |
433 | 433 |
434 HRESULT hr = media_control_->Stop(); | 434 HRESULT hr = media_control_->Stop(); |
435 if (FAILED(hr)) { | 435 if (FAILED(hr)) { |
436 SetErrorState(FROM_HERE, "Failed to stop the capture graph.", hr); | 436 SetErrorState(FROM_HERE, "Failed to stop the capture graph.", hr); |
437 return; | 437 return; |
438 } | 438 } |
439 | 439 |
440 graph_builder_->Disconnect(output_capture_pin_.get()); | 440 graph_builder_->Disconnect(output_capture_pin_.Get()); |
441 graph_builder_->Disconnect(input_sink_pin_.get()); | 441 graph_builder_->Disconnect(input_sink_pin_.Get()); |
442 | 442 |
443 client_.reset(); | 443 client_.reset(); |
444 state_ = kIdle; | 444 state_ = kIdle; |
445 } | 445 } |
446 | 446 |
447 void VideoCaptureDeviceWin::TakePhoto(TakePhotoCallback callback) { | 447 void VideoCaptureDeviceWin::TakePhoto(TakePhotoCallback callback) { |
448 DCHECK(thread_checker_.CalledOnValidThread()); | 448 DCHECK(thread_checker_.CalledOnValidThread()); |
449 // DirectShow has other means of capturing still pictures, e.g. connecting a | 449 // DirectShow has other means of capturing still pictures, e.g. connecting a |
450 // SampleGrabber filter to a PIN_CATEGORY_STILL of |capture_filter_|. This | 450 // SampleGrabber filter to a PIN_CATEGORY_STILL of |capture_filter_|. This |
451 // way, however, is not widespread and proves too cumbersome, so we just grab | 451 // way, however, is not widespread and proves too cumbersome, so we just grab |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
518 if (format.pixel_format == PIXEL_FORMAT_UNKNOWN) | 518 if (format.pixel_format == PIXEL_FORMAT_UNKNOWN) |
519 continue; | 519 continue; |
520 | 520 |
521 VIDEOINFOHEADER* h = | 521 VIDEOINFOHEADER* h = |
522 reinterpret_cast<VIDEOINFOHEADER*>(media_type->pbFormat); | 522 reinterpret_cast<VIDEOINFOHEADER*>(media_type->pbFormat); |
523 format.frame_size.SetSize(h->bmiHeader.biWidth, h->bmiHeader.biHeight); | 523 format.frame_size.SetSize(h->bmiHeader.biWidth, h->bmiHeader.biHeight); |
524 | 524 |
525 // Try to get a better |time_per_frame| from IAMVideoControl. If not, use | 525 // Try to get a better |time_per_frame| from IAMVideoControl. If not, use |
526 // the value from VIDEOINFOHEADER. | 526 // the value from VIDEOINFOHEADER. |
527 REFERENCE_TIME time_per_frame = h->AvgTimePerFrame; | 527 REFERENCE_TIME time_per_frame = h->AvgTimePerFrame; |
528 if (video_control.get()) { | 528 if (video_control.Get()) { |
529 ScopedCoMem<LONGLONG> max_fps; | 529 ScopedCoMem<LONGLONG> max_fps; |
530 LONG list_size = 0; | 530 LONG list_size = 0; |
531 const SIZE size = {format.frame_size.width(), | 531 const SIZE size = {format.frame_size.width(), |
532 format.frame_size.height()}; | 532 format.frame_size.height()}; |
533 hr = video_control->GetFrameRateList(output_capture_pin_.get(), | 533 hr = video_control->GetFrameRateList(output_capture_pin_.Get(), |
534 stream_index, size, &list_size, | 534 stream_index, size, &list_size, |
535 &max_fps); | 535 &max_fps); |
536 // Can't assume the first value will return the max fps. | 536 // Can't assume the first value will return the max fps. |
537 // Sometimes |list_size| will be > 0, but max_fps will be NULL. Some | 537 // Sometimes |list_size| will be > 0, but max_fps will be NULL. Some |
538 // drivers may return an HRESULT of S_FALSE which SUCCEEDED() translates | 538 // drivers may return an HRESULT of S_FALSE which SUCCEEDED() translates |
539 // into success, so explicitly check S_OK. See http://crbug.com/306237. | 539 // into success, so explicitly check S_OK. See http://crbug.com/306237. |
540 if (hr == S_OK && list_size > 0 && max_fps) { | 540 if (hr == S_OK && list_size > 0 && max_fps) { |
541 time_per_frame = | 541 time_per_frame = |
542 *std::min_element(max_fps.get(), max_fps.get() + list_size); | 542 *std::min_element(max_fps.get(), max_fps.get() + list_size); |
543 } | 543 } |
(...skipping 15 matching lines...) Expand all Loading... |
559 void VideoCaptureDeviceWin::SetAntiFlickerInCaptureFilter( | 559 void VideoCaptureDeviceWin::SetAntiFlickerInCaptureFilter( |
560 const VideoCaptureParams& params) { | 560 const VideoCaptureParams& params) { |
561 const PowerLineFrequency power_line_frequency = GetPowerLineFrequency(params); | 561 const PowerLineFrequency power_line_frequency = GetPowerLineFrequency(params); |
562 if (power_line_frequency != media::PowerLineFrequency::FREQUENCY_50HZ && | 562 if (power_line_frequency != media::PowerLineFrequency::FREQUENCY_50HZ && |
563 power_line_frequency != media::PowerLineFrequency::FREQUENCY_60HZ) { | 563 power_line_frequency != media::PowerLineFrequency::FREQUENCY_60HZ) { |
564 return; | 564 return; |
565 } | 565 } |
566 ScopedComPtr<IKsPropertySet> ks_propset; | 566 ScopedComPtr<IKsPropertySet> ks_propset; |
567 DWORD type_support = 0; | 567 DWORD type_support = 0; |
568 HRESULT hr; | 568 HRESULT hr; |
569 if (SUCCEEDED(hr = ks_propset.QueryFrom(capture_filter_.get())) && | 569 if (SUCCEEDED(hr = ks_propset.QueryFrom(capture_filter_.Get())) && |
570 SUCCEEDED(hr = ks_propset->QuerySupported( | 570 SUCCEEDED(hr = ks_propset->QuerySupported( |
571 PROPSETID_VIDCAP_VIDEOPROCAMP, | 571 PROPSETID_VIDCAP_VIDEOPROCAMP, |
572 KSPROPERTY_VIDEOPROCAMP_POWERLINE_FREQUENCY, | 572 KSPROPERTY_VIDEOPROCAMP_POWERLINE_FREQUENCY, |
573 &type_support)) && | 573 &type_support)) && |
574 (type_support & KSPROPERTY_SUPPORT_SET)) { | 574 (type_support & KSPROPERTY_SUPPORT_SET)) { |
575 KSPROPERTY_VIDEOPROCAMP_S data = {}; | 575 KSPROPERTY_VIDEOPROCAMP_S data = {}; |
576 data.Property.Set = PROPSETID_VIDCAP_VIDEOPROCAMP; | 576 data.Property.Set = PROPSETID_VIDCAP_VIDEOPROCAMP; |
577 data.Property.Id = KSPROPERTY_VIDEOPROCAMP_POWERLINE_FREQUENCY; | 577 data.Property.Id = KSPROPERTY_VIDEOPROCAMP_POWERLINE_FREQUENCY; |
578 data.Property.Flags = KSPROPERTY_TYPE_SET; | 578 data.Property.Flags = KSPROPERTY_TYPE_SET; |
579 data.Value = | 579 data.Value = |
(...skipping 10 matching lines...) Expand all Loading... |
590 void VideoCaptureDeviceWin::SetErrorState( | 590 void VideoCaptureDeviceWin::SetErrorState( |
591 const tracked_objects::Location& from_here, | 591 const tracked_objects::Location& from_here, |
592 const std::string& reason, | 592 const std::string& reason, |
593 HRESULT hr) { | 593 HRESULT hr) { |
594 DCHECK(thread_checker_.CalledOnValidThread()); | 594 DCHECK(thread_checker_.CalledOnValidThread()); |
595 DLOG_IF_FAILED_WITH_HRESULT(reason, hr); | 595 DLOG_IF_FAILED_WITH_HRESULT(reason, hr); |
596 state_ = kError; | 596 state_ = kError; |
597 client_->OnError(from_here, reason); | 597 client_->OnError(from_here, reason); |
598 } | 598 } |
599 } // namespace media | 599 } // namespace media |
OLD | NEW |