(SDL2)SDL在ubuntu下的测试代码(雷霄骅)
安装好SDL后,可以使用代码测试一下,本文所用代码为雷神的代码,只修改了头文件即可,一个为播放音频,一个为播放视频,但是播放音频的会有明显卡顿,如果后续找到问题,会及时修改,如果你已解决,欢迎评论分享。
1.播放PCM
/*** 最简单的SDL2播放音频的例子(SDL2播放PCM)* Simplest Audio Play SDL2 (SDL2 play PCM) ** 雷霄骅 Lei Xiaohua* leixiaohua1020@126.com* 中国传媒大学/数字电视技术* Communication University of China / Digital TV Technology* http://blog.csdn.net/leixiaohua1020** 本程序使用SDL2播放PCM音频采样数据。SDL实际上是对底层绘图* API(Direct3D,OpenGL)的封装,使用起来明显简单于直接调用底层* API。** 函数调用步骤如下: ** [初始化]* SDL_Init(): 初始化SDL。* SDL_OpenAudio(): 根据参数(存储于SDL_AudioSpec)打开音频设备。* SDL_PauseAudio(): 播放音频数据。** [循环播放数据]* SDL_Delay(): 延时等待播放完成。** This software plays PCM raw audio data using SDL2.* SDL is a wrapper of low-level API (DirectSound).* Use SDL is much easier than directly call these low-level API.** The process is shown as follows:** [Init]* SDL_Init(): Init SDL.* SDL_OpenAudio(): Opens the audio device with the desired * parameters (In SDL_AudioSpec).* SDL_PauseAudio(): Play Audio.** [Loop to play data]* SDL_Delay(): Wait for completetion of playback.*/#include <stdio.h>
// #include <tchar.h>extern "C"
{
#include "SDL2/SDL.h"
};//Buffer:
//|-----------|-------------|
//chunk-------pos---len-----|
static Uint8 *audio_chunk;
static Uint32 audio_len;
static Uint8 *audio_pos; /* Audio Callback* The audio function callback takes the following parameters: * stream: A pointer to the audio buffer to be filled * len: The length (in bytes) of the audio buffer *
*/
void fill_audio(void *udata,Uint8 *stream,int len){ //SDL 2.0SDL_memset(stream, 0, len);if(audio_len==0) /* Only play if we have data left */ return; len=(len>audio_len?audio_len:len); /* Mix as much data as possible */ SDL_MixAudio(stream,audio_pos,len,SDL_MIX_MAXVOLUME);audio_pos += len; audio_len -= len;
} int main(int argc, char* argv[])
{//Initif(SDL_Init(SDL_INIT_AUDIO | SDL_INIT_TIMER)) { printf( "Could not initialize SDL - %s\n", SDL_GetError()); return -1;}//SDL_AudioSpecSDL_AudioSpec wanted_spec;wanted_spec.freq = 44100; wanted_spec.format = AUDIO_S16SYS; wanted_spec.channels = 2; wanted_spec.silence = 0; wanted_spec.samples = 1024; wanted_spec.callback = fill_audio; if (SDL_OpenAudio(&wanted_spec, NULL)<0){ printf("can't open audio.\n"); return -1; } FILE *fp=fopen("NocturneNo2inEflat_44.1k_s16le.pcm","rb+");if(fp == NULL){printf("cannot open this file\n");return -1;}int pcm_buffer_size=4096;char *pcm_buffer=(char *)malloc(pcm_buffer_size);int data_count=0;//PlaySDL_PauseAudio(0);while(1){if (fread(pcm_buffer, 1, pcm_buffer_size, fp) != pcm_buffer_size){// Loopfseek(fp, 0, SEEK_SET);fread(pcm_buffer, 1, pcm_buffer_size, fp);data_count=0;} printf("Now Playing %10d Bytes data.\n",data_count);data_count+=pcm_buffer_size;//Set audio buffer (PCM data)audio_chunk = (Uint8 *) pcm_buffer; //Audio buffer lengthaudio_len =pcm_buffer_size;audio_pos = audio_chunk;while(audio_len>0)//Wait until finishSDL_Delay(1); }free(pcm_buffer);SDL_Quit();return 0;
}
ubuntu下编译:
gcc simplest_audio_play_sdl2.cpp -g -o simplest_audio_play_sdl2.out \
-I /usr/local/include -L /usr/local/lib -lSDL2main -lSDL2
2.播放yuv
/*** 最简单的SDL2播放视频的例子(SDL2播放RGB/YUV)* Simplest Video Play SDL2 (SDL2 play RGB/YUV) ** 雷霄骅 Lei Xiaohua* leixiaohua1020@126.com* 中国传媒大学/数字电视技术* Communication University of China / Digital TV Technology* http://blog.csdn.net/leixiaohua1020** 本程序使用SDL2播放RGB/YUV视频像素数据。SDL实际上是对底层绘图* API(Direct3D,OpenGL)的封装,使用起来明显简单于直接调用底层* API。** 函数调用步骤如下: ** [初始化]* SDL_Init(): 初始化SDL。* SDL_CreateWindow(): 创建窗口(Window)。* SDL_CreateRenderer(): 基于窗口创建渲染器(Render)。* SDL_CreateTexture(): 创建纹理(Texture)。** [循环渲染数据]* SDL_UpdateTexture(): 设置纹理的数据。* SDL_RenderCopy(): 纹理复制给渲染器。* SDL_RenderPresent(): 显示。** This software plays RGB/YUV raw video data using SDL2.* SDL is a wrapper of low-level API (Direct3D, OpenGL).* Use SDL is much easier than directly call these low-level API. ** The process is shown as follows:** [Init]* SDL_Init(): Init SDL.* SDL_CreateWindow(): Create a Window.* SDL_CreateRenderer(): Create a Render.* SDL_CreateTexture(): Create a Texture.** [Loop to Render data]* SDL_UpdateTexture(): Set Texture's data.* SDL_RenderCopy(): Copy Texture to Render.* SDL_RenderPresent(): Show.*/#include <stdio.h>extern "C"
{
#include "SDL2/SDL.h"
};const int bpp=12;int screen_w=500,screen_h=500;
const int pixel_w=320,pixel_h=180;unsigned char buffer[pixel_w*pixel_h*bpp/8];//Refresh Event
#define REFRESH_EVENT (SDL_USEREVENT + 1)#define BREAK_EVENT (SDL_USEREVENT + 2)int thread_exit=0;int refresh_video(void *opaque){thread_exit=0;while (!thread_exit) {SDL_Event event;event.type = REFRESH_EVENT;SDL_PushEvent(&event);SDL_Delay(40);}thread_exit=0;//BreakSDL_Event event;event.type = BREAK_EVENT;SDL_PushEvent(&event);return 0;
}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 windowsscreen = 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; SDL_Thread *refresh_thread = SDL_CreateThread(refresh_video,NULL,NULL);SDL_Event event;while(1){//WaitSDL_WaitEvent(&event);if(event.type==REFRESH_EVENT){if (fread(buffer, 1, pixel_w*pixel_h*bpp/8, fp) != pixel_w*pixel_h*bpp/8){// Loopfseek(fp, 0, SEEK_SET);fread(buffer, 1, pixel_w*pixel_h*bpp/8, fp);}SDL_UpdateTexture( sdlTexture, NULL, buffer, pixel_w); //FIX: If window is resizesdlRect.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){//If ResizeSDL_GetWindowSize(screen,&screen_w,&screen_h);}else if(event.type==SDL_QUIT){thread_exit=1;}else if(event.type==BREAK_EVENT){break;}}SDL_Quit();return 0;
}
ubuntu下编译:
gcc simplest_video_play_sdl2.cpp -g -o simplest_video_play_sdl2.out \
-I /usr/local/include -L /usr/local/lib -lSDL2main -lSDL2
雷神写的demo合集:
批量下载
2021/11/16 更新
解决了雷神SDL2播放PCM音频例子中的哒哒噪音问题,原因是在回调函数内使用了混音器,修改如下:
把原来的将audio_pos混音到stream改为直接复制audio_pos内容到stream。
2021/11/17更新
发现播放时的哒哒噪音声音并不是代码问题,因为昨天播放没有问题的代码今天又出现了异常。复现昨天的步骤发现,我昨天是在用SDL2播放一段16KS16单声道音频后,发现没有噪音,又去运行这段代码发现异常的哒哒噪音就没有了,今天在先播放昨天那段单声道音频后,噪音又消失了,怀疑虚拟机声卡有异常,暂时先这样吧。