【Ubuntu 上搭建 Nginx-RTMP 服务】
本章目录:
- 环境
- 1. 安装依赖
- 2. 创建 Nginx 编译目录
- 3. 下载 Nginx 和 Nginx-RTMP-Module
- 4. 编译 Nginx 并添加 RTMP 模块
- 5. 验证 Nginx 安装成功
- 6. 配置环境变量
- 7. 修改 Nginx 配置文件
- 8. 启动 Nginx 服务
- 查看 Nginx 是否启动成功
- 查看端口监听状态
- 8. 常见问题及解决方法
- 1. 缺少 `zlib` 库
- 2. 找不到 `openssl` 库
- 3. Nginx 端口冲突
- 9. 测试推流与播放
- 必要资源下载:
- 推流命令示例
- 服务端Ubuntu中推流:
- 客户端Windows中使用ffplay命令拉流:
- 播放效果如下:
- 10. 使用C++ 和FFmpeg库实现相同RTMP效果:
- 目录结构如下
- main.cpp源码如下,FFmpeg实现RTMP:
- cmake代码如下:
- 构建和执行步骤:
- 其它
- Nginx相关源码库的官网链接:
环境
- 服务端系统:Ubuntu
- 播放器:Windows 下使用
ffplay
命令
1. 安装依赖
在 Ubuntu 系统中,执行以下命令安装必要的依赖项:
sudo apt-get install build-essential libpcre3 libpcre3-dev libssl-dev
2. 创建 Nginx 编译目录
$ mkdir my_nginx_rtmp
$ cd my_nginx_rtmp/
$ pwd
/home/togevision/wzt/my_nginx_rtmp
3. 下载 Nginx 和 Nginx-RTMP-Module
wget http://nginx.org/download/nginx-1.21.6.tar.gz
wget https://github.com/arut/nginx-rtmp-module/archive/master.zip# 解压压缩包
tar -xf nginx-1.21.6.tar.gz
unzip master.zip
4. 编译 Nginx 并添加 RTMP 模块
进入解压后的 Nginx 源码目录,编译 Nginx,并添加 RTMP 模块:
cd nginx-1.21.6/
./configure --with-http_ssl_module --add-module=../nginx-rtmp-module-master
make -j4 && sudo make install
成功输出示例:
checking for C compiler ... found
...
creating objs/Makefile
Configuration summary+ using system PCRE library+ using system OpenSSL library+ RTMP module added
...
5. 验证 Nginx 安装成功
togevision@TG:~/wzt/my_nginx_rtmp$ /usr/local/nginx/sbin/nginx -v
nginx version: nginx/1.21.6
6. 配置环境变量
将 Nginx 添加到环境变量中:
sudo vi ~/.bashrc
在文件末尾添加:
export PATH=$PATH:/usr/local/nginx/sbin/
执行以下命令生效:
source ~/.bashrc
7. 修改 Nginx 配置文件
编辑 Nginx 配置文件:
sudo vim /usr/local/nginx/conf/nginx.conf
在文件末尾添加以下内容以启用 RTMP 模块:
rtmp {server {listen 1935;chunk_size 4096;application live {live on;record off;}}
}
8. 启动 Nginx 服务
nginx
启动后无提示,但可以通过以下命令确认状态
查看 Nginx 是否启动成功
ps -ef | grep nginx | grep -v grep
输出示例:
rog 1312637 2257 0 15:51 ? 00:00:00 nginx: master process nginx
rog 1314761 1312637 0 16:01 ? 00:00:06 nginx: worker process
查看端口监听状态
netstat -anp | grep nginx
输出示例:
tcp 0 0 0.0.0.0:1935 0.0.0.0:* LISTEN 1312637/nginx: mast
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 1312637/nginx: mast
- 端口 80:HTTP 服务默认监听端口
- 端口 1935:RTMP 服务默认监听端口
8. 常见问题及解决方法
1. 缺少 zlib
库
执行以下命令安装:
sudo apt-get install zlib1g-dev
输出示例:
Reading package lists... Done
...
2. 找不到 openssl
库
在 ~/.bashrc
文件中添加 OpenSSL 库位置:
export LD_LIBRARY_PATH=/home/rog/anaconda3/lib:$LD_LIBRARY_PATH
source ~/.bashrc
3. Nginx 端口冲突
如果出现以下错误:
nginx: [emerg] bind() to 0.0.0.0:80 failed (13: Permission denied)
修改 /usr/local/nginx/conf/nginx.conf
中的端口号为 1024 以上的端口,例如 8090
。
9. 测试推流与播放
必要资源下载:
测试视频下载
Linux下的x86版本 ffmpeg现成库下载
推流命令示例
服务端Ubuntu中推流:
ffmpeg -re -i ../res/video.mp4 -c copy -f flv rtmp://192.168.194.129:1935/live/1
客户端Windows中使用ffplay命令拉流:
ffplay.exe rtmp://192.168.194.129:1935/live/1
播放效果如下:
10. 使用C++ 和FFmpeg库实现相同RTMP效果:
目录结构如下
togevision@TG:~/wzt/av/rtmp_demo$ tree -L 2
.
├── build
│ ├── CMakeCache.txt
│ ├── CMakeFiles
│ ├── cmake_install.cmake
│ ├── Makefile
│ └── rtmp_demo
├── CMakeLists.txt
├── ffmpeg
│ ├── include
│ ├── lib
│ └── Makefile
├── ffmpeg_x86
│ ├── inc
│ └── lib
├── main.cpp
└── res└── video.mp49 directories, 8 files
main.cpp源码如下,FFmpeg实现RTMP:
#include <iostream>
#include <chrono>
#include <thread>
extern "C" {
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libavutil/time.h>
}// ffmpeg -re -i ../res/video.mp4 -c copy -f flv rtmp://192.168.194.129:1935/live/1int main() {const char *input_file = "../res/video.mp4";const char *output_url = "rtmp://192.168.194.129:1935/live/1";// 初始化网络组件avformat_network_init();AVFormatContext *input_ctx = nullptr;if (avformat_open_input(&input_ctx, input_file, nullptr, nullptr) < 0) {std::cerr << "Could not open input file." << std::endl;return -1;}if (avformat_find_stream_info(input_ctx, nullptr) < 0) {std::cerr << "Failed to retrieve input stream information." << std::endl;avformat_close_input(&input_ctx);return -1;}AVFormatContext *output_ctx = nullptr;if (avformat_alloc_output_context2(&output_ctx, nullptr, "flv", output_url) < 0) {std::cerr << "Could not create output context." << std::endl;avformat_close_input(&input_ctx);return -1;}for (unsigned int i = 0; i < input_ctx->nb_streams; i++) {AVStream *in_stream = input_ctx->streams[i];AVStream *out_stream = avformat_new_stream(output_ctx, nullptr);if (!out_stream) {std::cerr << "Failed to allocate output stream." << std::endl;avformat_close_input(&input_ctx);avformat_free_context(output_ctx);return -1;}if (avcodec_parameters_copy(out_stream->codecpar, in_stream->codecpar) < 0) {std::cerr << "Failed to copy codec parameters." << std::endl;avformat_close_input(&input_ctx);avformat_free_context(output_ctx);return -1;}out_stream->codecpar->codec_tag = 0;}if (!(output_ctx->oformat->flags & AVFMT_NOFILE)) {if (avio_open(&output_ctx->pb, output_url, AVIO_FLAG_WRITE) < 0) {std::cerr << "Could not open output URL." << std::endl;avformat_close_input(&input_ctx);avformat_free_context(output_ctx);return -1;}}if (avformat_write_header(output_ctx, nullptr) < 0) {std::cerr << "Error occurred when writing header to output." << std::endl;avformat_close_input(&input_ctx);if (!(output_ctx->oformat->flags & AVFMT_NOFILE))avio_closep(&output_ctx->pb);avformat_free_context(output_ctx);return -1;}int64_t start_time = av_gettime_relative();AVPacket pkt;while (true) {if (av_read_frame(input_ctx, &pkt) < 0)break;AVStream *in_stream = input_ctx->streams[pkt.stream_index];AVStream *out_stream = output_ctx->streams[pkt.stream_index];pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);pkt.pos = -1;// 计算每帧的发送时间int64_t pts_time = av_rescale_q(pkt.pts, out_stream->time_base, AVRational{1, AV_TIME_BASE});int64_t now_time = av_gettime_relative() - start_time;if (pts_time > now_time) {av_usleep(pts_time - now_time);}if (av_interleaved_write_frame(output_ctx, &pkt) < 0) {std::cerr << "Error writing frame." << std::endl;av_packet_unref(&pkt);break;}av_packet_unref(&pkt);}// 写入尾部信息if (av_write_trailer(output_ctx) < 0) {std::cerr << "Error occurred when writing trailer to output." << std::endl;}// 释放资源avformat_close_input(&input_ctx);if (!(output_ctx->oformat->flags & AVFMT_NOFILE))avio_closep(&output_ctx->pb);avformat_free_context(output_ctx);avformat_network_deinit();std::cout << "Streaming finished successfully!" << std::endl;return 0;
}
cmake代码如下:
cmake_minimum_required(VERSION 3.10)
project(FFmpegRTMPStreaming)# 设置C++标准
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)# SET(CMAKE_CXX_COMPILER "/home/togevision/toolchain/arm-AX620E-linux-uclibcgnueabihf/bin/arm-AX620E-linux-uclibcgnueabihf-g++")# 指定头文件和库文件的路径
include_directories(${CMAKE_SOURCE_DIR}/ffmpeg_x86/inc)
link_directories(${CMAKE_SOURCE_DIR}/ffmpeg_x86/lib)
# include_directories(${CMAKE_SOURCE_DIR}/ffmpeg/include)
# link_directories(${CMAKE_SOURCE_DIR}/ffmpeg/lib/arm/uclibc)# 添加可执行文件
add_executable(rtmp_demo main.cpp)# 链接FFmpeg库
target_link_libraries(rtmp_demo avformat avcodec avutil swresample)# 执行之前需要指定动态库路径:
# export LD_LIBRARY_PATH=/home/togevision/wzt/av/rtmp_demo/ffmpeg_x86/lib:$LD_LIBRARY_PATH
构建和执行步骤:
# 进入build目录,准备构建makefile
cd build/# 执行cmake
cmake ..# 执行make
make# 查看生成
ls# 指定动态库路径:
export LD_LIBRARY_PATH=/home/togevision/wzt/av/rtmp_demo/ffmpeg_x86/lib:$LD_LIBRARY_PATH# 执行生成的目标程序
./rtmp_demo # windows下使用ffplay或其它播放器播放rtmp
ffplay.exe rtmp://192.168.194.129:1935/live/1
其它
Nginx相关源码库的官网链接:
软件名称 | 下载链接 | 个人使用版本 | 描述 |
---|---|---|---|
Nginx | http://nginx.org/en/download.html | nginx-1.21.6.tar.gz | 一个高性能的HTTP和反向代理服务器。 |
Pcre | https://sourceforge.net/projects/pcre/files/pcre/8.45/ | pcre-8.45.tar.gz | 一个正则表达式库。(必须) |
Zlib | http://www.zlib.net/ | zlib-1.3.1.tar.gz | 一个开源的数据压缩库,提供了对数据的无损压缩和解压功能。(必须) |
Openssl | https://www.openssl.org/source/ | openssl-1.1.0l.tar.gz | 一个开源的加密库,提供了各种加密算法和安全协议的实现。(必须) |
相关文章:

【Ubuntu 上搭建 Nginx-RTMP 服务】
本章目录: 环境1. 安装依赖2. 创建 Nginx 编译目录3. 下载 Nginx 和 Nginx-RTMP-Module4. 编译 Nginx 并添加 RTMP 模块5. 验证 Nginx 安装成功6. 配置环境变量7. 修改 Nginx 配置文件8. 启动 Nginx 服务查看 Nginx 是否启动成功查看端口监听状态 8. 常见问题及解决方法1. 缺少…...

使用uniapp 微信小程序一些好用的插件分享
总结一下自己在开发中遇见的一问题,通过引入组件可以快速的解决 1.zxz-uni-data-select 下拉框选择器(添加下拉框检索,多选功能,多选搜索功能,自定义 下拉框插件,使用这个的原因是因为 uniui uview 组件库下拉框太…...

linux centos挂载未分配的磁盘空间
使用到的命令 lshw -class disk -short hostnamectl fdisk /dev/sdb partprobe /dev/sdb mount /dev/sdb2 /opt/fastdfs/ mkfs.ext4 /dev/sdb2 mount -t ext4 /dev/sdb2 /opt/fastdfs/...
C语言凯撒密码程序分享
把刚才编写的程序又加工了一下,变成了程序,发给大家 我用夸克网盘分享了「凯撒密码」,点击链接即可保存。打开「夸克APP」,无需下载在线播放视频,畅享原画5倍速,支持电视投屏。 链接:https://p…...

2025新年源码免费送
2025很开门很开门的源码免费传递。不需要馒头就能获取4套大开门源码。 听泉偷宝,又进来偷我源码啦👊👊👊。欢迎偷源码 🔥🔥🔥 获取免费源码以及更多源码,可以私信联系我 我们常常…...

阿里云ethereum
https://geth.ethereum.org/docs/getting-started/installing-geth#linux-and-mac git clone https://github.com/ethereum/go-ethereum.git git checkout v1.10.11 cd go-ethereum # 阿里云添加goproxy export GOPROXYhttps://mirrors.aliyun.com/goproxy/ make geth创建gene…...

子父组件传值
Angular 2 及以上版本中的父子组件通信方式 在 Angular 2 及以上版本中,父子组件通信主要通过以下几种方式实现: 一、使用Input()进行父向子通信 父组件通过属性绑定的方式将数据传递给子组件,子组件使用Input()装饰器来接收这些数据。 二…...

QT自定义工具条渐变背景颜色一例
使用样式定义: QWidget* toolbar new QWidget(this);toolbar->setObjectName("main_tool");toolbar->setStyleSheet("#main_tool{background: qlineargradient(x1:0 , y1:0 , x2:1 , y2:0,""stop:0 rgba(0,255,0, 0.2),"&q…...

2025最新Facebook广告投放常见问题:如何提高广告效果?
Facebook广告投放已成为众多品牌拓展市场、提升品牌知名度和促进销售增长的关键手段。然而经常有人提出遇到广告没人看、定位不准或者内容不吸引人这些问题。那怎么办呢?别急,下面咱们就来聊聊Facebook广告投放常见问题以及如何提高Facebook广告的效果。…...

双向导航和单向导航
目录 双向导航 单向导航 迁移数据库异常 解决办法 1.导航属性改为空 2.使用 ON DELETE NO ACTION 或 ON UPDATE NO ACTION 选择 双向导航 一对多:一个Article有多个Comment class Article {public long Id { get; set; }public string Title { get; set; }pu…...

Unity3d 基于Barracuda推理库和YOLO算法实现对象检测功能
前言 近年来,随着AI技术的发展,在游戏引擎中实现和运行机器学习模型的需求也逐渐显现。Unity3d引擎官方推出深度学习推理框架–Barracuda ,旨在帮助开发者在Unity3d中轻松地实现和运行机器学习模型,它的主要功能是支持在 Unity 中…...
Lambda离线实时分治架构深度解析与实战
一、引言 在大数据技术日新月异的今天,Lambda架构作为一种经典的数据处理模型,在应对大规模数据应用方面展现出了强大的能力。它整合了离线批处理和实时流处理,为需要同时处理批量和实时数据的应用场景提供了成熟的解决方案。本文将对Lambda…...

Spring Boot教程之五十一:Spring Boot – CrudRepository 示例
Spring Boot – CrudRepository 示例 Spring Boot 建立在 Spring 之上,包含 Spring 的所有功能。由于其快速的生产就绪环境,使开发人员能够直接专注于逻辑,而不必费力配置和设置,因此如今它正成为开发人员的最爱。Spring Boot 是…...

jenkins入门6 --拉取代码
Jenkins代码拉取 需要的插件,缺少的安装下 新建一个item,选择freestyle project 源码管理配置如下:需要添加git库地址,和登录git的用户密码 配置好后执行编译,成功后拉取的代码在工作空间里...
CAPL概述与环境搭建
CAPL概述与环境搭建 目录 CAPL概述与环境搭建1. CAPL简介与应用领域1.1 CAPL简介1.2 CAPL的应用领域 2. CANoe/CANalyzer 安装与配置2.1 CANoe/CANalyzer 简介2.2 安装CANoe/CANalyzer2.2.1 系统要求2.2.2 安装步骤 2.3 配置CANoe/CANalyzer2.3.1 配置CAN通道2.3.2 配置CAPL节点…...

Virgo:增强慢思考推理能力的多模态大语言模型
每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…...

偃动访无穿戴动作捕捉系统:赋能多行业开启动作捕捉新篇章
在当今科技飞速发展的时代,动作捕捉技术正以前所未有的态势深入到社会发展的各个领域,成为众多行业不可或缺的重要助力。从早期的惯性动捕与光捕技术,到如今更为先进的无标记动捕技术,动作捕捉领域不断迎来革新与突破。 无标记动…...
mikro-orm 和typeorm 对比
以下是Mikro-ORM和TypeORM的详细对比: 设计理念与架构 Mikro-ORM:基于数据映射器、工作单元和身份映射模式。这种设计使得它在管理内存中实体状态方面表现优异,能够自动处理事务,当调用em.flush()时,所有计算出的更改…...

Docker入门之docker基本命令
Docker入门之docker基本命令 官方网站:https://www.docker.com/ 1. 拉取官方镜像并创建容器(以redis为例) 拉取官方镜像 docker pull redis# 如果不需要添加到自定义网络使用这个命令,如需要,直接看第二步 docker r…...
mysql的一些函数及其用法
mysql 1-来自于leetcode1517的题目 表: Users------------------------ | Column Name | Type | ------------------------ | user_id | int | | name | varchar | | mail | varchar | ------------------------已知一个表,它的…...

大数据学习栈记——Neo4j的安装与使用
本文介绍图数据库Neofj的安装与使用,操作系统:Ubuntu24.04,Neofj版本:2025.04.0。 Apt安装 Neofj可以进行官网安装:Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...

shell脚本--常见案例
1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件: 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案
随着新能源汽车的快速普及,充电桩作为核心配套设施,其安全性与可靠性备受关注。然而,在高温、高负荷运行环境下,充电桩的散热问题与消防安全隐患日益凸显,成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...

云原生玩法三问:构建自定义开发环境
云原生玩法三问:构建自定义开发环境 引言 临时运维一个古董项目,无文档,无环境,无交接人,俗称三无。 运行设备的环境老,本地环境版本高,ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...

uniapp手机号一键登录保姆级教程(包含前端和后端)
目录 前置条件创建uniapp项目并关联uniClound云空间开启一键登录模块并开通一键登录服务编写云函数并上传部署获取手机号流程(第一种) 前端直接调用云函数获取手机号(第三种)后台调用云函数获取手机号 错误码常见问题 前置条件 手机安装有sim卡手机开启…...
小木的算法日记-多叉树的递归/层序遍历
🌲 从二叉树到森林:一文彻底搞懂多叉树遍历的艺术 🚀 引言 你好,未来的算法大神! 在数据结构的世界里,“树”无疑是最核心、最迷人的概念之一。我们中的大多数人都是从 二叉树 开始入门的,它…...

何谓AI编程【02】AI编程官网以优雅草星云智控为例建设实践-完善顶部-建立各项子页-调整排版-优雅草卓伊凡
何谓AI编程【02】AI编程官网以优雅草星云智控为例建设实践-完善顶部-建立各项子页-调整排版-优雅草卓伊凡 背景 我们以建设星云智控官网来做AI编程实践,很多人以为AI已经强大到不需要程序员了,其实不是,AI更加需要程序员,普通人…...
「Java基本语法」变量的使用
变量定义 变量是程序中存储数据的容器,用于保存可变的数据值。在Java中,变量必须先声明后使用,声明时需指定变量的数据类型和变量名。 语法 数据类型 变量名 [ 初始值]; 示例:声明与初始化 public class VariableDemo {publi…...
Netty自定义协议解析
目录 自定义协议设计 实现消息解码器 实现消息编码器 自定义消息对象 配置ChannelPipeline Netty提供了强大的编解码器抽象基类,这些基类能够帮助开发者快速实现自定义协议的解析。 自定义协议设计 在实现自定义协议解析之前,需要明确协议的具体格式。例如,一个简单的…...

Ray框架:分布式AI训练与调参实践
Ray框架:分布式AI训练与调参实践 系统化学习人工智能网站(收藏):https://www.captainbed.cn/flu 文章目录 Ray框架:分布式AI训练与调参实践摘要引言框架架构解析1. 核心组件设计2. 关键技术实现2.1 动态资源调度2.2 …...