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 |