SDL 学习笔记

SDL 学习笔记

目录

SDL 学习笔记

测试案例

显示图片案例

纹理与渲染案例

纹理与渲染图片案例

加载PNG图片

播放音频示例(使用扩展库SDL_mixer)

播放YUV视频示例

播放自定义YUV数据

事件机制

测试案例

  • 初始化:
    • SDL_Init(): 初始化 SDL。
    • SDL_CreateWindow(): 创建窗口(Window)。
    • SDL_CreateRenderer(): 基于窗口创建渲染器(Render)。
    • SDL_CreateTexture(): 创建纹理(Texture)。
  • 循环渲染数据:
    • SDL_UpdateTexture(): 设置纹理的数据。
    • SDL_RenderCopy(): 纹理复制给渲染器。
    • SDL_RenderPresent(): 显示。
  • 退出:
    • SDL_DestroyWindow()
    • SDL_DestroyRenderer();
    • SDL_DestroyTexture();
    • SDL_Quit();
  • SDL 的“标准库” 
    • SDL_image—支持时下流行的图像格式:BMP、PPM、XPM、 PCX、GIF、JPEG、PNG、TGA。 
    • SDL_mixer—更多的声音输出函数以及更多的声音格式支持。 
    • SDL_net—网络支持。 
    • SDL_ttf—TrueType 字体渲染支持。 
    • SDL_rtf—简单的 RTF 渲染支持。
  • 测试程序1:
#include <iostream>

extern "C" {
#include "SDL.h"
}

#undef main

int main()
{
	printf("Initialize SDL\n");
	if (SDL_Init(SDL_INIT_EVERYTHING) == -1)
		return(1);

	printf("Delay 2 seconds\n");
	SDL_Delay(2000);

	printf("Quit SDL\n");
	SDL_Quit();

	return 0;
}
  • 输出:

  •  注:qt 搭建根据具体的相对路径,这里是
INCLUDEPATH+=../SDL2/include
LIBS += -L../SDL2/lib/x86 -lSDL2 -lSDL2_image -lSDL2_mixer

显示图片案例

#include <iostream>

extern "C" {
#include "SDL.h"
}

#undef main

const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;

int main()
{
	//The window we'll be rendering to
	SDL_Window* gWindow = NULL;

	//The surface contained by the window
	SDL_Surface* gScreenSurface = NULL;

	//The image we will load and show on the screen
	SDL_Surface* gHelloWorld = NULL;

	//首先初始化   初始化SD视频子系统
	if (SDL_Init(SDL_INIT_VIDEO) < 0)
	{
		printf("Window could not be created! SDL_Error: %s\n", SDL_GetError());
		return false;
	}
	//创建窗口
	gWindow = SDL_CreateWindow("SHOW BMP",//窗口标题
		SDL_WINDOWPOS_UNDEFINED,//窗口位置设置
		SDL_WINDOWPOS_UNDEFINED,
		SCREEN_WIDTH,//窗口的宽度
		SCREEN_HEIGHT,//窗口的高度
		SDL_WINDOW_SHOWN//显示窗口
	);
	if (gWindow == NULL)
	{
		printf("Window could not be created! SDL_Error: %s\n", SDL_GetError());
		return false;
	}
	//Use this function to get the SDL surface associated with the window.
	//获取窗口对应的surface
	gScreenSurface = SDL_GetWindowSurface(gWindow);

	//加载图片
	gHelloWorld = SDL_LoadBMP("./Hello_World.bmp");//加载图片
	if (gHelloWorld == NULL)
	{
		printf("Unable to load image %s! SDL Error: %s\n", "Hello_World.bmp", SDL_GetError());
		return false;
	}
	//Use this function to perform a fast surface copy to a destination surface.
	//surface的快速复制
	//下面函数的参数分别为: SDL_Surface* src ,const SDL_Rect* srcrect , SDL_Surface* dst ,  SDL_Rect* dstrect
	SDL_BlitSurface(gHelloWorld, NULL, gScreenSurface, NULL);
	SDL_UpdateWindowSurface(gWindow);//更新显示copy the window surface to the screen
	SDL_Delay(2000);//延时2000毫秒,2s后自动关闭

					//释放内存
	SDL_FreeSurface(gHelloWorld);//释放空间
	gHelloWorld = NULL;

	SDL_DestroyWindow(gWindow);//销毁窗口
	gWindow = NULL;

	SDL_Quit();//退出SDL

	return 0;
}
  • 显示:

纹理与渲染案例

  • SDL 视频渲染主要涉及到四个对象:
    • SDL_WindowSDL_RenderSDL_Texture SDL_Surface
  • 初始化:
    • SDL_Init(): 初始化 SDL。
    • SDL_CreateWindow(): 创建窗口(Window)。
    • SDL_CreateRenderer(): 基于窗口创建渲染器(Render)。
    • SDL_CreateTexture():
    • 创建纹理(Texture)。
  • 循环渲染数据:
    • SDL_UpdateTexture():
    • 设置纹理的数据。
    • SDL_RenderCopy(): 纹理复制给渲染器。
    • SDL_RenderPresent(): 显示。
  • 使用 SDL_Texture 将视频纹理渲染出来。
#include <iostream>

extern "C" {
#include "SDL.h"
}

#undef main

int main()
{
	SDL_Window *window;
	SDL_Renderer *renderer;
	SDL_Texture *texture;
	SDL_Event event;
	SDL_Rect r;

	if (SDL_Init(SDL_INIT_VIDEO) < 0) {
		SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s", SDL_GetError());
		return 3;
	}

	window = SDL_CreateWindow("SDL_CreateTexture",
		SDL_WINDOWPOS_UNDEFINED,
		SDL_WINDOWPOS_UNDEFINED,
		1024, 768,
		SDL_WINDOW_RESIZABLE);

	r.w = 100;
	r.h = 100;

	/// render---->window
	renderer = SDL_CreateRenderer(window, -1, 0);

	/// texture-->render
	texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, 1024, 768);

	// 跳来跳去的方块
	while (1) {
		SDL_PollEvent(&event);
		if (event.type == SDL_QUIT)
			break;
		r.x = rand() % 500;
		r.y = rand() % 500;

		SDL_SetRenderTarget(renderer, texture);
		SDL_SetRenderDrawColor(renderer, 0x88, 0x88, 0x88, 0x00);
		/// 将上一次render中的内容清空
		SDL_RenderClear(renderer);

		SDL_RenderDrawRect(renderer, &r);
		SDL_SetRenderDrawColor(renderer, 0x00, 0xFF, 0x00, 0x00);
		SDL_RenderFillRect(renderer, &r);
		SDL_SetRenderTarget(renderer, NULL);

		/// core: 复制内容
		SDL_RenderCopy(renderer, texture, NULL, NULL);
		SDL_RenderPresent(renderer);

		SDL_Delay(1000);
	}

	/// 清理、释放
	SDL_DestroyRenderer(renderer);
	SDL_DestroyWindow(window);
	SDL_Quit();
	return 0;
}

纹理与渲染图片案例

#include "SDL.h"
}

#undef main

int main()
{
	SDL_Init(SDL_INIT_VIDEO);

	SDL_Window*window = SDL_CreateWindow(
		"显示bmp图片", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
		640, 480, SDL_WINDOW_SHOWN);

	SDL_Renderer*renderer = SDL_CreateRenderer(
		window, -1, SDL_RENDERER_ACCELERATED);

	SDL_RenderClear(renderer);

	SDL_Surface*surface = SDL_LoadBMP("./Hello_world.bmp");

	SDL_Rect box = { 0, 0, surface->w - 50, surface->h - 50 };

	/// 将 图片的surface 关联到 一个新的 纹理中
	SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);

	/// 复制 纹理中数据 到 渲染器
	SDL_RenderCopy(renderer, texture, &box, &box);

	/// 刷新 渲染器
	SDL_RenderPresent(renderer);

	SDL_Delay(2000);

	/// 清理、释放
	SDL_FreeSurface(surface);
	SDL_DestroyTexture(texture);
	SDL_DestroyRenderer(renderer);
	SDL_DestroyWindow(window);
	SDL_Quit();

	return 0;
}

加载PNG图片

  • 1. 初始化
  • 2. 创建窗口:CreateWindow
  • 3. 创建 渲染器(window)
  • 4. 加载 图片(“path”)(IMG_XXX-->Init, Load, Quit)
  • 5. 创建 纹理(render, bmp)
  • 6. 复制 纹理 到 渲染器 RenderCopy
  • 7. 刷新 渲染器(RenderPresent)
  • 8. 退出(释放、清理)
#include <iostream>

extern "C" {
#include "SDL.h"
#include "SDL_image.h"
}

#undef main

int main()
{
	bool quit = false;
	SDL_Event event;

	//SDL初始化,这里只显示图片,所以只初始化VIDEO系统,更多的支持查看官方文档
	SDL_Init(SDL_INIT_VIDEO);
	//为了显示png图片,额外使用了图片库,所以要单独初始化
	IMG_Init(IMG_INIT_JPG | IMG_INIT_PNG);

	//建立SDL窗口
	SDL_Window * window = SDL_CreateWindow("SDL2 Displaying Image",
		SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, 0);
	//渲染层
	SDL_Renderer * renderer = SDL_CreateRenderer(window, -1, 0);
	//如果只是显示一张bmp图片,使用sdl内置的功能即可
	//SDL_Surface * image = SDL_LoadBMP("only_support_BMP.bmp");
	//因为要显示png图片,所以使用了外部库,sdl_image库当前支持jpg/png/webp/tiff图片格式
	SDL_Surface * image = IMG_Load("Hello_world.png");
	//载入的图片生成SDL贴图材质
	SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer, image);

	while (!quit)
	{//主消息循环
		SDL_WaitEvent(&event);

		switch (event.type)
		{	//用户从菜单要求退出程序
		case SDL_QUIT:
			quit = true;
			break;
		}

		//如果指定显示位置使用下面注释起来的两句
		//SDL_Rect dstrect = { 5, 5, 320, 240 };
		//SDL_RenderCopy(renderer, texture, NULL, &dstrect);
		//把贴图材质复制到渲染器
		SDL_RenderCopy(renderer, texture, NULL, NULL);

		//显示出来:刷新渲染器
		SDL_RenderPresent(renderer);
	}


	//典型的三明治结构,清理各项资源
	SDL_DestroyTexture(texture);
	SDL_FreeSurface(image);
	SDL_DestroyRenderer(renderer);
	SDL_DestroyWindow(window);
	//退出image库
	IMG_Quit();
	//退出SDL
	SDL_Quit();

	return 0;
}

播放音频示例(使用扩展库SDL_mixer

  • 1. 初始化: Mix_Chunk
  • 2. 打开音频: Mix_OpenAudio
  • 3. 加载音频文件 wav:Mix_LoadWAV
  • 4. 播放音频:Mix_PlayChannel,Mix_Playing
  • 5. 退出(清理、释放):Mix_CloseAudio, Mix_FreeChunk
#include <iostream>

extern "C" {
#include "SDL.h"
#include "SDL_mixer.h"
}

#undef main

int main()
{
	SDL_Surface *screen = NULL;         //Pointer to the main screen surface
	Mix_Chunk *sound = NULL;			//Pointer to our sound, in memory
	int channel;						//Channel on which our sound is played

	int audio_rate = 22050;         //Frequency of audio playback
	Uint16 audio_format = AUDIO_S16SYS;     //Format of the audio we're playing
	int audio_channels = 2;         //2 channels = stereo
	int audio_buffers = 4096;       //Size of the audio buffers in memory

									//Initialize BOTH SDL video and SDL audio
	if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) != 0) {
		printf("Unable to initialize SDL: %s\n", SDL_GetError());
		return 1;
	}

	//Initialize SDL_mixer with our chosen audio settings
	if (Mix_OpenAudio(audio_rate, audio_format, audio_channels, audio_buffers) != 0) {
		printf("Unable to initialize audio: %s\n", Mix_GetError());
		exit(1);
	}

	//Load our WAV file from disk
	sound = Mix_LoadWAV("sound.wav");
	if (sound == NULL) {
		printf("Unable to load WAV file: %s\n", Mix_GetError());
	}

	//Set the video mode to anything, just need a window
	SDL_Window *pWindow = SDL_CreateWindow("My Game Window",
		SDL_WINDOWPOS_UNDEFINED,
		SDL_WINDOWPOS_UNDEFINED,
		640, 480,
		SDL_WINDOW_SHOWN);
	if (pWindow) {
		screen = SDL_GetWindowSurface(pWindow);
	}
	if (screen == NULL) {
		printf("Unable to set video mode: %s\n", SDL_GetError());
		return 1;
	}

	//Play our sound file, and capture the channel on which it is played
	channel = Mix_PlayChannel(-1, sound, 0);
	if (channel == -1) {
		printf("Unable to play WAV file: %s\n", Mix_GetError());
	}

	//Wait until the sound has stopped playing
	while (Mix_Playing(channel) != 0);

	//Release the memory allocated to our sound
	Mix_FreeChunk(sound);

	//Need to make sure that SDL_mixer and SDL have a chance to clean up
	Mix_CloseAudio();
	SDL_Quit();

	//Return success!
	return 0;
}
  • 示例2
Uint8* g_audio_chunk;
Uint32 g_audio_len;
Uint8* g_audio_pos;

const static uint32_t PCM_BUFFER_SIZE = 4096;
//ffplay.exe -ar 44100 -ac 2 -f s16le -i xxx_44.1k_s16le.pcm
const static std::string PCM_PATH = "gu10s-s16le-44100.pcm";

//数据到来的回调函数
void read_audio_data_cb(void* udata, Uint8* stream, int len)
{
	SDL_memset(stream, 0, len);
	if (g_audio_len == 0)
		return;
	len = std::min(len, static_cast<int>(g_audio_len));
	/// 将pcm音频数据送到声卡,最后一个参数控制 音量
	SDL_MixAudio(stream, g_audio_pos, len, SDL_MIX_MAXVOLUME/2);// 0---128
	g_audio_pos += len;
	g_audio_len -= len;
}

int mian_MixAudio()
{
	SDL_Init(SDL_INIT_AUDIO);   //init

	SDL_AudioSpec spec;
	spec.freq = 44100;
	spec.format = AUDIO_S16SYS;
	spec.channels = 2;
	spec.samples = 1024;
	spec.callback = read_audio_data_cb;
	spec.userdata = NULL;
	//根据参数,打开音频设备
	if (SDL_OpenAudio(&spec, NULL) < 0)
		return -1;

	//打开文件
	std::ifstream pcm(PCM_PATH.c_str(), std::ios::in | std::ios::binary);
	if (!pcm.is_open())
		return -1;
	char* pcm_buffer = (char*)malloc(PCM_BUFFER_SIZE);
	//开始播放
	SDL_PauseAudio(0);

	while (!pcm.eof())
	{
		pcm.read(pcm_buffer, PCM_BUFFER_SIZE);
		if (pcm.bad())
			break;
		g_audio_chunk = reinterpret_cast<Uint8*>(pcm_buffer);
		g_audio_len = pcm.gcount();                           //读取到的字节数
		g_audio_pos = g_audio_chunk;
		std::cout << "play " << g_audio_len << " data" << std::endl;
		while (g_audio_len > 0)       //等待audio_len长度的数据播放完成  
			SDL_Delay(1);
	}

	free(pcm_buffer);
	SDL_Quit();

	return 0;
}

播放YUV视频示例

#include <iostream>
#include <stdlib.h>
#include <string.h>
using namespace std;

extern "C" {
#include "SDL.h"
}
#undef main

static const int width = 352;
static const int height = 288;

static SDL_Window *window = nullptr;
static SDL_Renderer *ren = nullptr;

int main(int argc, char **argv)
{
	string filename = "background.bmp";
	SDL_Event        event;
	SDL_bool         done = SDL_FALSE;
	Uint32           pixel_format = SDL_PIXELFORMAT_IYUV;
	int frame_number = 0;
	/// c语言函数:fopen, "rb":只读,二进制
	/// 如果去掉“b”,文本模式读取,遇到“\0”,就会自动退出
	FILE *fp = fopen("ande_352x288_yuv420p.yuv", "rb");//ande_352x288_yuv420p//out1_352x288
	if (!fp)
	{
		return -1;
	}

	SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);

	//if (SDL_Init(SDL_INIT_EVERYTHING) != 0){
	if (SDL_Init(SDL_INIT_VIDEO) != 0) {
		SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError());
		return 3;
	}

	/// 创建窗口
	SDL_Window *win = SDL_CreateWindow("Hello", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_SHOWN);
	if (win == nullptr)
	{
		SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't set create window: %s\n", SDL_GetError());
		return 1;
	}

	/// 创建渲染器
	ren = SDL_CreateRenderer(win, 0, 0); //渲染器 底层,打底
	if (ren == nullptr)
	{
		SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't set create renderer: %s\n", SDL_GetError());
		return 1;
	}

	/// 创建纹理
	SDL_Texture *tex = SDL_CreateTexture(ren, pixel_format, SDL_TEXTUREACCESS_STREAMING, width, height);
	int len = height*width;
	Uint8* buf = (Uint8*)malloc(len * 2);

	int iPitch = width * SDL_BYTESPERPIXEL(pixel_format);
	printf("IPath %d\n", iPitch);
	SDL_Rect rec;
	rec.x = 0;
	rec.y = 0;
	rec.w = width;
	rec.h = height;
	int nRets = 0;
	while (!done)
	{
		while (SDL_PollEvent(&event)) {
			switch (event.type) {
			case SDL_KEYDOWN:
				if (event.key.keysym.sym == SDLK_ESCAPE) {
					done = SDL_TRUE;
				}
				break;
			case SDL_QUIT:
				done = SDL_TRUE;
				break;
			}
		}
		/// 注意:每次需要的字节数: width*height*1.5
		/// Y:  width*height: Bytes
		/// cb: width*height / 4
		/// cr: width*height / 4
		nRets = fread(buf, 1, height*width * 3 / 2, fp);

		if (nRets < 0) {
			break;
		}
		//printf("lee = %d\n",lee);

		/// 用buf缓冲区数据 更新 纹理
		SDL_UpdateTexture(tex, NULL, buf, iPitch);

		/*	刷新渲染器:三部曲:clear, copy, present */
		SDL_RenderClear(ren);
		SDL_RenderCopy(ren, tex, NULL, &rec);
		SDL_RenderPresent(ren);
		frame_number++;
		/// 音视频同步: 休眠
		SDL_Delay(40);  1S = 1000ms, 1000 / 40 = 25 fps(帧率:每秒25帧)

	}

	/// 退出:清理资源
	SDL_Delay(2000);
	SDL_DestroyTexture(tex);
	SDL_DestroyRenderer(ren);
	SDL_DestroyWindow(win);
	SDL_Quit();
	fclose(fp);
	return 0;
}

播放自定义YUV数据

#include <stdio.h>
#include <Windows.h>
extern "C" {
#include "SDL.h"
}

#undef main

#pragma comment(lib, "SDL2.lib")
#pragma comment(lib, "SDL2main.lib")

/* Prepare a dummy image.:填充随机颜色 */
static void FillYuvImage(BYTE* pYuv, int nWidth, int nHeight, int nIndex)
{
	int x, y, i;

	i = nIndex;

	BYTE* pY = pYuv;
	BYTE* pU = pYuv + nWidth * nHeight;
	BYTE* pV = pYuv + nWidth * nHeight * 5 / 4;

	/* Y */
	for (y = 0; y < nHeight; y++)
	{
		for (x = 0; x < nWidth; x++)
		{
			pY[y * nWidth + x] = x + y + i * 2;//+ y 
		}
	}

	/* Cb and Cr */
	for (y = 0; y < nHeight / 2; y++)
	{
		for (x = 0; x < nWidth / 2; x++)
		{
			pU[y * (nWidth / 2) + x] = 64 + y + i * 2;
			pV[y * (nWidth / 2) + x] = 64 + x + i * 5;
		}
	}
}

int main(int argc, char* argv[])
{
	if (SDL_Init(SDL_INIT_VIDEO))
	{
		printf("Could not initialize SDL - %s\n", SDL_GetError());
		return -1;
	}

	// 提升图像质量,否则默认缩放质量会有毛剌
	SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1");

	SDL_Window*   window = SDL_CreateWindowFrom(::GetConsoleWindow());
	SDL_Renderer* render = SDL_CreateRenderer(window, -1, 0);

	const int W = 1920;
	const int H = 1080;

	SDL_Texture*  texture = SDL_CreateTexture(render, SDL_PIXELFORMAT_YV12, SDL_TEXTUREACCESS_STREAMING, W, H);

	/// yuv 420P : planer
	static BYTE Yuv[W*H * 2];
	BYTE* pY = Yuv;
	BYTE* pU = Yuv + W*H;
	BYTE* pV = Yuv + W*H * 5 / 4;

	int index = 0;

	while (true)
	{
		FillYuvImage(Yuv, W, H, index++);///填充随机颜色

		int e = SDL_UpdateYUVTexture(texture, NULL,
			pY, W,
			pU, W / 2,
			pV, W / 2);

		/// 刷新渲染器:三部曲: clear, copy, present
		SDL_RenderClear(render);
		SDL_RenderCopy(render, texture, NULL, NULL);
		SDL_RenderPresent(render);
		Sleep(40);
	}

	SDL_DestroyTexture(texture);
	SDL_DestroyRenderer(render);
	//SDL_DestroyWindow(window);
	SDL_Quit();

	return 0;
}

事件机制

  •  示例1:
#include <SDL.h>

#undef main

int main__event2(int, char**)///__event2
{
	SDL_Init(SDL_INIT_EVERYTHING);
	SDL_Window* win = SDL_CreateWindow("yx3sxmeng", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, SDL_WINDOW_SHOWN);
	SDL_Renderer* renderer = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED);
	SDL_Surface* surface = SDL_LoadBMP("./Hello_world.bmp");
	SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);

	///1. window-->render(GPU, window),  surface内存信息(bitmap), texture描述信息(render, bitmap|surface);


	///2. SDL事件循环机制 
	bool quit = false;
	SDL_Event ev;
	SDL_Rect rect = { 0,0,800,600 };///目标位置大小(x,y, w,h);
	int sx = 0, sy = 0;
	while (!quit)
	{
		while (SDL_PollEvent(&ev))
		{
			switch (ev.type)
			{
			case SDL_QUIT:
				quit = true;
				break;
			case SDL_MOUSEBUTTONDOWN:
				sx = ev.button.x + rect.x;
				sy = ev.button.y + rect.y;
				break;
			case SDL_MOUSEMOTION:
				if (ev.motion.state & SDL_BUTTON_LMASK)
				{
					rect.x = ev.motion.x - sx;
					rect.y = ev.motion.y - sy;
				}
				break;

			case SDL_KEYDOWN:

				if (ev.key.keysym.sym == SDLK_LEFT)
				{
					rect.x -= 10;
					printf("SDLK_LEFT...");
				}
				else if (ev.key.keysym.sym == SDLK_RIGHT)
				{
					printf("SDLK_RIGHT...");
					rect.x += 10;

				}
				else if (ev.key.keysym.sym == SDLK_UP)
				{
					printf("SDLK_UP...");
					rect.w += 10;
					rect.h += 10;
				}
				else if (ev.key.keysym.sym == SDLK_DOWN)
				{
					printf("SDLK_DOWN...");
					rect.w -= 10;
					rect.h -= 10;
				}
				printf("scancode=%d\n", ev.key.keysym.scancode);
				break;

			case SDL_MOUSEWHEEL:
				if (ev.wheel.y > 0)
				{
					rect.h *= 1.1;
					rect.w *= 1.1;
				}
				if (ev.wheel.y < 0)
				{
					rect.w /= 1.1;
					rect.h /= 1.1;
				}
				break;
			}
		}
		SDL_RenderClear(renderer);
		SDL_RenderCopy(renderer, texture, NULL, &rect);
		SDL_RenderPresent(renderer);
		SDL_Delay(16);
	}

	//释放资源
	SDL_DestroyTexture(texture);
	SDL_DestroyRenderer(renderer);
	SDL_DestroyWindow(win);

	SDL_Quit();
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Iperf是一个用于测试网络带宽的工具。可以使用iperf命令来启动服务器端或客户端进行测试。通过指定不同的选项和参数,可以进行不同类型的测试,如TCP或UDP的测试。例如,可以使用以下命令启动一个UDP测试:iperf -u -c 10.10.10.10 -b 100M -t 99999 -i 1 -l 1470 -P 5。其中,-u表示使用UDP协议,-c指定了服务器端的IP地址,-b指定了带宽大小,-t指定了测试的时间,-i指定了输出结果的间隔时间,-l指定了数据包的大小,-P指定了并发连接的数量。 如果需要查看iperf的详细命令行参考,可以使用-h或--help选项。例如在Linux系统中,可以使用命令iperf3 -h来获取帮助信息。 安装iperf可以通过下载源代码进行编译安装。首先需要下载iperf源代码,然后使用gunzip解压缩,接着使用tar命令解压缩文件,最后进入解压后的目录,执行./configure、make和make install命令进行配置和安装。 总结来说,iperf是一个用于测试网络带宽的工具,可以使用不同的选项和参数进行不同类型的测试。可以通过-h或--help选项获取iperf的命令行参考。安装iperf可以通过下载源代码进行编译安装。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [【5G】Linux iperf 学习笔记](https://blog.csdn.net/u013865052/article/details/126419967)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [【山外笔记-工具框架】Iperf3网络性能测试工具详解教程](https://blog.csdn.net/sdl0928/article/details/105582927)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值