xref: /aosp_15_r20/external/webrtc/sdk/objc/native/src/objc_video_track_source.mm (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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