fffmpeg推流摄像头c++代码
时间: 2024-06-05 15:04:54 浏览: 160
ffmpeg 推流c++源码
FFmpeg是一款非常强大的音视频处理库,可以用来进行音视频的编解码、格式转换、推流等操作。下面是一个简单的C++代码示例,用于将摄像头采集到的视频数据进行推流:
```
#include <iostream>
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <libavutil/imgutils.h>
}
using namespace std;
int main()
{
AVFormatContext *fmt_ctx = NULL;
AVCodecContext *codec_ctx = NULL;
AVCodec *codec = NULL;
AVStream *stream = NULL;
AVPacket pkt;
int ret;
// 打开摄像头
cv::VideoCapture cap(0);
if (!cap.isOpened())
{
cerr << "Could not open camera" << endl;
return -1;
}
// 初始化FFmpeg
av_register_all();
avformat_network_init();
// 创建输出上下文
ret = avformat_alloc_output_context2(&fmt_ctx, NULL, "flv", "rtmp://localhost/live");
if (ret < 0)
{
cerr << "Could not allocate output context" << endl;
return -1;
}
// 查找编码器
codec = avcodec_find_encoder(AV_CODEC_ID_H264);
if (!codec)
{
cerr << "Could not find encoder" << endl;
return -1;
}
// 创建新的流
stream = avformat_new_stream(fmt_ctx, codec);
if (!stream)
{
cerr << "Could not create new stream" << endl;
return -1;
}
// 配置编码器上下文
codec_ctx = avcodec_alloc_context3(codec);
if (!codec_ctx)
{
cerr << "Could not allocate codec context" << endl;
return -1;
}
codec_ctx->width = cap.get(CV_CAP_PROP_FRAME_WIDTH);
codec_ctx->height = cap.get(CV_CAP_PROP_FRAME_HEIGHT);
codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
codec_ctx->time_base.num = 1;
codec_ctx->time_base.den = 25;
// 打开编码器
ret = avcodec_open2(codec_ctx, codec, NULL);
if (ret < 0)
{
cerr << "Could not open codec" << endl;
return -1;
}
// 将编码器上下文复制到流中
ret = avcodec_parameters_from_context(stream->codecpar, codec_ctx);
if (ret < 0)
{
cerr << "Could not copy codec parameters" << endl;
return -1;
}
stream->time_base = codec_ctx->time_base;
// 打开输出流
ret = avio_open(&fmt_ctx->pb, fmt_ctx->url, AVIO_FLAG_WRITE);
if (ret < 0)
{
cerr << "Could not open output stream" << endl;
return -1;
}
// 写入文件头部
ret = avformat_write_header(fmt_ctx, NULL);
if (ret < 0)
{
cerr << "Error writing header" << endl;
return -1;
}
// 创建图像缩放上下文
struct SwsContext *sws_ctx = sws_getContext(codec_ctx->width, codec_ctx->height,
AV_PIX_FMT_BGR24, codec_ctx->width, codec_ctx->height,
AV_PIX_FMT_YUV420P, SWS_BILINEAR, NULL, NULL, NULL);
if (!sws_ctx)
{
cerr << "Could not initialize the conversion context" << endl;
return -1;
}
// 读取摄像头数据并推流
while (true)
{
cv::Mat frame;
cap.read(frame);
if (frame.empty()) break;
// 将图像转换为YUV420P格式
AVFrame *yuv_frame = av_frame_alloc();
yuv_frame->width = codec_ctx->width;
yuv_frame->height = codec_ctx->height;
yuv_frame->format = AV_PIX_FMT_YUV420P;
av_image_alloc(yuv_frame->data, yuv_frame->linesize, codec_ctx->width, codec_ctx->height, AV_PIX_FMT_YUV420P, 32);
sws_scale(sws_ctx, (const uint8_t * const *)frame.data, frame.step, 0, codec_ctx->height,
yuv_frame->data, yuv_frame->linesize);
// 编码图像数据并写入输出流
av_init_packet(&pkt);
pkt.data = NULL; // 设置数据指针为NULL,防止出现奇怪的问题
pkt.size = 0;
ret = avcodec_send_frame(codec_ctx, yuv_frame);
if (ret < 0)
{
cerr << "Error sending frame to codec" << endl;
return -1;
}
while (ret >= 0)
{
ret = avcodec_receive_packet(codec_ctx, &pkt);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) break;
if (ret < 0)
{
cerr << "Error encoding packet" << endl;
return -1;
}
pkt.stream_index = stream->index;
av_packet_rescale_ts(&pkt, codec_ctx->time_base, stream->time_base);
ret = av_interleaved_write_frame(fmt_ctx, &pkt);
if (ret < 0)
{
cerr << "Error writing packet" << endl;
return -1;
}
av_packet_unref(&pkt);
}
av_frame_free(&yuv_frame);
}
// 写入文件尾部
ret = av_write_trailer(fmt_ctx);
if (ret < 0)
{
cerr << "Error writing trailer" << endl;
return -1;
}
// 清理资源
avformat_close_input(&fmt_ctx);
avformat_free_context(fmt_ctx);
avcodec_free_context(&codec_ctx);
return 0;
}
```
请注意,这只是一个简单的示例代码,实际情况可能会更加复杂。另外,需要安装OpenCV和FFmpeg库才能编译运行该代码。如果你还没有安装这些库,请先进行安装。
阅读全文