SDL播放YUV数据

#include <stdio.h>
#include <string.h>
#include <SDL.h>

//自定义消息类型
#define REFRESH_EVENT   (SDL_USEREVENT + 1)     // 请求画面刷新事件

//定义分辨率
// YUV像素分辨率
#define YUV_WIDTH   320
#define YUV_HEIGHT  240
//定义YUV格式
#define YUV_FORMAT  SDL_PIXELFORMAT_IYUV

int s_thread_exit = 0;  // 退出标志 = 1则退出

int refresh_video_timer(void *data)
{
    while (!s_thread_exit)
    {
        SDL_Event event;
        event.type = REFRESH_EVENT;
        SDL_PushEvent(&event);
        SDL_Delay(40);
    }
    return 0;
}
#undef main
int main(int argc, char* argv[])
{
    // 1.初始化SDL
    if (SDL_Init(SDL_INIT_VIDEO)) {
        fprintf( stderr, "SDL_Init error: %s
", SDL_GetError());
        return -1;
    }

    // 2.创建窗口
    SDL_Window *window  = SDL_CreateWindow("YUV Player", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, YUV_WIDTH, YUV_HEIGHT, SDL_WINDOW_RESIZABLE);
    if (window == NULL) {
        fprintf( stderr, "SDL_CreateWindow error: %s
", SDL_GetError());
        return -1;
    }

    // 3.创建渲染器
    SDL_Renderer *render = SDL_CreateRenderer(window, -1, 0);
    if (render == NULL) {
        fprintf( stderr, "SDL_CreateRenderer error: %s
", SDL_GetError());
        return -1;
    }

    // 4.创建纹理
    SDL_Texture * texture = SDL_CreateTexture(render,
                                  SDL_PIXELFORMAT_IYUV, // planar mode: Y + U + V (3 planes)
                                  SDL_TEXTUREACCESS_STREAMING, YUV_WIDTH, YUV_HEIGHT);
    if (texture == NULL) {
        fprintf( stderr, "SDL_CreateTexture error: %s
", SDL_GetError());
        return -1;
    }

    // 5.分配缓存空间
    uint32_t yuvlen = YUV_WIDTH*YUV_HEIGHT     // Y
                      + YUV_WIDTH*YUV_HEIGHT/4 // U
                      + YUV_WIDTH*YUV_HEIGHT/4;// V
    uint8_t *videobuf = (uint8_t*)malloc(yuvlen);
    if (videobuf == NULL) {
        fprintf( stderr, "YUV buf malloc error.
");
        return -1;
    }

    // 6.打开yuv文件
    FILE* videofd = fopen("yuv420p_320x240.yuv", "rb");
    if (videofd == NULL) {
        fprintf( stderr, "fopen yuv file error.
");
        return -1;
    }

    // 7.创建刷新线程
    SDL_Thread * sdlThread = SDL_CreateThread(refresh_video_timer, NULL, NULL);

    // 8.事件循环
    SDL_Event event;
    size_t video_buff_len = 0;
    SDL_Rect rect;
    int win_width = YUV_WIDTH;
    int win_height = YUV_HEIGHT;
    while (1) {
        SDL_WaitEvent(&event);
        if (event.type == REFRESH_EVENT) {
            // 读取yuv数据
            video_buff_len = fread(videobuf, 1, yuvlen, videofd);
            if (video_buff_len < 0) {
                fprintf( stderr, "Failed to read data from yuv file!
");
                break;
            }
            // 设置纹理数据
            SDL_UpdateTexture(texture, NULL, videobuf, YUV_WIDTH);

            // 设置大小
            if (win_width/win_height > YUV_WIDTH/YUV_HEIGHT) {
                int width = win_height * YUV_WIDTH/YUV_HEIGHT;
                rect.x = (win_width - width)/2;
                rect.y = 0;
                rect.w = width;
                rect.h = win_height;
            }else {
                int height = win_width * YUV_HEIGHT / YUV_WIDTH;
                rect.x = 0;
                rect.y = (win_height - height)/2;
                rect.w = win_width;
                rect.h = height;
            }

            // 清除显示区域
            SDL_RenderClear(render);

            // 拷贝纹理到渲染器
            SDL_RenderCopy(render, texture, NULL, &rect);

            // 显示数据
            SDL_RenderPresent(render);
        }
        else if (event.type == SDL_WINDOWEVENT) {
           SDL_GetWindowSize(window, &win_width, &win_height);
           printf("SDL_WINDOWEVENT win_%d, win_height:%d
",win_width, win_height);
        }
        else if (event.type == SDL_QUIT) {
            break;
        }
    }

    // 9.推出
    s_thread_exit = 1;
    if (sdlThread) {
        SDL_WaitThread(sdlThread, NULL);
    }
    if (videobuf) {
        free(videobuf);
    }
    if (videofd) {
        fclose(videofd);
    }
    if (texture) {
        SDL_DestroyTexture(texture);
    }
    if (render) {
        SDL_DestroyRenderer(render);
    }
    if (window) {
        SDL_DestroyWindow(window);
    }
    SDL_Quit();
    return 0;
}
原文地址:https://www.cnblogs.com/vczf/p/13503782.html