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
结论
1.读取一帧H264数据然后直接解码如果直接显示,结果就是显示会出现卡顿现象
解决方案:根据frame的pts来控制这帧的显示时间
2.进行网络传输的H264数据必须加 sps /pps 头 ,可以在每一个I帧前加上