in libraries/amazon/amazon-kinesis-video-streams-webrtc-sdk-c/patch/src/source/Rtp/Codecs/RtpH264Payloader.c [200:302]
STATUS createPayloadFromNalu(UINT32 mtu, PBYTE nalu, UINT32 naluLength, PPayloadArray pPayloadArray, PUINT32 filledLength, PUINT32 filledSubLenSize)
{
ENTERS();
STATUS retStatus = STATUS_SUCCESS;
PBYTE pPayload = NULL;
UINT8 naluType = 0;
UINT8 naluRefIdc = 0;
UINT32 maxPayloadSize = 0;
UINT32 curPayloadSize = 0;
UINT32 remainingNaluLength = naluLength;
UINT32 payloadLength = 0;
UINT32 payloadSubLenSize = 0;
PBYTE pCurPtrInNalu = NULL;
BOOL sizeCalculationOnly = (pPayloadArray == NULL);
CHK(nalu != NULL && filledLength != NULL && filledSubLenSize != NULL, STATUS_NULL_ARG);
sizeCalculationOnly = (pPayloadArray == NULL);
CHK(sizeCalculationOnly || (pPayloadArray->payloadSubLength != NULL && pPayloadArray->payloadBuffer != NULL), STATUS_NULL_ARG);
CHK(mtu > FU_A_HEADER_SIZE, STATUS_RTP_INPUT_MTU_TOO_SMALL);
// https://yumichan.net/video-processing/video-compression/introduction-to-h264-nal-unit/
naluType = *nalu & 0x1F; // last 5 bits
naluRefIdc = *nalu & 0x60; // 2 bits higher than naluType
if (!sizeCalculationOnly) {
pPayload = pPayloadArray->payloadBuffer;
}
if (naluLength <= mtu) {
payloadLength += naluLength;
payloadSubLenSize++;
if (!sizeCalculationOnly) {
CHK(payloadSubLenSize <= pPayloadArray->maxPayloadSubLenSize && payloadLength <= pPayloadArray->maxPayloadLength,
STATUS_BUFFER_TOO_SMALL);
// Single NALU https://tools.ietf.org/html/rfc6184#section-5.6
MEMCPY(pPayload, nalu, naluLength);
pPayloadArray->payloadSubLength[payloadSubLenSize - 1] = naluLength;
pPayload += pPayloadArray->payloadSubLength[payloadSubLenSize - 1];
#ifdef SUPPORT_SHARE_BUFFER
pPayloadArray->payloadRefOffset[payloadSubLenSize - 1] = pPayloadArray->currentOffset;
pPayloadArray->payloadRefLength[payloadSubLenSize - 1] = naluLength;
pPayloadArray->currentOffset += naluLength;
#endif
}
} else {
// FU-A https://tools.ietf.org/html/rfc6184#section-5.8
maxPayloadSize = mtu - FU_A_HEADER_SIZE;
// According to the RFC, the first octet is skipped due to redundant information
remainingNaluLength--;
pCurPtrInNalu = nalu + 1;
while (remainingNaluLength != 0) {
curPayloadSize = MIN(maxPayloadSize, remainingNaluLength);
payloadSubLenSize++;
payloadLength += FU_A_HEADER_SIZE + curPayloadSize;
if (!sizeCalculationOnly) {
CHK(payloadSubLenSize <= pPayloadArray->maxPayloadSubLenSize && payloadLength <= pPayloadArray->maxPayloadLength,
STATUS_BUFFER_TOO_SMALL);
MEMCPY(pPayload + FU_A_HEADER_SIZE, pCurPtrInNalu, curPayloadSize);
/* FU-A indicator is 28 */
pPayload[0] = 28 | naluRefIdc;
pPayload[1] = naluType;
if (remainingNaluLength == naluLength - 1) {
// Set for starting bit
pPayload[1] |= 1 << 7;
} else if (remainingNaluLength == curPayloadSize) {
// Set for ending bit
pPayload[1] |= 1 << 6;
}
pPayloadArray->payloadSubLength[payloadSubLenSize - 1] = FU_A_HEADER_SIZE + curPayloadSize;
pPayload += pPayloadArray->payloadSubLength[payloadSubLenSize - 1];
#ifdef SUPPORT_SHARE_BUFFER
pPayloadArray->payloadRefOffset[payloadSubLenSize - 1] = pPayloadArray->currentOffset;
pPayloadArray->payloadRefLength[payloadSubLenSize - 1] = curPayloadSize;
pPayloadArray->currentOffset += curPayloadSize;
#endif
}
pCurPtrInNalu += curPayloadSize;
remainingNaluLength -= curPayloadSize;
}
}
CleanUp:
if (STATUS_FAILED(retStatus) && sizeCalculationOnly) {
payloadLength = 0;
payloadSubLenSize = 0;
}
if (filledLength != NULL && filledSubLenSize != NULL) {
*filledLength = payloadLength;
*filledSubLenSize = payloadSubLenSize;
}
LEAVES();
return retStatus;
}