本博客是摘自雷霄骅大神的课程《基于 FFmpeg + SDL 的视频播放器的制作》课程 里的内容,非常适合音视频小白入门,在这里感谢雷神的指导!
SDL:把解码获得的YUV数据显示到屏幕上
1.视频显示知识
把YUV数据显示到屏幕上,相当于YUV播放器
2.SDL简介
SDL根据平台自动调用不同的底层API与硬件交互
3.VC下SDL开发环境的搭建
4.实例程序运行
/**
* 最简单的SDL2播放视频的例子(SDL2播放RGB/YUV)
* Simplest Video Play SDL2 (SDL2 play RGB/YUV)
*
* 雷霄骅 Lei Xiaohua
* leixiaohua1020@126.com
* 中国传媒大学/数字电视技术
* Communication University of China / Digital TV Technology
* http://blog.csdn.net/leixiaohua1020
*
* 本程序使用SDL2播放RGB/YUV视频像素数据。SDL实际上是对底层绘图
* API(Direct3D,OpenGL)的封装,使用起来明显简单于直接调用底层
* API。
*
* This software plays RGB/YUV raw video data using SDL2.
* SDL is a wrapper of low-level API (Direct3D, OpenGL).
* Use SDL is much easier than directly call these low-level API.
*/
#include <stdio.h>
#define SDL_MAIN_HANDLED
extern "C"
{
#include "SDL.h"
};
const int bpp = 12;
//窗口的宽高
int screen_w = 640, screen_h = 360;
//像素的宽高
const int pixel_w = 640, pixel_h = 360;
//保存yuv数据
unsigned char buffer[pixel_w * pixel_h * bpp / 8];
int main(int argc, char* argv[])
{
// 1.初始化SDL系统:SDL_Init
if (SDL_Init(SDL_INIT_VIDEO)) {
printf("Could not initialize SDL - %s\n", SDL_GetError());
return -1;
}
SDL_Window* screen;
//SDL 2.0 Support for multiple windows
// 2.创建窗口:SDL_CreateWindow
screen = SDL_CreateWindow("Simplest Video Play SDL2", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
screen_w, screen_h, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
if (!screen) {
printf("SDL: could not create window - exiting:%s\n", SDL_GetError());
return -1;
}
// 3.创建渲染器:SDL_CreateRenderer
SDL_Renderer* sdlRenderer = SDL_CreateRenderer(screen, -1, 0);
Uint32 pixformat = 0;
//IYUV: Y + U + V (3 planes)
//YV12: Y + V + U (3 planes)
pixformat = SDL_PIXELFORMAT_IYUV;
// 4.创建纹理:SDL_CreateTexture
SDL_Texture* sdlTexture = SDL_CreateTexture(sdlRenderer, pixformat, SDL_TEXTUREACCESS_STREAMING, pixel_w, pixel_h);
FILE* fp = NULL;
// YUV文件路径
fopen_s(&fp, "test.yuv", "rb+");
if (fp == NULL) {
printf("cannot open this file\n");
return -1;
}
// 矩形结构
SDL_Rect sdlRect;
while (1) {
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);
}
// 5.设置纹理的数据
SDL_UpdateTexture(sdlTexture, NULL, buffer, pixel_w);
// 播放窗口的起始位置左上角坐标(x, y),宽度width,高度height
// 比如设置大小10像素的视频周围黑框
sdlRect.x = 10;
sdlRect.y = 10;
sdlRect.w = screen_w - 20;
sdlRect.h = screen_h - 20;
SDL_RenderClear(sdlRenderer);
// 6.将纹理的数据拷贝给渲染器
SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, &sdlRect);
// 7.显示
SDL_RenderPresent(sdlRenderer);
// Delay 40ms
// 工具函数,用于延时,设置播放每桢之间的间隙时间
// 正常都是每秒25桢
SDL_Delay(40);
}
// 8.退出SDL系统
SDL_Quit();
return 0;
}