OLD | NEW |
| (Empty) |
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 #import "WebRTC/RTCVideoCodecH264.h" | |
12 | |
13 #include <vector> | |
14 | |
15 #import "RTCVideoCodec+Private.h" | |
16 #import "WebRTC/RTCVideoCodec.h" | |
17 #import "WebRTC/RTCVideoFrame.h" | |
18 #import "WebRTC/RTCVideoFrameBuffer.h" | |
19 | |
20 #include "webrtc/rtc_base/timeutils.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" | |
25 | |
26 const size_t kDefaultPayloadSize = 1440; | |
27 | |
28 const char kHighProfileExperiment[] = "WebRTC-H264HighProfile"; | |
29 | |
30 bool IsHighProfileEnabled() { | |
31 return webrtc::field_trial::IsEnabled(kHighProfileExperiment); | |
32 } | |
33 | |
34 // H264 specific settings. | |
35 @implementation RTCCodecSpecificInfoH264 | |
36 | |
37 @synthesize packetizationMode = _packetizationMode; | |
38 | |
39 - (webrtc::CodecSpecificInfo)toCpp { | |
40 webrtc::CodecSpecificInfo codecSpecificInfo; | |
41 codecSpecificInfo.codecType = webrtc::kVideoCodecH264; | |
42 codecSpecificInfo.codec_name = "H264"; | |
43 codecSpecificInfo.codecSpecific.H264.packetization_mode = | |
44 (webrtc::H264PacketizationMode)_packetizationMode; | |
45 | |
46 return codecSpecificInfo; | |
47 } | |
48 | |
49 @end | |
50 | |
51 namespace { | |
52 | |
53 class H264VideoToolboxEncodeCompleteCallback : public webrtc::EncodedImageCallba
ck { | |
54 public: | |
55 Result OnEncodedImage(const webrtc::EncodedImage &encoded_image, | |
56 const webrtc::CodecSpecificInfo *codec_specific_info, | |
57 const webrtc::RTPFragmentationHeader *fragmentation) { | |
58 RTCEncodedImage *image = [[RTCEncodedImage alloc] initWithEncodedImage:encod
ed_image]; | |
59 | |
60 RTCCodecSpecificInfoH264 *info = [[RTCCodecSpecificInfoH264 alloc] init]; | |
61 info.packetizationMode = | |
62 (RTCH264PacketizationMode)codec_specific_info->codecSpecific.H264.packet
ization_mode; | |
63 | |
64 RTCRtpFragmentationHeader *header = | |
65 [[RTCRtpFragmentationHeader alloc] initWithFragmentationHeader:fragmenta
tion]; | |
66 | |
67 callback(image, info, header); | |
68 return Result(Result::OK, 0); | |
69 } | |
70 | |
71 RTCVideoEncoderCallback callback; | |
72 }; | |
73 | |
74 class H264VideoToolboxDecodeCompleteCallback : public webrtc::DecodedImageCallba
ck { | |
75 public: | |
76 int32_t Decoded(webrtc::VideoFrame &decodedImage) { | |
77 rtc::scoped_refptr<webrtc::VideoFrameBuffer> video_frame_buffer = | |
78 decodedImage.video_frame_buffer(); | |
79 id<RTCVideoFrameBuffer> rtcFrameBuffer; | |
80 rtc::scoped_refptr<webrtc::ObjCFrameBuffer> objc_frame_buffer( | |
81 static_cast<webrtc::ObjCFrameBuffer *>(video_frame_buffer.get())); | |
82 rtcFrameBuffer = (id<RTCVideoFrameBuffer>)objc_frame_buffer->wrapped_frame_b
uffer(); | |
83 | |
84 RTCVideoFrame *videoFrame = [[RTCVideoFrame alloc] | |
85 initWithBuffer:rtcFrameBuffer | |
86 rotation:static_cast<RTCVideoRotation>(decodedImage.rotation()) | |
87 timeStampNs:decodedImage.timestamp_us() * rtc::kNumNanosecsPerMicrose
c]; | |
88 videoFrame.timeStamp = decodedImage.timestamp(); | |
89 | |
90 callback(videoFrame); | |
91 | |
92 return 0; | |
93 } | |
94 | |
95 RTCVideoDecoderCallback callback; | |
96 }; | |
97 | |
98 } // namespace | |
99 | |
100 // Encoder. | |
101 @implementation RTCVideoEncoderH264 { | |
102 webrtc::H264VideoToolboxEncoder *_videoToolboxEncoder; | |
103 H264VideoToolboxEncodeCompleteCallback *_toolboxCallback; | |
104 } | |
105 | |
106 - (instancetype)initWithCodecInfo:(RTCVideoCodecInfo *)codecInfo { | |
107 if (self = [super init]) { | |
108 cricket::VideoCodec codec = [codecInfo toCpp]; | |
109 _videoToolboxEncoder = new webrtc::H264VideoToolboxEncoder(codec); | |
110 } | |
111 return self; | |
112 } | |
113 | |
114 - (void)setCallback:(RTCVideoEncoderCallback)callback { | |
115 _toolboxCallback = new H264VideoToolboxEncodeCompleteCallback(); | |
116 _toolboxCallback->callback = callback; | |
117 _videoToolboxEncoder->RegisterEncodeCompleteCallback(_toolboxCallback); | |
118 } | |
119 | |
120 - (int)initEncodeWithSettings:(RTCVideoEncoderSettings *)settings numberOfCores:
(int)numberOfCores { | |
121 webrtc::VideoCodec *codecSettings = [settings toCpp]; | |
122 return _videoToolboxEncoder->InitEncode(codecSettings, numberOfCores, kDefault
PayloadSize); | |
123 } | |
124 | |
125 - (int)releaseEncode { | |
126 return _videoToolboxEncoder->Release(); | |
127 } | |
128 | |
129 - (int)encode:(RTCVideoFrame *)frame | |
130 codecSpecificInfo:(id<RTCCodecSpecificInfo>)info | |
131 frameTypes:(NSArray<NSNumber *> *)frameTypes { | |
132 rtc::scoped_refptr<webrtc::VideoFrameBuffer> frameBuffer = | |
133 new rtc::RefCountedObject<webrtc::ObjCFrameBuffer>(frame.buffer); | |
134 webrtc::VideoFrame videoFrame(frameBuffer, | |
135 (webrtc::VideoRotation)frame.rotation, | |
136 frame.timeStampNs / rtc::kNumNanosecsPerMicrosec
); | |
137 videoFrame.set_timestamp(frame.timeStamp); | |
138 | |
139 // Handle types than can be converted into one of webrtc::CodecSpecificInfo's
hard coded cases. | |
140 webrtc::CodecSpecificInfo codecSpecificInfo; | |
141 if ([info isKindOfClass:[RTCCodecSpecificInfoH264 class]]) { | |
142 codecSpecificInfo = [(RTCCodecSpecificInfoH264 *)info toCpp]; | |
143 } | |
144 | |
145 std::vector<webrtc::FrameType> nativeFrameTypes; | |
146 for (NSNumber *frameType in frameTypes) { | |
147 RTCFrameType rtcFrameType = (RTCFrameType)frameType.unsignedIntegerValue; | |
148 nativeFrameTypes.push_back((webrtc::FrameType)rtcFrameType); | |
149 } | |
150 | |
151 return _videoToolboxEncoder->Encode(videoFrame, &codecSpecificInfo, &nativeFra
meTypes); | |
152 } | |
153 | |
154 - (BOOL)setBitrate:(uint32_t)bitrateKbit framerate:(uint32_t)framerate { | |
155 return _videoToolboxEncoder->SetRates(bitrateKbit, framerate) == WEBRTC_VIDEO_
CODEC_OK; | |
156 } | |
157 | |
158 @end | |
159 | |
160 // Decoder. | |
161 @implementation RTCVideoDecoderH264 { | |
162 webrtc::H264VideoToolboxDecoder *_videoToolboxDecoder; | |
163 H264VideoToolboxDecodeCompleteCallback *_toolboxCallback; | |
164 } | |
165 | |
166 - (instancetype)init { | |
167 if (self = [super init]) { | |
168 cricket::VideoCodec codec(cricket::kH264CodecName); | |
169 _videoToolboxDecoder = new webrtc::H264VideoToolboxDecoder(); | |
170 } | |
171 return self; | |
172 } | |
173 | |
174 - (int)initDecodeWithSettings:(RTCVideoEncoderSettings *)settings numberOfCores:
(int)numberOfCores { | |
175 webrtc::VideoCodec *codecSettings = [settings toCpp]; | |
176 return _videoToolboxDecoder->InitDecode(codecSettings, numberOfCores); | |
177 } | |
178 | |
179 - (void)setCallback:(RTCVideoDecoderCallback)callback { | |
180 _toolboxCallback = new H264VideoToolboxDecodeCompleteCallback(); | |
181 _toolboxCallback->callback = callback; | |
182 _videoToolboxDecoder->RegisterDecodeCompleteCallback(_toolboxCallback); | |
183 } | |
184 | |
185 - (int32_t)releaseDecode { | |
186 return _videoToolboxDecoder->Release(); | |
187 } | |
188 | |
189 - (int)decode:(RTCEncodedImage *)encodedImage | |
190 missingFrames:(BOOL)missingFrames | |
191 fragmentationHeader:(RTCRtpFragmentationHeader *)fragmentationHeader | |
192 codecSpecificInfo:(__nullable id<RTCCodecSpecificInfo>)info | |
193 renderTimeMs:(int64_t)renderTimeMs { | |
194 webrtc::EncodedImage image = [encodedImage toCpp]; | |
195 | |
196 // Handle types than can be converted into one of webrtc::CodecSpecificInfo's
hard coded cases. | |
197 webrtc::CodecSpecificInfo codecSpecificInfo; | |
198 if ([info isKindOfClass:[RTCCodecSpecificInfoH264 class]]) { | |
199 codecSpecificInfo = [(RTCCodecSpecificInfoH264 *)info toCpp]; | |
200 } | |
201 | |
202 webrtc::RTPFragmentationHeader *header = [fragmentationHeader toCpp]; | |
203 | |
204 return _videoToolboxDecoder->Decode( | |
205 image, missingFrames, header, &codecSpecificInfo, renderTimeMs); | |
206 } | |
207 | |
208 @end | |
209 | |
210 // Encoder factory. | |
211 @implementation RTCVideoEncoderFactoryH264 | |
212 | |
213 - (NSArray<RTCVideoCodecInfo *> *)supportedCodecs { | |
214 NSMutableArray<RTCVideoCodecInfo *> *codecs = [NSMutableArray array]; | |
215 NSString *codecName = [NSString stringWithUTF8String:cricket::kH264CodecName]; | |
216 | |
217 if (IsHighProfileEnabled()) { | |
218 NSDictionary<NSString *, NSString *> *constrainedHighParams = @{ | |
219 @"profile-level-id" : @"640c1f", // Level 3.1 Constrained High. | |
220 @"level-asymmetry-allowed" : @"1", | |
221 @"packetization-mode" : @"1", | |
222 }; | |
223 RTCVideoCodecInfo *constrainedHighInfo = | |
224 [[RTCVideoCodecInfo alloc] initWithPayload:0 | |
225 name:codecName | |
226 parameters:constrainedHighParams]; | |
227 [codecs addObject:constrainedHighInfo]; | |
228 } | |
229 | |
230 NSDictionary<NSString *, NSString *> *constrainedBaselineParams = @{ | |
231 @"profile-level-id" : @"42e01f", // Level 3.1 Constrained Baseline. | |
232 @"level-asymmetry-allowed" : @"1", | |
233 @"packetization-mode" : @"1", | |
234 }; | |
235 RTCVideoCodecInfo *constrainedBaselineInfo = | |
236 [[RTCVideoCodecInfo alloc] initWithPayload:0 | |
237 name:codecName | |
238 parameters:constrainedBaselineParams]; | |
239 [codecs addObject:constrainedBaselineInfo]; | |
240 | |
241 return [codecs copy]; | |
242 } | |
243 | |
244 - (id<RTCVideoEncoder>)createEncoder:(RTCVideoCodecInfo *)info { | |
245 return [[RTCVideoEncoderH264 alloc] initWithCodecInfo:info]; | |
246 } | |
247 | |
248 @end | |
249 | |
250 // Decoder factory. | |
251 @implementation RTCVideoDecoderFactoryH264 | |
252 | |
253 - (id<RTCVideoDecoder>)createDecoder:(RTCVideoCodecInfo *)info { | |
254 return [[RTCVideoDecoderH264 alloc] init]; | |
255 } | |
256 | |
257 - (NSArray<RTCVideoCodecInfo *> *)supportedCodecs { | |
258 NSString *codecName = [NSString stringWithUTF8String:cricket::kH264CodecName]; | |
259 return @[ [[RTCVideoCodecInfo alloc] initWithPayload:0 name:codecName paramete
rs:@{}] ]; | |
260 } | |
261 | |
262 @end | |
OLD | NEW |