FFmpeg+SDL拉取网络摄像头流显示

1.功能说明

通过FFmpeg拉取网络摄像头推的rtmp和rtsp流解码利用SDL渲染显示出来

2.显示效果

拉流显示效果

3.网络摄像头参数

网络摄像头参数

4.FFMPEG拉流解码

/*************************************************************************************
* 项目 :		FFmpeg 获取网络摄像头的流 并渲染显示
* 类名 :		FVideoCapture
* 功能 :		打开网络摄像头采集设备 并采集视频数据
* 时间 :		2020/5/15  15:15
* 接口返回值 :  该项目所有返回值类型为 int 的 返回值  -1 代表失败  0 代表成功
***************************************************************************************/

#pragma once
#include <string>
#include <thread>
#include <atomic>

class AVFormatContext;
class AVInputFormat;
class AVCodecContext;
class AVCodec;
class AVFrame;

class FIPCameraCaptureNotify
{
public:
	FIPCameraCaptureNotify() {};
	virtual ~FIPCameraCaptureNotify() {};

	//输出解码视频数据包的回调  一帧数据回调进入渲染显示
	virtual void OnIOVideoDecNotifyFrame(AVFrame* frame) = 0;	

	//输出编码视频数据包的回调  一帧H264数据 进行网络传输
	virtual void OnIOVideoEndNotifyFrame(unsigned char * data,int size ,long long pts) = 0;
};

class FIPCameraCapture
{
public:
	FIPCameraCapture(FIPCameraCaptureNotify* VideoCaptureNotify = NULL);
	~FIPCameraCapture();

	//初始化视频采集设备
	virtual int Init(const char* url);

	//开始采集视频数据
	virtual int Start();

	//停止采集视频数据
	virtual int Stop();

	//获取采集视频宽度
	int GetWidth() {
		return m_width;
	}

	//获取采集视频高度
	int GetHeight() {
		return m_height;
	}

	//获取采集视频帧率
	int GetFps() {
		return m_fps;
	}

	//获取采集视频类型
	int GetVideoType() {
		return m_videotype;
	}

private:
	//采集线程函数
	void Record_Thread();

	//资源释放函数
	void Clean_ALL();


private:
	std::atomic_bool m_running = false;
	std::atomic_bool m_inited = false;

	std::thread m_thread;

	AVFormatContext* m_fmt_ctx = NULL;
	AVCodecContext* m_codec_ctx = NULL;
	AVCodec* m_codec = NULL;
	int m_stream_index = -1;

	//采集视频属性 宽 高 帧率 视频格式 如 rgb bgr rgba  
	int m_width = 0;
	int m_height = 0;
	int m_fps = 0;
	int m_videotype = 0;

	FIPCameraCaptureNotify* m_videoCaptureNotify = NULL;

};

5.SDL创建窗口并渲染

/*************************************************************************************
* 项目 :		FFmpeg 获取网络摄像头的流 并渲染显示
* 类名 :		FRenderer
* 功能 :		渲染器 创建窗口以及渲染纹理显示
* 时间 :		2020/5/15  15:15
* 接口返回值 :  该项目所有返回值类型为 int 的 返回值  -1 代表失败  0 代表成功
***************************************************************************************/

#pragma once
class AVFrame;
class SDL_Window;
class SDL_Renderer;
class SDL_Texture;

class FRenderer
{
public:
	FRenderer();
	~FRenderer();

	//初始化视频渲染器
	virtual int Init(int windows_w = 320,int windows_h = 240);

	//渲染一帧视频
	virtual int RenderFrame(AVFrame *frame , int videoType);

private:

	//释放所有资源
	void Clean_All();

	//判断视频格式是否为 yuv420p
	bool IsYUV(int videotype);

private:
	//SDL 窗口  渲染器   纹理
	SDL_Window*   m_window   = nullptr;
	SDL_Renderer* m_renderer = nullptr;
	SDL_Texture*  m_texture = nullptr;

	//采集视频属性 宽 高 帧率   FFmpeg的纹理格式 如 rgb bgr rgba  yuv420p .....
	int m_width = 0;
	int m_height = 0;
	int m_videotype = 0;
};

6.控制器

/*************************************************************************************
* 项目 :		FFmpeg 获取网络摄像头的流 并渲染显示
* 类名 :		FCameraContrl
* 功能 :		控制器
* 时间 :		2020/5/15  15:15
* 接口返回值 :  该项目所有返回值类型为 int 的 返回值  -1 代表失败  0 代表成功
***************************************************************************************/

#pragma once
#include "FIPCameraCapture.h"
#include "FRenderer.h"

#define   SAVE_H264

class FCameraContrl : public FIPCameraCaptureNotify
{
public:
	FCameraContrl();
	~FCameraContrl();

	//开始拉流显示
	virtual bool Start(const char* url);

	//结束拉流显示
	virtual void Stop();

	//输出解码视频数据包的回调  一帧数据回调进入渲染显示
	void OnIOVideoDecNotifyFrame(AVFrame* frame);

	//输出解码视频数据包的回调  一帧H264数据 进行网络传输 测试可以将回调的数据保存到一个文件
	void OnIOVideoEndNotifyFrame(unsigned char* data, int size, long long pts);

private:
	//释放所有资源
	void Clean_All();

private:
	FIPCameraCapture* m_ipCameraCapture = NULL;
	FRenderer* m_renderer = NULL;

#ifdef SAVE_H264
	FILE* file = NULL;
#endif

};


7.进行网络传输的H264

播放器播放保存的H264
雷神的分析工具真滴好用

结论

1.读取一帧H264数据然后直接解码如果直接显示,结果就是显示会出现卡顿现象
解决方案:根据frame的pts来控制这帧的显示时间
2.进行网络传输的H264数据必须加 sps /pps 头 ,可以在每一个I帧前加上
3.有问题要交流的可以加qq群  626718812

猜你喜欢

转载自blog.csdn.net/qq_34940879/article/details/106354822