ffmpeg推流rtsp c++
时间: 2023-10-01 13:12:35 浏览: 326
你可以使用 FFmpeg 的 C++ API 来进行 RTSP 推流。下面是一个简单的示例代码:
```c++
#include <iostream>
#include <string>
#include <chrono>
#include <thread>
extern "C" {
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libavutil/opt.h>
#include <libavutil/imgutils.h>
}
int main(int argc, char *argv[]) {
int ret = 0;
// 初始化 FFmpeg
av_register_all();
avformat_network_init();
// 打开输入文件
AVFormatContext *input_ctx = NULL;
if ((ret = avformat_open_input(&input_ctx, "input.mp4", NULL, NULL)) < 0) {
std::cerr << "Error: could not open input file" << std::endl;
return ret;
}
// 获取视频流信息
if ((ret = avformat_find_stream_info(input_ctx, NULL)) < 0) {
std::cerr << "Error: could not find stream information" << std::endl;
return ret;
}
// 获取视频流索引
int video_stream_index = -1;
for (int i = 0; i < input_ctx->nb_streams; i++) {
if (input_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
video_stream_index = i;
break;
}
}
if (video_stream_index == -1) {
std::cerr << "Error: could not find video stream" << std::endl;
return AVERROR(EINVAL);
}
// 打开输出文件
AVFormatContext *output_ctx = NULL;
if ((ret = avformat_alloc_output_context2(&output_ctx, NULL, "rtsp", "rtsp://localhost:8554/test")) < 0) {
std::cerr << "Error: could not create output context" << std::endl;
return ret;
}
// 添加视频流
AVStream *video_out = avformat_new_stream(output_ctx, NULL);
if (!video_out) {
std::cerr << "Error: could not create output stream" << std::endl;
return AVERROR_UNKNOWN;
}
// 复制参数
if ((ret = avcodec_parameters_copy(video_out->codecpar, input_ctx->streams[video_stream_index]->codecpar)) < 0) {
std::cerr << "Error: could not copy codec parameters" << std::endl;
return ret;
}
// 打开输出流
if (!(output_ctx->oformat->flags & AVFMT_NOFILE)) {
if ((ret = avio_open(&output_ctx->pb, "rtsp://localhost:8554/test", AVIO_FLAG_WRITE)) < 0) {
std::cerr << "Error: could not open output file" << std::endl;
return ret;
}
}
// 写文件头
if ((ret = avformat_write_header(output_ctx, NULL)) < 0) {
std::cerr << "Error: could not write output file header" << std::endl;
return ret;
}
// 编码和推流
AVPacket pkt;
while (true) {
// 读取一帧视频
AVFrame *frame = av_frame_alloc();
if (!frame) {
std::cerr << "Error: could not allocate video frame" << std::endl;
return AVERROR(ENOMEM);
}
AVPacket *packet = av_packet_alloc();
if (!packet) {
std::cerr << "Error: could not allocate packet" << std::endl;
return AVERROR(ENOMEM);
}
if ((ret = av_read_frame(input_ctx, packet)) < 0) {
break;
}
if (packet->stream_index != video_stream_index) {
continue;
}
if ((ret = avcodec_send_packet(input_ctx->streams[video_stream_index]->codecpar, packet)) < 0) {
std::cerr << "Error: could not send packet to decoder" << std::endl;
return ret;
}
while (ret >= 0) {
ret = avcodec_receive_frame(input_ctx->streams[video_stream_index]->codecpar, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
break;
} else if (ret < 0) {
std::cerr << "Error: could not receive frame from decoder" << std::endl;
return ret;
}
// 转换像素格式
AVFrame *out_frame = av_frame_alloc();
if (!out_frame) {
std::cerr << "Error: could not allocate output frame" << std::endl;
return AVERROR(ENOMEM);
}
if ((ret = av_image_alloc(out_frame->data, out_frame->linesize, video_out->codecpar->width, video_out->codecpar->height, video_out->codecpar->format, 1)) < 0) {
std::cerr << "Error: could not allocate image" << std::endl;
return ret;
}
if ((ret = av_image_copy(out_frame->data, out_frame->linesize, (const uint8_t **)frame->data, frame->linesize, video_out->codecpar->format, video_out->codecpar->width, video_out->codecpar->height)) < 0) {
std::cerr << "Error: could not copy image" << std::endl;
return ret;
}
out_frame->format = video_out->codecpar->format;
out_frame->width = video_out->codecpar->width;
out_frame->height = video_out->codecpar->height;
out_frame->pts = av_rescale_q(frame->pts, input_ctx->streams[video_stream_index]->time_base, video_out->time_base);
out_frame->pkt_dts = av_rescale_q(frame->pkt_dts, input_ctx->streams[video_stream_index]->time_base, video_out->time_base);
out_frame->pkt_duration = av_rescale_q(frame->pkt_duration, input_ctx->streams[video_stream_index]->time_base, video_out->time_base);
// 编码
if ((ret = avcodec_send_frame(video_out->codecpar, out_frame)) < 0) {
std::cerr << "Error: could not send frame to encoder" << std::endl;
return ret;
}
while (ret >= 0) {
ret = avcodec_receive_packet(video_out->codecpar, &pkt);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
break;
} else if (ret < 0) {
std::cerr << "Error: could not receive packet from encoder" << std::endl;
return ret;
}
// 推流
av_packet_rescale_ts(&pkt, video_out->codecpar->time_base, video_out->time_base);
pkt.stream_index = video_out->index;
if ((ret = av_interleaved_write_frame(output_ctx, &pkt)) < 0) {
std::cerr << "Error: could not write frame to output file" << std::endl;
return ret;
}
av_packet_unref(&pkt);
}
av_frame_free(&out_frame);
}
av_packet_free(&packet);
av_frame_free(&frame);
}
// 写文件尾
if ((ret = av_write_trailer(output_ctx)) < 0) {
std::cerr << "Error: could not write output file trailer" << std::endl;
return ret;
}
// 释放资源
avformat_close_input(&input_ctx);
if (output_ctx && !(output_ctx->oformat->flags & AVFMT_NOFILE)) {
avio_closep(&output_ctx->pb);
}
avformat_free_context(output_ctx);
return 0;
}
```
这个示例代码使用了 FFmpeg 的 C++ API 来打开一个 MP4 文件,将视频流推流到 RTSP 服务器。你需要根据你的实际情况进行修改。
阅读全文