实现opencv

This commit is contained in:
zhangpeng 2025-06-26 18:32:53 +08:00
parent 2a4d3516ca
commit 62d49d4dc8

View File

@ -0,0 +1,104 @@
RTSPStreamer::RTSPStreamer(const std::string& rtsp_url, int width, int height, int fps)
: m_rtspUrl(rtsp_url), m_width(width), m_height(height), m_fps(fps) {
// 初始化 FFmpeg
avformat_network_init();
// 创建输出上下文 (RTSP)
avformat_alloc_output_context2(&m_fmtCtx, nullptr, "rtsp", rtsp_url.c_str());
if (!m_fmtCtx) {
std::cerr << "Failed to create RTSP output context" << std::endl;
return;
}
// 查找 H.264 编码器
const AVCodec* codec = avcodec_find_encoder(AV_CODEC_ID_H264);
if (!codec) {
std::cerr << "H.264 encoder not found" << std::endl;
return;
}
// 创建编码器上下文
m_codecCtx = avcodec_alloc_context3(codec);
m_codecCtx->width = width;
m_codecCtx->height = height;
m_codecCtx->time_base = {1, fps};
m_codecCtx->pix_fmt = AV_PIX_FMT_YUV420P;
// 打开编码器
if (avcodec_open2(m_codecCtx, codec, nullptr) < 0) {
std::cerr << "Failed to open H.264 encoder" << std::endl;
return;
}
// 创建视频流
m_stream = avformat_new_stream(m_fmtCtx, codec);
avcodec_parameters_from_context(m_stream->codecpar, m_codecCtx);
// 打开 RTSP 输出
if (avio_open(&m_fmtCtx->pb, rtsp_url.c_str(), AVIO_FLAG_WRITE) < 0) {
std::cerr << "Failed to open RTSP output" << std::endl;
return;
}
// 写文件头
if (avformat_write_header(m_fmtCtx, nullptr) < 0) {
std::cerr << "Failed to write RTSP header" << std::endl;
return;
}
m_connected = true;
}
bool RTSPStreamer::pushFrame(const cv::Mat& frame) {
if (!m_connected) return false;
// 转换 BGR 到 YUV420
AVFrame* avFrame = av_frame_alloc();
avFrame->format = AV_PIX_FMT_YUV420P;
avFrame->width = m_width;
avFrame->height = m_height;
av_frame_get_buffer(avFrame, 0);
SwsContext* swsCtx = sws_getContext(
frame.cols, frame.rows, AV_PIX_FMT_BGR24,
m_width, m_height, AV_PIX_FMT_YUV420P,
SWS_BILINEAR, nullptr, nullptr, nullptr);
const uint8_t* srcData[1] = {frame.data};
int srcLinesize[1] = {frame.step};
sws_scale(swsCtx, srcData, srcLinesize, 0, frame.rows,
avFrame->data, avFrame->linesize);
sws_freeContext(swsCtx);
// 编码并发送
AVPacket pkt;
av_init_packet(&pkt);
pkt.data = nullptr;
pkt.size = 0;
if (avcodec_send_frame(m_codecCtx, avFrame) < 0) {
av_frame_free(&avFrame);
return false;
}
while (avcodec_receive_packet(m_codecCtx, &pkt) == 0) {
av_packet_rescale_ts(&pkt, m_codecCtx->time_base, m_stream->time_base);
pkt.stream_index = m_stream->index;
av_interleaved_write_frame(m_fmtCtx, &pkt);
av_packet_unref(&pkt);
}
av_frame_free(&avFrame);
return true;
}
RTSPStreamer::~RTSPStreamer() {
if (m_fmtCtx) {
av_write_trailer(m_fmtCtx);
avio_close(m_fmtCtx->pb);
avformat_free_context(m_fmtCtx);
}
if (m_codecCtx) avcodec_free_context(&m_codecCtx);
avformat_network_deinit();
}