描述
- 硬件:hi3559
- 系统:嵌入式linux
思路
- 海思音视频通过回调方式给出Frame数据,在回调函数中将Frame信息保存到循环缓冲区中。
关于缓冲区的实现参考循环缓冲区 - 在线程中读缓冲区中的frame信息,对比时间戳并写音视频数据。
- 使用HI_MUXER写MP4文件,有许多问题没解决,后续准备改成ffmpeg实现。
代码
- ProductRecord.h
#ifndef __PRODUCT_RECORD_H__
#define __PRODUCT_RECORD_H__
//HI_MP4_FRAME_DATA_S
#include "hi_mp4_muxer.h"
/***************************** Macro Definition ******************************/
//#define
#define RECORD_STOP 0
#define RECORD_START 1
/****************************************function***********************************************/
/**function: GetUdiskRecordStatus
* description: get udisk record status
* return: [0](RECORD_STOP)-stop record, [1](RECORD_START)-start record;
*/
int GetUdiskRecordStatus();
/**function: SetUdiskRecordEnd
* description: set udisk record end num
* param: [record]-record num
* return: [0];
*/
int SetUdiskRecordEnd(int record);
/**function: CreateUdiskRecordThr
* description: create udisk record thread
*/
int CreateUdiskRecordThr(void);
/**function: DestroyUdiskRecordThr
* description: destroy udisk record thread
*/
int DestroyUdiskRecordThr(void);
/**function: UdiskWriteAudioFrame
* description: audio writeFrame
*/
int UdiskWriteAudioFrame(HI_MP4_FRAME_DATA_S* stFrameData);
/**function: UdiskWriteVideoFrame()
* description: video writeFrame
*/
int UdiskWriteVideoFrame(HI_MP4_FRAME_DATA_S* stFrameData);
#endif /* End of #ifndef __PRODUCT_RECORD_H__*/
- ProductRecord.c
#include "ProductCircularBuffer.h"
#include "ProductUdiskFileMng.h"
/***************************** Macro Definition ******************************/
//#define
#define VIDEO_CIC_BUF_LEN 64 //video frame total 80
#define AUDIO_CIC_BUF_LEN 256 // audio frame total 300
/*************************** Structure Definition ****************************/
//typedef struct
typedef enum {
REC_IDLE,
REC_STOP,
REC_RUN,
REC_OVERTIME,
REC_OVERSPACE,
REC_DISKFULL,
REC_ERR,
}record_state_en;
/***************************** Global Definition *****************************/
/***************************** Static Definition *****************************/
//static
static HI_HANDLE udiskRecordStatus = RECORD_STOP;
static pthread_t pthreadUdiskRecord;
static HI_HANDLE hMP4Muxer = 0;
static HI_HANDLE hVideoTrack = 1;
static HI_HANDLE hAudioTrack = 2;
static HI_MP4_TRACK_INFO_S sTrackInfoVideo;
static HI_MP4_TRACK_INFO_S sTrackInfoAudio;
static HI_MP4_TRACK_INFO_S sTrackInfoData;
static HI_MP4_MUXER_CONFIG_S stMuxerCfg;
static record_state_en cmdReq = REC_IDLE;
static HI_U64 videoGapPts = 0;
static int recordStatus = RECORD_STOP;
static HI_U64 thdu64AudioPTS = 0;
static HI_U64 thdu64VideoPTS = 0;
static CircularBuffer audioCicbuf;
static CircularBuffer videoCicbuf;
/****************************************function***********************************************/
/**function: GetUdiskRecordStatus
* description: get udisk record status
* return: [0](RECORD_STOP)-stop record, [1](RECORD_START)-start record;
*/
int GetUdiskRecordStatus()
{
return udiskRecordStatus;
}
/**function: StartUdiskAVRecord()
* description: start av muxer
*/
static int StartUdiskAVRecord(HI_CHAR* filename)
{
MLOGD("udisk mp4 filename:"GREEN"%s"NONE" mux rec start\n", filename);
HI_S32 s32Ret = HI_SUCCESS;
//check udisk
if(GetUdiskMountState() != UDISK_MOUNT)//udisk out
{
MLOGD("udisk not mount\n");
return 0;
}
//video
memset(&sTrackInfoVideo, 0x00, sizeof(HI_MP4_TRACK_INFO_S));
sTrackInfoVideo.enTrackType = HI_MP4_STREAM_VIDEO;
sTrackInfoVideo.fSpeed = 1.0f;
//h265
int payload_type = GetCfgPayloadType();
MLOGD("loadType:%d\n", payload_type);
if(payload_type == 1)
{
sTrackInfoVideo.stVideoInfo.enCodecID = HI_MP4_CODEC_ID_H265;
}
else
{
sTrackInfoVideo.stVideoInfo.enCodecID = HI_MP4_CODEC_ID_H264;
}
int enVideoMode = 7;
enVideoMode = GetCfgVideoMode();
switch(enVideoMode)
{
case 1://720P60
sTrackInfoVideo.stVideoInfo.u32BitRate = 12800;//10240;
sTrackInfoVideo.stVideoInfo.u32FrameRate = 60;
sTrackInfoVideo.stVideoInfo.u32Width = 1280;
sTrackInfoVideo.stVideoInfo.u32Height = 720;
videoGapPts = 1000/60 + 10;
break;
case 2://1080P60
//case 5://2560x1440p60
sTrackInfoVideo.stVideoInfo.u32BitRate = 15360;
sTrackInfoVideo.stVideoInfo.u32FrameRate = 60;
sTrackInfoVideo.stVideoInfo.u32Width = 1920;
sTrackInfoVideo.stVideoInfo.u32Height = 1080;
videoGapPts = 1000/60 + 10;
break;
case 5://2560x1440p30
sTrackInfoVideo.stVideoInfo.u32BitRate = 20480;
sTrackInfoVideo.stVideoInfo.u32FrameRate = 30;
sTrackInfoVideo.stVideoInfo.u32Width = 2560;
sTrackInfoVideo.stVideoInfo.u32Height = 1440;
videoGapPts = 1000/30 + 15;
break;
case 7://4K2K30
default:
sTrackInfoVideo.stVideoInfo.u32BitRate = 25600;//51200;
sTrackInfoVideo.stVideoInfo.u32FrameRate = 30;
sTrackInfoVideo.stVideoInfo.u32Width = 3840;
sTrackInfoVideo.stVideoInfo.u32Height = 2160;
videoGapPts = 1000/30 + 15;
}
sTrackInfoVideo.u32TimeScale = 120000;
snprintf(sTrackInfoVideo.aszHdlrName, HI_MP4_MAX_HDLR_NAME, "%s", "Hisilicon VIDEO");
//audio
memset(&sTrackInfoAudio, 0x00, sizeof(HI_MP4_TRACK_INFO_S));
sTrackInfoAudio.fSpeed = 1.0f;
sTrackInfoAudio.enTrackType = HI_MP4_STREAM_AUDIO;
sTrackInfoAudio.stAudioInfo.enCodecID = HI_MP4_CODEC_ID_AACLC;
sTrackInfoAudio.stAudioInfo.u16SampleSize = 16;//16;32;
sTrackInfoAudio.stAudioInfo.u32Channels = 2;//1;
sTrackInfoAudio.stAudioInfo.u32SamplePerFrame = 1024;//512;err//1024;2048;
sTrackInfoAudio.stAudioInfo.u32SampleRate = 48000;
sTrackInfoAudio.u32TimeScale = 48000;
snprintf(sTrackInfoAudio.aszHdlrName, HI_MP4_MAX_HDLR_NAME, "%s", "Hisilicon AUDIO");
memset(&stMuxerCfg, 0x00, sizeof(HI_MP4_MUXER_CONFIG_S));
stMuxerCfg.hRepairHandle = -1;
stMuxerCfg.u32PreAllocUnit = 0;
stMuxerCfg.u32VBufSize = 4*1024 * 1024;
stMuxerCfg.bConstantFps = HI_TRUE;//HI_FALSE;//30fps
stMuxerCfg.bCo64Flag = HI_FALSE;
snprintf(stMuxerCfg.aszFileName, HI_MP4_MAX_FILE_NAME, "%s", filename);
s32Ret = HI_MP4_MUXER_Create(&hMP4Muxer, &stMuxerCfg);
if (HI_SUCCESS != s32Ret)
{
MLOGE("HI_MP4_MUXER_Create ret 0x%x\n", s32Ret);
}
PDT_CHECK_EXPR(HI_SUCCESS == s32Ret);
s32Ret = HI_MP4_MUXER_CreateTrack(hMP4Muxer, &hVideoTrack, &sTrackInfoVideo);
if (HI_SUCCESS != s32Ret)
{
MLOGE("HI_MP4_MUXER_CreateTrack fail 0x%x \n", s32Ret);
}
#if 1//rec_audio
s32Ret = HI_MP4_MUXER_CreateTrack(hMP4Muxer, &hAudioTrack, &sTrackInfoAudio);
if (HI_SUCCESS != s32Ret)
{
MLOGE("HI_MP4_MUXER_CreateTrack fail 0x%x \n", s32Ret);
}
#endif
MLOGD("udisk mp4 hMP4Muxer:0x%x width:%d, height:%d\n", hMP4Muxer, sTrackInfoVideo.stVideoInfo.u32Width, sTrackInfoVideo.stVideoInfo.u32Height);
udiskRecordStatus = RECORD_START;
return 0;
}
/**function: StopUdiskAVRecord()
* description: stop av muxer
*/
static int StopUdiskAVRecord(char* filename)
{
MLOGD("udiskRecordStatus:%d\n", udiskRecordStatus);
if(udiskRecordStatus != RECORD_STOP)
{
int fileErr = 0;
udiskRecordStatus = RECORD_STOP;
usleep(50*1000);
MLOGD("hMP4Muxer:0x%x, filename:"GREEN"%s"NONE" mux rec end\n", hMP4Muxer, filename);
HI_U64 u64Duration = 0;
HI_S32 s32Ret = HI_SUCCESS;
s32Ret = HI_MP4_MUXER_DestroyAllTracks(hMP4Muxer, NULL);
if (HI_SUCCESS != s32Ret)
{
MLOGE("HI_MP4_MUXER_DestroyAllTracks ret 0x%x\n", s32Ret);
fileErr = 1;
}
s32Ret = HI_MP4_MUXER_Destroy(hMP4Muxer, &u64Duration);
if (HI_SUCCESS != s32Ret)
{
MLOGE("HI_MP4_MUXER_Destroy ret 0x%x\n", s32Ret);
fileErr = 1;
}
PDT_CHECK_EXPR(HI_SUCCESS == s32Ret);
hMP4Muxer = 0;
if(fileErr == 1)
{
MLOGD("remove file:%s\n", filename);
remove(filename);
}
}
return 0;
}
#if 1//audio
/**function: UdiskWriteAudioFrame
* description: audio writeFrame
*/
int UdiskWriteAudioFrame(HI_MP4_FRAME_DATA_S* stFrameData)
{
HI_S32 s32Ret = HI_SUCCESS;
unsigned int gap = (unsigned int)stFrameData->u64TimeStamp - (unsigned int)thdu64AudioPTS;
//MLOGD("audio gap:%u\n", gap);
//if gap is 0 or pts equal before's, need discard data
if((gap == 0) || (thdu64AudioPTS == stFrameData->u64TimeStamp))
{
//end mux rec
return 0;
}
thdu64AudioPTS = stFrameData->u64TimeStamp;
if(CicbufIsInvalid(&audioCicbuf) != 0)
{
CicbufWrite(&audioCicbuf, (ElemType *)stFrameData);
}
return 0;
}
/**function: UdiskReadAudioFrame
* description: audio ReadFrame
*/
static int UdiskReadAudioFrame()
{
HI_S32 s32Ret = HI_SUCCESS;
HI_MP4_FRAME_DATA_S* stFrameData;
HI_MP4_FRAME_DATA_S mp4FrameData;
stFrameData = &mp4FrameData;
if(CicbufIsEmpty(&audioCicbuf))
{
return 0;
}
CicbufRead(&audioCicbuf, (ElemType*)stFrameData);
s32Ret = HI_MP4_MUXER_WriteFrame(hMP4Muxer, hAudioTrack, stFrameData);
if (HI_SUCCESS != s32Ret)
{
MLOGD("HI_MP4_MUXER_WriteFrame fail 0x%x \n", s32Ret);
if(s32Ret == 0x1)
{
}
}
PDT_CHECK_EXPR(HI_SUCCESS == s32Ret);
return 0;
}
#endif//audio
/**function: UdiskWriteVideoFrame()
* description: video writeFrame
*/
int UdiskWriteVideoFrame(HI_MP4_FRAME_DATA_S* stFrameData)
{
HI_S32 s32Ret = HI_SUCCESS;
unsigned int gap = (unsigned int)stFrameData->u64TimeStamp - (unsigned int)thdu64VideoPTS;
//MLOGD("audio gap:%u\n", gap);
//if gap is 0 or pts equal before's, need discard data
if((gap == 0) || (thdu64VideoPTS == stFrameData->u64TimeStamp))
{
//end mux rec
return 0;
}
thdu64VideoPTS = stFrameData->u64TimeStamp;
if(CicbufIsInvalid(&videoCicbuf) != 0)
{
CicbufWrite(&videoCicbuf, (ElemType *)stFrameData);
}
return 0;
}
/**function: UdiskReadVideoFrame()
* description: video read Frame
*/
static int UdiskReadVideoFrame()
{
HI_S32 s32Ret = HI_SUCCESS;
HI_MP4_FRAME_DATA_S* stFrameData;
HI_MP4_FRAME_DATA_S mp4FrameData;
stFrameData = &mp4FrameData;
if(CicbufIsEmpty(&videoCicbuf))
{
return 0;
}
CicbufRead(&videoCicbuf, (ElemType*)stFrameData);
s32Ret = HI_MP4_MUXER_WriteFrame(hMP4Muxer, hVideoTrack, stFrameData);
if (HI_SUCCESS != s32Ret)
{
MLOGD("HI_MP4_MUXER_WriteFrame fail 0x%x \n", s32Ret);
if(s32Ret == 0x1)
{
}
}
PDT_CHECK_EXPR(HI_SUCCESS == s32Ret);
return 0;
}
/***************************************************************************************/
/**function: CheckFileSizeLimit
* description: check file size limit
* return: [-1]-size overflow, [0]-size normal
*/
static int CheckFileSizeLimit(char* filename)
{
struct stat statbuf;
stat(filename, &statbuf);
if( statbuf.st_size >= 0xEFFFFFFF)//0xEFFFFFFF
{
return -1;
}
else
return 0;
}
/**function: UdiskAVRecordThr
* description: audio video record Thread
*/
static void UdiskAVRecordThr(void *args)
{
MLOGD("thread id: 0x%x\n", pthreadUdiskRecord);
struct tm *tm_now;
time_t nowT;
char out_filename[64];
int ret = 0;
record_state_en runState = REC_RUN;
// HI_U64 audioStartPts = 0;
HI_U64 videoStartPts = 0;
HI_MP4_FRAME_DATA_S* stAudioFrameData;
HI_MP4_FRAME_DATA_S* stVideoFrameData;
HI_MP4_FRAME_DATA_S mp4AudioFrameData;
HI_MP4_FRAME_DATA_S mp4VideoFrameData;
stAudioFrameData = &mp4AudioFrameData;
stVideoFrameData = &mp4VideoFrameData;
START_NEW_REC:
//if sdcard rec not rec, not start
if(GetFlagSdcardRec() == SDCARD_RECORD_STOP)//sd not rec
{
if(cmdReq == REC_STOP)
{
return (void *)0;
}
// MLOGD("udisk not mount\n");
sleep(1);
goto START_NEW_REC;
}
//if udisk unmount, not rec
if(GetUdiskMountState() != UDISK_MOUNT)//udisk out
{
if(cmdReq == REC_STOP)
{
return (void *)0;
}
// MLOGD("udisk not mount\n");
sleep(1);
goto START_NEW_REC;
}
recordStatus = RECORD_START;
nowT = time(NULL);
tm_now = localtime(&nowT);
static int udiskRecordFileNum = 1;
sprintf(out_filename, "/tmp/VIDEO_%04d.MP4", udiskRecordFileNum++);
StartUdiskAVRecord(out_filename);
runState = REC_RUN;
// audioStartPts = 0;
videoStartPts = 0;
int timeCnt = 0;
while(cmdReq != REC_STOP)
{
timeCnt ++;
if (timeCnt > 200) {
timeCnt = 0 ;
ret = CheckFileSizeLimit(out_filename);
if (ret < 0)
{
runState = REC_OVERSPACE;
break;
}
}
//video cicbuf is empty, not write
if(CicbufIsEmpty(&videoCicbuf))
{
usleep(2 * 1000);
continue;
}
else//video has frame, get video framebuf
{
CicbufGetData(&videoCicbuf, (ElemType*)stVideoFrameData);
}
//file frist record, get 'I' frame
if(videoStartPts == 0)
{
if(stVideoFrameData->bKeyFrameFlag == HI_TRUE)//is 'I' frame
{
videoStartPts = stVideoFrameData->u64TimeStamp;
}
else//not 'I' frame
{
continue;
}
}
if(CicbufIsEmpty(&audioCicbuf))//audio cicbuf is empty, only write video
{
UdiskReadVideoFrame();
}
else//audio has frame
{
CicbufGetData(&audioCicbuf, (ElemType*)stAudioFrameData);// get audio frame
if(stAudioFrameData->u64TimeStamp < videoStartPts)//audio frame < 'I' frame
{//remove audio frame
CicbufRemoveData(&audioCicbuf);
continue;
}
if(stAudioFrameData->u64TimeStamp <= stVideoFrameData->u64TimeStamp)//audio frame < video frame
{//write audio frame
UdiskReadAudioFrame();
}
else if(stAudioFrameData->u64TimeStamp > stVideoFrameData->u64TimeStamp)//audio frame > video frame
{//write video frame
UdiskReadVideoFrame();
}
}
usleep(2 * 1000);
}
StopUdiskAVRecord(out_filename);
end:
recordStatus = RECORD_STOP;
if((cmdReq != REC_STOP) && (runState == REC_OVERSPACE))
{
goto START_NEW_REC;
}
return (void *)0;
}
/**function: CreateUdiskRecordThr
* description: create udisk record thread
*/
int CreateUdiskRecordThr(void)
{
MLOGD("start hi_product_record thr\n");
if(cmdReq != REC_RUN)
{
cmdReq = REC_RUN;
//init circularbuf
CicbufInit(&audioCicbuf, AUDIO_CIC_BUF_LEN);
CicbufInit(&videoCicbuf, VIDEO_CIC_BUF_LEN);
// MLOGD("pthreadUdiskRecord:%d", pthreadUdiskRecord);
if(pthread_create(&pthreadUdiskRecord, NULL, UdiskAVRecordThr, NULL) != 0)
{
MLOGE("create UdiskAVRecordThr failed!\n");
return -1;
}
}
return 0;
}
/**function: DestroyUdiskRecordThr
* description: destroy udisk record thread
*/
int DestroyUdiskRecordThr(void)
{
MLOGD("stop hi_product_record thr\n");
if(cmdReq != REC_STOP && pthreadUdiskRecord != 0)
{
cmdReq = REC_STOP;
// MLOGD("pthreadUdiskRecord:%d\n", pthreadUdiskRecord);
pthread_join(pthreadUdiskRecord, NULL);//if pthread is 0, signal 11
// MLOGD("pthreadUdiskRecord:%d\n", pthreadUdiskRecord);
pthreadUdiskRecord = 0;
if(recordStatus == RECORD_STOP)
{
MLOGD("CicbufSetValid\n");
CicbufSetValid(&audioCicbuf);
CicbufSetValid(&videoCicbuf);
usleep(10*1000);
MLOGD("CicbufDeInit\n");
//deinit circularbuf, need not used cicbuf, otherwise result in signal 6 & 11???
CicbufDeInit(&audioCicbuf);
CicbufDeInit(&videoCicbuf);
}
}
return 0;
}
- AudioStream.h
#ifndef __AUDIO_STREAM_H__
#define __AUDIO_STREAM_H__
/**function: UdiskAudioAencInit
* description: udisk audio aenc init
*/
HI_S32 UdiskAudioAencInit(void);
/**function: UdiskAudioAencStart
* description: udisk audio aenc start
*/
HI_S32 UdiskAudioAencStart(void);
/**function: UdiskAudioAencStop
* description: udisk audio aenc stop
*/
HI_S32 UdiskAudioAencStop(void);
/**function: UdiskAudioAencDeinit
* description: udisk audio aenc deinit
*/
HI_S32 UdiskAudioAencDeinit(void);
#endif /* End of #ifndef __AUDIO_STREAM_H__*/
- AudioStream.c
#include "ProductRecord.h"
#include "AudioStream.h"
extern HI_PDT_PARAM_CFG_S* g_pstPDTCfg;
#if 1//aenc1
static HI_HANDLE hAEncHdl = 1;
#endif//aenc1
static HI_AENC_CALLBACK_S stAEncCB;
//udisk audio aenc enable
#define UDISK_AUDIO_AENC 1
#define UDISK_AUDIO_WRITE 1
static HI_U64 thdu64PTS = 0;
static HI_U32 thdu32Seq = 0;
/**function: SAMPLE_UdiskAUDIOAENC_DataProc
* description: udisk audio anechdl1 callback
*/
static HI_S32 SAMPLE_UdiskAUDIOAENC_DataProc(HI_HANDLE AencHdl, HI_MPP_AENC_STREAM_S* pAStreamData, HI_VOID* pPrivateData)
{
if(UDISK_AUDIO_WRITE){
HI_MP4_FRAME_DATA_S stFrameData;
memset(&stFrameData, 0x00, sizeof(HI_MP4_FRAME_DATA_S));
stFrameData.u64TimeStamp = pAStreamData->u64TimeStamp;
stFrameData.pu8DataBuffer = pAStreamData->pu8Addr;
stFrameData.u32DataLength = pAStreamData->u32Len;
stFrameData.bKeyFrameFlag = HI_FALSE;
unsigned long long gap = pAStreamData->u64TimeStamp - thdu64PTS;
if(gap > 26000)
{
printf("audio gap:%llu, beforeSeq:%d - %llu, this Seq:%d - %llu\n", gap, thdu32Seq , thdu64PTS, pAStreamData->u32Seq, pAStreamData->u64TimeStamp);
}
int seq = pAStreamData->u32Seq - thdu32Seq;
if(seq > 1)
{
printf("seq:%d, before %d : %llu, this %d : %llu\n", seq, thdu32Seq, thdu64PTS, pAStreamData->u32Seq, pAStreamData->u64TimeStamp);
}
thdu64PTS = pAStreamData->u64TimeStamp;
thdu32Seq = pAStreamData->u32Seq;
UdiskWriteAudioFrame(&stFrameData);
return HI_SUCCESS;
}
return HI_SUCCESS;
}
/**function: UdiskAudioAencInit
* description: udisk audio aenc init
*/
HI_S32 UdiskAudioAencInit()
{
if(UDISK_AUDIO_AENC == 0)
{
return HI_SUCCESS;
}
MLOGD("udisk aenc init\n");
HI_S32 s32Ret = HI_SUCCESS;
#if 1//aenc1
HI_MPP_AENC_ATTR_S stMppAencAttr;
stMppAencAttr.enAencFormat = g_pstPDTCfg->stMediaCfg.stAEncCfg[0].stAencAttr.enAencFormat;
stMppAencAttr.u32PtNumPerFrm = g_pstPDTCfg->stMediaCfg.stAEncCfg[0].stAencAttr.u32PtNumPerFrm;
stMppAencAttr.pValue = &g_pstPDTCfg->stMediaCfg.stAEncCfg[0].stAencAttr.stAacAencAttr;
// stMppAencAttr.pValue->enSoundType = 0;//mono//err, g_pstPDTCfg is const param
stMppAencAttr.u32Len = sizeof(AENC_ATTR_AAC_S);
s32Ret = HI_MAPI_AEnc_Init(hAEncHdl, &stMppAencAttr);
if(s32Ret != HI_SUCCESS)
{
MLOGE("HI_MAPI_AEnc_Init fail, s32Ret:0x%x\n", s32Ret);
}
#endif//aenc1
return s32Ret;
}
/**function: UdiskAudioAencStart
* description: udisk audio aenc start
*/
HI_S32 UdiskAudioAencStart()
{
if(UDISK_AUDIO_AENC == 0)
{
return HI_SUCCESS;
}
MLOGD("udisk aenc start\n");
HI_S32 s32Ret = HI_SUCCESS;
stAEncCB.pfnDataCB = SAMPLE_UdiskAUDIOAENC_DataProc;
stAEncCB.pPrivateData = HI_NULL;
#if 1//aenc1
s32Ret = HI_MAPI_AEnc_RegisterCallback(hAEncHdl, &stAEncCB);
if(s32Ret != HI_SUCCESS)
{
MLOGE("HI_MAPI_AEnc_RegisterCallback fail, s32Ret:0x%x\n", s32Ret);
}
s32Ret = HI_MAPI_AEnc_BindACap(g_pstPDTCfg->stMediaCfg.stAEncCfg[0].ACapHdl, hAEncHdl);
if (HI_SUCCESS != s32Ret)
{
MLOGD("HI_MAPI_AEnc_BindACap failed. s32Ret=0x%x\n", s32Ret);
}
s32Ret = HI_MAPI_AEnc_Start(hAEncHdl);
if(s32Ret != HI_SUCCESS)
{
MLOGE("HI_MAPI_AEnc_Start fail, s32Ret:0x%x\n", s32Ret);
}
#endif//aenc1
//printf("Press Enter key to stop audio record...\n");
return s32Ret;
}
/**function: UdiskAudioAencStop
* description: udisk audio aenc stop
*/
HI_S32 UdiskAudioAencStop()
{
if(UDISK_AUDIO_AENC == 0)
{
return HI_SUCCESS;
}
MLOGD("udisk aenc stop\n");
HI_S32 s32Ret = HI_SUCCESS;
#if 1//aenc1
s32Ret = HI_MAPI_AEnc_Stop(hAEncHdl);
if(s32Ret != HI_SUCCESS)
{
MLOGE("HI_MAPI_AEnc_Stop fail, s32Ret:0x%x\n", s32Ret);
}
s32Ret = HI_MAPI_AEnc_UnBindACap(g_pstPDTCfg->stMediaCfg.stAEncCfg[0].ACapHdl, hAEncHdl);
if (HI_SUCCESS != s32Ret)
{
MLOGD("HI_MAPI_AEnc_BindACap failed. s32Ret=0x%x\n", s32Ret);
}
s32Ret = HI_MAPI_AEnc_UnRegisterCallback(hAEncHdl, &stAEncCB);
if(s32Ret != HI_SUCCESS)
{
MLOGE("HI_MAPI_AEnc_UnRegisterCallback fail, s32Ret:0x%x\n", s32Ret);
}
#endif//aenc1
return s32Ret;
}
/**function: UdiskAudioAencDeinit
* description: udisk audio aenc deinit
*/
HI_S32 UdiskAudioAencDeinit()
{
if(UDISK_AUDIO_AENC == 0)
{
return HI_SUCCESS;
}
MLOGD("udisk aenc deinit\n");
HI_S32 s32Ret = HI_SUCCESS;
#if 1//aenc1
s32Ret = HI_MAPI_AEnc_DeInit(hAEncHdl);
if(s32Ret != HI_SUCCESS)
{
MLOGE("HI_MAPI_AEnc_DeInit fail, s32Ret:0x%x\n", s32Ret);
}
#endif//aenc1
return s32Ret;
}
- VideoStream.c
static HI_U64 thdu64PTS = 0;
static HI_U32 thdu32Seq = 0;
HI_S32 SAMPLE_VENC_VIDEO_DataProc(HI_HANDLE VencHdl, HI_VENC_DATA_S* pVStreamData, HI_VOID* pPrivateData)
{
#if 1
if((((HiLiveVideoContext*)pPrivateData)->hVencHdl == 0) || (VencHdl == 1 && enVideoMode == 5) )
{
if(1)
{
HI_MP4_FRAME_DATA_S stFrameData;
memset(&stFrameData, 0x00, sizeof(HI_MP4_FRAME_DATA_S));
//get keyFrame info
HI_U8* pu8Data = pVStreamData->astPack[0].pu8Addr[0] + pVStreamData->astPack[0].u32Offset;
HI_U32 u32Len = pVStreamData->astPack[0].au32Len[0] - pVStreamData->astPack[0].u32Offset;
HI_BOOL bKeyFrame = HI_FALSE;
if (HI_MPP_PAYLOAD_TYPE_H264 == pVStreamData->astPack[0].stDataType.enPayloadType)
{
if (HI_ENC_H264E_NALU_ISLICE == pVStreamData->astPack[0].stDataType.enH264EType
|| HI_ENC_H264E_NALU_IDRSLICE == pVStreamData->astPack[0].stDataType.enH264EType)
{
bKeyFrame = HI_TRUE;
}
}
else if (HI_MPP_PAYLOAD_TYPE_H265 == pVStreamData->astPack[0].stDataType.enPayloadType)
{
if (HI_ENC_H265E_NALU_ISLICE == pVStreamData->astPack[0].stDataType.enH265EType
|| HI_ENC_H265E_NALU_IDRSLICE == pVStreamData->astPack[0].stDataType.enH265EType)
{
bKeyFrame = HI_TRUE;
}
}
//video
stFrameData.pu8DataBuffer = pu8Data;
stFrameData.u32DataLength = u32Len;
stFrameData.bKeyFrameFlag = bKeyFrame;
stFrameData.u64TimeStamp = pVStreamData->astPack[0].u64PTS;
unsigned long long gap = pVStreamData->astPack[0].u64PTS - thdu64PTS;
if(gap > 35000)
{
printf("gap:%llu, beforeSeq:%d - %llu, this Seq:%d - %llu\n", gap, thdu32Seq, thdu64PTS, pVStreamData->u32Seq, pVStreamData->astPack[0].u64PTS);
}
int seq = pVStreamData->u32Seq - thdu32Seq;
if(seq > 1)
{
printf("seq:%d, before %d : %llu, this %d : %llu\n", seq, thdu32Seq, thdu64PTS, pVStreamData->u32Seq, pVStreamData->astPack[0].u64PTS);
}
thdu64PTS = pVStreamData->astPack[0].u64PTS;
thdu32Seq = pVStreamData->u32Seq;
UdiskWriteVideoFrame(&stFrameData);
return HI_SUCCESS;
}
}
#endif
return HI_SUCCESS;
}
HI_S32 HI_VSTREAM_Create(HI_LIVE_VIDEO_STREAM_S** ppStream, HI_HANDLE hVencHdl)
{
MLOGD("into----, hVencHdl:%d\n", hVencHdl);
HiLiveVideoContext* pContext = (HiLiveVideoContext*)malloc(sizeof(HiLiveVideoContext));
if (!pContext)
{
printf("malloc live video context failed! \n");
return HI_FAILURE;
}
memset(pContext, 0, sizeof(HiLiveVideoContext));
pContext->hVencHdl = hVencHdl;
/*create videostream and malloc*/
HI_LIVE_VIDEO_STREAM_S* pstStream = (HI_LIVE_VIDEO_STREAM_S*)malloc(sizeof(HI_LIVE_VIDEO_STREAM_S));
if (!pstStream)
{
SAFE_FREE(pContext);
printf("malloc HI_LIVE_VIDEO_STREAM_S failed! \n");
return HI_FAILURE;
}
/*init the videostream*/
*pstStream = liveVideoStream;
pstStream->handle = (HI_HANDLE)pContext;
/*force to translate to stream pointer*/
*ppStream = pstStream;
pContext->stVencCB.pfnDataCB = SAMPLE_VENC_VIDEO_DataProc;
pContext->stVencCB.pPrivateData = (HI_VOID*)pContext;
enVideoMode = GetCfgVideoMode();
MLOGD("venc\n");
return HI_MAPI_VEnc_RegisterCallback(pContext->hVencHdl, &pContext->stVencCB);
}
HI_VOID HI_VSTREAM_Destroy(HI_LIVE_VIDEO_STREAM_S* pstStream)
{
if (pstStream)
{
HiLiveVideoContext* pContext = (HiLiveVideoContext*)pstStream->handle;
if (pContext)
{
HI_MAPI_VEnc_UnRegisterCallback(pContext->hVencHdl, &pContext->stVencCB);
SAFE_FREE(pContext);
}
SAFE_FREE(pstStream);
}
}
关于Stream的说明:
1)音频句柄hAEncHdl用的是1,因为有特殊需求所以在ndk中做了相应处理,实际使用时用0即可。
2)UdiskAudioxxxStart需要在录像线程启动前调用。
3)UdiskAudioxxxInit需要在UdiskAudioxxxStart之前调用。
4)关机前需要stop并且deinit。
5)VideoStream实现参考AudioStream。
代码有些差,后续会接着优化。