海思音视频流合成mp4文件 您所在的位置:网站首页 ffmpeg缓存队列 海思音视频流合成mp4文件

海思音视频流合成mp4文件

2024-05-29 00:16| 来源: 网络整理| 查看: 265

海思SDK只提供了将视频文件合成MP4的例子,SDK中音频和视频流相关例子是分开的,如果需要将音频和视频同步合成MP4文件需要先将编码的音视频流送人合成缓存队列,然后从调用ffmpeg库接口从队列中读取音视频流进行MP4合成。ps:实现过程中参考了很多雷神的博客,在此感谢雷神。

MP4合成库文件下载路径:

https://download.csdn.net/download/luky_zhou123/20084201

下载该库后编译移植到海思,然后用以下方式进行调用。

1、将海思编码后的音频流存入合成队,修改sample_audio.c文件中SAMPLE_COMM_AUDIO_AencProc函数如下:  

void* SAMPLE_COMM_AUDIO_AencProc(void* parg) {     HI_S32 s32Ret;     HI_S32 AencFd;     SAMPLE_AENC_S* pstAencCtl = (SAMPLE_AENC_S*)parg;     AUDIO_STREAM_S stStream;     fd_set read_fds;     struct timeval TimeoutVal;     int ch = 0;     FD_ZERO(&read_fds);     AencFd = HI_MPI_AENC_GetFd(pstAencCtl->AeChn);     FD_SET(AencFd, &read_fds);     while (pstAencCtl->bStart)     {         TimeoutVal.tv_sec = 5;          TimeoutVal.tv_usec = 0;         FD_ZERO(&read_fds);         FD_SET(AencFd, &read_fds);         s32Ret = select(AencFd + 1, &read_fds, NULL, NULL, &TimeoutVal);         if (s32Ret < 0)         {             break;         }         else if (0 == s32Ret)         {             printf("%s: get aenc stream select time out\n", __FUNCTION__);             //break;                          continue;         }         if (FD_ISSET(AencFd, &read_fds))         {             /* get stream from aenc chn */             s32Ret = HI_MPI_AENC_GetStream(pstAencCtl->AeChn, &stStream, HI_FALSE);             if (HI_SUCCESS != s32Ret )             {                 printf("%s: HI_MPI_AENC_GetStream(%d), failed with %#x!\n", \                        __FUNCTION__, pstAencCtl->AeChn, s32Ret);                 pstAencCtl->bStart = HI_FALSE;                 return NULL;             }             /* send stream to decoder and play for testing */             if (HI_TRUE == pstAencCtl->bSendAdChn)             {                 s32Ret = HI_MPI_ADEC_SendStream(pstAencCtl->AdChn, &stStream, HI_TRUE);                 if (HI_SUCCESS != s32Ret )                 {                     printf("%s: HI_MPI_ADEC_SendStream(%d), failed with %#x!\n", \                            __FUNCTION__, pstAencCtl->AdChn, s32Ret);                     pstAencCtl->bStart = HI_FALSE;                     return NULL;                 }             }             /* save audio stream to file */             //printf("AppendAudio2Queue append data>>>>>>>>>>>>>>>>\n");             for(ch = 0; ch < MEDIA_CHAN_CNT; ch++)             {                 if(AppendAudio2Queue(stStream.pStream, stStream.u32Len,ch))                 {                     printf("AppendAudio2Queue error\n");                 }             }             //(HI_VOID)fwrite(stStream.pStream, 1, stStream.u32Len, pstAencCtl->pfd);             //fflush(pstAencCtl->pfd);                          /* finally you must release the stream */             s32Ret = HI_MPI_AENC_ReleaseStream(pstAencCtl->AeChn, &stStream);             if (HI_SUCCESS != s32Ret )             {                 printf("%s: HI_MPI_AENC_ReleaseStream(%d), failed with %#x!\n", \                        __FUNCTION__, pstAencCtl->AeChn, s32Ret);                 pstAencCtl->bStart = HI_FALSE;                 return NULL;             }         }     }     fclose(pstAencCtl->pfd);     pstAencCtl->bStart = HI_FALSE;     return NULL; }

2、将海思编码后的视频流存入队列修改sample_comm_venc.c文件中SAMPLE_COMM_VENC_GetVencStreamProc函数如下:  

HI_VOID* SAMPLE_COMM_VENC_GetVencStreamProc(HI_VOID* p) {     HI_S32 i,j;     HI_S32 s32ChnTotal;     VENC_CHN_ATTR_S stVencChnAttr;     SAMPLE_VENC_GETSTREAM_PARA_S* pstPara;     HI_S32 maxfd = 0;     struct timeval TimeoutVal;     fd_set read_fds;     HI_U32 u32PictureCnt[VENC_MAX_CHN_NUM]={0};     HI_S32 VencFd[VENC_MAX_CHN_NUM];     HI_CHAR aszFileName[VENC_MAX_CHN_NUM][64];     FILE* pFile[VENC_MAX_CHN_NUM];     char szFilePostfix[10];     VENC_CHN_STATUS_S stStat;     VENC_STREAM_S stStream;     HI_S32 s32Ret;     VENC_CHN VencChn;     PAYLOAD_TYPE_E enPayLoadType[VENC_MAX_CHN_NUM];     VENC_STREAM_BUF_INFO_S stStreamBufInfo[VENC_MAX_CHN_NUM];     unsigned char* pStremData = NULL;     int nSize = 0;     prctl(PR_SET_NAME, "GetVencStream", 0,0,0);     //thread_bind(4);     pstPara = (SAMPLE_VENC_GETSTREAM_PARA_S*)p;     s32ChnTotal = pstPara->s32Cnt;     /******************************************      step 1:  check & prepare save-file & venc-fd     ******************************************/     if (s32ChnTotal >= VENC_MAX_CHN_NUM)     {         SAMPLE_PRT("input count invaild\n");         return NULL;     }     for (i = 0; i < s32ChnTotal; i++)     {         /* decide the stream file name, and open file to save stream */         VencChn = pstPara->VeChn[i];         s32Ret = HI_MPI_VENC_GetChnAttr(VencChn, &stVencChnAttr);         if (s32Ret != HI_SUCCESS)         {             SAMPLE_PRT("HI_MPI_VENC_GetChnAttr chn[%d] failed with %#x!\n", \                        VencChn, s32Ret);             return NULL;         }         enPayLoadType[i] = stVencChnAttr.stVencAttr.enType;         s32Ret = SAMPLE_COMM_VENC_GetFilePostfix(enPayLoadType[i], szFilePostfix);         if (s32Ret != HI_SUCCESS)         {             SAMPLE_PRT("SAMPLE_COMM_VENC_GetFilePostfix [%d] failed with %#x!\n", \                        stVencChnAttr.stVencAttr.enType, s32Ret);             return NULL;         }         if(PT_JPEG != enPayLoadType[i])         {             snprintf(aszFileName[i],32, "stream_chn%d%s", i, szFilePostfix);             pFile[i] = fopen(aszFileName[i], "wb");             if (!pFile[i])             {                 SAMPLE_PRT("open file[%s] failed!\n",                            aszFileName[i]);                 return NULL;             }         }         /* Set Venc Fd. */         VencFd[i] = HI_MPI_VENC_GetFd(VencChn);         if (VencFd[i] < 0)         {             SAMPLE_PRT("HI_MPI_VENC_GetFd failed with %#x!\n",                        VencFd[i]);             return NULL;         }         if (maxfd VeChn[0], pstPara->VeChn[1], VencFd[0], VencFd[1]);     /******************************************      step 2:  Start to get streams of each channel.     ******************************************/     while (HI_TRUE == pstPara->bThreadStart)     {         FD_ZERO(&read_fds);         for (i = 0; i < s32ChnTotal; i++)         {             FD_SET(VencFd[i], &read_fds);         }         TimeoutVal.tv_sec  = 4;         TimeoutVal.tv_usec = 0;         s32Ret = select(maxfd + 1, &read_fds, NULL, NULL, &TimeoutVal);         if (s32Ret < 0)         {             SAMPLE_PRT("select failed!\n");             break;         }         else if (s32Ret == 0)         {             SAMPLE_PRT("get venc chn %d stream time out, continue\n", VencChn);             continue;         }         else         {             for (i = 0; i < s32ChnTotal; i++)             {                 if (FD_ISSET(VencFd[i], &read_fds))                 {                     /*******************************************************                      step 2.1 : query how many packs in one-frame stream.                     *******************************************************/                     memset(&stStream, 0, sizeof(stStream));                     //s32Ret = HI_MPI_VENC_QueryStatus(i, &stStat);                     s32Ret = HI_MPI_VENC_QueryStatus(pstPara->VeChn[i], &stStat);                     if (HI_SUCCESS != s32Ret)                     {                         SAMPLE_PRT("HI_MPI_VENC_QueryStatus chn[%d] failed with %#x!\n", pstPara->VeChn[i], s32Ret);                         break;                     }                     /*******************************************************                     step 2.2 :suggest to check both u32CurPacks and u32LeftStreamFrames at the same time,for example:                      if(0 == stStat.u32CurPacks || 0 == stStat.u32LeftStreamFrames)                      {                         SAMPLE_PRT("NOTE: Current  frame is NULL!\n");                         continue;                      }                     *******************************************************/                     if(0 == stStat.u32CurPacks)                     {                           SAMPLE_PRT("NOTE: Current  frame is NULL!\n");                           continue;                     }                     /*******************************************************                      step 2.3 : malloc corresponding number of pack nodes.                     *******************************************************/                     stStream.pstPack = (VENC_PACK_S*)malloc(sizeof(VENC_PACK_S) * stStat.u32CurPacks);                     if (NULL == stStream.pstPack)                     {                         SAMPLE_PRT("malloc stream pack failed!\n");                         break;                     }                     /*******************************************************                      step 2.4 : call mpi to get one-frame stream                     *******************************************************/                     stStream.u32PackCount = stStat.u32CurPacks;                     s32Ret = HI_MPI_VENC_GetStream(pstPara->VeChn[i], &stStream, HI_TRUE);                     if (HI_SUCCESS != s32Ret)                     {                         free(stStream.pstPack);                         stStream.pstPack = NULL;                         SAMPLE_PRT("HI_MPI_VENC_GetStream failed with %#x!\n", \                                    s32Ret);                         break;                     }                     /*******************************************************                      step 2.5 : save frame to file                     *******************************************************/                     if(PT_JPEG == enPayLoadType[i])                     {                         snprintf(aszFileName[i],32, "stream_chn%d_%d%s", i, u32PictureCnt[i],szFilePostfix);                         pFile[i] = fopen(aszFileName[i], "wb");                         if (!pFile[i])                         {                             SAMPLE_PRT("open file err!\n");                             return NULL;                         }                     } #ifndef __HuaweiLite__                     //SAMPLE_PRT("SAMPLE_COMM_VENC_SaveStream chan:%d\n",i);                     //if(0 == i)                     {                         //printf("SAMPLE_COMM_VENC_SaveStream2MuxerQueue>>>>>>>>>>>>>>\n");                         //s32Ret = SAMPLE_COMM_VENC_SaveStream(pFile[i], &stStream); //add by zhousl 20210205 17:11                          s32Ret = SAMPLE_COMM_VENC_SaveStream2MuxerQueue(i,&stStream);                     }                     //s32Ret = SAMPLE_COMM_VENC_SaveStream(pFile[i], &stStream); //add by zhousl 20210205 17:11                       #else                     s32Ret = SAMPLE_COMM_VENC_SaveStream_PhyAddr(pFile[i], &stStreamBufInfo[i], &stStream); #endif                     if (HI_SUCCESS != s32Ret)                     {                         free(stStream.pstPack);                         stStream.pstPack = NULL;                         SAMPLE_PRT("save stream failed!\n");                         break;                     }                     /*******************************************************                      step 2.6 : release stream                      *******************************************************/                     s32Ret = HI_MPI_VENC_ReleaseStream(pstPara->VeChn[i], &stStream);                     if (HI_SUCCESS != s32Ret)                     {                         SAMPLE_PRT("HI_MPI_VENC_ReleaseStream failed!\n");                         free(stStream.pstPack);                         stStream.pstPack = NULL;                         break;                     }                     /*******************************************************                      step 2.7 : free pack nodes                     *******************************************************/                     free(stStream.pstPack);                     stStream.pstPack = NULL;                     u32PictureCnt[i]++;                     if(PT_JPEG == enPayLoadType[i])                     {                         fclose(pFile[i]);                     }                 }             }         }     }     /*******************************************************     * step 3 : close save-file     *******************************************************/     for (i = 0; i < s32ChnTotal; i++)     {         if(PT_JPEG != enPayLoadType[i])         {             fclose(pFile[i]);         }     }     return NULL; }

sample_comm_venc.c文件中增加SAMPLE_COMM_VENC_SaveStream2MuxerQueue,该函数将视频流存入视频缓存队列

HI_S32 SAMPLE_COMM_VENC_SaveStream2MuxerQueue(int ch, VENC_STREAM_S* pstStream) {     HI_S32 i;     HI_S32 s32Ret = 0;     unsigned char *pStremData = NULL;     int nSize = 0;     for (i = 0; i < pstStream->u32PackCount; i++)     {                     pStremData = (unsigned char*)pstStream->pstPack[i].pu8Addr + pstStream->pstPack[i].u32Offset;         nSize = pstStream->pstPack[i].u32Len - pstStream->pstPack[i].u32Offset;         if(s32Ret = AppendVideo2Queue(pStremData,nSize, ch))         {             SAMPLE_PRT("AppendVideo2Queue chan:%d err %d\n", s32Ret,ch);             return s32Ret;         }     }     return HI_SUCCESS; }

3、在海思主程序中调用库中int StartMuxMp4File(void)接口启动合成  

有问题欢迎留言:)

参考资料:

https://blog.csdn.net/leixiaohua1020/article/details/39759623

https://blog.csdn.net/qq_29536949/article/details/108563398

https://blog.csdn.net/cfl927096306/article/details/107486805



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有