• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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