使用 C++ 和 FFmpeg 实现 RTSP 服务器
时间: 2024-05-11 14:18:10 浏览: 11
要使用 C++ 和 FFmpeg 实现 RTSP 服务器,需要遵循以下步骤:
1. 安装 FFmpeg 库:从官方网站下载并安装 FFmpeg 库,或使用包管理器进行安装。
2. 编写代码:使用 C++ 编写代码,包括创建 RTSP 服务器和处理客户端请求的逻辑。可以使用 FFmpeg 提供的 API 来处理媒体流。
3. 构建和运行服务器:使用编译器将代码编译成可执行文件,并运行服务器。
以下是一个简单的 C++ 代码示例,可以用来创建一个简单的 RTSP 服务器:
```cpp
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <unistd.h>
#include <thread>
#include <mutex>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
#include <libswscale/swscale.h>
#include <libavutil/imgutils.h>
#include <opencv2/opencv.hpp>
using namespace std;
mutex mtx;
AVFormatContext* pFormatCtx = nullptr;
AVCodecContext* pCodecCtx = nullptr;
AVCodec* pCodec = nullptr;
AVFrame* pFrame = nullptr;
AVPacket packet;
int videoStreamIndex = -1;
int initFFmpeg(char* rtspUrl) {
av_register_all();
avformat_network_init();
if (avformat_open_input(&pFormatCtx, rtspUrl, nullptr, nullptr) != 0) {
cerr << "Failed to open input file." << endl;
return -1;
}
if (avformat_find_stream_info(pFormatCtx, nullptr) < 0) {
cerr << "Failed to find stream information." << endl;
return -1;
}
for (int i = 0; i < pFormatCtx->nb_streams; i++) {
if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
videoStreamIndex = i;
break;
}
}
if (videoStreamIndex == -1) {
cerr << "Failed to find video stream." << endl;
return -1;
}
pCodecCtx = avcodec_alloc_context3(nullptr);
if (pCodecCtx == nullptr) {
cerr << "Failed to allocate codec context." << endl;
return -1;
}
if (avcodec_parameters_to_context(pCodecCtx, pFormatCtx->streams[videoStreamIndex]->codecpar) < 0) {
cerr << "Failed to copy codec parameters to codec context." << endl;
return -1;
}
pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
if (pCodec == nullptr) {
cerr << "Failed to find decoder." << endl;
return -1;
}
if (avcodec_open2(pCodecCtx, pCodec, nullptr) < 0) {
cerr << "Failed to open codec." << endl;
return -1;
}
pFrame = av_frame_alloc();
if (pFrame == nullptr) {
cerr << "Failed to allocate frame." << endl;
return -1;
}
return 0;
}
void sendFrames(int sockfd, struct sockaddr_in* clientAddr) {
SwsContext* pSwsCtx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt,
pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_BGR24, SWS_BICUBIC, nullptr, nullptr, nullptr);
cv::Mat dst(pCodecCtx->height, pCodecCtx->width, CV_8UC3);
while (1) {
if (av_read_frame(pFormatCtx, &packet) >= 0) {
if (packet.stream_index == videoStreamIndex) {
avcodec_send_packet(pCodecCtx, &packet);
while (avcodec_receive_frame(pCodecCtx, pFrame) == 0) {
sws_scale(pSwsCtx, pFrame->data, pFrame->linesize, 0, pFrame->height, dst.data, dst.step);
int numBytes = dst.cols * dst.rows * dst.channels();
mtx.lock();
sendto(sockfd, dst.data, numBytes, 0, (struct sockaddr*)clientAddr, sizeof(*clientAddr));
mtx.unlock();
}
}
av_packet_unref(&packet);
}
else {
av_seek_frame(pFormatCtx, videoStreamIndex, 0, AVSEEK_FLAG_BACKWARD);
}
}
}
int main(int argc, char** argv) {
if (argc != 2) {
cerr << "Usage: " << argv[0] << " <rtsp_url>" << endl;
return -1;
}
char* rtspUrl = argv[1];
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
cerr << "Failed to create socket." << endl;
return -1;
}
struct sockaddr_in serverAddr;
memset(&serverAddr, 0, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
serverAddr.sin_port = htons(8888);
if (bind(sockfd, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) {
cerr << "Failed to bind socket." << endl;
return -1;
}
if (initFFmpeg(rtspUrl) < 0) {
cerr << "Failed to initialize FFmpeg." << endl;
return -1;
}
struct sockaddr_in clientAddr;
socklen_t len = sizeof(clientAddr);
thread t(sendFrames, sockfd, &clientAddr);
while (1) {
char buf[1024];
int n = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr*)&clientAddr, &len);
if (n < 0) {
cerr << "Failed to receive data." << endl;
break;
}
}
t.join();
av_frame_free(&pFrame);
avcodec_close(pCodecCtx);
avformat_close_input(&pFormatCtx);
return 0;
}
```
这是一个简单的 RTSP 服务器,可以接收来自客户端的请求,并将媒体流发送回客户端。当客户端连接到服务器时,服务器将从 RTSP URL 中读取媒体流,并将其发送回客户端。