1 /*
2  * Copyright (C) 2022 Huawei Device 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 "fillp_frame.h"
17 #include "fillp_common.h"
18 
19 #define FRAME_VIDEO_FRAME_TYPE_STR(_type) (((_type) == VIDEO_I) ? "I" : "P")
20 
21 #ifdef __cplusplus
22 extern "C" {
23 #endif
24 
FillpFrameInit(struct FillpFrameHandle * h)25 void FillpFrameInit(struct FillpFrameHandle *h)
26 {
27     if (h != FILLP_NULL_PTR) {
28         (void)memset_s(h, sizeof(struct FillpFrameHandle), 0, sizeof(struct FillpFrameHandle));
29     }
30 }
31 
FillpFrameItemHold(struct FillpFrameItem * frameItem)32 static inline void FillpFrameItemHold(struct FillpFrameItem *frameItem)
33 {
34     FILLP_INT refCnt = SYS_ARCH_ATOMIC_INC(&frameItem->refCnt, 1);
35     FILLP_LOGDBG("item refcnt: %d, seq: %d", refCnt, frameItem->info.seqNum);
36 }
37 
FillpFrameItemPut(struct FillpFrameItem * frameItem)38 void FillpFrameItemPut(struct FillpFrameItem *frameItem)
39 {
40     if (frameItem != FILLP_NULL_PTR) {
41         if (SYS_ARCH_ATOMIC_DEC_AND_TEST(&frameItem->refCnt)) {
42             FILLP_LOGDBG("free frame item of seq: %d", frameItem->info.seqNum);
43             SpungeFree(frameItem, SPUNGE_ALLOC_TYPE_CALLOC);
44         }
45     }
46 }
47 
FillpFrameItemAlloc(FILLP_CONST struct FrameInfo * frame)48 struct FillpFrameItem *FillpFrameItemAlloc(FILLP_CONST struct FrameInfo *frame)
49 {
50     struct FillpFrameItem *frameItem = FILLP_NULL_PTR;
51 
52     if (frame != FILLP_NULL_PTR) {
53         frameItem = SpungeAlloc(1, sizeof(struct FillpFrameItem), SPUNGE_ALLOC_TYPE_CALLOC);
54         if (frameItem == FILLP_NULL_PTR) {
55             FILLP_LOGERR("alloc frame item failed, seq: %d", frame->seqNum);
56         } else {
57             frameItem->info = *frame;
58             /* hold the frame item until the sending of socket app ended */
59             FillpFrameItemHold(frameItem);
60             FILLP_LOGDBG("alloc frame item succeeded, seq: %d", frame->seqNum);
61         }
62     }
63 
64     return frameItem;
65 }
66 
FillpFrameItemReference(struct FillpPcbItem * item,struct FillpFrameItem * frameItem)67 void FillpFrameItemReference(struct FillpPcbItem *item, struct FillpFrameItem *frameItem)
68 {
69     if (frameItem != FILLP_NULL_PTR) {
70         FillpFrameItemHold(frameItem);
71         item->frame = frameItem;
72     } else {
73         item->frame = FILLP_NULL_PTR;
74     }
75 }
76 
FillpFrameAddItemStats(struct FillpFrameHandle * h,FILLP_INT frameType,FILLP_UINT32 size,FILLP_BOOL newFrame)77 static void FillpFrameAddItemStats(struct FillpFrameHandle *h, FILLP_INT frameType,
78     FILLP_UINT32 size, FILLP_BOOL newFrame)
79 {
80     if (frameType == VIDEO_I) {
81         if (newFrame) {
82             h->stats.iFrameCount++;
83         }
84         h->stats.iFrameTotalSize += size;
85     } else {
86         if (newFrame) {
87             h->stats.pFrameCount++;
88         }
89         h->stats.pFrameTotalSize += size;
90     }
91 }
92 
FillpFrameAddItem(struct FillpFrameHandle * h,struct FillpPcbItem * item)93 FILLP_INT FillpFrameAddItem(struct FillpFrameHandle *h, struct FillpPcbItem *item)
94 {
95     struct FrameInfo *info = FILLP_NULL_PTR;
96 
97     if (item->frame == FILLP_NULL_PTR || !FILLP_FRAME_IS_VIDEO(item->frame->info.frameType)) {
98         return NONE;
99     }
100 
101     info = &item->frame->info;
102 
103     if (UTILS_FLAGS_CHECK(item->flags, FILLP_ITEM_FLAGS_FIRST_PKT)) {
104         FillpFrameAddItemStats(h, info->frameType, item->frame->fragSize,
105             UTILS_FLAGS_CHECK(item->flags, FILLP_ITEM_FLAGS_FRAME_FIRST_FRAG_START));
106     }
107 
108     /* check FRAME_FLAGS_FIRST_FRAG_START after FRAME_FLAGS_FIRST_FRAG_PKT to statistics the fragment */
109     if (!UTILS_FLAGS_CHECK(item->flags, FILLP_ITEM_FLAGS_FRAME_FIRST_FRAG_START)) {
110         return NONE;
111     }
112 
113     return info->frameType;
114 }
115 
FillpFrameFreeItem(struct FillpPcbItem * item)116 void FillpFrameFreeItem(struct FillpPcbItem *item)
117 {
118     FillpFrameItemPut(item->frame);
119     item->frame = FILLP_NULL_PTR;
120 }
121 
FillpFrameTxInitItem(struct FillpFrameHandle * h,struct FillpPcbItem * item,const struct FrameInfo * info,FILLP_UINT32 fragSize,FILLP_BOOL firstPkt)122 void FillpFrameTxInitItem(struct FillpFrameHandle *h, struct FillpPcbItem *item,
123     const struct FrameInfo *info, FILLP_UINT32 fragSize, FILLP_BOOL firstPkt)
124 {
125     if (item->frame != FILLP_NULL_PTR && info != FILLP_NULL_PTR && FILLP_FRAME_IS_VIDEO(info->frameType)) {
126         item->frame->fragSize = fragSize;
127 
128         if (firstPkt) {
129             if (h->curFrame.info.size == 0 || (FILLP_UINT32)info->seqNum != h->curFrame.info.seqNum) {
130                 FILLP_LOGDBG("start sending a new frame, seq: %d", info->seqNum);
131                 UTILS_FLAGS_SET(item->flags, FILLP_ITEM_FLAGS_FRAME_FIRST_FRAG_START);
132                 h->curFrame.info.type = info->frameType;
133                 h->curFrame.info.seqNum = (FILLP_UINT32)info->seqNum;
134                 h->curFrame.info.size = fragSize;
135                 h->curFrame.info.fragCnt = 1;
136             } else {
137                 h->curFrame.info.size += fragSize;
138                 h->curFrame.info.fragCnt++;
139             }
140 
141             if (UTILS_FLAGS_CHECK(info->bitMap, FRAME_INFO_BITMAP_FRAME_END)) {
142                 UTILS_FLAGS_SET(item->flags, FILLP_ITEM_FLAGS_FRAME_LAST_FRAG_START);
143                 FILLP_LOGDBG("frame %d end, total size: %u", info->seqNum, h->curFrame.info.size);
144             }
145 
146             UTILS_FLAGS_SET(item->dataOptFlag, FILLP_OPT_FLAG_FRAME_INFO);
147             FILLP_LOGDBG("set the first pkt flag of seq: %d, seqNo %d", info->seqNum, info->subSeqNum);
148         }
149     }
150 }
151 
FillpFrameGetPktDataOptLen(FILLP_UINT32 flag,FILLP_UINT32 pktDataOptLen)152 FILLP_UINT32 FillpFrameGetPktDataOptLen(FILLP_UINT32 flag, FILLP_UINT32 pktDataOptLen)
153 {
154     FILLP_UINT32 optLen = pktDataOptLen;
155     if (UTILS_FLAGS_CHECK(flag, FILLP_OPT_FLAG_FRAME_INFO)) {
156         optLen = UTILS_MAX(pktDataOptLen, FILLP_DATA_OFFSET_LEN);
157         optLen += FILLP_OPT_FRAME_INFO_LEN + FILLP_DATA_OPT_HLEN;
158     }
159 
160     return optLen;
161 }
162 
FillpFrameBuildOption(const struct FillpPcbItem * item,FILLP_UINT8 * option)163 FILLP_UINT16 FillpFrameBuildOption(const struct FillpPcbItem *item, FILLP_UINT8 *option)
164 {
165     const struct FrameInfo *info = FILLP_NULL_PTR;
166     FillpDataOption *dataOpt = FILLP_NULL_PTR;
167     struct FillpFrameDataOption *frameOpt = FILLP_NULL_PTR;
168 
169     info = &item->frame->info;
170     dataOpt = (FillpDataOption *)option;
171     dataOpt->type = FILLP_OPT_FRAME_INFO;
172     dataOpt->len = FILLP_OPT_FRAME_INFO_LEN;
173 
174     frameOpt = (struct FillpFrameDataOption *)&dataOpt->value[0];
175     frameOpt->frameType = (FILLP_UINT8)info->frameType;
176     frameOpt->level = (FILLP_UINT8)info->level;
177     frameOpt->seqNum = FILLP_HTONS((FILLP_UINT16)info->seqNum);
178     frameOpt->subSeqNum = (FILLP_UINT8)info->subSeqNum;
179     frameOpt->bitMap = (FILLP_UINT8)(item->flags & FILLP_ITEM_FLAGS_FRAME_OPT_BITMAP_MASK);
180     frameOpt->fragSize = FILLP_HTONL(item->frame->fragSize);
181     frameOpt->txTimestamp = FILLP_HTONL((FILLP_UINT32)info->timestamp);
182 
183     FILLP_LOGDTL("fill option of frame %s, seq: %d, seqNo: %d, bitmap: 0x%x",
184         FRAME_VIDEO_FRAME_TYPE_STR(info->frameType), info->seqNum, info->subSeqNum, frameOpt->bitMap);
185 
186     return (FILLP_UINT16)(FILLP_DATA_OPT_HLEN + FILLP_OPT_FRAME_INFO_LEN);
187 }
188 
FillpFrameParseOption(struct FillpFrameHandle * h,struct FillpPcbItem * item,FILLP_UINT8 * option,FILLP_UINT8 optLen)189 FILLP_INT FillpFrameParseOption(struct FillpFrameHandle *h,
190     struct FillpPcbItem *item, FILLP_UINT8 *option, FILLP_UINT8 optLen)
191 {
192     struct FillpFrameDataOption *frameOpt = FILLP_NULL_PTR;
193     struct FillpFrameItem *frameItem = FILLP_NULL_PTR;
194     struct FrameInfo info;
195 
196     if (optLen < FILLP_OPT_FRAME_INFO_LEN) {
197         FILLP_LOGERR("invalid frame info len %u, seqNum: %u, pktNum: %u", optLen, item->seqNum, item->pktNum);
198         return FILLP_EINVAL;
199     }
200 
201     frameOpt = (struct FillpFrameDataOption *)option;
202 
203     (void)memset_s(&info, sizeof(info), 0, sizeof(info));
204     info.frameType = frameOpt->frameType;
205     info.level = frameOpt->level;
206     info.seqNum = FILLP_NTOHS(frameOpt->seqNum);
207     info.subSeqNum = frameOpt->subSeqNum;
208     info.timestamp = FILLP_NTOHL(frameOpt->txTimestamp);
209 
210     frameItem = FillpFrameItemAlloc(&info);
211     if (frameItem == FILLP_NULL_PTR) {
212         FILLP_LOGERR("alloc frame item failed, reset the rx status! seq: %d", info.seqNum);
213         h->curFrame.rxStarted = FILLP_FALSE;
214         return FILLP_OK;
215     }
216 
217     frameItem->fragSize = FILLP_NTOHL(frameOpt->fragSize);
218     FILLP_LOGDBG("get a fragment, seq: %d, fragment seq: %d, size: %u, timestamp: %ld, bitmap: 0x%x",
219         frameItem->info.seqNum, frameItem->info.subSeqNum, frameItem->fragSize,
220         frameItem->info.timestamp, frameOpt->bitMap);
221 
222     item->frame = frameItem;
223     UTILS_FLAGS_RESET(item->flags);
224     UTILS_FLAGS_SET(item->flags, (FILLP_UINT32)frameOpt->bitMap | FILLP_ITEM_FLAGS_FIRST_PKT);
225     return ERR_OK;
226 }
227 
FillpFrameRxNewFrag(struct FillpFrame * frame,const struct FillpPcbItem * item)228 static void FillpFrameRxNewFrag(struct FillpFrame *frame, const struct FillpPcbItem *item)
229 {
230     if (UTILS_FLAGS_CHECK(item->flags, FILLP_ITEM_FLAGS_FRAME_FIRST_FRAG_START)) {
231         frame->rxStarted = FILLP_TRUE;
232         frame->lastFragRecvd = FILLP_FALSE;
233         frame->info.firstPktRxTime = item->rxTimeStamp;
234         frame->info.lastPktRxTime = item->rxTimeStamp;
235         frame->info.size = 0;
236         frame->info.fragCnt = 0;
237         frame->info.totalItemCnt = 0;
238         frame->info.seqNum = (FILLP_UINT32)item->frame->info.seqNum;
239         frame->info.type = item->frame->info.frameType;
240         frame->info.txTimestamp = (FILLP_UINT32)item->frame->info.timestamp;
241     }
242 
243     if (!frame->rxStarted) {
244         FILLP_LOGERR("first fragment is NOT received!!!");
245         return;
246     }
247 
248     frame->info.size += item->frame->fragSize;
249     frame->info.fragCnt++;
250 
251     if (UTILS_FLAGS_CHECK(item->flags, FILLP_ITEM_FLAGS_FRAME_LAST_FRAG_START)) {
252         frame->lastFragRecvd = FILLP_TRUE;
253     }
254 
255     frame->curFrag.size = item->frame->fragSize;
256     frame->curFrag.procSize = 0;
257     frame->curFrag.seqNum = (FILLP_UINT32)item->frame->info.subSeqNum;
258 }
259 
FillpFrameStatistics(struct FillpFrameHandle * h)260 static inline void FillpFrameStatistics(struct FillpFrameHandle *h)
261 {
262     if (h->curFrame.info.type == VIDEO_I) {
263         h->stats.iFrameTotalSize += h->curFrame.info.size;
264         h->stats.iFrameCount++;
265     } else {
266         h->stats.pFrameTotalSize += h->curFrame.info.size;
267         h->stats.pFrameCount++;
268     }
269 }
270 
FillpFrameRxUpdateAndNotify(struct FillpFrameHandle * h,const struct FillpPcbItem * item)271 static void FillpFrameRxUpdateAndNotify(struct FillpFrameHandle *h, const struct FillpPcbItem *item)
272 {
273     h->curFrame.info.totalItemCnt++;
274     h->curFrame.info.firstPktRxTime = UTILS_MIN(h->curFrame.info.firstPktRxTime, item->rxTimeStamp);
275     h->curFrame.info.lastPktRxTime = UTILS_MAX(h->curFrame.info.lastPktRxTime, item->rxTimeStamp);
276 
277     h->curFrame.curFrag.procSize += item->dataLen;
278     if (h->curFrame.curFrag.size == h->curFrame.curFrag.procSize) {
279         if (h->curFrame.lastFragRecvd) {
280             FILLP_LOGINF("recv a %s frame, seq: %u, frame size: %u, fragment cnt: %u, total pkt cnt: %u,"
281                 " first pkt rx time: %lld, last pkt rx time: %lld",
282                 FRAME_VIDEO_FRAME_TYPE_STR(h->curFrame.info.type), h->curFrame.info.seqNum,
283                 h->curFrame.info.size, h->curFrame.info.fragCnt, h->curFrame.info.totalItemCnt,
284                 h->curFrame.info.firstPktRxTime, h->curFrame.info.lastPktRxTime);
285             if (h->rxCb != FILLP_NULL_PTR) {
286                 h->rxCb(h->rxCbArg, &h->curFrame.info);
287             }
288 
289             FillpFrameStatistics(h);
290             h->curFrame.rxStarted = FILLP_FALSE;
291         } else {
292             FILLP_LOGDBG("recv a fragment of %s frame, seq: %u, fragment seq: %u, size: %u",
293                 FRAME_VIDEO_FRAME_TYPE_STR(h->curFrame.info.type),
294                 h->curFrame.info.seqNum, h->curFrame.curFrag.seqNum, h->curFrame.curFrag.size);
295         }
296     }
297 }
298 
FillpFrameRx(struct FillpFrameHandle * h,const struct FillpPcbItem * item)299 void FillpFrameRx(struct FillpFrameHandle *h, const struct FillpPcbItem *item)
300 {
301     if (item->frame != FILLP_NULL_PTR && UTILS_FLAGS_CHECK(item->flags, FILLP_ITEM_FLAGS_FIRST_PKT)) {
302         FillpFrameRxNewFrag(&h->curFrame, item);
303     }
304 
305     if (!h->curFrame.rxStarted) {
306         return;
307     }
308 
309     FillpFrameRxUpdateAndNotify(h, item);
310 }
311 
312 #ifdef __cplusplus
313 }
314 #endif
315 
316