SDL 开发实战(六): 使用 SDL 实现 YUV 播放器

前面铺垫了这么多,现在终于进入核心的主题了,那就是使用SDL播放视频,本节我们将使用SDL播放YUV视频,也就是做一个YUV播放器。

下面说明一下使用SDL播放YUV视频的基本流程,主要分为两大部分:初始化SDL、循环显示画面。

1. 初始化SDL

1). 初始化SDL (SDL_Init)
2). 创建窗口(SDL_CreateWindow)
3). 基于窗口创建渲染器(SDL_CreateRenderer)
4). 创建纹理(SDL_CreateTexture)

2. 循环显示画面

1). 设置纹理的数据(SDL_UpdateTexture)
2). 纹理复制给渲染目标(SDL_RenderCopy)
3). 显示(SDL_RenderPresent)

具体涉及到每个API的含义,这里就不过多介绍了,在之前的内容中,我们已经都做了说明,下面我们直接开始实战。

实战

// SDL.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include "pch.h"
#include <iostream>

extern "C" {
#include "SDL.h"
}

//Bit per Pixel
const int bpp = 12;

int screen_w = 500, screen_h = 500;

// 根据不同的YUV视频,来设置不同的 宽 * 高 数据 
const int pixel_w = 352, pixel_h = 288;

unsigned char buffer[pixel_w*pixel_h*bpp / 8];

//Refresh Event
#define REFRESH_EVENT  (SDL_USEREVENT + 1)

int thread_exit = 0;

int refresh_video(void *opaque) {
    while (thread_exit == 0) {
        SDL_Event event;
        event.type = REFRESH_EVENT;
        SDL_PushEvent(&event);
        SDL_Delay(40);
    }
    return 0;
}

int main(int argc, char* argv[])
{
    if (SDL_Init(SDL_INIT_VIDEO)) {
        printf("Could not initialize SDL - %s
", SDL_GetError());
        return -1;
    }

    SDL_Window *window;

    // 创建SDL窗口
    window = SDL_CreateWindow("Simplest Video Play SDL2", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 
      screen_w, screen_h, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE); // 判断是否创建窗口成功 if (!window) { printf("SDL: could not create window - exiting:%s ", SDL_GetError()); return -1; } // 创建SDL渲染器 SDL_Renderer* sdlRenderer = SDL_CreateRenderer(window, -1, 0); // 声明像素格式 Uint32 pixformat = 0; // IYUV: Y + U + V (3 planes) // YV12: Y + V + U (3 planes) // I420也叫IYUV, 也叫YUV420 pixformat = SDL_PIXELFORMAT_IYUV; // 按照YUV视频的宽高创建SDL纹理对象 SDL_Texture* sdlTexture = SDL_CreateTexture(sdlRenderer, pixformat, SDL_TEXTUREACCESS_STREAMING, pixel_w, pixel_h); FILE *fp = NULL; fp = fopen("222.yuv", "rb+"); if (fp == NULL) { printf("cannot open this file "); return -1; } SDL_Rect sdlRect; SDL_Thread *refresh_thread = SDL_CreateThread(refresh_video, NULL, NULL); SDL_Event event; while (1) { //Wait 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; sdlRect.h = screen_h; SDL_RenderClear(sdlRenderer); // 将更新后的纹理拷贝到渲染器 SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, &sdlRect); // 渲染器显示画面 SDL_RenderPresent(sdlRenderer); //Delay 40ms -- Dealy时常根据帧率进行调整 SDL_Delay(40); } else if (event.type == SDL_WINDOWEVENT) { //If Resize SDL_GetWindowSize(window, &screen_w, &screen_h); } else if (event.type == SDL_QUIT) { break; } } return 0; }

运行效果:

原文地址:https://www.cnblogs.com/renhui/p/10469980.html