STATUS adaptFrameNalsFromAnnexBToAvcc()

in src/mkvgen/src/NalAdapter.c [11:134]


STATUS adaptFrameNalsFromAnnexBToAvcc(PBYTE pFrameData, UINT32 frameDataSize, BOOL removeEpb, PBYTE pAdaptedFrameData, PUINT32 pAdaptedFrameDataSize)
{
    STATUS retStatus = STATUS_SUCCESS;
    UINT32 i = 0, zeroCount = 0, runSize = 0;
    BOOL markerFound = FALSE;
    PBYTE pCurPnt = pFrameData, pAdaptedCurPnt = pAdaptedFrameData, pRunStart = NULL;

    CHK(pFrameData != NULL && pAdaptedFrameDataSize != NULL, STATUS_NULL_ARG);

    // Validate only when removeEpb flag is set which is the case when we need to split the NALus for
    // CPD processing. For frame adaptation we might have a certain bloat due to bad encoder adaptation flag
    if (removeEpb && pAdaptedFrameData != NULL && HANDLING_TRAILING_NALU_ZERO) {
        CHK(*pAdaptedFrameDataSize >= frameDataSize, STATUS_INVALID_ARG_LEN);
    }

    // Quick check for small size
    CHK(frameDataSize != 0, retStatus);

    // Calculate the size after adaptation
    // NOTE: We will not check for the correct buffer size for performance reasons.
    for (i = 0; i < frameDataSize; i++) {
        if (*pCurPnt == 0x00) {
            // Found a zero - increment the consecutive zero count
            zeroCount++;

            // Reset the last marker
            markerFound = FALSE;
        } else if (zeroCount > MAX_ANNEX_B_ZERO_COUNT) {
            // Ensure we don't have over 3 zero's in a row. However, some broken encoders produce zero-es
            // at the end of NALUs which ends up with 4 zeroes
            CHK(FALSE, STATUS_MKV_INVALID_ANNEXB_NALU_IN_FRAME_DATA);
        } else if (*pCurPnt == 0x01 && (zeroCount >= 2 && zeroCount <= MAX_ANNEX_B_ZERO_COUNT)) {
            // Found the Annex-B NAL
            // Check if we have previous run and fix it up
            if (pRunStart != NULL && pAdaptedFrameData != NULL) {
                // Fix-up the previous run by recording the size in Big-Endian format
                PUT_UNALIGNED_BIG_ENDIAN((PINT32) pRunStart, runSize);
            }

            // Store the beginning of the run
            pRunStart = pAdaptedCurPnt;

            // Increment the adapted pointer to 4 bytes
            pAdaptedCurPnt += 4;

            // Store an indicator that we have a marker
            markerFound = TRUE;

            // Start the new run
            zeroCount = 0;
            runSize = 0;
        } else if (removeEpb && *pCurPnt == 0x03 && zeroCount == 2 && (i < frameDataSize - 1) &&
                   ((*(pCurPnt + 1) == 0x00) || (*(pCurPnt + 1) == 0x01) || (*(pCurPnt + 1) == 0x02) || (*(pCurPnt + 1) == 0x03))) {
            // Removing the EPB
            pAdaptedCurPnt += zeroCount;

            // If the adapted frame is specified then copy the zeros and then the current byte
            if (pAdaptedFrameData != NULL) {
                while (zeroCount != 0) {
                    *(pAdaptedCurPnt - zeroCount) = 0x00;
                    zeroCount--;
                }
            }

            // Reset the zero count
            zeroCount = 0;
            runSize = 0;
        } else {
            // Advance the current pointer and the run size to the number of zeros so far
            // as well as add the zeros to the adapted buffer if any
            runSize += zeroCount + 1; // for the current byte
            pAdaptedCurPnt += zeroCount + 1;

            // If the adapted frame is specified then copy the zeros and then the current byte
            if (pAdaptedFrameData != NULL) {
                *(pAdaptedCurPnt - 1) = *pCurPnt;

                while (zeroCount != 0) {
                    *(pAdaptedCurPnt - 1 - zeroCount) = 0x00;
                    zeroCount--;
                }
            }

            zeroCount = 0;
            markerFound = FALSE;
        }

        // Iterate the current
        pCurPnt++;
    }

    // We could still have last few zeros at the end of the frame data and need to fix-up the last NAL
    pAdaptedCurPnt += zeroCount;
    if (pAdaptedFrameData != NULL) {
        // The last remaining zeros should go towards the run size
        runSize += zeroCount;

        while (zeroCount != 0) {
            *(pAdaptedCurPnt - zeroCount) = 0x00;
            zeroCount--;
        }

        // Fix-up the last run
        if (pRunStart != NULL) {
            PUT_UNALIGNED_BIG_ENDIAN((PINT32) pRunStart, runSize);
        }

        // Also, handle the case where there is a last 001/0001 at the end of the frame - we will fill with 0s
        if (markerFound) {
            PUT_UNALIGNED_BIG_ENDIAN((PUINT32) pAdaptedCurPnt - 1, 0);
        }
    }

CleanUp:

    if (STATUS_SUCCEEDED(retStatus) && pAdaptedFrameDataSize != NULL) {
        // NOTE: Due to EPB removal we could in fact make the adaptation buffer smaller than the original
        // We will require at least the original size buffer.
        *pAdaptedFrameDataSize = (removeEpb && HANDLING_TRAILING_NALU_ZERO) ? MAX(frameDataSize, (UINT32)(pAdaptedCurPnt - pAdaptedFrameData))
                                                                            : (UINT32)(pAdaptedCurPnt - pAdaptedFrameData);
    }

    return retStatus;
}