社区导航

 

搜索
查看: 312|回复: 1
打印 上一主题 下一主题

[原创] Hi3518重生记(三)minihttp中的http+mjpeg排bug

[复制链接]

52

TA的帖子

0

TA的资源

一粒金砂(中级)

Rank: 2

跳转到指定楼层
楼主
发表于 2020-5-11 08:55 | 只看该作者 |倒序浏览 |阅读模式

(一)BUG

经过群里的技术大佬们不懈努力,终于查出minihttp的bug出自tcp socket的意外断链,导致mjpeg的通信管道出问题。那么就需要对这种异常情况处理。

(二)超时处理

1-send超时返回

通过控制台printf排查,查出出bug时,是在【server_thread】线程里面调用send_mjpeg()函数时,卡在了send_to_client中的send这一socket发送函数内。

解决方法:

server_thread主循环开头加入超时处理协议:

SocketTimeoutChange(client_fd, 0,900);

 

函数定义:

 

void SocketTimeoutChange(int client_fd, int sec, int msec)
{
    struct timeval timeout = {sec, msec};
    int ret = setsockopt(client_fd, SOL_SOCKET, SO_SNDTIMEO, (const char *)&timeout, sizeof(timeout));
}

2-超时之后关闭socket,修改send_to_client函数

int send_to_client(int i, char* buf, ssize_t size) {;
    if (send_to_fd(client_fds.socket_fd, buf, size) < 0)
    {
        free_client(i);
        return -1;
    }
    return 0;
}

 

3-重启通道

光是关闭连接不够的,通道被破坏了,重新连接也接收不到mjpeg,需要重启 :

int restart_channal()
{

    printf("\tmjpegdead restart!-\t");

    //stop
    if (HI_MPI_VENC_StopRecvPic(g_mjpg_venc_chn) == HI_SUCCESS)
        printf("--\t");
    else
    {
        printf("->stop error\n");
        return -1;
    }

    //reset
    if (HI_MPI_VENC_ResetChn(g_mjpg_venc_chn) == HI_SUCCESS)
        printf("--\t");
    else
    {
        printf("->reset error\n");
    }


    //start
    if (HI_MPI_VENC_StartRecvPic(g_mjpg_venc_chn) == HI_SUCCESS)
        printf("--\t");
    else
    {
        printf("->restart error\n");
    }

    printf("-mjpeg finish!\n");
    return 0;
}

重启要重启在VENC的线程里面,不能在server_thread线程里面关完就在那个线程重启通道,会报错:

首先在send_to_fd里面设置一个标志位:

if (len < 0)
        {
            printf("~>len<0 error\t");
            g_resetChannalFlag = true;
            return -1;
        }

 

在VENC_GetVencStreamProc函数(这也是个子线程)里面while主循环的一开始:

        if (g_resetChannalFlag == true)
        {
            restart_channal();
            g_resetChannalFlag = false;
        }

(三)超时处理

到这里可以满足单连接,出现问题时直接关闭socket

但多连接时,其他连接继续运行有机会出现其他BUG,这是由于上一个socket的严重卡顿(上面设置了900ms)导致另一个本来好好的socket连接也因为本次卡顿,而导致远方客户端异常断连,但这时候诡异的时,他不会因为socket发不出去而关闭,甚至发了几帧之后会因为mjpeg通道被破坏而彻底停止发送,更加不会触发上面的socket断连后重启通道的机制。

这时候可以从两个角度解决:

1-想方设法触发上面的机制

2-另外设置机制

第一种方法比较简单,而且方便使用,或许可以通过调用send_to_socket函数发送一些无关数据来实现触发。

但遗憾的是一开始因为代码耦合性过强,暂时没想到该怎么实现,因此我用第二种方式处理:

 

1-VENC_SaveStream()判断H264帧和MJPEG帧不对等:

int t_mjpegErrorCounter=0;
HI_S32 VENC_SaveStream(int chn_index, PAYLOAD_TYPE_E enType, VENC_STREAM_S *pstStream) {
    // printf("Chn: %d   VENC_SaveStream %d  packs: %d\n", chn_index, enType, pstStream->u32PackCount, pstStream);
    HI_S32 s32Ret;
    if (PT_H264 == enType) { s32Ret = VENC_SaveH264(chn_index,  pstStream); t_mjpegErrorCounter++;}
    else if (PT_MJPEG == enType) { s32Ret = VENC_SaveMJpeg(chn_index, pstStream); t_mjpegErrorCounter=0;}
    else if (PT_JPEG == enType) { s32Ret = VENC_SaveJpeg(chn_index, pstStream); }
    // else if (PT_H265 == enType) { s32Ret = SAMPLE_COMM_VENC_SaveH265(pFd, pstStream); }
    else { return HI_FAILURE; }
    if(t_mjpegErrorCounter>=100){
        printf("mjpeg error\n");
        sleep(1);
        FreeAllMjpegClient();
        g_resetChannalFlag = true;
        g_DestoryErrorFlag = true;
        t_mjpegErrorCounter = 0;
        // restart_channal();
    }
    return s32Ret;
}

 

1-这片代码运行在【VENC_GetVencStreamProc】子线程里

2-睡眠1s是必须的,得让【server_thread】子线程里面向所有socket发送完本次的图像缓冲

3-FreeAllMjpegClient关掉所有客户端socket

4-g_resetChannalFlag置位标志这个循环重新到【VENC_GetVencStreamProc】子线程循环开始时会重新

5-其中g_DestoryErrorFlag是新设计的标志位,代表严重错误出现,全部mjpeg的客户端断连。

void FreeAllMjpegClient()
{

    printf("~>free all client :\n");
    for (uint32_t i = 0; i < MAX_CLIENTS; ++i)
    {
        if (client_fds.socket_fd < 0)
            continue;
        if (client_fds.type != STREAM_MJPEG)
            continue;
        free_client(i);
    }
    printf("\n");
}

 

在【server_thread】子线程的循坏一开始:

    while (keepRunning) {
        // waiting for a new connection
        int client_fd = accept(server_fd, NULL, NULL);
        printf("=>new socket\n\taccept:%d\t",client_fd);
        if (client_fd == -1) break;
        if(g_DestoryErrorFlag == true)
        {
            // sleep(3);
            g_DestoryErrorFlag = false;
            while(g_resetChannalFlag==true);
            // g_DestoryErrorFlag == false;
            // goto _FOUROFOUR;
        }
……

 

其中下面那个while的作用是等待mjpeg通道重启完成,避免再次出现通道错误而进行阻塞。

执行文件及源码: minihttp_http+mjpeg优化版本V200510.zip (174.88 KB, 下载次数: 0)

0

19

TA的帖子

10

TA的资源

一粒金砂(初级)

Rank: 1

沙发
发表于 2020-5-11 10:50 | 只看该作者

感谢楼主。代码写的很漂亮


您需要登录后才可以回帖 登录 | 注册

关闭

站长推荐上一条 1/4 下一条

  • 论坛活动 E手掌握

    扫码关注
    EEWORLD 官方微信

  • EE福利  唾手可得

    扫码关注
    EE福利 唾手可得

Archiver|手机版|小黑屋|电子工程世界 ( )

GMT+8, 2020-6-4 08:33 , Processed in 0.116338 second(s), 23 queries , Gzip On, MemCache On.

快速回复 返回顶部 返回列表
送彩金棋牌 买彩票充值送彩金 送彩金的棋牌app糖果派对 手机彩票送彩金 澳客彩票 澳客彩票 手机彩票送彩金 送彩金棋牌游戏 送彩金的网址怎么找 送彩金棋牌平台大全