[2] SDL的基础知识以及利用SDL播放视频

来源:互联网 发布:中国房价与收入比知乎 编辑:程序博客网 时间:2024/06/13 23:00

此博文相关知识点从雷神的博客以及视频学习,截图也是用了他的课件,
雷神博客地址:http://blog.csdn.net/leixiaohua1020/


日期:2016.10.1
作者:isshe
github:github.com/isshe
邮箱:i.sshe@outlook.com


SDL基础知识

  • SDL结构图
    这里写图片描述

  • SDL函数调用的一般流程
    这里写图片描述

    • 最最主要操作的函数是SDL_texture();
    • 工作过程大致是:FFMpeg「Decode」解码一帧,交给SDL_texture(), 然后再复制给渲染器,渲染器再显示出来。以此循环。
    • 相关函数:待补充(不定期更新)
  • SDL的一些主要的数据结构
    这里写图片描述

    • SDL2支持多窗口显示,主要是依靠SDL_rect().
    • 相关数据结构:待补充(不定期更新)

示例代码1:

  • 代码
#include <stdio.h>#include "SDL2/SDL.h"#define SCREEN_W    640             //窗口的宽#define SCREEN_H    360             //窗口的高#define PIXEL_W     320             //视频像素的宽,要和视频文件相同才能显示正常#define PIXEL_H     180             //像素的高#define BPP         12              //像素深度:指存储每个像素所用的位数(bit)#define BUF_LEN     ((PIXEL_W) * (PIXEL_H) * (BPP) / 8)     //存一帧的需要空间const int bpp = BPP;int screen_w = SCREEN_W;int screen_h = SCREEN_H;const int pixel_w = PIXEL_W;const int pixel_h = PIXEL_H;unsigned char buffer[BUF_LEN+1];int main(int argc, char* argv[]){    if(SDL_Init(SDL_INIT_VIDEO)) {        printf( "Could not initialize SDL - %s\n", SDL_GetError());        return -1;    }    SDL_Window *screen;    //SDL 2.0 Support for multiple windows    //画一个窗口,大小为screen_w * screen_h    screen = SDL_CreateWindow("Simplest Video Play SDL2", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,screen_w,screen_h,SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE);    if(!screen) {        printf("SDL: could not create window - exiting:%s\n",SDL_GetError());        return -1;    }    //新建一个渲染器    SDL_Renderer* sdlRenderer = SDL_CreateRenderer(screen, -1, 0);    Uint32 pixformat=0;    //IYUV: Y + U + V  (3 planes)    //YV12: Y + V + U  (3 planes)    pixformat= SDL_PIXELFORMAT_IYUV;        //???    SDL_Texture* sdlTexture = SDL_CreateTexture(sdlRenderer,pixformat, SDL_TEXTUREACCESS_STREAMING,pixel_w,pixel_h);    FILE *fp=NULL;    fp=fopen("test_yuv420p_320x180.yuv","rb+");    if(fp==NULL){        printf("cannot open this file\n");        return -1;    }    SDL_Rect sdlRect;    int i = 5;    while(i >= 0){            //一次读1byte,总共读一帧            if (fread(buffer, 1, pixel_w*pixel_h*bpp/8, fp) != pixel_w*pixel_h*bpp/8){                // Loop                fseek(fp, 0, SEEK_SET);//              fread(buffer, 1, pixel_w*pixel_h*bpp/8, fp);                i--;                continue;            }            //更新纹理数据            SDL_UpdateTexture( sdlTexture, NULL, buffer, pixel_w);            //(x,y)是窗口左上边开始的点。            //w,h是整个像素窗口宽和高(注意不是整个窗口)            sdlRect.x = 0;            sdlRect.y = 0;            sdlRect.w = screen_w;            sdlRect.h = screen_h;            //清空渲染器            //复制数据纹理给渲染器            //显示            SDL_RenderClear( sdlRenderer );            SDL_RenderCopy( sdlRenderer, sdlTexture, NULL, &sdlRect);            SDL_RenderPresent( sdlRenderer );            //Delay 40ms,一般视频都是这个,25帧/s.            SDL_Delay(40);    }    SDL_Quit();    return 0;}
  • 编译:
gcc1_SDL_create_window.c -o 1_SDL_create_window.out -O2 -Wall -g -lSDL2 -lSDL2main

结果截图:
这里写图片描述
* 注意,这个程序如果是在windows下面,窗口是不能移动的,鼠标放上去也是忙的状态。在下一个程序中修改程序,使它能移动,以及自动适应窗口大小。


示例程序2:

  • 代码:
#include <stdio.h>#include <errno.h>#include <string.h>#include <SDL2/SDL.h>#define SCREEN_W    640             //窗口的宽#define SCREEN_H    360             //窗口的高#define PIXEL_W     320             //视频像素的宽,要和视频文件相同才能显示正常#define PIXEL_H     180             //像素的高#define BPP         12              //像素深度:指存储每个像素所用的位数(bit)#define BUF_LEN     ((PIXEL_W) * (PIXEL_H) * (BPP) / 8)     //存一帧的需要空间#define FILENAME    "test_yuv420p_320x180.yuv"#define MY_DEFINE_REFRESH_EVENT     (SDL_USEREVENT + 1)#define MY_DEFINE_BREAK_EVENT       (SDL_USEREVENT + 2)int thread_exit = 0;static int refresh_func(void *arg){    SDL_Event   event;    thread_exit = 0;    while(0 == thread_exit)    {        event.type = MY_DEFINE_REFRESH_EVENT;        SDL_PushEvent(&event);      //发送一个事件,使主线程继续运行        SDL_Delay(40);    }    //子线程退出后发送事件给主线程,使主线程也退出    thread_exit = 0;    event.type = MY_DEFINE_BREAK_EVENT;    SDL_PushEvent(&event);    return 0;}const int bpp = BPP;int main(int argc, char *argv[]){    int screen_w = SCREEN_W;    int screen_h = SCREEN_H;    const int pixel_w = PIXEL_W;    const int pixel_h = PIXEL_H;    unsigned char buffer[BUF_LEN + 1];      //注意类型    char            filename[256] = FILENAME;    SDL_Window      *screen = NULL;         //窗口数据结构    SDL_Renderer    *sdlRenderer = NULL;    //渲染器数据结构    Uint32          pixformat = 0;    SDL_Texture     *sdlTexture = NULL;     //主要操作的    FILE            *fp = NULL;    SDL_Rect        sdlRect;//    SDL_Thread      *refresh_thread = NULL; //线程数据结构    SDL_Event       event;                  //事件数据结构    //注意:可以把文件传进来了,但是如果不使用ffmmpeg的函数还不知道怎么改像素值,以使视频正常显示!!!!!    if (argc > 2)    {         printf("Usage: ./*.out videofile.yuv\n");         return 0;    }    else if (argc == 2)    {         memcpy(filename, argv[1], strlen(argv[1]) + 1);//         filename[strlen(argv[1])] = '\0';    }    printf("video file name: %s\n", filename);    if (SDL_Init(SDL_INIT_VIDEO))     {         printf("Couldn't initialize SDL - %s\n", SDL_GetError());         return (-1);     }    screen = SDL_CreateWindow("isshe Video Player SDL2",            SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,            screen_w, screen_h,            SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);    if (!screen)    {         printf("SDL:Couldn't not create window error: %s\n", SDL_GetError());         return (-1);    }    //创建渲染器,-1,0不懂什么意思,再看这个函数的定义    sdlRenderer = SDL_CreateRenderer(screen, -1, 0);    //在pixels.h中,大概是指定输入数据格式?不懂!    pixformat = SDL_PIXELFORMAT_IYUV;    sdlTexture = SDL_CreateTexture(sdlRenderer, pixformat,            SDL_TEXTUREACCESS_STREAMING, pixel_w, pixel_h);    //打开文件    fp = fopen(filename, "r");    if (NULL == fp)    {        printf("Open file error:%s\n", strerror(errno));        return (-1);    }    //新建线程//    refresh_thread =    SDL_CreateThread(refresh_func, NULL, NULL);    while(1)    {         //等待一个事件         SDL_WaitEvent(&event);     //事件的信息存到结构中了         //处理事件, 尝试使用自定义的事件         if (event.type == MY_DEFINE_REFRESH_EVENT)         {              //读一帧              if (fread(buffer, 1, BUF_LEN, fp) != BUF_LEN) //出错或结尾              {                  //重定位会文件头部                  fseek(fp, 0, SEEK_SET);                  continue;         //              }              //更新纹理,但是不懂最后一个参数,是一次更新一行吗?              SDL_UpdateTexture(sdlTexture, NULL, buffer, pixel_w);              sdlRect.x = 0;              sdlRect.y = 0;              sdlRect.w = screen_w;              sdlRect.h = screen_h;              SDL_RenderClear(sdlRenderer);              //把数据从第二个参数复制到第一个参数              SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, &sdlRect);              SDL_RenderPresent(sdlRenderer);         }         else if (event.type == SDL_WINDOWEVENT)         {              //获取像素窗口的大小,窗口拉伸的时候用这个则会自动调整              SDL_GetWindowSize(screen, &screen_w, &screen_h);         }         else if (event.type == SDL_QUIT)         {             thread_exit = 1;         }         else if (event.type == MY_DEFINE_BREAK_EVENT)    //线程结束,主线程也结束         {              break;         }    }    fclose(fp);    SDL_Quit();    return 0;}
  • 程序中主线程阻塞等待事件,子线程发送事件后主线程继续运行。
  • 程序中自定义了两个事件类型,用以说明事件类型可自定义。

  • 编译:

gcc  2_SDL_pthread_event.c -o 2_SDL_pthread_event.out -O2 -Wall -g -lSDL2 -lSDL2main
  • 运行结果:
    这里写图片描述
    • 可以随意拉伸窗口。
    • 可以关闭。

参考资料:

  • 雷神的视频
  • SDL2.0 源码

资料下载:http://download.csdn.net/detail/i_scream_/9644380

1 0
原创粉丝点击