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.mzph.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;特征工程仍然是提升模型性能的关键环节。本文将深入探讨特征工程的重要性、常用方法以及在实际…