Ubuntu 編譯SRS和ZLMediaKit用于視頻推拉流

SRS實現視頻的rtmp webrtc推流

ZLMediaKit編譯生成MediaServer實現rtsp推流

SRS指定某個固定網卡,修改程序后重新編譯

打開SRS-4.0.0/trunk/src/app/srs_app_rtc_server.cpp,在 232 行后面添加:

ZLMediaKit編譯后文件存放在ZLMediakit/release/linux/Debug/下,需要在執行文件目錄放一個auth.json文件,存放rtsp使用用戶名admin和密碼admin(MD5加密),文件內容:

{"auth": [{"passwd": "21232F297A57A5A743894A0E4A801FC3","username": "admin"}]
}

使用FFMPEG實現獲取攝像頭數據,壓縮,推流過程。

FFMPEG編譯帶webrtc功能:sudo ./configure --enable-libx264 --enable-gpl --enable-nvmpi --enable-shared --prefix=/usr/local/ffmpeg_webrtc

具體程序如下:

FFmpegEncode.h

#ifndef ffmpeg_encode_hpp
#define ffmpeg_encode_hpp#include <iostream>
#include <opencv2/opencv.hpp>
#include <boost/thread.hpp>
#include <boost/smart_ptr.hpp>
#include <boost/bind.hpp>
#include <vector>
#include <map>
#include <stdio.h>
#include <string>
#include <utility>extern "C" {
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>#include <libavutil/avassert.h>
#include <libavutil/channel_layout.h>
#include <libavutil/opt.h>
#include <libavutil/mathematics.h>
#include <libavutil/timestamp.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <libswresample/swresample.h>#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <libavutil/imgutils.h>
#include <libavutil/opt.h>
#include <libavutil/mathematics.h>
#include <libavutil/samplefmt.h>#include <libavutil/time.h>
#include <libavdevice/avdevice.h>
}#include <thread>class FFmpegEncode
{
public:FFmpegEncode();~FFmpegEncode();int open_output(std::string path, std::string type, bool isAudio);// 初始化編碼器int init_encoderCodec(std::string type, int32_t fps, uint32_t width, uint32_t height, int IFrame, int code_rate);std::string get_encode_extradata();std::shared_ptr<AVPacket> encode();int write_packet(std::shared_ptr<AVPacket> packet){return av_interleaved_write_frame(outputContext, packet.get());}int mat_to_frame(cv::Mat &mat);private:int initSwsFrame(AVFrame *pSwsFrame, int iWidth, int iHeight);AVFrame *pSwsVideoFrame;AVFormatContext *outputContext = nullptr;AVCodecContext *encodeContext = nullptr;int64_t packetCount = 0;int video_fps = 25;uint8_t *pSwpBuffer = nullptr;
};#endif /* ffmpeg_encode_hpp*/

FFmpegEncode.cpp

#include "ffmpeg_encode.h"FFmpegEncode::FFmpegEncode()
{av_register_all();avcodec_register_all();avformat_network_init();avdevice_register_all();av_log_set_level(AV_LOG_ERROR);     // 設置 log 為error級別pSwsVideoFrame = av_frame_alloc();
}FFmpegEncode::~FFmpegEncode()
{if(encodeContext != nullptr)avcodec_free_context(&encodeContext);if(outputContext != nullptr){av_write_trailer(outputContext);for(uint32_t i = 0; i < outputContext->nb_streams; i++){avcodec_close(outputContext->streams[i]->codec);}avformat_close_input(&outputContext);}av_frame_free(&pSwsVideoFrame);if(pSwpBuffer)av_free(pSwpBuffer);
}int FFmpegEncode::open_output(std::string path, std::string type, bool isAudio)
{int ret = avformat_alloc_output_context2(&outputContext, NULL, type.c_str(), path.c_str());std::cout<<"avformat_alloc_output_context2 ret : "<<ret<<std::endl;if (ret < 0){av_log(NULL, AV_LOG_ERROR, "open output context failed\n");return ret;}ret = avio_open(&outputContext->pb, path.c_str(), AVIO_FLAG_WRITE);std::cout<<"avio_open ret : "<<ret<<std::endl;if (isAudio){for (uint32_t i = 0; i < outputContext->nb_streams; i++) // 如果有音頻 和 視頻 nputContext->nb_streams則為2{if (outputContext->streams[i]->codec->codec_type == AVMediaType::AVMEDIA_TYPE_AUDIO)// 如果有stream 為音頻 則不處理{continue;}AVStream * stream = avformat_new_stream(outputContext, encodeContext->codec);ret = avcodec_copy_context(stream->codec, encodeContext);if (ret < 0){av_log(NULL, AV_LOG_ERROR, "copy coddec context failed");return ret;}}}else{AVStream * stream = avformat_new_stream(outputContext, encodeContext->codec);if (!stream){char buf[1024];//獲取錯誤信息av_strerror(ret, buf, sizeof(buf));std::cout << " failed! " << buf << std::endl;return -1;}ret = avcodec_copy_context(stream->codec, encodeContext);std::cout<<"avcodec_copy_context ret : "<<ret<<std::endl;if (ret < 0){char buf[1024];//獲取錯誤信息av_strerror(ret, buf, sizeof(buf));std::cout << " failed! " << buf << std::endl;return ret;}}av_dump_format(outputContext, 0, path.c_str(), 1);ret = avformat_write_header(outputContext, nullptr);if (ret < 0){av_log(NULL, AV_LOG_ERROR, "format write header failed");return ret;}av_log(NULL, AV_LOG_FATAL, " Open output file success: %s\n", path.c_str());return ret;
}int FFmpegEncode::init_encoderCodec(std::string type, int32_t fps, uint32_t width, uint32_t height, int IFrame, int code_rate)
{video_fps = fps;// 終端運行 // ffmpeg -hwaccels// ffmpeg -codecs | grep videotoolbox// ffprobe -codecs -hide_banner| grep h264std::string encoder_name = type + "_nvmpi";AVCodec *enCodec = avcodec_find_encoder_by_name(encoder_name.c_str());if(!enCodec)enCodec = avcodec_find_encoder_by_name("libx264");std::cout<< "使用編碼器: "<< enCodec->name<< std::endl;encodeContext = avcodec_alloc_context3(enCodec);encodeContext->codec_id = enCodec->id;encodeContext->time_base = (AVRational){1, video_fps};encodeContext->framerate = (AVRational){video_fps, 1};encodeContext->gop_size = IFrame;  //每50幀插入1個I幀encodeContext->max_b_frames = 0;   //兩個非B幀之間允許出現多少個B幀數,設置0表示不使用B幀,b 幀越多,圖片越小encodeContext->pix_fmt = AV_PIX_FMT_YUV420P;     //像素的格式,也就是說采用什么樣的色彩空間來表明一個像素點encodeContext->width = (width == 0) ? outputContext->streams[0]->codecpar->width : width;encodeContext->height = (height == 0) ? outputContext->streams[0]->codecpar->height : height;encodeContext->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;encodeContext->bit_rate = code_rate*1024;AVDictionary *param = NULL;av_dict_set(&param, "preset", "fast", 0);        // ultrafast, superfast, veryfast, faster, fast, medium, slow, slower, veryslow, placebo.av_dict_set(&param, "tune", "fastdecode", 0);    // film、animation、grain、stillimage、psnr、ssim、fastdecode、zerolatencyav_dict_set(&param, "profile", "baseline", 0);   //baseline, extended, main, highint ret = avcodec_open2(encodeContext, enCodec, &param);av_free(param);param = NULL;if (ret < 0){std::cout<< "open video codec failed"<< std::endl;return  ret;}initSwsFrame(pSwsVideoFrame, encodeContext->width, encodeContext->height);return 1;
}std::string FFmpegEncode::get_encode_extradata()
{std::string output = "";if(encodeContext->extradata_size > 0){output = "extradata_" + std::to_string(encodeContext->extradata_size);for(int i = 0; i< encodeContext->extradata_size; i++)output = output + "_" + std::to_string(int(encodeContext->extradata[i]));}return output;
}std::shared_ptr<AVPacket> FFmpegEncode::encode()
{int gotOutput = 0;std::shared_ptr<AVPacket> pkt(static_cast<AVPacket*>(av_malloc(sizeof(AVPacket))), [&](AVPacket *p) { av_packet_free(&p); av_freep(&p); });av_init_packet(pkt.get());pkt->data = NULL;pkt->size = 0;int ret = avcodec_encode_video2(encodeContext, pkt.get(), pSwsVideoFrame, &gotOutput);if (ret >= 0 && gotOutput){int64_t pts_time = av_rescale_q(packetCount++, (AVRational){1, video_fps}, outputContext->streams[0]->time_base);pkt->pts = pkt->dts = pts_time;return pkt;}return nullptr;
}int FFmpegEncode::mat_to_frame(cv::Mat &mat)
{int width = mat.cols;int height = mat.rows;int cvLinesizes[1];cvLinesizes[0] = (int)mat.step1();if (pSwsVideoFrame == NULL){pSwsVideoFrame = av_frame_alloc();av_image_alloc(pSwsVideoFrame->data, pSwsVideoFrame->linesize, width, height, AVPixelFormat::AV_PIX_FMT_YUV420P, 1);}SwsContext* conversion = sws_getContext(width, height, AVPixelFormat::AV_PIX_FMT_BGR24, width, height, (AVPixelFormat)pSwsVideoFrame->format, SWS_FAST_BILINEAR, NULL, NULL, NULL);sws_scale(conversion, &mat.data, cvLinesizes , 0, height, pSwsVideoFrame->data, pSwsVideoFrame->linesize);sws_freeContext(conversion);return  0;
}int FFmpegEncode::initSwsFrame(AVFrame *pSwsFrame, int iWidth, int iHeight)
{// 計算一幀的大小int numBytes = av_image_get_buffer_size(encodeContext->pix_fmt, iWidth, iHeight, 1);if(pSwpBuffer)av_free(pSwpBuffer);pSwpBuffer = (uint8_t *)av_malloc(numBytes * sizeof(uint8_t));// 將數據存入 uint8_t 中av_image_fill_arrays(pSwsFrame->data, pSwsFrame->linesize, pSwpBuffer, encodeContext->pix_fmt, iWidth, iHeight, 1);pSwsFrame->width = iWidth;pSwsFrame->height = iHeight;pSwsFrame->format = encodeContext->pix_fmt;return 1;
}

main.cpp

//ZLMediaKit用于播放rtsp,SRS/nginx用于播放rtmp/webrtc
#include <iostream>
#include <opencv2/opencv.hpp>
#include <boost/thread.hpp>
#include <boost/smart_ptr.hpp>
#include <boost/bind.hpp>
#include <vector>
#include <map>
#include <stdio.h>
#include <string>
#include <utility>#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/thread.hpp>
#include "ffmpeg_encode.hpp"using namespace std;uint32_t rgb_fps = 20;                      // 可見光視頻幀率int main(int argc, char* argv[])
{std::cout << "start" << std::endl;std::string pipeline = "rtsp://admin:123456@192.168.1.235/h264/ch1/main/av_stream";std::string rgb_rtmp_path = "rtmp://127.0.0.1:1935/hls/test_rgb";std::string rgb_rtsp_path = "rtsp://127.0.0.1:8556/hls/test_rgb";std::string rgb_webrtc_path = "webrtc://127.0.0.1:1985/hls/test_rgb";std::string rgb_path;std::string rgb_type;if(argc != 2) {cout<<"1-rtmp 2-rtsp 3-webrtc"<<endl;} else {if (strcmp(argv[1], "1") == 0) {rgb_path = rgb_rtmp_path;rgb_type = "flv";} else if (strcmp(argv[1], "2") == 0) {rgb_path = rgb_rtsp_path;rgb_type = "rtsp";} else if (strcmp(argv[1], "3") == 0) {rgb_path = rgb_webrtc_path;rgb_type = "webrtc";}}cv::VideoCapture capture(pipeline);if (! capture.isOpened()){std::cout<< "RGB攝像頭打開失敗"<< std::endl;return -1;}FFmpegEncode camera_io;// 初始化編碼器if(camera_io.init_encoderCodec("h264", rgb_fps, 1280, 720, 50, 4096) < 0)return -3;std::string rgb_extradata = camera_io.get_encode_extradata() + "_" + "h264";rgb_extradata = rgb_extradata + "&&" + std::to_string(rgb_fps) + "_1280_720";std::cout<<"rgb_extradata = "<<rgb_extradata<<std::endl;cout<<"rgb_path: "<<rgb_path<<" rgb_type: "<<rgb_type<<endl;if(camera_io.open_output(rgb_path, rgb_type, false) < 0)return -4;int64_t fps_start_time = av_gettime();uint64_t fps_count = 0;int64_t get_frame_time = 0;// 獲取可見光視頻while(capture.isOpened()){cv::Mat rgb_mat;capture >> rgb_mat;get_frame_time = av_gettime();if(rgb_mat.empty()){boost::this_thread::sleep(boost::posix_time::microseconds(5));continue;}// 輸出可見光視頻幀率if(get_frame_time - fps_start_time < 1 * 1000 * 1000){fps_count++;}else{std::cout<< "rgb fps: "<< fps_count + 1 << std::endl;fps_count = 0;fps_start_time = get_frame_time;}// Mat轉frameif(camera_io.mat_to_frame(rgb_mat) < 0)continue;// 編碼auto packet_encode = camera_io.encode();if(packet_encode){camera_io.write_packet(packet_encode);av_free_packet(packet_encode.get());}}std::cout<< "RGB攝像頭編解碼程序退出"<< std::endl;return 0;
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/83292.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/83292.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/83292.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

如何備考GRE?

1.引言 GRE和雅思不太相同&#xff0c;首先GRE是美國人的考試&#xff0c;思維方式和很多細節和英系雅思不一樣。所以底層邏輯上我覺得有點區別。 難度方面&#xff0c;我感覺GRE不容易考低分&#xff0c;但考高分較難。雅思就不一樣了不僅上限難突破&#xff0c;下限還容易6…

uniapp|商品列表加入購物車實現拋物線動畫效果、上下左右拋入、多端兼容(H5、APP、微信小程序)

以uniapp框架為基礎,詳細解析商品列表加入購物車拋物線動畫的實現方案。通過動態獲取商品點擊位置與購物車坐標,結合CSS過渡動畫模擬拋物線軌跡,實現從商品圖到購物車圖標的動態效果。 目錄 核心實現原理坐標動態計算拋物線軌跡模擬?動畫元素控制代碼實現詳解模板層設計腳本…

React中使用openLayer畫地圖

OpenLayers&#xff08;簡稱ol&#xff09;是一個?開源的WebGIS前端開發庫?&#xff0c;基于JavaScript實現&#xff0c;主要用于在網頁中嵌入動態二維地圖。 官方網站&#xff1a; https://openlayers.org 中文官網&#xff1a; https://openlayers.vip 大家可以去參考學習…

WHAT - 緩存命中 Cache Hit 和緩存未命中 Cache Miss

文章目錄 一、什么是緩存命中&#xff1f;二、前端開發要知道哪些緩存機制&#xff08;以及命中條件&#xff09;&#xff1f;1. 瀏覽器緩存&#xff08;主要針對靜態資源&#xff09;常見的緩存位置關鍵 HTTP 頭字段&#xff08;決定命中與否&#xff09; 2. 前端應用層緩存&a…

10 個可靠的 Android 文件傳輸應用程序

Android 文件傳輸是 Android 用戶的常見需求。我們經常需要將文件從一臺 Android 設備傳輸到 PC 或 Mac。但我們怎樣才能做到這一點呢&#xff1f;俗話說&#xff0c;工欲善其事&#xff0c;必先利其器。因此&#xff0c;首先了解 10 個鋒利的 Android 文件傳輸應用程序&#x…

AlphaEvolve:LLM驅動的算法進化革命與科學發現新范式

AlphaEvolve&#xff1a;LLM驅動的算法進化革命與科學發現新范式 本文聚焦Google DeepMind最新發布的AlphaEvolve&#xff0c;探討其如何通過LLM與進化算法的結合&#xff0c;在數學難題突破、計算基礎設施優化等領域實現革命性進展。從48次乘法優化44矩陣相乘到數據中心資源利…

Java大師成長計劃之第24天:Spring生態與微服務架構之分布式配置與API網關

&#x1f4e2; 友情提示&#xff1a; 本文由銀河易創AI&#xff08;https://ai.eaigx.com&#xff09;平臺gpt-4-turbo模型輔助創作完成&#xff0c;旨在提供靈感參考與技術分享&#xff0c;文中關鍵數據、代碼與結論建議通過官方渠道驗證。 在微服務架構中&#xff0c;如何管理…

eSwitch manager 簡介

eSwitch manager 的定義和作用 eSwitch manager 通常指的是能夠配置和管理 eSwitch&#xff08;嵌入式交換機&#xff09;的實體或接口。在 NVIDIA/Mellanox 的網絡架構中&#xff0c;Physical Function&#xff08;PF&#xff09;在 switchdev 模式下充當 eSwitch manager&am…

最新開源 TEN VAD 與 Turn Detection 讓 Voice Agent 對話更擬人 | 社區來稿

關鍵詞&#xff1a;對話式 AI | 語音智能體 | Voice Agent | VAD | 輪次檢測 | 聲網 | TEN GPT-4o 所展示對話式 AI 的新高度&#xff0c;正一步步把我們在電影《Her》中看到的 AI 語音體驗變成現實。AI 的語音交互正在變得更豐富、更流暢、更易用&#xff0c;成為構建多模態智…

AI實踐用例---日程規劃(通用日程管理文件ICS)靈感踩坑日常

我是一位踐行獨立開發者之路的菜鳥開發者。 由于執行力較差,常常有很多想法但是很多時候沒有去踐行。 所以我有了讓大模型為我生成日程安排的想法,這確實可以,很簡單。只需要將你的想法告訴ai就行了。 例如: 發給AI的提示詞: 我想你幫我對,嗯,未來的一年做一個嗯,大…

大疆無人機??DRC 鏈路

在大疆上云API中&#xff0c;??DRC 鏈路??通常指 ??Device-Cloud Remote Control Link&#xff08;設備-云端遠程控制鏈路&#xff09;??&#xff0c;它是無人機&#xff08;或設備&#xff09;與云端服務之間建立的??實時控制與數據傳輸通道??&#xff0c;用于實現…

tomcat一閃而過,按任意鍵繼續以及控制臺中文亂碼問題

問題描述 今天在打開tomcat,啟動startup.bat程序時 tomcat直接閃退,后面查找資料后發現,可以通過編輯startup.bat文件內容,在最后一行加入pause即可讓程序不會因為異常而終止退出 這樣方便查看tomcat所爆出的錯誤: 然后,我明確看到我的tomcat啟動程序顯示如下的內容,沒有明確…

中大型水閘安全監測系統解決方案

一、方案概述 中大型水閘作為水利工程的重要組成部分&#xff0c;承擔著調節水位、控制水流、防洪排澇等多重功能&#xff0c;在防洪減災、水資源配置、生態環境改善等方面發揮著巨大作用。然而&#xff0c;由于歷史原因&#xff0c;許多水閘存在建設標準偏低、質量較差、配套設…

軌跡誤差評估完整流程總結(使用 evo 工具)

roslaunch .launch rosbag play your_dataset.bag -r 2.0 ? 第二步&#xff1a;錄制估計軌跡 bash 復制編輯 rosbag record -O traj_only.bag /aft_mapped_to_init 運行一段時間后 CtrlC 停止&#xff0c;生成 traj_only.bag 第三步&#xff1a;提取估計軌跡和真值軌跡為…

Linux任務管理與守護進程

目錄 任務管理 jobs&#xff0c;fg&#xff0c;bg 進程組概念 任務概念 守護進程 守護進程的概念 守護進程的查看 守護進程的創建 ?編輯模擬實現daemon函數 任務管理 每當有一個用戶登錄Linux時&#xff0c;系統就會創建一個會話&#xff08;session&#xff09; 任何…

Json rpc 2.0比起傳統Json在通信中的優勢

JSON-RPC 2.0 相較于直接使用傳統 JSON 進行通信&#xff0c;在協議規范性、開發效率、通信性能等方面具有顯著優勢。以下是核心差異點及技術價值分析&#xff1a; 一、結構化通信協議&#xff0c;降低開發成本 傳統 JSON 通信需要開發者自定義數據結構和處理邏輯&#xff0c;…

機器學習與人工智能:NLP分詞與文本相似度分析

DIY AI & ML NLP — Tokenization & Text Similarity by Jacob Ingle in Data Science Collective 本文所使用的數據是在 Creative Commons license 下提供的。盡管我們已盡力確保信息的準確性和完整性&#xff0c;但我們不對數據的完整性或可靠性做任何保證。數據的使…

RK3568平臺OpenHarmony系統移植可行性評估

https://docs.openharmony.cn/pages/v5.0/zh-cn/device-dev/quick-start/quickstart-appendix-compiledform.md 官方給的標準系統就是RK3568, 所以肯定可以, 關于硬件加速部分 看了鴻蒙RK3568開發板的GPU編譯配置,只能說能用 https://docs.openharmony.cn/pages/v4.1/zh-cn/…

論文淺嘗 | HOLMES:面向大語言模型多跳問答的超關系知識圖譜方法(ACL2024)

筆記整理&#xff1a;李曉彤&#xff0c;浙江大學碩士&#xff0c;研究方向為大語言模型 論文鏈接&#xff1a;https://arxiv.org/pdf/2406.06027 發表會議&#xff1a;ACL 2024 1. 動機 多跳問答&#xff08;Multi-Hop Question Answering, MHQA&#xff09;技術近年來在自然語…

機器學習中的特征工程:解鎖模型性能的關鍵

在機器學習領域&#xff0c;模型的性能往往取決于數據的質量和特征的有效性。盡管深度學習模型在某些任務中能夠自動提取特征&#xff0c;但在大多數傳統機器學習任務中&#xff0c;特征工程仍然是提升模型性能的關鍵環節。本文將深入探討特征工程的重要性、常用方法以及在實際…