ffmpeg之显示一个yuv照片
显示YUV图片的步骤
1.初始化SDL库
- 目的:确保SDL库正确初始化,以便可以使用其窗口、渲染和事件处理功能。
- 操作:
调用 ·SDL_Init(SDL_INIT_VIDEO)
来初始化SDL的视频子系统。
2.创建窗口用于显示YUV图像:
- 目的:创建一个窗口作为显示YUV图像的目标。
- 操作:使用
SDL_CreateWindow
创建一个SDL窗口,并指定窗口的位置、大小和标志(如是否全屏等)。你可以根据需要自定义窗口的属性。
- 创建渲染器:
- 目的:创建一个渲染器,用于在窗口中绘制图像。
- 操作:使用
SDL_CreateRenderer
创建一个渲染器。可以选择硬件加速和垂直同步选项以提高性能和视觉质量。
- 读取YUV文件并准备数据:
- 目的:从YUV文件中读取原始像素数据,并准备好这些数据以便后续处理。
- 操作:打开YUV文件,读取Y、U、V平面的数据到内存中。这一步骤通常包括分配适当的缓冲区来存储YUV数据。
- 创建纹理并设置颜色格式:
- 目的:创建一个纹理对象,用于在GPU中存储图像数据,并设置纹理的颜色格式(如YUV420P)。
- 操作:使用
SDL_CreateTexture
创建一个纹理,指定像素格式(例如SDL_PIXELFORMAT_YV12
或SDL_PIXELFORMAT_IYUV
),以及访问模式(如SDL_TEXTUREACCESS_STREAMING
)。
- 将YUV数据更新到纹理:
- 目的:将读取的YUV数据复制到纹理中,以便可以在渲染时使用。
- 操作:使用
SDL_UpdateYUVTexture
函数将Y、U、V平面的数据分别更新到纹理中。
- 渲染纹理到屏幕上:
- 目的:将纹理绘制到窗口的渲染层上,完成图像的显示。
- 操作:调用
SDL_RenderClear
清除渲染目标,然后使用SDL_RenderCopy
将纹理复制到渲染器的目标区域,最后调用SDL_RenderPresent
刷新屏幕以显示图像。
- 处理事件和清理资源:
- 目的:处理用户输入或事件,并释放所有分配的资源。
- 操作:使用
SDL_PollEvent
处理事件(如关闭窗口),并在程序结束时调用相应的销毁函数(如SDL_DestroyTexture、SDL_DestroyRenderer 和 SDL_DestroyWindow
),最后调用 SDL_Quit 退出SDL库。
代码用例:
void playThread::run()
{
//创建窗口
SDL_Window *window = nullptr;
//渲染上下文
SDL_Renderer *renderer = nullptr;
//纹理(直接跟特定驱动程序相关的像素数据)
SDL_Texture *texture = nullptr;
//文件
QFile file(FILENAME);
//初始化子系统
END(SDL_Init(SDL_INIT_VIDEO),SDL_Init);
//创建一个窗口
//标题-X-Y-width-height
window = SDL_CreateWindow("SDL显示YUV图片",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
IMG_W,IMG_H,
SDL_WINDOW_SHOWN);
END(!window,SDL_CreateWindow);
//创建渲染上下文--用于渲染图形到窗口
//这SDL_RENDERER_ACCELERATED -- 个标志告诉 SDL 尝试创建一个使用硬件加速的渲染器
//SDL_RENDERER_PRESENTVSYNC -- 这个标志使渲染器的呈现操作同步到显示器的垂直同步(VSync)
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
//如果创建失败
if(!renderer)
{
renderer = SDL_CreateRenderer(window,-1,0);
END(!renderer,SDL_CreateRenderer);
}
//创建纹理t
texture = SDL_CreateTexture(renderer,
PIXEL_FORMAT,
SDL_TEXTUREACCESS_STREAMING,
IMG_W,IMG_H);
END(!texture,SDL_CreateTextureFromSurface);
//打开YUV文件
if(!file.open(QFile::ReadOnly))
{
qDebug() << "file open error" << FILENAME;
goto end;
}
//将YUV的像素数据填充到texture -- nullptr空表示整个texture都是
END(SDL_UpdateTexture(texture,nullptr,file.readAll().data(),IMG_W),SDL_UpdateTexture);
//设置绘制颜色(画笔颜色)
SDL_SetRenderDrawColor(renderer,0,0,0,SDL_ALPHA_OPAQUE);
//用绘制颜色(画笔颜色)清除渲染目标---也就是覆盖
SDL_RenderClear(renderer);
//拷贝纹理数据到渲染目标(默认时window)
END(SDL_RenderCopy(renderer,texture,nullptr,nullptr),SDL_RenderCopy);
//更新所有的渲染操作到屏幕上
SDL_RenderPresent(renderer);
SDL_Delay(2000);
end:
file.close();
SDL_DestroyRenderer(renderer);
SDL_DestroyTexture(texture);
SDL_DestroyWindow(window);
SDL_Quit();//初始化子系统后必须做一个退出操作
}
用例输出图:
如何自定义显示窗口呢?
首先我们在create窗口的时候,我们可以通过winId来设置的它的显示窗口,如下例子所示:
在进行点击按钮显示的时候,将显示窗口目标的winId传给create窗口。
void MainWindow::on_pushButton_clicked()
{
//playThread * pt = new playThread((void *)ui->label->winId(),this);
playThread * pt = new playThread((void *)_widget->winId(),this);
pt->start();
}
oid playThread::run()
{
//创建窗口
SDL_Window *window = nullptr;
//渲染上下文
SDL_Renderer *renderer = nullptr;
//纹理(直接跟特定驱动程序相关的像素数据)
SDL_Texture *texture = nullptr;
//文件
QFile file(FILENAME);
//初始化子系统
END(SDL_Init(SDL_INIT_VIDEO),SDL_Init);
//创建一个窗口
//标题-X-Y-width-height
window = SDL_CreateWindowFrom(_winId);
END(!window,SDL_CreateWindow);
//创建渲染上下文--用于渲染图形到窗口
//这SDL_RENDERER_ACCELERATED -- 个标志告诉 SDL 尝试创建一个使用硬件加速的渲染器
//SDL_RENDERER_PRESENTVSYNC -- 这个标志使渲染器的呈现操作同步到显示器的垂直同步(VSync)
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
//如果创建失败
if(!renderer)
{
renderer = SDL_CreateRenderer(window,-1,0);
END(!renderer,SDL_CreateRenderer);
}
//创建纹理t
texture = SDL_CreateTexture(renderer,
PIXEL_FORMAT,
SDL_TEXTUREACCESS_STREAMING,
IMG_W,IMG_H);
END(!texture,SDL_CreateTextureFromSurface);
//打开YUV文件
if(!file.open(QFile::ReadOnly))
{
qDebug() << "file open error" << FILENAME;
goto end;
}
//将YUV的像素数据填充到texture -- nullptr空表示整个texture都是
END(SDL_UpdateTexture(texture,nullptr,file.readAll().data(),IMG_W),SDL_UpdateTexture);
//设置绘制颜色(画笔颜色)
SDL_SetRenderDrawColor(renderer,0,0,0,SDL_ALPHA_OPAQUE);
//用绘制颜色(画笔颜色)清除渲染目标---也就是覆盖
SDL_RenderClear(renderer);
//拷贝纹理数据到渲染目标(默认时window)
END(SDL_RenderCopy(renderer,texture,nullptr,nullptr),SDL_RenderCopy);
//更新所有的渲染操作到屏幕上
SDL_RenderPresent(renderer);
SDL_Delay(2000);
end:
file.close();
SDL_DestroyRenderer(renderer);
SDL_DestroyTexture(texture);
SDL_DestroyWindow(window);
SDL_Quit();//初始化子系统后必须做一个退出操作
}
用例输出图: