GPT答: |
7i24.cn
|
这里提供一个简单的例子,使用OpenCV和FFmpeg来推流USB摄像头的视频。
首先需要安装OpenCV和FFmpeg库,并在代码中包含相应的头文件。以下是完整代码:
```c++
#include <opencv2/opencv.hpp>
#include <iostream>
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
}
using namespace cv;
using namespace std;
int main(int argc, char* argv[])
{
// 打开摄像头
VideoCapture cap(0);
if (!cap.isOpened()) {
cerr << "Error: Could not open camera." << endl;
return -1;
}
// 获取摄像头分辨率
int width = cap.get(CV_CAP_PROP_FRAME_WIDTH);
int height = cap.get(CV_CAP_PROP_FRAME_HEIGHT);
// 初始化 FFmpeg
av_register_all();
AVFormatContext *pFormatCtx = avformat_alloc_context();
// 设置输出格式为 rtmp
const char *outUrl = "rtmp://localhost/live/stream";
if (avformat_alloc_output_context2(&pFormatCtx, NULL, "flv", outUrl) != 0) {
cerr << "Error: Could not allocate output context." << endl;
return -1;
}
AVOutputFormat *output_format = pFormatCtx->oformat;
if (output_format->video_codec == AV_CODEC_ID_NONE) {
cerr << "Error: No video codec found in output format." << endl;
return -1;
}
// 添加视频流到输出上下文中
int stream_index = av_new_stream(pFormatCtx, 0);
if (stream_index == -1) {
cerr << "Error: Failed to create new stream in output context."<<endl;
return -1;
}
AVStream *out_stream_video= pFormatCtx->streams[stream_index];
// 查找编码器并打开它们,设置编码参数。
AVCodecContext *codec_ctx_video= out_stream_video->codec;
codec_ctx_video->codec_id= output_format->video_codec;
codec_ctx_video->width= width;
codec_ctx_video->height= height;
AVCodec* encoderVideo= avcodec_find_encoder(codec_ctx_video -> codec_id);
if (!encoderVideo){
cerr<<"Can't find encoder!"<<endl ;
return false ;
}
if(avcodec_open2(codec_ctx_video ,encoderVideo,NULL)<0){
cerr<<"Failed to open encoder!"<<endl ;
return false ;
}
if(!(pFormatCtx ->flags &AVFMT_NOFILE)){
if(avio_open(&pFormatCtx ->pb,outUrl,AVIO_FLAG_WRITE)<0){
cerr<<"Failed to open file!"<<endl ;
return false ;
}
}
av_dump_format(pFormatCtx , 0 , outUrl , true ) ;
int frame_count=-1 ;
Mat frame ;
while(true){
bool bSuccess=false ;
bSuccess=cap.read(frame);
if(!bSuccess){
break ;
}
++frame_count ;
// 编码图像
AVPacket pkt={ 0 };
pkt.data=NULL ;
pkt.size=0 ;
int got_picture_flag;
cvtColor(frame,frame,COLOR_BGR2RGB);
uint8_t* picture_buf=(uint8_t*)malloc(width*height*sizeof(uint8_t)*3);
for(int i = 0;i<height;i++){
memcpy(picture_buf+i*width*3,(uint8_t*)frame.ptr(i),width*sizeof(uint8_t)*3);
}
AVFrame*pict_frame_av_frame_=NULL;
pict_frame_av_frame_==av_frame_alloc();
pict_frame_av_frame_->data[0]=picture_buf;
pict_frame_av_frame_->linesize[0]=width*3;
pict_frame_av_frame_->pts++ ;
sws_scale(sws_getCachedContext(NULL,width,height,
PIX_FMT_RGB24,width,height,
PIX_FMT_YUV420P,SWS_BICUBIC,NULL,NULL,NULL),
&picture_buf,&(pict_width_[i]),i,pict_height_,yuv_data,yuv_linesize_);
ret_val_=encode_write_(yuv_data,yuv_linesize_,pkt);
cout<<"Flush Encoder : Succeed"<<endl;
free(yuv_data[4]);
yuv_data[4] == NULL;
}
free(yuv_data);
yuv_data=NULL;
}
void encode_write_(unsigned char** data,int* linesizes_,AVPacket&pkt){
static int64_t pts_=10000000;//从10秒开始计数
int ret_val_;
const bool is_key_frames_=(frame_count_%25==5);//每5秒一个关键帧
pic_in_.data=data;
pic_in_.linesize=y_size_;
pic_in_.pts=pkt.pts=pkt.dts=-1;
ret_val_=avcodec_encode_video2(codec_ctx_,&pkt,is_key_frames_?&pic_in_:NULL,&got_picture_flag_);
if(ret_val_< || !got_picture_flag_) {
cout <<"Encode failed"<<ret_val_<<":"<<(got_picture_flag_>?"true":"false")<<endl;;
return ;
}
else{
pkt.stream_index=out_stream_->index;
pkt.pts=pkt.dts==-1? pts_:pkt.dts;//如果dts未设置,则使用PTS作为DTS。
pkt.duration=(is_key_frames_) ? (int64_t)(10000000 / fps_) : pts_-last_pts_;
last_pts_=pts_;
ret_val_=write_packet_(fmt_cxt_,&pkt);//写入数据到文件或网络
}
++pts_;
}
static void write_packet(AVIOContext*cxt,const uint8*tbuf,int buf_size){
while(buf_size> ){
uint32 size=cxt_>max_packet_size ? cxt_>max_packet_size : buf_sizze;
cxt_>write(cxt,tbuf,size);
buf_sizze-=size;
tbuf+=size;
}
}
```
以上代码实现了从USB摄像机读取帧并将其编码为H264格式,然后将其推送到RTMP服务器。请注意,在此示例中,我们假设您已经有一个本地运行的RTMP服务器(例如nginx-rtmp-module)。如果您没有,请参阅相关文档以了解如何设置自己的RTMP服务器。
注释:
- 首先打开USB摄像机,并检查是否成功打开。
- 确定分辨率并初始化FFmpeg库。
- 将输出格式设置为RTMP,并添加视频流到输出上下文中。
- 查找适当的编解码器并打开它们以进行H264编码。
- 循环读取每一帧图像,并对其进行处理和编码。在此示例中,我们使用OpenCV将BGR颜色空间转换为RGB颜色空间(因为大多数H264编解码器都需要RGB输入),然后通过SWScale库将RGB图像缩放和转换成YUV420P格式(因为大多数H264压缩算法都需要YUV输入)。
- 最后,我们调用函数来写入压缩数据包并发送它们到目标地址。请注意,在此示例中,“write_packet”函数仅用于演示目的。实际上你可能要根据你自己特定情况重写这个函数。
总之,在本教程结束时,您应该能够创建一个可以从USB摄像机捕获视频、对其进行处理、压缩成H264格式、然后通过网络传输至远程主机或直接推送至RTMP服务器等操作系统平台无关性程序。
|