基于SDL3的简单播放器

发布时间 2023-08-25 16:18:46作者: Traveller_Leon

修改自雷神的代码,使用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 }
View Code

 

基于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 }
View Code