ffmpeg + sdl player console
{
#include <iostream> extern "C" { #include <SDL.h> } static Uint8 *pAudio_chunk; static Uint32 audio_len; static Uint8 *pAudio_pos; void fill_audio_buffer(void *userdata, Uint8 * stream, int len) { SDL_memset(stream, 0, len); // 判断是否有读到数据 if (audio_len == 0) return; len = (len > audio_len ? audio_len : len); SDL_MixAudio(stream, pAudio_pos, len, SDL_MIX_MAXVOLUME); pAudio_pos += len; audio_len -= len; } int playAudio(const char *file) { /*** 初始化SDL ***/ if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_TIMER)) { printf("Initialize SDL failed: %s\n", SDL_GetError()); return -1; } /****************/ /*** 初始化初始化SDL_AudioSpec结构体 ***/ SDL_AudioSpec audioSpec; // 音频数据的采样率。常用的有48000,44100等 audioSpec.freq = 48000; // 音频数据的格式 audioSpec.format = AUDIO_F32LSB; // 声道数。例如单声道取值为1,立体声取值为2 audioSpec.channels = 2; // 设置静音的值 audioSpec.silence = 0; // 音频缓冲区中的采样个数,要求必须是2的n次方 audioSpec.samples = 1024; // 填充音频缓冲区的回调函数 audioSpec.callback = fill_audio_buffer; /************************************/ // 打开音频设备 if (SDL_OpenAudio(&audioSpec, nullptr) < 0) { printf("Can not open audio!"); return -1; } FILE *pAudioFile = fopen(file, "rb+"); if (pAudioFile == nullptr) { printf("Can not open audio file!"); return -1; } int pcm_buffer_size = 48000; char *pcm_buffer = (char *)malloc(pcm_buffer_size); int data_count = 0; SDL_PauseAudio(0); for (;;) { // 循环播放 if (fread(pcm_buffer, 1, pcm_buffer_size, pAudioFile) != pcm_buffer_size) { fseek(pAudioFile, 0, SEEK_SET); fread(pcm_buffer, 1, pcm_buffer_size, pAudioFile); data_count = 0; } printf("Playing %10d Bytes data.\n", data_count); data_count += pcm_buffer_size; pAudio_chunk = (Uint8 *)pcm_buffer; audio_len = pcm_buffer_size; pAudio_pos = pAudio_chunk; while (audio_len > 0) SDL_Delay(0); } free(pcm_buffer); SDL_Quit(); } //======================================= const int bpp = 12; //int screen_w=500,screen_h=500; //const int pixel_w=680,pixel_h=180; int screen_w = 640, screen_h = 360; const int pixel_w = 960, pixel_h = 544;//这里必须与原视频的宽高像素匹配 unsigned char buffer[pixel_w*pixel_h*bpp / 8]; //Refresh Event #define REFRESH_EVENT (SDL_USEREVENT + 1) //Break #define BREAK_EVENT (SDL_USEREVENT + 2) int thread_exit = 0; int refresh_video(void *opaque) { thread_exit = 0; while (thread_exit == 0) { SDL_Event event; event.type = REFRESH_EVENT;//自定义的事件 SDL_PushEvent(&event); SDL_Delay(40); } thread_exit = 0; //Break SDL_Event event; event.type = BREAK_EVENT;//自定义的事件 SDL_PushEvent(&event); return 0; } int playVideo(const char *file) { 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 = 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(file, "rb+");//只读(r)写(+)方式,打开一个二进制文件(b) 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; int player_state = 1;//0:表示暂定,1表示继续播放 while (1) { //Wait SDL_WaitEvent(&event); if (event.type == REFRESH_EVENT && player_state == 1) { 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); } SDL_UpdateTexture(sdlTexture, NULL, buffer, pixel_w); //FIX: If window is resize 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 == BREAK_EVENT) { break; } else if (event.key.keysym.scancode == SDL_SCANCODE_SPACE && event.key.state == SDL_PRESSED)//按空格键,暂停或者播放 { SDL_Delay(40); player_state = (player_state == 1) ? 0 : 1; printf("player_state=%d\n", player_state); } else if (event.key.keysym.scancode == SDL_SCANCODE_ESCAPE && event.key.state == SDL_PRESSED)//按Esc键,退出播放 { SDL_Delay(40); break; //SDL_Quit(); } //printf("event.key.keysym.scancode=%d\n", event.key.keysym.scancode); } SDL_Quit(); return 0; } int player(const char *audio, const char *video) { /*** 初始化SDL ***/ if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_TIMER)) { printf("Initialize SDL failed: %s\n", SDL_GetError()); return -1; } /****************/ /*** 初始化初始化SDL_AudioSpec结构体 ***/ SDL_AudioSpec audioSpec; // 音频数据的采样率。常用的有48000,44100等 audioSpec.freq = 48000; // 音频数据的格式 audioSpec.format = AUDIO_F32LSB; // 声道数。例如单声道取值为1,立体声取值为2 audioSpec.channels = 2; // 设置静音的值 audioSpec.silence = 0; // 音频缓冲区中的采样个数,要求必须是2的n次方 audioSpec.samples = 1024; // 填充音频缓冲区的回调函数 audioSpec.callback = fill_audio_buffer; /************************************/ // 打开音频设备 if (SDL_OpenAudio(&audioSpec, nullptr) < 0) { printf("Can not open audio!"); return -1; } FILE *pAudioFile = fopen(audio, "rb+"); if (pAudioFile == nullptr) { printf("Can not open audio file!"); return -1; } int pcm_buffer_size = 48000; char *pcm_buffer = (char *)malloc(pcm_buffer_size); int data_count = 0; SDL_PauseAudio(0); // SDL_Window *screen; //SDL 2.0 Support for multiple windows 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(video, "rb+");//只读(r)写(+)方式,打开一个二进制文件(b) 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; int player_state = 1;//0:表示暂定,1表示继续播放 // for (;;) { // 循环播放 if (fread(pcm_buffer, 1, pcm_buffer_size, pAudioFile) != pcm_buffer_size) { fseek(pAudioFile, 0, SEEK_SET); fread(pcm_buffer, 1, pcm_buffer_size, pAudioFile); data_count = 0; } printf("Playing %10d Bytes data.\n", data_count); data_count += pcm_buffer_size; pAudio_chunk = (Uint8 *)pcm_buffer; audio_len = pcm_buffer_size; pAudio_pos = pAudio_chunk; while (audio_len > 0) SDL_Delay(0); //Wait SDL_WaitEvent(&event); if (event.type == REFRESH_EVENT && player_state == 1) { 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); } SDL_UpdateTexture(sdlTexture, NULL, buffer, pixel_w); //FIX: If window is resize 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 == BREAK_EVENT) { break; } else if (event.key.keysym.scancode == SDL_SCANCODE_SPACE && event.key.state == SDL_PRESSED)//按空格键,暂停或者播放 { SDL_Delay(40); player_state = (player_state == 1) ? 0 : 1; //printf("player_state=%d\n", player_state); } else if (event.key.keysym.scancode == SDL_SCANCODE_ESCAPE && event.key.state == SDL_PRESSED)//按Esc键,退出播放 { SDL_Delay(40); break; //SDL_Quit(); } //printf("event.key.keysym.scancode=%d\n", event.key.keysym.scancode); } free(pcm_buffer); SDL_Quit(); return 0; } //int SDL_main(int argc, char *argv[]) int main(int argc, char *argv[]) { //playAudio("D:\\out0.pcm"); //playVideo("D:\\out0.yuv"); //player("D:\\out0.pcm", "D:\\out0.yuv"); return 0; }
}