STATUS adaptVideoFrameFromAvccToAnnexB()

in gst/gst-kvs-plugin/src/KvsWebRtc.c [1379:1470]


STATUS adaptVideoFrameFromAvccToAnnexB(PGstKvsPlugin pGstKvsPlugin, PFrame pFrame, ELEMENTARY_STREAM_NAL_FORMAT nalFormat)
{
    STATUS retStatus = STATUS_SUCCESS;
    PBYTE pCurPnt, pEndPnt, pDst;
    UINT32 runLen = 0, overallSize;
    BOOL includeCpd, iterate = TRUE;
    BYTE naluHeader;

    CHK(pGstKvsPlugin != NULL && pFrame != NULL, STATUS_NULL_ARG);
    CHK(pFrame->size > SIZEOF(UINT32) + 1, STATUS_FORMAT_ERROR);

    pCurPnt = pFrame->frameData;
    pEndPnt = pCurPnt + pFrame->size;

    // Pre-set the defaults before determining whether we need to include the CPD
    includeCpd = FALSE;
    overallSize = pFrame->size;

    // Check if we need to prepend the Annex-B format stored CPD
    // It should only be prepended to an IDR frame.
    // We are skipping over non-RBSP NALus and check if we have an IDR or VPS/SPS/PPS
    if (CHECK_FRAME_FLAG_KEY_FRAME(pFrame->flags)) {
        while (iterate && pCurPnt != pEndPnt) {
            CHK(pCurPnt + SIZEOF(UINT32) < pEndPnt, STATUS_FORMAT_ERROR);

            // Skip the AvCC/HEVC NALu run length
            naluHeader = *(pCurPnt + SIZEOF(UINT32));
            runLen = (UINT32) GET_UNALIGNED_BIG_ENDIAN((PUINT32) pCurPnt);

            // Check if we need to prepend the stored Annex-B formatted CPD only to a key frame
            if ((nalFormat == ELEMENTARY_STREAM_NAL_FORMAT_AVCC && IS_NALU_H264_IDR_HEADER(naluHeader)) ||
                (nalFormat == ELEMENTARY_STREAM_NAL_FORMAT_HEVC && IS_NALU_H265_IDR_HEADER(naluHeader))) {
                includeCpd = TRUE;
                overallSize += pGstKvsPlugin->videoCpdSize;
                iterate = FALSE;
            } else if ((nalFormat == ELEMENTARY_STREAM_NAL_FORMAT_AVCC && IS_NALU_H264_SPS_PPS_HEADER(naluHeader)) ||
                       (nalFormat == ELEMENTARY_STREAM_NAL_FORMAT_HEVC && IS_NALU_H265_VPS_SPS_PPS_HEADER(naluHeader))) {
                iterate = FALSE;
            }

            pCurPnt += runLen + SIZEOF(UINT32);
        }
    }

    pCurPnt = pFrame->frameData;

    // Check if we need to allocate/re-allocate
    if (pGstKvsPlugin->adaptedFrameBufSize < overallSize) {
        CHK(NULL != (pGstKvsPlugin->pAdaptedFrameBuf = (PBYTE) MEMREALLOC(pGstKvsPlugin->pAdaptedFrameBuf, overallSize)), STATUS_NOT_ENOUGH_MEMORY);
        pGstKvsPlugin->adaptedFrameBufSize = overallSize;
    }

    pDst = pGstKvsPlugin->pAdaptedFrameBuf;

    // Copy the stored Annex-B format CPD
    if (includeCpd) {
        MEMCPY(pDst, pGstKvsPlugin->videoCpd, pGstKvsPlugin->videoCpdSize);
        pDst += pGstKvsPlugin->videoCpdSize;
    }

    pEndPnt = pCurPnt + pFrame->size;

    while (pCurPnt != pEndPnt) {
        // Check if we can still read 32 bit
        CHK(pCurPnt + SIZEOF(UINT32) <= pEndPnt, STATUS_FORMAT_ERROR);

        runLen = (UINT32) GET_UNALIGNED_BIG_ENDIAN((PUINT32) pCurPnt);
        pCurPnt += SIZEOF(UINT32);

        CHK(pCurPnt + runLen <= pEndPnt, STATUS_FORMAT_ERROR);

        // Adapt with 4 byte version of the start sequence
        PUT_UNALIGNED_BIG_ENDIAN((PINT32) pDst, 0x0001);

        // Copy the bits to adapted destination
        pDst += SIZEOF(UINT32);
        MEMCPY(pDst, pCurPnt, runLen);

        pDst += runLen;

        // Jump to the next NAL
        pCurPnt += runLen;
    }

    // Set the adapted frame buffer
    pFrame->frameData = pGstKvsPlugin->pAdaptedFrameBuf;
    pFrame->size = overallSize;

CleanUp:

    return retStatus;
}