u盘录像功能实现

作者: 幕枫楚雨 | 来源:发表于2020-04-14 19:05 被阅读0次

    描述

    • 硬件: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盘录像功能实现

        本文链接:https://www.haomeiwen.com/subject/hxsxmhtx.html