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