| OLD | NEW |
| 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/mac/video_capture_device_mac.h" | 5 #include "media/video/capture/mac/video_capture_device_mac.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/location.h" | 8 #include "base/location.h" |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/time/time.h" | 10 #include "base/time/time.h" |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 127 weak_this_(weak_factory_.GetWeakPtr()), | 127 weak_this_(weak_factory_.GetWeakPtr()), |
| 128 capture_device_(nil) { | 128 capture_device_(nil) { |
| 129 } | 129 } |
| 130 | 130 |
| 131 VideoCaptureDeviceMac::~VideoCaptureDeviceMac() { | 131 VideoCaptureDeviceMac::~VideoCaptureDeviceMac() { |
| 132 DCHECK_EQ(loop_proxy_, base::MessageLoopProxy::current()); | 132 DCHECK_EQ(loop_proxy_, base::MessageLoopProxy::current()); |
| 133 [capture_device_ release]; | 133 [capture_device_ release]; |
| 134 } | 134 } |
| 135 | 135 |
| 136 void VideoCaptureDeviceMac::AllocateAndStart( | 136 void VideoCaptureDeviceMac::AllocateAndStart( |
| 137 const VideoCaptureCapability& capture_format, | 137 const VideoCaptureParams& params, |
| 138 scoped_ptr<VideoCaptureDevice::Client> client) { | 138 scoped_ptr<VideoCaptureDevice::Client> client) { |
| 139 DCHECK_EQ(loop_proxy_, base::MessageLoopProxy::current()); | 139 DCHECK_EQ(loop_proxy_, base::MessageLoopProxy::current()); |
| 140 if (state_ != kIdle) { | 140 if (state_ != kIdle) { |
| 141 return; | 141 return; |
| 142 } | 142 } |
| 143 int width = capture_format.width; | 143 int width = params.requested_format.frame_size.width(); |
| 144 int height = capture_format.height; | 144 int height = params.requested_format.frame_size.height(); |
| 145 int frame_rate = capture_format.frame_rate; | 145 int frame_rate = params.requested_format.frame_rate; |
| 146 | 146 |
| 147 // The OS API can scale captured frame to any size requested, which would lead | 147 // The OS API can scale captured frame to any size requested, which would lead |
| 148 // to undesired aspect ratio change. Try to open the camera with a natively | 148 // to undesired aspect ratio change. Try to open the camera with a natively |
| 149 // supported format and let the client crop/pad the captured frames. | 149 // supported format and let the client crop/pad the captured frames. |
| 150 GetBestMatchSupportedResolution(&width, &height); | 150 GetBestMatchSupportedResolution(&width, &height); |
| 151 | 151 |
| 152 client_ = client.Pass(); | 152 client_ = client.Pass(); |
| 153 NSString* deviceId = | 153 NSString* deviceId = |
| 154 [NSString stringWithUTF8String:device_name_.id().c_str()]; | 154 [NSString stringWithUTF8String:device_name_.id().c_str()]; |
| 155 | 155 |
| 156 [capture_device_ setFrameReceiver:this]; | 156 [capture_device_ setFrameReceiver:this]; |
| 157 | 157 |
| 158 if (![capture_device_ setCaptureDevice:deviceId]) { | 158 if (![capture_device_ setCaptureDevice:deviceId]) { |
| 159 SetErrorState("Could not open capture device."); | 159 SetErrorState("Could not open capture device."); |
| 160 return; | 160 return; |
| 161 } | 161 } |
| 162 if (frame_rate < kMinFrameRate) | 162 if (frame_rate < kMinFrameRate) |
| 163 frame_rate = kMinFrameRate; | 163 frame_rate = kMinFrameRate; |
| 164 else if (frame_rate > kMaxFrameRate) | 164 else if (frame_rate > kMaxFrameRate) |
| 165 frame_rate = kMaxFrameRate; | 165 frame_rate = kMaxFrameRate; |
| 166 | 166 |
| 167 current_settings_.color = PIXEL_FORMAT_UYVY; | 167 capture_format_.frame_size.SetSize(width, height); |
| 168 current_settings_.width = width; | 168 capture_format_.frame_rate = frame_rate; |
| 169 current_settings_.height = height; | 169 capture_format_.pixel_format = PIXEL_FORMAT_UYVY; |
| 170 current_settings_.frame_rate = frame_rate; | |
| 171 | 170 |
| 172 if (width <= kVGA.width || height <= kVGA.height) { | 171 if (width <= kVGA.width || height <= kVGA.height) { |
| 173 // If the resolution is VGA or QVGA, set the capture resolution to the | 172 // If the resolution is VGA or QVGA, set the capture resolution to the |
| 174 // target size. Essentially all supported cameras offer at least VGA. | 173 // target size. Essentially all supported cameras offer at least VGA. |
| 175 if (!UpdateCaptureResolution()) | 174 if (!UpdateCaptureResolution()) |
| 176 return; | 175 return; |
| 177 } | 176 } |
| 178 // For higher resolutions, we first open at the default resolution to find | 177 // For higher resolutions, we first open at the default resolution to find |
| 179 // out if the request is larger than the camera's native resolution. | 178 // out if the request is larger than the camera's native resolution. |
| 180 | 179 |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 219 if (!capture_device_) | 218 if (!capture_device_) |
| 220 return false; | 219 return false; |
| 221 | 220 |
| 222 state_ = kIdle; | 221 state_ = kIdle; |
| 223 return true; | 222 return true; |
| 224 } | 223 } |
| 225 | 224 |
| 226 void VideoCaptureDeviceMac::ReceiveFrame( | 225 void VideoCaptureDeviceMac::ReceiveFrame( |
| 227 const uint8* video_frame, | 226 const uint8* video_frame, |
| 228 int video_frame_length, | 227 int video_frame_length, |
| 229 const VideoCaptureCapability& frame_info, | 228 const VideoCaptureFormat& frame_format, |
| 230 int aspect_numerator, | 229 int aspect_numerator, |
| 231 int aspect_denominator) { | 230 int aspect_denominator) { |
| 232 // This method is safe to call from a device capture thread, | 231 // This method is safe to call from a device capture thread, |
| 233 // i.e. any thread controlled by QTKit. | 232 // i.e. any thread controlled by QTKit. |
| 234 | 233 |
| 235 if (!sent_frame_info_) { | 234 if (!sent_frame_info_) { |
| 236 // Final resolution has not yet been selected. | 235 // Final resolution has not yet been selected. |
| 237 if (current_settings_.width > kVGA.width || | 236 if (capture_format_.frame_size.width() > kVGA.width || |
| 238 current_settings_.height > kVGA.height) { | 237 capture_format_.frame_size.height() > kVGA.height) { |
| 239 // We are requesting HD. Make sure that the picture is good, otherwise | 238 // We are requesting HD. Make sure that the picture is good, otherwise |
| 240 // drop down to VGA. | 239 // drop down to VGA. |
| 241 bool change_to_vga = false; | 240 bool change_to_vga = false; |
| 242 if (frame_info.width < current_settings_.width || | 241 if (frame_format.frame_size.width() < |
| 243 frame_info.height < current_settings_.height) { | 242 capture_format_.frame_size.width() || |
| 243 frame_format.frame_size.height() < |
| 244 capture_format_.frame_size.height()) { |
| 244 // These are the default capture settings, not yet configured to match | 245 // These are the default capture settings, not yet configured to match |
| 245 // |current_settings_|. | 246 // |capture_format_|. |
| 246 DCHECK(frame_info.frame_rate == 0); | 247 DCHECK(frame_format.frame_rate == 0); |
| 247 DVLOG(1) << "Switching to VGA because the default resolution is " << | 248 DVLOG(1) << "Switching to VGA because the default resolution is " << |
| 248 frame_info.width << "x" << frame_info.height; | 249 frame_format.frame_size.ToString(); |
| 249 change_to_vga = true; | 250 change_to_vga = true; |
| 250 } | 251 } |
| 251 | 252 |
| 252 if (frame_info.width == current_settings_.width && | 253 if (capture_format_.frame_size == frame_format.frame_size && |
| 253 frame_info.height == current_settings_.height && | |
| 254 aspect_numerator != aspect_denominator) { | 254 aspect_numerator != aspect_denominator) { |
| 255 DVLOG(1) << "Switching to VGA because HD has nonsquare pixel " << | 255 DVLOG(1) << "Switching to VGA because HD has nonsquare pixel " << |
| 256 "aspect ratio " << aspect_numerator << ":" << aspect_denominator; | 256 "aspect ratio " << aspect_numerator << ":" << aspect_denominator; |
| 257 change_to_vga = true; | 257 change_to_vga = true; |
| 258 } | 258 } |
| 259 | 259 |
| 260 if (change_to_vga) { | 260 if (change_to_vga) { |
| 261 current_settings_.width = kVGA.width; | 261 capture_format_.frame_size.SetSize(kVGA.width, kVGA.height); |
| 262 current_settings_.height = kVGA.height; | |
| 263 } | 262 } |
| 264 } | 263 } |
| 265 | 264 |
| 266 if (current_settings_.width == frame_info.width && | 265 if (capture_format_.frame_size == frame_format.frame_size && |
| 267 current_settings_.height == frame_info.height && | |
| 268 !tried_to_square_pixels_ && | 266 !tried_to_square_pixels_ && |
| 269 (aspect_numerator > kMaxPixelAspectRatio * aspect_denominator || | 267 (aspect_numerator > kMaxPixelAspectRatio * aspect_denominator || |
| 270 aspect_denominator > kMaxPixelAspectRatio * aspect_numerator)) { | 268 aspect_denominator > kMaxPixelAspectRatio * aspect_numerator)) { |
| 271 // The requested size results in non-square PAR. | 269 // The requested size results in non-square PAR. |
| 272 // Shrink the frame to 1:1 PAR (assuming QTKit selects the same input | 270 // Shrink the frame to 1:1 PAR (assuming QTKit selects the same input |
| 273 // mode, which is not guaranteed). | 271 // mode, which is not guaranteed). |
| 274 int new_width = current_settings_.width; | 272 int new_width = capture_format_.frame_size.width(); |
| 275 int new_height = current_settings_.height; | 273 int new_height = capture_format_.frame_size.height(); |
| 276 if (aspect_numerator < aspect_denominator) { | 274 if (aspect_numerator < aspect_denominator) { |
| 277 new_width = (new_width * aspect_numerator) / aspect_denominator; | 275 new_width = (new_width * aspect_numerator) / aspect_denominator; |
| 278 } else { | 276 } else { |
| 279 new_height = (new_height * aspect_denominator) / aspect_numerator; | 277 new_height = (new_height * aspect_denominator) / aspect_numerator; |
| 280 } | 278 } |
| 281 current_settings_.width = new_width; | 279 capture_format_.frame_size.SetSize(new_width, new_height); |
| 282 current_settings_.height = new_height; | |
| 283 tried_to_square_pixels_ = true; | 280 tried_to_square_pixels_ = true; |
| 284 } | 281 } |
| 285 | 282 |
| 286 if (current_settings_.width == frame_info.width && | 283 if (capture_format_.frame_size == frame_format.frame_size) { |
| 287 current_settings_.height == frame_info.height) { | |
| 288 sent_frame_info_ = true; | 284 sent_frame_info_ = true; |
| 289 } else { | 285 } else { |
| 290 UpdateCaptureResolution(); | 286 UpdateCaptureResolution(); |
| 291 // OnFrameInfo has not yet been called. OnIncomingCapturedFrame must | 287 // OnFrameInfo has not yet been called. OnIncomingCapturedFrame must |
| 292 // not be called until after OnFrameInfo, so we return early. | 288 // not be called until after OnFrameInfo, so we return early. |
| 293 return; | 289 return; |
| 294 } | 290 } |
| 295 } | 291 } |
| 296 | 292 |
| 297 DCHECK(current_settings_.width == frame_info.width && | 293 DCHECK_EQ(capture_format_.frame_size.width(), |
| 298 current_settings_.height == frame_info.height); | 294 frame_format.frame_size.width()); |
| 295 DCHECK_EQ(capture_format_.frame_size.height(), |
| 296 frame_format.frame_size.height()); |
| 299 | 297 |
| 300 client_->OnIncomingCapturedFrame(video_frame, | 298 client_->OnIncomingCapturedFrame(video_frame, |
| 301 video_frame_length, | 299 video_frame_length, |
| 302 base::Time::Now(), | 300 base::Time::Now(), |
| 303 0, | 301 0, |
| 304 false, | 302 false, |
| 305 false, | 303 false, |
| 306 current_settings_); | 304 capture_format_); |
| 307 } | 305 } |
| 308 | 306 |
| 309 void VideoCaptureDeviceMac::ReceiveError(const std::string& reason) { | 307 void VideoCaptureDeviceMac::ReceiveError(const std::string& reason) { |
| 310 loop_proxy_->PostTask(FROM_HERE, | 308 loop_proxy_->PostTask(FROM_HERE, |
| 311 base::Bind(&VideoCaptureDeviceMac::SetErrorState, weak_this_, | 309 base::Bind(&VideoCaptureDeviceMac::SetErrorState, weak_this_, |
| 312 reason)); | 310 reason)); |
| 313 } | 311 } |
| 314 | 312 |
| 315 void VideoCaptureDeviceMac::SetErrorState(const std::string& reason) { | 313 void VideoCaptureDeviceMac::SetErrorState(const std::string& reason) { |
| 316 DCHECK_EQ(loop_proxy_, base::MessageLoopProxy::current()); | 314 DCHECK_EQ(loop_proxy_, base::MessageLoopProxy::current()); |
| 317 DLOG(ERROR) << reason; | 315 DLOG(ERROR) << reason; |
| 318 state_ = kError; | 316 state_ = kError; |
| 319 client_->OnError(); | 317 client_->OnError(); |
| 320 } | 318 } |
| 321 | 319 |
| 322 bool VideoCaptureDeviceMac::UpdateCaptureResolution() { | 320 bool VideoCaptureDeviceMac::UpdateCaptureResolution() { |
| 323 if (![capture_device_ setCaptureHeight:current_settings_.height | 321 if (![capture_device_ setCaptureHeight:capture_format_.frame_size.height() |
| 324 width:current_settings_.width | 322 width:capture_format_.frame_size.width() |
| 325 frameRate:current_settings_.frame_rate]) { | 323 frameRate:capture_format_.frame_rate]) { |
| 326 ReceiveError("Could not configure capture device."); | 324 ReceiveError("Could not configure capture device."); |
| 327 return false; | 325 return false; |
| 328 } | 326 } |
| 329 return true; | 327 return true; |
| 330 } | 328 } |
| 331 | 329 |
| 332 } // namespace media | 330 } // namespace media |
| OLD | NEW |