SDL2的渲染

使用SDL2播放视频时需要通过渲染操作令视频的每一帧在窗口的显示。

SDL播放视频的流程如下图所示:

初始化组件:

SDL_Init();          //初始化SDL
SDL_CreateWindow();    //创建播放器的窗口
SDL_CreateRenderer();    //创建基于窗口的渲染器
SDL_CreateTexture();    //创建基于渲染器与视频格式的纹理

循环渲染:

SDL_UpdateTexture();  //设置纹理的数据
SDL_RenderCopy();    //将纹理复制给渲染器
SDL_RenderPresent();  //使用渲染器进行显示

初始化组件

SDL_Init(SDL_INIT_VIDEO);

由于我们想实现一个播放器,所以SDL的子系统设成视频。

        window = SDL_CreateWindow("Simplest YUV Player",
		SDL_WINDOWPOS_UNDEFINED,
		SDL_WINDOWPOS_UNDEFINED,
		video_width, video_height,
		SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);

窗口主要仅和视频的长和宽有关。

renderer = SDL_CreateRenderer(window, -1, 0);

创建渲染器,渲染器可见也是基于窗口进行初始化的。

        texture = SDL_CreateTexture(renderer,
		pixformat,
		SDL_TEXTUREACCESS_STREAMING,
		video_width,
		video_height);

创建纹理,可以看到纹理的创建与渲染器renderer,视频的格式pixformat与视频的长宽video_width,video_height相关,实际上从源码中可以看出,纹理的创建使用了渲染器renderer的组件。

循环渲染

SDL_UpdateTexture(texture, NULL, video_buf, video_width);

以上代码实现了纹理的更新,设置纹理的像素数据,这里需要注意一个变量video_buf。

    // 分配空间
	video_buf = (uint8_t*)malloc(yuv_frame_len);
	if (!video_buf)
	{
		fprintf(stderr, "Failed to alloce yuv frame space!\n");
		goto _FAIL;
	}

video_buf是特别创建的一个缓冲区,视频会先放在缓冲区内,再交给纹理进行更新。

            // 清除当前显示
			SDL_RenderClear(renderer);
			// 将纹理的数据拷贝给渲染器
			SDL_RenderCopy(renderer, texture, NULL, &rect);
			// 显示
			SDL_RenderPresent(renderer);

纹理更新完毕后会将纹理的数据拷贝给渲染器,交由渲染器进行显示。

在SDL_RenderCopy()函数中,第三个第四个参数需要注意下。

第三个参数:选择输入纹理的一块矩形区域作为输入,设置为null时整个纹理输入。

第四个参数:选择渲染目标的一块矩形区域作为输出,设置为null时整个渲染目标输出。

我们可以理解为纹理就是原视频文件的图像,渲染目标是播放器中显示的输出图像。

因此,一般原视频文件的图像是要全部读取的,而输出的图像大小还需要取决于当前播放器窗口的大小,因此第四个参数通常是可调整的,而第三个参数一般是null。

    // 1. YUV的分辨率
	int video_width = YUV_WIDTH;
	int video_height = YUV_HEIGHT;
	// 2.显示窗口的分辨率
	int win_width = YUV_WIDTH;
	int win_height = YUV_WIDTH;

    // 显示区域,可以通过修改w和h进行缩放
	rect.x = 0;
	rect.y = 0;
	float w_ratio = win_width * 1.0 / video_width;
	float h_ratio = win_height * 1.0 / video_height;
	// 320x240 怎么保持原视频的宽高比例
	rect.w = video_width * w_ratio;
	rect.h = video_height * h_ratio;

第四个参数使用SDL_Rect类型的rect变量进行表示。

当窗口大小相对视频的长宽大小出现变化时,需要根据变化比例,对渲染输出的目标,即显示的视频长宽也进行相应的调整。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SDL2.0 支持渲染 YUV4:2:0 格式的视频,需要使用 SDL_Texture 和 SDL_RenderCopy 函数来实现。 以下是一个简单的示例代码: ```c #include <SDL2/SDL.h> #include <stdio.h> const int SCREEN_WIDTH = 640; const int SCREEN_HEIGHT = 480; int main(int argc, char* argv[]) { SDL_Window* window = NULL; SDL_Renderer* renderer = NULL; SDL_Texture* texture = NULL; if (SDL_Init(SDL_INIT_VIDEO) < 0) { printf("SDL could not initialize! SDL_Error: %s\n", SDL_GetError()); return 1; } window = SDL_CreateWindow("YUV4:2:0 Video", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN); if (window == NULL) { printf("Window could not be created! SDL_Error: %s\n", SDL_GetError()); return 1; } renderer = SDL_CreateRenderer(window, -1, 0); if (renderer == NULL) { printf("Renderer could not be created! SDL_Error: %s\n", SDL_GetError()); return 1; } texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_YV12, SDL_TEXTUREACCESS_STREAMING, SCREEN_WIDTH, SCREEN_HEIGHT); if (texture == NULL) { printf("Texture could not be created! SDL_Error: %s\n", SDL_GetError()); return 1; } // YUV data Uint8* yPlane = NULL; Uint8* uPlane = NULL; Uint8* vPlane = NULL; int yPitch = 0; int uPitch = 0; int vPitch = 0; int w = 0; int h = 0; // read YUV file FILE* fp = fopen("video.yuv", "rb"); if (fp == NULL) { printf("Could not open YUV file!\n"); return 1; } // allocate memory for YUV data int bufferSize = SCREEN_WIDTH * SCREEN_HEIGHT * 3 / 2; Uint8* buffer = (Uint8*)malloc(bufferSize); // main loop SDL_Event event; bool quit = false; while (!quit) { while (SDL_PollEvent(&event)) { if (event.type == SDL_QUIT) { quit = true; } } // read YUV data if (fread(buffer, 1, bufferSize, fp) != bufferSize) { // end of file rewind(fp); } // set YUV data yPlane = buffer; uPlane = yPlane + SCREEN_WIDTH * SCREEN_HEIGHT; vPlane = uPlane + SCREEN_WIDTH * SCREEN_HEIGHT / 4; yPitch = SCREEN_WIDTH; uPitch = SCREEN_WIDTH / 2; vPitch = SCREEN_WIDTH / 2; w = SCREEN_WIDTH; h = SCREEN_HEIGHT; // update texture SDL_UpdateYUVTexture(texture, NULL, yPlane, yPitch, uPlane, uPitch, vPlane, vPitch); // clear screen SDL_SetRenderDrawColor(renderer, 0xFF, 0xFF, 0xFF, 0xFF); SDL_RenderClear(renderer); // render texture SDL_RenderCopy(renderer, texture, NULL, NULL); // update screen SDL_RenderPresent(renderer); } // free memory free(buffer); // cleanup SDL_DestroyTexture(texture); SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); SDL_Quit(); return 0; } ``` 在代码中,我们首先创建一个 SDL 窗口和渲染器。然后,使用 SDL_CreateTexture 函数创建一个 YV12 格式的纹理。接下来,读取 YUV 文件,并将数据设置到纹理中。在主循环中,使用 SDL_RenderCopy 函数将纹理渲染到屏幕上。最后,记得在程序结束前释放所有内存和资源。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值