说明
使用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
步骤
- 打开YUV文件
- 循环读取一帧图片的Y、U、V到内存。
- 将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