当前位置: 首页 > article >正文

ffmpeg之播放一个yuv视频

播放YUV视频的步骤

  1. 初始化SDL库:
  • 目的:确保SDL库正确初始化,以便可以使用其窗口、渲染和事件处理功能。
  • 操作:调用 SDL_Init(SDL_INIT_VIDEO) 来初始化SDL的视频子系统。
  1. 创建窗口用于显示YUV视频:
    目的:创建一个窗口作为显示YUV视频的目标。
    操作:使用 SDL_CreateWindow 创建一个SDL窗口,并指定窗口的位置、大小和标志(如是否全屏等)。你可以根据需要自定义窗口的属性。
  2. 创建渲染器:
  • 目的:创建一个渲染器,用于在窗口中绘制图像。
  • 操作:使用 SDL_CreateRenderer 创建一个渲染器。可以选择硬件加速和垂直同步选项以提高性能和视觉质量。
  1. 创建纹理并设置颜色格式:
  • 目的:创建一个纹理对象,用于在GPU中存储图像数据,并设置纹理的颜色格式(如YUV420P)。
  • 操作:使用 SDL_CreateTexture 创建一个纹理,指定像素格式(例如 SDL_PIXELFORMAT_YV12 或 SDL_PIXELFORMAT_IYUV),以及访问模式(如 SDL_TEXTUREACCESS_STREAMING)。
  1. 循环读取YUV文件并更新纹理:
  • 目的:从YUV文件中逐帧读取原始像素数据,并将每一帧的数据更新到纹理中,完成每一帧的渲染。
  • 操作:在一个循环中读取YUV文件中的每一帧数据,使用 SDL_UpdateYUVTexture 将Y、U、V平面的数据分别更新到纹理中,然后调用 SDL_RenderClearSDL_RenderCopySDL_RenderPresent 来刷新屏幕以显示当前帧。确保每帧之间有适当的延时以维持正确的播放速度。
  1. 清理资源:
    目的:释放所有分配的资源,确保没有内存泄漏。
    操作:在程序结束时调用相应的销毁函数(如 SDL_DestroyTexture、SDL_DestroyRenderer 和 SDL_DestroyWindow),最后调用 SDL_Quit 退出SDL库。

示例代码如下:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <SDL2/SDL.h>
#include <QDebug>
#include <QFile>

#define RET(judge,SDL_Init) \
    if(judge) \
    {\
        qDebug() << #SDL_Init << "error" << SDL_GetError();\
        return;\
    }
#define FILENAME "D:/ffmpeg/in.yuv"
#define PIXEL_FORMAT SDL_PIXELFORMAT_IYUV
#define IMG_W 352
#define IMG_H 288


MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{

    ui->setupUi(this);
    _widget = new QWidget(this);
    //设置窗口位置和大小
    _widget->setGeometry(100,0,IMG_W,IMG_H);

    //初始化子系统
    RET(SDL_Init(SDL_INIT_VIDEO),SDL_Init);

    //创建一个窗口
    //标题-X-Y-width-height
    _window = SDL_CreateWindowFrom((void *)_widget->winId());
    RET(!_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);
        RET(!_renderer,SDL_CreateRenderer);
    }

    //创建纹理t
    _texture = SDL_CreateTexture(_renderer,
                                PIXEL_FORMAT,
                                SDL_TEXTUREACCESS_STREAMING,
                                IMG_W,IMG_H);
    RET(!_texture,SDL_CreateTextureFromSurface);

    //打开YUV文件
    _file.setFileName(FILENAME);
    if(!_file.open(QFile::ReadOnly))
    {
        qDebug() << "_file open error" << FILENAME;
        return;
    }
}

MainWindow::~MainWindow()
{
    delete ui;
    _file.close();
    SDL_DestroyRenderer(_renderer);
    SDL_DestroyTexture(_texture);
    SDL_DestroyWindow(_window);
    SDL_Quit();//初始化子系统后必须做一个退出操作
}

void MainWindow::on_pushButton_clicked()
{
    //开启定时器
    _timerId = startTimer(60);

}

//每隔一段事件就会调用
void MainWindow::timerEvent(QTimerEvent *enent)
{
    int imgSize = IMG_W * IMG_H * 1.5;
    char data[imgSize];

    if(_file.read(data,imgSize) > 0)
    {
        //将YUV的像素数据填充到texture -- nullptr空表示整个texture都是
        RET(SDL_UpdateTexture(_texture,nullptr,data,IMG_W),SDL_UpdateTexture);

        //设置绘制颜色(画笔颜色)
        SDL_SetRenderDrawColor(_renderer,0,0,0,SDL_ALPHA_OPAQUE);

        //用绘制颜色(画笔颜色)清除渲染目标---也就是覆盖
        SDL_RenderClear(_renderer);

        //拷贝纹理数据到渲染目标(默认时window)
        RET(SDL_RenderCopy(_renderer,_texture,nullptr,nullptr),SDL_RenderCopy);

        //更新所有的渲染操作到屏幕上
        SDL_RenderPresent(_renderer);
    }
    else
    {
        //文件数据已经读取完毕
        killTimer(_timerId);
    }

}

由于是一个视频,所以只截取了一个照片
在这里插入图片描述


http://www.kler.cn/a/452309.html

相关文章:

  • 编码转换(实例)
  • 前端Python应用指南(三)Django vs Flask:哪种框架适合构建你的下一个Web应用?
  • 查看php已安装扩展命令
  • Unity 6 中的新增功能
  • 结构化Prompt:让大模型更智能的秘诀
  • 分别查询 user 表中 avatar 和 nickname 列为空的用户数量
  • 常见问题解决方案:Keen CommonWeb 开源项目
  • CVPR-2024 | 具身导航模型大一统!NaviLLM:学习迈向具身导航的通用模型
  • Unity中如何修改Sprite的渲染网格
  • NFC 碰一碰发视频源码搭建技术详解,支持OEM
  • 从零用java实现 小红书 springboot vue uniapp (6)用户登录鉴权及发布笔记
  • 【Trick】解决服务器cuda报错——RuntimeError: cuDNN error: CUDNN_STATUS_NOT_INITIALIZED
  • 前端三大主流框架:React、Vue、Angular
  • 网络管理-期末项目(附源码)
  • PySide6如何实现点击TableWidget列表头在该列右侧显示列表选择框筛选列数据
  • 数据仓库是什么?数据仓库简介
  • 设计一个自己的AI Agent
  • .NET 9 中的 多级缓存 HybridCache
  • Android绘图Path基于LinearGradient线性动画渐变,Kotlin(2)
  • HarmonyOS NEXT 实战之元服务:静态案例效果---电台推荐
  • 【1224】数据结构(sizeof/数组的长度定义/读取字符串函数/线性表长度/左值右值/静态变量/指针与引用)
  • WPF自定义窗口 输入验证不生效
  • SpringBoot3-第四篇(基础特性)
  • Mybatisplus如何使用selectPage
  • 接口测试Day03-postman断言关联
  • HuaWei、NVIDIA 数据中心 AI 算力对比