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/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 - (void)initEncodeWithSettings:(RTCVideoEncoderSettings *)settings | |
121 numberOfCores:(int)numberOfCores { | |
122 webrtc::VideoCodec *codecSettings = [settings toCpp]; | |
123 _videoToolboxEncoder->InitEncode(codecSettings, numberOfCores, kDefaultPayload
Size); | |
124 } | |
125 | |
126 - (void)releaseEncode { | |
127 _videoToolboxEncoder->Release(); | |
128 } | |
129 | |
130 - (void)encode:(RTCVideoFrame *)frame | |
131 codecSpecificInfo:(id<RTCCodecSpecificInfo>)info | |
132 frameTypes:(NSArray<NSNumber *> *)frameTypes { | |
133 rtc::scoped_refptr<webrtc::VideoFrameBuffer> frameBuffer = | |
134 new rtc::RefCountedObject<webrtc::ObjCFrameBuffer>(frame.buffer); | |
135 webrtc::VideoFrame videoFrame(frameBuffer, | |
136 (webrtc::VideoRotation)frame.rotation, | |
137 frame.timeStampNs / rtc::kNumNanosecsPerMicrosec
); | |
138 videoFrame.set_timestamp(frame.timeStamp); | |
139 | |
140 // Handle types than can be converted into one of webrtc::CodecSpecificInfo's
hard coded cases. | |
141 webrtc::CodecSpecificInfo codecSpecificInfo; | |
142 if ([info isKindOfClass:[RTCCodecSpecificInfoH264 class]]) { | |
143 codecSpecificInfo = [(RTCCodecSpecificInfoH264 *)info toCpp]; | |
144 } | |
145 | |
146 std::vector<webrtc::FrameType> nativeFrameTypes; | |
147 for (NSNumber *frameType in frameTypes) { | |
148 RTCFrameType rtcFrameType = (RTCFrameType)frameType.unsignedIntegerValue; | |
149 nativeFrameTypes.push_back((webrtc::FrameType)rtcFrameType); | |
150 } | |
151 | |
152 _videoToolboxEncoder->Encode(videoFrame, &codecSpecificInfo, &nativeFrameTypes
); | |
153 } | |
154 | |
155 - (BOOL)setBitrate:(uint32_t)bitrateKbit framerate:(uint32_t)framerate { | |
156 return _videoToolboxEncoder->SetRates(bitrateKbit, framerate) == WEBRTC_VIDEO_
CODEC_OK; | |
157 } | |
158 | |
159 @end | |
160 | |
161 // Decoder. | |
162 @implementation RTCVideoDecoderH264 { | |
163 webrtc::H264VideoToolboxDecoder *_videoToolboxDecoder; | |
164 H264VideoToolboxDecodeCompleteCallback *_toolboxCallback; | |
165 } | |
166 | |
167 - (instancetype)init { | |
168 if (self = [super init]) { | |
169 cricket::VideoCodec codec(cricket::kH264CodecName); | |
170 _videoToolboxDecoder = new webrtc::H264VideoToolboxDecoder(); | |
171 } | |
172 return self; | |
173 } | |
174 | |
175 - (int)initDecodeWithSettings:(RTCVideoEncoderSettings *)settings numberOfCores:
(int)numberOfCores { | |
176 webrtc::VideoCodec *codecSettings = [settings toCpp]; | |
177 return _videoToolboxDecoder->InitDecode(codecSettings, numberOfCores); | |
178 } | |
179 | |
180 - (void)setCallback:(RTCVideoDecoderCallback)callback { | |
181 _toolboxCallback = new H264VideoToolboxDecodeCompleteCallback(); | |
182 _toolboxCallback->callback = callback; | |
183 _videoToolboxDecoder->RegisterDecodeCompleteCallback(_toolboxCallback); | |
184 } | |
185 | |
186 - (int32_t)releaseDecode { | |
187 return _videoToolboxDecoder->Release(); | |
188 } | |
189 | |
190 - (int)decode:(RTCEncodedImage *)encodedImage | |
191 missingFrames:(BOOL)missingFrames | |
192 fragmentationHeader:(RTCRtpFragmentationHeader *)fragmentationHeader | |
193 codecSpecificInfo:(__nullable id<RTCCodecSpecificInfo>)info | |
194 renderTimeMs:(int64_t)renderTimeMs { | |
195 webrtc::EncodedImage image = [encodedImage toCpp]; | |
196 | |
197 // Handle types than can be converted into one of webrtc::CodecSpecificInfo's
hard coded cases. | |
198 webrtc::CodecSpecificInfo codecSpecificInfo; | |
199 if ([info isKindOfClass:[RTCCodecSpecificInfoH264 class]]) { | |
200 codecSpecificInfo = [(RTCCodecSpecificInfoH264 *)info toCpp]; | |
201 } | |
202 | |
203 webrtc::RTPFragmentationHeader *header = [fragmentationHeader toCpp]; | |
204 | |
205 return _videoToolboxDecoder->Decode( | |
206 image, missingFrames, header, &codecSpecificInfo, renderTimeMs); | |
207 } | |
208 | |
209 @end | |
210 | |
211 // Encoder factory. | |
212 @implementation RTCVideoEncoderFactoryH264 | |
213 | |
214 - (NSArray<RTCVideoCodecInfo *> *)supportedCodecs { | |
215 NSMutableArray<RTCVideoCodecInfo *> *codecs = [NSMutableArray array]; | |
216 NSString *codecName = [NSString stringWithUTF8String:cricket::kH264CodecName]; | |
217 | |
218 if (IsHighProfileEnabled()) { | |
219 NSDictionary<NSString *, NSString *> *constrainedHighParams = @{ | |
220 @"profile-level-id" : @"640c1f", // Level 3.1 Constrained High. | |
221 @"level-asymmetry-allowed" : @"1", | |
222 @"packetization-mode" : @"1", | |
223 }; | |
224 RTCVideoCodecInfo *constrainedHighInfo = | |
225 [[RTCVideoCodecInfo alloc] initWithPayload:0 | |
226 name:codecName | |
227 parameters:constrainedHighParams]; | |
228 [codecs addObject:constrainedHighInfo]; | |
229 } | |
230 | |
231 NSDictionary<NSString *, NSString *> *constrainedBaselineParams = @{ | |
232 @"profile-level-id" : @"42e01f", // Level 3.1 Constrained Baseline. | |
233 @"level-asymmetry-allowed" : @"1", | |
234 @"packetization-mode" : @"1", | |
235 }; | |
236 RTCVideoCodecInfo *constrainedBaselineInfo = | |
237 [[RTCVideoCodecInfo alloc] initWithPayload:0 | |
238 name:codecName | |
239 parameters:constrainedBaselineParams]; | |
240 [codecs addObject:constrainedBaselineInfo]; | |
241 | |
242 return [codecs copy]; | |
243 } | |
244 | |
245 - (id<RTCVideoEncoder>)createEncoder:(RTCVideoCodecInfo *)info { | |
246 return [[RTCVideoEncoderH264 alloc] initWithCodecInfo:info]; | |
247 } | |
248 | |
249 @end | |
250 | |
251 // Decoder factory. | |
252 @implementation RTCVideoDecoderFactoryH264 | |
253 | |
254 - (id<RTCVideoDecoder>)createDecoder:(RTCVideoCodecInfo *)info { | |
255 return [[RTCVideoDecoderH264 alloc] init]; | |
256 } | |
257 | |
258 - (NSArray<RTCVideoCodecInfo *> *)supportedCodecs { | |
259 NSString *codecName = [NSString stringWithUTF8String:cricket::kH264CodecName]; | |
260 return @[ [[RTCVideoCodecInfo alloc] initWithPayload:0 name:codecName paramete
rs:@{}] ]; | |
261 } | |
262 | |
263 @end | |
OLD | NEW |