u盤錄像功能實現(xiàn)

描述

  • 硬件:hi3559
  • 系統(tǒng):嵌入式linux

思路

  1. 海思音視頻通過回調(diào)方式給出Frame數(shù)據(jù)谋旦,在回調(diào)函數(shù)中將Frame信息保存到循環(huán)緩沖區(qū)中污桦。
    關(guān)于緩沖區(qū)的實現(xiàn)參考循環(huán)緩沖區(qū)
  2. 在線程中讀緩沖區(qū)中的frame信息,對比時間戳并寫音視頻數(shù)據(jù)。
  3. 使用HI_MUXER寫MP4文件晦溪,有許多問題沒解決,后續(xù)準備改成ffmpeg實現(xiàn)挣跋。

代碼

  • 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);
    }
}

關(guān)于Stream的說明:
1)音頻句柄hAEncHdl用的是1三圆,因為有特殊需求所以在ndk中做了相應(yīng)處理,實際使用時用0即可。
2)UdiskAudioxxxStart需要在錄像線程啟動前調(diào)用舟肉。
3)UdiskAudioxxxInit需要在UdiskAudioxxxStart之前調(diào)用修噪。
4)關(guān)機前需要stop并且deinit。
5)VideoStream實現(xiàn)參考AudioStream路媚。

代碼有些差黄琼,后續(xù)會接著優(yōu)化。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末整慎,一起剝皮案震驚了整個濱河市脏款,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌裤园,老刑警劉巖撤师,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異拧揽,居然都是意外死亡剃盾,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進店門强法,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人湾笛,你說我怎么就攤上這事饮怯。” “怎么了嚎研?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵蓖墅,是天一觀的道長。 經(jīng)常有香客問我临扮,道長论矾,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任杆勇,我火速辦了婚禮贪壳,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蚜退。我一直安慰自己闰靴,他們只是感情好,可當我...
    茶點故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布钻注。 她就那樣靜靜地躺著蚂且,像睡著了一般。 火紅的嫁衣襯著肌膚如雪幅恋。 梳的紋絲不亂的頭發(fā)上杏死,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天,我揣著相機與錄音,去河邊找鬼淑翼。 笑死腐巢,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的窒舟。 我是一名探鬼主播系忙,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼惠豺!你這毒婦竟也來了银还?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤洁墙,失蹤者是張志新(化名)和其女友劉穎蛹疯,沒想到半個月后热监,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體捺弦,經(jīng)...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年孝扛,在試婚紗的時候發(fā)現(xiàn)自己被綠了列吼。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,622評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡苦始,死狀恐怖寞钥,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情陌选,我是刑警寧澤理郑,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站咨油,受9級特大地震影響您炉,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜役电,卻給世界環(huán)境...
    茶點故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一赚爵、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧法瑟,春花似錦囱晴、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至氓扛,卻和暖如春枯芬,著一層夾襖步出監(jiān)牢的瞬間论笔,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工千所, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留狂魔,地道東北人。 一個月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓淫痰,卻偏偏與公主長得像最楷,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子待错,可洞房花燭夜當晚...
    茶點故事閱讀 43,490評論 2 348

推薦閱讀更多精彩內(nèi)容