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 |