sdk-hwV1.3/external/eyesee-mpp/middleware/sun8iw21/media/mpi_mux.c

1203 lines
38 KiB
C
Executable File

/******************************************************************************
Copyright (C), 2001-2016, Allwinner Tech. Co., Ltd.
******************************************************************************
File Name : mpi_venc.c
Version : Initial Draft
Author : Allwinner BU3-PD2 Team
Created : 2016/05/23
Last Modified :
Description : mpi functions implement for mux module.
Function List :
History :
******************************************************************************/
#define LOG_TAG "mpi_mux"
#include <utils/plat_log.h>
//ref platform headers
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "plat_type.h"
#include "plat_errno.h"
#include "plat_defines.h"
#include "plat_math.h"
#include "cdx_list.h"
//media api headers to app
#include "mm_common.h"
#include "mm_comm_mux.h"
#include "mpi_mux.h"
//media internal common headers.
#include <tsemaphore.h>
#include <media_common.h>
#include <mm_component.h>
#include <mpi_mux_common.h>
#include <RecRender_Component.h>
#include <EncodedStream.h>
typedef struct
{
struct list_head mMuxChnList; //element type: MUX_CHN_S
pthread_mutex_t mMuxChnListLock;
}MuxChnManager;
MuxChnManager *gMuxChnMgr = NULL;
typedef struct MUX_CHN_S
{
MUX_CHN mMuxChn; // mux channel id, [0, MUX_MAX_CHN_NUM)
MM_COMPONENTTYPE *mComp; // mux component instance
cdx_sem_t mSemCompCmd;
//cdx_sem_t mSemAddChn;
//cdx_sem_t mSemRemoveChn;
MPPCallbackInfo mCallbackInfo;
cdx_sem_t mSemWaitEncodedStreamRelease;
pthread_mutex_t mSendStreamSyncLock; //used for AW_MPI_MUX_SendVideoStreamSync(),etc.
struct list_head mList;
}MUX_CHN_S;
static ERRORTYPE MUX_searchExistChn_l(PARAM_IN MUX_CHN muxChn, PARAM_OUT MUX_CHN_S **ppChn)
{
ERRORTYPE ret = ERR_MUX_UNEXIST;
MUX_CHN_S* pEntry;
list_for_each_entry(pEntry, &gMuxChnMgr->mMuxChnList, mList)
{
if(pEntry->mMuxChn == muxChn)
{
if(ppChn)
{
*ppChn = pEntry;
}
ret = SUCCESS;
break;
}
}
return ret;
}
static ERRORTYPE MUX_searchExistChn(PARAM_IN MUX_CHN muxChn, PARAM_OUT MUX_CHN_S **ppChn)
{
ERRORTYPE ret = ERR_MUX_UNEXIST;
MUX_CHN_S* pEntry;
pthread_mutex_lock(&gMuxChnMgr->mMuxChnListLock);
ret = MUX_searchExistChn_l(muxChn, ppChn);
pthread_mutex_unlock(&gMuxChnMgr->mMuxChnListLock);
return ret;
}
static ERRORTYPE addChn_l(MUX_CHN_S *pChn)
{
list_add_tail(&pChn->mList, &gMuxChnMgr->mMuxChnList);
return SUCCESS;
}
static ERRORTYPE addChn(MUX_CHN_S *pChn)
{
pthread_mutex_lock(&gMuxChnMgr->mMuxChnListLock);
list_add_tail(&pChn->mList, &gMuxChnMgr->mMuxChnList);
pthread_mutex_unlock(&gMuxChnMgr->mMuxChnListLock);
return SUCCESS;
}
static ERRORTYPE removeChn(MUX_CHN_S *pChn)
{
pthread_mutex_lock(&gMuxChnMgr->mMuxChnListLock);
list_del(&pChn->mList);
pthread_mutex_unlock(&gMuxChnMgr->mMuxChnListLock);
return SUCCESS;
}
static MUX_CHN_S* MUX_CHN_S_Construct()
{
int ret;
MUX_CHN_S *pChn = (MUX_CHN_S*)malloc(sizeof(MUX_CHN_S));
if(NULL == pChn)
{
aloge("fatal error! malloc fail[%s]!", strerror(errno));
return NULL;
}
memset(pChn, 0, sizeof(MUX_CHN_S));
ret = cdx_sem_init(&pChn->mSemCompCmd, 0);
if (ret!=0)
{
aloge("fatal error! cdx sem init fail:%d", ret);
}
//cdx_sem_init(&pChn->mSemAddChn, 0);
//cdx_sem_init(&pChn->mSemRemoveChn, 0);
ret = cdx_sem_init(&pChn->mSemWaitEncodedStreamRelease, 0);
if (ret!=0)
{
aloge("fatal error! cdx sem init fail:%d", ret);
}
ret = pthread_mutex_init(&pChn->mSendStreamSyncLock, NULL);
if (ret!=0)
{
aloge("fatal error! mutex init fail:%d", ret);
}
return pChn;
}
static void MUX_CHN_S_Destruct(MUX_CHN_S *pChn)
{
if(pChn->mComp)
{
aloge("fatal error! mux component need free before!");
COMP_FreeHandle(pChn->mComp);
pChn->mComp = NULL;
}
cdx_sem_deinit(&pChn->mSemCompCmd);
//cdx_sem_deinit(&pGroup->mSemAddChn);
//cdx_sem_deinit(&pGroup->mSemRemoveChn);
cdx_sem_deinit(&pChn->mSemWaitEncodedStreamRelease);
pthread_mutex_destroy(&pChn->mSendStreamSyncLock);
free(pChn);
}
ERRORTYPE MUX_Construct(void)
{
ERRORTYPE eError = SUCCESS;
int ret;
if(gMuxChnMgr)
{
alogw("mpi_mux module already create!");
return SUCCESS;
}
gMuxChnMgr = malloc(sizeof(MuxChnManager));
if(NULL == gMuxChnMgr)
{
aloge("fatal error! malloc fail!");
return ERR_MUX_NULL_PTR;
}
INIT_LIST_HEAD(&gMuxChnMgr->mMuxChnList);
ret = pthread_mutex_init(&gMuxChnMgr->mMuxChnListLock, NULL);
if (ret!=0)
{
aloge("fatal error! mutex init fail");
eError = ERR_MUX_NOMEM;
goto _err0;
}
return eError;
_err0:
free(gMuxChnMgr);
gMuxChnMgr = NULL;
return eError;
}
ERRORTYPE MUX_Destruct(void)
{
if(NULL == gMuxChnMgr)
{
alogw("mpi_mux module already NULL!");
return SUCCESS;
}
pthread_mutex_lock(&gMuxChnMgr->mMuxChnListLock);
if(!list_empty(&gMuxChnMgr->mMuxChnList))
{
pthread_mutex_unlock(&gMuxChnMgr->mMuxChnListLock);
aloge("fatal error! mux channel list is not empty!");
return ERR_MUX_BUSY;
}
pthread_mutex_unlock(&gMuxChnMgr->mMuxChnListLock);
pthread_mutex_destroy(&gMuxChnMgr->mMuxChnListLock);
free(gMuxChnMgr);
gMuxChnMgr = NULL;
return SUCCESS;
}
MM_COMPONENTTYPE *MUX_GetChnComp(PARAM_IN MPP_CHN_S *pMppchn)
{
MUX_CHN_S* pChn;
if (MUX_searchExistChn(pMppchn->mChnId, &pChn) != SUCCESS)
{
return NULL;
}
return pChn->mComp;
}
static ERRORTYPE RecRenderEventHandler(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_IN void* pAppData,
PARAM_IN COMP_EVENTTYPE eEvent,
PARAM_IN unsigned int nData1,
PARAM_IN unsigned int nData2,
PARAM_IN void* pEventData)
{
ERRORTYPE ret;
MUX_CHN_S *pChn = (MUX_CHN_S*)pAppData;
MPP_CHN_S ChannelInfo;
ChannelInfo.mModId = MOD_ID_MUX;
ChannelInfo.mDevId = 0;
ChannelInfo.mChnId = pChn->mMuxChn;
switch(eEvent)
{
case COMP_EventCmdComplete:
{
if(COMP_CommandStateSet == nData1)
{
alogv("muxChn EventCmdComplete, current StateSet[%d]", nData2);
cdx_sem_up(&pChn->mSemCompCmd);
break;
}
else
{
alogw("Low probability! what command[0x%x]?", nData1);
break;
}
}
case COMP_EventError:
{
if(ERR_MUX_SAMESTATE == nData1)
{
alogv("set same state to muxChn!");
cdx_sem_up(&pChn->mSemCompCmd);
break;
}
else if(ERR_MUX_INVALIDSTATE == nData1)
{
aloge("why muxChn state turn to invalid?");
break;
}
else if(ERR_MUX_INCORRECT_STATE_TRANSITION == nData1)
{
aloge("fatal error! muxChn state transition incorrect.");
break;
}
else
{
aloge("fatal error! other param[%d][%d]", nData1, nData2);
break;
}
}
case COMP_EventNeedNextFd:
{
CHECK_MPP_CALLBACK(pChn->mCallbackInfo.callback);
pChn->mCallbackInfo.callback(pChn->mCallbackInfo.cookie, &ChannelInfo, MPP_EVENT_NEED_NEXT_FD, (void*)&nData1);
break;
}
case COMP_EventRecordDone:
{
CHECK_MPP_CALLBACK(pChn->mCallbackInfo.callback);
pChn->mCallbackInfo.callback(pChn->mCallbackInfo.cookie, &ChannelInfo, MPP_EVENT_RECORD_DONE, (void*)&nData1);
break;
}
case COMP_EventBsframeAvailable:
{
CHECK_MPP_CALLBACK(pChn->mCallbackInfo.callback);
pChn->mCallbackInfo.callback(pChn->mCallbackInfo.cookie, &ChannelInfo, MPP_EVENT_BSFRAME_AVAILABLE, pEventData);
break;
}
case COMP_EventWriteDiskError:
{
CHECK_MPP_CALLBACK(pChn->mCallbackInfo.callback);
pChn->mCallbackInfo.callback(pChn->mCallbackInfo.cookie, &ChannelInfo, MPP_EVENT_WRITE_DISK_ERROR, (void*)&nData1);
break;
}
case COMP_EventMuxForceIFrame:
{
CHECK_MPP_CALLBACK(pChn->mCallbackInfo.callback);
pChn->mCallbackInfo.callback(pChn->mCallbackInfo.cookie, &ChannelInfo, MPP_EVENT_MUX_FORCE_I_FRAME, (void*)&nData1);
break;
}
default:
aloge("fatal error! unknown event[0x%x]", eEvent);
break;
}
return SUCCESS;
}
static ERRORTYPE RecRenderEmptyBufferDone(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_IN void* pAppData,
PARAM_IN COMP_BUFFERHEADERTYPE* pBuffer)
{
MUX_CHN_S *pChn = (MUX_CHN_S*)pAppData;
EncodedStream *pEncodedStream = (EncodedStream*)pBuffer->pAppPrivate;
int nStreamId = pBuffer->nInputPortIndex;
MPP_CHN_S stMppChn;
stMppChn.mModId = MOD_ID_MUX;
stMppChn.mDevId = 0;
stMppChn.mChnId = pChn->mMuxChn;
/* ENCODED_FRAME_ID_INVALID means that usr sends frame synchronously */
if (ENCODED_FRAME_ID_INVALID == pEncodedStream->nID)
{
cdx_sem_up(&pChn->mSemWaitEncodedStreamRelease);
return SUCCESS;
}
else
{
CHECK_MPP_CALLBACK(pChn->mCallbackInfo.callback);
if(CDX_PacketVideo == pEncodedStream->media_type)
{
MUX_VENC_STREAM_S stMuxVencStream;
VENC_PACK_S stVencPack;
memset(&stMuxVencStream, 0, sizeof(MUX_VENC_STREAM_S));
memset(&stVencPack, 0, sizeof(VENC_PACK_S));
stMuxVencStream.mVencStream.mpPack = &stVencPack;
stMuxVencStream.mVencStream.mPackCount = 1;
stMuxVencStream.mVencStream.mpPack[0].mpAddr0 = pEncodedStream->pBuffer;
stMuxVencStream.mVencStream.mpPack[0].mpAddr1 = pEncodedStream->pBufferExtra;
stMuxVencStream.mVencStream.mpPack[0].mpAddr2 = pEncodedStream->pBufferExtra2;
stMuxVencStream.mVencStream.mpPack[0].mLen0 = pEncodedStream->nBufferLen;
stMuxVencStream.mVencStream.mpPack[0].mLen1 = pEncodedStream->nBufferExtraLen;
stMuxVencStream.mVencStream.mpPack[0].mLen2 = pEncodedStream->nBufferExtraLen2;
stMuxVencStream.mVencStream.mpPack[0].mPTS = pEncodedStream->nTimeStamp;
stMuxVencStream.mVencStream.mpPack[0].mbFrameEnd = TRUE;
stMuxVencStream.mVencStream.mSeq = pEncodedStream->nID;
stMuxVencStream.mStreamId = nStreamId;
pChn->mCallbackInfo.callback(pChn->mCallbackInfo.cookie, &stMppChn, MPP_EVENT_RELEASE_VENC_STREAM, (void*)&stMuxVencStream);
}
else if(CDX_PacketAudio == pEncodedStream->media_type)
{
MUX_AENC_STREAM_S stMuxAencStream;
memset(&stMuxAencStream, 0, sizeof(MUX_AENC_STREAM_S));
stMuxAencStream.mAencStream.pStream = pEncodedStream->pBuffer;
stMuxAencStream.mAencStream.mLen = pEncodedStream->nBufferLen;
stMuxAencStream.mAencStream.pStreamExtra = pEncodedStream->pBufferExtra;
stMuxAencStream.mAencStream.mExtraLen = pEncodedStream->nBufferExtraLen;
stMuxAencStream.mAencStream.mTimeStamp = pEncodedStream->nTimeStamp;
stMuxAencStream.mAencStream.mId = pEncodedStream->nID;
stMuxAencStream.mStreamId = nStreamId;
pChn->mCallbackInfo.callback(pChn->mCallbackInfo.cookie, &stMppChn, MPP_EVENT_RELEASE_AENC_STREAM, (void*)&stMuxAencStream);
}
else if(CDX_PacketSubtitle == pEncodedStream->media_type)
{
MUX_TENC_STREAM_S stMuxTencStream;
memset(&stMuxTencStream, 0, sizeof(MUX_TENC_STREAM_S));
stMuxTencStream.mTencStream.pStream = pEncodedStream->pBuffer;
stMuxTencStream.mTencStream.mLen = pEncodedStream->nBufferLen;
stMuxTencStream.mTencStream.pStreamExtra = pEncodedStream->pBufferExtra;
stMuxTencStream.mTencStream.mExtraLen = pEncodedStream->nBufferExtraLen;
stMuxTencStream.mTencStream.mTimeStamp = pEncodedStream->nTimeStamp;
stMuxTencStream.mTencStream.mId = pEncodedStream->nID;
stMuxTencStream.mStreamId = nStreamId;
pChn->mCallbackInfo.callback(pChn->mCallbackInfo.cookie, &stMppChn, MPP_EVENT_RELEASE_TENC_STREAM, (void*)&stMuxTencStream);
}
else
{
aloge("fatal error! muxChn[%d] encoded stream type[%d] is wrong!", pChn->mMuxChn, pEncodedStream->media_type);
}
return SUCCESS;
}
}
COMP_CALLBACKTYPE RecRenderCallback = {
.EventHandler = RecRenderEventHandler,
.EmptyBufferDone = RecRenderEmptyBufferDone,
.FillBufferDone = NULL,
};
ERRORTYPE AW_MPI_MUX_CreateChn(MUX_CHN muxChn, MUX_CHN_ATTR_S *pChnAttr, int nFd, int nFallocateLen)
{
if(!(muxChn>=0 && muxChn <MUX_MAX_CHN_NUM))
{
aloge("fatal error! invalid muxChn[%d]!", muxChn);
return ERR_MUX_INVALID_CHNID;
}
if(NULL == pChnAttr)
{
aloge("fatal error! illagal MuxChnAttr!");
return ERR_MUX_ILLEGAL_PARAM;
}
pthread_mutex_lock(&gMuxChnMgr->mMuxChnListLock);
if(SUCCESS == MUX_searchExistChn_l(muxChn, NULL))
{
pthread_mutex_unlock(&gMuxChnMgr->mMuxChnListLock);
return ERR_MUX_EXIST;
}
MUX_CHN_S *pNode = MUX_CHN_S_Construct();
pNode->mMuxChn = muxChn;
//create mux Component here
ERRORTYPE eRet = SUCCESS;
eRet = COMP_GetHandle((COMP_HANDLETYPE*)&pNode->mComp, CDX_ComponentNameMuxer, (void*)pNode, &RecRenderCallback);
if(eRet != SUCCESS)
{
aloge("fatal error! get comp handle fail!");
}
MPP_CHN_S ChannelInfo;
ChannelInfo.mModId = MOD_ID_MUX;
ChannelInfo.mDevId = 0;
ChannelInfo.mChnId = pNode->mMuxChn;
eRet = COMP_SetConfig(pNode->mComp, COMP_IndexVendorMPPChannelInfo, (void*)&ChannelInfo);
eRet = COMP_SetConfig(pNode->mComp, COMP_IndexVendorMuxChnAttr, (void*)pChnAttr);
CdxFdT stCdxFd;
stCdxFd.mFd = nFd;
stCdxFd.mnFallocateLen = nFallocateLen;
eRet = COMP_SetConfig(pNode->mComp, COMP_IndexVendorMuxFD, (void*)&stCdxFd);
eRet = COMP_SendCommand(pNode->mComp, COMP_CommandStateSet, COMP_StateIdle, NULL);
cdx_sem_down(&pNode->mSemCompCmd);
//create mux Component done!
addChn_l(pNode);
pthread_mutex_unlock(&gMuxChnMgr->mMuxChnListLock);
return SUCCESS;
}
ERRORTYPE AW_MPI_MUX_DestroyChn(MUX_CHN muxChn)
{
ERRORTYPE ret;
if(!(muxChn >= 0 && muxChn < MUX_MAX_CHN_NUM))
{
aloge("fatal error! invalid muxChn[%d]!", muxChn);
return ERR_MUX_INVALID_CHNID;
}
MUX_CHN_S *pChn;
if(SUCCESS != MUX_searchExistChn(muxChn, &pChn))
{
return ERR_MUX_UNEXIST;
}
ERRORTYPE eRet;
if(pChn->mComp)
{
COMP_STATETYPE nCompState;
if(SUCCESS == COMP_GetState(pChn->mComp, &nCompState))
{
if(nCompState == COMP_StateIdle)
{
//COMP_SetConfig(pChn->mComp, COMP_IndexVendorMuxShutDownType, (void *)&bShutDownNowFlag);
eRet = COMP_SendCommand(pChn->mComp, COMP_CommandStateSet, COMP_StateLoaded, NULL);
cdx_sem_down(&pChn->mSemCompCmd);
if(eRet != SUCCESS)
{
aloge("fatal error! why transmit state to loaded fail?");
}
}
else if(nCompState == COMP_StateLoaded)
{
eRet = SUCCESS;
}
else if(nCompState == COMP_StateInvalid)
{
alogw("Low probability! Component StateInvalid?");
eRet = SUCCESS;
}
else
{
aloge("fatal error! invalid VeChn[%d] state[0x%x]!", muxChn, nCompState);
eRet = ERR_MUX_INCORRECT_STATE_OPERATION;
}
if(eRet == SUCCESS)
{
removeChn(pChn);
COMP_FreeHandle(pChn->mComp);
pChn->mComp = NULL;
MUX_CHN_S_Destruct(pChn);
}
ret = eRet;
}
else
{
aloge("fatal error! GetState fail!");
ret = ERR_MUX_BUSY;
}
}
else
{
aloge("fatal error! no mux component!");
list_del(&pChn->mList);
MUX_CHN_S_Destruct(pChn);
ret = SUCCESS;
}
return ret;
}
ERRORTYPE AW_MPI_MUX_StartChn(MUX_CHN muxChn)
{
if(!(muxChn>=0 && muxChn <MUX_MAX_CHN_NUM))
{
aloge("fatal error! invalid muxChn[%d]!", muxChn);
return ERR_MUX_INVALID_CHNID;
}
MUX_CHN_S *pChn;
if(SUCCESS != MUX_searchExistChn(muxChn, &pChn))
{
return ERR_MUX_UNEXIST;
}
int ret;
int eRet;
COMP_STATETYPE nCompState;
eRet = COMP_GetState(pChn->mComp, &nCompState);
if(SUCCESS == eRet && COMP_StateIdle == nCompState)
{
eRet = COMP_SendCommand(pChn->mComp, COMP_CommandStateSet, COMP_StateExecuting, NULL);
cdx_sem_down(&pChn->mSemCompCmd);
ret = SUCCESS;
}
else
{
alogd("mux comp state[0x%x], do nothing!", nCompState);
ret = SUCCESS;
}
return ret;
}
/**
if bShutDownNowFlag is true, will discard cache data.
*/
ERRORTYPE AW_MPI_MUX_StopChn(MUX_CHN muxChn, BOOL bShutDownNowFlag)
{
if(!(muxChn>=0 && muxChn<MUX_MAX_CHN_NUM))
{
aloge("fatal error! invalid mux chn[%d]!", muxChn);
return ERR_MUX_INVALID_CHNID;
}
MUX_CHN_S *pChn;
if(SUCCESS != MUX_searchExistChn(muxChn, &pChn))
{
return ERR_MUX_UNEXIST;
}
ERRORTYPE eError;
ERRORTYPE eRet;
COMP_STATETYPE nCompState;
eRet = COMP_GetState(pChn->mComp, &nCompState);
if(COMP_StateExecuting == nCompState || COMP_StatePause == nCompState)
{
COMP_SetConfig(pChn->mComp, COMP_IndexVendorMuxShutDownType, (void *)&bShutDownNowFlag);
eRet = COMP_SendCommand(pChn->mComp, COMP_CommandStateSet, COMP_StateIdle, NULL);
cdx_sem_down(&pChn->mSemCompCmd);
eError = eRet;
}
else if(COMP_StateIdle == nCompState)
{
alogv("mux comp state[0x%x], do nothing!", nCompState);
eError = SUCCESS;
}
else
{
aloge("fatal error! check mux state[0x%x]!", nCompState);
eError = SUCCESS;
}
return eError;
}
/**
set output fd.
*/
ERRORTYPE AW_MPI_MUX_SetFd(MUX_CHN muxChn, int nFd, int nFallocateLen)
{
if(!(muxChn>=0 && muxChn < MUX_MAX_CHN_NUM))
{
aloge("fatal error! invalid muxChn[%d]!", muxChn);
return ERR_MUX_INVALID_CHNID;
}
MUX_CHN_S *pChn;
if(SUCCESS != MUX_searchExistChn(muxChn, &pChn))
{
return ERR_MUX_UNEXIST;
}
ERRORTYPE ret;
COMP_STATETYPE eState;
ret = COMP_GetState(pChn->mComp, &eState);
if(eState != COMP_StateIdle)
{
aloge("muxChn[%d] wrong state[0x%x], return!", muxChn, eState);
return ERR_MUX_NOT_PERM;
}
CdxFdT stCdxFd;
stCdxFd.mFd = nFd;
stCdxFd.mnFallocateLen = nFallocateLen;
ret = COMP_SetConfig(pChn->mComp, COMP_IndexVendorMuxFD, (void*)&stCdxFd);
return ret;
}
ERRORTYPE AW_MPI_MUX_GetChnAttr(MUX_CHN muxChn, MUX_CHN_ATTR_S *pChnAttr)
{
if(!(muxChn>=0 && muxChn < MUX_MAX_CHN_NUM))
{
aloge("fatal error! invalid muxChn[%d]!", muxChn);
return ERR_MUX_INVALID_CHNID;
}
MUX_CHN_S *pChn;
if(SUCCESS != MUX_searchExistChn(muxChn, &pChn))
{
return ERR_MUX_UNEXIST;
}
ERRORTYPE ret;
COMP_STATETYPE nState;
ret = COMP_GetState(pChn->mComp, &nState);
if(COMP_StateExecuting != nState && COMP_StateIdle != nState)
{
aloge("wrong state[0x%x], return!", nState);
return ERR_MUX_NOT_PERM;
}
ret = COMP_GetConfig(pChn->mComp, COMP_IndexVendorMuxChnAttr, (void*)pChnAttr);
return ret;
}
ERRORTYPE AW_MPI_MUX_SetChnAttr(MUX_CHN muxChn, MUX_CHN_ATTR_S *pChnAttr)
{
if(!(muxChn>=0 && muxChn < MUX_MAX_CHN_NUM))
{
aloge("fatal error! invalid muxChn[%d]!", muxChn);
return ERR_MUX_INVALID_CHNID;
}
MUX_CHN_S *pChn;
if(SUCCESS != MUX_searchExistChn(muxChn, &pChn))
{
return ERR_MUX_UNEXIST;
}
ERRORTYPE ret;
COMP_STATETYPE nState;
ret = COMP_GetState(pChn->mComp, &nState);
if(COMP_StateExecuting != nState && COMP_StateIdle != nState)
{
aloge("wrong state[0x%x], return!", nState);
return ERR_MUX_NOT_PERM;
}
ret = COMP_SetConfig(pChn->mComp, COMP_IndexVendorMuxChnAttr, (void*)pChnAttr);
return ret;
}
/**
set spspps to mux.
It is better to call this function after calling AW_MPI_MUX_SetVeChnBindStreamId(), because we need to know VeChn
match to which streamId.
*/
ERRORTYPE AW_MPI_MUX_SetH264SpsPpsInfo(MUX_CHN muxChn, VENC_CHN VeChn, VencHeaderData *pH264SpsPpsInfo)
{
if(!(muxChn>=0 && muxChn < MUX_MAX_CHN_NUM))
{
aloge("fatal error! invalid muxChn[%d]!", muxChn);
return ERR_MUX_INVALID_CHNID;
}
MUX_CHN_S *pChn;
if(SUCCESS != MUX_searchExistChn(muxChn, &pChn))
{
return ERR_MUX_UNEXIST;
}
ERRORTYPE ret;
COMP_STATETYPE nState;
ret = COMP_GetState(pChn->mComp, &nState);
if(COMP_StateExecuting != nState && COMP_StateIdle != nState)
{
aloge("wrong state[0x%x], return!", nState);
return ERR_MUX_NOT_PERM;
}
VencHeaderDataParam stVencHeaderDataParam;
stVencHeaderDataParam.mVeChn = VeChn;
stVencHeaderDataParam.mH264SpsPpsInfo.nLength = pH264SpsPpsInfo->nLength;
stVencHeaderDataParam.mH264SpsPpsInfo.pBuffer = pH264SpsPpsInfo->pBuffer;
ret = COMP_SetConfig(pChn->mComp, COMP_IndexVendorExtraData, (void*)&stVencHeaderDataParam);
return ret;
}
ERRORTYPE AW_MPI_MUX_SetH265SpsPpsInfo(MUX_CHN muxChn, VENC_CHN VeChn, VencHeaderData *pH265SpsPpsInfo)
{
return AW_MPI_MUX_SetH264SpsPpsInfo(muxChn, VeChn, pH265SpsPpsInfo);
}
ERRORTYPE AW_MPI_MUX_SetThmPic(MUX_CHN muxChn, char *p_thm_pic, int thm_pic_size)
{
if(!(muxChn >=0 && muxChn < MUX_MAX_CHN_NUM))
{
aloge("fatal error! invalid muxChn[%d]!", muxChn);
return ERR_MUX_INVALID_CHNID;
}
MUX_CHN_S *pChn;
if(SUCCESS != MUX_searchExistChn(muxChn, &pChn))
{
return ERR_MUX_UNEXIST;
}
ERRORTYPE ret;
COMP_STATETYPE nState;
ret = COMP_GetState(pChn->mComp, &nState);
if(COMP_StateExecuting != nState)
{
aloge("wrong state[0x%x], return!", nState);
return ERR_MUX_NOT_PERM;
}
THM_PIC thm_pic;
thm_pic.p_thm_pic_addr = p_thm_pic;
thm_pic.thm_pic_size = thm_pic_size;
ret = COMP_SetConfig(pChn->mComp, COMP_IndexVendorMuxSetThmPic, (void*)&thm_pic);
return ret;
}
/**
set next fd to muxChn.
muxChn will store this fd, when file duration come, close current file, use this fd to create next file to store
stream contiguously.
*/
ERRORTYPE AW_MPI_MUX_SwitchFd(MUX_CHN muxChn, int fd, int nFallocateLen)
{
if(!(muxChn>=0 && muxChn < MUX_MAX_CHN_NUM))
{
aloge("fatal error! invalid muxGroup[%d]!", muxChn);
return ERR_MUX_INVALID_CHNID;
}
MUX_CHN_S *pChn;
if(SUCCESS != MUX_searchExistChn(muxChn, &pChn))
{
return ERR_MUX_UNEXIST;
}
ERRORTYPE ret;
COMP_STATETYPE nState;
ret = COMP_GetState(pChn->mComp, &nState);
if(COMP_StateExecuting != nState)
{
aloge("wrong state[0x%x], return!", nState);
return ERR_MUX_NOT_PERM;
}
CdxFdT stCdxFd;
stCdxFd.mFd = fd;
stCdxFd.mnFallocateLen = nFallocateLen;
//stCdxFd.mIsImpact = 0;
//stCdxFd.mMuxerId = stMppChnAttr.mMuxerId;
ret = COMP_SetConfig(pChn->mComp, COMP_IndexVendorMuxSwitchFd, (void*)&stCdxFd);
return ret;
}
/**
switch file right now.
muxChn will store this fd, then switch file after this call, close current file, use fd to create next file. When fd
is -1, not create next file, and ignore stream until valid fd coming.
user will receive MPP_EVENT_RECORD_DONE message when switching file is done.
@param fd
for next file. if -1, not create next file.
*/
ERRORTYPE AW_MPI_MUX_SwitchFileNormal(MUX_CHN muxChn, int fd, int nFallocateLen)
{
if(!(muxChn>=0 && muxChn < MUX_MAX_CHN_NUM))
{
aloge("fatal error! invalid muxGroup[%d]!", muxChn);
return ERR_MUX_INVALID_CHNID;
}
MUX_CHN_S *pChn;
if(SUCCESS != MUX_searchExistChn(muxChn, &pChn))
{
return ERR_MUX_UNEXIST;
}
ERRORTYPE ret;
COMP_STATETYPE nState;
ret = COMP_GetState(pChn->mComp, &nState);
if(COMP_StateExecuting != nState)
{
aloge("wrong state[0x%x], return!", nState);
return ERR_MUX_NOT_PERM;
}
SwitchFileNormalInfo stInfo;
memset(&stInfo, 0, sizeof(SwitchFileNormalInfo));
//stInfo.mMuxerId = stMppChnAttr.mMuxerId;
stInfo.mFd = fd;
stInfo.mnFallocateLen = nFallocateLen;
ret = COMP_SetConfig(pChn->mComp, COMP_IndexSwitchFileNormal, (void*)&stInfo);
return ret;
}
ERRORTYPE AW_MPI_MUX_RegisterCallback(MUX_CHN muxChn, MPPCallbackInfo *pCallback)
{
if(!(muxChn>=0 && muxChn <MUX_MAX_CHN_NUM))
{
aloge("fatal error! invalid muxChn[%d]!", muxChn);
return ERR_MUX_INVALID_CHNID;
}
MUX_CHN_S *pChn;
if(SUCCESS != MUX_searchExistChn(muxChn, &pChn))
{
return ERR_MUX_UNEXIST;
}
pChn->mCallbackInfo.callback = pCallback->callback;
pChn->mCallbackInfo.cookie = pCallback->cookie;
return SUCCESS;
}
/**
List valid streamIds in this mux channel.
MUX_CHN_ATTR_S->mVideoAttr[MAX_VIDEO_TRACK_COUNT] must list all streams whatever is used in mux channel.
But not all streams will be sent to this mux channel.
So use this api to tell mux channel which streams will be sent to it.
@param nStrmIdsCnt
must <= MAX_TRACK_COUNT
*/
ERRORTYPE AW_MPI_MUX_SetStrmIds(MUX_CHN muxChn, MuxStreamIdsInfo *pStrmIdsInfo)
{
if(!(muxChn>=0 && muxChn <MUX_MAX_CHN_NUM))
{
aloge("fatal error! invalid muxChn[%d]!", muxChn);
return ERR_MUX_INVALID_CHNID;
}
MUX_CHN_S *pChn;
if(SUCCESS != MUX_searchExistChn(muxChn, &pChn))
{
return ERR_MUX_UNEXIST;
}
ERRORTYPE ret;
COMP_STATETYPE eState;
ret = COMP_GetState(pChn->mComp, &eState);
if(eState != COMP_StateIdle)
{
aloge("muxChn[%d] wrong state[0x%x], return!", muxChn, eState);
return ERR_MUX_NOT_PERM;
}
return COMP_SetConfig(pChn->mComp, COMP_IndexVendorMuxStrmIds, (void *)pStrmIdsInfo);
}
ERRORTYPE AW_MPI_MUX_SetSwitchFileDurationPolicy(MUX_CHN muxChn, RecordFileDurationPolicy ePolicy)
{
if(!(muxChn>=0 && muxChn <MUX_MAX_CHN_NUM))
{
aloge("fatal error! invalid muxChn[%d]!", muxChn);
return ERR_MUX_INVALID_CHNID;
}
MUX_CHN_S *pChn;
if(SUCCESS != MUX_searchExistChn(muxChn, &pChn))
{
return ERR_MUX_UNEXIST;
}
ERRORTYPE ret;
COMP_STATETYPE nState;
ret = COMP_GetState(pChn->mComp, &nState);
if(COMP_StateIdle != nState)
{
aloge("wrong state[0x%x], return!", nState);
return ERR_MUX_NOT_PERM;
}
return COMP_SetConfig(pChn->mComp, COMP_IndexVendorMuxSwitchPolicy, (void *)&ePolicy);
}
ERRORTYPE AW_MPI_MUX_GetSwitchFileDurationPolicy(MUX_CHN muxChn, RecordFileDurationPolicy *pPolicy)
{
if(!(muxChn>=0 && muxChn <MUX_MAX_CHN_NUM))
{
aloge("fatal error! invalid muxGroup[%d]!", muxChn);
return ERR_MUX_INVALID_CHNID;
}
MUX_CHN_S *pChn;
if(SUCCESS != MUX_searchExistChn(muxChn, &pChn))
{
return ERR_MUX_UNEXIST;
}
ERRORTYPE ret;
COMP_STATETYPE nState;
ret = COMP_GetState(pChn->mComp, &nState);
if(COMP_StateIdle != nState || COMP_StateExecuting != nState || COMP_StatePause != nState)
{
aloge("wrong state[0x%x], return!", nState);
return ERR_MUX_NOT_PERM;
}
return COMP_GetConfig(pChn->mComp, COMP_IndexVendorMuxSwitchPolicy, (void *)pPolicy);
}
ERRORTYPE AW_MPI_MUX_SetSdCardState(MUX_CHN muxChn, BOOL bExist)
{
if(!(muxChn>=0 && muxChn<MUX_MAX_CHN_NUM))
{
aloge("fatal error! invalid muxGroup[%d]!", muxChn);
return ERR_MUX_INVALID_CHNID;
}
MUX_CHN_S *pGrp;
if(SUCCESS != MUX_searchExistChn(muxChn, &pGrp))
{
return ERR_MUX_UNEXIST;
}
int bState = (int)bExist;
return COMP_SetConfig(pGrp->mComp, COMP_IndexVendorSdcardState, (void*)&bState);
}
/**
for non-tunnel mode, directly bind veChn and streamId. streamId = portIndex in mpi_mux.
must be set before AW_MPI_MUX_SetH264SpsPpsInfo(), because AW_MPI_MUX_SetH264SpsPpsInfo() need to know which stream
spsppsinfo is matched to.
*/
ERRORTYPE AW_MPI_MUX_SetVeChnBindStreamId(MUX_CHN muxChn, VENC_CHN VeChn, int nStreamId)
{
if(!(muxChn>=0 && muxChn<MUX_MAX_CHN_NUM))
{
aloge("fatal error! invalid muxGroup[%d]!", muxChn);
return ERR_MUX_INVALID_CHNID;
}
MUX_CHN_S *pChn;
if(SUCCESS != MUX_searchExistChn(muxChn, &pChn))
{
return ERR_MUX_UNEXIST;
}
ERRORTYPE ret;
COMP_STATETYPE nState;
ret = COMP_GetState(pChn->mComp, &nState);
if(nState != COMP_StateIdle)
{
aloge("fatal error! wrong state[0x%x], return!", nState);
return ERR_MUX_NOT_PERM;
}
VeChnBindStreamIdNode stVeChnBindStreamId;
memset(&stVeChnBindStreamId, 0, sizeof(stVeChnBindStreamId));
stVeChnBindStreamId.mStreamId = nStreamId;
stVeChnBindStreamId.mVeChn.mModId = MOD_ID_VENC;
stVeChnBindStreamId.mVeChn.mDevId = 0;
stVeChnBindStreamId.mVeChn.mChnId = VeChn;
return COMP_SetConfig(pChn->mComp, COMP_IndexVendorMuxVeChnBindStreamId, &stVeChnBindStreamId);
}
static ERRORTYPE aw_mux_SendStream(MUX_CHN_S *pChn, MUX_CHN_ATTR_S *pChnAttr, EncodedStream *pEncodedStream, int nStreamId, BOOL bSyncFlag)
{
ERRORTYPE ret = SUCCESS;
COMP_STATETYPE eState;
ret = COMP_GetState(pChn->mComp, &eState);
if(eState != COMP_StateExecuting && eState != COMP_StateIdle && eState != COMP_StatePause)
{
aloge("fatal error! muxChn[%d-%d] wrong state[0x%x], return!", pChn->mMuxChn, pChnAttr->mMuxerId, eState);
return ERR_MUX_INCORRECT_STATE_OPERATION;
}
if(bSyncFlag)
{
pthread_mutex_lock(&pChn->mSendStreamSyncLock);
// ignore usr pEncodedStream->nID and don't change it, just use it to identify
// sync or async in RecRenderEmptyBufferDone().
EncodedStream tmpEncodedStream;
memcpy(&tmpEncodedStream, pEncodedStream, sizeof(EncodedStream));
tmpEncodedStream.nID = ENCODED_FRAME_ID_INVALID;
COMP_BUFFERHEADERTYPE bufferHeader;
bufferHeader.pAppPrivate = (void*)&tmpEncodedStream;
bufferHeader.nInputPortIndex = nStreamId;
ret = COMP_EmptyThisBuffer(pChn->mComp, &bufferHeader);
// blocked here, until the encodedStream be returned.
cdx_sem_down(&pChn->mSemWaitEncodedStreamRelease);
pthread_mutex_unlock(&pChn->mSendStreamSyncLock);
}
else
{
if (ENCODED_FRAME_ID_INVALID == pEncodedStream->nID)
{
aloge("fatal error! muxChn[%d-%d] invalid audio frame id[0x%x] in async mode!", pChn->mMuxChn, pChnAttr->mMuxerId, pEncodedStream->nID);
return ERR_AO_ILLEGAL_PARAM;
}
COMP_BUFFERHEADERTYPE bufferHeader;
bufferHeader.pAppPrivate = (void*)pEncodedStream;
bufferHeader.nInputPortIndex = nStreamId;
ret = COMP_EmptyThisBuffer(pChn->mComp, &bufferHeader);
}
return ret;
}
/*
* use memory from VENC_STREAM_S. no need malloc memory self.
*/
static ERRORTYPE InitEncodedStreamByVENC_STREAM_S(EncodedStream *pDst, VENC_STREAM_S *pSrc, PAYLOAD_TYPE_E eType)
{
if (pDst == NULL || pSrc == NULL)
{
aloge("fatal error! Empty pointer.");
return FAILURE;
}
memset(pDst, 0, sizeof(EncodedStream));
pDst->media_type = CDX_PacketVideo;
pDst->nID = pSrc->mSeq;
pDst->nFilledLen = pSrc->mpPack[0].mLen0 + pSrc->mpPack[0].mLen1 + pSrc->mpPack[0].mLen2;
pDst->nTobeFillLen = 0;
pDst->nTimeStamp = pSrc->mpPack[0].mPTS;
pDst->nFlags = 0;
if(PT_H264 == eType)
{
if(H264E_NALU_ISLICE == pSrc->mpPack[0].mDataType.enH264EType)
{
pDst->nFlags |= CEDARV_FLAG_KEYFRAME;
}
}
else if(PT_H265 == eType)
{
if(H265E_NALU_ISLICE == pSrc->mpPack[0].mDataType.enH265EType)
{
pDst->nFlags |= CEDARV_FLAG_KEYFRAME;
}
}
else if(PT_JPEG == eType || PT_MJPEG == eType)
{
pDst->nFlags |= CEDARV_FLAG_KEYFRAME;
}
pDst->pBuffer = pSrc->mpPack[0].mpAddr0;
pDst->nBufferLen = pSrc->mpPack[0].mLen0;
pDst->pBufferExtra = pSrc->mpPack[0].mpAddr1;
pDst->nBufferExtraLen = pSrc->mpPack[0].mLen1;
pDst->pBufferExtra2 = pSrc->mpPack[0].mpAddr2;
pDst->nBufferExtraLen2 = pSrc->mpPack[0].mLen2;
pDst->infoVersion = -1;
pDst->pChangedStreamsInfo = NULL;
pDst->duration = -1;
return SUCCESS;
}
static ERRORTYPE aw_mux_SendVideoStream(MUX_CHN muxChn, VENC_STREAM_S *pStream, int nStreamId, BOOL bSyncFlag)
{
ERRORTYPE ret;
if(!(muxChn>=0 && muxChn<MUX_MAX_CHN_NUM))
{
aloge("fatal error! invalid muxChn[%d]!", muxChn);
return ERR_MUX_INVALID_CHNID;
}
MUX_CHN_S *pChn;
if(SUCCESS != MUX_searchExistChn(muxChn, &pChn))
{
return ERR_MUX_UNEXIST;
}
MUX_CHN_ATTR_S stChnAttr;
ret = COMP_GetConfig(pChn->mComp, COMP_IndexVendorMuxChnAttr, (void*)&stChnAttr);
PAYLOAD_TYPE_E ePayloadType;
if(nStreamId < stChnAttr.mVideoAttrValidNum)
{
ePayloadType = stChnAttr.mVideoAttr[nStreamId].mVideoEncodeType;
}
else
{
aloge("fatal error! muxChn[%d-%d] video streamId[%d>=%d] wrong", muxChn, stChnAttr.mMuxerId, nStreamId, stChnAttr.mVideoAttrValidNum);
ePayloadType = PT_MAX;
}
EncodedStream stEncodedStream;
ret = InitEncodedStreamByVENC_STREAM_S(&stEncodedStream, pStream, ePayloadType);
ret = aw_mux_SendStream(pChn, &stChnAttr, &stEncodedStream, nStreamId, bSyncFlag);
return ret;
}
ERRORTYPE AW_MPI_MUX_SendVideoStream(MUX_CHN muxChn, VENC_STREAM_S *pStream, int nStreamId)
{
return aw_mux_SendVideoStream(muxChn, pStream, nStreamId, FALSE);
}
/**
use sync mode, when function return, user can release stream.
component use internal memory to store input stream, so it can return immediately.
*/
ERRORTYPE AW_MPI_MUX_SendVideoStreamSync(MUX_CHN muxChn, VENC_STREAM_S *pStream, int nStreamId)
{
return aw_mux_SendVideoStream(muxChn, pStream, nStreamId, TRUE);
}
static ERRORTYPE InitEncodedStreamByAUDIO_STREAM_S(EncodedStream *pDst, AUDIO_STREAM_S *pSrc)
{
if (pDst == NULL || pSrc == NULL)
{
aloge("fatal error! Empty pointer.");
return FAILURE;
}
memset(pDst, 0, sizeof(EncodedStream));
pDst->media_type = CDX_PacketAudio;
pDst->pBuffer = pSrc->pStream;
pDst->nBufferLen = pSrc->mLen;
pDst->pBufferExtra = pSrc->pStreamExtra;
pDst->nBufferExtraLen = pSrc->mExtraLen;
pDst->nFilledLen = pSrc->mLen + pSrc->mExtraLen;
pDst->nTimeStamp = pSrc->mTimeStamp;
pDst->nID = pSrc->mId;
return SUCCESS;
}
static ERRORTYPE aw_mux_SendAudioStream(MUX_CHN muxChn, AUDIO_STREAM_S *pStream, int nStreamId, BOOL bSyncFlag)
{
ERRORTYPE ret;
if(!(muxChn>=0 && muxChn<MUX_MAX_CHN_NUM))
{
aloge("fatal error! invalid muxChn[%d]!", muxChn);
return ERR_MUX_INVALID_CHNID;
}
MUX_CHN_S *pChn;
if(SUCCESS != MUX_searchExistChn(muxChn, &pChn))
{
return ERR_MUX_UNEXIST;
}
MUX_CHN_ATTR_S stChnAttr;
ret = COMP_GetConfig(pChn->mComp, COMP_IndexVendorMuxChnAttr, (void*)&stChnAttr);
if(nStreamId != stChnAttr.mVideoAttrValidNum)
{
aloge("fatal error! muxChn[%d-%d] auido streamId[%d!=%d] wrong", muxChn, stChnAttr.mMuxerId, nStreamId, stChnAttr.mVideoAttrValidNum);
}
EncodedStream stEncodedStream;
ret = InitEncodedStreamByAUDIO_STREAM_S(&stEncodedStream, pStream);
ret = aw_mux_SendStream(pChn, &stChnAttr, &stEncodedStream, nStreamId, bSyncFlag);
return ret;
}
ERRORTYPE AW_MPI_MUX_SendAudioStream(MUX_CHN muxChn, AUDIO_STREAM_S *pStream, int nStreamId)
{
return aw_mux_SendAudioStream(muxChn, pStream, nStreamId, FALSE);
}
ERRORTYPE AW_MPI_MUX_SendAudioStreamSync(MUX_CHN muxChn, AUDIO_STREAM_S *pStream, int nStreamId)
{
return aw_mux_SendAudioStream(muxChn, pStream, nStreamId, TRUE);
}
static ERRORTYPE InitEncodedStreamByTEXT_STREAM_S(EncodedStream *pDst, TEXT_STREAM_S *pSrc)
{
if (pDst == NULL || pSrc == NULL)
{
aloge("fatal error! Empty pointer.");
return FAILURE;
}
memset(pDst, 0, sizeof(EncodedStream));
pDst->media_type = CDX_PacketSubtitle;
pDst->pBuffer = pSrc->pStream;
pDst->nBufferLen = pSrc->mLen;
pDst->pBufferExtra = pSrc->pStreamExtra;
pDst->nBufferExtraLen = pSrc->mExtraLen;
pDst->nFilledLen = pSrc->mLen + pSrc->mExtraLen;
pDst->nTimeStamp = pSrc->mTimeStamp;
pDst->nID = pSrc->mId;
return SUCCESS;
}
static ERRORTYPE aw_mux_SendTextStream(MUX_CHN muxChn, TEXT_STREAM_S *pStream, int nStreamId, BOOL bSyncFlag)
{
ERRORTYPE ret;
if(!(muxChn>=0 && muxChn<MUX_MAX_CHN_NUM))
{
aloge("fatal error! invalid muxChn[%d]!", muxChn);
return ERR_MUX_INVALID_CHNID;
}
MUX_CHN_S *pChn;
if(SUCCESS != MUX_searchExistChn(muxChn, &pChn))
{
return ERR_MUX_UNEXIST;
}
MUX_CHN_ATTR_S stChnAttr;
ret = COMP_GetConfig(pChn->mComp, COMP_IndexVendorMuxChnAttr, (void*)&stChnAttr);
if(nStreamId < stChnAttr.mVideoAttrValidNum)
{
aloge("fatal error! muxChn[%d-%d] text streamId[%d<%d] wrong", muxChn, stChnAttr.mMuxerId, nStreamId, stChnAttr.mVideoAttrValidNum);
}
EncodedStream stEncodedStream;
ret = InitEncodedStreamByTEXT_STREAM_S(&stEncodedStream, pStream);
ret = aw_mux_SendStream(pChn, &stChnAttr, &stEncodedStream, nStreamId, bSyncFlag);
return ret;
}
ERRORTYPE AW_MPI_MUX_SendTextStream(MUX_CHN muxChn, TEXT_STREAM_S *pStream, int nStreamId)
{
return aw_mux_SendTextStream(muxChn, pStream, nStreamId, FALSE);
}
ERRORTYPE AW_MPI_MUX_SendTextStreamSync(MUX_CHN muxChn, TEXT_STREAM_S *pStream, int nStreamId)
{
return aw_mux_SendTextStream(muxChn, pStream, nStreamId, TRUE);
}