基于SDL3的简单播放器
修改自雷神的代码,使用SDL3。目前SDL3还没有正式发布,只作为学习用。
感觉Audio模块的API变化比Video大,而且也没有丰富的官方样例程序,可以运行,但不保证代码的正确性。
VS工程已经配置好了,SDL库也是直接放在仓库中,应该是可以直接使用,如果有问题可以交流。
本人使用的是VS2019
基于SDL3播放PCM文件:https://github.com/xuminjieleon/simplest_media_play/blob/master/simplest_audio_play_sdl2/simplest_audio_play_sdl2.cpp
参考 https://github.com/libsdl-org/SDL/blob/main/test/loopwave.c

1 #include <stdio.h> 2 #include <tchar.h> 3 4 #include "SDL3/SDL.h" 5 #include "SDL3/SDL_audio.h" 6 7 //Buffer: 8 //|-----------|-------------| 9 //chunk-------pos---len-----| 10 static Uint8 *audio_chunk; 11 static Uint32 audio_len; 12 static Uint8 *audio_pos; 13 14 static SDL_AudioDeviceID audioDeviceId; 15 static SDL_AudioStream* stream; 16 17 static void quit(int rc) 18 { 19 SDL_Quit(); 20 /* Let 'main()' return normally */ 21 if (rc != 0) { 22 exit(rc); 23 } 24 } 25 26 static void close_audio(void) 27 { 28 if (audioDeviceId != 0) { 29 SDL_DestroyAudioStream(stream); 30 stream = NULL; 31 SDL_CloseAudioDevice(audioDeviceId); 32 audioDeviceId = 0; 33 } 34 } 35 36 static void open_audio(void) 37 { 38 //SDL_AudioSpec 39 SDL_AudioSpec wanted_spec; 40 wanted_spec.freq = 44100; 41 wanted_spec.format = SDL_AUDIO_S16SYS; 42 wanted_spec.channels = 2; 43 44 audioDeviceId = SDL_OpenAudioDevice(SDL_AUDIO_DEVICE_DEFAULT_OUTPUT, &wanted_spec); 45 if (!audioDeviceId) { 46 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't open audio: %s\n", SDL_GetError()); 47 quit(2); 48 } 49 50 stream = SDL_CreateAndBindAudioStream(audioDeviceId, &wanted_spec); 51 if (!stream) 52 { 53 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create audio stream: %s\n", SDL_GetError()); 54 SDL_CloseAudioDevice(audioDeviceId); 55 quit(2); 56 } 57 } 58 59 int main(int argc, char* argv[]) 60 { 61 //Init 62 if(SDL_Init(SDL_INIT_AUDIO | SDL_INIT_TIMER | SDL_INIT_EVENTS)) { 63 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Could not initialize SDL - %s\n", SDL_GetError()); 64 return -1; 65 } 66 67 open_audio(); 68 69 FILE *fp=fopen("../NocturneNo2inEflat_44.1k_s16le.pcm","rb+"); 70 if (fp == NULL) { 71 printf("cannot open this file\n"); 72 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "cannot open this file\n"); 73 return -1; 74 } 75 76 int pcm_buffer_size=4096; 77 char *pcm_buffer=(char *)SDL_malloc(pcm_buffer_size); 78 int data_count=0; 79 80 bool done = 0; 81 while(!done){ 82 if (fread(pcm_buffer, 1, pcm_buffer_size, fp) != pcm_buffer_size){ 83 // Loop 84 fseek(fp, 0, SEEK_SET); 85 fread(pcm_buffer, 1, pcm_buffer_size, fp); 86 data_count=0; 87 } 88 89 SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Now Playing %10d Bytes data.\n", data_count); 90 data_count+=pcm_buffer_size; 91 //Set audio buffer (PCM data) 92 audio_chunk = (Uint8 *) pcm_buffer; 93 //Audio buffer length 94 audio_len =pcm_buffer_size; 95 audio_pos = audio_chunk; 96 97 int ret = SDL_PutAudioStreamData(stream, audio_chunk, audio_len); 98 if(ret == 0) 99 audio_pos += audio_len; 100 else 101 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't SDL_PutAudioStreamData: %s\n", SDL_GetError()); 102 103 SDL_Event event; 104 while (SDL_PollEvent(&event) > 0) { 105 if (event.type == SDL_EVENT_QUIT) { 106 done = 1; 107 } 108 } 109 } 110 111 free(pcm_buffer); 112 close_audio(); 113 SDL_Quit(); 114 115 return 0; 116 }
基于SDL3播放Video文件:https://github.com/xuminjieleon/simplest_media_play/blob/master/simplest_video_play_sdl2/simplest_video_play_sdl2.cpp

1 #include <stdio.h> 2 3 #include "SDL3/SDL.h" 4 5 //set '1' to choose a type of file to play 6 #define LOAD_BGRA 1 7 #define LOAD_RGB24 0 8 #define LOAD_BGR24 0 9 #define LOAD_YUV420P 0 10 11 //Bit per Pixel 12 #if LOAD_BGRA 13 const int bpp=32; 14 #elif LOAD_RGB24|LOAD_BGR24 15 const int bpp=24; 16 #elif LOAD_YUV420P 17 const int bpp=12; 18 #endif 19 20 int screen_w=500,screen_h=500; 21 const int pixel_w=320,pixel_h=180; 22 23 unsigned char buffer[pixel_w*pixel_h*bpp/8]; 24 //BPP=32 25 unsigned char buffer_convert[pixel_w*pixel_h*4]; 26 27 //Convert RGB24/BGR24 to RGB32/BGR32 28 //And change Endian if needed 29 void CONVERT_24to32(unsigned char *image_in,unsigned char *image_out,int w,int h){ 30 for(int i =0;i<h;i++) 31 for(int j=0;j<w;j++){ 32 //Big Endian or Small Endian? 33 //"ARGB" order:high bit -> low bit. 34 //ARGB Format Big Endian (low address save high MSB, here is A) in memory : A|R|G|B 35 //ARGB Format Little Endian (low address save low MSB, here is B) in memory : B|G|R|A 36 if(SDL_BYTEORDER==SDL_LIL_ENDIAN){ 37 //Little Endian (x86): R|G|B --> B|G|R|A 38 image_out[(i*w+j)*4+0]=image_in[(i*w+j)*3+2]; 39 image_out[(i*w+j)*4+1]=image_in[(i*w+j)*3+1]; 40 image_out[(i*w+j)*4+2]=image_in[(i*w+j)*3]; 41 image_out[(i*w+j)*4+3]='0'; 42 }else{ 43 //Big Endian: R|G|B --> A|R|G|B 44 image_out[(i*w+j)*4]='0'; 45 memcpy(image_out+(i*w+j)*4+1,image_in+(i*w+j)*3,3); 46 } 47 } 48 } 49 50 51 //Refresh Event 52 #define REFRESH_EVENT (SDL_EVENT_USER + 1) 53 //Break 54 #define BREAK_EVENT (SDL_EVENT_USER + 2) 55 56 int thread_exit=0; 57 58 int refresh_video(void *opaque){ 59 thread_exit=0; 60 while (!thread_exit) { 61 SDL_Event event; 62 event.type = REFRESH_EVENT; 63 SDL_PushEvent(&event); 64 SDL_Delay(40); 65 } 66 thread_exit=0; 67 //Break 68 SDL_Event event; 69 event.type = BREAK_EVENT; 70 SDL_PushEvent(&event); 71 return 0; 72 } 73 74 int main(int argc, char* argv[]) 75 { 76 if(SDL_Init(SDL_INIT_VIDEO)) { 77 printf( "Could not initialize SDL - %s\n", SDL_GetError()); 78 return -1; 79 } 80 81 SDL_Window *screen; 82 //SDL 2.0 Support for multiple windows 83 screen = SDL_CreateWindow("Simplest Video Play SDL2", 84 screen_w, screen_h,SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE); 85 if(!screen) { 86 printf("SDL: could not create window - exiting:%s\n",SDL_GetError()); 87 return -1; 88 } 89 SDL_Renderer* sdlRenderer = SDL_CreateRenderer(screen, 0, 0); 90 91 Uint32 pixformat=0; 92 #if LOAD_BGRA 93 //Note: ARGB8888 in "Little Endian" system stores as B|G|R|A 94 pixformat= SDL_PIXELFORMAT_ARGB8888; 95 #elif LOAD_RGB24 96 pixformat= SDL_PIXELFORMAT_RGB888; 97 #elif LOAD_BGR24 98 pixformat= SDL_PIXELFORMAT_BGR888; 99 #elif LOAD_YUV420P 100 //IYUV: Y + U + V (3 planes) 101 //YV12: Y + V + U (3 planes) 102 pixformat= SDL_PIXELFORMAT_IYUV; 103 #endif 104 105 SDL_Texture* sdlTexture = SDL_CreateTexture(sdlRenderer,pixformat, SDL_TEXTUREACCESS_STREAMING,pixel_w,pixel_h); 106 107 FILE *fp=NULL; 108 #if LOAD_BGRA 109 fp=fopen("../test_bgra_320x180.rgb","rb+"); 110 #elif LOAD_RGB24 111 fp=fopen("../test_rgb24_320x180.rgb","rb+"); 112 #elif LOAD_BGR24 113 fp=fopen("../test_bgr24_320x180.rgb","rb+"); 114 #elif LOAD_YUV420P 115 fp=fopen("../test_yuv420p_320x180.yuv","rb+"); 116 #endif 117 if(fp==NULL){ 118 printf("cannot open this file\n"); 119 return -1; 120 } 121 122 SDL_FRect sdlRect; 123 124 SDL_Thread *refresh_thread = SDL_CreateThread(refresh_video,NULL,NULL); 125 SDL_Event event; 126 while(1){ 127 //Wait 128 SDL_WaitEvent(&event); 129 if(event.type==REFRESH_EVENT){ 130 if (fread(buffer, 1, pixel_w*pixel_h*bpp/8, fp) != pixel_w*pixel_h*bpp/8){ 131 // Loop 132 fseek(fp, 0, SEEK_SET); 133 fread(buffer, 1, pixel_w*pixel_h*bpp/8, fp); 134 } 135 136 #if LOAD_BGRA 137 //We don't need to change Endian 138 //Because input BGRA pixel data(B|G|R|A) is same as ARGB8888 in Little Endian (B|G|R|A) 139 SDL_UpdateTexture( sdlTexture, NULL, buffer, pixel_w*4); 140 #elif LOAD_RGB24|LOAD_BGR24 141 //change 24bit to 32 bit 142 //and in Windows we need to change Endian 143 CONVERT_24to32(buffer,buffer_convert,pixel_w,pixel_h); 144 SDL_UpdateTexture( sdlTexture, NULL, buffer_convert, pixel_w*4); 145 #elif LOAD_YUV420P 146 SDL_UpdateTexture( sdlTexture, NULL, buffer, pixel_w); 147 #endif 148 //FIX: If window is resize 149 sdlRect.x = 0; 150 sdlRect.y = 0; 151 sdlRect.w = screen_w; 152 sdlRect.h = screen_h; 153 154 SDL_RenderClear( sdlRenderer ); 155 SDL_RenderTexture( sdlRenderer, sdlTexture, NULL, &sdlRect); 156 SDL_RenderPresent( sdlRenderer ); 157 158 }else if(event.type== SDL_EVENT_WINDOW_RESIZED){ 159 //If Resize 160 SDL_GetWindowSize(screen,&screen_w,&screen_h); 161 }else if(event.type== SDL_EVENT_QUIT){ 162 thread_exit=1; 163 }else if(event.type==BREAK_EVENT){ 164 break; 165 } 166 } 167 SDL_Quit(); 168 169 return 0; 170 }