SDL播放YUV数据

发布时间 2023-11-14 16:42:27作者: 飘杨......

一、概述

  上一节使用SDL2在窗口上显示了一张图片,本节使用SDL2播放YUV420P数据。

  YUV420P一帧数据的长度=width*height*3/2

二、代码示例

  下面这段示例代码读取YUV数据和现实YUV数据都是在同一个线程中的。播放是能播放,但是会很卡,不一会儿就会出现无响应的情况。下一节使用多线程进行改造

#include "include/sdl_read_yuv.h"
#include <iostream>
using namespace std;

SDLReadYuv::SDLReadYuv() {

    const int bpp = 12;
    int window_w = 640, window_h = 360;
    const int pixel_w = 640, pixel_h = 360;
    unsigned char buffer[pixel_w * pixel_h * bpp / 8];

    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;

    while (true) {
        //这里是读取一帧视频真,数据格式是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 * 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(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);

        SDL_Delay(40);

    }

    SDL_DestroyTexture(texture);
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);

    SDL_Quit();

}