首页 > 其他分享 >基于SDL的yuv视频播放

基于SDL的yuv视频播放

时间:2024-03-21 19:05:01浏览次数:23  
标签:frame len YUV video SDL 播放 yuv

## 1 基于SDL的yuv视频播放

YUV的播放涉及到创建窗口和创建线程,在窗口中传入YUV码流数据,以达到播放视频的目的。

## 2 代码例子

#include <stdio.h>
#include <string.h>

#include <SDL.h>

//自定义消息类型
#define REFRESH_EVENT   (SDL_USEREVENT + 1)     // 请求画面刷新事件
#define QUIT_EVENT      (SDL_USEREVENT + 2)     // 退出事件

//定义分辨率
// YUV像素分辨率
#define YUV_WIDTH   320
#define YUV_HEIGHT  240
//定义YUV格式
#define YUV_FORMAT  SDL_PIXELFORMAT_IYUV

int s_thread_exit = 0;  // 退出标志 = 1则退出

int refresh_video_timer(void *data)
{
    while (!s_thread_exit)
    {
        SDL_Event event;
        event.type = REFRESH_EVENT;
        SDL_PushEvent(&event);
        SDL_Delay(40);
    }

    s_thread_exit = 0;

    //push quit event
    SDL_Event event;
    event.type = QUIT_EVENT;
    SDL_PushEvent(&event);

    return 0;
}
#undef main
int main(int argc, char* argv[])
{
    //初始化 SDL
    if(SDL_Init(SDL_INIT_VIDEO))
    {
        fprintf( stderr, "Could not initialize SDL - %s\n", SDL_GetError());
        return -1;
    }

    // SDL
    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;            // YUV420P,即是SDL_PIXELFORMAT_IYUV

    // 分辨率
    // 1. YUV的分辨率
    int video_width = YUV_WIDTH;
    int video_height = YUV_HEIGHT;
    // 2.显示窗口的分辨率
    int win_width = YUV_WIDTH;
    int win_height = YUV_WIDTH;

    // YUV文件句柄
    FILE *video_fd = NULL;
    const char *yuv_path = "D:/software/Qt/project/05-sdl-yuv/yuv420p_320x240.yuv";

    size_t video_buff_len = 0;

    uint8_t *video_buf = NULL; //读取数据后先把放到buffer里面

    // 我们测试的文件是YUV420P格式
    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;
    }

    // 打开YUV文件
    video_fd = fopen(yuv_path, "rb");
    if( !video_fd )
    {
        fprintf(stderr, "Failed to open yuv file\n");
        goto _FAIL;
    }
    // 创建请求刷新线程
    timer_thread = SDL_CreateThread(refresh_video_timer,
                                    NULL,
                                    NULL);

    while (1)
    {
        // 收取SDL系统里面的事件
        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;
            }
            // 设置纹理的数据 video_width = 320, plane
            SDL_UpdateTexture(texture, NULL, video_buf, video_width);

            // 显示区域,可以通过修改w和h进行缩放
            rect.x = 0;
            rect.y = 0;
            float w_ratio = win_width * 1.0 /video_width;
            float h_ratio = win_height * 1.0 /video_height;
            // 320x240 
            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)
        {
            //If Resize
            SDL_GetWindowSize(window, &win_width, &win_height);
            printf("SDL_WINDOWEVENT win_width:%d, win_height:%d\n",win_width,
                   win_height );
        }
        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)
        fclose(video_fd);
    if(texture)
        SDL_DestroyTexture(texture);
    if(renderer)
        SDL_DestroyRenderer(renderer);
    if(window)
        SDL_DestroyWindow(window);

    SDL_Quit();

    return 0;

}

## 3.实现结果

320X240

显示窗口的长宽比例可自己设置。

 窗口拉伸时,相应的长宽数据也会打印在命令框上。 

标签:frame,len,YUV,video,SDL,播放,yuv
From: https://blog.csdn.net/weixin_69942267/article/details/136787890

相关文章

  • <sa8650>sa8650 video-之-vidc_test_app测试播放mp4
    <sa8650>sa8650video-之-vidc_test_app测试播放mp41、前言2、编写测试xml3、测试运行4、其它5、参考1、前言在SA8650中有一个测试video的测试程序那就是vidc_test_app;vidc_test_app的可是视频的编解码功能;本文主要分析讲解解码mp4文件的测试过程;详细内容下面分......
  • js实现多个video,一个播放其他暂停
    window.onload=function(){varvideos=document.getElementsByTagName('video');//获取所有video//循环给所有video添加监听事件当前的video开始播时调用pauseAll将当前播放的video的索引传值过去for(vari=videos.length-1;i>=0;i--){(......
  • 梨花带雨网页音乐播放器二开优化修复美化版全开源版本源码,附带系统搭建教程
    梨花带雨播放器基于thinkphp6开发的XPlayerHTML5网页播放器前台控制面板,支持多音乐平台音乐解析。二开内容:修复播放器接口问题,把接口本地化替换掉原来的接口,扒梨花的前端UI,美化登录页面源码免费下载地址抄笔记chaobiji.cn......
  • 将图片贴片到视频并播放3s
    首先用ffmeg获取视频的宽高为了使图片看起来和视频大小一致ffprobe-verror-select_streamsv:0-show_entriesstream=width,height-ofcsv=s=x:p=0xx1.mp4将图片缩放到视频宽高ffmpeg-itest.jpeg-vfscale=1200:750-update1test_xx1.jpeg将图片生成2s的视频......
  • Winform程序播放视频
    需求:在Winform程序中播放视频,并且控制循环播放1、管理NuGet程序包2、搜索“Vlc”,安装“Vlc.DotNet.Forms”“VideoLAN.LibVLC.Windows”“Vlc.DotNet.Core”3、搜索“VideoLAN.LibVLC”,安装“VideoLAN.LibVLC.Windows”4、编译后会生成“Vlc.DotNet.Core.dll”、“Vlc.Dot......
  • GB28181视频汇聚平台EasyCVR接入Ehome设备,设备在线但视频无法播放的原因排查
    安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快,可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等,以及支持厂家私有协议与SDK接入,包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安防视频监控的能力,也具备接入AI智能分析的......
  • vue使用JSWebrtc播放webrtc视频流
    1、下载JSWebrtc.min.js文件地址:https://github.com/kernelj/jswebrtc/tree/master/dist 或者再此路径下载 https://files.cnblogs.com/files/blogs/702532/jswebrtc.min.js?t=1710839018&download=true2、使用jswebrtc2.1文件放到public/static目录下,位置不能放错 2......
  • 通过GroovySDL实现GradleScript
    文章目录Groovy是什么GroovyDependencyDSL是什么初识GroovyDSLClosure,Delegate,Script&ShellCompilationCustomizersDSLStyleCustomizerDSL风格脚本展示Groovy是什么Groovy是一种在JVM上运行的敏捷开发语言Groovy80%的语法和Java完全一致,同时吸取了......
  • YUV与RGB转换公式(BT601、BT709、BT2020)
    1、在图像处理中经常需要对图像数据进行转换,最常见的莫过于YUV2RGB。并且这个转化在不同的标准下有不同的转化公式。2、如果公式不匹配,则会导致转换后的图像效果有偏差。3、full_range下Y\U\V的取值范围都为[0,255];limit_range(也叫part_range)下Y的取值范围为[16,235],UV的......
  • 通过视频帧提取及批量取模转换实现基于STC32的点阵LED动画播放
    项目摘要通过视频帧图片提取,图片批量裁剪,转换为BMP文件并取模,获得显示屏代码,基于STC32单片机,在8x8点阵LED模块上实现动画播放。项目方案将目标动图或视频提取为帧图片,可通过MATLAB程序实现;将帧图片裁剪为目标显示屏的像素比例,如0.96英寸OLED显示屏的像素为128x64,......