示例使用的是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的大小。

posted on 2024-07-24 20:27  NOPASSWD  阅读(25)  评论(0编辑  收藏  举报