本章目录:
-
- 环境
- [1. 安装依赖](#1. 安装依赖)
- [2. 创建 Nginx 编译目录](#2. 创建 Nginx 编译目录)
- [3. 下载 Nginx 和 Nginx-RTMP-Module](#3. 下载 Nginx 和 Nginx-RTMP-Module)
- [4. 编译 Nginx 并添加 RTMP 模块](#4. 编译 Nginx 并添加 RTMP 模块)
- [5. 验证 Nginx 安装成功](#5. 验证 Nginx 安装成功)
- [6. 配置环境变量](#6. 配置环境变量)
- [7. 修改 Nginx 配置文件](#7. 修改 Nginx 配置文件)
- [8. 启动 Nginx 服务](#8. 启动 Nginx 服务)
-
- [查看 Nginx 是否启动成功](#查看 Nginx 是否启动成功)
- 查看端口监听状态
- [8. 常见问题及解决方法](#8. 常见问题及解决方法)
-
- [1. 缺少 `zlib` 库](#1. 缺少
zlib
库) - [2. 找不到 `openssl` 库](#2. 找不到
openssl
库) - [3. Nginx 端口冲突](#3. Nginx 端口冲突)
- [1. 缺少 `zlib` 库](#1. 缺少
- [9. 测试推流与播放](#9. 测试推流与播放)
- [10. 使用C++ 和FFmpeg库实现相同RTMP效果:](#10. 使用C++ 和FFmpeg库实现相同RTMP效果:)
- 其它
环境
- 服务端系统:Ubuntu
- 播放器 :Windows 下使用
ffplay
命令
1. 安装依赖
在 Ubuntu 系统中,执行以下命令安装必要的依赖项:
bash
sudo apt-get install build-essential libpcre3 libpcre3-dev libssl-dev
2. 创建 Nginx 编译目录
bash
$ mkdir my_nginx_rtmp
$ cd my_nginx_rtmp/
$ pwd
/home/togevision/wzt/my_nginx_rtmp
3. 下载 Nginx 和 Nginx-RTMP-Module
bash
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 模块:
bash
cd nginx-1.21.6/
./configure --with-http_ssl_module --add-module=../nginx-rtmp-module-master
make -j4 && sudo make install
成功输出示例:
bash
checking for C compiler ... found
...
creating objs/Makefile
Configuration summary
+ using system PCRE library
+ using system OpenSSL library
+ RTMP module added
...
5. 验证 Nginx 安装成功
bash
togevision@TG:~/wzt/my_nginx_rtmp$ /usr/local/nginx/sbin/nginx -v
nginx version: nginx/1.21.6
6. 配置环境变量
将 Nginx 添加到环境变量中:
bash
sudo vi ~/.bashrc
在文件末尾添加:
bash
export PATH=$PATH:/usr/local/nginx/sbin/
执行以下命令生效:
bash
source ~/.bashrc
7. 修改 Nginx 配置文件
编辑 Nginx 配置文件:
bash
sudo vim /usr/local/nginx/conf/nginx.conf
在文件末尾添加以下内容以启用 RTMP 模块:
css
rtmp {
server {
listen 1935;
chunk_size 4096;
application live {
live on;
record off;
}
}
}
8. 启动 Nginx 服务
bash
nginx
启动后无提示,但可以通过以下命令确认状态
查看 Nginx 是否启动成功
bash
ps -ef | grep nginx | grep -v grep
输出示例:
plain
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
查看端口监听状态
bash
netstat -anp | grep nginx
输出示例:
plain
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
库
执行以下命令安装:
bash
sudo apt-get install zlib1g-dev
输出示例:
plain
Reading package lists... Done
...
2. 找不到 openssl
库
在 ~/.bashrc
文件中添加 OpenSSL 库位置:
bash
export LD_LIBRARY_PATH=/home/rog/anaconda3/lib:$LD_LIBRARY_PATH
source ~/.bashrc
3. Nginx 端口冲突
如果出现以下错误:
plain
nginx: [emerg] bind() to 0.0.0.0:80 failed (13: Permission denied)
修改 /usr/local/nginx/conf/nginx.conf
中的端口号为 1024 以上的端口,例如 8090
。
9. 测试推流与播放
必要资源下载:
推流命令示例
服务端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效果:
目录结构如下
shell
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.mp4
9 directories, 8 files
main.cpp源码如下,FFmpeg实现RTMP:
cpp
#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/1
int 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代码如下:
bash
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
构建和执行步骤:
bash
# 进入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 | 一个开源的加密库,提供了各种加密算法和安全协议的实现。(必须) |