1/*
2 *  Copyright 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_encoder_factory.h"
12
13#include <string>
14
15#import "base/RTCMacros.h"
16#import "base/RTCVideoEncoder.h"
17#import "base/RTCVideoEncoderFactory.h"
18#import "components/video_codec/RTCCodecSpecificInfoH264+Private.h"
19#import "sdk/objc/api/peerconnection/RTCEncodedImage+Private.h"
20#import "sdk/objc/api/peerconnection/RTCRtpFragmentationHeader+Private.h"
21#import "sdk/objc/api/peerconnection/RTCVideoCodecInfo+Private.h"
22#import "sdk/objc/api/peerconnection/RTCVideoEncoderSettings+Private.h"
23#import "sdk/objc/api/video_codec/RTCVideoCodecConstants.h"
24#import "sdk/objc/api/video_codec/RTCWrappedNativeVideoEncoder.h"
25#import "sdk/objc/helpers/NSString+StdString.h"
26
27#include "api/video/video_frame.h"
28#include "api/video_codecs/sdp_video_format.h"
29#include "api/video_codecs/video_encoder.h"
30#include "modules/include/module_common_types.h"
31#include "modules/video_coding/include/video_codec_interface.h"
32#include "modules/video_coding/include/video_error_codes.h"
33#include "rtc_base/logging.h"
34#include "sdk/objc/native/src/objc_video_frame.h"
35
36namespace webrtc {
37
38namespace {
39
40class ObjCVideoEncoder : public VideoEncoder {
41 public:
42  ObjCVideoEncoder(id<RTC_OBJC_TYPE(RTCVideoEncoder)> encoder)
43      : encoder_(encoder), implementation_name_([encoder implementationName].stdString) {}
44
45  int32_t InitEncode(const VideoCodec *codec_settings, const Settings &encoder_settings) override {
46    RTC_OBJC_TYPE(RTCVideoEncoderSettings) *settings =
47        [[RTC_OBJC_TYPE(RTCVideoEncoderSettings) alloc] initWithNativeVideoCodec:codec_settings];
48    return [encoder_ startEncodeWithSettings:settings
49                               numberOfCores:encoder_settings.number_of_cores];
50  }
51
52  int32_t RegisterEncodeCompleteCallback(EncodedImageCallback *callback) override {
53    [encoder_ setCallback:^BOOL(RTC_OBJC_TYPE(RTCEncodedImage) * _Nonnull frame,
54                                id<RTC_OBJC_TYPE(RTCCodecSpecificInfo)> _Nonnull info,
55                                RTC_OBJC_TYPE(RTCRtpFragmentationHeader) * _Nonnull header) {
56      EncodedImage encodedImage = [frame nativeEncodedImage];
57
58      // Handle types that can be converted into one of CodecSpecificInfo's hard coded cases.
59      CodecSpecificInfo codecSpecificInfo;
60      if ([info isKindOfClass:[RTC_OBJC_TYPE(RTCCodecSpecificInfoH264) class]]) {
61        codecSpecificInfo =
62            [(RTC_OBJC_TYPE(RTCCodecSpecificInfoH264) *)info nativeCodecSpecificInfo];
63      }
64
65      std::unique_ptr<RTPFragmentationHeader> fragmentationHeader =
66          [header createNativeFragmentationHeader];
67      EncodedImageCallback::Result res =
68          callback->OnEncodedImage(encodedImage, &codecSpecificInfo, fragmentationHeader.get());
69      return res.error == EncodedImageCallback::Result::OK;
70    }];
71
72    return WEBRTC_VIDEO_CODEC_OK;
73  }
74
75  int32_t Release() override { return [encoder_ releaseEncoder]; }
76
77  int32_t Encode(const VideoFrame &frame,
78                 const std::vector<VideoFrameType> *frame_types) override {
79    NSMutableArray<NSNumber *> *rtcFrameTypes = [NSMutableArray array];
80    for (size_t i = 0; i < frame_types->size(); ++i) {
81      [rtcFrameTypes addObject:@(RTCFrameType(frame_types->at(i)))];
82    }
83
84    return [encoder_ encode:ToObjCVideoFrame(frame)
85          codecSpecificInfo:nil
86                 frameTypes:rtcFrameTypes];
87  }
88
89  void SetRates(const RateControlParameters &parameters) override {
90    const uint32_t bitrate = parameters.bitrate.get_sum_kbps();
91    const uint32_t framerate = static_cast<uint32_t>(parameters.framerate_fps + 0.5);
92    [encoder_ setBitrate:bitrate framerate:framerate];
93  }
94
95  VideoEncoder::EncoderInfo GetEncoderInfo() const override {
96    EncoderInfo info;
97    info.supports_native_handle = true;
98    info.implementation_name = implementation_name_;
99
100    RTC_OBJC_TYPE(RTCVideoEncoderQpThresholds) *qp_thresholds = [encoder_ scalingSettings];
101    info.scaling_settings = qp_thresholds ? ScalingSettings(qp_thresholds.low, qp_thresholds.high) :
102                                            ScalingSettings::kOff;
103
104    info.is_hardware_accelerated = true;
105    info.has_internal_source = false;
106    return info;
107  }
108
109 private:
110  id<RTC_OBJC_TYPE(RTCVideoEncoder)> encoder_;
111  const std::string implementation_name_;
112};
113
114class ObjcVideoEncoderSelector : public VideoEncoderFactory::EncoderSelectorInterface {
115 public:
116  ObjcVideoEncoderSelector(id<RTC_OBJC_TYPE(RTCVideoEncoderSelector)> selector) {
117    selector_ = selector;
118  }
119  void OnCurrentEncoder(const SdpVideoFormat &format) override {
120    RTC_OBJC_TYPE(RTCVideoCodecInfo) *info =
121        [[RTC_OBJC_TYPE(RTCVideoCodecInfo) alloc] initWithNativeSdpVideoFormat:format];
122    [selector_ registerCurrentEncoderInfo:info];
123  }
124  absl::optional<SdpVideoFormat> OnEncoderBroken() override {
125    RTC_OBJC_TYPE(RTCVideoCodecInfo) *info = [selector_ encoderForBrokenEncoder];
126    if (info) {
127      return [info nativeSdpVideoFormat];
128    }
129    return absl::nullopt;
130  }
131  absl::optional<SdpVideoFormat> OnAvailableBitrate(const DataRate &rate) override {
132    RTC_OBJC_TYPE(RTCVideoCodecInfo) *info = [selector_ encoderForBitrate:rate.kbps<NSInteger>()];
133    if (info) {
134      return [info nativeSdpVideoFormat];
135    }
136    return absl::nullopt;
137  }
138
139 private:
140  id<RTC_OBJC_TYPE(RTCVideoEncoderSelector)> selector_;
141};
142
143}  // namespace
144
145ObjCVideoEncoderFactory::ObjCVideoEncoderFactory(
146    id<RTC_OBJC_TYPE(RTCVideoEncoderFactory)> encoder_factory)
147    : encoder_factory_(encoder_factory) {}
148
149ObjCVideoEncoderFactory::~ObjCVideoEncoderFactory() {}
150
151id<RTC_OBJC_TYPE(RTCVideoEncoderFactory)> ObjCVideoEncoderFactory::wrapped_encoder_factory() const {
152  return encoder_factory_;
153}
154
155std::vector<SdpVideoFormat> ObjCVideoEncoderFactory::GetSupportedFormats() const {
156  std::vector<SdpVideoFormat> supported_formats;
157  for (RTC_OBJC_TYPE(RTCVideoCodecInfo) * supportedCodec in [encoder_factory_ supportedCodecs]) {
158    SdpVideoFormat format = [supportedCodec nativeSdpVideoFormat];
159    supported_formats.push_back(format);
160  }
161
162  return supported_formats;
163}
164
165std::vector<SdpVideoFormat> ObjCVideoEncoderFactory::GetImplementations() const {
166  if ([encoder_factory_ respondsToSelector:@selector(implementations)]) {
167    std::vector<SdpVideoFormat> supported_formats;
168    for (RTC_OBJC_TYPE(RTCVideoCodecInfo) * supportedCodec in [encoder_factory_ implementations]) {
169      SdpVideoFormat format = [supportedCodec nativeSdpVideoFormat];
170      supported_formats.push_back(format);
171    }
172    return supported_formats;
173  }
174  return GetSupportedFormats();
175}
176
177VideoEncoderFactory::CodecInfo ObjCVideoEncoderFactory::QueryVideoEncoder(
178    const SdpVideoFormat &format) const {
179  // TODO(andersc): This is a hack until we figure out how this should be done properly.
180  NSString *formatName = [NSString stringForStdString:format.name];
181  NSSet *wrappedSoftwareFormats =
182      [NSSet setWithObjects:kRTCVideoCodecVp8Name, kRTCVideoCodecVp9Name, nil];
183
184  CodecInfo codec_info;
185  codec_info.is_hardware_accelerated = ![wrappedSoftwareFormats containsObject:formatName];
186  codec_info.has_internal_source = false;
187  return codec_info;
188}
189
190std::unique_ptr<VideoEncoder> ObjCVideoEncoderFactory::CreateVideoEncoder(
191    const SdpVideoFormat &format) {
192  RTC_OBJC_TYPE(RTCVideoCodecInfo) *info =
193      [[RTC_OBJC_TYPE(RTCVideoCodecInfo) alloc] initWithNativeSdpVideoFormat:format];
194  id<RTC_OBJC_TYPE(RTCVideoEncoder)> encoder = [encoder_factory_ createEncoder:info];
195  if ([encoder isKindOfClass:[RTCWrappedNativeVideoEncoder class]]) {
196    return [(RTCWrappedNativeVideoEncoder *)encoder releaseWrappedEncoder];
197  } else {
198    return std::unique_ptr<ObjCVideoEncoder>(new ObjCVideoEncoder(encoder));
199  }
200}
201
202std::unique_ptr<VideoEncoderFactory::EncoderSelectorInterface>
203    ObjCVideoEncoderFactory::GetEncoderSelector() const {
204  if ([encoder_factory_ respondsToSelector:@selector(encoderSelector)]) {
205    id<RTC_OBJC_TYPE(RTCVideoEncoderSelector)> selector = [encoder_factory_ encoderSelector];
206    if (selector) {
207      return absl::make_unique<ObjcVideoEncoderSelector>(selector);
208    }
209  }
210  return nullptr;
211}
212
213}  // namespace webrtc
214