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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
#include <stdio.h>
extern "C"
{
#include "SDL2/SDL.h"
};
const int bpp = 12;
int screen_w = 500, screen_h = 500;
const int pixel_w = 320, pixel_h = 180;
unsigned char buffer[pixel_w * pixel_h * bpp / 8];
// SDL_USEREVENT是SDL库中预定义的一个用户事件起始值
// 刷新事件
#define REFRESH_EVENT (SDL_USEREVENT + 1)
// 中断事件
#define BREAK_EVENT (SDL_USEREVENT + 2)
// 线程退出标志
int thread_exit = 0;
int refresh_video(void *opaque)
{
thread_exit = 0;
while (!thread_exit)
{
SDL_Event event;
event.type = REFRESH_EVENT;
SDL_PushEvent(&event);
SDL_Delay(40);
}
thread_exit = 0;
// 推送一个退出主线程的事件
SDL_Event event;
event.type = BREAK_EVENT;
SDL_PushEvent(&event);
return 0;
}
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
screen =
SDL_CreateWindow("Simplest Video Play SDL2", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
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;
}
// 创建一个渲染器,将窗口与渲染器关联
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;
// 创建纹理,用于存储视频数据
SDL_Texture *sdlTexture =
SDL_CreateTexture(sdlRenderer, pixformat, SDL_TEXTUREACCESS_STREAMING, pixel_w, pixel_h);
// 打开 YUV 文件
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;
// 创建一个子线程,用于定时触发视频刷新事件
// 第一个参数是函数指针
SDL_Thread *refresh_thread = SDL_CreateThread(refresh_video, NULL, NULL);
SDL_Event event;
while (1)
{
// 等待事件
SDL_WaitEvent(&event);
if (event.type == REFRESH_EVENT)
{
if (fread(buffer, 1, pixel_w * pixel_h * bpp / 8, fp) != pixel_w * pixel_h * bpp / 8)
{
// Loop
fseek(fp, 0, SEEK_SET);
fread(buffer, 1, pixel_w * pixel_h * bpp / 8, fp);
}
SDL_UpdateTexture(sdlTexture, NULL, buffer, pixel_w);
// FIX: If window is resize
sdlRect.x = 0;
sdlRect.y = 0;
sdlRect.w = screen_w/2;
sdlRect.h = screen_h/2;
SDL_RenderClear(sdlRenderer);
SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, &sdlRect);
SDL_RenderPresent(sdlRenderer);
}
// SDL_WINDOWEVENT 当窗口大小改变时,更新屏幕宽度和高度
else if (event.type == SDL_WINDOWEVENT)
{
// window
SDL_GetWindowSize(screen, &screen_w, &screen_h);
}
// 当用户关闭窗口时,设置退出标志使子线程退出
else if (event.type == SDL_QUIT)
{
thread_exit = 1;
}
// 当接收到退出事件时,退出主循环并释放资源
// 这个退出事件由子线程提供
else if (event.type == BREAK_EVENT)
{
break;
}
}
SDL_Quit();
return 0;
}
|