FFplay框架
main函数
int main(int argc, char **argv) { int flags; VideoState *is; // av_log_set_level(AV_LOG_TRACE); init_dynload(); // 1. 对FFmpeg的初始化 av_log_set_flags(AV_LOG_SKIP_REPEATED); parse_loglevel(argc, argv, options); /// av_log_set_level(AV_LOG_DEBUG); /* register all codecs, demux and protocols */ #if CONFIG_AVDEVICE avdevice_register_all(); #endif avformat_network_init(); init_opts(); signal(SIGINT , sigterm_handler); /* Interrupt (ANSI). */ signal(SIGTERM, sigterm_handler); /* Termination (ANSI). */ show_banner(argc, argv, options); // 2. 对传递的参数进行初始化 parse_options(NULL, argc, argv, options, opt_input_file); if (!input_filename) { show_usage(); av_log(NULL, AV_LOG_FATAL, "An input file must be specified\n"); av_log(NULL, AV_LOG_FATAL, "Use -h to get full help or, even better, run 'man %s'\n", program_name); exit(1); } /* 是否显示视频 */ if (display_disable) { video_disable = 1; } // 3. SDL的初始化 flags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER; /* 是否运行音频 */ if (audio_disable) flags &= ~SDL_INIT_AUDIO; else { /* Try to work around an occasional ALSA buffer underflow issue when the * period size is NPOT due to ALSA resampling by forcing the buffer size. */ if (!SDL_getenv("SDL_AUDIO_ALSA_SET_BUFFER_SIZE")) SDL_setenv("SDL_AUDIO_ALSA_SET_BUFFER_SIZE","1", 1); } if (display_disable) flags &= ~SDL_INIT_VIDEO; if (SDL_Init (flags)) { av_log(NULL, AV_LOG_FATAL, "Could not initialize SDL - %s\n", SDL_GetError()); av_log(NULL, AV_LOG_FATAL, "(Did you set the DISPLAY variable?)\n"); exit(1); } // 禁用一些事件 SDL_EventState(SDL_SYSWMEVENT, SDL_IGNORE); SDL_EventState(SDL_USEREVENT, SDL_IGNORE); av_init_packet(&flush_pkt); // 初始化flush_packet flush_pkt.data = (uint8_t *)&flush_pkt; // 初始化为数据指向自己本身 // 4. 创建窗口 if (!display_disable) { int flags = SDL_WINDOW_HIDDEN; if (alwaysontop) #if SDL_VERSION_ATLEAST(2,0,5) flags |= SDL_WINDOW_ALWAYS_ON_TOP; #else av_log(NULL, AV_LOG_WARNING, "Your SDL version doesn't support SDL_WINDOW_ALWAYS_ON_TOP. Feature will be inactive.\n"); #endif if (borderless) flags |= SDL_WINDOW_BORDERLESS; else flags |= SDL_WINDOW_RESIZABLE; window = SDL_CreateWindow(program_name, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, default_width, default_height, flags); SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); if (window) { renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); if (!renderer) { av_log(NULL, AV_LOG_WARNING, "Failed to initialize a hardware accelerated renderer: %s\n", SDL_GetError()); renderer = SDL_CreateRenderer(window, -1, 0); } if (renderer) { if (!SDL_GetRendererInfo(renderer, &renderer_info)) av_log(NULL, AV_LOG_VERBOSE, "Initialized %s renderer.\n", renderer_info.name); } } if (!window || !renderer || !renderer_info.num_texture_formats) { av_log(NULL, AV_LOG_FATAL, "Failed to create window or renderer: %s", SDL_GetError()); do_exit(NULL); } } // 5. 通过stream_open函数,开启read_thread读取线程 is = stream_open(input_filename, file_iformat); if (!is) { av_log(NULL, AV_LOG_FATAL, "Failed to initialize VideoState!\n"); do_exit(NULL); } // 6. 事件响应 event_loop(is); /* never returns */ return 0; }
main函数做的事比较简单主要做了几件事:
- 数据初始化,这里包括日志、ffmpeg、SDL和输入参数解析等。
- 通过SDL创建窗口。
- 打开文件。
- 启动事件循环监听,这里主要是鼠标键盘事件、窗口事件和退出事件。