午夜视频在线网站,日韩视频精品在线,中文字幕精品一区二区三区在线,在线播放精品,1024你懂我懂的旧版人,欧美日韩一级黄色片,一区二区三区在线观看视频

分享

用Rust通過(guò)網(wǎng)絡(luò)攝像頭構(gòu)建實(shí)時(shí)流媒體服務(wù)器

 風(fēng)聲之家 2023-10-05 發(fā)布于江蘇

原創(chuàng) 李明 coding到燈火闌珊 2023-10-02 06:01 發(fā)表于北京

收錄于合集

#Rust253
#網(wǎng)絡(luò)攝像頭1
#流媒體服務(wù)器1

在當(dāng)今快速發(fā)展的技術(shù)環(huán)境中,實(shí)時(shí)多媒體流已經(jīng)成為數(shù)字體驗(yàn)中不可或缺的一部分。無(wú)論是視頻會(huì)議、直播還是遠(yuǎn)程監(jiān)控,實(shí)時(shí)捕獲和傳輸視頻幀的能力都是一項(xiàng)強(qiáng)大的功能。

在本文中,我們將探索如何使用Rust和OpenCV crate通過(guò)實(shí)時(shí)網(wǎng)絡(luò)攝像頭構(gòu)建一個(gè)簡(jiǎn)單的流媒體服務(wù)器。

我們的目標(biāo)是創(chuàng)建一個(gè)服務(wù)器,從網(wǎng)絡(luò)攝像頭捕獲幀,并通過(guò)HTTP實(shí)時(shí)傳輸?shù)竭B接的客戶(hù)端。我們將利用OpenCV crate進(jìn)行網(wǎng)絡(luò)攝像頭交互和圖像處理。


創(chuàng)建項(xiàng)目

安裝OpenCV
brew install opencv
新建一個(gè)Rust項(xiàng)目:
cargo new rust-opencv
在Cargo.toml文件中加入依賴(lài)項(xiàng):
[dependencies]
opencv = "0.84.5"
如果出現(xiàn)找不到libclang.dylib的錯(cuò)誤,參考下面的解決方法:
mdfind -name libclang.dylib

sudo ln -s /usr/local/Cellar/llvm/16.0.6/lib/libclang.dylib /usr/local/lib

下面讓我們一步一步地分解實(shí)現(xiàn):

1,導(dǎo)入依賴(lài)項(xiàng)

在src/main.rs文件中,寫(xiě)入以下代碼:
use opencv::{
    core::{Mat, Vector}, imgcodecs, prelude::*, videoio,
};

use std::net::TcpListener;
use std::io::Write;

首先從OpenCV crate和標(biāo)準(zhǔn)Rust crate中導(dǎo)入必要的依賴(lài)項(xiàng),OpenCV crate用于圖像和視頻處理。

2,綁定TCP監(jiān)聽(tīng)器

代碼使用TcpListener::bind函數(shù)將TCP偵聽(tīng)器綁定到IP地址“127.0.0.1”和端口“8080”上。這將設(shè)置服務(wù)器偵聽(tīng)該IP和端口上的接入的客戶(hù)端連接。
fn main() {
    let listener = TcpListener::bind("127.0.0.1:8080").unwrap();
    println!("服務(wù)器在端口8080上監(jiān)聽(tīng) ... ");
}

3,初始化攝像頭

初始化一個(gè)視頻捕獲對(duì)象(cam)來(lái)從默認(rèn)的webcam(設(shè)備索引0)捕獲幀,并設(shè)置主循環(huán)。
fn main() {
    ......

    let mut cam = videoio::VideoCapture::new(0, videoio::CAP_ANY).expect("視頻捕獲失敗");
    let mut frame = Mat::default();
    let mut buf = Vector::new();
    loop{
        // ... 
    }
}

4,接受客戶(hù)端連接

在循環(huán)中,服務(wù)器使用listener.accept()函數(shù)等待客戶(hù)端連接。一旦建立連接,它將返回一個(gè)TCP流(stream),該流將用于與客戶(hù)端通信。
fn main() {
    ......

    loop{
        let (mut stream, _) = listener.accept().expect("無(wú)法接受連接");
    }
}

上面的代碼進(jìn)入一個(gè)主循環(huán),在這個(gè)主循環(huán)中,它不斷地監(jiān)聽(tīng)傳入的客戶(hù)端連接,并為它們提供實(shí)時(shí)視頻幀。

5,捕獲和編碼幀

建立連接后,使用cam.read(&mut frame)函數(shù)從網(wǎng)絡(luò)攝像頭讀取視頻幀,然后使用imgcodecs::imencode函數(shù)將捕獲的幀編碼為JPEG圖像。編碼后的圖像數(shù)據(jù)存儲(chǔ)在buf向量中。
fn main() {
    .....

    loop{
        let (mut stream, _) = listener.accept().expect("Failed to accept connection");

        cam.read(&mut frame).expect("捕獲幀失敗");
        buf.clear();
        let _ = imgcodecs::imencode(".jpg", &frame, &mut buf, &Vector::new());
    }
}

6,創(chuàng)建響應(yīng)頭

該代碼創(chuàng)建了一個(gè)內(nèi)容類(lèi)型為“multipart/x-mix -replace”的HTTP響應(yīng)頭,并指定了一個(gè)名為“frame”的邊界。這個(gè)響應(yīng)頭表示多個(gè)圖像幀將依次發(fā)送,這將使客戶(hù)端實(shí)時(shí)接收和顯示幀,而無(wú)需為每個(gè)新幀關(guān)閉和重新打開(kāi)連接。
fn main() {
    ......

    loop{
        ......

        let response = format!(
            "HTTP/1.1 200 OK\r\nContent-Type: multipart/x-mixed-replace; boundary=frame\r\n\r\n"
        );

        stream.write_all(response.as_bytes()).unwrap();
    }
}

使用stream.write_all函數(shù)響應(yīng)頭被寫(xiě)入客戶(hù)端的流,這通知客戶(hù)端,服務(wù)器已準(zhǔn)備好發(fā)送圖像幀。

7,內(nèi)部循環(huán):發(fā)送視頻幀

在嵌套循環(huán)中,服務(wù)器連續(xù)捕獲幀,對(duì)它們進(jìn)行編碼,并以連續(xù)流的形式將它們發(fā)送給客戶(hù)端。這個(gè)循環(huán)確保新幀一旦可用就被捕獲并發(fā)送。
fn main() {
    ......

    loop{
        ......

        loop {
            cam.read(&mut frame).expect("捕獲幀失敗");
            buf.clear();
            let _ = imgcodecs::imencode(".jpg", &frame, &mut buf, &Vector::new());

            let image_data = format!(
                "--frame\r\nContent-Type: image/jpeg\r\nContent-Length: {}\r\n\r\n",
                buf.len()
            );

            stream.write_all(image_data.as_bytes()).unwrap();
            stream.write_all(buf.as_slice()).unwrap();
            stream.write_all(b"\r\n").unwrap();
            stream.flush().unwrap();
        }
    }
}

在內(nèi)部循環(huán)中,服務(wù)器再次捕獲幀,對(duì)其進(jìn)行編碼,并將編碼后的數(shù)據(jù)存儲(chǔ)在buf向量中。然后,它為圖像構(gòu)造一個(gè)具有適當(dāng)內(nèi)容類(lèi)型和內(nèi)容長(zhǎng)度的HTTP響應(yīng)。使用stream.write_all函數(shù)將圖像數(shù)據(jù)發(fā)送到客戶(hù)端。

發(fā)送圖像數(shù)據(jù)后,服務(wù)器使用stream.flush()刷新流,以確保數(shù)據(jù)立即發(fā)送到客戶(hù)端。

完整代碼:
use opencv::{
    core::{Mat, Vector}, imgcodecs, prelude::*, videoio,
};

use std::net::TcpListener;
use std::io::Write;

fn main() {
    let listener = TcpListener::bind("127.0.0.1:8080").unwrap();
    println!("服務(wù)器在端口8080上監(jiān)聽(tīng) ... ");

    let mut cam = videoio::VideoCapture::new(0, videoio::CAP_ANY).expect("視頻捕獲失敗");
    let mut frame = Mat::default();
    let mut buf = Vector::new();

    loop{
        let (mut stream, _) = listener.accept().expect("無(wú)法接受連接");

        cam.read(&mut frame).expect("捕獲幀失敗");
        buf.clear();
        let _ = imgcodecs::imencode(".jpg", &frame, &mut buf, &Vector::new());

        let response = format!(
            "HTTP/1.1 200 OK\r\nContent-Type: multipart/x-mixed-replace; boundary=frame\r\n\r\n"
        );

        stream.write_all(response.as_bytes()).unwrap();

        loop {
            cam.read(&mut frame).expect("捕獲幀失敗");
            buf.clear();
            let _ = imgcodecs::imencode(".jpg", &frame, &mut buf, &Vector::new());

            let image_data = format!(
                "--frame\r\nContent-Type: image/jpeg\r\nContent-Length: {}\r\n\r\n",
                buf.len()
            );

            stream.write_all(image_data.as_bytes()).unwrap();
            stream.write_all(buf.as_slice()).unwrap();
            stream.write_all(b"\r\n").unwrap();
            stream.flush().unwrap();
        }
    }
}

運(yùn)行

輸入“cargo run”命令運(yùn)行程序,然后打開(kāi)瀏覽器,輸入IP地址127.0.0.1:8080開(kāi)始接收視頻數(shù)據(jù)。


總結(jié)

恭喜你!你已經(jīng)成功地使用Rust和OpenCV crate構(gòu)建了一個(gè)實(shí)時(shí)網(wǎng)絡(luò)攝像頭流媒體服務(wù)器。你可以通過(guò)添加身份驗(yàn)證、多攝像頭支持和客戶(hù)端等功能或?qū)⑵渑cweb界面集成來(lái)進(jìn)一步增強(qiáng)該服務(wù)器的功能。

實(shí)時(shí)流只是Rust和OpenCV支持的眾多令人興奮的功能之一。通過(guò)掌握這些工具,你可以探索廣泛的多媒體應(yīng)用,從計(jì)算機(jī)視覺(jué)到視頻處理等等。



coding到燈火闌珊

專(zhuān)注于技術(shù)分享,包括Rust、Golang、分布式架構(gòu)、云原生等。

180篇原創(chuàng)內(nèi)容

公眾號(hào)

收錄于合集 #Rust

 253

上一篇Rust中的設(shè)計(jì)模式:構(gòu)建者模式(Builder)下一篇Rust代碼安全:混淆的魔力

閱讀 1124

coding到燈火闌珊

關(guān)注 

分享收藏312

喜歡此內(nèi)容的人還喜歡

coding到燈火闌珊 

不喜歡

確定

閱讀9萬(wàn)+

黃梅文哲 

不喜歡

確定

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多