LINUX C++ ffmpeg 摄像头 推流 代码示例
时间: 2023-07-26 09:03:24 浏览: 217
简单的ffmpeg推流demo
这里提供一个简单的示例代码,使用FFmpeg推送摄像头采集到的视频流:
```c++
#include <iostream>
#include <thread>
#include <chrono>
#include <opencv2/opencv.hpp>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
using namespace std;
using namespace cv;
int main(int argc, char* argv[])
{
// 打开摄像头
VideoCapture cap(0);
if (!cap.isOpened())
{
cerr << "Failed to open camera!" << endl;
return -1;
}
// 初始化FFmpeg
av_register_all();
avformat_network_init();
// 创建输出上下文
AVFormatContext* outctx = nullptr;
if (avformat_alloc_output_context2(&outctx, nullptr, "flv", "rtmp://localhost/live/test") < 0)
{
cerr << "Failed to create output context!" << endl;
return -1;
}
// 添加视频流
AVCodecID codec_id = AV_CODEC_ID_H264;
AVCodec* codec = avcodec_find_encoder(codec_id);
if (!codec)
{
cerr << "Failed to find encoder!" << endl;
return -1;
}
AVStream* outstream = avformat_new_stream(outctx, codec);
if (!outstream)
{
cerr << "Failed to create stream!" << endl;
return -1;
}
outstream->codecpar->codec_id = codec_id;
outstream->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
outstream->codecpar->width = cap.get(CV_CAP_PROP_FRAME_WIDTH);
outstream->codecpar->height = cap.get(CV_CAP_PROP_FRAME_HEIGHT);
outstream->codecpar->format = AV_PIX_FMT_YUV420P;
// 打开编码器
if (avcodec_open2(outstream->codec, codec, nullptr) < 0)
{
cerr << "Failed to open encoder!" << endl;
return -1;
}
// 打开输出流
if (!(outctx->oformat->flags & AVFMT_NOFILE))
{
if (avio_open(&outctx->pb, outctx->url, AVIO_FLAG_WRITE) < 0)
{
cerr << "Failed to open output stream!" << endl;
return -1;
}
}
// 写文件头
if (avformat_write_header(outctx, nullptr) < 0)
{
cerr << "Failed to write header!" << endl;
return -1;
}
// 初始化图像转换器
SwsContext* swsctx = sws_getContext(cap.get(CV_CAP_PROP_FRAME_WIDTH), cap.get(CV_CAP_PROP_FRAME_HEIGHT), AV_PIX_FMT_BGR24,
outstream->codecpar->width, outstream->codecpar->height, outstream->codecpar->format, SWS_BICUBIC, nullptr, nullptr, nullptr);
if (!swsctx)
{
cerr << "Failed to create image converter!" << endl;
return -1;
}
// 循环读取视频帧并推送
Mat frame;
AVFrame* avframe = av_frame_alloc();
avframe->format = outstream->codecpar->format;
avframe->width = outstream->codecpar->width;
avframe->height = outstream->codecpar->height;
av_frame_get_buffer(avframe, 32);
while (true)
{
cap >> frame;
if (frame.empty())
break;
// 转换图像格式
uint8_t* data[AV_NUM_DATA_POINTERS] = { 0 };
data[0] = frame.data;
int linesize[AV_NUM_DATA_POINTERS] = { 0 };
linesize[0] = frame.step;
sws_scale(swsctx, data, linesize, 0, frame.rows, avframe->data, avframe->linesize);
// 编码并发送视频帧
AVPacket pkt = { 0 };
av_init_packet(&pkt);
int ret = avcodec_send_frame(outstream->codec, avframe);
if (ret < 0)
{
cerr << "Failed to send frame!" << endl;
break;
}
while (ret >= 0)
{
ret = avcodec_receive_packet(outstream->codec, &pkt);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
break;
else if (ret < 0)
{
cerr << "Error while encoding frame!" << endl;
break;
}
// 发送数据包
av_packet_rescale_ts(&pkt, outstream->codec->time_base, outstream->time_base);
pkt.stream_index = outstream->index;
ret = av_interleaved_write_frame(outctx, &pkt);
if (ret < 0)
cerr << "Failed to write packet!" << endl;
av_packet_unref(&pkt);
}
// 等待一段时间
this_thread::sleep_for(chrono::milliseconds(30));
}
// 写文件尾
av_write_trailer(outctx);
// 释放资源
avcodec_close(outstream->codec);
avcodec_free_context(&outstream->codec);
avformat_free_context(outctx);
av_frame_free(&avframe);
sws_freeContext(swsctx);
return 0;
}
```
请注意修改代码中的推流地址和编码器参数,以适应你的需求。
阅读全文