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;
}
相关推荐
紫金修道20 小时前
【编解码】RK3588 平台基于 FFmpeg RKMPP 硬解的多路 RTSP 抓帧插件实战
ffmpeg·rkmpp
电子科技圈21 小时前
赋能高端音频功能促进多样化设备创新——XMOS USB Audio平台实现四大功能升级
人工智能·mcu·音视频·智能家居·边缘计算·语音识别·智能硬件
EasyDSS21 小时前
视频高清直播点播/云点播/云直播EasyDSS:一站式视频云平台全链路整合,重塑企业视频应用新生态
音视频
jwybobo200721 小时前
AV1 码流 RTP 封装
音视频·av1
愚公搬代码1 天前
【愚公系列】《剪映+DeepSeek+即梦:短视频制作》055-即梦+DeepSeek生成AI视频(文生视频案例)
人工智能·音视频
l14372332671 天前
AI电影解说的技术链路拆解:从视频理解到自动剪辑
人工智能·音视频
飞睿科技1 天前
ESP32-S31 高性能 AIoT SoC 在智能音频领域的应用实践
音视频·esp32·智能家居·乐鑫科技·ai智能
AI2512241 天前
免费AI视频生成工具技术解析与功能对比
人工智能·音视频
EasyCVR1 天前
国标GB28181视频监控平台EasyCVR视频质量诊断赋能智慧城市精细化治理
人工智能·音视频·智慧城市
炭烤毛蛋1 天前
rk3588 适配音频解码芯片 es8388
arm开发·音视频·rk3588·es8388