diff options
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.mm | 145 |
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 |