summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authorbemasc@chromium.org <bemasc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-02 05:20:08 +0000
committerbemasc@chromium.org <bemasc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-02 05:20:08 +0000
commit62762db880f2fdcdc376f49b4d179bf18020e3ef (patch)
tree17d44b240b1b8c014fc6ea705fdbb6beee8e48b1 /media
parent00a77fa687891eb36ef2531820503c9735703dd2 (diff)
downloadchromium_src-62762db880f2fdcdc376f49b4d179bf18020e3ef.zip
chromium_src-62762db880f2fdcdc376f49b4d179bf18020e3ef.tar.gz
chromium_src-62762db880f2fdcdc376f49b4d179bf18020e3ef.tar.bz2
Add a heuristic to try to avoid distorted aspect ratios on Mac.
The test case here is a Logitech B910 opened at 320x240. QTKit satisfies this request by opening at 16:9 and downscaling to 4:3, resulting in an image that is squished (and has severe artifacts due to the low-quality scaler used in QTKit). This CL detects that squishing, and retries at 320x180, resulting in an image with square pixels and no weird scaling artifacts. BUG=303298 Review URL: https://codereview.chromium.org/25629003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@232583 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r--media/video/capture/mac/video_capture_device_mac.h1
-rw-r--r--media/video/capture/mac/video_capture_device_mac.mm65
2 files changed, 50 insertions, 16 deletions
diff --git a/media/video/capture/mac/video_capture_device_mac.h b/media/video/capture/mac/video_capture_device_mac.h
index 5e08223..adfd4c7 100644
--- a/media/video/capture/mac/video_capture_device_mac.h
+++ b/media/video/capture/mac/video_capture_device_mac.h
@@ -63,6 +63,7 @@ class VideoCaptureDeviceMac : public VideoCaptureDevice {
VideoCaptureCapability current_settings_;
bool sent_frame_info_;
+ bool tried_to_square_pixels_;
// Only read and write state_ from inside this loop.
const scoped_refptr<base::MessageLoopProxy> loop_proxy_;
diff --git a/media/video/capture/mac/video_capture_device_mac.mm b/media/video/capture/mac/video_capture_device_mac.mm
index 8235ede..77d30e9 100644
--- a/media/video/capture/mac/video_capture_device_mac.mm
+++ b/media/video/capture/mac/video_capture_device_mac.mm
@@ -34,6 +34,12 @@ const Resolution* const kWellSupportedResolutions[] = {
&kHD,
};
+// Rescaling the image to fix the pixel aspect ratio runs the risk of making
+// the aspect ratio worse, if QTKit selects a new source mode with a different
+// shape. This constant ensures that we don't take this risk if the current
+// aspect ratio is tolerable.
+const float kMaxPixelAspectRatio = 1.15;
+
// TODO(ronghuawu): Replace this with CapabilityList::GetBestMatchedCapability.
void GetBestMatchSupportedResolution(int* width, int* height) {
int min_diff = kint32max;
@@ -105,6 +111,7 @@ VideoCaptureDevice* VideoCaptureDevice::Create(const Name& device_name) {
VideoCaptureDeviceMac::VideoCaptureDeviceMac(const Name& device_name)
: device_name_(device_name),
sent_frame_info_(false),
+ tried_to_square_pixels_(false),
loop_proxy_(base::MessageLoopProxy::current()),
state_(kNotInitialized),
weak_factory_(this),
@@ -153,16 +160,14 @@ void VideoCaptureDeviceMac::AllocateAndStart(
current_settings_.height = height;
current_settings_.frame_rate = frame_rate;
- if (width != kHD.width || height != kHD.height) {
+ if (width <= kVGA.width || height <= kVGA.height) {
// If the resolution is VGA or QVGA, set the capture resolution to the
- // target size. For most cameras (though not all), at these resolutions
- // QTKit produces frames with square pixels.
+ // target size. Essentially all supported cameras offer at least VGA.
if (!UpdateCaptureResolution())
return;
-
- sent_frame_info_ = true;
- client_->OnFrameInfo(current_settings_);
}
+ // For higher resolutions, we first open at the default resolution to find
+ // out if the request is larger than the camera's native resolution.
// If the resolution is HD, start capturing without setting a resolution.
// QTKit will produce frames at the native resolution, allowing us to
@@ -182,10 +187,12 @@ void VideoCaptureDeviceMac::StopAndDeAllocate() {
DCHECK_EQ(loop_proxy_, base::MessageLoopProxy::current());
DCHECK(state_ == kCapturing || state_ == kError) << state_;
[capture_device_ stopCapture];
+
[capture_device_ setCaptureDevice:nil];
[capture_device_ setFrameReceiver:nil];
client_.reset();
state_ = kIdle;
+ tried_to_square_pixels_ = false;
}
bool VideoCaptureDeviceMac::Init() {
@@ -217,38 +224,64 @@ void VideoCaptureDeviceMac::ReceiveFrame(
// i.e. any thread controlled by QTKit.
if (!sent_frame_info_) {
- if (current_settings_.width == kHD.width &&
- current_settings_.height == kHD.height) {
- bool changeToVga = false;
- if (frame_info.width < kHD.width || frame_info.height < kHD.height) {
+ // Final resolution has not yet been selected.
+ if (current_settings_.width > kVGA.width ||
+ current_settings_.height > kVGA.height) {
+ // We are requesting HD. Make sure that the picture is good, otherwise
+ // drop down to VGA.
+ bool change_to_vga = false;
+ if (frame_info.width < current_settings_.width ||
+ frame_info.height < current_settings_.height) {
// These are the default capture settings, not yet configured to match
// |current_settings_|.
DCHECK(frame_info.frame_rate == 0);
DVLOG(1) << "Switching to VGA because the default resolution is " <<
frame_info.width << "x" << frame_info.height;
- changeToVga = true;
+ change_to_vga = true;
}
- if (frame_info.width == kHD.width && frame_info.height == kHD.height &&
+
+ if (frame_info.width == current_settings_.width &&
+ frame_info.height == current_settings_.height &&
aspect_numerator != aspect_denominator) {
DVLOG(1) << "Switching to VGA because HD has nonsquare pixel " <<
"aspect ratio " << aspect_numerator << ":" << aspect_denominator;
- changeToVga = true;
+ change_to_vga = true;
}
- if (changeToVga) {
+ if (change_to_vga) {
current_settings_.width = kVGA.width;
current_settings_.height = kVGA.height;
}
}
if (current_settings_.width == frame_info.width &&
+ current_settings_.height == frame_info.height &&
+ !tried_to_square_pixels_ &&
+ (aspect_numerator > kMaxPixelAspectRatio * aspect_denominator ||
+ aspect_denominator > kMaxPixelAspectRatio * aspect_numerator)) {
+ // The requested size results in non-square PAR.
+ // Shrink the frame to 1:1 PAR (assuming QTKit selects the same input
+ // mode, which is not guaranteed).
+ int new_width = current_settings_.width;
+ int new_height = current_settings_.height;
+ if (aspect_numerator < aspect_denominator) {
+ new_width = (new_width * aspect_numerator) / aspect_denominator;
+ } else {
+ new_height = (new_height * aspect_denominator) / aspect_numerator;
+ }
+ current_settings_.width = new_width;
+ current_settings_.height = new_height;
+ tried_to_square_pixels_ = true;
+ }
+
+ if (current_settings_.width == frame_info.width &&
current_settings_.height == frame_info.height) {
sent_frame_info_ = true;
client_->OnFrameInfo(current_settings_);
} else {
UpdateCaptureResolution();
- // The current frame does not have the right width and height, so it
- // must not be passed to |client_|.
+ // OnFrameInfo has not yet been called. OnIncomingCapturedFrame must
+ // not be called until after OnFrameInfo, so we return early.
return;
}
}