龙空技术网

基于Qt和ffmpeg的抓屏rtsp服务(一)

音视频流媒体技术 276

前言:

当前兄弟们对“ffmpeg录制rtsp”可能比较关注,兄弟们都想要知道一些“ffmpeg录制rtsp”的相关内容。那么小编同时在网络上网罗了一些对于“ffmpeg录制rtsp””的相关内容,希望你们能喜欢,姐妹们一起来了解一下吧!

实现一个基于ffmpeg的rtsp抓屏服务一、服务实现图1、整体图2、 采集图3、 编码图4、 传输二、各个模块简要说明1、模块讲解

上面图1

在上面的1、中,主要是整个程序的主要流程走向,使用ffmpeg **gdigrab**进行采集,ffmpeg中的libx264进行编码,

由于直接使用ES流进行传输。所以,封装这层先不做过多的处理。传输,是网络上找的一个rtsp服务,最终会使用**vlc**进行验证。

上面图2、

图2中,有几个函数avdevice_register_all,是需要使用到采集的gdi设备,所以需要该函数进行注册。使用av_dict_set_int来设

置编码参数,

图2中av_dict_set_int,设置抓屏参数

小编整理了一些学习资料、教学视频和学习路线图共享在群文件,资料包括《Andoird音视频开发必备手册+音视频最新学习视频+大厂面试真题+2022最新学习路线图+项目实战源码》等等(C/C++,Linux,FFmpeg ,webRTC, rtmp, hls, rtsp, ffplay, srs)

部分采集编码:

	AVDictionary *options = nullptr;	av_dict_set_int(&options, "framerate", 25, 1);	av_dict_set_int(&options, "draw_mouse", 1, 1);	av_dict_set_int(&options, "offset_x", 0, 1);	av_dict_set_int(&options, "offset_y", 0, 1);	av_dict_set(&options, "video_size", video_size, 1);	AVInputFormat* pInputFmt = av_find_input_format("gdigrab");	AVFormatContext* pFmtCtx = avformat_alloc_context();	avformat_open_input(&pFmtCtx , "desktop", pInputFmt, &options);	if (avformat_find_stream_info(pFmtCtx , nullptr) < 0) 	{		printf("Couldn't find stream info.\n");		avformat_close_input(&pFmtCtx);		pFmtCtx = nullptr;		return false;	}	int video_index = -1;	for (unsigned int i = 0; i < pFmtCtx ->nb_streams; i++) 	{		if (pFmtCtx ->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) 		{			video_index = i;		}	}	if (video_index < 0) 	{		printf("Couldn't find video stream.\n");		avformat_close_input(&pFmtCtx );		pFmtCtx = nullptr;		return false;	}	AVCodec* codec = avcodec_find_decoder(pFmtCtx->streams[video_index]->codecpar->codec_id);	if (!codec) 	{		avformat_close_input(&pFmtCtx );		pFmtCtx = nullptr;		return false;	}	m_pCodecCtx = avcodec_alloc_context3(codec);	if (!m_pCodecCtx ) 	{		return false;	}		avcodec_parameters_to_context(m_pCodecCtx , pFmtCtx->streams[video_index]->codecpar);	if (avcodec_open2(m_pCodecCtx , codec, nullptr) != 0) 	{		avcodec_close(m_pCodecCtx );		codec_context_ = nullptr;		avformat_close_input(&pFmtCtx);		pFmtCtx= nullptr;		return false;	}

部分编码

	AVCodec *codec = nullptr;	//codec = avcodec_find_encoder(AV_CODEC_ID_H264);	codec = avcodec_find_encoder_by_name("libx264");	if (!codec) 	{		std::cout << "H.264 Encoder not found.\n"  << std::endl;		return false;	}	codec_context_ = avcodec_alloc_context3(codec);	if (!codec_context_) 	{		std::cout << "avcodec_alloc_context3() failed." << std::endl;		return false;	}		codec_context_->width = av_config_.video.width;	codec_context_->height = av_config_.video.height;	codec_context_->time_base = { 1,  (int)av_config_.video.framerate };	codec_context_->framerate = { (int)av_config_.video.framerate, 1 };	codec_context_->gop_size = av_config_.video.gop;	codec_context_->max_b_frames = 0;	codec_context_->pix_fmt = AV_PIX_FMT_YUV420P;	// rc control mode: abr	codec_context_->bit_rate = av_config_.video.bitrate;	// cbr mode config	codec_context_->rc_min_rate = av_config_.video.bitrate;	codec_context_->rc_max_rate = av_config_.video.bitrate;	codec_context_->rc_buffer_size = (int)av_config_.video.bitrate;	codec_context_->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;	if (codec->id == AV_CODEC_ID_H264) 	{		av_opt_set(codec_context_->priv_data, "preset", "ultrafast", 0); //ultrafast 	}	av_opt_set(codec_context_->priv_data, "tune", "zerolatency", 0);	av_opt_set_int(codec_context_->priv_data, "forced-idr", 1, 0);	av_opt_set_int(codec_context_->priv_data, "avcintra-class", -1, 0);		if (avcodec_open2(codec_context_, codec, NULL) != 0) 	{		std::cout << "avcodec_open2() failed." << std::endl;		return false;	}	

部分代码如上

① 采集流程

上面主要是获取设备信息,并打开解码器

后面通过av_read_frame读取流,avcodec_send_packet/avcodec_receive_frame来进行解码流

同时,将获取到的数据进行编码成h264,

② 编码流程

编码流程中需要注意,数据是通过采集中获取到的数据,AVframe,需要先将AVFrame转为yuvAVFrame,然后通过接口avcodec_send_frame/avcodec_receive_packet,avcodec_receive_packet中的数据,得到的是AVPacket的数据,需要去掉其中h264中的起始码,传给rtsp服务,rtsp服务就能将数据传输给用户端。

③ 封装

由于此处直接使用ES流,不做封装,直接将编码器中的数据进行传输。

④ 传输

传输参考下面的3.rtsp服务

总结

本章节只讲述整个服务器相关的流程

标签: #ffmpeg录制rtsp