OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2015 The WebRTC project authors. All Rights Reserved. | 2 * Copyright 2015 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 |
11 #include "avfoundationvideocapturer.h" | 11 #include "avfoundationvideocapturer.h" |
12 | 12 |
13 #import <AVFoundation/AVFoundation.h> | 13 #import <AVFoundation/AVFoundation.h> |
14 #import <Foundation/Foundation.h> | 14 #import <Foundation/Foundation.h> |
15 #if TARGET_OS_IPHONE | 15 #if TARGET_OS_IPHONE |
16 #import <UIKit/UIKit.h> | 16 #import <UIKit/UIKit.h> |
17 #endif | 17 #endif |
18 | 18 |
19 #import "RTCDispatcher+Private.h" | 19 #import "RTCDispatcher+Private.h" |
20 #import "WebRTC/RTCLogging.h" | 20 #import "WebRTC/RTCLogging.h" |
21 | 21 |
22 #include "webrtc/base/bind.h" | 22 #include "webrtc/base/bind.h" |
23 #include "webrtc/base/checks.h" | 23 #include "webrtc/base/checks.h" |
24 #include "webrtc/base/thread.h" | 24 #include "webrtc/base/thread.h" |
| 25 #include "webrtc/common_video/include/corevideo_frame_buffer.h" |
25 | 26 |
26 // TODO(tkchin): support other formats. | 27 // TODO(tkchin): support other formats. |
27 static NSString *const kDefaultPreset = AVCaptureSessionPreset640x480; | 28 static NSString *const kDefaultPreset = AVCaptureSessionPreset640x480; |
28 static cricket::VideoFormat const kDefaultFormat = | 29 static cricket::VideoFormat const kDefaultFormat = |
29 cricket::VideoFormat(640, | 30 cricket::VideoFormat(640, |
30 480, | 31 480, |
31 cricket::VideoFormat::FpsToInterval(30), | 32 cricket::VideoFormat::FpsToInterval(30), |
32 cricket::FOURCC_NV12); | 33 cricket::FOURCC_NV12); |
33 | 34 |
34 // This class used to capture frames using AVFoundation APIs on iOS. It is meant | 35 // This class used to capture frames using AVFoundation APIs on iOS. It is meant |
(...skipping 600 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
635 static_cast<rtc::TypedMessageData<AVFoundationFrame>*>(msg->pdata); | 636 static_cast<rtc::TypedMessageData<AVFoundationFrame>*>(msg->pdata); |
636 const AVFoundationFrame& frame = data->data(); | 637 const AVFoundationFrame& frame = data->data(); |
637 OnFrameMessage(frame.image_buffer, frame.capture_time); | 638 OnFrameMessage(frame.image_buffer, frame.capture_time); |
638 delete data; | 639 delete data; |
639 break; | 640 break; |
640 } | 641 } |
641 } | 642 } |
642 } | 643 } |
643 | 644 |
644 void AVFoundationVideoCapturer::OnFrameMessage(CVImageBufferRef image_buffer, | 645 void AVFoundationVideoCapturer::OnFrameMessage(CVImageBufferRef image_buffer, |
645 int64_t capture_time) { | 646 int64_t capture_time_ns) { |
646 RTC_DCHECK(_startThread->IsCurrent()); | 647 RTC_DCHECK(_startThread->IsCurrent()); |
647 | 648 |
648 // Base address must be unlocked to access frame data. | 649 rtc::scoped_refptr<webrtc::VideoFrameBuffer> buffer = |
649 CVOptionFlags lock_flags = kCVPixelBufferLock_ReadOnly; | 650 new rtc::RefCountedObject<webrtc::CoreVideoFrameBuffer>(image_buffer); |
650 CVReturn ret = CVPixelBufferLockBaseAddress(image_buffer, lock_flags); | 651 |
651 if (ret != kCVReturnSuccess) { | 652 const int captured_width = buffer->width(); |
| 653 const int captured_height = buffer->height(); |
| 654 |
| 655 int adapted_width; |
| 656 int adapted_height; |
| 657 int crop_width; |
| 658 int crop_height; |
| 659 int crop_x; |
| 660 int crop_y; |
| 661 int64_t translated_camera_time_us; |
| 662 |
| 663 if (!AdaptFrame(captured_width, captured_height, |
| 664 capture_time_ns / rtc::kNumNanosecsPerMicrosec, |
| 665 rtc::TimeMicros(), &adapted_width, &adapted_height, |
| 666 &crop_width, &crop_height, &crop_x, &crop_y, |
| 667 &translated_camera_time_us)) { |
| 668 CVBufferRelease(image_buffer); |
652 return; | 669 return; |
653 } | 670 } |
654 | 671 |
655 static size_t const kYPlaneIndex = 0; | 672 if (adapted_width != captured_width || crop_width != captured_width || |
656 static size_t const kUVPlaneIndex = 1; | 673 adapted_height != captured_height || crop_height != captured_height) { |
657 uint8_t* y_plane_address = | 674 // TODO(magjed): Avoid converting to I420. |
658 static_cast<uint8_t*>(CVPixelBufferGetBaseAddressOfPlane(image_buffer, | 675 rtc::scoped_refptr<webrtc::I420Buffer> scaled_buffer( |
659 kYPlaneIndex)); | 676 _buffer_pool.CreateBuffer(adapted_width, adapted_height)); |
660 size_t y_plane_height = | 677 scaled_buffer->CropAndScaleFrom(buffer->NativeToI420Buffer(), crop_x, |
661 CVPixelBufferGetHeightOfPlane(image_buffer, kYPlaneIndex); | 678 crop_y, crop_width, crop_height); |
662 size_t y_plane_width = | 679 buffer = scaled_buffer; |
663 CVPixelBufferGetWidthOfPlane(image_buffer, kYPlaneIndex); | 680 } |
664 size_t y_plane_bytes_per_row = | |
665 CVPixelBufferGetBytesPerRowOfPlane(image_buffer, kYPlaneIndex); | |
666 size_t uv_plane_height = | |
667 CVPixelBufferGetHeightOfPlane(image_buffer, kUVPlaneIndex); | |
668 size_t uv_plane_bytes_per_row = | |
669 CVPixelBufferGetBytesPerRowOfPlane(image_buffer, kUVPlaneIndex); | |
670 size_t frame_size = y_plane_bytes_per_row * y_plane_height + | |
671 uv_plane_bytes_per_row * uv_plane_height; | |
672 | 681 |
673 // Sanity check assumption that planar bytes are contiguous. | 682 OnFrame(cricket::WebRtcVideoFrame(buffer, webrtc::kVideoRotation_0, |
674 uint8_t* uv_plane_address = | 683 translated_camera_time_us), |
675 static_cast<uint8_t*>(CVPixelBufferGetBaseAddressOfPlane(image_buffer, | 684 captured_width, captured_height); |
676 kUVPlaneIndex)); | |
677 RTC_DCHECK(uv_plane_address == | |
678 y_plane_address + y_plane_height * y_plane_bytes_per_row); | |
679 | 685 |
680 // Stuff data into a cricket::CapturedFrame. | |
681 cricket::CapturedFrame frame; | |
682 frame.width = y_plane_width; | |
683 frame.height = y_plane_height; | |
684 frame.pixel_width = 1; | |
685 frame.pixel_height = 1; | |
686 frame.fourcc = static_cast<uint32_t>(cricket::FOURCC_NV12); | |
687 frame.time_stamp = capture_time; | |
688 frame.data = y_plane_address; | |
689 frame.data_size = frame_size; | |
690 | |
691 // This will call a superclass method that will perform the frame conversion | |
692 // to I420. | |
693 SignalFrameCaptured(this, &frame); | |
694 | |
695 CVPixelBufferUnlockBaseAddress(image_buffer, lock_flags); | |
696 CVBufferRelease(image_buffer); | 686 CVBufferRelease(image_buffer); |
697 } | 687 } |
698 | 688 |
699 } // namespace webrtc | 689 } // namespace webrtc |
OLD | NEW |