一、概述
上一节使用单线程播放了YUV文件。在一个线程中播放yuv文件逻辑看起来简单,但是会产生一些问题。如:视频卡顿、无响应等问题。
本节在上一节的基础上对播放YUV文件的代码进行改造,加入SDL_Event和SDL_Thread。使SDL_Thread现成发出命令时刷新YUV视频帧。等收到结束命令时退出整个应用程序
参考:雷霄骅大神的博客
二、代码示例
#include "include/sdl_read_yuv.h" #include <iostream> using namespace std; //Refresh Event #define REFRESH_EVENT (SDL_USEREVENT + 1) //Break #define BREAK_EVENT (SDL_USEREVENT + 2) int thread_exit = 0; int refresh_video(void* args) { thread_exit = 0; while (thread_exit == 0) { //每隔40毫秒推送一次刷新事件 SDL_Event event; event.type = REFRESH_EVENT; SDL_PushEvent(&event); SDL_Delay(40); } thread_exit = 0; //break SDL_Event event; event.type = BREAK_EVENT; SDL_PushEvent(&event);//将结束事件推送出去 return 0; } SDLReadYuv::SDLReadYuv() { //window窗体的宽高 int window_w = 640, window_h = 360; //像素的宽高 const int pixel_w = 640, pixel_h = 360; //设置一帧像素的容量 unsigned char buffer[pixel_w * pixel_h * 3/2]; if (SDL_Init(SDL_INIT_VIDEO)) { cout << "初始化SDL失败" << SDL_GetError() << endl; return; } SDL_Window* window; window = SDL_CreateWindow("Simplest Video Play SDL2", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, window_w, window_h, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE); if (!window) { cout << "SDL: could not create window" << SDL_GetError() << endl; return; } SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, 0); Uint32 pixFormat = 0; pixFormat = SDL_PIXELFORMAT_IYUV; SDL_Texture* texture = SDL_CreateTexture(renderer, pixFormat, SDL_TEXTUREACCESS_STREAMING, pixel_w, pixel_h); FILE* fp = NULL; fp = fopen("E:/tony/demo/visualstudio_workspace/SDLDemo/out/build/x64-debug/SDLDemo/yuv/sintel_640_360.yuv", "rb+"); if (fp == NULL) { cout << "cannot open this file" << endl; return; } //这个区域会存放显示的视频 SDL_Rect sdlRect; //初始化SDL事件 SDL_Event event; //创建一个SDL线程,SDL_CreateThread最后一个参数传递的参数 SDL_Thread* thread = SDL_CreateThread(refresh_video,NULL,NULL); while (true) { //等待SDL事件进入 SDL_WaitEvent(&event); //收到刷新事件对页面进行刷新 if (event.type == REFRESH_EVENT) { //这里是读取一帧视频真,数据格式是YUV420P,像素排列是4:2:0,一行像素=width*height+width*1/4+height*1/4 = width*height*3/2 //所以下面这句话刚好就是读取了一个视频帧YUV的数据长度 if (fread(buffer, 1, pixel_w * pixel_h * 3/2, fp) != pixel_w * pixel_h * 3/2) { // Loop fseek(fp, 0, SEEK_SET); fread(buffer, 1, pixel_w * pixel_h * 3/2, fp);//读取一帧数据的容量并放入buffer中 } SDL_UpdateTexture(texture, NULL, buffer, pixel_w); sdlRect.x = 0; sdlRect.y = 0; sdlRect.w = window_w; sdlRect.h = window_h;//把视频就显示到这个区域 SDL_RenderClear(renderer); SDL_RenderCopy(renderer, texture, NULL, &sdlRect); SDL_RenderPresent(renderer); } else if (event.type == SDL_WINDOWEVENT) { //resize SDL_GetWindowSize(window, &window_w, &window_h); } else if (event.type == SDL_QUIT) {//点击右上角的叉号退出线程 thread_exit = 1; } else if (event.type == BREAK_EVENT) {//退出标志 break; } } SDL_DestroyTexture(texture); SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); SDL_Quit(); }
标签:Thread,SDL2,pixel,exit,SDL,event,Event From: https://www.cnblogs.com/tony-yang-flutter/p/17832081.html