mengxp

mengxp

0个粉丝

18

问答

0

专栏

1

资料

mengxp  发布于  2017-09-11 10:02:23
采纳率 0%
18个问答
3811

非rtmp实现实时播放

 
本帖最后由 mengxp 于 2017-9-11 10:05 编辑

rtmp是一套标准协议,可以方便与其他程序对接。但是如果不需要考虑接口,只是自己使用的话,就不需要rtmp。
最简单的思路就是,从海思venc读出数据流不包装,直接通过tcp发出。解码程序收到数据流之后,直接送解码器,解出yuv数据直接送显示。
可见这种方案,不需要考虑什么时间戳之类的东西,就是直接干。
整套流程时延100ms
架构:
VI-----------VENC--------TCP send---------- TCP recv ----------官方SDK解码---------DirectDraw显示图像

贴个代码片段,
编码端(hi3516D)


void VencGetStream(VENC_CHN VeChn)
{
    HI_S32 s32Ret;
    int fdVenc, fdFile;
    PAYLOAD_TYPE_E enType;
    VENC_CHN_ATTR_S stVencChnAttr;

    fdVenc = HI_MPI_VENC_GetFd(VeChn);
    if(fdVenc < 0)
    {
        printf("VencGetStream: HI_MPI_VENC_GetFdfailed\n");
        return;
    }

    s32Ret = HI_MPI_VENC_GetChnAttr(VeChn, &stVencChnAttr);
    if (s32Ret)
    {
        printf("VencGetStream: HI_MPI_VENC_GetChnAttr chn[%d] failed with %#x!\n", VeChn, s32Ret);
        return;
    }
    enType = stVencChnAttr.stVeAttr.enType;

        if(UseNetwork)
        {
                fdFile = fdNetwork;
        }
        else
        {
                fdFile = open("/tmp/stream0.h265", O_CREAT | O_TRUNC | O_RDWR);
                if(fdFile < 0)
                {
                        printf("VencGetStream: create stream file failed!\n");
                        return;
                }
        }
       
    printf("receiving stream, press enter to break\n");
    while(1)
    {
        struct timeval tv;
        fd_set fds;

        FD_ZERO(&fds);
        FD_SET(fdVenc, &fds);
        FD_SET(STDIN_FILENO, &fds);
        
        tv.tv_sec  = 2;
        tv.tv_usec = 0;
        s32Ret = select(fdVenc + 1, &fds, NULL, NULL, &tv);
        if (s32Ret == 0)
            continue;   //timeout

        if (s32Ret < 0)
        {
            printf("VencGetStream: select failed!\n");
            break;
        }

        if(FD_ISSET(STDIN_FILENO, &fds))
        {
            char k = getchar();
            if(k == '\n')
            {
                printf("user interupt!\n");
                break;
            }
        }

        if(FD_ISSET(fdVenc, &fds))
        {
            VENC_CHN_STAT_S stStat;
            VENC_STREAM_S stStream;

            //有数据来了,检查有多少包
            s32Ret = HI_MPI_VENC_Query(VeChn, &stStat);
            if (s32Ret)
            {
                printf("VencGetStream: HI_MPI_VENC_Query failed with %#x!\n", s32Ret);
                break;
            }

            if(!stStat.u32CurPacks)
            {
                printf("NOTE: Current  frame is NULL!\n");
                continue;
            }
            
            //申请描述符内存
            stStream.pstPack = (VENC_PACK_S*)malloc(sizeof(VENC_PACK_S) * stStat.u32CurPacks);
            if (!stStream.pstPack)
            {
                printf("malloc stream pack failed!\n");
                break;
            }

            //获取描述符
            stStream.u32PackCount = stStat.u32CurPacks;
            s32Ret = HI_MPI_VENC_GetStream(VeChn, &stStream, HI_TRUE);
            if (s32Ret)
            {
                free(stStream.pstPack);
                stStream.pstPack = NULL;
                printf("HI_MPI_VENC_GetStream failed with %#x!\n", s32Ret);
                break;
            }
            
            //保存流数据
            switch(enType)
            {
                VENC_PACK_S*  pstData;
                char *pStream;
                int StreamSize;
                int i;

            case PT_H264:
                for (i = 0; i < stStream.u32PackCount; i++)
                {
                    pStream = (char *)stStream.pstPack.pu8Addr + stStream.pstPack.u32Offset;
                    StreamSize = stStream.pstPack.u32Len - stStream.pstPack.u32Offset;
                                        write(fdFile, pStream, StreamSize);
                    printf("Read H264 Stream %d bytes @ %p\n", StreamSize, pStream);
                }
                break;

            case PT_H265:
                for (i = 0; i < stStream.u32PackCount; i++)
                {
                    pStream = (char *)stStream.pstPack.pu8Addr + stStream.pstPack.u32Offset;
                    StreamSize = stStream.pstPack.u32Len - stStream.pstPack.u32Offset;
                                        write(fdFile, pStream, StreamSize);
                    printf("Read H265 Stream %d bytes @ %p\n", StreamSize, pStream);
                }
                break;

            case PT_MJPEG:
                for (i = 0; i < stStream.u32PackCount; i++)
                {
                    pstData = &stStream.pstPack;
                    pStream = (char *)pstData->pu8Addr + pstData->u32Offset;
                    StreamSize = pstData->u32Len - pstData->u32Offset;
                                        write(fdFile, pStream, StreamSize);
                    printf("Read MJPEG Stream %d bytes @ %p\n", StreamSize, pStream);
                }
                break;

            case PT_JPEG:
                for (i = 0; i < stStream.u32PackCount; i++)
                {
                    pstData = &stStream.pstPack;
                    pStream = (char *)pstData->pu8Addr + pstData->u32Offset;
                    StreamSize = pstData->u32Len - pstData->u32Offset;
                                        write(fdFile, pStream, StreamSize);
                    printf("Read JPEG Stream %d bytes @ %p\n", StreamSize, pStream);
                }
                break;
                               
                        default:
                                break;
            }

            //释放流数据
            s32Ret = HI_MPI_VENC_ReleaseStream(VeChn, &stStream);
            if (s32Ret)
            {
                free(stStream.pstPack);
                stStream.pstPack = NULL;
                break;
            }

            //释放描述符
            free(stStream.pstPack);
            stStream.pstPack = NULL;
        }
    }
        close(fdFile);
}



解码端只处理一个连接

int BufferDataOut(char *buf, int total, int len)
{
    int restlen = total - len;
    int i;

    if(restlen <= 0)
        return 0;

    for(i = 0; i < restlen; i++)
    {
        buf = buf[restlen + i];
    }
    return restlen;
}

void NetListen()
{
    WSADATA wsa;
    SOCKET sock = INVALID_SOCKET;
    char *RecvBuf = NULL;
    ULONG RecvBufSize = 1024*1024;

    do {
        struct sockaddr_in sin;
        int ret;

        WSAStartup(0x101, &wsa);

        RecvBuf = malloc(RecvBufSize);
        if(!RecvBuf)
            break;

        sock = socket(AF_INET, SOCK_STREAM, 0);
        if(sock == INVALID_SOCKET)
        {
            printf("NetListen: socket failed\n");
            break;
        }

        memset(&sin, 0, sizeof(sin));
        sin.sin_family = AF_INET;
        sin.sin_addr.s_addr = 0;
        sin.sin_port = htons(6666);
        ret = bind(sock, (struct sockaddr *)&sin, sizeof(sin));
        if(ret)
        {
            printf("NetListen: bind failed\n");
            break;
        }

        ret = listen(sock, 1);
        if(ret)
        {
            printf("NetListen: listen failed\n");
            break;
        }

        while(1)
        {
            struct sockaddr_in sin_accept;
            int sinlen = sizeof(sin_accept);
            SOCKET recvsock = INVALID_SOCKET;
            IH265DEC_HANDLE hDecoder;
            int RecvTotalLen = 0;

            recvsock = accept(sock, (struct sockaddr *)&sin_accept, &sinlen);
            if(recvsock == INVALID_SOCKET)
                continue;

            hDecoder = CreateH265Decoder(FALSE, TRUE);
            if(!hDecoder)
            {
                closesocket(recvsock);
                continue;
            }

            while(1)
            {
                char *buf = RecvBuf + RecvTotalLen;
                int bufsize = RecvBufSize - RecvTotalLen;
                int len, declen, err;
                ULONG dwTick = GetTickCount();
                char tmp[256];

                len = recv(recvsock, buf, bufsize, 0);
                if(len <= 0)
                {
                    break;
                }
                RecvTotalLen += len;
                RecvBytes += len;
                if(dwTick - RecvLastTick >= 1000)
                {
                    RecvBytesThisSec = RecvBytes - RecvBytesLastSec;
                    RecvBytesLastSec = RecvBytes;
                    RecvLastTick = dwTick;
                    sprintf(tmp, "Hi3516 H265 decode sample  recv: %d KB/s", RecvBytesThisSec / 1024);
                    SetWindowText(hWinMain, tmp);
                }

                err = H265StreamIn(hDecoder, RecvBuf, RecvTotalLen, &declen);
                if(err)
                {
                    break;
                }

                RecvTotalLen = BufferDataOut(RecvBuf, RecvTotalLen, declen);
            }

            closesocket(recvsock);
            DestroyH265Decoder(hDecoder);
        }

    } while (0);

    if(sock != INVALID_SOCKET)
        closesocket(sock);
}


BOOL DDraw(PDDRAW_HANDLE pHandle, IH265DEC_OUTARGS *pDecArgs)
{
    DDSURFACEDESC2 ddsd;    // DirectDraw 表面描述
    RECT rcDst;             // 目标区域
    RECT rcSrc;             // 源区域
    HRESULT hr;             // DirectDraw 函数返回值
    LPBYTE lpSurf;
    ULONG i, pos;

    if(!pHandle || !pHandle->pDirectDraw || !pHandle->pSurfaceOffScreen || !pHandle->pSurfacePrimary)
        return FALSE;

    memset(&ddsd, 0, sizeof(ddsd));
    ddsd.dwSize = sizeof(ddsd);
    hr = pHandle->pSurfaceOffScreen->Lock(NULL, &ddsd,DDLOCK_WAIT | DDLOCK_WRITEONLY,NULL);
    if(hr != S_OK)
        return FALSE;

    lpSurf = (LPBYTE)ddsd.lpSurface;
    for(i = 0, pos = 0; i < pDecArgs->uiDecHeight; i++, pos += pDecArgs->uiDecWidth)
    {
        memcpy(lpSurf, pDecArgs->pucOutYUV[0] + i * pDecArgs->uiYStride, pDecArgs->uiDecWidth);
        lpSurf += ddsd.lPitch;
    }
    for(i = 0, pos = 0; i < ((pDecArgs->uiDecHeight) >> 1); i++, pos += pDecArgs->uiDecWidth >> 1)
    {
        memcpy(lpSurf, pDecArgs->pucOutYUV[2] + i * pDecArgs->uiUVStride, pDecArgs->uiDecWidth >> 1);
        lpSurf += ddsd.lPitch >> 1;
    }
    for(i = 0, pos = 0; i < ((pDecArgs->uiDecHeight) >> 1); i++, pos += pDecArgs->uiDecWidth >> 1)
    {
        memcpy(lpSurf, pDecArgs->pucOutYUV[1] + i * pDecArgs->uiUVStride, pDecArgs->uiDecWidth >> 1);
        lpSurf += ddsd.lPitch >> 1;
    }
    pHandle->pSurfaceOffScreen->Unlock(NULL);

    // Blt到主表面上
    rcSrc.left = 0;
    rcSrc.top = 0;
    rcSrc.right = ddsd.dwWidth;
    rcSrc.bottom = ddsd.dwHeight;
    GetClientRect(pHandle->hWnd,&rcDst);
    ClientToScreen(pHandle->hWnd, (LPPOINT)&rcDst.left);
    ClientToScreen(pHandle->hWnd, (LPPOINT)&rcDst.right);
    while(1)
    {
        hr = pHandle->pSurfacePrimary->Blt(&rcDst, pHandle->pSurfaceOffScreen, &rcSrc, DDBLT_WAIT, NULL);
        if(hr == DDERR_SURFACELOST)
        {
            pHandle->pSurfacePrimary->Restore();
            pHandle->pSurfaceOffScreen->Restore();

        }
        if(hr != DDERR_WASSTILLDRAWING)
            break;
    }

    return TRUE;
}

int H265StreamIn(IH265DEC_HANDLE hDecoder, char *pStream, int iFileLen, int *pFrameTotalLen)
{
    IH265DEC_INARGS stInArgs;
    IH265DEC_OUTARGS stOutArgs = {0};
    int FrameTotalLen = 0;
    int DecodeEnd = 0;
    int ret = 0;

    while(!DecodeEnd)
    {
        UINT32 iNaluLen;

        H265DecLoadAU((UINT8 *)pStream, iFileLen, &iNaluLen);
        if(iNaluLen > 0)
            FrameTotalLen += iNaluLen;
        else
            break;

        stInArgs.eDecodeMode = IH265D_DECODE;
        stInArgs.pStream = (UINT8 *)pStream;
        stInArgs.uiStreamLen = iNaluLen;

        pStream += iNaluLen;
        iFileLen -= iNaluLen;

        stOutArgs.eDecodeStatus = (HW265D_DECODESTATUS)-1;
        stOutArgs.uiBytsConsumed = 0;

        // if return value if IH265D_NEED_MORE_BITS, read more bits from files
        while(stOutArgs.eDecodeStatus != IH265D_NEED_MORE_BITS)
        {
            INT32 iRet;

            // decode end
            if(stOutArgs.eDecodeStatus == IH265D_NO_PICTURE)
            {
                DbgPrint("IH265D_NO_PICTURE !!!!!!\n");
                DecodeEnd = 1;
                ret = -1;
                break;
            }
            // output decoded pictures
            if (stOutArgs.eDecodeStatus == IH265D_GETDISPLAY)
            {
                DDraw(pDDraw, &stOutArgs);

                iFrameIdx++;
            }

            stInArgs.pStream += stOutArgs.uiBytsConsumed;
            stInArgs.uiStreamLen -= stOutArgs.uiBytsConsumed;

            iRet = IHW265D_DecodeFrame(hDecoder, &stInArgs, &stOutArgs);

            if ((iRet != IHW265D_OK) && (iRet != IHW265D_NEED_MORE_BITS))
            {
                DbgPrint("IHW265D_DecodeFrame FAILED !!!!!! %d %d\n", iRet, iFrameIdx);
                DecodeEnd = 1;
                ret = -1;
                break;
            }
        }
    }
    *pFrameTotalLen = FrameTotalLen;
    return ret;
}

我来回答
回答7个
时间排序
认可量排序

zhuangweiye

8个粉丝

0

问答

0

专栏

0

资料

zhuangweiye 2017-09-11 10:23:15
认可0
够简单

不过监控行业还是实现rtsp比较好

eddiewu2017

0个粉丝

1

问答

0

专栏

0

资料

eddiewu2017 2017-09-11 11:03:41
认可0
这个延时是非常理想的,如果解码端是iOS,请问LZ有没有合适的想法?

mengxp

0个粉丝

18

问答

0

专栏

1

资料

mengxp 2017-09-11 11:33:25
认可0
[quote][url=forum.php?mod=redirect&goto=findpost&pid=63772&ptid=23453]eddiewu2017 发表于 2017-9-11 11:03[/url]
这个延时是非常理想的,如果解码端是iOS,请问LZ有没有合适的想法?[/quote]

官方sdk也支持ios吧。只要解决如何把yuv数据显示出来就可以啦。
估计要用opengl之类的吧??没玩过ios

eddiewu2017

0个粉丝

1

问答

0

专栏

0

资料

eddiewu2017 2017-09-12 21:01:04
认可0
[quote][url=forum.php?mod=redirect&goto=findpost&pid=63784&ptid=23453]mengxp 发表于 2017-9-11 11:33[/url]
官方sdk也支持ios吧。只要解决如何把yuv数据显示出来就可以啦。
估计要用opengl之类的吧??没玩过ios[/quote]

就是沒有看到有官方支持的iOS解码。

mengxp

0个粉丝

18

问答

0

专栏

1

资料

mengxp 2017-09-12 21:55:12
认可0
[quote][url=forum.php?mod=redirect&goto=findpost&pid=63918&ptid=23453]eddiewu2017 发表于 2017-9-12 21:01[/url]
就是沒有看到有官方支持的iOS解码。[/quote]

libHW_H265dec_IOS.a
有的。

eddiewu2017

0个粉丝

1

问答

0

专栏

0

资料

eddiewu2017 2017-09-12 23:27:17
认可0
[quote][url=forum.php?mod=redirect&goto=findpost&pid=63919&ptid=23453]mengxp 发表于 2017-9-12 21:55[/url]
libHW_H265dec_IOS.a
有的。[/quote]

谢谢!我只看了264目录下的,没有发现就主观认为其它都没有,:$,能发个稍微完整一点的编码端代码参考一下吗?

Arthur_LH

0个粉丝

2

问答

0

专栏

0

资料

Arthur_LH 2017-09-21 09:49:56
认可0
楼主能否给个demo看看,挪到3518试试去
或将文件直接拖到这里
悬赏:
E币
网盘
* 网盘链接:
* 提取码:
悬赏:
E币

Markdown 语法

  • 加粗**内容**
  • 斜体*内容*
  • 删除线~~内容~~
  • 引用> 引用内容
  • 代码`代码`
  • 代码块```编程语言↵代码```
  • 链接[链接标题](url)
  • 无序列表- 内容
  • 有序列表1. 内容
  • 缩进内容
  • 图片![alt](url)
+ 添加网盘链接/附件

Markdown 语法

  • 加粗**内容**
  • 斜体*内容*
  • 删除线~~内容~~
  • 引用> 引用内容
  • 代码`代码`
  • 代码块```编程语言↵代码```
  • 链接[链接标题](url)
  • 无序列表- 内容
  • 有序列表1. 内容
  • 缩进内容
  • 图片![alt](url)
举报反馈

举报类型

  • 内容涉黄/赌/毒
  • 内容侵权/抄袭
  • 政治相关
  • 涉嫌广告
  • 侮辱谩骂
  • 其他

详细说明

易百纳技术社区