summaryrefslogtreecommitdiff
path: root/chromium/media/video/capture/mac/video_capture_device_mac.mm
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/media/video/capture/mac/video_capture_device_mac.mm')
-rw-r--r--chromium/media/video/capture/mac/video_capture_device_mac.mm145
1 files changed, 118 insertions, 27 deletions
diff --git a/chromium/media/video/capture/mac/video_capture_device_mac.mm b/chromium/media/video/capture/mac/video_capture_device_mac.mm
index 18912170a10..eea861481fe 100644
--- a/chromium/media/video/capture/mac/video_capture_device_mac.mm
+++ b/chromium/media/video/capture/mac/video_capture_device_mac.mm
@@ -6,6 +6,8 @@
#import <QTKit/QTKit.h>
+#include "base/bind.h"
+#include "base/location.h"
#include "base/logging.h"
#include "base/time/time.h"
#include "media/video/capture/mac/video_capture_device_qtkit_mac.h"
@@ -23,10 +25,14 @@ struct Resolution {
int height;
};
-const Resolution kWellSupportedResolutions[] = {
- { 320, 240 },
- { 640, 480 },
- { 1280, 720 },
+const Resolution kQVGA = { 320, 240 },
+ kVGA = { 640, 480 },
+ kHD = { 1280, 720 };
+
+const Resolution* const kWellSupportedResolutions[] = {
+ &kQVGA,
+ &kVGA,
+ &kHD,
};
// TODO(ronghuawu): Replace this with CapabilityList::GetBestMatchedCapability.
@@ -36,13 +42,13 @@ void GetBestMatchSupportedResolution(int* width, int* height) {
int matched_height = *height;
int desired_res_area = *width * *height;
for (size_t i = 0; i < arraysize(kWellSupportedResolutions); ++i) {
- int area = kWellSupportedResolutions[i].width *
- kWellSupportedResolutions[i].height;
+ int area = kWellSupportedResolutions[i]->width *
+ kWellSupportedResolutions[i]->height;
int diff = std::abs(desired_res_area - area);
if (diff < min_diff) {
min_diff = diff;
- matched_width = kWellSupportedResolutions[i].width;
- matched_height = kWellSupportedResolutions[i].height;
+ matched_width = kWellSupportedResolutions[i]->width;
+ matched_height = kWellSupportedResolutions[i]->height;
}
}
*width = matched_width;
@@ -94,17 +100,23 @@ VideoCaptureDevice* VideoCaptureDevice::Create(const Name& device_name) {
VideoCaptureDeviceMac::VideoCaptureDeviceMac(const Name& device_name)
: device_name_(device_name),
observer_(NULL),
+ sent_frame_info_(false),
+ loop_proxy_(base::MessageLoopProxy::current()),
state_(kNotInitialized),
+ weak_factory_(this),
+ weak_this_(weak_factory_.GetWeakPtr()),
capture_device_(nil) {
}
VideoCaptureDeviceMac::~VideoCaptureDeviceMac() {
+ DCHECK_EQ(loop_proxy_, base::MessageLoopProxy::current());
[capture_device_ release];
}
void VideoCaptureDeviceMac::Allocate(
const VideoCaptureCapability& capture_format,
EventHandler* observer) {
+ DCHECK_EQ(loop_proxy_, base::MessageLoopProxy::current());
if (state_ != kIdle) {
return;
}
@@ -133,41 +145,57 @@ void VideoCaptureDeviceMac::Allocate(
else if (frame_rate > kMaxFrameRate)
frame_rate = kMaxFrameRate;
- if (![capture_device_ setCaptureHeight:height
- width:width
- frameRate:frame_rate]) {
- SetErrorState("Could not configure capture device.");
+ current_settings_.color = PIXEL_FORMAT_UYVY;
+ current_settings_.width = width;
+ current_settings_.height = height;
+ current_settings_.frame_rate = frame_rate;
+ current_settings_.expected_capture_delay = 0;
+ current_settings_.interlaced = false;
+
+ if (width != kHD.width || height != kHD.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.
+ if (!UpdateCaptureResolution())
+ return;
+
+ sent_frame_info_ = true;
+ observer_->OnFrameInfo(current_settings_);
+ }
+
+ // If the resolution is HD, start capturing without setting a resolution.
+ // QTKit will produce frames at the native resolution, allowing us to
+ // identify cameras whose native resolution is too low for HD. This
+ // additional information comes at a cost in startup latency, because the
+ // webcam will need to be reopened if its default resolution is not HD or VGA.
+
+ if (![capture_device_ startCapture]) {
+ SetErrorState("Could not start capture device.");
return;
}
state_ = kAllocated;
- VideoCaptureCapability current_settings;
- current_settings.color = VideoCaptureCapability::kARGB;
- current_settings.width = width;
- current_settings.height = height;
- current_settings.frame_rate = frame_rate;
- current_settings.expected_capture_delay = 0;
- current_settings.interlaced = false;
-
- observer_->OnFrameInfo(current_settings);
}
void VideoCaptureDeviceMac::Start() {
+ DCHECK_EQ(loop_proxy_, base::MessageLoopProxy::current());
DCHECK_EQ(state_, kAllocated);
- if (![capture_device_ startCapture]) {
- SetErrorState("Could not start capture device.");
- return;
- }
state_ = kCapturing;
+
+ // This method no longer has any effect. Capturing is triggered by
+ // the call to Allocate.
+ // TODO(bemasc, ncarter): Remove this method.
}
void VideoCaptureDeviceMac::Stop() {
- DCHECK_EQ(state_, kCapturing);
+ DCHECK_EQ(loop_proxy_, base::MessageLoopProxy::current());
+ DCHECK(state_ == kCapturing || state_ == kError) << state_;
[capture_device_ stopCapture];
state_ = kAllocated;
}
void VideoCaptureDeviceMac::DeAllocate() {
+ DCHECK_EQ(loop_proxy_, base::MessageLoopProxy::current());
if (state_ != kAllocated && state_ != kCapturing) {
return;
}
@@ -185,6 +213,7 @@ const VideoCaptureDevice::Name& VideoCaptureDeviceMac::device_name() {
}
bool VideoCaptureDeviceMac::Init() {
+ DCHECK_EQ(loop_proxy_, base::MessageLoopProxy::current());
DCHECK_EQ(state_, kNotInitialized);
Names device_names;
@@ -205,15 +234,77 @@ bool VideoCaptureDeviceMac::Init() {
void VideoCaptureDeviceMac::ReceiveFrame(
const uint8* video_frame,
int video_frame_length,
- const VideoCaptureCapability& frame_info) {
+ const VideoCaptureCapability& frame_info,
+ int aspect_numerator,
+ int aspect_denominator) {
+ // This method is safe to call from a device capture thread,
+ // 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) {
+ // 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;
+ }
+ if (frame_info.width == kHD.width && frame_info.height == kHD.height &&
+ aspect_numerator != aspect_denominator) {
+ DVLOG(1) << "Switching to VGA because HD has nonsquare pixel " <<
+ "aspect ratio " << aspect_numerator << ":" << aspect_denominator;
+ changeToVga = true;
+ }
+
+ if (changeToVga) {
+ current_settings_.width = kVGA.width;
+ current_settings_.height = kVGA.height;
+ }
+ }
+
+ if (current_settings_.width == frame_info.width &&
+ current_settings_.height == frame_info.height) {
+ sent_frame_info_ = true;
+ observer_->OnFrameInfo(current_settings_);
+ } else {
+ UpdateCaptureResolution();
+ // The current frame does not have the right width and height, so it
+ // must not be passed to |observer_|.
+ return;
+ }
+ }
+
+ DCHECK(current_settings_.width == frame_info.width &&
+ current_settings_.height == frame_info.height);
+
observer_->OnIncomingCapturedFrame(
video_frame, video_frame_length, base::Time::Now(), 0, false, false);
}
+void VideoCaptureDeviceMac::ReceiveError(const std::string& reason) {
+ loop_proxy_->PostTask(FROM_HERE,
+ base::Bind(&VideoCaptureDeviceMac::SetErrorState, weak_this_,
+ reason));
+}
+
void VideoCaptureDeviceMac::SetErrorState(const std::string& reason) {
+ DCHECK_EQ(loop_proxy_, base::MessageLoopProxy::current());
DLOG(ERROR) << reason;
state_ = kError;
observer_->OnError();
}
+bool VideoCaptureDeviceMac::UpdateCaptureResolution() {
+ if (![capture_device_ setCaptureHeight:current_settings_.height
+ width:current_settings_.width
+ frameRate:current_settings_.frame_rate]) {
+ ReceiveError("Could not configure capture device.");
+ return false;
+ }
+ return true;
+}
+
} // namespace media