Chromium Code Reviews| OLD | NEW | 
|---|---|
| 1 /* | 1 /* | 
| 2 * Copyright (c) 2010 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2010 The WebRTC project authors. All Rights Reserved. | 
| 3 * | 3 * | 
| 4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license | 
| 5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source | 
| 6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found | 
| 7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may | 
| 8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. | 
| 9 */ | 9 */ | 
| 10 | 10 | 
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 59 | 59 | 
| 60 ///////////////////////////////////////////////////////////////////// | 60 ///////////////////////////////////////////////////////////////////// | 
| 61 // Implementation of class VideoCapturer | 61 // Implementation of class VideoCapturer | 
| 62 ///////////////////////////////////////////////////////////////////// | 62 ///////////////////////////////////////////////////////////////////// | 
| 63 VideoCapturer::VideoCapturer() : apply_rotation_(false) { | 63 VideoCapturer::VideoCapturer() : apply_rotation_(false) { | 
| 64 thread_checker_.DetachFromThread(); | 64 thread_checker_.DetachFromThread(); | 
| 65 Construct(); | 65 Construct(); | 
| 66 } | 66 } | 
| 67 | 67 | 
| 68 void VideoCapturer::Construct() { | 68 void VideoCapturer::Construct() { | 
| 69 ratio_w_ = 0; | |
| 70 ratio_h_ = 0; | |
| 71 enable_camera_list_ = false; | 69 enable_camera_list_ = false; | 
| 72 square_pixel_aspect_ratio_ = false; | |
| 73 capture_state_ = CS_STOPPED; | 70 capture_state_ = CS_STOPPED; | 
| 74 SignalFrameCaptured.connect(this, &VideoCapturer::OnFrameCaptured); | 71 SignalFrameCaptured.connect(this, &VideoCapturer::OnFrameCaptured); | 
| 75 scaled_width_ = 0; | 72 scaled_width_ = 0; | 
| 76 scaled_height_ = 0; | 73 scaled_height_ = 0; | 
| 77 enable_video_adapter_ = true; | 74 enable_video_adapter_ = true; | 
| 78 // There are lots of video capturers out there that don't call | 75 // There are lots of video capturers out there that don't call | 
| 79 // set_frame_factory. We can either go change all of them, or we | 76 // set_frame_factory. We can either go change all of them, or we | 
| 80 // can set this default. | 77 // can set this default. | 
| 81 // TODO(pthatcher): Remove this hack and require the frame factory | 78 // TODO(pthatcher): Remove this hack and require the frame factory | 
| 82 // to be passed in the constructor. | 79 // to be passed in the constructor. | 
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 219 } | 216 } | 
| 220 | 217 | 
| 221 void VideoCapturer::OnFrameCaptured(VideoCapturer*, | 218 void VideoCapturer::OnFrameCaptured(VideoCapturer*, | 
| 222 const CapturedFrame* captured_frame) { | 219 const CapturedFrame* captured_frame) { | 
| 223 if (!broadcaster_.frame_wanted()) { | 220 if (!broadcaster_.frame_wanted()) { | 
| 224 return; | 221 return; | 
| 225 } | 222 } | 
| 226 | 223 | 
| 227 // Use a temporary buffer to scale | 224 // Use a temporary buffer to scale | 
| 228 std::unique_ptr<uint8_t[]> scale_buffer; | 225 std::unique_ptr<uint8_t[]> scale_buffer; | 
| 229 if (IsScreencast()) { | 226 if (IsScreencast()) { | 
| 
 
pbos-webrtc
2016/04/29 15:48:32
Are we scaling screencast? This sounds weird/wrong
 
perkj_webrtc
2016/05/02 15:29:19
No, we don't get ARGB but there has been talks abo
 
pbos-webrtc
2016/05/02 16:14:40
I think removing is right, the behavior doesn't so
 
nisse-webrtc
2016/05/04 10:04:33
Done.
 
 | |
| 230 int scaled_width, scaled_height; | 227 int scaled_width, scaled_height; | 
| 231 int desired_screencast_fps = | 228 int desired_screencast_fps = | 
| 232 capture_format_.get() | 229 capture_format_.get() | 
| 233 ? VideoFormat::IntervalToFps(capture_format_->interval) | 230 ? VideoFormat::IntervalToFps(capture_format_->interval) | 
| 234 : kDefaultScreencastFps; | 231 : kDefaultScreencastFps; | 
| 235 ComputeScale(captured_frame->width, captured_frame->height, | 232 ComputeScale(captured_frame->width, captured_frame->height, | 
| 236 desired_screencast_fps, &scaled_width, &scaled_height); | 233 desired_screencast_fps, &scaled_width, &scaled_height); | 
| 237 | 234 | 
| 238 if (FOURCC_ARGB == captured_frame->fourcc && | 235 if (FOURCC_ARGB == captured_frame->fourcc && | 
| 239 (scaled_width != captured_frame->width || | 236 (scaled_width != captured_frame->width || | 
| (...skipping 19 matching lines...) Expand all Loading... | |
| 259 captured_frame->height, scale_buffer.get(), | 256 captured_frame->height, scale_buffer.get(), | 
| 260 scaled_width * 4, scaled_width, scaled_height, | 257 scaled_width * 4, scaled_width, scaled_height, | 
| 261 libyuv::kFilterBilinear); | 258 libyuv::kFilterBilinear); | 
| 262 modified_frame->width = scaled_width; | 259 modified_frame->width = scaled_width; | 
| 263 modified_frame->height = scaled_height; | 260 modified_frame->height = scaled_height; | 
| 264 modified_frame->data_size = scaled_width * 4 * scaled_height; | 261 modified_frame->data_size = scaled_width * 4 * scaled_height; | 
| 265 modified_frame->data = scale_buffer.get(); | 262 modified_frame->data = scale_buffer.get(); | 
| 266 } | 263 } | 
| 267 } | 264 } | 
| 268 | 265 | 
| 269 const int kYuy2Bpp = 2; | 266 int adapted_width = captured_frame->width; | 
| 
 
pbos-webrtc
2016/04/29 15:48:32
Can you put a good comment here? This looks like i
 
nisse-webrtc
2016/05/03 07:08:25
Is "output_width" or "target_width" better? The va
 
nisse-webrtc
2016/05/04 10:04:33
I'm inclined to leave this as is. Naming is consis
 
 | |
| 270 const int kArgbBpp = 4; | 267 int adapted_height = captured_frame->height; | 
| 271 // TODO(fbarchard): Make a helper function to adjust pixels to square. | |
| 272 // TODO(fbarchard): Hook up experiment to scaling. | |
| 273 // Temporary buffer is scoped here so it will persist until i420_frame.Init() | |
| 274 // makes a copy of the frame, converting to I420. | |
| 275 std::unique_ptr<uint8_t[]> temp_buffer; | |
| 276 // YUY2 can be scaled vertically using an ARGB scaler. Aspect ratio is only | |
| 277 // a problem on OSX. OSX always converts webcams to YUY2 or UYVY. | |
| 278 bool can_scale = | |
| 279 FOURCC_YUY2 == CanonicalFourCC(captured_frame->fourcc) || | |
| 280 FOURCC_UYVY == CanonicalFourCC(captured_frame->fourcc); | |
| 281 | |
| 282 // If pixels are not square, optionally use vertical scaling to make them | |
| 283 // square. Square pixels simplify the rest of the pipeline, including | |
| 284 // effects and rendering. | |
| 285 if (can_scale && square_pixel_aspect_ratio_ && | |
| 286 captured_frame->pixel_width != captured_frame->pixel_height) { | |
| 287 int scaled_width, scaled_height; | |
| 288 // modified_frame points to the captured_frame but with const casted away | |
| 289 // so it can be modified. | |
| 290 CapturedFrame* modified_frame = const_cast<CapturedFrame*>(captured_frame); | |
| 291 // Compute the frame size that makes pixels square pixel aspect ratio. | |
| 292 ComputeScaleToSquarePixels(captured_frame->width, captured_frame->height, | |
| 293 captured_frame->pixel_width, | |
| 294 captured_frame->pixel_height, | |
| 295 &scaled_width, &scaled_height); | |
| 296 | |
| 297 if (scaled_width != scaled_width_ || scaled_height != scaled_height_) { | |
| 298 LOG(LS_INFO) << "Scaling WebCam from " | |
| 299 << captured_frame->width << "x" | |
| 300 << captured_frame->height << " to " | |
| 301 << scaled_width << "x" << scaled_height | |
| 302 << " for PAR " | |
| 303 << captured_frame->pixel_width << "x" | |
| 304 << captured_frame->pixel_height; | |
| 305 scaled_width_ = scaled_width; | |
| 306 scaled_height_ = scaled_height; | |
| 307 } | |
| 308 const int modified_frame_size = scaled_width * scaled_height * kYuy2Bpp; | |
| 309 uint8_t* temp_buffer_data; | |
| 310 // Pixels are wide and short; Increasing height. Requires temporary buffer. | |
| 311 if (scaled_height > captured_frame->height) { | |
| 312 temp_buffer.reset(new uint8_t[modified_frame_size]); | |
| 313 temp_buffer_data = temp_buffer.get(); | |
| 314 } else { | |
| 315 // Pixels are narrow and tall; Decreasing height. Scale will be done | |
| 316 // in place. | |
| 317 temp_buffer_data = reinterpret_cast<uint8_t*>(captured_frame->data); | |
| 318 } | |
| 319 | |
| 320 // Use ARGBScaler to vertically scale the YUY2 image, adjusting for 16 bpp. | |
| 321 libyuv::ARGBScale(reinterpret_cast<const uint8_t*>(captured_frame->data), | |
| 322 captured_frame->width * kYuy2Bpp, // Stride for YUY2. | |
| 323 captured_frame->width * kYuy2Bpp / kArgbBpp, // Width. | |
| 324 abs(captured_frame->height), // Height. | |
| 325 temp_buffer_data, | |
| 326 scaled_width * kYuy2Bpp, // Stride for YUY2. | |
| 327 scaled_width * kYuy2Bpp / kArgbBpp, // Width. | |
| 328 abs(scaled_height), // New height. | |
| 329 libyuv::kFilterBilinear); | |
| 330 modified_frame->width = scaled_width; | |
| 331 modified_frame->height = scaled_height; | |
| 332 modified_frame->pixel_width = 1; | |
| 333 modified_frame->pixel_height = 1; | |
| 334 modified_frame->data_size = modified_frame_size; | |
| 335 modified_frame->data = temp_buffer_data; | |
| 336 } | |
| 337 | |
| 338 // Size to crop captured frame to. This adjusts the captured frames | |
| 339 // aspect ratio to match the final view aspect ratio, considering pixel | |
| 340 // aspect ratio and rotation. The final size may be scaled down by video | |
| 341 // adapter to better match ratio_w_ x ratio_h_. | |
| 342 // Note that abs() of frame height is passed in, because source may be | |
| 343 // inverted, but output will be positive. | |
| 344 int cropped_width = captured_frame->width; | |
| 345 int cropped_height = captured_frame->height; | |
| 346 | |
| 347 // TODO(fbarchard): Improve logic to pad or crop. | |
| 348 // MJPG can crop vertically, but not horizontally. This logic disables crop. | |
| 349 // Alternatively we could pad the image with black, or implement a 2 step | |
| 350 // crop. | |
| 351 bool can_crop = true; | |
| 352 if (captured_frame->fourcc == FOURCC_MJPG) { | |
| 353 float cam_aspect = static_cast<float>(captured_frame->width) / | |
| 354 static_cast<float>(captured_frame->height); | |
| 355 float view_aspect = static_cast<float>(ratio_w_) / | |
| 356 static_cast<float>(ratio_h_); | |
| 357 can_crop = cam_aspect <= view_aspect; | |
| 358 } | |
| 359 if (can_crop && !IsScreencast()) { | |
| 360 // TODO(ronghuawu): The capturer should always produce the native | |
| 361 // resolution and the cropping should be done in downstream code. | |
| 362 ComputeCrop(ratio_w_, ratio_h_, captured_frame->width, | |
| 363 abs(captured_frame->height), captured_frame->pixel_width, | |
| 364 captured_frame->pixel_height, captured_frame->rotation, | |
| 365 &cropped_width, &cropped_height); | |
| 366 } | |
| 367 | |
| 368 int adapted_width = cropped_width; | |
| 369 int adapted_height = cropped_height; | |
| 370 if (enable_video_adapter_ && !IsScreencast()) { | 268 if (enable_video_adapter_ && !IsScreencast()) { | 
| 371 const VideoFormat adapted_format = | 269 const VideoFormat adapted_format = | 
| 372 video_adapter_.AdaptFrameResolution(cropped_width, cropped_height); | 270 video_adapter_.AdaptFrameResolution(adapted_width, adapted_height); | 
| 
 
perkj_webrtc
2016/05/02 15:29:19
captured_frame->width and  captured_frame->height
 
 | |
| 373 if (adapted_format.IsSize0x0()) { | 271 if (adapted_format.IsSize0x0()) { | 
| 374 // VideoAdapter dropped the frame. | 272 // VideoAdapter dropped the frame. | 
| 375 return; | 273 return; | 
| 376 } | 274 } | 
| 377 adapted_width = adapted_format.width; | 275 adapted_width = adapted_format.width; | 
| 378 adapted_height = adapted_format.height; | 276 adapted_height = adapted_format.height; | 
| 379 } | 277 } | 
| 380 | 278 | 
| 381 if (!frame_factory_) { | 279 if (!frame_factory_) { | 
| 382 LOG(LS_ERROR) << "No video frame factory."; | 280 LOG(LS_ERROR) << "No video frame factory."; | 
| 383 return; | 281 return; | 
| 384 } | 282 } | 
| 385 | 283 | 
| 386 std::unique_ptr<VideoFrame> adapted_frame( | 284 // TODO(nisse): Reorganize frame factory methods, deleting crop | 
| 387 frame_factory_->CreateAliasedFrame(captured_frame, | 285 // support there too. | 
| 388 cropped_width, cropped_height, | 286 std::unique_ptr<VideoFrame> adapted_frame(frame_factory_->CreateAliasedFrame( | 
| 389 adapted_width, adapted_height)); | 287 captured_frame, captured_frame->width, captured_frame->height, | 
| 288 adapted_width, adapted_height)); | |
| 390 | 289 | 
| 391 if (!adapted_frame) { | 290 if (!adapted_frame) { | 
| 392 // TODO(fbarchard): LOG more information about captured frame attributes. | 291 // TODO(fbarchard): LOG more information about captured frame attributes. | 
| 393 LOG(LS_ERROR) << "Couldn't convert to I420! " | 292 LOG(LS_ERROR) << "Couldn't convert to I420! " | 
| 394 << "From " << ToString(captured_frame) << " To " | 293 << "From " << ToString(captured_frame) << " To " | 
| 395 << cropped_width << " x " << cropped_height; | 294 << adapted_width << " x " << adapted_height; | 
| 396 return; | 295 return; | 
| 397 } | 296 } | 
| 398 | 297 | 
| 399 OnFrame(this, adapted_frame.get()); | 298 OnFrame(this, adapted_frame.get()); | 
| 400 UpdateInputSize(captured_frame); | 299 UpdateInputSize(captured_frame); | 
| 401 } | 300 } | 
| 402 | 301 | 
| 403 void VideoCapturer::OnFrame(VideoCapturer* capturer, const VideoFrame* frame) { | 302 void VideoCapturer::OnFrame(VideoCapturer* capturer, const VideoFrame* frame) { | 
| 404 broadcaster_.OnFrame(*frame); | 303 broadcaster_.OnFrame(*frame); | 
| 405 } | 304 } | 
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 545 void VideoCapturer::UpdateInputSize(const CapturedFrame* captured_frame) { | 444 void VideoCapturer::UpdateInputSize(const CapturedFrame* captured_frame) { | 
| 546 // Update stats protected from fetches from different thread. | 445 // Update stats protected from fetches from different thread. | 
| 547 rtc::CritScope cs(&frame_stats_crit_); | 446 rtc::CritScope cs(&frame_stats_crit_); | 
| 548 | 447 | 
| 549 input_size_valid_ = true; | 448 input_size_valid_ = true; | 
| 550 input_width_ = captured_frame->width; | 449 input_width_ = captured_frame->width; | 
| 551 input_height_ = captured_frame->height; | 450 input_height_ = captured_frame->height; | 
| 552 } | 451 } | 
| 553 | 452 | 
| 554 } // namespace cricket | 453 } // namespace cricket | 
| OLD | NEW |