原文地址:http://blog.csdn.net/i_scream_/article/details/52714378

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

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
  • 1

结果截图:

* 注意,这个程序如果是在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

SDL的基础知识以及利用SDL播放视频的更多相关文章

  1. iOS开发--利用MPMoviePlayerViewController播放视频简单实现

    一.MPMoviePlayerViewController和MPMoviePlayerController区分开,前者继承自NSObject,后者继承自UIViewController 二.MPMov ...

  2. iOS开发--利用MPMoviePlayerController播放视频简单实现

    一.包含头文件#import <MediaPlayer/MediaPlayer.h> 二.重点:给MPMoviePlayerController的view设置frame,并且将view添加 ...

  3. 利用MPMoviePlayerViewController 播放视频 iOS

    方法一: @property (nonatomic, strong) MPMoviePlayerController *player; NSString *url = [[NSBundle mainB ...

  4. 利用VideoView播放视频

    package com.qianhua.ui; 002   003 import android.app.Activity; 004 import android.content.Intent; 00 ...

  5. Unity3D基础学习 利用NGUI的Texture播放视频

    利用NGUI播放视频,首先你得导入你的视频 你的电脑中必须安装QuickTime软件,没有,去下一个,如果是Windows系统,安装完之后重启. 接下来转换你的视频格式,如果你的视频在QuickTim ...

  6. 菜鸟脱壳之脱壳的基础知识(五)——利用内存断点寻找OEP

    经过第一节的基础知识,我们都知道了,加壳程序首先解把原来压缩的代码解压,然后放到所对应的区块中,当外壳程序执行完毕后,跳回到OEP执行,我们都知道,OEP是放在代码段中,也就是当外壳程序处理完毕后,跳 ...

  7. HTML基础知识总结

    经过这段时间的学习,对于html的一些基础知识有了一定的了解.所谓好记性不如烂笔头,唯有一点点累积,才能汇聚成知识的海洋.现在,我对这段时间的学习做一个总结. 一.HTML的定义 HTML,超文本标记 ...

  8. Unity3D基础知识梳理

    这段时间在做Unity的项目,这差不多是我的第一次实战啊~然后公司来了实习的童鞋要学Unity,但是我一向不靠谱啊,所以只能帮他们稍微梳理下基础的东西了啊,唉~学长只能帮你们到这里了~顺便就把自己这两 ...

  9. Android 应用基础知识和应用组件

    应用基础知识 安装到设备后,每个 Android 应用都运行在自己的安全沙箱内: Android 操作系统是一种多用户 Linux 系统,其中的每个应用都是一个不同的用户: 默认情况下,系统会为每个应 ...

随机推荐

  1. 带你走进EJB--它都有哪些Bean

    通过前面一系列EJB的博客,我们已经对EJB有了一个宏观的了解.为够更好的在企业项目中使用EJB,我们很有必要对EJB的一些基本内容进行深入,这次我们主要进行的主题是Enterprise Java B ...

  2. 混沌数学之Duffing(杜芬)振子

    杜芬振子 Duffing oscillator是一个描写强迫振动的振动子,由非线性微分方程表示 杜芬方程列式如下: 其中 γ控制阻尼度 α控制韧度 β控制动力的非线性度 δ驱动力的振幅 ω驱动力的圆频 ...

  3. Informatica 常用组件Filter之一 概述

    转换类型:已连接.主动 过滤器转换允许您过滤映射中的行.通过过滤器转换从源转换传递所有的行,然后为转换输入过滤条件.所有过滤器转换中的端口均为输入/输出端口,只有符合条件的行才能通过过滤器转换. 在某 ...

  4. 第一章 Java常用集合类总览

    1.Java最常用的集合类 Collection接口 List接口(允许有重复元素):ArrayList.LinkedList.Vector.Stack Set接口(不允许有重复元素,可用于去重操作) ...

  5. [leetcode]Sum Root to Leaf Numbers @ Python

    原题地址:http://oj.leetcode.com/problems/sum-root-to-leaf-numbers/ 题意: Given a binary tree containing di ...

  6. sass与less

    刚刚发现sass这个东西,前端真热闹,下面比较一下这两者的共同点与区别. 开头总结一下,方便记忆:sass依赖后端计算能力,less依赖客户端的计算能力. 很多开发者不选择LESS是因为LESS输出修 ...

  7. IE11与Cognos怪谈

    想必大家都知道高版本的IE运行Cognos相关组件的时候要设置兼容性,安全级别相对调低等设置.但是升级了win10系统后,默认的IE版本是IE11的,装了Cognos10.2.1之后,进行了一个常规的 ...

  8. (字符串)最长公共子序列(Longest-Common-Subsequence,LCS)

    问题: 最长公共子序列就是寻找两个给定序列的子序列,该子序列在两个序列中以相同的顺序出现,但是不必要是连续的. 例如序列X=ABCBDAB,Y=BDCABA.序列BCA是X和Y的一个公共子序列,但是不 ...

  9. spring源代码系列(一)sring源代码编译 spring源代码下载 spring源代码阅读

    想对spring框架进行深入的学习一下,看看源码,提升和沉淀下自己,工欲善其事必先利其器,还是先搭建好开发环境吧. 环境搭建 sping源代码之前是svn管理,如今已经迁移到了github中了.新版本 ...

  10. JavsScript 之 求时间差

    var dateStart = new Date(); //开始时间var dateEnd = new Date(); //结束时间 var timePeriod = dateEnd.getTime( ...