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

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

这种工作模式

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

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


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


然后去执行,打印如下图

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

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]里,如下图注释:



我现在将这个函数再改为下面这样,只为将分开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;i<pstStream->u32PackCount;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;i<pstStream->u32PackCount;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; i<s32ReadLen-5; i++)
            {
                if (  pu8Buf[i  ] == 0 && pu8Buf[i+1] == 0 && pu8Buf[i+2] == 1 &&
                    ((pu8Buf[i+3]&0x1F) == 0x5 || (pu8Buf[i+3]&0x1F) == 0x1) &&
                    ((pu8Buf[i+4]&0x80) == 0x80)
                   )
                {
                    bFindStart = HI_TRUE;
                    i += 4;
                    break;
                }
            }
            for (; i<s32ReadLen-5; i++)
            {
                if (  pu8Buf[i  ] == 0 && pu8Buf[i+1] == 0 && pu8Buf[i+2] == 1 &&
                    ((pu8Buf[i+3]&0x1F) == 0x5 || (pu8Buf[i+3]&0x1F) == 0x1) &&
                    ((pu8Buf[i+4]&0x80) == 0x80)
                   )
                {
                    bFindEnd = HI_TRUE;
                    break;
                }
            }
            s32ReadLen = i;
            if (bFindStart == HI_FALSE)
            {
                SAMPLE_PRT("can not find start code in send stream thread:%d\n",pstSendParam->VdChn);
            }
            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; i<s32ReadLen-2; i++)
            {
                if (pu8Buf[i] == 0xFF && pu8Buf[i+1] == 0xD8)
                {
                    start = i;
                    bFindStart = HI_TRUE;
                    i = i + 2;
                    break;
                }
            }
            for (; i<s32ReadLen-4; i++)
            {
                if ((pu8Buf[i] == 0xFF) && (pu8Buf[i+1]& 0xF0) == 0xE0)
                {
                     len = (pu8Buf[i+2]<<8) + pu8Buf[i+3];
                     i += 1 + len;
                }
                else
                {
                    break;
                }
            }
            for (; i<s32ReadLen-2; i++)
            {
                if (pu8Buf[i] == 0xFF && pu8Buf[i+1] == 0xD8)

            s32ReadLen = i;
            if (bFindStart == HI_FALSE)
            {
                printf("\033[0;31mALERT!!!,can not find start code in send stream thread:%d!!!\033[0;39m\n",
                pstSendParam->VdChn);
            }
            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 *****************/改为上面那样就行
然后编译运行成功显示出来

  • 3
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hmbbPdx_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值