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