91欧美超碰AV自拍|国产成年人性爱视频免费看|亚洲 日韩 欧美一厂二区入|人人看人人爽人人操aV|丝袜美腿视频一区二区在线看|人人操人人爽人人爱|婷婷五月天超碰|97色色欧美亚州A√|另类A√无码精品一级av|欧美特级日韩特级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

發(fā)燒友實(shí)測(cè) | i.MX8MP 基于HTTP網(wǎng)頁(yè)服務(wù)器和UDP上位機(jī)的MJPG碼流傳輸(mjpg-steamer)

飛凌嵌入式 ? 2022-01-10 16:30 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

作者|donatello1996

來(lái)源 | 電子發(fā)燒友

題圖|飛凌嵌入式

本文采用的硬件板卡為飛凌嵌入式OKMX8MP-C開發(fā)板,系統(tǒng)版本Linux5.4.70+Qt5.15.0,主要介紹基于HTTP網(wǎng)頁(yè)服務(wù)器和UDP上位機(jī)的MJPG碼流傳輸。

MJPG格式作為一種持續(xù)傳輸?shù)囊曨l碼流,在遠(yuǎn)程監(jiān)控領(lǐng)域中應(yīng)用較廣,而實(shí)現(xiàn)這種遠(yuǎn)程監(jiān)控的第三方應(yīng)用最常見(jiàn)的有兩種:瀏覽器HTTP網(wǎng)頁(yè)、UDP上位機(jī)。

7d22b602-6fd6-11ec-86cf-dac502259ad0.png

兩者各有優(yōu)勢(shì),對(duì)比鮮明,其中:

  • UDP上位機(jī):傳輸效率高,上位機(jī)編寫方便。

  • HTTP網(wǎng)頁(yè)方式:客戶端無(wú)需安裝上位機(jī),只需要一個(gè)瀏覽器應(yīng)用即可;客戶端訪問(wèn)服務(wù)器支持跨平臺(tái)支持,無(wú)論是電腦、平板、手機(jī),還是Linux系統(tǒng)、Windows系統(tǒng)及安卓系統(tǒng)都可以,只要有瀏覽器應(yīng)用都可訪問(wèn),而UDP上位機(jī)則受限于目標(biāo)平臺(tái),不易移植。

這兩種應(yīng)用各有優(yōu)缺點(diǎn),對(duì)于嵌入式開發(fā)者來(lái)說(shuō),兩者都必須掌握。

一、HTTP網(wǎng)頁(yè)服務(wù)器

先說(shuō)下HTTP網(wǎng)頁(yè)服務(wù)器獲取MJPG碼流的代碼,首先是OKMX8MP-C在開發(fā)板端建立TCP服務(wù)器:

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;}
左右滑動(dòng)查看完整代碼

其中setsockopt()函數(shù)是可選的,一般只用于規(guī)避socket()函數(shù)的建立錯(cuò)誤。

建立了TCP服務(wù)器后,返回的socklen_t型實(shí)參在后面的HTTP網(wǎng)頁(yè)服務(wù)器中需要用到。

HTTP網(wǎng)頁(yè)服務(wù)器所屬的TCP操作是需要另起輪詢線程來(lái)讓客戶端進(jìn)行accept()握手操作的,accept()之前的listen()倒是只需要執(zhí)行一次即可,accept()握手操作和recv()接收操作需要?jiǎng)?chuàng)建一個(gè)死循環(huán)線程:

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);}。。。}
左右滑動(dòng)查看完整代碼

MJPG幀可以使用Grab操作獲取,獲取到的MJPG幀需要在TCP線程中讀,在Grab操作線程中寫,這種被多個(gè)線程訪問(wèn)的資源需要加鎖防止讀寫沖突,即資源被Grab操作寫入時(shí),需要上鎖,不允許其它線程訪問(wèn),操作完成時(shí)需要解鎖,允許其它線程訪問(wèn):

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

左右滑動(dòng)查看完整代碼

線程互斥鎖使用之前需要初始化:

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);...    }...}
左右滑動(dòng)查看完整代碼

然后是發(fā)送的細(xì)節(jié),發(fā)送圖片文件之前,需要先發(fā)送HTTP標(biāo)準(zhǔn)頭,這個(gè)相當(dāng)于給發(fā)送圖片或者其它類型的流數(shù)據(jù)鋪路:

#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;    }
左右滑動(dòng)查看完整代碼

發(fā)送完HTTP標(biāo)準(zhǔn)頭之后,就需要發(fā)送內(nèi)容頭(Content-Type),這處的Content-Type為image/jpeg,同樣,HTTP標(biāo)準(zhǔn)協(xié)議里面image支持的類型遠(yuǎn)不止jpeg一種,發(fā)送完內(nèi)容頭之后就是正文和boundary結(jié)尾,這樣幀完整的HTTP頭發(fā)送到指定的TCP GET地址,就會(huì)在瀏覽器中顯示剛剛發(fā)送的圖片:

       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;
左右滑動(dòng)查看完整代碼

另外需要說(shuō)明的是,TCP服務(wù)器線程在發(fā)送MJPEG流的時(shí)候是死循環(huán)發(fā)送的,因此TCP客戶端在發(fā)送完GET指令之后,就會(huì)收到TCP服務(wù)器循環(huán)發(fā)送的圖像緩存,TCP客戶端會(huì)陷入忙等待狀態(tài)無(wú)法再對(duì)外發(fā)送任何GET或者POST指令,從客戶端使用者角度來(lái)看的效果就是網(wǎng)頁(yè)一直在等待。

7d4341f6-6fd6-11ec-86cf-dac502259ad0.jpg

7d72d344-6fd6-11ec-86cf-dac502259ad0.png

二、UDP上位機(jī)

UDP發(fā)送操作,同樣需要先建立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;}
左右滑動(dòng)查看完整代碼

而UDP文件發(fā)送則要比HTTP發(fā)送簡(jiǎn)單得多,只需要將文件切片,每一片為固定長(zhǎng)度的UDP幀長(zhǎng)度,逐幀發(fā)送即可:

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;}}
左右滑動(dòng)查看完整代碼

7dd5dec6-6fd6-11ec-86cf-dac502259ad0.jpg

作者簡(jiǎn)介

donatello1996,某大型企業(yè)資深嵌入式工程師,電子發(fā)燒友論壇技術(shù)大牛,同時(shí)也是飛凌嵌入式多年鐵粉,曾基于飛凌多款板卡產(chǎn)出過(guò)優(yōu)質(zhì)測(cè)評(píng)文章或使用心得。本期三篇文章為donatello1996在使用OKMX8MP-C開發(fā)板過(guò)程中精心產(chǎn)出的干貨,在此對(duì)donatello1996表示感謝。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 服務(wù)器
    +關(guān)注

    關(guān)注

    14

    文章

    10270

    瀏覽量

    91540
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    電子發(fā)燒友榮獲電子工業(yè)出版社博文視點(diǎn) “2025 年度卓越合作伙伴”

    推廣服務(wù),為推動(dòng)電子技術(shù)知識(shí)傳播所做出的突出貢獻(xiàn)。 電子發(fā)燒友作為國(guó)內(nèi)電子技術(shù)領(lǐng)域的專業(yè)媒體平臺(tái),自成立以來(lái),始終致力于為廣大電子技術(shù)愛(ài)好者、工程師等提供最新、最專業(yè)的電子科技資訊和深度技術(shù)內(nèi)容
    發(fā)表于 02-06 11:58

    ESP32開發(fā)板創(chuàng)建同步WebServer網(wǎng)頁(yè)服務(wù)器

    ESP32 內(nèi)置了 Wi-Fi 功能,能夠作為網(wǎng)頁(yè)服務(wù)器(Web Server)向網(wǎng)絡(luò)中的其他設(shè)備提供服務(wù)。通過(guò)在 ESP32 上運(yùn)行網(wǎng)頁(yè)服務(wù)器
    的頭像 發(fā)表于 01-30 11:36 ?232次閱讀
    ESP32開發(fā)板創(chuàng)建同步WebServer<b class='flag-5'>網(wǎng)頁(yè)</b><b class='flag-5'>服務(wù)器</b>

    電子發(fā)燒友積分如何兌換獎(jiǎng)勵(lì)?

    電子發(fā)燒友積分如何兌換獎(jiǎng)勵(lì)?
    發(fā)表于 11-19 09:34

    [投票評(píng)選]2025電子發(fā)燒友開發(fā)板測(cè)評(píng)大賽--最受歡迎開發(fā)板

    2025電子發(fā)燒友開發(fā)板測(cè)評(píng)大賽--最受歡迎開發(fā)板 大賽詳情: 電子發(fā)燒友攜手 16 家生態(tài)廠商發(fā)起開發(fā)板測(cè)評(píng)大賽,設(shè) OpenHarmony、RISC - V、Rockchip 三大賽道,共計(jì)
    發(fā)表于 10-13 16:25

    【上海晶珩睿莓1開發(fā)板試用體驗(yàn)】2、視頻監(jiān)控監(jiān)控系統(tǒng)

    感謝電子發(fā)燒友論壇 1、系統(tǒng)說(shuō)明 硬件準(zhǔn)備:睿莓板卡、網(wǎng)線、路由、攝像頭、用于遠(yuǎn)程看監(jiān)控的手機(jī) 系統(tǒng)功能:睿莓板卡驅(qū)動(dòng)攝像頭獲取監(jiān)控流媒體,手機(jī)遠(yuǎn)程查看監(jiān)控視頻 2、硬件連接 如下圖,攝像頭通過(guò)
    發(fā)表于 09-14 19:16

    電子發(fā)燒友工程師看!電子領(lǐng)域評(píng)職稱,技術(shù)之路更扎實(shí)

    論壇分享,沒(méi)評(píng)職稱前只能做基礎(chǔ)電路調(diào)試;評(píng)上 “中級(jí)電子工程師” 后,被納入公司傳感研發(fā)組,主導(dǎo)的低功耗電路設(shè)計(jì)方案,還被收錄到電子發(fā)燒友 “優(yōu)質(zhì)參考設(shè)計(jì)庫(kù)”,薪資漲幅達(dá) 35%,同時(shí)獲得了 TI
    發(fā)表于 08-20 13:53

    ESP32-運(yùn)行網(wǎng)頁(yè)服務(wù)器(Web Server)-實(shí)用篇

    在前一篇文章《ESP32-運(yùn)行網(wǎng)頁(yè)服務(wù)器(WebServer)-入門篇》,我們介紹了ESP32運(yùn)行網(wǎng)頁(yè)服務(wù)器(WebServer)的原理,然后我們基于ESP32實(shí)現(xiàn)了一個(gè)demo代碼;
    的頭像 發(fā)表于 07-28 18:05 ?3678次閱讀
    ESP32-運(yùn)行<b class='flag-5'>網(wǎng)頁(yè)</b><b class='flag-5'>服務(wù)器</b>(Web Server)-實(shí)用篇

    教你如何手搓一個(gè)樹莓派網(wǎng)絡(luò)服務(wù)器

    使用樹莓派的定義和好處網(wǎng)絡(luò)服務(wù)器是指利用HTTP及其他協(xié)議進(jìn)行數(shù)據(jù)傳輸,處理通過(guò)萬(wàn)維網(wǎng)提交的客戶端請(qǐng)求的軟硬件組合。網(wǎng)絡(luò)服務(wù)器的主要功能是存儲(chǔ)、處理并向客戶端(通常是
    的頭像 發(fā)表于 07-12 08:23 ?647次閱讀
    教你如何手搓一個(gè)樹莓派網(wǎng)絡(luò)<b class='flag-5'>服務(wù)器</b>!

    如何在米爾TI AM62開發(fā)板上部署流媒體服務(wù)實(shí)現(xiàn)監(jiān)控功能

    這塊開發(fā)板上部署流媒體服務(wù),通過(guò)USB攝像頭實(shí)現(xiàn)監(jiān)控功能。 一、軟件準(zhǔn)備 要在Linux上面部署流媒體服務(wù),mjpg-streamer是最合適的。 首先,在應(yīng)用開發(fā)環(huán)境中,進(jìn)行 mjpg
    發(fā)表于 07-03 18:32

    新進(jìn)發(fā)燒友

    今天注冊(cè)成為了電子發(fā)燒友,多學(xué)習(xí),多交流,多進(jìn)步
    發(fā)表于 06-10 10:59

    電子發(fā)燒友積分能換什么?

    電子發(fā)燒友積分能換什么?
    發(fā)表于 06-10 05:55

    i.MX8MP使用最新的BSP (6.6.52-2.2.0) 映像安裝TA失敗,為什么?

    我正在為 i.MX8MP 測(cè)試最新的 BSP image(),發(fā)現(xiàn)在嘗試安裝 TA 時(shí)會(huì)出現(xiàn)以下錯(cuò)誤 root@imx8mpevk:~# xtest --install-ta /usr/lib
    發(fā)表于 03-28 07:40

    將Deepseek移植到i.MX 8MP|93 EVK的步驟

    測(cè)試了不同模型對(duì)不同電路板的影響。需要注意的是,限制模型在電路板上運(yùn)行的最大障礙是內(nèi)存。包括 CPU 和內(nèi)存使用情況在內(nèi)的測(cè)試結(jié)果如下: a. i.MX8mp 深度搜索-r1-蒸餾
    發(fā)表于 03-26 06:08

    【幸狐Omni3576邊緣計(jì)算套件試用體驗(yàn)】資源傳輸與 Home Assistant 連接

    根據(jù)板端 ip 地址,瀏覽進(jìn)入網(wǎng)頁(yè) 192.168.31.108:8080 (注意根據(jù)打印出來(lái)的 HTTP 信息輸入正確的端口號(hào))即可獲取視頻流 Ctrl + C 即可退出正在運(yùn)行的程序。 效果
    發(fā)表于 03-18 16:47

    如何在IMX8MP上配置單通道內(nèi)存?

    我正在使用 i.MX 8M Plus 評(píng)估套件。測(cè)試 2 通道 LPDDR4 設(shè)備很好。但是,配置 1 個(gè)通道 LPDDR4 很困難,因?yàn)楦鶕?jù)原理圖,i.MX8MP 側(cè)的通道 A 連接到 LPDDR4 側(cè)的通道 B。如何在此交換
    發(fā)表于 03-17 07:00