企业号介绍

全部
  • 全部
  • 产品
  • 方案
  • 文章
  • 资料
  • 企业

飞凌嵌入式

141内容数 29608浏览量 71粉丝

专注智能设备核心平台研发与制造

发烧友实测 | i.MX8MP 基于HTTP网页服务器和UDP上位机的MJPG码流传输(mjpg-steamer)

01-10 78浏览量

 

 

作者|donatello1996

来源 | 电子发烧友

题图|飞凌嵌入式

 

本文采用的硬件板卡为飞凌嵌入式OKMX8MP-C开发板,系统版本Linux5.4.70+Qt5.15.0,主要介绍基于HTTP网页服务器和UDP上位机的MJPG码流传输

MJPG格式作为一种持续传输的视频码流,在远程监控领域中应用较广,而实现这种远程监控的第三方应用最常见的有两种:浏览器HTTP网页、UDP上位机。

 

 

两者各有优势,对比鲜明,其中:

  • UDP上位机:传输效率高,上位机编写方便。

  • HTTP网页方式:客户端无需安装上位机,只需要一个浏览器应用即可;客户端访问服务器支持跨平台支持,无论是电脑、平板、手机,还是Linux系统、Windows系统及安卓系统都可以,只要有浏览器应用都可访问,而UDP上位机则受限于目标平台,不易移植。

这两种应用各有优缺点,对于嵌入式开发者来说,两者都必须掌握。

 

一、HTTP网页服务器

先说下HTTP网页服务器获取MJPG码流的代码,首先是OKMX8MP-C在开发板端建立TCP服务器:

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
int TCP_Server_Found(socklen_t* socket_found , char* ip , int port){    struct sockaddr_in servaddr;    socklen_t addrsize = sizeof(struct sockaddr);
    bzero(&servaddr , sizeof(servaddr));    servaddr.sin_family = AF_INET;    servaddr.sin_addr.s_addr = inet_addr(ip);    servaddr.sin_port = htons(port);
    int ret;    IF( (*socket_found = socket(AF_INET , SOCK_STREAM , 0)) == -1)        {            printf("Create socket error: %s (errno :%d)\n",strerror(errno),errno);            return -1;        }
    int on = 1;    if(setsockopt(*socket_found , SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)    {        printf("setsockopt error\n");    }
    ret = bind(*socket_found , (struct sockaddr *)&servaddr , addrsize);    if(ret == -1)    {            printf("Tcp bind faiLED!\n");            return -1;    }
    if(listen(*socket_found , 5) == -1)    {            printf("Listen failed!\n");            return -1;    }    return 0;}
左右滑动查看完整代码

其中setsockopt()函数是可选的,一般只用于规避socket()函数的建立错误。

建立了TCP服务器后,返回的socklen_t型实参在后面的HTTP网页服务器中需要用到。

HTTP网页服务器所属的TCP操作是需要另起轮询线程来让客户端进行accept()握手操作的,accept()之前的listen()倒是只需要执行一次即可,accept()握手操作和recv()接收操作需要创建一个死循环线程:

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
pthread_create(&tid_tcp_web_recv , NULL , Thread_TCP_Web_Recv , NULL);
void * Thread_TCP_Web_Recv(void *arg){。。。while(1){            fd_socket_conn = accept(socket_web_server , (struct sockaddr *)&sockaddr_in_conn , &addrsize);           printf("fd_socket_conn = accept()\n");    。。。    recv(fd_socket_conn , recvbuf , 1000 , 0);}。。。}
左右滑动查看完整代码

MJPG帧可以使用Grab操作获取,获取到的MJPG帧需要在TCP线程中读,在Grab操作线程中写,这种被多个线程访问的资源需要加锁防止读写冲突,即资源被Grab操作写入时,需要上锁,不允许其它线程访问,操作完成时需要解锁,允许其它线程访问:

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
    pthread_mutex_lock(&pmt);
    pic_tmpbuffer = pic.tmpbuffer;    pic.tmpbytesused = buff.bytesused;    pic_tmpbytesused = pic.tmpbytesused;
    pthread_cond_broadcast(&pct);    pthread_mutex_unlock(&pmt);

左右滑动查看完整代码

线程互斥锁使用之前需要初始化:

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
pthread_mutex_t pmt;pthread_cond_t pct;
int main(int argc, char* argv[]){...TCP_Server_Found(&socket_web_server , (char*)argv[2] , PORT_TCP);pthread_mutex_init(&pmt , NULL);
    pthread_create(&tid_tcp_web_recv , NULL , Thread_TCP_Web_Recv , NULL);
    pthread_create(&tid_tcp_web_send , NULL , Thread_TCP_Web_Send , NULL);...    while(1)    {        V4l2_Grab_Mjpeg(false , MJPEG_FILE_NAME);...    }...}
左右滑动查看完整代码

然后是发送的细节,发送图片文件之前,需要先发送HTTP标准头,这个相当于给发送图片或者其它类型的流数据铺路:

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
#define STD_HEADER "Connection: close\r\n" \    "Server: MJPG-Streamer/0.2\r\n" \    "Cache-Control: no-store, no-cache, must-revalidate, pre-check=0, post-check=0, max-age=0\r\n" \    "Pragma: no-cache\r\n" \    "Expires: Mon, 3 Jan 2000 1256 GMT\r\n"
#define BOUNDARY "boundarydonotcross"
    printf("preparing header\n");    sprintf(buffer, "HTTP/1.0 200 OK\r\n" \            "Access-Control-Allow-Origin: *\r\n" \            STD_HEADER \            "Content-Type: multipart/x-mixed-replace;boundary=" BOUNDARY "\r\n" \            "\r\n" \            "--" BOUNDARY "\r\n");
    if(write(fd, buffer, strlen(buffer)) < 0)    {        free(frame);        return;    }
左右滑动查看完整代码

发送完HTTP标准头之后,就需要发送内容头(Content-Type),这处的Content-Type为image/jpeg,同样,HTTP标准协议里面image支持的类型远不止jpeg一种,发送完内容头之后就是正文和boundary结尾,这样帧完整的HTTP头发送到指定的TCP GET地址,就会在浏览器中显示刚刚发送的图片:

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
       sprintf(buffer, "Content-Type: image/jpeg\r\n" \                "Content-Length: %d\r\n" \                "X-Timestamp: %d.%06d\r\n" \                "\r\n", frame_size, (int)timestamp.tv_sec, (int)timestamp.tv_usec);
        printf("sending intemdiate header\n");        if(write(fd, buffer, strlen(buffer)) < 0)            break;
        printf("sending frame\n");        if(write(fd, frame, frame_size) < 0)            break;
        printf("sending boundary\n");        sprintf(buffer, "\r\n--" BOUNDARY "\r\n");        if(write(fd, buffer, strlen(buffer)) < 0)            break;
左右滑动查看完整代码

另外需要说明的是,TCP服务器线程在发送MJPEG流的时候是死循环发送的,因此TCP客户端在发送完GET指令之后,就会收到TCP服务器循环发送的图像缓存,TCP客户端会陷入忙等待状态无法再对外发送任何GET或者POST指令,从客户端使用者角度来看的效果就是网页一直在等待。

 

 

 

 

二、UDP上位机

UDP发送操作,同样需要先建立UDP Socket:

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
int UDP_Send_Found(socklen_t* socket_found , struct sockaddr_in *addr , char* ip , int port){    *socket_found = socket(AF_INET, SOCK_DGRAM, 0);
    if(*socket_found == (~0))    {        printf("Create udp send socket failed!\n");        return -1;    }
    addr->sin_family = AF_INET;    addr->sin_addr.s_addr = inet_addr(ip);    addr->sin_port = htons(port);    memset(addr->sin_zero, 0, 8);    return 0;}
左右滑动查看完整代码

而UDP文件发送则要比HTTP发送简单得多,只需要将文件切片,每一片为固定长度的UDP帧长度,逐帧发送即可:

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
while(fend > 0){memset(picture.data , 0 , sizeof(picture.data));fread(picture.data , UDP_FRAME_LEN , 1, fp);if(fend >= UDP_FRAME_LEN){picture.length = UDP_FRAME_LEN;picture.fin = 0;}else{picture.length = fend;picture.fin = 1;}
//printf("sendbytes = %d \n",sendbytes);
sendbytes = sendto(socket_send, (char *)&picture, sizeof(struct Package), 0, (struct sockaddr*)&addr,addr_len);
if(sendbytes == -1){printf("Send Picture Failed!d\n");return -1;}else{fend -= UDP_FRAME_LEN;}}
左右滑动查看完整代码

 

 

 

作者简介

 

donatello1996,某大型企业资深嵌入式工程师,电子发烧友论坛技术大牛,同时也是飞凌嵌入式多年铁粉,曾基于飞凌多款板卡产出过优质测评文章或使用心得。本期三篇文章为donatello1996在使用OKMX8MP-C开发板过程中精心产出的干货,在此对donatello1996表示感谢。

 

 

最近浏览过的用户(0查看全部

为你推荐

  • FET-G2LD-C核心板及开发板上手评测2022-05-27 11:05

    5月18日,飞凌嵌入式发布了基于瑞萨电子RZ/G2L处理器开发的FET-G2LD-C核心板和OK-G2LD-C开发板。RZ/G2L处理器有着丰富的外设接口,在具有较高的性能表现的同时还兼具低功耗的特点。由于这款处理器上市时间较短,还有很多的工程师朋友对它不够了解,存在很多疑问,为解答大家反馈较多的问题,今天小编专门针对FET-G2LD-C核心板和OK-G2L
    开发板 6浏览量
  • 未来已来 | 万物互联让农业更智慧2022-05-27 11:04

    今年一月,中央网信办、农业农村部等10个部门联合印发了《数字乡村发展行动计划(2022-2025年)》,将“智慧农业创新发展行动”列入重点任务。作为发展数字乡村建设的关键,智慧农业对于我国农业现代化建设和实施乡村振兴战略具有重大引领与推动作用。农业如何变得智慧?“智慧农业”是农业生产的高级阶段,是集新兴的互联网、移动互联网、云计算和物联网技术为一体,依托部署
    物联网 6浏览量
  • 重磅新品丨飞凌FET-G2LD-C工业级核心板发布!2022-05-26 10:31

    谈及瑞萨电子,相信大部分工程师对其印象是全球领先的微控制器、模拟功率器件和SoC供应商,技术实力雄厚。RZ/G2L是瑞萨电子在泛工业领域推出的一颗高性能、超高效处理器,亮点颇多,其采用Cortex-A55+Cortex-M33多核异构,功能接口资源丰富,多媒体性能出众,具有很强的泛用性和易用性。为了让更多工程师用户可以更好的了解这颗稳定易用的处理器,更便捷的
    核心板 5浏览量
  • 用智慧照亮生活—FET1046A-C核心板打造智慧灯杆方案2022-05-21 09:24

    智慧灯杆是集照明、视频监控、交通管理、环境监测、通信等多功能于一体的新型信息基础设施,是构建新型智慧城市的重要载体。5G的普及,为智慧灯杆发展创造了新机遇,作为新一代城市信息基础设施的智慧灯杆,与“新基建”中的不少领域相关,比如5G基站、新能源汽车充电桩和车联网等。智慧灯杆作为智慧城市的一个重要组成部分和重要入口,是智慧城市信息化建设天然的搭载平台。可以说在
    智慧灯杆 核心板 16浏览量
  • 干货分享 | Debian系统移植USBWiFi RTL8192EU驱动并设置开机自启2022-05-21 09:24

    作者:donatello1996来源:电子发烧友题图:飞凌嵌入式原文标题:【飞凌嵌入式OKMX8MP-C开发板试用体验】移植USBWIFIRTL8192EU驱动并设置开机自启动我(笔者)在飞凌OKMX8MP-C开发板上移植了自行搭建的Debian系统之后,发现板卡原有的WiFi模块无法使用,在内核里面添加了支持项也没用,后面跟飞凌的技术支持工程师王工沟通,了
    驱动器 19浏览量
  • 瑞萨RZ/G2L系列-飞凌嵌入式FET-G2LD-C核心板新品发布2022-05-18 16:37

    RZ/G2L是瑞萨电子在泛工业领域推出的一颗高性能、超高效处理器,亮点颇多,其采用Cortex-A55+Cortex-M33多核异构,功能接口资源丰富,多媒体性能出众,具有很强的泛用性和易用性。作为国内主流嵌入式ARM板卡供应商的飞凌嵌入式与瑞萨电子强势合作,正式推出搭载RZ/G2L处理器的FET-G2LD-C核
  • iMX6ULL动态评测-老将新甲 29*40mm的iMX6ULL 够小2022-05-05 11:58

    iMX6ULL核心板尺寸仅29*40mm,采用NXP iMX6ULL低功耗处理器设计,小尺寸,高性能应用领域更加广泛
    NXP arm 开发板 74浏览量
  • iMX6ULL功能介绍|框架图|功耗|核心板硬件设计说明|原理图2022-04-30 09:55

    NXPi.MX6ULL扩展了i.MX6系列,它是一个高性能、超高效、低成本处理器子系列,采用先进的ARMCortex-A7内核,运行速度高达800MHz。i.MX6ULL应用处理器包括一个集成的电源管理模块,降低了外接电源的复杂性,并简化了上电时序,目标应用有:汽车远程信息处理、IoT网关、人机界面、家庭能源管理系统、智能能源信息集中器、智能工业控制系统、电子POS设备、便携医疗设备、打印机和2D
    arm 开发板 58浏览量
  • 赋能安防监控智能化升级 | 由嵌入式板卡实现的NVR方案2022-04-29 09:53

    随着网络技术的不断发展,通过网络对视频数据进行存储的需求越来越多,这直接推动了DVR(硬盘录像机)发展为具有网络功能的NVR(网络视频录像机)。NVR是NetVideoRecorder的缩写,主要负责网络视音频信号的接入和存储、转发、解码、预览等功能。纵观视频监控系统的技术变革,从第一代的模拟监控到第二代的数字监控,再到现在盛行的网络监控,视频监控系统已成功
    嵌入式 26浏览量
  • 先睹为快! FETMX6ULL-C核心板开箱2022-04-21 11:25

    飞凌嵌入式于4月11日发布了一款新品FETMX6ULL-C核心板。作为飞凌基于NXPi.MX6U系处理器所开发的第三款核心板,它有什么独特优势?让我们通过视频一睹为快!钩沉新生匠心可见FETMX6ULL-C核心板基于NXPi.MX6ULL处理器设计开发,ARMCortex-A7架构,在保持低功耗的同时主频高达800MHz。FETMX6ULL-C核心板接口资源
    核心板 49浏览量
  • 基于A40i平台在RTK接收机上的应用-RTK接收机解决方案-飞凌嵌入式2021-10-28 10:33

    RTK接收机是一款通过无线通信设备接收单基站或者网络 RTK 播发的北斗/GNSS 载波相位实时动态差分数据,自主进行实时解算,提供高精度定位结果的终端设备。本文介绍了一款基于国产A40i设计RTK接收机的应用方案
    RTK 89浏览量
  • 激光喷码机-基于ARM+FPGA的控制系统设计方案-飞凌嵌入式2021-10-28 10:11

    激光喷码机-基于ARM+FPGA的控制系统设计方案。激光喷码机是通过高能量的激光直接聚焦到物体表面,使之发生物理化学变化而形成的,并随着激光束的焦点在打标物体表面上有规律地移动,同时控制激光的有无,就在物体表面形成了指定的打标图案。 激光打标具有非接触式标记,标记速度快,污染小,无耗材损失和标识清晰、永久等优点,具有强大的竞争能力,正在逐渐地取代传统的油墨喷码机
    63浏览量
  • 一种基于ARM核心板设计的无线示教器解决方案-飞凌嵌入式2021-10-28 10:04

    目前机器人示教器通过摇杆;按键;旋钮等方式对机器人的运动做出控制,结合示教器内部的系统软件,将数据发送至机器人控制系统,以此达到示教器的输入目的,当机器人运动时,其运动状态等信息需要展示给用户,则机器人系统将数据传输到示教器,示教器对机器人运动状态进行相关的显示,以此达到人际交互的目的。
    63浏览量
  • ARM核心板在3D打印机中的解决方案推荐-飞凌嵌入式2021-10-28 10:01

    3D打印机通常是采用数字技术材料打印机来实现的。常在模具制造、工业设计等领域被用于制造模型,后逐渐用于一些产品的直接制造,在珠宝、鞋类、工业设计、建筑、工程和施工(AEC)、汽车,航空航天、牙科和医疗产业、教育、地理信息系统、土木工程、枪支以及其他领域都有所应用。
    3D打印机 63浏览量
  • 环保数采仪|环保监测数采仪|生态环境监测数据采集器解决方案-飞凌嵌入式2021-10-27 17:27

    环保数采仪采用高性能ARM高端处理器,嵌入式Linux操作系统和嵌入式实时数据库。飞凌嵌入式推出ARM核心板广泛应用于环保数采仪|环保监测数采仪|生态环境监测数据采集器,为环保监测提供硬件解决方案
    81浏览量
  • ARM核心板应用于在线水质检测仪器解决方案2021-10-27 17:08

    ARM核心板应用于在线水质检测仪器解决方案。飞凌嵌入式ARM嵌入式核心板除了应用于在线水质监测,还可应用于大气有害气体监测、扬尘监测、废弃监测、噪声扬尘、气象等多种环境监测领域;面对多种不同的监测需求,飞凌嵌入式可根据客户需求进行定制开发
  • 特高压输电线路在线监测系统方案-A40i 核心板 应用解析-飞凌嵌入式2021-10-27 16:45

    本文中介绍的特高压输电线路在线监测系统,不仅能提高输电线路运行的可靠性,还能实现数据的融合共享,因此成为了输电线路中必不可少的一部分。基于特高压输电线在线监测系统的原理及系统组成,推荐飞凌嵌入式基于全志A40i设计的FETA40i-C核心板,首先是国产工业级的稳定性,再加上成本上的优势,让其在众多产品中脱颖而出
    34浏览量
  • 卡车高级驾驶辅助系统 (ADAS) 解决方案 -飞凌嵌入式2021-10-27 16:31

    卡车高级驾驶辅助系统 (ADAS) 解决方案,汽车ADAS指的是高级驾驶辅助系统,ADAS是Advanced Driver Assistance System的简称。该系统的核心在于“驾驶辅助”,可以为驾驶员提供更安全的驾驶体验。辅助驾驶系统,作为车车辆安全管理中的一个非常重要的内容。
  • 解决方案:核心板在自助加油机上的应用 - 飞凌嵌入式2021-10-27 15:51

    加油站的智能化解决方案。 加油站是多元的,应用场景也简单明了,给车加油。加油站的智能化方案中自助加油系统的广泛性和便利性,使得其应用越来越多地受到青睐。飞凌嵌入式为您提供智慧自助加油机显控终端主控板,智能加油机解决方案
    37浏览量
  • 车联网车载T-BOX系统解决方案_汽车TBOX 嵌入式arm应用-飞凌嵌入式2021-10-27 15:31

    车联网车载T-BOX系统解决方案_嵌入式arm在汽车TBOX 中的应用,飞凌嵌入式推出基于嵌入式arm技术的核心板在T-Box的解决方案中得到广泛应用,为用户缩短研发周期、提升产品整体竞争力提供有效的保证。
    454浏览量
  • RK3568核心板-飞凌嵌入式2022-03-16 18:23

    产品型号:RK3568 CPU:RK3568 架构:Cortex-A55 主频:2.0GHz 内存:2GB/4GB/8GB DDR4(标配2GB) ROM:16GB eMMC
  • RK3568开发板-飞凌嵌入式2022-03-16 18:17

    产品型号:RK3568 CPU:RK3568 架构:Cortex-A55 主频:2.0GHz 内存:2GB/4GB/8GB DDR4(标配2GB) ROM:16GB eMMC
  • iMX6ULL开发板-飞凌嵌入式2021-10-23 15:55

    产品型号:OKMX6ULL-S开发板 CPU:i.MX6ULL 架构:Cortex-A7 主频:800MHz 内存:256MB DDR3,512MB DDR3 存储:256MB NandFlash,4GB eMMC
  • iMX8M Plus 开发板-飞凌嵌入式2021-08-20 14:00

    产品型号:i.MX8MPlus CPU:i.MX8M Plus 架构:4*Cortex-A53+Cortex-M7 主频:1.6GHz 内存:4GB LPDDR4 ROM:16GB eMMC
  • 全志国产工业级A40i开发板-飞凌嵌入式2021-08-16 13:44

    产品型号:A40i CPU:A40i 架构:Cortex-A7 主频:1.2GHz 内存:1GB DDR3,2GB DDR3 ROM:8GB eMMC
  • 全志系列-T507开发板-飞凌嵌入式2021-08-16 12:03

    产品型号:T507 CPU:T507 架构:Cortex-A53 主频:1.5GHz 内存:2GB DDR3L ROM:8GB eMMC
  • iMX8MQ开发板-飞凌嵌入式2021-08-16 11:44

    产品型号:iMX8MQ CPU:iMX8MQ 架构:四核Cortex-A53+Cortex-M4 主频:1.3GHz 内存:2GB DDR4 ROM:8GB eMMC
  • LS1028A开发板-飞凌嵌入式2021-08-12 14:08

    产品型号:LS1028A CPU:LS1028A 架构:Cortex-A72 主频:1.5GHz 内存:2GB DDR4 ROM:8GB eMMC