1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
|
#include <stdio.h>
extern "C"
{
#include "SDL2/SDL.h"
};
const int bpp = 12;
// 窗口的宽度和高度
int screen_w = 1000, screen_h = 1000;
// 视频像素的宽度和高度
const int pixel_w = 320, pixel_h = 180;
// 用于存储一帧 YUV 数据的缓冲区
unsigned char buffer[pixel_w * pixel_h * bpp / 8];
int main(int argc, char *argv[])
{
// 初始化 SDL 库
if (SDL_Init(SDL_INIT_VIDEO))
{
printf("Could not initialize SDL - %s\n", SDL_GetError());
return -1;
}
// 创建窗口
SDL_Window *screen;
// SDL 2.0 Support for multiple windows
// title 窗口标题,x y 窗口位置,w h 窗口大小
// flags 标志包括允许改变窗口大小(SDL_WINDOW_RESIZABLE)和使用OpenGL(SDL_WINDOW_OPENGL
screen = SDL_CreateWindow("Simplest Video Play SDL2", SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_UNDEFINED, screen_w, screen_h,
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
if (!screen)
{
printf("SDL: could not create window - exiting:%s\n", SDL_GetError());
return -1;
}
// 创建渲染器,将窗口与渲染器关联
// index 使用默认的渲染驱动,flags 标志为 0 (不使用加速功能)
SDL_Renderer *sdlRenderer = SDL_CreateRenderer(screen, -1, 0);
Uint32 pixformat = 0;
// IYUV: Y + U + V (3 planes)
// YV12: Y + V + U (3 planes)
// 设置像素格式
// SDL_PIXELFORMAT_IYUV 表示使用 YUV420
pixformat = SDL_PIXELFORMAT_IYUV;
// 创建纹理,用于存储视频数据
// pixformat 使用之前设置的像素格式 IYUV,access 纹理访问模式为流式访问(适合频繁更新纹理数据)
// w h 纹理宽度和高度
SDL_Texture *sdlTexture =
SDL_CreateTexture(sdlRenderer, pixformat, SDL_TEXTUREACCESS_STREAMING, pixel_w, pixel_h);
FILE *fp = NULL;
fp = fopen("../video/test_yuv420p_320x180.yuv", "rb+");
if (fp == NULL)
{
printf("cannot open this file\n");
return -1;
}
SDL_Rect sdlRect;
while (1)
{
// 从文件中读取一帧 YUV 数据到 buffer 中
if (fread(buffer, 1, pixel_w * pixel_h * bpp / 8, fp) != pixel_w * pixel_h * bpp / 8)
{
// 重新定位文件指针实现循环播放
fseek(fp, 0, SEEK_SET);
fread(buffer, 1, pixel_w * pixel_h * bpp / 8, fp);
}
// 更新纹理中的数据,将 buffer 中的内容传递给纹理
// pitch 每行像素占用的字节数
SDL_UpdateTexture(sdlTexture, NULL, buffer, pixel_w);
// 设置渲染区域
// 这表示这个矩形从屏幕的左上角(0, 0)开始,宽度和高度与屏幕相同,即覆盖整个屏幕
sdlRect.x = 10;
sdlRect.y = 10;
sdlRect.w = screen_w - 20;
sdlRect.h = screen_h - 20;
// 清楚渲染器
SDL_RenderClear(sdlRenderer);
// 复制纹理到渲染器
SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, &sdlRect);
// 呈现渲染结果
// 将渲染器中的后缓冲区内容呈现到前缓冲区,即更新屏幕显示内容
SDL_RenderPresent(sdlRenderer);
// 延迟以控制帧率
SDL_Delay(40);
}
SDL_Quit();
return 0;
}
|