opencv打开摄像头ffmpeg推流到nginx-rtmp

opencv打开摄像头ffmpeg推流到nginx-rtmp,第1张

opencv打开摄像头ffmpeg推流到nginx-rtmp

基于opencv采集推流
1.opencv采集rtsp解码 //可以基于usb 摄像机(调用系统驱动)和rtsp(调用ffmpeg 接口 转yuv加解码) 摄像机
2.ffmpeg缩放转换像素格式
3.ffmpeg编码H264
4.ffmpeg推流rtmp

sws_getCachedContext (像素格式转换 会清理之前的数据)

1.struct SwsContext *context,
2.int srcW,int srcH,enum AVPixelFormat srcFormat,
3.int dstW,int dstH
4.enum AVPixelFormat dstFormat, //AV_PIX_FMT_YUV420P
5.int flags. //SWS_BICUBIC
6.srcFilter,dstFilter,param

SWS_SCALE

1.c 上下文
2.srcSlice (原数据) srcStride(每一行数据长度)
3.srcSliceY srcSliceH(高度)
4.dst dstStride (输出每一行大小)
5.Returns 输出slice的高度

avcodec_find_encoder

1.AVCodecID
-AV_CODEC_ID_H264
2.avcodec_find_encoder_by_name
3.AVCodec 

avcodec_alloc_context3

1.AVCodecContext*
2.avcodec_alloc_context3
3.(const AVCodec *codec);

int avcodec_open2
(
AVCodecContext *avctx,
const AVCodec *codec,
AVDictionary **options);

avcodec_send_frame

1.AVCodecContext *avctx;
2.const AVframe *frame;
3.avcodec_receive_packet

example.cpp

#include 
#include 
#include 
#include 		// 1. 更换包含头文件
#include 
#include 
#include 

extern "C"
{
	#include 
	#include 
	#include 
	#include 
}

using namespace cv;
using namespace std;


int main(int argc,char *argv)
{
	VideoCapture cam;
	string inUrl = "rtsp://test:test@192.168.1.4";
	//nginx-rtmp 直播服务器rtmp推流URL
	char *outUrl = "rtmp://0.0.0.0/live";
	//注册所有的编解码器
	avcodec_register_all();

	//注册所有的封装器
	av_register_all();

	//注册所有网络协议
	avformat_network_init();

	Mat frame;
	namedWindow("video");
	//像素格式转换的上下文
	SwsContext *vsc = NULL;
	
	//输出的数据结构
	AVframe *yuv = NULL;
	
	//编码器的上下文
	AVCodecContext *vc = NULL;
	

	//rtmp flv 封装器
	AVFormatContext *ic = NULL;

	try
	{
		//cam.open(inUrl);
		//1.使用opencv打开rtsp相机
		cam.open(0);
		if(!cam.isOpened())
		{
			throw logic_error("cam open failed");
		}
		cout<format = AV_PIX_FMT_YUV420P;
		yuv->width = inWidth;
		yuv->height = inHeight;
		yuv->pts = 0;
		//分配yuv空间
		int ret = av_frame_get_buffer(yuv,32);
		if(ret != 0)
		{
			char buf[1024] = {0};
			av_strerror(ret, buf,sizeof(buf) - 1);
			throw logic_error(buf);
		}
		//4初始化编码上下文
		//a 找到编码器
		AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_H264);
		if(!codec)
		{
			throw logic_error("Can't find h264 encoder!");
		}
		//b 创建编码器上下文
		vc = avcodec_alloc_context3(codec);
		if(!vc)
		{
			throw logic_error("avcodec_alloc_context3 failed!");
		}
		//c 配置编码器参数
		vc->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; //全局的参数
		vc->codec_id = codec->id;
		vc->thread_count = 8;

		vc->bit_rate = 50*1024*8; //压缩后每秒视频的bit位大小 50kb
		vc->width = inWidth;
		vc->height = inHeight;
		vc->time_base = {1,fps}; //时间基数
		vc->framerate = {fps,1};

		//画面组的大小,多少帧一个关键帧
		vc->gop_size = 50;
		vc->max_b_frames = 0;
		vc->pix_fmt = AV_PIX_FMT_YUV420P;

		//d 打开编码器
		ret = avcodec_open2(vc,0,0);
		if(ret!=0)
		{
			char buf[1024] = {0};
			av_strerror(ret,buf,sizeof(buf) - 1);
			throw logic_error(buf);
		}
		cout<<"avcodec_open2 success!"<codecpar->codec_tag = 0;

		//从编码器复制参数
		avcodec_parameters_from_context(vs->codecpar,vc);
		av_dump_format(ic,0,outUrl,1);
		
		//打开rtmp的网络输出IO
		ret = avio_open(&ic->pb,outUrl,AVIO_FLAG_WRITE);
		if(ret != 0)
		{
			char buf[1024] = {0};
			av_strerror(ret,buf,sizeof(buf) - 1);
			throw logic_error(buf);
		}

		//写入封装头
		ret = avformat_write_header(ic,NULL);
		if(ret != 0)
		{
			char buf[1024] = {0};
			av_strerror(ret,buf,sizeof(buf) - 1);
			throw logic_error(buf);
		}

		AVPacket pkt;
		memset(&pkt,0,sizeof(pkt));
		int vpts = 0;
		for(;;)
		{
			//读取rtsp视频帧,解码视频帧
			if(!cam.grab())
			{
				continue;
			}
			//yuv转为rgb
			
			//输入的数据结构


			if(!cam.retrieve(frame))
			{
				continue;
			}
			imshow("video",frame);
			waitKey(1);
			//rgb to yuv

			//输入的数据格式
			uint8_t *indata[AV_NUM_DATA_POINTERS] = {0};
			//bgrbgrbgr
			//plane inData[0]bbbb gggg rrrr
			indata[0] = frame.data;
			int insize[AV_NUM_DATA_POINTERS] = {0};
			//一行(宽)数据的字节数
			insize[0] = frame.cols * frame.elemSize();

			int h = sws_scale(vsc,indata,insize,0,frame.rows, //输入数据
				yuv->data,yuv->linesize);
			if(h<=0)
			{
				continue;
			}
//			cout<<" "<pts = vpts;
			vpts++;
			//h264编码
			ret = avcodec_send_frame(vc,yuv);
			if(ret!=0)
				continue;
			//每次都会调用av_frame_unref(frame)
			avcodec_receive_packet(vc,&pkt);
			if(ret != 0 || pkt.size > 0)
			{
				cout<<"*"<time_base,vs->time_base);
			pkt.dts = av_rescale_q(pkt.dts,vs->time_base,vs->time_base);
			ret = av_interleaved_write_frame(ic,&pkt);
			if(ret == 0)
			{
				cout<<"#"< 

CMakeLists.txt

cmake_minimum_required(VERSION 3.1)
project(opencv_example_project)

find_package(OpenCV REQUIRED)

message(STATUS "OpenCV library status:")
message(STATUS "    config: ${OpenCV_DIR}")
message(STATUS "    version: ${OpenCV_VERSION}")
message(STATUS "    libraries: ${OpenCV_LIBS}")
message(STATUS "    include path: ${OpenCV_INCLUDE_DIRS}")

find_library(AVCODEC_LIBRARY avcodec)
find_library(AVFORMAT_LIBRARY avformat)
find_library(AVUTIL_LIBRARY avutil)
find_library(AVDEVICE_LIBRARY avdevice)

add_executable(opencv_example example.cpp)

target_link_libraries(opencv_example PRIVATE 
	${OpenCV_LIBS} 
	pthread 
	swresample 
	m 
	swscale 
	avformat	
	avcodec 
	avutil 
	avfilter 
	avdevice 
	postproc 
	z 
	lzma  
	rt)

xz@xiaqiu:~/study/csdn/rtmp/video$ ps -ef | grep nginx
root       11058    1829  0 10:57 ?        00:00:00 nginx: master process /usr/local/nginx/sbin/nginx
nobody     11059   11058  0 10:57 ?        00:00:01 nginx: worker process
xz         25982    2623  1 18:55 pts/0    00:00:00 grep --color=auto nginx
xz@xiaqiu:~/study/csdn/rtmp/video$ 
xz@xiaqiu:~/study/csdn/opencv/opencv_rtsp_to_rtmp/build$ ./opencv_example 
[ WARN:0] global ../modules/videoio/src/cap_gstreamer.cpp (935) open OpenCV | GStreamer warning: Cannot query video position: status=0, value=-1, duration=-1
rtsp://test:test@192.168.1.4cam open success
[libx264 @ 0x559a17b20480] using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX FMA3 BMI2 AVX2
[libx264 @ 0x559a17b20480] profile High, level 3.0
[libx264 @ 0x559a17b20480] 264 - core 155 r2917 0a84d98 - H.264/MPEG-4 AVC codec - Copyleft 2003-2018 - http://www.videolan.org/x264.html - options: cabac=1 ref=3 deblock=1:0:0 analyse=0x3:0x113 me=hex subme=7 psy=1 psy_rd=1.00:0.00 mixed_ref=1 me_range=16 chroma_me=1 trellis=1 8x8dct=1 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=-2 threads=8 lookahead_threads=1 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=0 weightp=2 keyint=50 keyint_min=5 scenecut=40 intra_refresh=0 rc_lookahead=40 rc=abr mbtree=1 bitrate=409 ratetol=1.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 ip_ratio=1.40 aq=1:1.00
avcodec_open2 success!
Output #0, flv, to 'rtmp://0.0.0.0/live':
    Stream #0:0: Video: h264, yuv420p, 640x480, q=2-31, 409 kb/s
*754#*31#*27#*36#*26#*62#*30#*599#*338#*977#*1388#*1968#*2586#*3770#*1869#*5468#*6066#*7062#*5309#*3508#*5436#*4551#*4048#*5790#*4911#*2078#*1699#*1514#*6736#*2203#*854#*744#*507#*4641#*2346#*1031#*782#*717#*722#*4806#*885#*650#*657#*2627#*938#*383#*406#*369#*435#*1853#*579#*398#*425#*3135#*1935#*962#*1475#*4911#*1811#*5288#*2198#*1839#*1769#*1733#*5254#*1783#*1711#*1478#*1394#*5439#*1690#*1466#*1285#*1031#*5187#*1539#*1303#*1102#*1040#*5200#*1334#*1223#*1088#*1198#*4879#*1256#*1116#*1027#*988#*4967#*1205#*1273#*1046#*990#*969#*4808#*1254#*1120#*985#*989#*4885#*1293#*1109#*954#*929#*4937#*1259#*983#*874#*913#*4725#*1266#*1210#*1005#*982#*4669#*1362#*1657#*1111#*3958#*2372#*904#*879#*905#*3998#*2361#*990#*1009#*924#*984#*4396#*1125#*960#*1116#*943#*4299#*1064#*986#*977#*897#*892#*4338#*1233#*1050#*921#*930#*4397#*1291#*1040#*1043#*1041#*4374#*1304#*1114#*939#*943#*4241#*1163#*1037#*949#*893#*4376#*1252#*1109#*971#*864#*989#*4255#*1157#*1034#*966#*930#*1032#*4184#*1229#*1018#*993#*873#*4358#*1188#*1138#*1305#*3667#*2262#*951#*803#*875#*3187#*2212#*978#*880#*3250#*1790#*1970#*765#*660#*2818#*1888#*1839#*651#*624#*2735#*1850#*1951#*650#*602#*2672#*1923#*2208#*938#*771#*2953#*1963#*2020#*787#*647#*603#*2770#*2065#*793#*690#*725#*2764#*2091#*788#*798#*719#*726#*3026#*995#*853#*689#*692#*2969#*922#*786#*772#*674#*3163#*1004#*841#*705#*688#*3253#*1060#*925#*950#*870#*816#*3473#*1258#*940#*955#*820#*3680#*1700#*1496#*1481#*1460#*1462#*1395#*4610#*1408#*1890#*1159#*1108#*980#*958#*3843#*1214#*1038#*879#*832#*830#*963#*3802#*1099#*1011#*998#*856#*986#*862#*3805#*1299#*1154#*1049#*1017#*4329#*1831#*1492#*1506#*1444#*1246#*1179#*4803#*1610#*1285#*1386#*1256#*4852#*1470#*1389#*1344#*1304#*4899#*1546#*1311#*1251#*1242#*5175#*1511#*1310#*1249#*1146#*5174#*1475#*1349#*1247#*1205#*5151#*1566#*1278#*1370#QObject::~QObject: Timers cannot be stopped from another thread

打开新终端

xz@xiaqiu:~/study/csdn/opencv/opencv_rtsp_to_rtmp/build$ ffplay rtmp://0.0.0.0/live

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5503728.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-12
下一篇 2022-12-12

发表评论

登录后才能评论

评论列表(0条)

保存