1 /**
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <ImsMediaDefine.h>
18 #include <VideoRtpPayloadEncoderNode.h>
19 #include <ImsMediaBinaryFormat.h>
20 #include <ImsMediaTimer.h>
21 #include <ImsMediaTrace.h>
22 #include <VideoConfig.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 
27 #ifdef DEBUG_JITTER_GEN_SIMULATION_REORDER
28 #define MEDIABUF_DATAPACKET_MAX 200
29 #else
30 #define MEDIABUF_DATAPACKET_MAX 1300
31 #endif
32 
33 using namespace android::telephony::imsmedia;
34 
VideoRtpPayloadEncoderNode(BaseSessionCallback * callback)35 VideoRtpPayloadEncoderNode::VideoRtpPayloadEncoderNode(BaseSessionCallback* callback) :
36         BaseNode(callback)
37 {
38     mCodecType = VideoConfig::CODEC_AVC;
39     mPayloadMode = kRtpPayloadHeaderModeNonInterleaved;
40     mPrevMark = false;
41     mBuffer = nullptr;
42     memset(mVPS, 0, sizeof(mVPS));
43     memset(mSPS, 0, sizeof(mSPS));
44     memset(mPPS, 0, sizeof(mPPS));
45     mSpsSize = 0;
46     mPpsSize = 0;
47     mVPSsize = 0;
48     mMaxFragmentUnitSize = MEDIABUF_DATAPACKET_MAX;
49 }
50 
~VideoRtpPayloadEncoderNode()51 VideoRtpPayloadEncoderNode::~VideoRtpPayloadEncoderNode() {}
52 
GetNodeId()53 kBaseNodeId VideoRtpPayloadEncoderNode::GetNodeId()
54 {
55     return kNodeIdVideoPayloadEncoder;
56 }
57 
Start()58 ImsMediaResult VideoRtpPayloadEncoderNode::Start()
59 {
60     mPrevMark = true;
61 
62     if (mMaxFragmentUnitSize == 0)
63     {
64         mMaxFragmentUnitSize = MEDIABUF_DATAPACKET_MAX;
65     }
66 
67     IMLOGD3("[Start] codecType[%d], PayloadMode[%d], mtu[%d]", mCodecType, mPayloadMode,
68             mMaxFragmentUnitSize);
69 
70     mBuffer = reinterpret_cast<uint8_t*>(malloc(MAX_RTP_PAYLOAD_BUFFER_SIZE * sizeof(uint8_t)));
71 
72     if (mBuffer == nullptr)
73     {
74         return RESULT_NO_MEMORY;
75     }
76 
77     mNodeState = kNodeStateRunning;
78     return RESULT_SUCCESS;
79 }
80 
Stop()81 void VideoRtpPayloadEncoderNode::Stop()
82 {
83     if (mBuffer != nullptr)
84     {
85         free(mBuffer);
86         mBuffer = nullptr;
87     }
88 
89     mNodeState = kNodeStateStopped;
90 }
91 
IsRunTime()92 bool VideoRtpPayloadEncoderNode::IsRunTime()
93 {
94     return true;
95 }
96 
IsSourceNode()97 bool VideoRtpPayloadEncoderNode::IsSourceNode()
98 {
99     return false;
100 }
101 
SetConfig(void * config)102 void VideoRtpPayloadEncoderNode::SetConfig(void* config)
103 {
104     if (config == nullptr)
105     {
106         return;
107     }
108 
109     VideoConfig* pConfig = reinterpret_cast<VideoConfig*>(config);
110     mCodecType = pConfig->getCodecType();
111     mPayloadMode = pConfig->getPacketizationMode();
112     mMaxFragmentUnitSize = pConfig->getMaxMtuBytes();
113 }
114 
IsSameConfig(void * config)115 bool VideoRtpPayloadEncoderNode::IsSameConfig(void* config)
116 {
117     if (config == nullptr)
118     {
119         return false;
120     }
121 
122     VideoConfig* pConfig = reinterpret_cast<VideoConfig*>(config);
123     return (mCodecType == pConfig->getCodecType() &&
124             mPayloadMode == pConfig->getPacketizationMode() &&
125             mMaxFragmentUnitSize == pConfig->getMaxMtuBytes());
126 }
127 
OnDataFromFrontNode(ImsMediaSubType subtype,uint8_t * pData,uint32_t nDataSize,uint32_t nTimestamp,bool bMark,uint32_t nSeqNum,ImsMediaSubType nDataType,uint32_t arrivalTime)128 void VideoRtpPayloadEncoderNode::OnDataFromFrontNode(ImsMediaSubType subtype, uint8_t* pData,
129         uint32_t nDataSize, uint32_t nTimestamp, bool bMark, uint32_t nSeqNum,
130         ImsMediaSubType nDataType, uint32_t arrivalTime)
131 {
132     (void)subtype;
133     (void)nSeqNum;
134     (void)nDataType;
135     (void)arrivalTime;
136 
137     switch (mCodecType)
138     {
139         case VideoConfig::CODEC_AVC:
140             EncodeAvc(pData, nDataSize, nTimestamp, bMark);
141             break;
142         case VideoConfig::CODEC_HEVC:
143             EncodeHevc(pData, nDataSize, nTimestamp, bMark);
144             break;
145         default:
146             IMLOGE1("[OnDataFromFrontNode] invalid codec type[%d]", mCodecType);
147             SendDataToRearNode(MEDIASUBTYPE_RTPPAYLOAD, pData, nDataSize, nTimestamp, bMark, 0);
148             break;
149     }
150 }
151 
FindAvcStartCode(uint8_t * pData,uint32_t nDataSize,uint32_t * pnSkipSize)152 uint8_t* VideoRtpPayloadEncoderNode::FindAvcStartCode(
153         uint8_t* pData, uint32_t nDataSize, uint32_t* pnSkipSize)
154 {
155     uint8_t* pCurDataPos = pData;
156     uint32_t nSkipSize = 0;
157 
158     // remove leading zero bytes and start code prefix
159     while (nDataSize >= 4)
160     {
161         // Start Code 00 00 00 01 case.
162         if (pCurDataPos[0] == 0x00 && pCurDataPos[1] == 0x00 && pCurDataPos[2] == 0x00 &&
163                 pCurDataPos[3] == 0x01)
164         {
165             if (pnSkipSize)
166                 *pnSkipSize = nSkipSize;
167             return pCurDataPos;
168         }
169         else
170         {
171             pCurDataPos += 1;
172             nDataSize -= 1;
173             nSkipSize += 1;
174         }
175     }
176 
177     if (pnSkipSize)
178         *pnSkipSize = nSkipSize;
179     return nullptr;
180 }
181 
182 // [HEVC] return buffer position of h.265 start code
FindHevcStartCode(uint8_t * pData,uint32_t nDataSize,uint32_t * pnSkipSize)183 uint8_t* VideoRtpPayloadEncoderNode::FindHevcStartCode(
184         uint8_t* pData, uint32_t nDataSize, uint32_t* pnSkipSize)
185 {
186     uint8_t* pCurDataPos = pData;
187     uint32_t nSkipSize = 0;
188 
189     // remove leading zero bytes and start code prefix
190     while (nDataSize >= 4)
191     {
192         // Start Code 00 00 00 01 case.
193         if (pCurDataPos[0] == 0x00 && pCurDataPos[1] == 0x00 && pCurDataPos[2] == 0x00 &&
194                 pCurDataPos[3] == 0x01)
195         {
196             if (pnSkipSize)
197                 *pnSkipSize = nSkipSize;
198             return pCurDataPos;
199         }
200         else
201         {
202             pCurDataPos += 1;
203             nDataSize -= 1;
204             nSkipSize += 1;
205         }
206     }
207 
208     if (pnSkipSize)
209         *pnSkipSize = nSkipSize;
210     return nullptr;
211 }
212 
EncodeAvc(uint8_t * pData,uint32_t nDataSize,uint32_t nTimestamp,bool bMark)213 void VideoRtpPayloadEncoderNode::EncodeAvc(
214         uint8_t* pData, uint32_t nDataSize, uint32_t nTimestamp, bool bMark)
215 {
216     uint8_t* pCurDataPos = pData;
217     uint32_t nCurDataSize;
218     uint32_t nSkipSize;
219     uint8_t* pStartCodePos;
220     uint8_t nNalUnitType;
221     char spsEncoded[255];
222     uint32_t spsEncodedSize = 0;
223     char ppsEncoded[255];
224     uint32_t ppsEncodedSize = 0;
225 
226     if (nDataSize > 5)
227     {
228         IMLOGD_PACKET8(IM_PACKET_LOG_PH,
229                 "[EncodeAvc] [%02X %02X %02X %02X %02X] nDataSize[%d], TS[%u], mark[%d]", pData[0],
230                 pData[1], pData[2], pData[3], pData[4], nDataSize, nTimestamp, bMark);
231     }
232 
233     pStartCodePos = FindAvcStartCode(pCurDataPos, nDataSize, &nSkipSize);
234 
235     if (pStartCodePos == nullptr)
236     {
237         return;
238     }
239 
240     // remove padding
241     pCurDataPos = pStartCodePos + 4;
242     nDataSize -= (nSkipSize + 4);
243     nNalUnitType = pCurDataPos[0] & 0x1F;
244 
245     while (nNalUnitType == 7 || nNalUnitType == 8)  // config frame
246     {
247         // extract nal unit
248         pStartCodePos = FindAvcStartCode(pCurDataPos + 1, nDataSize - 1);
249 
250         if (pStartCodePos == nullptr)
251         {
252             nCurDataSize = nDataSize;
253         }
254         else
255         {
256             nCurDataSize = pStartCodePos - pCurDataPos;
257         }
258 
259         if (nNalUnitType == 7)
260         {
261             memset(mSPS, 0, MAX_CONFIG_LEN);
262             memcpy(mSPS, pCurDataPos, nCurDataSize);
263             mSpsSize = nCurDataSize;
264             ImsMediaBinaryFormat::BinaryToBase00(
265                     spsEncoded, spsEncodedSize, mSPS, mSpsSize, BINARY_FORMAT_BASE64);
266             IMLOGD2("[EncodeAvc] save sps size[%d], data : %s", mSpsSize, spsEncoded);
267         }
268         else if (nNalUnitType == 8)
269         {
270             memset(mPPS, 0, MAX_CONFIG_LEN);
271             memcpy(mPPS, pCurDataPos, nCurDataSize);
272             mPpsSize = nCurDataSize;
273 
274             ImsMediaBinaryFormat::BinaryToBase00(
275                     ppsEncoded, ppsEncodedSize, mPPS, mPpsSize, BINARY_FORMAT_BASE64);
276             IMLOGD2("[EncodeAvc] save pps, size[%d], data : %s", mPpsSize, ppsEncoded);
277         }
278 
279         if (nDataSize < nCurDataSize + 4)
280         {
281             return;
282         }
283 
284         nDataSize -= (nCurDataSize + 4);
285         pCurDataPos += (nCurDataSize + 4);
286         nNalUnitType = pCurDataPos[0] & 0x1F;
287     }
288 
289     if (nNalUnitType == 5)  // check idf frame, send sps/pps
290     {
291         // sps
292         EncodeAvcNALUnit(mSPS, mSpsSize, nTimestamp, 1, 7);
293         // pps
294         EncodeAvcNALUnit(mPPS, mPpsSize, nTimestamp, 1, 8);
295         IMLOGD0("[EncodeAvc] Send SPS, PPS when an I frame send");
296     }
297 
298     if (nDataSize > 0)
299     {
300         EncodeAvcNALUnit(pCurDataPos, nDataSize, nTimestamp, bMark, nNalUnitType);
301     }
302 }
303 
EncodeAvcNALUnit(uint8_t * pData,uint32_t nDataSize,uint32_t nTimestamp,bool bMark,uint32_t nNalUnitType)304 void VideoRtpPayloadEncoderNode::EncodeAvcNALUnit(
305         uint8_t* pData, uint32_t nDataSize, uint32_t nTimestamp, bool bMark, uint32_t nNalUnitType)
306 {
307     uint8_t* pCurDataPos = pData;
308     uint32_t nMtu = mMaxFragmentUnitSize * 0.9;
309 
310     if (nDataSize > 5)
311     {
312         IMLOGD_PACKET8(IM_PACKET_LOG_PH,
313                 "[EncodeAvcNALUnit] [%02X%02X%02X%02X] size[%d], TS[%u], mark[%d], nalType[%d]",
314                 pData[0], pData[1], pData[2], pData[3], nDataSize, nTimestamp, bMark, nNalUnitType);
315     }
316 
317     if (nDataSize > MAX_RTP_PAYLOAD_BUFFER_SIZE)
318     {
319         IMLOGE1("[EncodeAvcNALUnit] nDataSize[%d]", nDataSize);
320         return;
321     }
322 
323     if (mBuffer == nullptr)
324     {
325         return;
326     }
327 
328     // make FU-A packets
329     if (mPayloadMode == kRtpPayloadHeaderModeNonInterleaved && nDataSize > nMtu)
330     {
331         uint32_t nRemainSize = nDataSize;
332         uint32_t nSendDataSize;
333         bool bFirstPacket = true;
334         bool bMbit;
335         uint8_t bFUIndicator;
336         uint8_t bFUHeader;
337         uint8_t bNALUnitType;
338 
339         // Make FU indicator and save NAL unit type
340         bFUIndicator = pCurDataPos[0] & 0xE0;  // copy F and NRI from NAL unit header
341         bFUIndicator += 28;                    // Type is 28(FU-A)
342         bNALUnitType = pCurDataPos[0] & 0x1F;  // copy NAL unit type from NAL unit header
343 
344         while (nRemainSize)
345         {
346             // set bMbit, nSendDataSize, bFUHeader
347             if (nRemainSize <= nMtu)
348             {
349                 bMbit = bMark;                    // RTP marker bit
350                 bFUHeader = 0x40 + bNALUnitType;  // set E bit
351                 nSendDataSize = nRemainSize;
352             }
353             else
354             {
355                 bMbit = false;  // RTP marker bit
356 
357                 if (bFirstPacket)
358                     bFUHeader = 0x80 + bNALUnitType;  // set S bit
359                 else
360                     bFUHeader = bNALUnitType;
361                 if (nRemainSize >= nMtu * 2)
362                 {
363                     nSendDataSize = nMtu;
364                 }
365                 else
366                 {
367                     nSendDataSize = nRemainSize / 2;
368                 }
369             }
370 
371             /** pData is the buffer of front node (not mine) bacause this method is called in
372              * OnDataFromFrontNode method. Then, to modify it, we have to copy it to
373              * another buffer */
374             if (bFirstPacket)
375             {
376                 if (nSendDataSize <= MAX_RTP_PAYLOAD_BUFFER_SIZE - 1)
377                 {
378                     memcpy(mBuffer + 1, pCurDataPos, nSendDataSize);
379                 }
380                 else
381                 {
382                     IMLOGE1("[EncodeAvcNALUnit] memcpy Error!! - nDataSize[%d]", nSendDataSize);
383                     return;
384                 }
385 
386                 pCurDataPos += nSendDataSize;
387                 nRemainSize -= nSendDataSize;
388 
389                 nSendDataSize += 1;
390                 bFirstPacket = false;
391             }
392             else
393             {
394                 if (nSendDataSize <= MAX_RTP_PAYLOAD_BUFFER_SIZE - 2)
395                 {
396                     memcpy(mBuffer + 2, pCurDataPos, nSendDataSize);
397                 }
398                 else
399                 {
400                     IMLOGE1("[EncodeAvcNALUnit] memcpy Error!! - nDataSize[%d]", nSendDataSize);
401                     return;
402                 }
403 
404                 pCurDataPos += nSendDataSize;
405                 nRemainSize -= nSendDataSize;
406                 nSendDataSize += 2;
407             }
408 
409             mBuffer[0] = bFUIndicator;
410             mBuffer[1] = bFUHeader;
411 
412             // Insert CVO extension when the last packet of IDR frame
413             if (nNalUnitType == 5)
414             {
415                 SendDataToRearNode(
416                         MEDIASUBTYPE_VIDEO_IDR_FRAME, mBuffer, nSendDataSize, nTimestamp, bMbit, 0);
417             }
418             else
419             {
420                 SendDataToRearNode(
421                         MEDIASUBTYPE_RTPPAYLOAD, mBuffer, nSendDataSize, nTimestamp, bMbit, 0);
422             }
423         }
424     }
425     else
426     {
427         IMLOGD_PACKET4(IM_PACKET_LOG_PH,
428                 "[EncodeAvcNALUnit] [%02X] nDataSize[%d], TS[%u], mark[%d]", pCurDataPos[0],
429                 nDataSize, nTimestamp, bMark);
430         // Insert CVO extension when the last packet of IDR frame
431         if (nNalUnitType == 5)
432         {
433             SendDataToRearNode(
434                     MEDIASUBTYPE_VIDEO_IDR_FRAME, pCurDataPos, nDataSize, nTimestamp, bMark, 0);
435         }
436         else
437         {
438             SendDataToRearNode(
439                     MEDIASUBTYPE_RTPPAYLOAD, pCurDataPos, nDataSize, nTimestamp, bMark, 0);
440         }
441     }
442 }
443 
EncodeHevc(uint8_t * pData,uint32_t nDataSize,uint32_t nTimestamp,bool bMark)444 void VideoRtpPayloadEncoderNode::EncodeHevc(
445         uint8_t* pData, uint32_t nDataSize, uint32_t nTimestamp, bool bMark)
446 {
447     uint8_t* pCurDataPos = pData;
448     uint32_t nSkipSize;
449     uint8_t* pStartCodePos;
450     uint8_t nNalUnitType;
451 
452     if (nDataSize > 6)
453     {
454         IMLOGD_PACKET6(IM_PACKET_LOG_PH, "[EncodeHevc] [%02X %02X %02X %02X %02X %02X]", pData[0],
455                 pData[1], pData[2], pData[3], pData[4], pData[5]);
456         IMLOGD_PACKET3(IM_PACKET_LOG_PH, "[EncodeHevc] nDataSize[%d], TS[%u], mark[%d]", nDataSize,
457                 nTimestamp, bMark);
458     }
459 
460     pStartCodePos = FindHevcStartCode(pCurDataPos, nDataSize, &nSkipSize);
461 
462     if (pStartCodePos == nullptr)
463     {
464         return;
465     }
466 
467     pCurDataPos = pStartCodePos + 4;
468     nDataSize -= (nSkipSize + 4);
469     nNalUnitType = (pCurDataPos[0] >> 1) & 0x3F;
470 
471     // 32: VPS, 33: SPS, 34: PPS
472     while (nNalUnitType == 32 || nNalUnitType == 33 || nNalUnitType == 34)
473     {
474         // extract nal unit
475         // NAL unit header is 2 bytes on HEVC.
476         pStartCodePos = FindHevcStartCode(pCurDataPos + 2, nDataSize - 2);
477 
478         if (pStartCodePos == nullptr)
479         {
480             break;
481         }
482 
483         uint32_t nCurDataSize = pStartCodePos - pCurDataPos;
484         EncodeHevcNALUnit(pCurDataPos, nCurDataSize, nTimestamp, bMark, nNalUnitType);
485 
486         if (nNalUnitType == 32)
487         {
488             memset(mVPS, 0, MAX_CONFIG_LEN);
489             memcpy(mVPS, pCurDataPos, nCurDataSize);
490             mVPSsize = nCurDataSize;
491             IMLOGD1("[EncodeHevc] VPS Size [%d]", mVPSsize);
492         }
493         else if (nNalUnitType == 33)
494         {
495             memset(mSPS, 0, MAX_CONFIG_LEN);
496             memcpy(mSPS, pCurDataPos, nCurDataSize);
497             mSpsSize = nCurDataSize;
498             IMLOGD1("[EncodeHevc] SPS Size [%d]", mSpsSize);
499         }
500         else if (nNalUnitType == 34)
501         {
502             memset(mPPS, 0, MAX_CONFIG_LEN);
503             memcpy(mPPS, pCurDataPos, nCurDataSize);
504             mPpsSize = nCurDataSize;
505             IMLOGD1("[EncodeHevc] PPS Size [%d]", mPpsSize);
506         }
507 
508         if (nDataSize < nCurDataSize + 4)
509         {
510             IMLOGE0("[EncodeHevc] error - extract nal unit!!!");
511             return;
512         }
513 
514         // exclude start code
515         nDataSize -= (nCurDataSize + 4);
516         pCurDataPos += (nCurDataSize + 4);
517         nNalUnitType = (pCurDataPos[0] >> 1) & 0x3F;
518     }
519 
520     // nal unit type 19, 20 are IDR picture, 21 is CRA picture
521     if ((nNalUnitType == 19) || (nNalUnitType == 20) || (nNalUnitType == 21))
522     {
523         // sending vps/sps/pps on I-frame
524         EncodeHevcNALUnit(mVPS, mVPSsize, nTimestamp, 1, nNalUnitType);
525         EncodeHevcNALUnit(mSPS, mSpsSize, nTimestamp, 1, nNalUnitType);
526         EncodeHevcNALUnit(mPPS, mPpsSize, nTimestamp, 1, nNalUnitType);
527     }
528 
529     if (nDataSize > 0)
530     {
531         EncodeHevcNALUnit(pCurDataPos, nDataSize, nTimestamp, bMark, nNalUnitType);
532         if (nNalUnitType == 34)
533         {
534             memset(mPPS, 0, MAX_CONFIG_LEN);
535             memcpy(mPPS, pCurDataPos, nDataSize);
536             mPpsSize = nDataSize;
537             IMLOGD1("[EncodeHevc] PPS Size[%d]", mPpsSize);
538         }
539     }
540 }
541 
EncodeHevcNALUnit(uint8_t * pData,uint32_t nDataSize,uint32_t nTimestamp,bool bMark,uint32_t nNalUnitType)542 void VideoRtpPayloadEncoderNode::EncodeHevcNALUnit(
543         uint8_t* pData, uint32_t nDataSize, uint32_t nTimestamp, bool bMark, uint32_t nNalUnitType)
544 {
545     uint8_t* pCurDataPos = pData;
546     uint32_t nMtu = mMaxFragmentUnitSize * 0.9;
547 
548     if (nDataSize > 5)
549     {
550         IMLOGD_PACKET8(IM_PACKET_LOG_PH,
551                 "[EncodeHevcNALUnit] [%02X %02X %02X %02X] nDataSize[%d], TS[%u], mark[%d], "
552                 "nalType[%d]",
553                 pData[0], pData[1], pData[2], pData[3], nDataSize, nTimestamp, bMark, nNalUnitType);
554     }
555 
556     if (mBuffer == nullptr)
557     {
558         return;
559     }
560 
561     // Share payload header mode with h.264 - single nal unit mode, non interleaved mode
562     // make FU-A packets
563     if (mPayloadMode == kRtpPayloadHeaderModeNonInterleaved && nDataSize > nMtu)
564     {
565         uint32_t nRemainSize = nDataSize;
566         uint32_t nSendDataSize;
567         bool bFirstPacket = true;
568         bool bMbit;
569         uint8_t bFUIndicator1;
570         uint8_t bFUIndicator2;
571         uint8_t bFUHeader;
572 
573         // Make FU indicator and save NAL unit type
574         // bNALUnitType = pCurDataPos[0] & 0x7E;         // copy NAL unit type from NAL unit header
575         bFUIndicator1 = pCurDataPos[0] & 0x81;        // copy F and NRI from NAL unit header
576         bFUIndicator1 = bFUIndicator1 + (0x31 << 1);  // Type is 49(FU-A)
577         bFUIndicator2 = pCurDataPos[1];               // copy LayerId, TID
578 
579         while (nRemainSize)
580         {
581             // set bMbit, nSendDataSize, bFUHeader
582             // last packet
583             if (nRemainSize <= nMtu)
584             {
585                 bMbit = bMark;                    // RTP marker bit
586                 bFUHeader = 0x40 | nNalUnitType;  // set E bit
587                 nSendDataSize = nRemainSize;
588             }
589             else
590             {
591                 // First and Mid packets
592                 bMbit = false;  // RTP marker bit
593 
594                 if (bFirstPacket)
595                 {
596                     bFUHeader = 0x80 | nNalUnitType;  // set S bit
597                 }
598                 else
599                 {
600                     bFUHeader = nNalUnitType;
601                 }
602 
603                 if (nRemainSize >= nMtu * 2)
604                 {
605                     nSendDataSize = nMtu;
606                 }
607                 else
608                 {
609                     nSendDataSize = nRemainSize / 2;
610                 }
611             }
612 
613             /** pData is the buffer of front node (not mine) bacause this method is called
614              * in OnDataFromFrontNode method. then, to modify it, we have to copy it
615              * to another buffer*/
616             if (bFirstPacket)
617             {
618                 memcpy(mBuffer + 1, pCurDataPos, nSendDataSize);
619                 pCurDataPos += nSendDataSize;
620                 nRemainSize -= nSendDataSize;
621                 nSendDataSize += 1;
622                 bFirstPacket = false;
623             }
624             else
625             {
626                 memcpy(mBuffer + 3, pCurDataPos, nSendDataSize);
627                 pCurDataPos += nSendDataSize;
628                 nRemainSize -= nSendDataSize;
629                 nSendDataSize += 3;
630             }
631 
632             mBuffer[0] = bFUIndicator1;
633             mBuffer[1] = bFUIndicator2;
634             mBuffer[2] = bFUHeader;
635 
636             // Insert CVO Rtp extension when the last packet of IDR frame
637             // nal unit type 19, 20 are IDR picture, 21 is CRA picture
638             if ((nNalUnitType == 19) || (nNalUnitType == 20) || (nNalUnitType == 21))
639             {
640                 SendDataToRearNode(
641                         MEDIASUBTYPE_VIDEO_IDR_FRAME, mBuffer, nSendDataSize, nTimestamp, bMbit, 0);
642             }
643             else
644             {
645                 SendDataToRearNode(
646                         MEDIASUBTYPE_RTPPAYLOAD, mBuffer, nSendDataSize, nTimestamp, bMbit, 0);
647             }
648         }
649     }
650     else
651     {
652         IMLOGD_PACKET5(IM_PACKET_LOG_PH,
653                 "[EncodeHevcNALUnit] [%02X %02X] nDataSize[%d], TS[%u], mark[%d]", pCurDataPos[0],
654                 pCurDataPos[1], nDataSize, nTimestamp, bMark);
655 
656         // Insert CVO Rtp extension when the last packet of IDR frame
657         // nal unit type 19, 20 are IDR picture, 21 is CRA picture
658         if ((nNalUnitType == 19) || (nNalUnitType == 20) || (nNalUnitType == 21))
659         {
660             SendDataToRearNode(
661                     MEDIASUBTYPE_VIDEO_IDR_FRAME, pCurDataPos, nDataSize, nTimestamp, bMark, 0);
662         }
663         else
664         {
665             SendDataToRearNode(
666                     MEDIASUBTYPE_RTPPAYLOAD, pCurDataPos, nDataSize, nTimestamp, bMark, 0);
667         }
668     }
669 }
670