| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2017 The WebRTC project authors. All Rights Reserved. | 2 * Copyright 2017 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 #import "WebRTC/RTCVideoCodecH264.h" | 11 #import "WebRTC/RTCVideoCodecH264.h" |
| 12 | 12 |
| 13 #include <vector> | 13 #include <vector> |
| 14 | 14 |
| 15 #import "RTCVideoCodec+Private.h" | 15 #import "RTCVideoCodec+Private.h" |
| 16 #import "WebRTC/RTCVideoCodec.h" | 16 #import "WebRTC/RTCVideoCodec.h" |
| 17 #import "WebRTC/RTCVideoFrame.h" | 17 #import "WebRTC/RTCVideoFrame.h" |
| 18 #import "WebRTC/RTCVideoFrameBuffer.h" | 18 #import "WebRTC/RTCVideoFrameBuffer.h" |
| 19 | 19 |
| 20 #include "webrtc/rtc_base/timeutils.h" | 20 #include "webrtc/rtc_base/timeutils.h" |
| 21 #include "webrtc/sdk/objc/Framework/Classes/Video/objc_frame_buffer.h" | 21 #include "webrtc/sdk/objc/Framework/Classes/Video/objc_frame_buffer.h" |
| 22 #include "webrtc/sdk/objc/Framework/Classes/VideoToolbox/decoder.h" | |
| 23 #include "webrtc/sdk/objc/Framework/Classes/VideoToolbox/encoder.h" | |
| 24 #include "webrtc/system_wrappers/include/field_trial.h" | 22 #include "webrtc/system_wrappers/include/field_trial.h" |
| 25 | 23 |
| 26 const size_t kDefaultPayloadSize = 1440; | |
| 27 | |
| 28 const char kHighProfileExperiment[] = "WebRTC-H264HighProfile"; | 24 const char kHighProfileExperiment[] = "WebRTC-H264HighProfile"; |
| 29 | 25 static NSString *kLevel31ConstrainedHigh = @"640c1f"; |
| 30 // These thresholds deviate from the default h264 QP thresholds, as they have be
en found to work | 26 static NSString *kLevel31ConstrainedBaseline = @"42e01f"; |
| 31 // better on devices that support VideoToolbox | |
| 32 const int kLowH264QpThreshold = 28; | |
| 33 const int kHighH264QpThreshold = 39; | |
| 34 | 27 |
| 35 bool IsHighProfileEnabled() { | 28 bool IsHighProfileEnabled() { |
| 36 return webrtc::field_trial::IsEnabled(kHighProfileExperiment); | 29 return webrtc::field_trial::IsEnabled(kHighProfileExperiment); |
| 37 } | 30 } |
| 38 | 31 |
| 39 // H264 specific settings. | 32 // H264 specific settings. |
| 40 @implementation RTCCodecSpecificInfoH264 | 33 @implementation RTCCodecSpecificInfoH264 |
| 41 | 34 |
| 42 @synthesize packetizationMode = _packetizationMode; | 35 @synthesize packetizationMode = _packetizationMode; |
| 43 | 36 |
| 44 - (webrtc::CodecSpecificInfo)nativeCodecSpecificInfo { | 37 - (webrtc::CodecSpecificInfo)nativeCodecSpecificInfo { |
| 45 webrtc::CodecSpecificInfo codecSpecificInfo; | 38 webrtc::CodecSpecificInfo codecSpecificInfo; |
| 46 codecSpecificInfo.codecType = webrtc::kVideoCodecH264; | 39 codecSpecificInfo.codecType = webrtc::kVideoCodecH264; |
| 47 codecSpecificInfo.codec_name = "H264"; | 40 codecSpecificInfo.codec_name = "H264"; |
| 48 codecSpecificInfo.codecSpecific.H264.packetization_mode = | 41 codecSpecificInfo.codecSpecific.H264.packetization_mode = |
| 49 (webrtc::H264PacketizationMode)_packetizationMode; | 42 (webrtc::H264PacketizationMode)_packetizationMode; |
| 50 | 43 |
| 51 return codecSpecificInfo; | 44 return codecSpecificInfo; |
| 52 } | 45 } |
| 53 | 46 |
| 54 @end | 47 @end |
| 55 | 48 |
| 56 namespace { | |
| 57 | |
| 58 class H264VideoToolboxEncodeCompleteCallback : public webrtc::EncodedImageCallba
ck { | |
| 59 public: | |
| 60 Result OnEncodedImage(const webrtc::EncodedImage &encoded_image, | |
| 61 const webrtc::CodecSpecificInfo *codec_specific_info, | |
| 62 const webrtc::RTPFragmentationHeader *fragmentation) { | |
| 63 RTCEncodedImage *image = [[RTCEncodedImage alloc] initWithNativeEncodedImage
:encoded_image]; | |
| 64 | |
| 65 RTCCodecSpecificInfoH264 *info = [[RTCCodecSpecificInfoH264 alloc] init]; | |
| 66 info.packetizationMode = | |
| 67 (RTCH264PacketizationMode)codec_specific_info->codecSpecific.H264.packet
ization_mode; | |
| 68 | |
| 69 RTCRtpFragmentationHeader *header = | |
| 70 [[RTCRtpFragmentationHeader alloc] initWithNativeFragmentationHeader:fra
gmentation]; | |
| 71 | |
| 72 callback(image, info, header); | |
| 73 return Result(Result::OK, 0); | |
| 74 } | |
| 75 | |
| 76 RTCVideoEncoderCallback callback; | |
| 77 }; | |
| 78 | |
| 79 class H264VideoToolboxDecodeCompleteCallback : public webrtc::DecodedImageCallba
ck { | |
| 80 public: | |
| 81 int32_t Decoded(webrtc::VideoFrame &decodedImage) { | |
| 82 rtc::scoped_refptr<webrtc::VideoFrameBuffer> video_frame_buffer = | |
| 83 decodedImage.video_frame_buffer(); | |
| 84 id<RTCVideoFrameBuffer> rtcFrameBuffer; | |
| 85 rtc::scoped_refptr<webrtc::ObjCFrameBuffer> objc_frame_buffer( | |
| 86 static_cast<webrtc::ObjCFrameBuffer *>(video_frame_buffer.get())); | |
| 87 rtcFrameBuffer = (id<RTCVideoFrameBuffer>)objc_frame_buffer->wrapped_frame_b
uffer(); | |
| 88 | |
| 89 RTCVideoFrame *videoFrame = [[RTCVideoFrame alloc] | |
| 90 initWithBuffer:rtcFrameBuffer | |
| 91 rotation:static_cast<RTCVideoRotation>(decodedImage.rotation()) | |
| 92 timeStampNs:decodedImage.timestamp_us() * rtc::kNumNanosecsPerMicrose
c]; | |
| 93 videoFrame.timeStamp = decodedImage.timestamp(); | |
| 94 | |
| 95 callback(videoFrame); | |
| 96 | |
| 97 return 0; | |
| 98 } | |
| 99 | |
| 100 RTCVideoDecoderCallback callback; | |
| 101 }; | |
| 102 | |
| 103 } // namespace | |
| 104 | |
| 105 // Encoder. | |
| 106 @implementation RTCVideoEncoderH264 { | |
| 107 webrtc::H264VideoToolboxEncoder *_videoToolboxEncoder; | |
| 108 H264VideoToolboxEncodeCompleteCallback *_toolboxCallback; | |
| 109 } | |
| 110 | |
| 111 - (instancetype)initWithCodecInfo:(RTCVideoCodecInfo *)codecInfo { | |
| 112 if (self = [super init]) { | |
| 113 cricket::VideoCodec codec = [codecInfo nativeVideoCodec]; | |
| 114 _videoToolboxEncoder = new webrtc::H264VideoToolboxEncoder(codec); | |
| 115 } | |
| 116 return self; | |
| 117 } | |
| 118 | |
| 119 - (void)setCallback:(RTCVideoEncoderCallback)callback { | |
| 120 if (!_toolboxCallback) _toolboxCallback = new H264VideoToolboxEncodeCompleteCa
llback(); | |
| 121 _toolboxCallback->callback = callback; | |
| 122 _videoToolboxEncoder->RegisterEncodeCompleteCallback(_toolboxCallback); | |
| 123 } | |
| 124 | |
| 125 - (void)destroy { | |
| 126 delete _videoToolboxEncoder; | |
| 127 _videoToolboxEncoder = nullptr; | |
| 128 delete _toolboxCallback; | |
| 129 _toolboxCallback = nullptr; | |
| 130 } | |
| 131 | |
| 132 -(void)dealloc { | |
| 133 // Make sure C++ objects have been properly cleaned up before this | |
| 134 // is dealloc'd. | |
| 135 RTC_DCHECK(!_videoToolboxEncoder); | |
| 136 RTC_DCHECK(!_toolboxCallback); | |
| 137 } | |
| 138 | |
| 139 - (NSInteger)startEncodeWithSettings:(RTCVideoEncoderSettings *)settings | |
| 140 numberOfCores:(int)numberOfCores { | |
| 141 std::unique_ptr<webrtc::VideoCodec> codecSettings = [settings createNativeVide
oEncoderSettings]; | |
| 142 return _videoToolboxEncoder->InitEncode( | |
| 143 codecSettings.release(), numberOfCores, kDefaultPayloadSize); | |
| 144 } | |
| 145 | |
| 146 - (NSInteger)releaseEncoder { | |
| 147 return _videoToolboxEncoder->Release(); | |
| 148 } | |
| 149 | |
| 150 - (NSInteger)encode:(RTCVideoFrame *)frame | |
| 151 codecSpecificInfo:(id<RTCCodecSpecificInfo>)info | |
| 152 frameTypes:(NSArray<NSNumber *> *)frameTypes { | |
| 153 rtc::scoped_refptr<webrtc::VideoFrameBuffer> frameBuffer = | |
| 154 new rtc::RefCountedObject<webrtc::ObjCFrameBuffer>(frame.buffer); | |
| 155 webrtc::VideoFrame videoFrame(frameBuffer, | |
| 156 (webrtc::VideoRotation)frame.rotation, | |
| 157 frame.timeStampNs / rtc::kNumNanosecsPerMicrosec
); | |
| 158 videoFrame.set_timestamp(frame.timeStamp); | |
| 159 | |
| 160 // Handle types than can be converted into one of webrtc::CodecSpecificInfo's
hard coded cases. | |
| 161 webrtc::CodecSpecificInfo codecSpecificInfo; | |
| 162 if ([info isKindOfClass:[RTCCodecSpecificInfoH264 class]]) { | |
| 163 codecSpecificInfo = [(RTCCodecSpecificInfoH264 *)info nativeCodecSpecificInf
o]; | |
| 164 } | |
| 165 | |
| 166 std::vector<webrtc::FrameType> nativeFrameTypes; | |
| 167 for (NSNumber *frameType in frameTypes) { | |
| 168 RTCFrameType rtcFrameType = (RTCFrameType)frameType.unsignedIntegerValue; | |
| 169 nativeFrameTypes.push_back((webrtc::FrameType)rtcFrameType); | |
| 170 } | |
| 171 | |
| 172 return _videoToolboxEncoder->Encode(videoFrame, &codecSpecificInfo, &nativeFra
meTypes); | |
| 173 } | |
| 174 | |
| 175 - (BOOL)setBitrate:(uint32_t)bitrateKbit framerate:(uint32_t)framerate { | |
| 176 return _videoToolboxEncoder->SetRates(bitrateKbit, framerate) == WEBRTC_VIDEO_
CODEC_OK; | |
| 177 } | |
| 178 | |
| 179 - (RTCVideoEncoderQpThresholds *)scalingSettings { | |
| 180 return [[RTCVideoEncoderQpThresholds alloc] initWithThresholdsLow:kLowH264QpTh
reshold | |
| 181 high:kHighH264QpT
hreshold]; | |
| 182 } | |
| 183 | |
| 184 - (NSString *)implementationName { | |
| 185 return @"VideoToolbox"; | |
| 186 } | |
| 187 | |
| 188 @end | |
| 189 | |
| 190 // Decoder. | |
| 191 @implementation RTCVideoDecoderH264 { | |
| 192 webrtc::H264VideoToolboxDecoder *_videoToolboxDecoder; | |
| 193 H264VideoToolboxDecodeCompleteCallback *_toolboxCallback; | |
| 194 } | |
| 195 | |
| 196 - (instancetype)init { | |
| 197 if (self = [super init]) { | |
| 198 cricket::VideoCodec codec(cricket::kH264CodecName); | |
| 199 _videoToolboxDecoder = new webrtc::H264VideoToolboxDecoder(); | |
| 200 } | |
| 201 return self; | |
| 202 } | |
| 203 | |
| 204 - (NSInteger)startDecodeWithSettings:(RTCVideoEncoderSettings *)settings | |
| 205 numberOfCores:(int)numberOfCores { | |
| 206 std::unique_ptr<webrtc::VideoCodec> codecSettings = [settings createNativeVide
oEncoderSettings]; | |
| 207 return _videoToolboxDecoder->InitDecode(codecSettings.release(), numberOfCores
); | |
| 208 } | |
| 209 | |
| 210 - (void)setCallback:(RTCVideoDecoderCallback)callback { | |
| 211 if (!_toolboxCallback) _toolboxCallback = new H264VideoToolboxDecodeCompleteCa
llback(); | |
| 212 _toolboxCallback->callback = callback; | |
| 213 _videoToolboxDecoder->RegisterDecodeCompleteCallback(_toolboxCallback); | |
| 214 } | |
| 215 | |
| 216 - (NSInteger)releaseDecoder { | |
| 217 return _videoToolboxDecoder->Release(); | |
| 218 } | |
| 219 | |
| 220 - (void)destroy { | |
| 221 delete _videoToolboxDecoder; | |
| 222 _videoToolboxDecoder = nullptr; | |
| 223 delete _toolboxCallback; | |
| 224 _toolboxCallback = nullptr; | |
| 225 } | |
| 226 | |
| 227 -(void)dealloc { | |
| 228 // Make sure C++ objects have been properly cleaned up before this | |
| 229 // is dealloc'd. | |
| 230 RTC_DCHECK(!_videoToolboxDecoder); | |
| 231 RTC_DCHECK(!_toolboxCallback); | |
| 232 } | |
| 233 | |
| 234 - (NSInteger)decode:(RTCEncodedImage *)encodedImage | |
| 235 missingFrames:(BOOL)missingFrames | |
| 236 fragmentationHeader:(RTCRtpFragmentationHeader *)fragmentationHeader | |
| 237 codecSpecificInfo:(__nullable id<RTCCodecSpecificInfo>)info | |
| 238 renderTimeMs:(int64_t)renderTimeMs { | |
| 239 webrtc::EncodedImage image = [encodedImage nativeEncodedImage]; | |
| 240 | |
| 241 // Handle types than can be converted into one of webrtc::CodecSpecificInfo's
hard coded cases. | |
| 242 webrtc::CodecSpecificInfo codecSpecificInfo; | |
| 243 if ([info isKindOfClass:[RTCCodecSpecificInfoH264 class]]) { | |
| 244 codecSpecificInfo = [(RTCCodecSpecificInfoH264 *)info nativeCodecSpecificInf
o]; | |
| 245 } | |
| 246 | |
| 247 std::unique_ptr<webrtc::RTPFragmentationHeader> header = | |
| 248 [fragmentationHeader createNativeFragmentationHeader]; | |
| 249 | |
| 250 return _videoToolboxDecoder->Decode( | |
| 251 image, missingFrames, header.release(), &codecSpecificInfo, renderTimeMs); | |
| 252 } | |
| 253 | |
| 254 - (NSString *)implementationName { | |
| 255 return @"VideoToolbox"; | |
| 256 } | |
| 257 | |
| 258 @end | |
| 259 | |
| 260 // Encoder factory. | 49 // Encoder factory. |
| 261 @implementation RTCVideoEncoderFactoryH264 | 50 @implementation RTCVideoEncoderFactoryH264 |
| 262 | 51 |
| 263 - (NSArray<RTCVideoCodecInfo *> *)supportedCodecs { | 52 - (NSArray<RTCVideoCodecInfo *> *)supportedCodecs { |
| 264 NSMutableArray<RTCVideoCodecInfo *> *codecs = [NSMutableArray array]; | 53 NSMutableArray<RTCVideoCodecInfo *> *codecs = [NSMutableArray array]; |
| 265 NSString *codecName = [NSString stringWithUTF8String:cricket::kH264CodecName]; | 54 NSString *codecName = [NSString stringWithUTF8String:cricket::kH264CodecName]; |
| 266 | 55 |
| 267 if (IsHighProfileEnabled()) { | 56 if (IsHighProfileEnabled()) { |
| 268 NSDictionary<NSString *, NSString *> *constrainedHighParams = @{ | 57 NSDictionary<NSString *, NSString *> *constrainedHighParams = @{ |
| 269 @"profile-level-id" : @"640c1f", // Level 3.1 Constrained High. | 58 @"profile-level-id" : kLevel31ConstrainedHigh, |
| 270 @"level-asymmetry-allowed" : @"1", | 59 @"level-asymmetry-allowed" : @"1", |
| 271 @"packetization-mode" : @"1", | 60 @"packetization-mode" : @"1", |
| 272 }; | 61 }; |
| 273 RTCVideoCodecInfo *constrainedHighInfo = | 62 RTCVideoCodecInfo *constrainedHighInfo = |
| 274 [[RTCVideoCodecInfo alloc] initWithPayload:0 | 63 [[RTCVideoCodecInfo alloc] initWithPayload:0 |
| 275 name:codecName | 64 name:codecName |
| 276 parameters:constrainedHighParams]; | 65 parameters:constrainedHighParams]; |
| 277 [codecs addObject:constrainedHighInfo]; | 66 [codecs addObject:constrainedHighInfo]; |
| 278 } | 67 } |
| 279 | 68 |
| 280 NSDictionary<NSString *, NSString *> *constrainedBaselineParams = @{ | 69 NSDictionary<NSString *, NSString *> *constrainedBaselineParams = @{ |
| 281 @"profile-level-id" : @"42e01f", // Level 3.1 Constrained Baseline. | 70 @"profile-level-id" : kLevel31ConstrainedBaseline, |
| 282 @"level-asymmetry-allowed" : @"1", | 71 @"level-asymmetry-allowed" : @"1", |
| 283 @"packetization-mode" : @"1", | 72 @"packetization-mode" : @"1", |
| 284 }; | 73 }; |
| 285 RTCVideoCodecInfo *constrainedBaselineInfo = | 74 RTCVideoCodecInfo *constrainedBaselineInfo = |
| 286 [[RTCVideoCodecInfo alloc] initWithPayload:0 | 75 [[RTCVideoCodecInfo alloc] initWithPayload:0 |
| 287 name:codecName | 76 name:codecName |
| 288 parameters:constrainedBaselineParams]; | 77 parameters:constrainedBaselineParams]; |
| 289 [codecs addObject:constrainedBaselineInfo]; | 78 [codecs addObject:constrainedBaselineInfo]; |
| 290 | 79 |
| 291 return [codecs copy]; | 80 return [codecs copy]; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 303 - (id<RTCVideoDecoder>)createDecoder:(RTCVideoCodecInfo *)info { | 92 - (id<RTCVideoDecoder>)createDecoder:(RTCVideoCodecInfo *)info { |
| 304 return [[RTCVideoDecoderH264 alloc] init]; | 93 return [[RTCVideoDecoderH264 alloc] init]; |
| 305 } | 94 } |
| 306 | 95 |
| 307 - (NSArray<RTCVideoCodecInfo *> *)supportedCodecs { | 96 - (NSArray<RTCVideoCodecInfo *> *)supportedCodecs { |
| 308 NSString *codecName = [NSString stringWithUTF8String:cricket::kH264CodecName]; | 97 NSString *codecName = [NSString stringWithUTF8String:cricket::kH264CodecName]; |
| 309 return @[ [[RTCVideoCodecInfo alloc] initWithPayload:0 name:codecName paramete
rs:@{}] ]; | 98 return @[ [[RTCVideoCodecInfo alloc] initWithPayload:0 name:codecName paramete
rs:@{}] ]; |
| 310 } | 99 } |
| 311 | 100 |
| 312 @end | 101 @end |
| OLD | NEW |