Implement ObjCVideoEncoderFactory::QueryCodecSupport To allow objc video encoders to support scalability modes Bug: b/299588022 Change-Id: Id58f996b8c48c6688cccdc32caff6adb00370d5c Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/358580 Reviewed-by: Kári Helgason <kthelgason@webrtc.org> Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org> Commit-Queue: Danil Chapovalov <danilchap@webrtc.org> Cr-Commit-Position: refs/heads/main@{#42985}
diff --git a/sdk/BUILD.gn b/sdk/BUILD.gn index 0c33be3..27fb4ad 100644 --- a/sdk/BUILD.gn +++ b/sdk/BUILD.gn
@@ -110,6 +110,7 @@ "objc/base/RTCVideoDecoderFactory.h", "objc/base/RTCVideoEncoder.h", "objc/base/RTCVideoEncoderFactory.h", + "objc/base/RTCVideoEncoderFactory.mm", "objc/base/RTCVideoEncoderQpThresholds.h", "objc/base/RTCVideoEncoderQpThresholds.m", "objc/base/RTCVideoEncoderSettings.h",
diff --git a/sdk/objc/base/RTCVideoEncoderFactory.h b/sdk/objc/base/RTCVideoEncoderFactory.h index a73cd77..31e469d 100644 --- a/sdk/objc/base/RTCVideoEncoderFactory.h +++ b/sdk/objc/base/RTCVideoEncoderFactory.h
@@ -32,6 +32,22 @@ @end +/** RTCVideoEncoderCodecSupport is an Objective-C version of + * webrtc::VideoEncoderFactory::CodecSupport. */ +RTC_OBJC_EXPORT +@interface RTC_OBJC_TYPE (RTCVideoEncoderCodecSupport) : NSObject + +- (instancetype)init NS_UNAVAILABLE; + +- (instancetype)initWithSupported:(bool)isSupported; +- (instancetype)initWithSupported:(bool)isSupported + isPowerEfficient:(bool)isPowerEfficient NS_DESIGNATED_INITIALIZER; + +@property(nonatomic, readonly) bool isSupported; +@property(nonatomic, readonly) bool isPowerEfficient; + +@end + /** RTCVideoEncoderFactory is an Objective-C version of webrtc::VideoEncoderFactory. */ RTC_OBJC_EXPORT @@ -46,6 +62,10 @@ @optional - (NSArray<RTC_OBJC_TYPE(RTCVideoCodecInfo) *> *)implementations; - (nullable id<RTC_OBJC_TYPE(RTCVideoEncoderSelector)>)encoderSelector; +/* TODO: b/299588022 - move to non-optional section when implemented by all derived classes. */ +- (RTC_OBJC_TYPE(RTCVideoEncoderCodecSupport) *) + queryCodecSupport:(RTC_OBJC_TYPE(RTCVideoCodecInfo) *)info + scalabilityMode:(nullable NSString *)scalabilityMode; @end
diff --git a/sdk/objc/base/RTCVideoEncoderFactory.mm b/sdk/objc/base/RTCVideoEncoderFactory.mm new file mode 100644 index 0000000..604a524 --- /dev/null +++ b/sdk/objc/base/RTCVideoEncoderFactory.mm
@@ -0,0 +1,32 @@ +/* + * Copyright 2024 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#import "RTCVideoEncoderFactory.h" +#import "RTCMacros.h" + +@implementation RTC_OBJC_TYPE (RTCVideoEncoderCodecSupport) + +@synthesize isSupported = _isSupported; +@synthesize isPowerEfficient = _isPowerEfficient; + +- (instancetype)initWithSupported:(bool)isSupported { + return [self initWithSupported:isSupported isPowerEfficient:false]; +} + +- (instancetype)initWithSupported:(bool)isSupported isPowerEfficient:(bool)isPowerEfficient { + self = [super init]; + if (self) { + _isSupported = isSupported; + _isPowerEfficient = isPowerEfficient; + } + return self; +} + +@end
diff --git a/sdk/objc/native/src/objc_video_encoder_factory.h b/sdk/objc/native/src/objc_video_encoder_factory.h index d74e493..62af09c 100644 --- a/sdk/objc/native/src/objc_video_encoder_factory.h +++ b/sdk/objc/native/src/objc_video_encoder_factory.h
@@ -13,10 +13,13 @@ #import <Foundation/Foundation.h> -#import "base/RTCMacros.h" +#include <optional> +#include <string> #include "api/environment/environment.h" +#include "api/video_codecs/sdp_video_format.h" #include "api/video_codecs/video_encoder_factory.h" +#import "base/RTCMacros.h" @protocol RTC_OBJC_TYPE (RTCVideoEncoderFactory); @@ -32,6 +35,8 @@ std::vector<SdpVideoFormat> GetSupportedFormats() const override; std::vector<SdpVideoFormat> GetImplementations() const override; + CodecSupport QueryCodecSupport(const SdpVideoFormat& format, + std::optional<std::string> scalability_mode) const override; std::unique_ptr<VideoEncoder> Create(const Environment& env, const SdpVideoFormat& format) override; std::unique_ptr<EncoderSelectorInterface> GetEncoderSelector() const override;
diff --git a/sdk/objc/native/src/objc_video_encoder_factory.mm b/sdk/objc/native/src/objc_video_encoder_factory.mm index e5fb3da..bc8c532 100644 --- a/sdk/objc/native/src/objc_video_encoder_factory.mm +++ b/sdk/objc/native/src/objc_video_encoder_factory.mm
@@ -10,6 +10,7 @@ #include "sdk/objc/native/src/objc_video_encoder_factory.h" +#include <optional> #include <string> #import "base/RTCMacros.h" @@ -184,6 +185,25 @@ return GetSupportedFormats(); } +VideoEncoderFactory::CodecSupport ObjCVideoEncoderFactory::QueryCodecSupport( + const SdpVideoFormat &format, std::optional<std::string> scalability_mode) const { + if ([encoder_factory_ respondsToSelector:@selector(queryCodecSupport:scalabilityMode:)]) { + RTC_OBJC_TYPE(RTCVideoCodecInfo) *info = + [[RTC_OBJC_TYPE(RTCVideoCodecInfo) alloc] initWithNativeSdpVideoFormat:format]; + NSString *mode; + if (scalability_mode.has_value()) { + mode = [NSString stringForAbslStringView:*scalability_mode]; + } + + RTC_OBJC_TYPE(RTCVideoEncoderCodecSupport) *result = [encoder_factory_ queryCodecSupport:info + scalabilityMode:mode]; + return {.is_supported = result.isSupported, .is_power_efficient = result.isPowerEfficient}; + } + + // Use default implementation. + return VideoEncoderFactory::QueryCodecSupport(format, scalability_mode); +} + std::unique_ptr<VideoEncoder> ObjCVideoEncoderFactory::Create(const Environment &env, const SdpVideoFormat &format) { RTC_OBJC_TYPE(RTCVideoCodecInfo) *info =
diff --git a/sdk/objc/unittests/objc_video_encoder_factory_tests.mm b/sdk/objc/unittests/objc_video_encoder_factory_tests.mm index a04e797..2f469bb 100644 --- a/sdk/objc/unittests/objc_video_encoder_factory_tests.mm +++ b/sdk/objc/unittests/objc_video_encoder_factory_tests.mm
@@ -52,6 +52,55 @@ return CreateEncoderFactoryReturning(WEBRTC_VIDEO_CODEC_ERROR); } +@interface RTCVideoEncoderFactoryFake : NSObject <RTC_OBJC_TYPE (RTCVideoEncoderFactory)> + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithScalabilityMode:(NSString *)scalabilityMode; +- (instancetype)initWithScalabilityMode:(NSString *)scalabilityMode + isPowerEfficient:(bool)isPowerEfficient NS_DESIGNATED_INITIALIZER; +@end +@implementation RTCVideoEncoderFactoryFake + +NSString *_scalabilityMode; +bool _isPowerEfficient; + +- (instancetype)initWithScalabilityMode:(NSString *)scalabilityMode { + return [self initWithScalabilityMode:scalabilityMode isPowerEfficient:false]; +} + +- (instancetype)initWithScalabilityMode:(NSString *)scalabilityMode + isPowerEfficient:(bool)isPowerEfficient { + self = [super init]; + if (self) { + _scalabilityMode = scalabilityMode; + _isPowerEfficient = isPowerEfficient; + } + return self; +} + +- (nullable id<RTC_OBJC_TYPE(RTCVideoEncoder)>)createEncoder: + (RTC_OBJC_TYPE(RTCVideoCodecInfo) *)info { + return nil; +} + +- (NSArray<RTC_OBJC_TYPE(RTCVideoCodecInfo) *> *)supportedCodecs { + return @[]; +} + +- (RTC_OBJC_TYPE(RTCVideoEncoderCodecSupport) *) + queryCodecSupport:(RTC_OBJC_TYPE(RTCVideoCodecInfo) *)info + scalabilityMode:(nullable NSString *)scalabilityMode { + if (_scalabilityMode ? [_scalabilityMode isEqualToString:scalabilityMode] : + scalabilityMode == nil) { + return [[RTC_OBJC_TYPE(RTCVideoEncoderCodecSupport) alloc] initWithSupported:true + isPowerEfficient:_isPowerEfficient]; + } else { + return [[RTC_OBJC_TYPE(RTCVideoEncoderCodecSupport) alloc] initWithSupported:false]; + } +} + +@end + std::unique_ptr<webrtc::VideoEncoder> GetObjCEncoder( id<RTC_OBJC_TYPE(RTCVideoEncoderFactory)> factory) { webrtc::ObjCVideoEncoderFactory encoder_factory(factory); @@ -132,6 +181,36 @@ EXPECT_EQ(encoder->Release(), WEBRTC_VIDEO_CODEC_ERROR); } +- (void)testQueryCodecSupportDelegatesToObjcFactoryConvertsNulloptModeToNil { + id fakeEncoderFactory = [[RTCVideoEncoderFactoryFake alloc] initWithScalabilityMode:nil]; + webrtc::SdpVideoFormat codec("VP8"); + webrtc::ObjCVideoEncoderFactory encoder_factory(fakeEncoderFactory); + + webrtc::VideoEncoderFactory::CodecSupport s = + encoder_factory.QueryCodecSupport(codec, std::nullopt); + + EXPECT_TRUE(s.is_supported); +} + +- (void)testQueryCodecSupportDelegatesToObjcFactoryMayReturnUnsupported { + id fakeEncoderFactory = [[RTCVideoEncoderFactoryFake alloc] initWithScalabilityMode:@"L1T2"]; + webrtc::SdpVideoFormat codec("VP8"); + webrtc::ObjCVideoEncoderFactory encoder_factory(fakeEncoderFactory); + + EXPECT_FALSE(encoder_factory.QueryCodecSupport(codec, "S2T1").is_supported); +} + +- (void)testQueryCodecSupportDelegatesToObjcFactoryIncludesPowerEfficientFlag { + id fakeEncoderFactory = [[RTCVideoEncoderFactoryFake alloc] initWithScalabilityMode:@"L1T2" + isPowerEfficient:true]; + webrtc::SdpVideoFormat codec("VP8"); + webrtc::ObjCVideoEncoderFactory encoder_factory(fakeEncoderFactory); + + webrtc::VideoEncoderFactory::CodecSupport s = encoder_factory.QueryCodecSupport(codec, "L1T2"); + EXPECT_TRUE(s.is_supported); + EXPECT_TRUE(s.is_power_efficient); +} + - (void)testGetSupportedFormats { webrtc::ObjCVideoEncoderFactory encoder_factory(CreateOKEncoderFactory()); std::vector<webrtc::SdpVideoFormat> supportedFormats = encoder_factory.GetSupportedFormats();