Index: media/video/capture/win/video_capture_device_win.cc |
=================================================================== |
--- media/video/capture/win/video_capture_device_win.cc (revision 170924) |
+++ media/video/capture/win/video_capture_device_win.cc (working copy) |
@@ -10,8 +10,6 @@ |
#include "base/string_util.h" |
#include "base/sys_string_conversions.h" |
#include "base/win/scoped_variant.h" |
-#include "base/win/windows_version.h" |
-#include "media/video/capture/win/video_capture_device_mf_win.h" |
using base::win::ScopedComPtr; |
using base::win::ScopedVariant; |
@@ -144,39 +142,42 @@ |
} |
} |
-} // namespace |
+// Help structure used for comparing video capture capabilities. |
+struct ResolutionDiff { |
+ int capability_index; |
+ int diff_height; |
+ int diff_width; |
+ int diff_frame_rate; |
+ media::VideoCaptureCapability::Format color; |
+}; |
-namespace media { |
+bool CompareHeight(const ResolutionDiff& item1, const ResolutionDiff& item2) { |
+ return abs(item1.diff_height) < abs(item2.diff_height); |
+} |
-// static |
-void VideoCaptureDevice::GetDeviceNames(Names* device_names) { |
- if (base::win::GetVersion() >= base::win::VERSION_VISTA) { |
- VideoCaptureDeviceMFWin::GetDeviceNames(device_names); |
- } else { |
- VideoCaptureDeviceWin::GetDeviceNames(device_names); |
- } |
+bool CompareWidth(const ResolutionDiff& item1, const ResolutionDiff& item2) { |
+ return abs(item1.diff_width) < abs(item2.diff_width); |
} |
-// static |
-VideoCaptureDevice* VideoCaptureDevice::Create(const Name& device_name) { |
- VideoCaptureDevice* ret = NULL; |
- if (base::win::GetVersion() >= base::win::VERSION_VISTA) { |
- scoped_ptr<VideoCaptureDeviceMFWin> device( |
- new VideoCaptureDeviceMFWin(device_name)); |
- if (device->Init()) |
- ret = device.release(); |
- } else { |
- scoped_ptr<VideoCaptureDeviceWin> device( |
- new VideoCaptureDeviceWin(device_name)); |
- if (device->Init()) |
- ret = device.release(); |
- } |
+bool CompareFrameRate(const ResolutionDiff& item1, |
+ const ResolutionDiff& item2) { |
+ return abs(item1.diff_frame_rate) < abs(item2.diff_frame_rate); |
+} |
- return ret; |
+bool CompareColor(const ResolutionDiff& item1, const ResolutionDiff& item2) { |
+ return (item1.color < item2.color); |
} |
-// static |
-void VideoCaptureDeviceWin::GetDeviceNames(Names* device_names) { |
+} // namespace |
+ |
+namespace media { |
+ |
+// Name of a fake DirectShow filter that exist on computers with |
+// GTalk installed. |
+static const char kGoogleCameraAdapter[] = "google camera adapter"; |
+ |
+// Gets the names of all video capture devices connected to this computer. |
+void VideoCaptureDevice::GetDeviceNames(Names* device_names) { |
DCHECK(device_names); |
ScopedComPtr<ICreateDevEnum> dev_enum; |
@@ -195,10 +196,6 @@ |
device_names->clear(); |
- // Name of a fake DirectShow filter that exist on computers with |
- // GTalk installed. |
- static const char kGoogleCameraAdapter[] = "google camera adapter"; |
- |
// Enumerate all video capture devices. |
ScopedComPtr<IMoniker> moniker; |
int index = 0; |
@@ -244,6 +241,15 @@ |
} |
} |
+VideoCaptureDevice* VideoCaptureDevice::Create(const Name& device_name) { |
+ VideoCaptureDeviceWin* self = new VideoCaptureDeviceWin(device_name); |
+ if (self && self->Init()) |
+ return self; |
+ |
+ delete self; |
+ return NULL; |
+} |
+ |
VideoCaptureDeviceWin::VideoCaptureDeviceWin(const Name& device_name) |
: device_name_(device_name), |
state_(kIdle), |
@@ -332,11 +338,10 @@ |
return; |
observer_ = observer; |
- |
// Get the camera capability that best match the requested resolution. |
- const VideoCaptureCapabilityWin& found_capability = |
- capabilities_.GetBestMatchedCapability(width, height, frame_rate); |
- VideoCaptureCapability capability = found_capability; |
+ const int capability_index = GetBestMatchedCapability(width, height, |
+ frame_rate); |
+ VideoCaptureCapability capability = capabilities_[capability_index]; |
// Reduce the frame rate if the requested frame rate is lower |
// than the capability. |
@@ -354,7 +359,7 @@ |
} |
// Get the windows capability from the capture device. |
- hr = stream_config->GetStreamCaps(found_capability.stream_index, &pmt, |
+ hr = stream_config->GetStreamCaps(capability_index, &pmt, |
reinterpret_cast<BYTE*>(&caps)); |
if (SUCCEEDED(hr)) { |
if (pmt->formattype == FORMAT_VideoInfo) { |
@@ -521,7 +526,7 @@ |
if (media_type->majortype == MEDIATYPE_Video && |
media_type->formattype == FORMAT_VideoInfo) { |
- VideoCaptureCapabilityWin capability(i); |
+ VideoCaptureCapability capability; |
REFERENCE_TIME time_per_frame = 0; |
VIDEOINFOHEADER* h = |
@@ -581,15 +586,81 @@ |
DVLOG(2) << "Device support unknown media type " << guid_str; |
continue; |
} |
- capabilities_.Add(capability); |
+ capabilities_[i] = capability; |
} |
DeleteMediaType(media_type); |
media_type = NULL; |
} |
- return !capabilities_.empty(); |
+ return capabilities_.size() > 0; |
} |
+// Loops through the list of capabilities and returns an index of the best |
+// matching capability. |
+// The algorithm prioritize height, width, frame rate and color format in that |
+// order. |
+int VideoCaptureDeviceWin::GetBestMatchedCapability(int requested_width, |
+ int requested_height, |
+ int requested_frame_rate) { |
+ DCHECK(CalledOnValidThread()); |
+ std::list<ResolutionDiff> diff_list; |
+ |
+ // Loop through the candidates to create a list of differentials between the |
+ // requested resolution and the camera capability. |
+ for (CapabilityMap::iterator iterator = capabilities_.begin(); |
+ iterator != capabilities_.end(); |
+ ++iterator) { |
+ VideoCaptureCapability capability = iterator->second; |
+ |
+ ResolutionDiff diff; |
+ diff.capability_index = iterator->first; |
+ diff.diff_width = capability.width - requested_width; |
+ diff.diff_height = capability.height - requested_height; |
+ diff.diff_frame_rate = capability.frame_rate - requested_frame_rate; |
+ diff.color = capability.color; |
+ diff_list.push_back(diff); |
+ } |
+ |
+ // Sort the best height candidates. |
+ diff_list.sort(&CompareHeight); |
+ int best_diff = diff_list.front().diff_height; |
+ for (std::list<ResolutionDiff>::iterator it = diff_list.begin(); |
+ it != diff_list.end(); ++it) { |
+ if (it->diff_height != best_diff) { |
+ // Remove all candidates but the best. |
+ diff_list.erase(it, diff_list.end()); |
+ break; |
+ } |
+ } |
+ |
+ // Sort the best width candidates. |
+ diff_list.sort(&CompareWidth); |
+ best_diff = diff_list.front().diff_width; |
+ for (std::list<ResolutionDiff>::iterator it = diff_list.begin(); |
+ it != diff_list.end(); ++it) { |
+ if (it->diff_width != best_diff) { |
+ // Remove all candidates but the best. |
+ diff_list.erase(it, diff_list.end()); |
+ break; |
+ } |
+ } |
+ |
+ // Sort the best frame rate candidates. |
+ diff_list.sort(&CompareFrameRate); |
+ best_diff = diff_list.front().diff_frame_rate; |
+ for (std::list<ResolutionDiff>::iterator it = diff_list.begin(); |
+ it != diff_list.end(); ++it) { |
+ if (it->diff_frame_rate != best_diff) { |
+ diff_list.erase(it, diff_list.end()); |
+ break; |
+ } |
+ } |
+ |
+ // Decide the best color format. |
+ diff_list.sort(&CompareColor); |
+ return diff_list.front().capability_index; |
+} |
+ |
void VideoCaptureDeviceWin::SetErrorState(const char* reason) { |
DCHECK(CalledOnValidThread()); |
DVLOG(1) << reason; |