1/* 2 * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. 3 * 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 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11#include "sdk/objc/native/src/objc_video_track_source.h" 12 13#import "base/RTCVideoFrame.h" 14#import "base/RTCVideoFrameBuffer.h" 15#import "components/video_frame_buffer/RTCCVPixelBuffer.h" 16 17#include "api/video/i420_buffer.h" 18#include "sdk/objc/native/src/objc_frame_buffer.h" 19 20@interface RTCObjCVideoSourceAdapter () 21@property(nonatomic) webrtc::ObjCVideoTrackSource *objCVideoTrackSource; 22@end 23 24@implementation RTCObjCVideoSourceAdapter 25 26@synthesize objCVideoTrackSource = _objCVideoTrackSource; 27 28- (void)capturer:(RTC_OBJC_TYPE(RTCVideoCapturer) *)capturer 29 didCaptureVideoFrame:(RTC_OBJC_TYPE(RTCVideoFrame) *)frame { 30 _objCVideoTrackSource->OnCapturedFrame(frame); 31} 32 33@end 34 35namespace webrtc { 36 37ObjCVideoTrackSource::ObjCVideoTrackSource() : ObjCVideoTrackSource(false) {} 38 39ObjCVideoTrackSource::ObjCVideoTrackSource(bool is_screencast) 40 : AdaptedVideoTrackSource(/* required resolution alignment */ 2), 41 is_screencast_(is_screencast) {} 42 43ObjCVideoTrackSource::ObjCVideoTrackSource(RTCObjCVideoSourceAdapter *adapter) : adapter_(adapter) { 44 adapter_.objCVideoTrackSource = this; 45} 46 47bool ObjCVideoTrackSource::is_screencast() const { 48 return is_screencast_; 49} 50 51absl::optional<bool> ObjCVideoTrackSource::needs_denoising() const { 52 return false; 53} 54 55MediaSourceInterface::SourceState ObjCVideoTrackSource::state() const { 56 return SourceState::kLive; 57} 58 59bool ObjCVideoTrackSource::remote() const { 60 return false; 61} 62 63void ObjCVideoTrackSource::OnOutputFormatRequest(int width, int height, int fps) { 64 cricket::VideoFormat format(width, height, cricket::VideoFormat::FpsToInterval(fps), 0); 65 video_adapter()->OnOutputFormatRequest(format); 66} 67 68void ObjCVideoTrackSource::OnCapturedFrame(RTC_OBJC_TYPE(RTCVideoFrame) * frame) { 69 const int64_t timestamp_us = frame.timeStampNs / rtc::kNumNanosecsPerMicrosec; 70 const int64_t translated_timestamp_us = 71 timestamp_aligner_.TranslateTimestamp(timestamp_us, rtc::TimeMicros()); 72 73 int adapted_width; 74 int adapted_height; 75 int crop_width; 76 int crop_height; 77 int crop_x; 78 int crop_y; 79 if (!AdaptFrame(frame.width, 80 frame.height, 81 timestamp_us, 82 &adapted_width, 83 &adapted_height, 84 &crop_width, 85 &crop_height, 86 &crop_x, 87 &crop_y)) { 88 return; 89 } 90 91 rtc::scoped_refptr<VideoFrameBuffer> buffer; 92 if (adapted_width == frame.width && adapted_height == frame.height) { 93 // No adaption - optimized path. 94 buffer = rtc::make_ref_counted<ObjCFrameBuffer>(frame.buffer); 95 } else if ([frame.buffer isKindOfClass:[RTC_OBJC_TYPE(RTCCVPixelBuffer) class]]) { 96 // Adapted CVPixelBuffer frame. 97 RTC_OBJC_TYPE(RTCCVPixelBuffer) *rtcPixelBuffer = 98 (RTC_OBJC_TYPE(RTCCVPixelBuffer) *)frame.buffer; 99 buffer = rtc::make_ref_counted<ObjCFrameBuffer>([[RTC_OBJC_TYPE(RTCCVPixelBuffer) alloc] 100 initWithPixelBuffer:rtcPixelBuffer.pixelBuffer 101 adaptedWidth:adapted_width 102 adaptedHeight:adapted_height 103 cropWidth:crop_width 104 cropHeight:crop_height 105 cropX:crop_x + rtcPixelBuffer.cropX 106 cropY:crop_y + rtcPixelBuffer.cropY]); 107 } else { 108 // Adapted I420 frame. 109 // TODO(magjed): Optimize this I420 path. 110 rtc::scoped_refptr<I420Buffer> i420_buffer = I420Buffer::Create(adapted_width, adapted_height); 111 buffer = rtc::make_ref_counted<ObjCFrameBuffer>(frame.buffer); 112 i420_buffer->CropAndScaleFrom(*buffer->ToI420(), crop_x, crop_y, crop_width, crop_height); 113 buffer = i420_buffer; 114 } 115 116 // Applying rotation is only supported for legacy reasons and performance is 117 // not critical here. 118 VideoRotation rotation = static_cast<VideoRotation>(frame.rotation); 119 if (apply_rotation() && rotation != kVideoRotation_0) { 120 buffer = I420Buffer::Rotate(*buffer->ToI420(), rotation); 121 rotation = kVideoRotation_0; 122 } 123 124 OnFrame(VideoFrame::Builder() 125 .set_video_frame_buffer(buffer) 126 .set_rotation(rotation) 127 .set_timestamp_us(translated_timestamp_us) 128 .build()); 129} 130 131} // namespace webrtc 132