SDL2.0 播放YUV420p文件

说明

使用SDL2.0 播放YUV420p文件,必须要知道该视频文件的分辨率。
结合之前写的显示SDL2.0显示YUV图片改动下即可实现播放YUV序列。

ffmpeg提取YUV

ffmpeg -i xiongmao.flv -c:v rawvideo -pix_fmt yuv420p out.yuv

ffplay播放YUV

ffplay -f rawvideo -video_size 1000x562 out.yu

步骤

  1. 打开YUV文件
  2. 循环读取一帧图片的Y、U、V到内存。
  3. 将YUV数据交给纹理显示

代码

// SDL2_PLAY_YUV420.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "SDL.h"
#include "SDL_version.h"

#undef main


#define PATH_YUV420 "D:\\out.yuv"

#define width  1000
#define height 562


int main()
{

    //打印版本信息
    SDL_version compiled;
    SDL_VERSION(&compiled);

    printf("SDL version %d.%d.%d\n", compiled.major, compiled.minor, compiled.patch);


    //根据分辨率计算Y,U,V的长度
    int lenY = width * height;
    int lenU = width * height / 4;
    int lenV = width * height / 4;

    Uint8 *pYBuf = (Uint8 *)malloc(lenY);
    Uint8 *pUBuf = (Uint8 *)malloc(lenU);
    Uint8 *pVBuf = (Uint8 *)malloc(lenV);

    FILE *pFile = fopen(PATH_YUV420, "rb");
    if (pFile == NULL) {
        printf("open file failed\n");
        return -1;
    }

    //初始化SDL
    if (SDL_Init(SDL_INIT_VIDEO) < 0)
        return 1;

    SDL_Window *window = SDL_CreateWindow("SDL_WINDOW_TITLE", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, 0);
    SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, 0);   //渲染器
    SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, width, height);    //纹理是渲染的内容

    SDL_Rect rect;

    rect.x = 0;
    rect.y = 0;
    rect.w = width;
    rect.h = height;

    while (true) {

        if ((fread((void *)pYBuf, 1, lenY, pFile) == 0 || fread((void *)pUBuf, 1, lenU, pFile) == 0 || fread((void *)pVBuf, 1, lenV, pFile) == 0)) {

            printf("reach the end!\n");
            break;
        }


        SDL_UpdateYUVTexture(texture, &rect, pYBuf, width, pUBuf, width / 2, pVBuf, width / 2);

        //下面开始显示纹理
        SDL_RenderClear(renderer);
        SDL_RenderCopy(renderer, texture, NULL, &rect);
        SDL_RenderPresent(renderer);
        SDL_Delay(45);
    }

    fclose(pFile);

    free((void *)pYBuf);
    free((void *)pUBuf);
    free((void *)pVBuf);
    return 0;
}



#if 0

必须先知道YUV420的分辨率。根据分辨率才能知道一帧的Y、U、V分别长多是多少


#endif 

代码下载

SDL2播放YUV420P序列

SDL2.0 支持渲染 YUV4:2:0 格式的视频,需要使用 SDL_Texture 和 SDL_RenderCopy 函数来实现。 以下是一个简单的示例代码: ```c #include <SDL2/SDL.h> #include <stdio.h> const int SCREEN_WIDTH = 640; const int SCREEN_HEIGHT = 480; int main(int argc, char* argv[]) { SDL_Window* window = NULL; SDL_Renderer* renderer = NULL; SDL_Texture* texture = NULL; if (SDL_Init(SDL_INIT_VIDEO) < 0) { printf("SDL could not initialize! SDL_Error: %s\n", SDL_GetError()); return 1; } window = SDL_CreateWindow("YUV4:2:0 Video", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN); if (window == NULL) { printf("Window could not be created! SDL_Error: %s\n", SDL_GetError()); return 1; } renderer = SDL_CreateRenderer(window, -1, 0); if (renderer == NULL) { printf("Renderer could not be created! SDL_Error: %s\n", SDL_GetError()); return 1; } texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_YV12, SDL_TEXTUREACCESS_STREAMING, SCREEN_WIDTH, SCREEN_HEIGHT); if (texture == NULL) { printf("Texture could not be created! SDL_Error: %s\n", SDL_GetError()); return 1; } // YUV data Uint8* yPlane = NULL; Uint8* uPlane = NULL; Uint8* vPlane = NULL; int yPitch = 0; int uPitch = 0; int vPitch = 0; int w = 0; int h = 0; // read YUV file FILE* fp = fopen("video.yuv", "rb"); if (fp == NULL) { printf("Could not open YUV file!\n"); return 1; } // allocate memory for YUV data int bufferSize = SCREEN_WIDTH * SCREEN_HEIGHT * 3 / 2; Uint8* buffer = (Uint8*)malloc(bufferSize); // main loop SDL_Event event; bool quit = false; while (!quit) { while (SDL_PollEvent(&event)) { if (event.type == SDL_QUIT) { quit = true; } } // read YUV data if (fread(buffer, 1, bufferSize, fp) != bufferSize) { // end of file rewind(fp); } // set YUV data yPlane = buffer; uPlane = yPlane + SCREEN_WIDTH * SCREEN_HEIGHT; vPlane = uPlane + SCREEN_WIDTH * SCREEN_HEIGHT / 4; yPitch = SCREEN_WIDTH; uPitch = SCREEN_WIDTH / 2; vPitch = SCREEN_WIDTH / 2; w = SCREEN_WIDTH; h = SCREEN_HEIGHT; // update texture SDL_UpdateYUVTexture(texture, NULL, yPlane, yPitch, uPlane, uPitch, vPlane, vPitch); // clear screen SDL_SetRenderDrawColor(renderer, 0xFF, 0xFF, 0xFF, 0xFF); SDL_RenderClear(renderer); // render texture SDL_RenderCopy(renderer, texture, NULL, NULL); // update screen SDL_RenderPresent(renderer); } // free memory free(buffer); // cleanup SDL_DestroyTexture(texture); SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); SDL_Quit(); return 0; } ``` 在代码中,我们首先创建一个 SDL 窗口和渲染器。然后,使用 SDL_CreateTexture 函数创建一个 YV12 格式的纹理。接下来,读取 YUV 文件,并将数据设置到纹理中。在主循环中,使用 SDL_RenderCopy 函数将纹理渲染到屏幕上。最后,记得在程序结束前释放所有内存和资源。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值