1 /*
2 * Copyright (c) 2023 Shenzhen Kaihong Digital Industry Development Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "rtp_codec_h264.h"
17 #include <securec.h>
18 #include "common/common_macro.h"
19 #include "common/media_log.h"
20 #include "frame/h264_frame.h"
21
22 namespace OHOS {
23 namespace Sharing {
24 class FuFlags {
25 public:
26 #if __BYTE_ORDER == __BIG_ENDIAN
27 unsigned startBit_ : 1;
28 unsigned endBit_ : 1;
29 unsigned reserved : 1;
30 unsigned nalType : 5;
31 #else
32 unsigned nalType_ : 5;
33 unsigned reserved_ : 1;
34 unsigned endBit_ : 1;
35 unsigned startBit_ : 1;
36 #endif
37 } __attribute__((packed));
38
RtpDecoderH264()39 RtpDecoderH264::RtpDecoderH264()
40 {
41 MEDIA_LOGD("trace.");
42 frame_ = ObtainFrame();
43 }
44
~RtpDecoderH264()45 RtpDecoderH264::~RtpDecoderH264() {}
46
InputRtp(const RtpPacket::Ptr & rtp)47 void RtpDecoderH264::InputRtp(const RtpPacket::Ptr &rtp)
48 {
49 RETURN_IF_NULL(rtp);
50 auto frame = rtp->GetPayload();
51 int32_t length = rtp->GetPayloadSize();
52 auto stamp = rtp->GetStampMS();
53 auto seq = rtp->GetSeq();
54 int32_t nal = H264_TYPE(frame[0]);
55 MEDIA_LOGD("rtpDecoderH264::InputRtp length: %{public}d, stamp: %{public}d, seq: %{public}d, nal: %{public}d.",
56 length, stamp, seq, nal);
57
58 switch (nal) {
59 case 24: // 24:STAP-A Single-time aggregation packet 5.7.1
60 UnpackStapA(rtp, frame + 1, length - 1, stamp);
61 break;
62 case 28: // 28:FU-A Fragmentation unit
63 UnpackFuA(rtp, frame, length, stamp, seq);
64 break;
65 default: {
66 if (nal < 24) { // 24:STAP-A Single-time aggregation packet
67 // Single NAL Unit Packets
68 UnpackSingle(rtp, frame, length, stamp);
69 break;
70 }
71 gopDropped_ = true;
72 break;
73 }
74 }
75
76 if (!gopDropped_ && seq != (uint16_t)(lastSeq_ + 1) && lastSeq_) {
77 gopDropped_ = true;
78 }
79 lastSeq_ = seq;
80 }
81
SetOnFrame(const OnFrame & cb)82 void RtpDecoderH264::SetOnFrame(const OnFrame &cb)
83 {
84 onFrame_ = cb;
85 }
86
UnpackSingle(const RtpPacket::Ptr & rtp,const uint8_t * ptr,ssize_t size,uint32_t stamp)87 bool RtpDecoderH264::UnpackSingle(const RtpPacket::Ptr &rtp, const uint8_t *ptr, ssize_t size, uint32_t stamp)
88 {
89 RETURN_FALSE_IF_NULL(frame_);
90 RETURN_FALSE_IF_NULL(ptr);
91 MEDIA_LOGD("rtpDecoderH264::UnpackSingle.");
92 frame_->Assign("\x00\x00\x00\x01", 4); // 4:avc start code size
93 frame_->Append((char *)ptr, size);
94 frame_->pts_ = stamp;
95 auto key = frame_->KeyFrame();
96 OutputFrame(rtp, frame_);
97 return key;
98 }
99
UnpackStapA(const RtpPacket::Ptr & rtp,const uint8_t * ptr,ssize_t size,uint32_t stamp)100 bool RtpDecoderH264::UnpackStapA(const RtpPacket::Ptr &rtp, const uint8_t *ptr, ssize_t size, uint32_t stamp)
101 {
102 RETURN_FALSE_IF_NULL(rtp);
103 RETURN_FALSE_IF_NULL(ptr);
104
105 auto haveKeyFrame = false;
106 auto end = ptr + size;
107 while (ptr + 2 < end) { // 2:fixed size
108 uint16_t len = (ptr[0] << 8) | ptr[1]; // 8:byte offset
109 if (!len || ptr + len > end) {
110 gopDropped_ = true;
111 break;
112 }
113 ptr += 2; // 2:fixed size
114 if (UnpackSingle(rtp, ptr, len, stamp)) {
115 haveKeyFrame = true;
116 }
117 ptr += len;
118 }
119
120 return haveKeyFrame;
121 }
122
UnpackFuA(const RtpPacket::Ptr & rtp,const uint8_t * ptr,ssize_t size,uint32_t stamp,uint16_t seq)123 bool RtpDecoderH264::UnpackFuA(const RtpPacket::Ptr &rtp, const uint8_t *ptr, ssize_t size, uint32_t stamp,
124 uint16_t seq)
125 {
126 RETURN_FALSE_IF_NULL(rtp);
127 RETURN_FALSE_IF_NULL(ptr);
128 RETURN_FALSE_IF_NULL(frame_);
129 auto nalSuffix = *ptr & (~0x1F);
130 FuFlags *fu = (FuFlags *)(ptr + 1);
131 if (fu->startBit_) {
132 frame_->Assign("\x00\x00\x00\x01", 4); // 4:avc start code size
133 uint8_t flag = nalSuffix | fu->nalType_;
134 frame_->Append(&flag, 1);
135 frame_->pts_ = stamp;
136 fuDropped_ = false;
137 }
138
139 if (fuDropped_) {
140 return false;
141 }
142
143 if (!fu->startBit_ && seq != (uint16_t)(lastSeq_ + 1)) {
144 fuDropped_ = true;
145 frame_->Clear();
146 return false;
147 }
148
149 frame_->Append((char *)ptr + 2, size - 2); // 2:fixed size
150
151 if (!fu->endBit_) {
152 return fu->startBit_ ? frame_->KeyFrame() : false;
153 }
154
155 fuDropped_ = true;
156
157 OutputFrame(rtp, frame_);
158 return false;
159 }
160
ObtainFrame()161 H264Frame::Ptr RtpDecoderH264::ObtainFrame()
162 {
163 auto frame = std::make_shared<H264Frame>();
164 frame->prefixSize_ = 4; // 4:fixed size
165 return frame;
166 }
167
OutputFrame(const RtpPacket::Ptr & rtp,const H264Frame::Ptr & frame)168 void RtpDecoderH264::OutputFrame(const RtpPacket::Ptr &rtp, const H264Frame::Ptr &frame)
169 {
170 RETURN_IF_NULL(rtp);
171 RETURN_IF_NULL(frame);
172 if (frame->KeyFrame() && gopDropped_) {
173 gopDropped_ = false;
174 MEDIA_LOGD("new gop received.");
175 }
176
177 if (!gopDropped_) {
178 onFrame_(frame);
179 }
180 frame_ = ObtainFrame();
181 }
182
RtpEncoderH264(uint32_t ssrc,uint32_t mtuSize,uint32_t sampleRate,uint8_t payloadType,uint16_t seq)183 RtpEncoderH264::RtpEncoderH264(uint32_t ssrc, uint32_t mtuSize, uint32_t sampleRate, uint8_t payloadType, uint16_t seq)
184 : RtpMaker(ssrc, mtuSize, payloadType, sampleRate, seq)
185 {}
186
~RtpEncoderH264()187 RtpEncoderH264::~RtpEncoderH264() {}
188
InputFrame(const Frame::Ptr & frame)189 void RtpEncoderH264::InputFrame(const Frame::Ptr &frame)
190 {
191 RETURN_IF_NULL(frame);
192 auto ptr = frame->Data() + frame->PrefixSize();
193 switch (H264_TYPE(ptr[0])) {
194 case H264Frame::NAL_SPS: {
195 sps_ = frame;
196 return;
197 }
198 case H264Frame::NAL_PPS: {
199 pps_ = frame;
200 return;
201 }
202 default:
203 break;
204 }
205
206 if (lastFrame_) {
207 InputFrame(lastFrame_, lastFrame_->Pts() != frame->Pts());
208 }
209 lastFrame_ = frame;
210 }
211
SetOnRtpPack(const OnRtpPack & cb)212 void RtpEncoderH264::SetOnRtpPack(const OnRtpPack &cb)
213 {
214 onRtpPack_ = cb;
215 }
216
InsertConfigFrame(uint32_t pts)217 void RtpEncoderH264::InsertConfigFrame(uint32_t pts)
218 {
219 if (!sps_ || !pps_) {
220 return;
221 }
222
223 PackRtp(sps_->Data() + sps_->PrefixSize(), sps_->Size() - sps_->PrefixSize(), pts, false, false);
224 PackRtp(pps_->Data() + pps_->PrefixSize(), pps_->Size() - pps_->PrefixSize(), pts, false, false);
225 }
226
InputFrame(const Frame::Ptr & frame,bool isMark)227 bool RtpEncoderH264::InputFrame(const Frame::Ptr &frame, bool isMark)
228 {
229 RETURN_FALSE_IF_NULL(frame);
230 if (frame->KeyFrame()) {
231 InsertConfigFrame(frame->Pts());
232 }
233 PackRtp(frame->Data() + frame->PrefixSize(), frame->Size() - frame->PrefixSize(), frame->Pts(), isMark, false);
234 return true;
235 }
236
PackRtp(const uint8_t * data,size_t len,uint32_t pts,bool isMark,bool gopPos)237 void RtpEncoderH264::PackRtp(const uint8_t *data, size_t len, uint32_t pts, bool isMark, bool gopPos)
238 {
239 RETURN_IF_NULL(data);
240 if (len <= GetMaxSize()) {
241 PackSingle(data, len, pts, isMark, gopPos);
242 } else {
243 PackRtpFu(data, len, pts, isMark, gopPos);
244 }
245 }
246
PackRtpFu(const uint8_t * data,size_t len,uint32_t pts,bool isMark,bool gopPos)247 void RtpEncoderH264::PackRtpFu(const uint8_t *data, size_t len, uint32_t pts, bool isMark, bool gopPos)
248 {
249 RETURN_IF_NULL(data);
250 auto packetSize = GetMaxSize() - 2; // 2:fixed size
251 if (len <= packetSize + 1) {
252 PackRtpStapA(data, len, pts, isMark, gopPos);
253 return;
254 }
255
256 auto fuChar0 = (data[0] & (~0x1F)) | 28; // 28:fixed size
257 auto fuChar1 = H264_TYPE(data[0]);
258 FuFlags *fuFlags = (FuFlags *)(&fuChar1);
259 fuFlags->startBit_ = 1;
260
261 size_t offset = 1;
262 while (!fuFlags->endBit_) {
263 if (!fuFlags->startBit_ && len <= offset + packetSize) {
264 // FU-A end
265 packetSize = len - offset;
266 fuFlags->endBit_ = 1;
267 }
268
269 auto rtp = MakeRtp(nullptr, packetSize + 2, fuFlags->endBit_ && isMark, pts); // 2:fixed size
270
271 uint8_t *payload = rtp->GetPayload();
272
273 payload[0] = fuChar0;
274
275 payload[1] = fuChar1;
276
277 auto ret = memcpy_s(payload + 2, packetSize, (uint8_t *)data + offset, packetSize); // 2:fixed size
278 if (ret != EOK) {
279 return;
280 }
281
282 offset += packetSize;
283 fuFlags->startBit_ = 0;
284 onRtpPack_(rtp);
285 }
286 }
287
PackRtpStapA(const uint8_t * data,size_t len,uint32_t pts,bool isMark,bool gopPos)288 void RtpEncoderH264::PackRtpStapA(const uint8_t *data, size_t len, uint32_t pts, bool isMark, bool gopPos)
289 {
290 RETURN_IF_NULL(data);
291 auto rtp = MakeRtp(nullptr, len + 3, isMark, pts); // 3:fixed size
292 uint8_t *payload = rtp->GetPayload();
293 // STAP-A
294 payload[0] = (data[0] & (~0x1F)) | 24; // 24:fixed size
295 payload[1] = (len >> 8) & 0xFF; // 8:byte offset
296 payload[2] = len & 0xff; // 2:byte offset
297 auto ret = memcpy_s(payload + 3, len, (uint8_t *)data, len); // 3:fixed size
298 if (ret != EOK) {
299 return;
300 }
301
302 onRtpPack_(rtp);
303 }
304
PackSingle(const uint8_t * data,size_t len,uint32_t pts,bool isMark,bool gopPos)305 void RtpEncoderH264::PackSingle(const uint8_t *data, size_t len, uint32_t pts, bool isMark, bool gopPos)
306 {
307 RETURN_IF_NULL(data);
308 // single NAl unit packet
309 auto rtp = MakeRtp(data, len, isMark, pts);
310 onRtpPack_(rtp);
311 }
312 } // namespace Sharing
313 } // namespace OHOS