u盘录像功能实现

描述

  • 硬件:hi3559
  • 系统:嵌入式linux

思路

  1. 海思音视频通过回调方式给出Frame数据,在回调函数中将Frame信息保存到循环缓冲区中。
    关于缓冲区的实现参考循环缓冲区
  2. 在线程中读缓冲区中的frame信息,对比时间戳并写音视频数据。
  3. 使用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。

代码有些差,后续会接着优化。

你可能感兴趣的:(u盘录像功能实现)