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 |