海思3531 一如何实时观看摄像头VENC编码后的视频

要想看到摄像头图像实时VENC编码后的视频和画质,需要海思开启VI->VPSS->虚拟VO->VENC->视频队列->VDEC->VO 

这种工作模式

先打开海思SDK的mpp/samole/comom/sample_comm_venc.c文件

在第199行我们可以看到SAMPLE_COMM_VENC_SaveH264()这条函数,这条函数就是保存h264数据成为视频的。

海思3531 一如何实时观看摄像头VENC编码后的视频_第1张图片

现在将这个条函数修改如下图

海思3531 一如何实时观看摄像头VENC编码后的视频_第2张图片

然后去执行,打印如下图

海思3531 一如何实时观看摄像头VENC编码后的视频_第3张图片

如图打印所示,我们可以得出结论

pstStream->u32PacketCount是代表这次有多少个h264的NAL,pstStream->pstPack[i]->pu8Addr[0] 是数据开始存储的地址,pstStream->pstPack[i].u32Len[0] 代表这次数据有多长,当pstStream->pstPack[i].u32Len[1]>0的时候代表这段NAL还有一个地址空间的数据是在pstStream->pstPack[i]->pu8Addr[1]里,如下图注释:

海思3531 一如何实时观看摄像头VENC编码后的视频_第4张图片


我现在将这个函数再改为下面这样,只为将分开IDR帧数据连接起来入队列,如果是P帧也入队列。

HI_S32 SAMPLE_COMM_VENC_SaveH264(FILE* fpH264File, VENC_STREAM_S *pstStream)
{
    HI_U32 i;
    int data_len=0,buf_offset;
    unsigned char *buf=NULL;
    for(i=0;iu32PackCount;i++)   //计算长度
    {
        data_len+=pstStream->pstPack[i].u32Len[0];
        if(pstStream->pstPack[i].u32Len[1]>0)
        {
            data_len+=pstStream->pstPack[i].u32Len[1];
        }
    }

    buf=malloc(data_len);//根据长度分配空间
    if(NULL==buf)
    {
      printf("molloc buf error");
      return -1;
    }
    buf_offset=0;
    for(i=0;iu32PackCount;i++)//将数据装入buf
    {
        memcpy(buf+buf_offset,pstStream->pstPack[i].pu8Addr[0],pstStream->pstPack[i].u32Len[0]);
        buf_offset+=pstStream->pstPack[i].u32Len[0];
        if(pstStream->pstPack[i].u32Len[1]>0)
        {
            memcpy(buf+buf_offset,pstStream->pstPack[i].pu8Addr[1],pstStream->pstPack[i].u32Len[1]);
            buf_offset+=pstStream->pstPack[i].u32Len[i];
        }
    }
    inQueue(buf,buf_offset,0);//数据如队列
    return HI_SUCCESS;
}

数据入队列之后我们主要是看他是如何读取h264数据的显示出来主要程序是在mpp/sample/vdec/sample_vdec.c

void* SAMPLE_VDEC_SendStream(void* p)
{
    VDEC_STREAM_S stStream;
    SAMPLE_VDEC_SENDPARAM_S *pstSendParam;
    char sFileName[50], sFilePostfix[20];
    FILE* fp = NULL;
    HI_S32 s32BlockMode = HI_IO_BLOCK;
    HI_U8 *pu8Buf;
    HI_U64 u64pts;
    HI_S32 s32IntervalTime = 40000;
    HI_S32 i, s32Ret, len, start;
    HI_S32 s32UsedBytes, s32ReadLen;
    HI_BOOL bFindStart, bFindEnd;

    start = 0;
    u64pts= 0;
    s32UsedBytes = 0;
    pstSendParam = (SAMPLE_VDEC_SENDPARAM_S *)p;

    /******************* open the stream file *****************/
    SAMPLE_COMM_SYS_Payload2FilePostfix(pstSendParam->enPayload, sFilePostfix);
    sprintf(sFileName, "stream_chn0%s", sFilePostfix);
     fp = fopen(sFileName, "r");
    if (HI_NULL == fp)
    {
        SAMPLE_PRT("can't open file %s in send stream thread:%d\n", sFileName,pstSendParam->VdChn);
        return (HI_VOID *)(HI_FAILURE);
    }
    printf("open file [%s] ok in send stream thread:%d!\n", sFileName,pstSendParam->VdChn);


    /******************* malloc the  stream buffer in user space *****************/
    if(pstSendParam->s32MinBufSize!=0)
    {
        pu8Buf=malloc(pstSendParam->s32MinBufSize);
        if(pu8Buf==NULL)
        {
            SAMPLE_PRT("can't alloc %d in send stream thread:%d\n",pstSendParam->s32MinBufSize,pstSendParam->VdChn);
            fclose(fp);
            return (HI_VOID *)(HI_FAILURE);
        }
    }
    else
    {
        SAMPLE_PRT("none buffer to operate in send stream thread:%d\n",pstSendParam->VdChn);
        return (HI_VOID *)(HI_FAILURE);
    }

    while (pstSendParam->bRun)
    {
        fseek(fp, s32UsedBytes, SEEK_SET);
        s32ReadLen = fread(pu8Buf, 1, pstSendParam->s32MinBufSize, fp);
        if (s32ReadLen<=0)
        {
             printf("file end.\n");
             break;
        }

        /******************* cutting the stream for frame *****************/
        if( (pstSendParam->enVideoMode==VIDEO_MODE_FRAME) && (pstSendParam->enPayload== PT_H264) )
        {
            bFindStart = HI_FALSE;
            bFindEnd   = HI_FALSE;
            for (i=0; iVdChn);
            }
            else if (bFindEnd == HI_FALSE)
            {
                s32ReadLen = i+5;
            }
        }
        else if( (pstSendParam->enPayload== PT_JPEG) || (pstSendParam->enPayload == PT_MJPEG) )
        {
            bFindStart = HI_FALSE;
            bFindEnd   = HI_FALSE;
            for (i=0; iVdChn);
            }
            else if (bFindEnd == HI_FALSE)
            {
                s32ReadLen = i+2;
            }
        }
         stStream.u64PTS  = u64pts;
         stStream.pu8Addr = pu8Buf + start;
         stStream.u32Len  = s32ReadLen;
        if(pstSendParam->enVideoMode==VIDEO_MODE_FRAME)
        {
            u64pts+=40000;
        }
        /******************* send stream *****************/
        if (s32BlockMode == HI_IO_BLOCK)
        {
            s32Ret=HI_MPI_VDEC_SendStream(pstSendParam->VdChn, &stStream, HI_IO_BLOCK);
        }
        else if (s32BlockMode == HI_IO_NOBLOCK)
        {
            s32Ret=HI_MPI_VDEC_SendStream(pstSendParam->VdChn, &stStream, HI_IO_NOBLOCK);
        }
        else
        {
            s32Ret=HI_MPI_VDEC_SendStream_TimeOut(pstSendParam->VdChn, &stStream, 8000);
        }

        if (HI_SUCCESS == s32Ret)
        {
            s32UsedBytes = s32UsedBytes +s32ReadLen + start;
        }
        else
        {
            if (s32BlockMode != HI_IO_BLOCK)
            {
                SAMPLE_PRT("failret:%x\n",s32Ret);
            }
            usleep(s32IntervalTime);
        }
        usleep(20000);

    }
        printf("send steam thread %d return ...\n", pstSendParam->VdChn);
        fflush(stdout);
        if (pu8Buf != HI_NULL)
        {
        free(pu8Buf);
        }       
        fclose(fp);
      return (HI_VOID *)HI_SUCCESS
}
主要是这一条是显示函数,其实它是获取h264文件里的IDR帧和P帧然后在再送去显示
因为我们入队列已经是IDR帧和P帧,所以我们直接将数据出队列提交给它就行,主要改动如下
...
  while (pstSendParam->bRun)
    {
        while(isEmptyQueue());
        a=(struct data_infornation *)outQueue();
        memcpy(pu8Buf,a->buf,a->len);
        s32ReadLen=a->len;
        free(a->buf);
        free(a);
        /******************* cutting the stream for frame *****************/
        if( (pstSendParam->enVideoMode==VIDEO_MODE_FRAME) && (pstSendParam->enPayload== PT_H264) )
.....
在while(pstSendParam->bRun) 到/******************* cutting the stream for frame *****************/改为上面那样就行
然后编译运行成功显示出来

你可能感兴趣的:(海思3531)