SDL直接渲染yuv视频帧数据

用ffmpeg解码出来的视频数据都是yuv视频帧,直接用sdl渲染可以有效的降低系统的cpu资源

直接上代码把

cpp 复制代码
SDLRender::SDLRender()
{
	SDL_Init(SDL_INIT_VIDEO);
	m_spN12Chech = std::make_shared<std::vector<uint8_t>>();
}
cpp 复制代码
bool SDLRender::DrawFrame(AVFrame *frame)
{
	std::unique_lock<std::mutex> locker(m_mtDrawFrame);
	if (!frame)
	{
		return false;
	}

	if (!m_SdlRender)
	{
		m_SdlRender = SDL_CreateRenderer(m_SdlWindow, -1, SDL_RendererFlags::SDL_RENDERER_ACCELERATED);
	}

	if (frame->width != m_tureWidth || frame->height != m_tureHeight || !m_SdlTexture)
	{
		m_tureWidth = frame->width;
		m_tureHeight = frame->height;

		if (m_SdlTexture)
		{
			SDL_DestroyTexture(m_SdlTexture);
			m_SdlTexture = nullptr;
		}
		
		m_SdlTexture = SDL_CreateTexture(m_SdlRender, GetSDLFormat((AVPixelFormat)frame->format), SDL_TEXTUREACCESS_STREAMING, frame->width, frame->height);
	}

	int linesize = 0;
	switch (frame->format)
	{
	case AV_PIX_FMT_YUVJ420P:
	case AV_PIX_FMT_YUV420P:
		return Draw(frame->data[0], frame->linesize[0], frame->data[1], frame->linesize[1], frame->data[2], frame->linesize[2]);
	case AV_PIX_FMT_NV12:
		if (m_spN12Chech)
		{
			m_spN12Chech->clear();
		}
		else
		{
			return false;
		}
		linesize = frame->width;
		if (frame->linesize[0] == frame->width)
		{
			// 拷贝所有Y分量
			m_spN12Chech->insert(m_spN12Chech->end(), frame->data[0], frame->data[0] + frame->linesize[0] * frame->height);
			// 拷贝所有的UV分量
			m_spN12Chech->insert(m_spN12Chech->end(), frame->data[1], frame->data[1] + frame->linesize[1] * frame->height/2);
		}
		return Draw(m_spN12Chech->data(), linesize);
	case AV_PIX_FMT_RGBA:
	case AV_PIX_FMT_BGRA:
	case AV_PIX_FMT_ARGB:
		return Draw(frame->data[0], frame->linesize[0]);
	default:
		break;
	}

	return false;
}
cpp 复制代码
bool SDLRender::Draw(const unsigned char* y, int y_pitch, const unsigned char* u, int u_pitch, const unsigned char* v, int v_pitch)
{
	if (!y || !u || !v)
	{
		return false;
	}

	std::unique_lock<std::mutex> locker(m_mtSdl);
	if (!m_SdlWindow || !m_SdlRender || !m_SdlTexture)
	{
		return false;
	}

	// 复制内存到显存
	auto re = SDL_UpdateYUVTexture(m_SdlTexture, NULL, y, y_pitch, u, u_pitch, v, v_pitch);
	if (re)
	{
		return false;
	}

	// 清理渲染器
	SDL_RenderClear(m_SdlRender);

	// 如果用户手动设置了缩放,就按照用户设置的大小显示
	// 如果用户没有设置,就传递null, 采用默认的窗口大小
	SDL_Rect* prect = nullptr;
	if (m_nScaleWidth > 0 || m_nScaleHeight > 0)
	{
		SDL_Rect rect;
		rect.x = 0;
		rect.y = 0;
		rect.w = m_nScaleWidth;
		rect.h = m_nScaleHeight;
		prect = &rect;
	}

	// 拷贝材质到渲染器
	re = SDL_RenderCopy(m_SdlRender, m_SdlTexture, NULL, prect);
	if (re)
	{
		return false;
	}

	SDL_RenderPresent(m_SdlRender);
	return true;
}
cpp 复制代码
bool SDLRender::Draw(const unsigned char* data, int linesize)
{
	if (!data)
	{
		return false;
	}

	std::unique_lock<std::mutex> locker(m_mtSdl);
	if (!m_SdlWindow || !m_SdlRender || !m_SdlTexture)
	{
		return false;
	}

	if (linesize <= 0)
	{
		return false;
	}

	// 复制内存到显存
	auto re = SDL_UpdateTexture(m_SdlTexture, NULL, data, linesize);
	if (re)
	{
		return false;
	}

	// 清理渲染器
	SDL_RenderClear(m_SdlRender);

	// 如果用户手动设置了缩放,就按照用户设置的大小显示
	// 如果用户没有设置,就传递null, 采用默认的窗口大小
	SDL_Rect *prect = nullptr;
	if (m_nScaleWidth > 0 || m_nScaleHeight > 0)
	{
		SDL_Rect rect;
		rect.x = 0;
		rect.y = 0;
		rect.w = m_nScaleWidth;
		rect.h = m_nScaleHeight;
		prect = &rect;
	}
	re = SDL_RenderCopy(m_SdlRender, m_SdlTexture, NULL, prect);
	if (re)
	{
		return false;
	}

	SDL_RenderPresent(m_SdlRender);
	return true;
}
相关推荐
肥or胖6 小时前
【音视频协议篇】WebRTC 快速入门
ffmpeg·音视频·webrtc
aqi007 小时前
FFmpeg开发笔记(七十八)采用Kotlin+Compose的NextPlayer播放器
android·ffmpeg·音视频·直播·流媒体
QMCY_jason10 小时前
Ubuntu 1804 编译ffmpeg qsv MediaSDK libva 遇到的问题记录
linux·ubuntu·ffmpeg
tang_jian_dong11 小时前
springboot + vue3 拉取海康视频点位及播放
spring boot·后端·音视频
青牛科技-Allen13 小时前
GC8871刷式直流电机驱动器深度解析:3.6A驱动与内置电流检测技术
单片机·嵌入式硬件·音视频·音响·电动工具·散热风扇·电脑散热风扇
Tracy9731 天前
HF83311_VB1/HF83311Q_VB1:高性能USB HiFi音频解码器固件技术解析
音视频·xmos 模组·xmos 模组固件
_可乐无糖1 天前
AWS WebRTC:我们的业务模式
云计算·音视频·webrtc·aws
Kandiy180253981871 天前
DP4871音频放大芯片3W功率单通道AB类立体声/音频放大器
音视频·音频·视频编解码