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

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

Issue 11419200: Video capture implementation using the Media Foundation API. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Add denominator check Created 8 years 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 | Annotate | Revision Log
« no previous file with comments | « media/video/capture/win/video_capture_device_win.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/video/capture/win/video_capture_device_win.h" 5 #include "media/video/capture/win/video_capture_device_win.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <list> 8 #include <list>
9 9
10 #include "base/string_util.h" 10 #include "base/string_util.h"
11 #include "base/sys_string_conversions.h" 11 #include "base/sys_string_conversions.h"
12 #include "base/win/scoped_variant.h" 12 #include "base/win/scoped_variant.h"
13 #include "base/win/windows_version.h"
14 #include "media/video/capture/win/video_capture_device_mf_win.h"
13 15
14 using base::win::ScopedComPtr; 16 using base::win::ScopedComPtr;
15 using base::win::ScopedVariant; 17 using base::win::ScopedVariant;
16 18
17 namespace { 19 namespace {
18 20
19 // Finds and creates a DirectShow Video Capture filter matching the device_name. 21 // Finds and creates a DirectShow Video Capture filter matching the device_name.
20 HRESULT GetDeviceFilter(const media::VideoCaptureDevice::Name& device_name, 22 HRESULT GetDeviceFilter(const media::VideoCaptureDevice::Name& device_name,
21 IBaseFilter** filter) { 23 IBaseFilter** filter) {
22 DCHECK(filter); 24 DCHECK(filter);
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
135 137
136 // Delete a media type structure that was allocated on the heap. 138 // Delete a media type structure that was allocated on the heap.
137 // http://msdn.microsoft.com/en-us/library/dd375432(VS.85).aspx 139 // http://msdn.microsoft.com/en-us/library/dd375432(VS.85).aspx
138 void DeleteMediaType(AM_MEDIA_TYPE* mt) { 140 void DeleteMediaType(AM_MEDIA_TYPE* mt) {
139 if (mt != NULL) { 141 if (mt != NULL) {
140 FreeMediaType(mt); 142 FreeMediaType(mt);
141 CoTaskMemFree(mt); 143 CoTaskMemFree(mt);
142 } 144 }
143 } 145 }
144 146
145 // Help structure used for comparing video capture capabilities.
146 struct ResolutionDiff {
147 int capability_index;
148 int diff_height;
149 int diff_width;
150 int diff_frame_rate;
151 media::VideoCaptureCapability::Format color;
152 };
153
154 bool CompareHeight(const ResolutionDiff& item1, const ResolutionDiff& item2) {
155 return abs(item1.diff_height) < abs(item2.diff_height);
156 }
157
158 bool CompareWidth(const ResolutionDiff& item1, const ResolutionDiff& item2) {
159 return abs(item1.diff_width) < abs(item2.diff_width);
160 }
161
162 bool CompareFrameRate(const ResolutionDiff& item1,
163 const ResolutionDiff& item2) {
164 return abs(item1.diff_frame_rate) < abs(item2.diff_frame_rate);
165 }
166
167 bool CompareColor(const ResolutionDiff& item1, const ResolutionDiff& item2) {
168 return (item1.color < item2.color);
169 }
170
171 } // namespace 147 } // namespace
172 148
173 namespace media { 149 namespace media {
174 150
175 // Name of a fake DirectShow filter that exist on computers with 151 // static
176 // GTalk installed. 152 void VideoCaptureDevice::GetDeviceNames(Names* device_names) {
177 static const char kGoogleCameraAdapter[] = "google camera adapter"; 153 if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
154 VideoCaptureDeviceMFWin::GetDeviceNames(device_names);
155 } else {
156 VideoCaptureDeviceWin::GetDeviceNames(device_names);
157 }
158 }
178 159
179 // Gets the names of all video capture devices connected to this computer. 160 // static
180 void VideoCaptureDevice::GetDeviceNames(Names* device_names) { 161 VideoCaptureDevice* VideoCaptureDevice::Create(const Name& device_name) {
darin (slow to review) 2012/12/03 18:15:43 nit: might be nice to return scoped_ptr<VideoCaptu
162 VideoCaptureDevice* ret = NULL;
163 if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
164 scoped_ptr<VideoCaptureDeviceMFWin> device(
165 new VideoCaptureDeviceMFWin(device_name));
166 if (device->Init())
167 ret = device.release();
168 } else {
169 scoped_ptr<VideoCaptureDeviceWin> device(
170 new VideoCaptureDeviceWin(device_name));
171 if (device->Init())
172 ret = device.release();
173 }
174
175 return ret;
176 }
177
178 // static
179 void VideoCaptureDeviceWin::GetDeviceNames(Names* device_names) {
181 DCHECK(device_names); 180 DCHECK(device_names);
182 181
183 ScopedComPtr<ICreateDevEnum> dev_enum; 182 ScopedComPtr<ICreateDevEnum> dev_enum;
184 HRESULT hr = dev_enum.CreateInstance(CLSID_SystemDeviceEnum, NULL, 183 HRESULT hr = dev_enum.CreateInstance(CLSID_SystemDeviceEnum, NULL,
185 CLSCTX_INPROC); 184 CLSCTX_INPROC);
186 if (FAILED(hr)) 185 if (FAILED(hr))
187 return; 186 return;
188 187
189 ScopedComPtr<IEnumMoniker> enum_moniker; 188 ScopedComPtr<IEnumMoniker> enum_moniker;
190 hr = dev_enum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, 189 hr = dev_enum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,
191 enum_moniker.Receive(), 0); 190 enum_moniker.Receive(), 0);
192 // CreateClassEnumerator returns S_FALSE on some Windows OS 191 // CreateClassEnumerator returns S_FALSE on some Windows OS
193 // when no camera exist. Therefore the FAILED macro can't be used. 192 // when no camera exist. Therefore the FAILED macro can't be used.
194 if (hr != S_OK) 193 if (hr != S_OK)
195 return; 194 return;
196 195
197 device_names->clear(); 196 device_names->clear();
198 197
198 // Name of a fake DirectShow filter that exist on computers with
199 // GTalk installed.
200 static const char kGoogleCameraAdapter[] = "google camera adapter";
201
199 // Enumerate all video capture devices. 202 // Enumerate all video capture devices.
200 ScopedComPtr<IMoniker> moniker; 203 ScopedComPtr<IMoniker> moniker;
201 int index = 0; 204 int index = 0;
202 while (enum_moniker->Next(1, moniker.Receive(), NULL) == S_OK) { 205 while (enum_moniker->Next(1, moniker.Receive(), NULL) == S_OK) {
203 Name device; 206 Name device;
204 ScopedComPtr<IPropertyBag> prop_bag; 207 ScopedComPtr<IPropertyBag> prop_bag;
205 hr = moniker->BindToStorage(0, 0, IID_IPropertyBag, prop_bag.ReceiveVoid()); 208 hr = moniker->BindToStorage(0, 0, IID_IPropertyBag, prop_bag.ReceiveVoid());
206 if (FAILED(hr)) { 209 if (FAILED(hr)) {
207 moniker.Release(); 210 moniker.Release();
208 continue; 211 continue;
(...skipping 25 matching lines...) Expand all
234 device.unique_id = base::SysWideToUTF8(V_BSTR(&name)); 237 device.unique_id = base::SysWideToUTF8(V_BSTR(&name));
235 } 238 }
236 239
237 device_names->push_back(device); 240 device_names->push_back(device);
238 } 241 }
239 } 242 }
240 moniker.Release(); 243 moniker.Release();
241 } 244 }
242 } 245 }
243 246
244 VideoCaptureDevice* VideoCaptureDevice::Create(const Name& device_name) {
245 VideoCaptureDeviceWin* self = new VideoCaptureDeviceWin(device_name);
246 if (self && self->Init())
247 return self;
248
249 delete self;
250 return NULL;
251 }
252
253 VideoCaptureDeviceWin::VideoCaptureDeviceWin(const Name& device_name) 247 VideoCaptureDeviceWin::VideoCaptureDeviceWin(const Name& device_name)
254 : device_name_(device_name), 248 : device_name_(device_name),
255 state_(kIdle), 249 state_(kIdle),
256 observer_(NULL) { 250 observer_(NULL) {
257 DetachFromThread(); 251 DetachFromThread();
258 } 252 }
259 253
260 VideoCaptureDeviceWin::~VideoCaptureDeviceWin() { 254 VideoCaptureDeviceWin::~VideoCaptureDeviceWin() {
261 DCHECK(CalledOnValidThread()); 255 DCHECK(CalledOnValidThread());
262 if (media_control_) 256 if (media_control_)
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
331 void VideoCaptureDeviceWin::Allocate( 325 void VideoCaptureDeviceWin::Allocate(
332 int width, 326 int width,
333 int height, 327 int height,
334 int frame_rate, 328 int frame_rate,
335 VideoCaptureDevice::EventHandler* observer) { 329 VideoCaptureDevice::EventHandler* observer) {
336 DCHECK(CalledOnValidThread()); 330 DCHECK(CalledOnValidThread());
337 if (state_ != kIdle) 331 if (state_ != kIdle)
338 return; 332 return;
339 333
340 observer_ = observer; 334 observer_ = observer;
335
341 // Get the camera capability that best match the requested resolution. 336 // Get the camera capability that best match the requested resolution.
342 const int capability_index = GetBestMatchedCapability(width, height, 337 const VideoCaptureCapabilityWin& found_capability =
343 frame_rate); 338 capabilities_.GetBestMatchedCapability(width, height, frame_rate);
344 VideoCaptureCapability capability = capabilities_[capability_index]; 339 VideoCaptureCapability capability = found_capability;
345 340
346 // Reduce the frame rate if the requested frame rate is lower 341 // Reduce the frame rate if the requested frame rate is lower
347 // than the capability. 342 // than the capability.
348 if (capability.frame_rate > frame_rate) 343 if (capability.frame_rate > frame_rate)
349 capability.frame_rate = frame_rate; 344 capability.frame_rate = frame_rate;
350 345
351 AM_MEDIA_TYPE* pmt = NULL; 346 AM_MEDIA_TYPE* pmt = NULL;
352 VIDEO_STREAM_CONFIG_CAPS caps; 347 VIDEO_STREAM_CONFIG_CAPS caps;
353 348
354 ScopedComPtr<IAMStreamConfig> stream_config; 349 ScopedComPtr<IAMStreamConfig> stream_config;
355 HRESULT hr = output_capture_pin_.QueryInterface(stream_config.Receive()); 350 HRESULT hr = output_capture_pin_.QueryInterface(stream_config.Receive());
356 if (FAILED(hr)) { 351 if (FAILED(hr)) {
357 SetErrorState("Can't get the Capture format settings"); 352 SetErrorState("Can't get the Capture format settings");
358 return; 353 return;
359 } 354 }
360 355
361 // Get the windows capability from the capture device. 356 // Get the windows capability from the capture device.
362 hr = stream_config->GetStreamCaps(capability_index, &pmt, 357 hr = stream_config->GetStreamCaps(found_capability.stream_index, &pmt,
363 reinterpret_cast<BYTE*>(&caps)); 358 reinterpret_cast<BYTE*>(&caps));
364 if (SUCCEEDED(hr)) { 359 if (SUCCEEDED(hr)) {
365 if (pmt->formattype == FORMAT_VideoInfo) { 360 if (pmt->formattype == FORMAT_VideoInfo) {
366 VIDEOINFOHEADER* h = reinterpret_cast<VIDEOINFOHEADER*>(pmt->pbFormat); 361 VIDEOINFOHEADER* h = reinterpret_cast<VIDEOINFOHEADER*>(pmt->pbFormat);
367 if (capability.frame_rate > 0) 362 if (capability.frame_rate > 0)
368 h->AvgTimePerFrame = kSecondsToReferenceTime / capability.frame_rate; 363 h->AvgTimePerFrame = kSecondsToReferenceTime / capability.frame_rate;
369 } 364 }
370 // Set the sink filter to request this capability. 365 // Set the sink filter to request this capability.
371 sink_filter_->SetRequestedMediaCapability(capability); 366 sink_filter_->SetRequestedMediaCapability(capability);
372 // Order the capture device to use this capability. 367 // Order the capture device to use this capability.
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after
519 for (int i = 0; i < count; ++i) { 514 for (int i = 0; i < count; ++i) {
520 hr = stream_config->GetStreamCaps(i, &media_type, 515 hr = stream_config->GetStreamCaps(i, &media_type,
521 reinterpret_cast<BYTE*>(&caps)); 516 reinterpret_cast<BYTE*>(&caps));
522 if (FAILED(hr)) { 517 if (FAILED(hr)) {
523 DVLOG(2) << "Failed to GetStreamCaps"; 518 DVLOG(2) << "Failed to GetStreamCaps";
524 return false; 519 return false;
525 } 520 }
526 521
527 if (media_type->majortype == MEDIATYPE_Video && 522 if (media_type->majortype == MEDIATYPE_Video &&
528 media_type->formattype == FORMAT_VideoInfo) { 523 media_type->formattype == FORMAT_VideoInfo) {
529 VideoCaptureCapability capability; 524 VideoCaptureCapabilityWin capability(i);
530 REFERENCE_TIME time_per_frame = 0; 525 REFERENCE_TIME time_per_frame = 0;
531 526
532 VIDEOINFOHEADER* h = 527 VIDEOINFOHEADER* h =
533 reinterpret_cast<VIDEOINFOHEADER*>(media_type->pbFormat); 528 reinterpret_cast<VIDEOINFOHEADER*>(media_type->pbFormat);
534 capability.width = h->bmiHeader.biWidth; 529 capability.width = h->bmiHeader.biWidth;
535 capability.height = h->bmiHeader.biHeight; 530 capability.height = h->bmiHeader.biHeight;
536 time_per_frame = h->AvgTimePerFrame; 531 time_per_frame = h->AvgTimePerFrame;
537 532
538 // Try to get the max frame rate from IAMVideoControl. 533 // Try to get the max frame rate from IAMVideoControl.
539 if (video_control.get()) { 534 if (video_control.get()) {
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
579 } else if (media_type->subtype == MEDIASUBTYPE_YUY2) { 574 } else if (media_type->subtype == MEDIASUBTYPE_YUY2) {
580 capability.color = VideoCaptureCapability::kYUY2; 575 capability.color = VideoCaptureCapability::kYUY2;
581 } else if (media_type->subtype == MEDIASUBTYPE_MJPG) { 576 } else if (media_type->subtype == MEDIASUBTYPE_MJPG) {
582 capability.color = VideoCaptureCapability::kMJPEG; 577 capability.color = VideoCaptureCapability::kMJPEG;
583 } else { 578 } else {
584 WCHAR guid_str[128]; 579 WCHAR guid_str[128];
585 StringFromGUID2(media_type->subtype, guid_str, arraysize(guid_str)); 580 StringFromGUID2(media_type->subtype, guid_str, arraysize(guid_str));
586 DVLOG(2) << "Device support unknown media type " << guid_str; 581 DVLOG(2) << "Device support unknown media type " << guid_str;
587 continue; 582 continue;
588 } 583 }
589 capabilities_[i] = capability; 584 capabilities_.Add(capability);
590 } 585 }
591 DeleteMediaType(media_type); 586 DeleteMediaType(media_type);
592 media_type = NULL; 587 media_type = NULL;
593 } 588 }
594 589
595 return capabilities_.size() > 0; 590 return !capabilities_.empty();
596 }
597
598 // Loops through the list of capabilities and returns an index of the best
599 // matching capability.
600 // The algorithm prioritize height, width, frame rate and color format in that
601 // order.
602 int VideoCaptureDeviceWin::GetBestMatchedCapability(int requested_width,
603 int requested_height,
604 int requested_frame_rate) {
605 DCHECK(CalledOnValidThread());
606 std::list<ResolutionDiff> diff_list;
607
608 // Loop through the candidates to create a list of differentials between the
609 // requested resolution and the camera capability.
610 for (CapabilityMap::iterator iterator = capabilities_.begin();
611 iterator != capabilities_.end();
612 ++iterator) {
613 VideoCaptureCapability capability = iterator->second;
614
615 ResolutionDiff diff;
616 diff.capability_index = iterator->first;
617 diff.diff_width = capability.width - requested_width;
618 diff.diff_height = capability.height - requested_height;
619 diff.diff_frame_rate = capability.frame_rate - requested_frame_rate;
620 diff.color = capability.color;
621 diff_list.push_back(diff);
622 }
623
624 // Sort the best height candidates.
625 diff_list.sort(&CompareHeight);
626 int best_diff = diff_list.front().diff_height;
627 for (std::list<ResolutionDiff>::iterator it = diff_list.begin();
628 it != diff_list.end(); ++it) {
629 if (it->diff_height != best_diff) {
630 // Remove all candidates but the best.
631 diff_list.erase(it, diff_list.end());
632 break;
633 }
634 }
635
636 // Sort the best width candidates.
637 diff_list.sort(&CompareWidth);
638 best_diff = diff_list.front().diff_width;
639 for (std::list<ResolutionDiff>::iterator it = diff_list.begin();
640 it != diff_list.end(); ++it) {
641 if (it->diff_width != best_diff) {
642 // Remove all candidates but the best.
643 diff_list.erase(it, diff_list.end());
644 break;
645 }
646 }
647
648 // Sort the best frame rate candidates.
649 diff_list.sort(&CompareFrameRate);
650 best_diff = diff_list.front().diff_frame_rate;
651 for (std::list<ResolutionDiff>::iterator it = diff_list.begin();
652 it != diff_list.end(); ++it) {
653 if (it->diff_frame_rate != best_diff) {
654 diff_list.erase(it, diff_list.end());
655 break;
656 }
657 }
658
659 // Decide the best color format.
660 diff_list.sort(&CompareColor);
661 return diff_list.front().capability_index;
662 } 591 }
663 592
664 void VideoCaptureDeviceWin::SetErrorState(const char* reason) { 593 void VideoCaptureDeviceWin::SetErrorState(const char* reason) {
665 DCHECK(CalledOnValidThread()); 594 DCHECK(CalledOnValidThread());
666 DVLOG(1) << reason; 595 DVLOG(1) << reason;
667 state_ = kError; 596 state_ = kError;
668 observer_->OnError(); 597 observer_->OnError();
669 } 598 }
670 599
671 } // namespace media 600 } // namespace media
OLDNEW
« no previous file with comments | « media/video/capture/win/video_capture_device_win.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698