SmartAudio/package/allwinner/tina_multimedia/libcedarc/vdecoder/sbm/sbmFrameH265.c

1982 lines
56 KiB
C
Executable File

/*
* Copyright (c) 2008-2016 Allwinner Technology Co. Ltd.
* All rights reserved.
*
* File : sbm.c
* Description :This is the stream buffer module. The SBM provides
* methods for managing the stream data before decode.
* History :
* Author : xyliu <xyliu@allwinnertech.com>
* Date : 2016/04/13
* Comment :
*
*
*/
#include <stdlib.h>
#include<string.h>
#include <pthread.h>
#include "sbm.h"
#include "CdcMessageQueue.h"
//#include "secureMemoryAdapter.h"
#include "log.h"
#define SBM_FRAME_FIFO_SIZE (2048) //* store 2048 frames of bitstream data at maximum.
#define MAX_INVALID_STREAM_DATA_SIZE (1*1024*1024) //* 1 MB
#define MAX_NALU_NUM_IN_FRAME (1024)
typedef struct StreamBufferManagerFrame
{
SbmInterface sbmInterface;
pthread_mutex_t mutex;
char* pStreamBuffer; //* start buffer address
char* pStreamBufferEnd;
int nStreamBufferSize; //* buffer total size
char* pWriteAddr;
int nValidDataSize;
StreamFrameFifo frameFifo;
CdcMessageQueue* mq;
pthread_t mThreadId;
FramePicFifo mFramePicFifo;
sem_t streamDataSem;
sem_t emptyFramePicSem;
sem_t resetSem;
int bStreamWithStartCode;
DetectFramePicInfo mDetectInfo;
SbmConfig mConfig;
int nEosFlag;
}SbmFrame;
extern SbmInterface* GetSbmInterfaceStream();
extern SbmInterface* GetSbmInterfaceFrameAvc();
static int lock(SbmFrame *pSbm);
static void unlock(SbmFrame *pSbm);
static void* ProcessThread(void* pThreadData);
enum SBM_THREAD_CMD
{
SBM_THREAD_CMD_START = 0,
SBM_THREAD_CMD_READ = 1,
SBM_THREAD_CMD_QUIT = 2,
SBM_THREAD_CMD_RESET = 3
};
typedef enum SbmHevcNaluType
{
SBM_HEVC_NAL_TRAIL_N = 0,
SBM_HEVC_NAL_TRAIL_R = 1,
SBM_HEVC_NAL_TSA_N = 2,
SBM_HEVC_NAL_TSA_R = 3,
SBM_HEVC_NAL_STSA_N = 4,
SBM_HEVC_NAL_STSA_R = 5,
SBM_HEVC_NAL_RADL_N = 6,
SBM_HEVC_NAL_RADL_R = 7,
SBM_HEVC_NAL_RASL_N = 8,
SBM_HEVC_NAL_RASL_R = 9,
SBM_HEVC_NAL_BLA_W_LP = 16,
SBM_HEVC_NAL_BLA_W_RADL = 17,
SBM_HEVC_NAL_BLA_N_LP = 18,
SBM_HEVC_NAL_IDR_W_RADL = 19,
SBM_HEVC_NAL_IDR_N_LP = 20,
SBM_HEVC_NAL_CRA_NUT = 21,
SBM_HEVC_NAL_VPS = 32,
SBM_HEVC_NAL_SPS = 33,
SBM_HEVC_NAL_PPS = 34,
SBM_HEVC_NAL_AUD = 35,
SBM_HEVC_NAL_EOS_NUT = 36,
SBM_HEVC_NAL_EOB_NUT = 37,
SBM_HEVC_NAL_FD_NUT = 38,
SBM_HEVC_NAL_SEI_PREFIX = 39,
SBM_HEVC_NAL_SEI_SUFFIX = 40,
SBM_HEVC_UNSPEC63 = 63
}SbmHevcNaluType;
#define IsFrameNalu(eNaluType) (eNaluType <= SBM_HEVC_NAL_CRA_NUT)
static int lock(SbmFrame *pSbm)
{
if(pthread_mutex_lock(&pSbm->mutex) != 0)
return -1;
return 0;
}
static void unlock(SbmFrame *pSbm)
{
pthread_mutex_unlock(&pSbm->mutex);
return;
}
/*
**********************************************************************
* SbmCreate
*
*Description: Create Stream Buffer Manager module.
*
*Arguments : nBufferSize the size of pStreamBuffer, to store stream info.
*
*Return : result
* = NULL; failed;
* != NULL; Sbm handler.
*
*Summary : nBufferSize is between 4MB and 12MB.
*
**********************************************************************
*/
static int SbmFrameInit(SbmInterface* pSelf, SbmConfig* pSbmConfig)
{
SbmFrame *pSbm = (SbmFrame*)pSelf;
char *pSbmBuf;
int i;
int ret;
if(pSbmConfig == NULL)
{
loge(" pSbmConfig is null");
return -1;
}
if(pSbmConfig->nSbmBufferTotalSize <= 0)
{
loge(" pSbmConfig->nBufferSize(%d) is invalid",pSbmConfig->nSbmBufferTotalSize);
return -1;
}
memcpy(&pSbm->mConfig, pSbmConfig, sizeof(SbmConfig));
pSbmBuf = (char*)CdcMemPalloc(pSbm->mConfig.memops, pSbm->mConfig.nSbmBufferTotalSize,
pSbm->mConfig.veOpsS, pSbm->mConfig.pVeOpsSelf);//*
if(pSbmBuf == NULL)
{
loge(" palloc for sbmBuf failed, size = %d MB",
pSbm->mConfig.nSbmBufferTotalSize/1024/1024);
goto ERROR;
}
pSbm->frameFifo.pFrames = (VideoStreamDataInfo *)malloc(SBM_FRAME_FIFO_SIZE
* sizeof(VideoStreamDataInfo));
if(pSbm->frameFifo.pFrames == NULL)
{
loge("sbm->frameFifo.pFrames == NULL.");
goto ERROR;
}
memset(pSbm->frameFifo.pFrames, 0, SBM_FRAME_FIFO_SIZE * sizeof(VideoStreamDataInfo));
for(i = 0; i < SBM_FRAME_FIFO_SIZE; i++)
{
pSbm->frameFifo.pFrames[i].nID = i;
}
ret = pthread_mutex_init(&pSbm->mutex, NULL);
if(ret != 0)
{
loge("pthread_mutex_init failed.");
goto ERROR;
}
pSbm->pStreamBuffer = pSbmBuf;
pSbm->pStreamBufferEnd = pSbmBuf + pSbm->mConfig.nSbmBufferTotalSize - 1;
pSbm->nStreamBufferSize = pSbm->mConfig.nSbmBufferTotalSize;
pSbm->pWriteAddr = pSbmBuf;
pSbm->nValidDataSize = 0;
pSbm->frameFifo.nMaxFrameNum = SBM_FRAME_FIFO_SIZE;
pSbm->frameFifo.nValidFrameNum = 0;
pSbm->frameFifo.nUnReadFrameNum = 0;
pSbm->frameFifo.nReadPos = 0;
pSbm->frameFifo.nWritePos = 0;
pSbm->frameFifo.nFlushPos = 0;
pSbm->mFramePicFifo.pFramePics = (FramePicInfo*)malloc(MAX_FRAME_PIC_NUM*sizeof(FramePicInfo));
if(pSbm->mFramePicFifo.pFramePics == NULL)
{
loge("malloc for framePic failed");
goto ERROR;
}
memset(pSbm->mFramePicFifo.pFramePics, 0, MAX_FRAME_PIC_NUM*sizeof(FramePicInfo));
pSbm->mFramePicFifo.nMaxFramePicNum = MAX_FRAME_PIC_NUM;
for(i = 0; i < MAX_FRAME_PIC_NUM; i++)
{
pSbm->mFramePicFifo.pFramePics[i].pNaluInfoList
= (NaluInfo*)malloc(DEFAULT_NALU_NUM*sizeof(NaluInfo));
if(pSbm->mFramePicFifo.pFramePics[i].pNaluInfoList == NULL)
{
loge("malloc for naluInfo failed");
goto ERROR;
}
memset(pSbm->mFramePicFifo.pFramePics[i].pNaluInfoList, 0,
DEFAULT_NALU_NUM*sizeof(NaluInfo));
pSbm->mFramePicFifo.pFramePics[i].nMaxNaluNum = DEFAULT_NALU_NUM;
}
sem_init(&pSbm->streamDataSem, 0, 0);
sem_init(&pSbm->emptyFramePicSem, 0, 0);
sem_init(&pSbm->resetSem, 0, 0);
pSbm->mq = CdcMessageQueueCreate(32, "sbm_Thread");
int err = pthread_create(&pSbm->mThreadId, NULL, ProcessThread, pSbm);
if(err || pSbm->mThreadId == 0)
{
loge("create sbm pthread failed");
goto ERROR;
}
CdcMessage mMsg;
memset(&mMsg, 0, sizeof(CdcMessage));
mMsg.messageId = SBM_THREAD_CMD_READ;
CdcMessageQueuePostMessage(pSbm->mq, &mMsg);
pSbm->bStreamWithStartCode = -1;
return 0;
ERROR:
if(pSbmBuf)
CdcMemPfree(pSbm->mConfig.memops,pSbmBuf,
pSbm->mConfig.veOpsS, pSbm->mConfig.pVeOpsSelf);
if(pSbm)
{
sem_destroy(&pSbm->streamDataSem);
sem_destroy(&pSbm->emptyFramePicSem);
sem_destroy(&pSbm->resetSem);
if(pSbm->frameFifo.pFrames)
free(pSbm->frameFifo.pFrames);
if(pSbm->mFramePicFifo.pFramePics)
{
for(i=0; i < MAX_FRAME_PIC_NUM; i++)
{
if(pSbm->mFramePicFifo.pFramePics[i].pNaluInfoList)
free(pSbm->mFramePicFifo.pFramePics[i].pNaluInfoList);
}
free(pSbm->mFramePicFifo.pFramePics);
}
free(pSbm);
}
return -1;
}
/*
**********************************************************************
* SbmDestroy
*
*Description: Destroy Stream Buffer Manager module, free resource.
*
*Arguments : pSbm Created by SbmCreate function.
*
*Return : NULL
*
*Summary :
*
**********************************************************************
*/
static void SbmFrameDestroy(SbmInterface* pSelf)
{
SbmFrame* pSbm = (SbmFrame*)pSelf;
logv(" sbm destroy");
//int i=0;
if(pSbm != NULL)
{
//* send stop cmd to thread here
if(pSbm->mq)
{
CdcMessage msg;
memset(&msg, 0, sizeof(CdcMessage));
msg.messageId = SBM_THREAD_CMD_QUIT;
CdcMessageQueuePostMessage(pSbm->mq,&msg);
logv("*** post quit message");
int error;
pthread_join(pSbm->mThreadId, (void**)&error);
logv("*** pthread_join finish");
pthread_mutex_destroy(&pSbm->mutex);
}
sem_destroy(&pSbm->streamDataSem);
sem_destroy(&pSbm->emptyFramePicSem);
sem_destroy(&pSbm->resetSem);
if(pSbm->pStreamBuffer != NULL)
{
CdcMemPfree(pSbm->mConfig.memops,pSbm->pStreamBuffer,
pSbm->mConfig.veOpsS, pSbm->mConfig.pVeOpsSelf);
pSbm->pStreamBuffer = NULL;
}
if(pSbm->frameFifo.pFrames != NULL)
{
free(pSbm->frameFifo.pFrames);
pSbm->frameFifo.pFrames = NULL;
}
if(pSbm->mq)
CdcMessageQueueDestroy(pSbm->mq);
if(pSbm->mFramePicFifo.pFramePics)
{
int i=0;
for(i=0; i < MAX_FRAME_PIC_NUM; i++)
{
if(pSbm->mFramePicFifo.pFramePics[i].pNaluInfoList)
free(pSbm->mFramePicFifo.pFramePics[i].pNaluInfoList);
}
free(pSbm->mFramePicFifo.pFramePics);
}
free(pSbm);
}
logv(" sbm destroy finish");
return;
}
/*
**********************************************************************
* SbmReset
*
*Description: Reset Stream Buffer Manager module.
*
*Arguments : pSbm Created by SbmCreate function.
*
*Return : NULL
*
*Summary : If succeed, Stream Buffer Manager module will be resumed to initial state,
* stream data will be discarded.
*
**********************************************************************
*/
static void SbmFrameReset(SbmInterface* pSelf)
{
logd("SbmFrameReset");
SbmFrame* pSbm = (SbmFrame*)pSelf;
if(pSbm == NULL)
{
loge("pSbm == NULL.");
return;
}
CdcMessage mMsg;
memset(&mMsg, 0, sizeof(CdcMessage));
mMsg.messageId = SBM_THREAD_CMD_RESET;
mMsg.params[0] = (uintptr_t)(&pSbm->resetSem);
CdcMessageQueuePostMessage(pSbm->mq, &mMsg);
logd("** wait for reset sem");
SemTimedWait(&pSbm->resetSem, -1);
logd("** wait for reset sem ok");
memset(&mMsg, 0, sizeof(CdcMessage));
mMsg.messageId = SBM_THREAD_CMD_READ;
CdcMessageQueuePostMessage(pSbm->mq, &mMsg);
logd("SbmFrameReset finish");
return;
}
/*
**********************************************************************
* SbmBufferAddress
*
*Description: Get the base address of SBM buffer.
*
*Arguments : pSbm Created by SbmCreate function.
*
*Return : The base address of SBM buffer.
*
*Summary :
*
**********************************************************************
*/
static void *SbmFrameGetBufferAddress(SbmInterface* pSelf)
{
SbmFrame *pSbm = (SbmFrame*)pSelf;
if(pSbm == NULL)
{
loge("pSbm == NULL.");
return NULL;
}
return pSbm->pStreamBuffer;
}
/*
**********************************************************************
* SbmBufferSize
*
*Description: Get the sbm buffer size.
*
*Arguments : pSbm Created by SbmCreate function.
*
*Return : The size of SBM buffer, in Bytes.
*
*Summary : The size is set when create SBM.
*
**********************************************************************
*/
static int SbmFrameGetBufferSize(SbmInterface* pSelf)
{
SbmFrame* pSbm = (SbmFrame*)pSelf;
if(pSbm == NULL)
{
loge("pSbm == NULL.");
return 0;
}
return pSbm->nStreamBufferSize;
}
/*
**********************************************************************
* SbmStreamFrameNum
*
*Description: Get the total frames of undecoded stream data.
*
*Arguments : pSbm Created by SbmCreate function.
*
*Return : The frames of undecoded stream data.
*
*Summary :
*
**********************************************************************
*/
static int SbmFrameGetStreamFrameNum(SbmInterface* pSelf)
{
SbmFrame *pSbm = (SbmFrame*)pSelf;
if(pSbm == NULL)
{
loge("pSbm == NULL.");
return 0;
}
return pSbm->frameFifo.nValidFrameNum + pSbm->mFramePicFifo.nValidFramePicNum;
}
/*
**********************************************************************
* SbmStreamDataSize
*
*Description: Get the total size of undecoded data.
*
*Arguments : pSbm Created by SbmCreate function.
*
*Return : The total size of undecoded stream data, in bytes.
*
*Summary :
*
**********************************************************************
*/
static int SbmFrameGetStreamDataSize(SbmInterface* pSelf)
{
SbmFrame* pSbm = (SbmFrame*)pSelf;
if(pSbm == NULL)
{
loge("pSbm == NULL.");
return 0;
}
return pSbm->nValidDataSize;
}
static char* SbmFrameGetBufferWritePointer(SbmInterface* pSelf)
{
SbmFrame* pSbm = (SbmFrame*)pSelf;
if(pSbm == NULL)
{
loge("pSbm == NULL.");
return 0;
}
return pSbm->pWriteAddr;
}
static void* SbmFrameGetBufferDataInfo(SbmInterface* pSelf)
{
SbmFrame* pSbm = (SbmFrame*)pSelf;
FramePicInfo* pFramePic = NULL;
if(pSbm == NULL )
{
loge("pSbm == NULL.");
return NULL;
}
if(lock(pSbm) != 0)
{
return NULL;
}
if(pSbm->mFramePicFifo.nUnReadFramePicNum == 0)
{
logv("nUnReadFrameNum == 0.");
unlock(pSbm);
return NULL;
}
pFramePic = &pSbm->mFramePicFifo.pFramePics[pSbm->mFramePicFifo.nFPReadPos];
if(pFramePic == NULL)
{
loge("request failed.");
unlock(pSbm);
return NULL;
}
unlock(pSbm);
return pFramePic->pVideoInfo;
}
/*
**********************************************************************
* SbmRequestBuffer
*
*Description: Request buffer from sbm module.
*
*Arguments : pSbm Created by SbmCreate function;
* nRequireSize the required size, in bytes;
* ppBuf store the requested buffer address;
* pBufSize store the requested buffer size.
*
*Return : result;
* = 0; succeeded;
* = -1; failed.
*
*Summary : SBM buffer is cyclic, if the buffer turns around, there will be 2 blocks.
*
**********************************************************************
*/
static int SbmFrameRequestBuffer(SbmInterface* pSelf, int nRequireSize,
char **ppBuf, int *pBufSize)
{
SbmFrame *pSbm = (SbmFrame*)pSelf;
if(pSbm == NULL || ppBuf == NULL || pBufSize == NULL)
{
loge("input error.");
return -1;
}
if(lock(pSbm) != 0)
return -1;
if(pSbm->frameFifo.nValidFrameNum >= pSbm->frameFifo.nMaxFrameNum)
{
logv("nValidFrameNum >= nMaxFrameNum.");
unlock(pSbm);
return -1;
}
if(pSbm->nValidDataSize < pSbm->nStreamBufferSize)
{
int nFreeSize = pSbm->nStreamBufferSize - pSbm->nValidDataSize;
if((nRequireSize + 64) > nFreeSize)
{
unlock(pSbm);
return -1;
}
*ppBuf = pSbm->pWriteAddr;
*pBufSize = nRequireSize;
unlock(pSbm);
return 0;
}
else
{
loge("no free buffer.");
unlock(pSbm);
return -1;
}
}
/*
**********************************************************************
* SbmAddStream
*
*Description: Add one frame stream to sbm module.
*
*Arguments : pSbm Created by SbmCreate function;
* pDataInfo the stream info need to be added.
*
*Return : result;
* = 0; succeeded;
* = -1; failed.
*
*Summary : pDataInfo should contain Complete frame, bIsFirstPart=bIsLastPart=1.
*
**********************************************************************
*/
static int SbmFrameAddStream(SbmInterface* pSelf, VideoStreamDataInfo *pDataInfo)
{
SbmFrame *pSbm = (SbmFrame*)pSelf;
int nWritePos;
char *pNewWriteAddr;
if(pSbm == NULL || pDataInfo == NULL)
{
loge("input error.");
return -1;
}
if(lock(pSbm) != 0)
return -1;
if(pDataInfo->pData == 0)
{
loge("data buffer is NULL.\n");
unlock(pSbm);
return -1;
}
if(pSbm->frameFifo.nValidFrameNum >= pSbm->frameFifo.nMaxFrameNum)
{
loge("nValidFrameNum > nMaxFrameNum.");
unlock(pSbm);
return -1;
}
if(pDataInfo->nLength + pSbm->nValidDataSize > pSbm->nStreamBufferSize)
{
loge("no free buffer.");
unlock(pSbm);
return -1;
}
if(pDataInfo->bValid == 0)
{
pDataInfo->bValid = 1;
}
nWritePos = pSbm->frameFifo.nWritePos;
memcpy(&pSbm->frameFifo.pFrames[nWritePos], pDataInfo, sizeof(VideoStreamDataInfo));
nWritePos++;
if(nWritePos >= pSbm->frameFifo.nMaxFrameNum)
{
nWritePos = 0;
}
pSbm->frameFifo.nWritePos = nWritePos;
pSbm->frameFifo.nValidFrameNum++;
pSbm->frameFifo.nUnReadFrameNum++;
pSbm->nValidDataSize += pDataInfo->nLength;
pNewWriteAddr = pSbm->pWriteAddr + pDataInfo->nLength;
if(pNewWriteAddr > pSbm->pStreamBufferEnd)
{
pNewWriteAddr -= pSbm->nStreamBufferSize;
}
pSbm->pWriteAddr = pNewWriteAddr;
int nSemCnt = 0;
if(sem_getvalue(&pSbm->streamDataSem, &nSemCnt) == 0)
{
if(nSemCnt == 0)
sem_post(&pSbm->streamDataSem);
}
unlock(pSbm);
return 0;
}
//* in fact, this is the function of requestFramePic
static VideoStreamDataInfo* SbmFrameRequestFramePic(SbmInterface* pSelf) //* requestFramePic
{
SbmFrame* pSbm = (SbmFrame*)pSelf;
FramePicInfo* pFramePic = NULL;
if(pSbm == NULL )
{
loge("pSbm == NULL.");
return NULL;
}
if(lock(pSbm) != 0)
return NULL;
if(pSbm->mFramePicFifo.nUnReadFramePicNum == 0)
{
logv("nUnReadFrameNum == 0.");
unlock(pSbm);
return NULL;
}
pFramePic = &pSbm->mFramePicFifo.pFramePics[pSbm->mFramePicFifo.nFPReadPos];
if(pFramePic == NULL)
{
loge("request framePic failed");
unlock(pSbm);
return NULL;
}
pSbm->mFramePicFifo.nFPReadPos++;
pSbm->mFramePicFifo.nUnReadFramePicNum--;
if(pSbm->mFramePicFifo.nFPReadPos >= pSbm->mFramePicFifo.nMaxFramePicNum)
{
pSbm->mFramePicFifo.nFPReadPos = 0;
}
logv("sbm request stream, pos = %d, pFrame = %p, pts = %lld",
pSbm->mFramePicFifo.nFPReadPos,pFramePic, pFramePic->nPts);
unlock(pSbm);
return (VideoStreamDataInfo*)pFramePic;
}
//* in fact, this is the function of returnFramePic
static int SbmFrameReturnFramePic(SbmInterface* pSelf,
VideoStreamDataInfo *pDataInfo)
{
SbmFrame* pSbm = (SbmFrame*)pSelf;
FramePicInfo* pFramePic = (FramePicInfo*)pDataInfo;
int nReadPos;
if(pSbm == NULL || pFramePic == NULL)
{
loge("input error.");
return -1;
}
if(lock(pSbm) != 0)
return -1;
if(pSbm->mFramePicFifo.nValidFramePicNum == 0)
{
loge("nValidFrameNum == 0.");
unlock(pSbm);
return -1;
}
nReadPos = pSbm->mFramePicFifo.nFPReadPos;
nReadPos--;
if(nReadPos < 0)
{
nReadPos = pSbm->mFramePicFifo.nMaxFramePicNum - 1;
}
if(pFramePic != &pSbm->mFramePicFifo.pFramePics[nReadPos])
{
loge("wrong frame pic sequence.");
abort();
}
pSbm->mFramePicFifo.nFPReadPos = nReadPos;
pSbm->mFramePicFifo.nUnReadFramePicNum++;
unlock(pSbm);
return 0;
}
//* in fact, this is the function of flushFramePic
static int SbmFrameFlushFramePic(SbmInterface* pSelf,
VideoStreamDataInfo *pDataInfo)
{
SbmFrame* pSbm = (SbmFrame*)pSelf;
FramePicInfo* pFramePic = (FramePicInfo*)pDataInfo;
int nFlushPos;
if(pSbm == NULL || pFramePic == NULL)
{
loge("input error");
return -1;
}
if(lock(pSbm) != 0)
return -1;
if(pSbm->mFramePicFifo.nValidFramePicNum == 0)
{
loge("nValidFrameNum == 0.");
unlock(pSbm);
return -1;
}
nFlushPos = pSbm->mFramePicFifo.nFPFlushPos;
logv("sbm flush stream , pos = %d, pFrame = %p, %p",nFlushPos,
pFramePic, &pSbm->mFramePicFifo.pFramePics[nFlushPos]);
if(pFramePic != &pSbm->mFramePicFifo.pFramePics[nFlushPos])
{
loge("not current nFlushPos.");
abort();
}
nFlushPos++;
if(nFlushPos >= pSbm->mFramePicFifo.nMaxFramePicNum)
{
nFlushPos = 0;
}
pSbm->mFramePicFifo.nValidFramePicNum--;
pSbm->mFramePicFifo.nFPFlushPos = nFlushPos;
pSbm->nValidDataSize -= pFramePic->nlength;
int nSemCnt = 0;
if(sem_getvalue(&pSbm->emptyFramePicSem, &nSemCnt) == 0)
{
if(nSemCnt == 0)
sem_post(&pSbm->emptyFramePicSem);
}
unlock(pSbm);
return 0;
}
static int SbmFrameSetEos(SbmInterface* pSelf, int nEosFlag)
{
SbmFrame* pSbm = (SbmFrame*)pSelf;
if(pSbm == NULL)
{
logw("set eos failed");
return -1;
}
pSbm->nEosFlag = nEosFlag;
return 0;
}
/*
**********************************************************************
* SbmRequestStream
*
*Description: Request one frame stream data from sbm module to decoder.
*
*Arguments : pSbm Created by SbmCreate function;
*
*Return : The stream infomation.
*
*Summary : The stream data obeys FIFO rule.
*
**********************************************************************
*/
static VideoStreamDataInfo *requestStream(SbmFrame *pSbm)
{
VideoStreamDataInfo *pDataInfo;
if(pSbm == NULL )
{
loge("pSbm == NULL.");
return NULL;
}
if(lock(pSbm) != 0)
{
return NULL;
}
if(pSbm->frameFifo.nUnReadFrameNum == 0)
{
logv("nUnReadFrameNum == 0.");
unlock(pSbm);
return NULL;
}
pDataInfo = &pSbm->frameFifo.pFrames[pSbm->frameFifo.nReadPos];
if(pDataInfo == NULL)
{
loge("request failed.");
unlock(pSbm);
return NULL;
}
pSbm->frameFifo.nReadPos++;
pSbm->frameFifo.nUnReadFrameNum--;
if(pSbm->frameFifo.nReadPos >= pSbm->frameFifo.nMaxFrameNum)
{
pSbm->frameFifo.nReadPos = 0;
}
unlock(pSbm);
logv("*** reqeust stream, pDataInfo = %p, pos = %d",pDataInfo, pSbm->frameFifo.nReadPos - 1);
logv("*** reqeust stream, data: %x %x %x %x %x %x %x %x ",
pDataInfo->pData[0], pDataInfo->pData[1],pDataInfo->pData[2],pDataInfo->pData[3],
pDataInfo->pData[4],pDataInfo->pData[5],pDataInfo->pData[6],pDataInfo->pData[7]);
return pDataInfo;
}
/*
**********************************************************************
* SbmReturnStream
*
*Description: Return one undecoded frame to sbm module.
*
*Arguments : pSbm Created by SbmCreate function;
* pDataInfo the stream info need to be returned.
*
*Return : result;
* = 0; succeeded;
* = -1; failed.
*
*Summary : After returned, the stream data's sequence is the same as before.
*
**********************************************************************
*/
static int returnStream(SbmFrame* pSbm , VideoStreamDataInfo *pDataInfo)
{
int nReadPos;
if(pSbm == NULL || pDataInfo == NULL)
{
loge("input error.");
return -1;
}
if(lock(pSbm) != 0)
{
return -1;
}
if(pSbm->frameFifo.nValidFrameNum == 0)
{
loge("nValidFrameNum == 0.");
unlock(pSbm);
return -1;
}
nReadPos = pSbm->frameFifo.nReadPos;
nReadPos--;
if(nReadPos < 0)
{
nReadPos = pSbm->frameFifo.nMaxFrameNum - 1;
}
pSbm->frameFifo.nUnReadFrameNum++;
if(pDataInfo != &pSbm->frameFifo.pFrames[nReadPos])
{
loge("wrong frame sequence.");
abort();
}
pSbm->frameFifo.pFrames[nReadPos] = *pDataInfo;
pSbm->frameFifo.nReadPos = nReadPos;
unlock(pSbm);
return 0;
}
/*
**********************************************************************
* SbmFlushStream
*
*Description: Flush one frame which is requested from SBM.
*
*Arguments : pSbm Created by SbmCreate function;
* pDataInfo the stream info need to be flushed.
*
*Return : result;
* = 0; succeeded;
* = -1; failed.
*
*Summary : After flushed, the buffer can be used to store new stream.
*
**********************************************************************
*/
static int flushStream(SbmFrame *pSbm, VideoStreamDataInfo *pDataInfo, int bFlush)
{
int nFlushPos;
if(pSbm == NULL)
{
loge("pSbm == NULL.");
return -1;
}
if(lock(pSbm) != 0)
{
return -1;
}
if(pSbm->frameFifo.nValidFrameNum == 0)
{
loge("no valid frame., flush pos = %d, pDataInfo = %p",
pSbm->frameFifo.nFlushPos, pDataInfo);
unlock(pSbm);
return -1;
}
nFlushPos = pSbm->frameFifo.nFlushPos;
logv("flush stream, pDataInfo = %p, pos = %d, %p",
pDataInfo, nFlushPos,&pSbm->frameFifo.pFrames[nFlushPos]);
if(pDataInfo != &pSbm->frameFifo.pFrames[nFlushPos])
{
loge("not current nFlushPos.");
unlock(pSbm);
abort();
return -1;
}
nFlushPos++;
if(nFlushPos >= pSbm->frameFifo.nMaxFrameNum)
{
nFlushPos = 0;
}
pSbm->frameFifo.nValidFrameNum--;
if(bFlush)
pSbm->nValidDataSize -= pDataInfo->nLength;
pSbm->frameFifo.nFlushPos = nFlushPos; //*
unlock(pSbm);
return 0;
}
static FramePicInfo* requestEmptyFramePic(SbmFrame* pSbm)
{
int nWritePos = -1;
FramePicInfo* pFramePic = NULL;
if(pSbm == NULL)
{
logd("pSbm == NULL.");
return NULL;
}
if(lock(pSbm) != 0)
return NULL;
if(pSbm->mFramePicFifo.nValidFramePicNum >= pSbm->mFramePicFifo.nMaxFramePicNum)
{
logv("no emptye framePic");
unlock(pSbm);
return NULL;
}
nWritePos = pSbm->mFramePicFifo.nFPWritePos;
pFramePic = &pSbm->mFramePicFifo.pFramePics[nWritePos];
unlock(pSbm);
logv("request empty frame pic, pos = %d, pFramePic = %p",nWritePos, pFramePic);
return pFramePic;
}
static int addFramePic(SbmFrame* pSbm, FramePicInfo* pFramePic) //* addFramePic
{
int nWritePos = -1;
if(pSbm == NULL || pFramePic == NULL)
{
logd("error input");
return -1;
}
if(lock(pSbm) != 0)
return -1;
if(pSbm->mFramePicFifo.nValidFramePicNum >= pSbm->mFramePicFifo.nMaxFramePicNum)
{
loge("nValidFrameNum >= nMaxFrameNum.");
unlock(pSbm);
return -1;
}
nWritePos = pSbm->mFramePicFifo.nFPWritePos;
if(pFramePic != &pSbm->mFramePicFifo.pFramePics[nWritePos])
{
loge("the frame pic is not match: %p, %p, %d",
pFramePic, &pSbm->mFramePicFifo.pFramePics[nWritePos], nWritePos);
abort();
}
nWritePos++;
if(nWritePos >= pSbm->mFramePicFifo.nMaxFramePicNum)
{
nWritePos = 0;
}
pSbm->mFramePicFifo.nFPWritePos = nWritePos;
pSbm->mFramePicFifo.nValidFramePicNum++;
pSbm->mFramePicFifo.nUnReadFramePicNum++;
unlock(pSbm);
return 0;
}
static inline char readByteIdx(char *p, char *pStart, char *pEnd, s32 i)
{
logv("p = %p, start = %p, end = %p, i = %d",p,pStart, pEnd, i);
char c = 0x0;
if((p+i) <= pEnd)
c = p[i];
else
{
s32 d = (s32)(pEnd - p) + 1;
c = pStart[i - d];
}
return c;
}
static inline void ptrPlusOne(char **p, char *pStart, char *pEnd)
{
if((*p) == pEnd)
(*p) = pStart;
else
(*p) += 1;
}
static s32 checkBitStreamTypeWithStartCode(SbmFrame* pSbm,
VideoStreamDataInfo *pStream)
{
char *pBuf = NULL;
char tmpBuf[6] = {0};
const s32 nTsStreamType = 0x000001;
const s32 nForbiddenBitValue = 0;
const s32 nTemporalIdMinValue = 1;
char* pStart = pSbm->pStreamBuffer;
char* pEnd = pSbm->pStreamBufferEnd;
s32 nHadCheckBytesLen = 0;
s32 nCheck4BitsValue = -1;
s32 nTemporalId = -1;
s32 nForbiddenBit = -1;
//*1. process sbm-cycle-buffer case
pBuf = pStream->pData;
while((nHadCheckBytesLen + 6) < pStream->nLength)
{
tmpBuf[0] = readByteIdx(pBuf, pStart, pEnd, nHadCheckBytesLen + 0);
tmpBuf[1] = readByteIdx(pBuf, pStart, pEnd, nHadCheckBytesLen + 1);
tmpBuf[2] = readByteIdx(pBuf, pStart, pEnd, nHadCheckBytesLen + 2);
tmpBuf[3] = readByteIdx(pBuf, pStart, pEnd, nHadCheckBytesLen + 3);
tmpBuf[4] = readByteIdx(pBuf, pStart, pEnd, nHadCheckBytesLen + 4);
tmpBuf[5] = readByteIdx(pBuf, pStart, pEnd, nHadCheckBytesLen + 5);
nCheck4BitsValue = (tmpBuf[0] << 24) | (tmpBuf[1] << 16) | (tmpBuf[2] << 8) | tmpBuf[3];
if(nCheck4BitsValue == 0) //*compatible for the case: 00 00 00 00 00 00 00 01
{
nHadCheckBytesLen++;
continue;
}
if(nCheck4BitsValue == nTsStreamType)
{
nForbiddenBit = tmpBuf[4] >> 7; //* read 1 bits
nTemporalId = tmpBuf[5] & 0x7;//* read 3 bits
if(nTemporalId >= nTemporalIdMinValue && nForbiddenBit == nForbiddenBitValue)
{
pSbm->bStreamWithStartCode = 1;
return 0;
}
else
{
nHadCheckBytesLen += 4;
continue;
}
}
else if((nCheck4BitsValue >> 8) == nTsStreamType)
{
nForbiddenBit = tmpBuf[3] >> 7; //* read 1 bits
nTemporalId = tmpBuf[4] & 0x7;//* read 3 bits
if(nTemporalId >= nTemporalIdMinValue && nForbiddenBit == nForbiddenBitValue)
{
pSbm->bStreamWithStartCode = 1;
return 0;
}
else
{
nHadCheckBytesLen += 3;
continue;
}
}
else
{
nHadCheckBytesLen += 4;
continue;
}
}
return -1;
}
static s32 checkBitStreamTypeWithoutStartCode(SbmFrame* pSbm,
VideoStreamDataInfo *pStream)
{
const s32 nForbiddenBitValue = 0;
const s32 nTemporalIdMinValue = 1;
char *pBuf = NULL;
char tmpBuf[6] = {0};
s32 nTemporalId = -1;
s32 nForbiddenBit = -1;
s32 nDataSize = -1;
s32 nRemainSize = -1;
s32 nRet = -1;
char* pStart = pSbm->pStreamBuffer;
char* pEnd = pSbm->pStreamBufferEnd;
s32 nHadProcessLen = 0;
pBuf = pStream->pData;
while(nHadProcessLen < pStream->nLength)
{
nRemainSize = pStream->nLength-nHadProcessLen;
tmpBuf[0] = readByteIdx(pBuf, pStart, pEnd, 0);
tmpBuf[1] = readByteIdx(pBuf, pStart, pEnd, 1);
tmpBuf[2] = readByteIdx(pBuf, pStart, pEnd, 2);
tmpBuf[3] = readByteIdx(pBuf, pStart, pEnd, 3);
tmpBuf[4] = readByteIdx(pBuf, pStart, pEnd, 4);
tmpBuf[5] = readByteIdx(pBuf, pStart, pEnd, 5);
nDataSize = (tmpBuf[0] << 24) | (tmpBuf[1] << 16) | (tmpBuf[2] << 8) | tmpBuf[3];
nForbiddenBit = tmpBuf[4] >> 7; //* read 1 bits
nTemporalId = tmpBuf[5] & 0x7;//* read 3 bits
if(nDataSize > (nRemainSize - 4)
|| nDataSize < 0
|| nTemporalId < nTemporalIdMinValue
|| nForbiddenBit != nForbiddenBitValue)
{
logd("check stream type fail: nDataSize[%d], streamSize[%d], nTempId[%d], fobBit[%d]",
nDataSize, (pStream->nLength-nHadProcessLen),nTemporalId,nForbiddenBit);
nRet = -1;
break;
}
logv("*** nDataSize = %d, nRemainSize = %d, proceLen = %d, totalLen = %d",
nDataSize, nRemainSize,
nHadProcessLen,pStream->nLength);
if(nDataSize == (nRemainSize - 4) && nDataSize != 0)
{
nRet = 0;
break;
}
nHadProcessLen += nDataSize + 4;
pBuf = pStream->pData + nHadProcessLen;
if(pBuf - pSbm->pStreamBufferEnd > 0)
{
pBuf = pSbm->pStreamBuffer + (pBuf - pSbm->pStreamBufferEnd);
}
}
return nRet;
}
static s32 checkBitStreamType(SbmFrame* pSbm)
{
const s32 nUpLimitCount = 50;
s32 nReqeustCounter = 0;
s32 nRet = VDECODE_RESULT_NO_BITSTREAM;
s32 bStartCode_with = 0;
s32 bStartCode_without = 0;
while(nReqeustCounter < nUpLimitCount)
{
VideoStreamDataInfo *pStream = NULL;
nReqeustCounter++;
pStream = requestStream(pSbm);
if(pStream == NULL)
{
nRet = VDECODE_RESULT_NO_BITSTREAM;
break;
}
if(pStream->nLength == 0 || pStream->pData == NULL)
{
flushStream(pSbm, pStream, 1);
pStream = NULL;
continue;
}
if(checkBitStreamTypeWithStartCode(pSbm, pStream) == 0)
{
bStartCode_with = 1;
}
else
{
bStartCode_with = 0;
}
if(checkBitStreamTypeWithoutStartCode(pSbm, pStream) == 0)
{
bStartCode_without = 1;
}
else
{
bStartCode_without = 0;
}
if(bStartCode_with == 1 && bStartCode_without == 1)
{
pSbm->bStreamWithStartCode = 0;
}
else if(bStartCode_with == 1 && bStartCode_without == 0)
{
pSbm->bStreamWithStartCode = 1;
}
else if(bStartCode_with == 0 && bStartCode_without == 1)
{
pSbm->bStreamWithStartCode = 0;
}
else
{
pSbm->bStreamWithStartCode = -1;
}
logd("result: bStreamWithStartCode[%d], with[%d], whitout[%d]",pSbm->bStreamWithStartCode,
bStartCode_with, bStartCode_without);
//*continue reqeust stream from sbm when if judge the stream type
if(pSbm->bStreamWithStartCode == -1)
{
flushStream(pSbm, pStream, 1);
continue;
}
else
{
//* judge stream type successfully, return.
returnStream(pSbm, pStream);
nRet = 0;
break;
}
}
return nRet;
}
static void expandNaluList(FramePicInfo* pFramePic)
{
logd("nalu num for one frame is not enought, expand it: %d, %d",
pFramePic->nMaxNaluNum, pFramePic->nMaxNaluNum + DEFAULT_NALU_NUM);
pFramePic->nMaxNaluNum += DEFAULT_NALU_NUM;
pFramePic->pNaluInfoList = realloc(pFramePic->pNaluInfoList,
pFramePic->nMaxNaluNum*sizeof(NaluInfo));
}
static void chooseFramePts(DetectFramePicInfo* pDetectInfo)
{
int i;
pDetectInfo->pCurFramePic->nPts = -1;
for(i=0; i < MAX_FRAME_PTS_LIST_NUM; i++)
{
logv("*** choose pts: %lld, i = %d",pDetectInfo->nCurFramePtsList[i], i);
if(pDetectInfo->nCurFramePtsList[i] != -1)
{
pDetectInfo->pCurFramePic->nPts = pDetectInfo->nCurFramePtsList[i];
break;
}
}
}
static void initFramePicInfo(DetectFramePicInfo* pDetectInfo)
{
FramePicInfo* pFramePic = pDetectInfo->pCurFramePic;
pFramePic->bValidFlag = 1;
pFramePic->nlength = 0;
pFramePic->pDataStartAddr = NULL;
pFramePic->nPts = -1;
pFramePic->nPcr = -1;
pFramePic->nCurNaluIdx = 0;
int i;
for(i = 0; i < MAX_FRAME_PTS_LIST_NUM; i++)
pDetectInfo->nCurFramePtsList[i] = -1;
if(pFramePic->nMaxNaluNum > DEFAULT_NALU_NUM)
{
pFramePic->nMaxNaluNum = DEFAULT_NALU_NUM;
pFramePic->pNaluInfoList = realloc(pFramePic->pNaluInfoList,
pFramePic->nMaxNaluNum*sizeof(NaluInfo));
}
memset(pFramePic->pNaluInfoList, 0, pFramePic->nMaxNaluNum*sizeof(NaluInfo));
}
static int searchStartCode(SbmFrame* pSbm, int* pAfterStartCodeIdx)
{
char* pStart = pSbm->pStreamBuffer;
char* pEnd = pSbm->pStreamBufferEnd;
DetectFramePicInfo* pDetectInfo = &pSbm->mDetectInfo;
char* pBuf = pDetectInfo->pCurStreamDataptr;
s32 nSize = pDetectInfo->nCurStreamDataSize - 3;
if(pDetectInfo->nCurStreamRebackFlag)
{
logv("bHasTwoDataTrunk pSbmBuf: %p, pSbmBufEnd: %p, curr: %p, diff: %d ",
pStart, pEnd, pBuf, (u32)(pEnd - pBuf));
char tmpBuf[3];
while(nSize > 0)
{
tmpBuf[0] = readByteIdx(pBuf , pStart, pEnd, 0);
tmpBuf[1] = readByteIdx(pBuf , pStart, pEnd, 1);
tmpBuf[2] = readByteIdx(pBuf , pStart, pEnd, 2);
if(tmpBuf[0] == 0 && tmpBuf[1] == 0 && tmpBuf[2] == 1)
{
(*pAfterStartCodeIdx) += 3; //so that buf[0] is the actual data, not start code
return 0;
}
ptrPlusOne(&pBuf, pStart, pEnd);
++(*pAfterStartCodeIdx);
--nSize;
}
}
else
{
while(nSize > 0)
{
if(pBuf[0] == 0 && pBuf[1] == 0 && pBuf[2] == 1)
{
(*pAfterStartCodeIdx) += 3; //so that buf[0] is the actual data, not start code
return 0;
}
++pBuf;
++(*pAfterStartCodeIdx);
--nSize;
}
}
return -1;
}
static inline int supplyStreamData(SbmFrame* pSbm)
{
char* pEnd = pSbm->pStreamBufferEnd;
DetectFramePicInfo* pDetectInfo = &pSbm->mDetectInfo;
if(pDetectInfo->pCurStream)
{
flushStream(pSbm, pDetectInfo->pCurStream, 0);
pDetectInfo->pCurStream = NULL;
if(pDetectInfo->pCurFramePic)
{
pDetectInfo->pCurFramePic->nlength += pDetectInfo->nCurStreamDataSize;
}
pDetectInfo->nCurStreamDataSize = 0;
pDetectInfo->pCurStreamDataptr = NULL;
}
VideoStreamDataInfo *pStream = requestStream(pSbm);
if(pStream == NULL)
{
logv("no bit stream");
SemTimedWait(&pSbm->streamDataSem, 20);
return -1;
}
pDetectInfo->pCurStream = pStream;
pDetectInfo->pCurStreamDataptr = pDetectInfo->pCurStream->pData;
pDetectInfo->nCurStreamDataSize = pDetectInfo->pCurStream->nLength;
pDetectInfo->nCurStreamRebackFlag = 0;
if((pDetectInfo->pCurStream->pData + pDetectInfo->pCurStream->nLength) > pEnd)
{
pDetectInfo->nCurStreamRebackFlag = 1;
}
return 0;
}
static void disposeInvalidStreamData(SbmFrame* pSbm)
{
DetectFramePicInfo* pDetectInfo = &pSbm->mDetectInfo;
int bNeedAddFramePic = 0;
logd("**1 pCurFramePic->nlength = %d, flag = %d",pDetectInfo->pCurFramePic->nlength,
(pDetectInfo->pCurStreamDataptr == pDetectInfo->pCurStream->pData));
if(pDetectInfo->pCurStreamDataptr == pDetectInfo->pCurStream->pData
&& pDetectInfo->pCurFramePic->nlength == 0)
{
pDetectInfo->pCurFramePic->pDataStartAddr = pDetectInfo->pCurStream->pData;
pDetectInfo->pCurFramePic->nlength = pDetectInfo->pCurStream->nLength;
pDetectInfo->pCurFramePic->bValidFlag = 0;
bNeedAddFramePic = 1;
}
else
{
pDetectInfo->pCurFramePic->nlength += pDetectInfo->nCurStreamDataSize;
logd("**2, pCurFramePic->nlength = %d, diff = %d",pDetectInfo->pCurFramePic->nlength,
pDetectInfo->pCurFramePic->nlength - MAX_INVALID_STREAM_DATA_SIZE);
if(pDetectInfo->pCurFramePic->nlength > MAX_INVALID_STREAM_DATA_SIZE)
{
pDetectInfo->pCurFramePic->bValidFlag = 0;
bNeedAddFramePic = 1;
}
}
logd("bNeedAddFramePic = %d",bNeedAddFramePic );
flushStream(pSbm, pDetectInfo->pCurStream, 0);
pDetectInfo->pCurStream = NULL;
pDetectInfo->pCurStreamDataptr = NULL;
pDetectInfo->nCurStreamDataSize = 0;
if(bNeedAddFramePic)
{
addFramePic(pSbm, pDetectInfo->pCurFramePic);
pDetectInfo->pCurFramePic = NULL;
}
}
static inline void skipCurStreamDataBytes(SbmFrame* pSbm, int nSkipSize)
{
char* pStart = pSbm->pStreamBuffer;
char* pEnd = pSbm->pStreamBufferEnd;
DetectFramePicInfo* pDetectInfo = &pSbm->mDetectInfo;
pDetectInfo->pCurStreamDataptr += nSkipSize;
pDetectInfo->nCurStreamDataSize -= nSkipSize;
if(pDetectInfo->pCurStreamDataptr > pEnd)
{
pDetectInfo->pCurStreamDataptr = pStart + (pDetectInfo->pCurStreamDataptr - pEnd - 1);
}
pDetectInfo->pCurFramePic->nlength += nSkipSize;
}
static inline void storeNaluInfo(SbmFrame* pSbm, int nNaluType, int nNaluSize, char* pNaluBuf)
{
DetectFramePicInfo* pDetectInfo = &pSbm->mDetectInfo;
int nNaluIdx = pDetectInfo->pCurFramePic->nCurNaluIdx;
NaluInfo* pNaluInfo = &pDetectInfo->pCurFramePic->pNaluInfoList[nNaluIdx];
logv("*** nNaluIdx = %d, pts = %lld",nNaluIdx, pDetectInfo->pCurStream->nPts);
if(nNaluIdx < MAX_FRAME_PTS_LIST_NUM)
pDetectInfo->nCurFramePtsList[nNaluIdx] = pDetectInfo->pCurStream->nPts;
pNaluInfo->nType = nNaluType;
pNaluInfo->pDataBuf = pNaluBuf;
pNaluInfo->nDataSize = nNaluSize;
pDetectInfo->pCurFramePic->nCurNaluIdx++;
if(pDetectInfo->pCurFramePic->nCurNaluIdx >= pDetectInfo->pCurFramePic->nMaxNaluNum)
{
expandNaluList(pDetectInfo->pCurFramePic);
}
}
/*
detect step:
1. request bit stream
2. find startCode
3. read the naluType and bFirstSliceSegment
4. skip nAfterStartCodeIdx
5. find the next startCode to determine size of cur nalu
6. store nalu info
7. skip naluSize bytes
*/
static void detectWithStartCode(SbmFrame* pSbm)
{
char tmpBuf[6] = {0};
char* pStart = pSbm->pStreamBuffer;
char* pEnd = pSbm->pStreamBufferEnd;
int bFirstSliceSegment = 0;
DetectFramePicInfo* pDetectInfo = &pSbm->mDetectInfo;
if(pDetectInfo->pCurFramePic == NULL)
{
pDetectInfo->pCurFramePic = requestEmptyFramePic(pSbm);
if(pDetectInfo->pCurFramePic == NULL)
{
SemTimedWait(&pSbm->emptyFramePicSem, 20);
return ;
}
initFramePicInfo(pDetectInfo);
}
while(1)
{
//*1. request bit stream
if(pDetectInfo->nCurStreamDataSize < 5 || pDetectInfo->pCurStreamDataptr == NULL)
{
if(supplyStreamData(pSbm) != 0)
{
if(pDetectInfo->bCurFrameStartCodeFound == 1 && pSbm->nEosFlag == 1)
{
pDetectInfo->bCurFrameStartCodeFound = 0;
chooseFramePts(pDetectInfo);
addFramePic(pSbm, pDetectInfo->pCurFramePic);
logd("find eos, flush last stream frame, pts = %lld",
(long long int)pDetectInfo->pCurFramePic->nPts);
pDetectInfo->pCurFramePic = NULL;
}
return ;
}
}
if(pDetectInfo->pCurFramePic->pDataStartAddr == NULL)
{
pDetectInfo->pCurFramePic->pDataStartAddr = pDetectInfo->pCurStreamDataptr;
pDetectInfo->pCurFramePic->pVideoInfo = pDetectInfo->pCurStream->pVideoInfo;
}
//*2. find startCode
int nAfterStartCodeIdx = 0;
int nRet = searchStartCode(pSbm,&nAfterStartCodeIdx);
if(nRet != 0 //* can not find startCode
|| pDetectInfo->pCurFramePic->nCurNaluIdx > MAX_NALU_NUM_IN_FRAME)
{
logw("can not find startCode, curNaluIdx = %d, max = %d",
pDetectInfo->pCurFramePic->nCurNaluIdx, MAX_NALU_NUM_IN_FRAME);
disposeInvalidStreamData(pSbm);
return ;
}
//* now had find the startCode
//*3. read the naluType and bFirstSliceSegment
char* pAfterStartCodeBuf = pDetectInfo->pCurStreamDataptr + nAfterStartCodeIdx;
tmpBuf[0] = readByteIdx(pAfterStartCodeBuf ,pStart, pEnd, 0);
int nNaluType = (tmpBuf[0] & 0x7e) >> 1;
logv("*** nNaluType = %d",nNaluType);
if((nNaluType >= SBM_HEVC_NAL_VPS && nNaluType <= SBM_HEVC_NAL_AUD) ||
nNaluType == SBM_HEVC_NAL_SEI_PREFIX)
{
/* Begining of access unit, needn't bFirstSliceSegment */
if(pDetectInfo->bCurFrameStartCodeFound == 1)
{
pDetectInfo->bCurFrameStartCodeFound = 0;
chooseFramePts(pDetectInfo);
addFramePic(pSbm, pDetectInfo->pCurFramePic);
pDetectInfo->pCurFramePic = NULL;
return ;
}
}
if(IsFrameNalu(nNaluType))
{
tmpBuf[2] = readByteIdx(pAfterStartCodeBuf ,pStart, pEnd, 2);
bFirstSliceSegment = (tmpBuf[2] >> 7);
logv("***bFirstSliceSegment = %d", bFirstSliceSegment);
if(bFirstSliceSegment == 1)
{
if(pDetectInfo->bCurFrameStartCodeFound == 0)
{
logv("pCurFramePic = %p, pCurStream = %p",
pDetectInfo->pCurFramePic, pDetectInfo->pCurStream);
pDetectInfo->bCurFrameStartCodeFound = 1;
pDetectInfo->pCurFramePic->nFrameNaluType = nNaluType;
}
else
{
logv("**** have found one frame pic ****");
pDetectInfo->bCurFrameStartCodeFound = 0;
chooseFramePts(pDetectInfo);
addFramePic(pSbm, pDetectInfo->pCurFramePic);
pDetectInfo->pCurFramePic = NULL;
return ;
}
}
}
//*if code run here, it means that this is the normal nalu of new frame, we should store it
//*4. skip nAfterStartCodeIdx
skipCurStreamDataBytes(pSbm, nAfterStartCodeIdx);
//*5. find the next startCode to determine size of cur nalu
int nNaluSize = 0;
nAfterStartCodeIdx = 0;
nRet = searchStartCode(pSbm,&nAfterStartCodeIdx);
if(nRet != 0)//* can not find next startCode
{
nNaluSize = pDetectInfo->nCurStreamDataSize;
}
else
{
nNaluSize = nAfterStartCodeIdx - 3; //* 3 is the length of startCode
}
//*6. store nalu info
storeNaluInfo(pSbm, nNaluType, nNaluSize, pDetectInfo->pCurStreamDataptr);
//*7. skip naluSize bytes
skipCurStreamDataBytes(pSbm, nNaluSize);
}
return ;
}
/*
detect step:
1. request bit stream
2. read nalu size
3. read the naluType and bFirstSliceSegment
4. skip 4 bytes
5. store nalu info
6. skip naluSize bytes
*/
static void detectWithoutStartCode(SbmFrame* pSbm)
{
char tmpBuf[6] = {0};
char* pStart = pSbm->pStreamBuffer;
char* pEnd = pSbm->pStreamBufferEnd;
unsigned int bFirstSliceSegment=0;
const int nPrefixBytes = 4; // indicate data length
//int i = 0;
DetectFramePicInfo* pDetectInfo = &pSbm->mDetectInfo;
if(pDetectInfo->pCurFramePic == NULL)
{
pDetectInfo->pCurFramePic = requestEmptyFramePic(pSbm);
if(pDetectInfo->pCurFramePic == NULL)
{
SemTimedWait(&pSbm->emptyFramePicSem, 20);
return ;
}
initFramePicInfo(pDetectInfo);
}
while(1)
{
//*1. request bit stream
if(pDetectInfo->nCurStreamDataSize < 5 || pDetectInfo->pCurStreamDataptr == NULL)
{
if(supplyStreamData(pSbm) != 0)
{
if(pDetectInfo->bCurFrameStartCodeFound == 1 && pSbm->nEosFlag == 1)
{
pDetectInfo->bCurFrameStartCodeFound = 0;
chooseFramePts(pDetectInfo);
addFramePic(pSbm, pDetectInfo->pCurFramePic);
pDetectInfo->pCurFramePic = NULL;
}
return ;
}
}
if(pDetectInfo->pCurFramePic->pDataStartAddr == NULL)
{
pDetectInfo->pCurFramePic->pDataStartAddr = pDetectInfo->pCurStreamDataptr;
pDetectInfo->pCurFramePic->pVideoInfo = pDetectInfo->pCurStream->pVideoInfo;
}
//*2. read nalu size
tmpBuf[0] = readByteIdx(pDetectInfo->pCurStreamDataptr ,pStart,pEnd, 0);
tmpBuf[1] = readByteIdx(pDetectInfo->pCurStreamDataptr ,pStart,pEnd, 1);
tmpBuf[2] = readByteIdx(pDetectInfo->pCurStreamDataptr ,pStart,pEnd, 2);
tmpBuf[3] = readByteIdx(pDetectInfo->pCurStreamDataptr ,pStart,pEnd, 3);
unsigned int nNaluSize = 0;
nNaluSize = (tmpBuf[0] << 24) | (tmpBuf[1] << 16) | (tmpBuf[2] << 8) | tmpBuf[3];
logv("*** read nalu size = %u, ",nNaluSize);
if(nNaluSize > (pDetectInfo->nCurStreamDataSize - nPrefixBytes)
|| nNaluSize == 0
|| pDetectInfo->pCurFramePic->nCurNaluIdx > MAX_NALU_NUM_IN_FRAME)
{
logw(" error: nNaluSize[%u] > nCurStreamDataSize[%d], curNaluIdx = %d, max = %d",
nNaluSize, pDetectInfo->nCurStreamDataSize,
pDetectInfo->pCurFramePic->nCurNaluIdx, MAX_NALU_NUM_IN_FRAME);
disposeInvalidStreamData(pSbm);
return ;
}
//*3. read the naluType and bFirstSliceSegment
char* pAfterStartCodePtr = NULL;
unsigned int nNaluType=0;
pAfterStartCodePtr = pDetectInfo->pCurStreamDataptr + nPrefixBytes;
tmpBuf[0] = readByteIdx(pAfterStartCodePtr ,pStart, pEnd, 0);
nNaluType = (tmpBuf[0] & 0x7e) >> 1;
logv("*** nNaluType = %d",nNaluType);
if((nNaluType >= SBM_HEVC_NAL_VPS && nNaluType <= SBM_HEVC_NAL_AUD) ||
nNaluType == SBM_HEVC_NAL_SEI_PREFIX)
{
/* Begining of access unit, needn't bFirstSliceSegment */
if(pDetectInfo->bCurFrameStartCodeFound == 1)
{
pDetectInfo->bCurFrameStartCodeFound = 0;
chooseFramePts(pDetectInfo);
addFramePic(pSbm, pDetectInfo->pCurFramePic);
pDetectInfo->pCurFramePic = NULL;
return ;
}
}
if(IsFrameNalu(nNaluType))
{
tmpBuf[2] = readByteIdx(pAfterStartCodePtr ,pStart, pEnd, 2);
bFirstSliceSegment = (tmpBuf[2] >> 7);
logv("***bFirstSliceSegment = %d", bFirstSliceSegment);
if(bFirstSliceSegment == 1)
{
if(pDetectInfo->bCurFrameStartCodeFound == 0)
{
pDetectInfo->bCurFrameStartCodeFound = 1;
pDetectInfo->pCurFramePic->nFrameNaluType = nNaluType;
}
else
{
logv("**** have found one frame pic ****");
pDetectInfo->bCurFrameStartCodeFound = 0;
chooseFramePts(pDetectInfo);
addFramePic(pSbm, pDetectInfo->pCurFramePic);
pDetectInfo->pCurFramePic = NULL;
return ;
}
}
}
//*4. skip 4 bytes
skipCurStreamDataBytes(pSbm, nPrefixBytes);
//*5. store nalu info
storeNaluInfo(pSbm, nNaluType, nNaluSize, pDetectInfo->pCurStreamDataptr);
//*6. skip naluSize bytes
skipCurStreamDataBytes(pSbm, nNaluSize);
}
return ;
}
static void detectOneFramePic(SbmFrame* pSbm)
{
logv("pSbm->bStreamWithStartCode = %d",pSbm->bStreamWithStartCode);
if(pSbm->bStreamWithStartCode == 1)
{
detectWithStartCode(pSbm);
}
else
{
detectWithoutStartCode(pSbm);
}
}
static void* ProcessThread(void* pThreadData)
{
SbmFrame* pSbm = (SbmFrame*)pThreadData;
DetectFramePicInfo* pDetectInfo = &pSbm->mDetectInfo;
CdcMessage msg;
memset(&msg, 0, sizeof(CdcMessage));
while(1)
{
if(CdcMessageQueueTryGetMessage(pSbm->mq, &msg, 20) == 0)
{
//* process message here
if(msg.messageId == SBM_THREAD_CMD_QUIT)
{
goto EXIT;
}
else if(msg.messageId == SBM_THREAD_CMD_READ)
{
if(pSbm->bStreamWithStartCode == -1)
{
checkBitStreamType(pSbm);
}
else
{
detectOneFramePic(pSbm);
}
if(CdcMessageQueueGetCount(pSbm->mq) <= 0)
{
msg.messageId = SBM_THREAD_CMD_READ;
CdcMessageQueuePostMessage(pSbm->mq, &msg);
}
}
else if(msg.messageId == SBM_THREAD_CMD_RESET)
{
logd("*** post reset sem");
if(pDetectInfo->pCurStream)
{
flushStream(pSbm, pDetectInfo->pCurStream, 0);
pDetectInfo->pCurStream = NULL;
}
lock(pSbm);
pDetectInfo->bCurFrameStartCodeFound = 0;
pDetectInfo->nCurStreamDataSize = 0;
pDetectInfo->nCurStreamRebackFlag = 0;
pDetectInfo->pCurStreamDataptr = NULL;
if(pDetectInfo->pCurFramePic)
{
pDetectInfo->pCurFramePic = NULL;
}
pSbm->pWriteAddr = pSbm->pStreamBuffer;
pSbm->nValidDataSize = 0;
pSbm->frameFifo.nReadPos = 0;
pSbm->frameFifo.nWritePos = 0;
pSbm->frameFifo.nFlushPos = 0;
pSbm->frameFifo.nValidFrameNum = 0;
pSbm->frameFifo.nUnReadFrameNum = 0;
pSbm->mFramePicFifo.nFPFlushPos = 0;
pSbm->mFramePicFifo.nFPReadPos = 0;
pSbm->mFramePicFifo.nFPWritePos = 0;
pSbm->mFramePicFifo.nUnReadFramePicNum = 0;
pSbm->mFramePicFifo.nValidFramePicNum = 0;
unlock(pSbm);
sem_t* replySem = (sem_t*)msg.params[0];
sem_post(replySem);
//* do nothing
}
}
}
EXIT:
logd(" exit sbm thread ");
return NULL;
}
SbmInterface* GetSbmInterfaceFrame()
{
logd("******* sbm-type: Frame*******");
SbmFrame* pSbmFrame = NULL;
pSbmFrame = (SbmFrame*)malloc(sizeof(SbmFrame));
if(pSbmFrame == NULL)
{
loge("malloc for sbm frame struct failed");
return NULL;
}
memset(pSbmFrame, 0, sizeof(SbmFrame));
pSbmFrame->sbmInterface.init = SbmFrameInit;
pSbmFrame->sbmInterface.destroy = SbmFrameDestroy;
pSbmFrame->sbmInterface.reset = SbmFrameReset;
pSbmFrame->sbmInterface.getBufferSize = SbmFrameGetBufferSize;
pSbmFrame->sbmInterface.getStreamDataSize = SbmFrameGetStreamDataSize;
pSbmFrame->sbmInterface.getStreamFrameNum = SbmFrameGetStreamFrameNum;
pSbmFrame->sbmInterface.getBufferAddress = SbmFrameGetBufferAddress;
pSbmFrame->sbmInterface.getBufferWritePointer = SbmFrameGetBufferWritePointer;
pSbmFrame->sbmInterface.getBufferDataInfo = SbmFrameGetBufferDataInfo;
pSbmFrame->sbmInterface.requestBuffer = SbmFrameRequestBuffer;
pSbmFrame->sbmInterface.addStream = SbmFrameAddStream;
pSbmFrame->sbmInterface.requestStream = SbmFrameRequestFramePic;
pSbmFrame->sbmInterface.returnStream = SbmFrameReturnFramePic;
pSbmFrame->sbmInterface.flushStream = SbmFrameFlushFramePic;
pSbmFrame->sbmInterface.setEos = SbmFrameSetEos;
pSbmFrame->sbmInterface.nType = SBM_TYPE_FRAME;
return &pSbmFrame->sbmInterface;
}
SbmInterface* GetSbmInterface(int nType)
{
if(nType == SBM_TYPE_STREAM)
{
return GetSbmInterfaceStream();
}
else if(nType == SBM_TYPE_FRAME)
{
return GetSbmInterfaceFrame();
}
else if(nType == SBM_TYPE_FRAME_AVC)
{
return GetSbmInterfaceFrameAvc();
}
else
{
loge("not support the sbm interface type = %d",nType);
return NULL;
}
return NULL;
}