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 VideoCaptureParams& params, | 137 const VideoCaptureCapability& capture_format, |
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 = params.requested_format.frame_size.width(); | 143 int width = capture_format.width; |
144 int height = params.requested_format.frame_size.height(); | 144 int height = capture_format.height; |
145 int frame_rate = params.requested_format.frame_rate; | 145 int frame_rate = capture_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 capture_format_.frame_size.SetSize(width, height); | 167 current_settings_.color = PIXEL_FORMAT_UYVY; |
168 capture_format_.frame_rate = frame_rate; | 168 current_settings_.width = width; |
169 capture_format_.pixel_format = PIXEL_FORMAT_UYVY; | 169 current_settings_.height = height; |
| 170 current_settings_.frame_rate = frame_rate; |
170 | 171 |
171 if (width <= kVGA.width || height <= kVGA.height) { | 172 if (width <= kVGA.width || height <= kVGA.height) { |
172 // If the resolution is VGA or QVGA, set the capture resolution to the | 173 // If the resolution is VGA or QVGA, set the capture resolution to the |
173 // target size. Essentially all supported cameras offer at least VGA. | 174 // target size. Essentially all supported cameras offer at least VGA. |
174 if (!UpdateCaptureResolution()) | 175 if (!UpdateCaptureResolution()) |
175 return; | 176 return; |
176 } | 177 } |
177 // For higher resolutions, we first open at the default resolution to find | 178 // For higher resolutions, we first open at the default resolution to find |
178 // out if the request is larger than the camera's native resolution. | 179 // out if the request is larger than the camera's native resolution. |
179 | 180 |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
218 if (!capture_device_) | 219 if (!capture_device_) |
219 return false; | 220 return false; |
220 | 221 |
221 state_ = kIdle; | 222 state_ = kIdle; |
222 return true; | 223 return true; |
223 } | 224 } |
224 | 225 |
225 void VideoCaptureDeviceMac::ReceiveFrame( | 226 void VideoCaptureDeviceMac::ReceiveFrame( |
226 const uint8* video_frame, | 227 const uint8* video_frame, |
227 int video_frame_length, | 228 int video_frame_length, |
228 const VideoCaptureFormat& frame_format, | 229 const VideoCaptureCapability& frame_info, |
229 int aspect_numerator, | 230 int aspect_numerator, |
230 int aspect_denominator) { | 231 int aspect_denominator) { |
231 // This method is safe to call from a device capture thread, | 232 // This method is safe to call from a device capture thread, |
232 // i.e. any thread controlled by QTKit. | 233 // i.e. any thread controlled by QTKit. |
233 | 234 |
234 if (!sent_frame_info_) { | 235 if (!sent_frame_info_) { |
235 // Final resolution has not yet been selected. | 236 // Final resolution has not yet been selected. |
236 if (capture_format_.frame_size.width() > kVGA.width || | 237 if (current_settings_.width > kVGA.width || |
237 capture_format_.frame_size.height() > kVGA.height) { | 238 current_settings_.height > kVGA.height) { |
238 // We are requesting HD. Make sure that the picture is good, otherwise | 239 // We are requesting HD. Make sure that the picture is good, otherwise |
239 // drop down to VGA. | 240 // drop down to VGA. |
240 bool change_to_vga = false; | 241 bool change_to_vga = false; |
241 if (frame_format.frame_size.width() < | 242 if (frame_info.width < current_settings_.width || |
242 capture_format_.frame_size.width() || | 243 frame_info.height < current_settings_.height) { |
243 frame_format.frame_size.height() < | |
244 capture_format_.frame_size.height()) { | |
245 // These are the default capture settings, not yet configured to match | 244 // These are the default capture settings, not yet configured to match |
246 // |capture_format_|. | 245 // |current_settings_|. |
247 DCHECK(frame_format.frame_rate == 0); | 246 DCHECK(frame_info.frame_rate == 0); |
248 DVLOG(1) << "Switching to VGA because the default resolution is " << | 247 DVLOG(1) << "Switching to VGA because the default resolution is " << |
249 frame_format.frame_size.ToString(); | 248 frame_info.width << "x" << frame_info.height; |
250 change_to_vga = true; | 249 change_to_vga = true; |
251 } | 250 } |
252 | 251 |
253 if (capture_format_.frame_size == frame_format.frame_size && | 252 if (frame_info.width == current_settings_.width && |
| 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 capture_format_.frame_size.SetSize(kVGA.width, kVGA.height); | 261 current_settings_.width = kVGA.width; |
| 262 current_settings_.height = kVGA.height; |
262 } | 263 } |
263 } | 264 } |
264 | 265 |
265 if (capture_format_.frame_size == frame_format.frame_size && | 266 if (current_settings_.width == frame_info.width && |
| 267 current_settings_.height == frame_info.height && |
266 !tried_to_square_pixels_ && | 268 !tried_to_square_pixels_ && |
267 (aspect_numerator > kMaxPixelAspectRatio * aspect_denominator || | 269 (aspect_numerator > kMaxPixelAspectRatio * aspect_denominator || |
268 aspect_denominator > kMaxPixelAspectRatio * aspect_numerator)) { | 270 aspect_denominator > kMaxPixelAspectRatio * aspect_numerator)) { |
269 // The requested size results in non-square PAR. | 271 // The requested size results in non-square PAR. |
270 // Shrink the frame to 1:1 PAR (assuming QTKit selects the same input | 272 // Shrink the frame to 1:1 PAR (assuming QTKit selects the same input |
271 // mode, which is not guaranteed). | 273 // mode, which is not guaranteed). |
272 int new_width = capture_format_.frame_size.width(); | 274 int new_width = current_settings_.width; |
273 int new_height = capture_format_.frame_size.height(); | 275 int new_height = current_settings_.height; |
274 if (aspect_numerator < aspect_denominator) { | 276 if (aspect_numerator < aspect_denominator) { |
275 new_width = (new_width * aspect_numerator) / aspect_denominator; | 277 new_width = (new_width * aspect_numerator) / aspect_denominator; |
276 } else { | 278 } else { |
277 new_height = (new_height * aspect_denominator) / aspect_numerator; | 279 new_height = (new_height * aspect_denominator) / aspect_numerator; |
278 } | 280 } |
279 capture_format_.frame_size.SetSize(new_width, new_height); | 281 current_settings_.width = new_width; |
| 282 current_settings_.height = new_height; |
280 tried_to_square_pixels_ = true; | 283 tried_to_square_pixels_ = true; |
281 } | 284 } |
282 | 285 |
283 if (capture_format_.frame_size == frame_format.frame_size) { | 286 if (current_settings_.width == frame_info.width && |
| 287 current_settings_.height == frame_info.height) { |
284 sent_frame_info_ = true; | 288 sent_frame_info_ = true; |
285 } else { | 289 } else { |
286 UpdateCaptureResolution(); | 290 UpdateCaptureResolution(); |
287 // OnFrameInfo has not yet been called. OnIncomingCapturedFrame must | 291 // OnFrameInfo has not yet been called. OnIncomingCapturedFrame must |
288 // not be called until after OnFrameInfo, so we return early. | 292 // not be called until after OnFrameInfo, so we return early. |
289 return; | 293 return; |
290 } | 294 } |
291 } | 295 } |
292 | 296 |
293 DCHECK_EQ(capture_format_.frame_size.width(), | 297 DCHECK(current_settings_.width == frame_info.width && |
294 frame_format.frame_size.width()); | 298 current_settings_.height == frame_info.height); |
295 DCHECK_EQ(capture_format_.frame_size.height(), | |
296 frame_format.frame_size.height()); | |
297 | 299 |
298 client_->OnIncomingCapturedFrame(video_frame, | 300 client_->OnIncomingCapturedFrame(video_frame, |
299 video_frame_length, | 301 video_frame_length, |
300 base::Time::Now(), | 302 base::Time::Now(), |
301 0, | 303 0, |
302 false, | 304 false, |
303 false, | 305 false, |
304 capture_format_); | 306 current_settings_); |
305 } | 307 } |
306 | 308 |
307 void VideoCaptureDeviceMac::ReceiveError(const std::string& reason) { | 309 void VideoCaptureDeviceMac::ReceiveError(const std::string& reason) { |
308 loop_proxy_->PostTask(FROM_HERE, | 310 loop_proxy_->PostTask(FROM_HERE, |
309 base::Bind(&VideoCaptureDeviceMac::SetErrorState, weak_this_, | 311 base::Bind(&VideoCaptureDeviceMac::SetErrorState, weak_this_, |
310 reason)); | 312 reason)); |
311 } | 313 } |
312 | 314 |
313 void VideoCaptureDeviceMac::SetErrorState(const std::string& reason) { | 315 void VideoCaptureDeviceMac::SetErrorState(const std::string& reason) { |
314 DCHECK_EQ(loop_proxy_, base::MessageLoopProxy::current()); | 316 DCHECK_EQ(loop_proxy_, base::MessageLoopProxy::current()); |
315 DLOG(ERROR) << reason; | 317 DLOG(ERROR) << reason; |
316 state_ = kError; | 318 state_ = kError; |
317 client_->OnError(); | 319 client_->OnError(); |
318 } | 320 } |
319 | 321 |
320 bool VideoCaptureDeviceMac::UpdateCaptureResolution() { | 322 bool VideoCaptureDeviceMac::UpdateCaptureResolution() { |
321 if (![capture_device_ setCaptureHeight:capture_format_.frame_size.height() | 323 if (![capture_device_ setCaptureHeight:current_settings_.height |
322 width:capture_format_.frame_size.width() | 324 width:current_settings_.width |
323 frameRate:capture_format_.frame_rate]) { | 325 frameRate:current_settings_.frame_rate]) { |
324 ReceiveError("Could not configure capture device."); | 326 ReceiveError("Could not configure capture device."); |
325 return false; | 327 return false; |
326 } | 328 } |
327 return true; | 329 return true; |
328 } | 330 } |
329 | 331 |
330 } // namespace media | 332 } // namespace media |
OLD | NEW |