首页 > 其他分享 >Qt基于SDL库简单实现YUV视频播放

Qt基于SDL库简单实现YUV视频播放

时间:2024-07-24 20:29:24浏览次数:8  
标签:Qt frame len YUV video SDL event

示例使用的是Qt5.10和minGW_32位,用C语言实现。
将用于测试的YUV视频和SDL2.dll放到对应的build目录下,将SDL库放到项目目录下


.pro文件:

点击查看代码
TEMPLATE = app
CONFIG += console
CONFIG -= app_bundle
CONFIG -= qt

SOURCES += main.c

win32{
INCLUDEPATH += $$PWD/SDL2/include
LIBS += $$PWD/SDL2/lib/x86/SDL2.lib
}
main.c文件:
点击查看代码
#include <stdio.h>
#include <string.h>
#include <SDL.h>
#define REFRESH_EVENT (SDL_USEREVENT+1)
#define QUIT_EVENT (SDL_USEREVENT+2)
#define YUV_WIDTH 320
#define YUV_HEIGHT 240
#define YUV_FORMAT SDL_PIXELFORMAT_IYUV
int s_thread_exit = 0;
int refresh_video_timer(void *data){
    while(!s_thread_exit){
        SDL_Event event;
        event.type = REFRESH_EVENT;
        SDL_PushEvent(&event);
        SDL_Delay(40);
    }
//线程不退出,就持续将事件(更新事件)发送到事件队列当中,每个事件对应一帧,40ms延迟能实现25fps的视频播放
    s_thread_exit = 0;
    SDL_Event event;
    event.type = QUIT_EVENT;
    SDL_PushEvent(&event);
    return 0;
}
#undef main
int main(int argc,char* argv[])
{
    if(SDL_Init(SDL_INIT_VIDEO)){
        fprintf(stderr,"Could not initialize SDL:%s\n",SDL_GetError());
        return -1;
    }
    SDL_Event event;
    SDL_Rect rect;
    SDL_Window *window=NULL;
    SDL_Renderer *renderer = NULL;
    SDL_Texture *texture = NULL;
    SDL_Thread *timer_thread = NULL;
    uint32_t pixformat = YUV_FORMAT;
    int video_width = YUV_WIDTH;
    int video_height = YUV_HEIGHT;
    int win_width = YUV_WIDTH;
    int win_height = YUV_HEIGHT;
    FILE *video_fd = NULL;
    const char *yuv_path = "yuv420p_320x240.yuv";
    size_t video_buff_len = 0;
    uint8_t *video_buf = NULL;
    uint32_t y_frame_len = video_width*video_height;
    uint32_t u_frame_len = video_width*video_height/4;
    uint32_t v_frame_len = video_width*video_height/4;
    uint32_t yuv_frame_len = y_frame_len + u_frame_len + v_frame_len;
    window = SDL_CreateWindow("Simplest YUV Player",SDL_WINDOWPOS_UNDEFINED,
                              SDL_WINDOWPOS_UNDEFINED,video_width,video_height,
                              SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
    if(!window){
        fprintf(stderr,"SDL:could not create window,err:%s\n",SDL_GetError());
        goto _FAIL;
    }
    renderer = SDL_CreateRenderer(window,-1,0);
    texture = SDL_CreateTexture(renderer,pixformat,SDL_TEXTUREACCESS_STREAMING,
                                video_width,video_height);
    video_buf = (uint8_t*)malloc(yuv_frame_len);
    if(!video_buf){
        fprintf(stderr,"Failed to alloce yuv frame space!\n");
        goto _FAIL;
    }
    video_fd = fopen(yuv_path,"rb");
    if(!video_fd){
        printf(stderr,"Failed to open yuv file\n");
        goto _FAIL;
    }
    timer_thread = SDL_CreateThread(refresh_video_timer,NULL,NULL);
    while (1) {
        SDL_WaitEvent(&event);
        if(event.type== REFRESH_EVENT){
            video_buff_len = fread(video_buf,1,yuv_frame_len,video_fd);
            if(video_buff_len<=0){
                fprintf(stderr,"Failed to read data from yuv file!\n");
                goto _FAIL;
            }
            SDL_UpdateTexture(texture,NULL,video_buf,video_width);
            rect.x = 0;
            rect.y = 0;
            float w_ratio=win_width*1.0/video_width;
            float h_ratio=win_height*1.0/video_height;
            rect.w=video_width*w_ratio;
            rect.h=video_height*h_ratio;
//            rect.w = video_width * 0.5;
//            rect.h = video_height * 0.5;
            SDL_RenderClear(renderer);
            SDL_RenderCopy(renderer,texture,NULL,&rect);
            SDL_RenderPresent(renderer);
        }
        else if(event.type==SDL_WINDOWEVENT){
            SDL_GetWindowSize(window,&win_width,&win_height);
            printf("SDL_WINDOWEVENT win_width:%d,win_height:%d",win_width,win_height);
            printf("video_width:%d,video_height:%d",video_width,video_height);
            printf("rect.w:%d,rect.h:%d\n",rect.w,rect.h);
        }
        else if(event.type==SDL_QUIT){
            s_thread_exit =1;
        }
        else if(event.type==QUIT_EVENT){
            break;
        }
    }
    _FAIL:
    s_thread_exit =1;
    if(timer_thread)
        SDL_WaitThread(timer_thread,NULL);
    if(video_buf)
        free(video_buf);
    if(video_fd)
        free(video_fd);
    if(texture)
        SDL_DestroyTexture(texture);
    if(renderer)
        SDL_DestroyRenderer(renderer);
    SDL_Quit();
    return 0;
}

使用qq自带的截图工具查看视频分辨率和窗口大小(打开qq挂着,Alt+A),

如果大小和命令行输出的不一致,可能是代码错误或者显示设置不是100%。

rect.w=video_width*w_ratio;
rect.h=video_height*h_ratio;

rect的大小随窗口window的大小改变

这张图是

rect.w = video_width * 0.5;
rect.h = video_height * 0.5;

的运行结果。
可见视频的分辨率并不随窗口window的缩放而改变,黑色区域大小就是windows的大小,视频可视范围就是rect的大小。

标签:Qt,frame,len,YUV,video,SDL,event
From: https://www.cnblogs.com/NOPASSWD/p/18321656

相关文章

  • mqtt- 轻量级的消息传输协议
    金融数据流:实时数据传输 实现方式基于mqttMQTT(MessageQueuingTelemetryTransport)是一种轻量级的消息传输协议,主要用于低带宽和高延迟的网络环境。它特别适合于物联网(IoT)应用、移动设备和其他需要可靠消息传递的场景。MQTT的主要特点1.轻量级和高效:•MQTT协议......
  • Qt - 网络相关的类
    1.QHostInfoQHostInfo类为主机名查找提供了静态函数。QHostInfo查找与主机名关联的IP地址或与IP地址关联的主机名。这个类提供了两个方便的静态函数:一个异步工作并在找到主机时发出信号,另一个阻塞并返回QHostInfo对象。要异步查找主机的IP地址,调用lookupHost(),它接受主机名......
  • Windows 使用 Visual Studio 2013 编译 paho-mqtt 生成dll lib 文件
    前言全局说明Windows使用VisualStudio2013编译paho-mqtt生成dlllib文件一、说明环境:Windows7旗舰版VisualStudio2013RTMPROCHS二、环境准备2.1安装VisualStudio2013https://www.cnblogs.com/wutou/p/183205322.2安装CMakehttps://www.cnblo......
  • Qt实现图片拖拽上传过滤文件夹内图片自动搜索列表展示
     1.功能实现支持图片、或者文件夹拖拽上传,会自动获取文件夹中的图片。对拖入的文件做格式判断,不符合格式要求的会不支持拖入,拖入后展示在list列表中,可以进行删除,和上下滚动查看;#ifndefDRAGDROPPIC_H#defineDRAGDROPPIC_H#include<QWidget>#include"ui_DragDropPic.h......
  • pyqt5中带有特定按钮的setCurrentIndex()方法问题
    我对pyqt5还很陌生,坦率地说,这是我使用这个框架的第一个项目,所以请耐心等待。当我尝试将sign_up按钮连接到我的goto时,它向用户显示SignUpMainWindow,即使具有相同连接功能的其他按钮正常工作,它似乎根本不起作用...我已经去了多次检查我的代码以确保它......
  • 【Qt项目制作普通计算器】C++语言
    目录一、概述二、界面设计三、程序代码1、程序代码存放位置2、widget.h文件3、widget.cpp4、main.cpp5、.pro文件6、资源文件的添加一、概述1.规划与设计功能确定:决定计算器将支持哪些基本运算(加、减、乘、除、百分之、平方、开根号、变分数等)。界面设计:设计用......
  • Qt与C++标准的兼容之旅
    第一章:Qt与C++:相互成就的技术演进Qt,作为一个跨平台的应用程序和用户界面框架,自其诞生之初便与C++紧密相连。C++,一种广泛使用的高级编程语言,以其高效的性能和面向对象的特性在软件开发中占据重要地位。在探讨Qt与C++之间的关系时,我们不仅是在分析技术层面的互动,更是在审视一......
  • 如何将字典放入剪贴板以将其复制/粘贴到另一个 pyqt6 窗口中?
    我想使用剪贴板将字典从Qapplication传递到另一个应用程序。我可以复制文本,但我不明白如何传递其他内容。我需要传递一个字典而不是文本。这是一个最小的示例,我可以启动该软件两次并将文本复制到另一个:importsysimportnumpyasnpfromPyQt6.QtGuiimport*from......
  • Qt 实战(7)元对象系统 | 7.5、QMetaProperty详解
    文章目录一、QMetaProperty详解1、QMetaProperty的作用2、使用QMetaProperty2.1、声明属性2.2、访问属性3、QMetaProperty成员方法4、示例4.1、通过名称获取指定属性4.2、遍历全部属性(包含从基类继承下来的)4.3、遍历当前类的全部属性(不包含从基类继承下来的)5、动态属性......
  • QT 之 USB SCSI指令0x2A对USB设备进行写有问题
     摘要:使用QT进行SCSI指令操作时遇到问题,0x28读取正常,但0x2A写入失败,原因是系统对0x2A命令的写入权限控制严格。解决方法是通过FSCTL_LOCK_VOLUME实现独占访问,实现对USB设备的写操作。 问题参考:https://blog.csdn.net/kifea/article/details/1036960990x2A命令参考: https:/......