int NALU_convertAnnexBToAvccInPlace()

in src/source/codec/nalu.c [230:375]


int NALU_convertAnnexBToAvccInPlace(uint8_t *pAnnexbBuf, uint32_t uAnnexbBufLen, uint32_t uAnnexbBufSize, uint32_t *pAvccLen)
{
    int xRes = KVS_ERRNO_NONE;
    uint32_t i = 0;
    Nal_t xNals[ MAX_NALU_COUNT_IN_A_FRAME ];
    uint32_t uNalRbspCount = 0;
    uint32_t uAvccTotalLen = 0;
    uint32_t uAvccIdx = 0;

    if (pAnnexbBuf == NULL || uAnnexbBufLen <= 4 || pAvccLen == NULL)
    {
        LogError("Invalid argument");
        xRes = KVS_ERRNO_FAIL;
    }
    else if (!NALU_isAnnexBFrame(pAnnexbBuf, uAnnexbBufLen))
    {
        LogInfo("It's not a Annex-B frame, skip convert");
    }
    else
    {
        /* Go through all Annex-B buffer and record all RBSP begin and length first. */
        while (i < uAnnexbBufLen - 4)
        {
            if (uNalRbspCount > MAX_NALU_COUNT_IN_A_FRAME)
            {
                break;
            }

            if (pAnnexbBuf[i] == 0x00)
            {
                if (pAnnexbBuf[i+1] == 0x00)
                {
                    if (pAnnexbBuf[i+2] == 0x00)
                    {
                        if (pAnnexbBuf[i+3] == 0x01)
                        {
                            /* 0x00000001 is start code of NAL. */
                            if (uNalRbspCount > 0)
                            {
                                xNals[uNalRbspCount-1].uNalLen = i - xNals[uNalRbspCount-1].uNalBeginIdx;
                            }

                            i += 4;
                            xNals[uNalRbspCount++].uNalBeginIdx = i;
                        }
                        else if (pAnnexbBuf[i + 3] == 0x00)
                        {
                            /* 0x00000000 is not allowed. */
                            LogInfo("Invalid NALU format");
                            xRes = KVS_ERRNO_FAIL;
                            break;
                        }
                        else
                        {
                            /* 0x000000XX is acceptable. */
                            i += 4;
                        }
                    }
                    else if (pAnnexbBuf[i+2] == 0x01)
                    {
                        /* 0x000001 is start code of NAL */
                        if (uNalRbspCount > 0)
                        {
                            xNals[uNalRbspCount-1].uNalLen = i - xNals[uNalRbspCount-1].uNalBeginIdx;
                        }

                        i += 3;
                        xNals[uNalRbspCount++].uNalBeginIdx = i;
                    }
                    else
                    {
                        /* 0x0000XX is acceptable. It includes EPB case and we reserve EPB byte. */
                        i += 3;
                    }
                }
                else
                {
                    /* 0x00XX is acceptable. */
                    i += 2;
                }
            }
            else
            {
                /* 0xXX is acceptable. */
                i++;
            }
        }

        if (uNalRbspCount == 0)
        {
            LogInfo("No NALU is found in Annex-B frame");
            xRes = KVS_ERRNO_FAIL;
        }
        else if (uNalRbspCount > MAX_NALU_COUNT_IN_A_FRAME)
        {
            LogError("NAL RBSP count exceeds max count");
            xRes = KVS_ERRNO_FAIL;
        }
        else
        {
            /* Update the last BSPS. */
            xNals[ uNalRbspCount - 1 ].uNalLen = uAnnexbBufLen - xNals[ uNalRbspCount - 1 ].uNalBeginIdx;

            /* Calculate needed size if we convert it to Avcc format. */
            uAvccTotalLen = 4 * uNalRbspCount;
            for (i=0; i<uNalRbspCount; i++)
            {
                uAvccTotalLen += xNals[i].uNalLen;
            }

            if (uAvccTotalLen > uAnnexbBufSize)
            {
                /* We don't have enough space to convert Annex-B to Avcc in place. */
                LogInfo("No available space to convert Annex-B inplace");
                *pAvccLen = 0;
                xRes = KVS_ERRNO_FAIL;
            }
            else
            {
               /* move RBSP from back to head */
                i = uNalRbspCount - 1;
                uAvccIdx = uAvccTotalLen;
                do
                {
                    /* move RBSP */
                    uAvccIdx -= xNals[i].uNalLen;
                    memmove(pAnnexbBuf + uAvccIdx, pAnnexbBuf + xNals[i].uNalBeginIdx, xNals[i].uNalLen);

                    /* fill length info */
                    uAvccIdx -= 4;
                    PUT_UNALIGNED_4_byte_BE(pAnnexbBuf + uAvccIdx, xNals[i].uNalLen);

                    if (i == 0)
                    {
                        break;
                    }
                    i--;
                } while (true);

                *pAvccLen = uAvccTotalLen;
            }
        }
    }

    return xRes;
}