STATUS createPayloadFromNalu()

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;
}