介绍
我是李铁山,ffplay是基于ffmpeg的播放器,B站大名鼎鼎的ijkplayer也是基于此二次开发,因此很有学习价值。
这篇文章将会从main函数,自顶向下地剖析源码。
如果您对于源码感兴趣,可以查看ffplay的github地址https://github.com/FFmpeg/FFmpeg/blob/master/fftools/ffplay.c
解读源码
上次的代码讲完了前半段,咱接着讲后半段。如果您对前半段感兴趣,请查看ffplay深入解析——main函数解析篇(五)
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;
#ifdef SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR
SDL_SetHint(SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR, "0");
#endif
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);
}
}
大体上看,后半段代码主要与 SDL_CreateWindow 和 SDL_CreateRenderer 有关,这块比较重要,也比较的墨守成规,开发的时候按流程走就好。
首先是 SDL_CreateWindow,原函数是 SDL_Window* SDL_CreateWindow(const char* title, int x, int y, int width, int height, uint_32t flags)。
const char* title:窗口标题
int x:窗口左上角相对与屏幕的 x 坐标,用来做横向定位
int y:窗口左上角相对于屏幕的 y 坐标,用来左纵向定位
int width:窗口的宽度,定义窗口大小
int height:窗口的高度,定义窗口大小
uint32_t flags:标志位,指定窗口的各种属性。想深入了解的朋友可以阅读前篇的几篇文章,讲到了 flags 属性的设置。
好了,SDL_CreateWindow 讲完了。接下来我们看 SDL_SetHint,这个代码是告诉SDL渲染器,当需要缩放图像时,应使用线性插值方法。知道这个就行,不深入讲。
接下来有个条件判断,用来初始化渲染器的,渲染器主要是用来渲染2D图像和3D模型的。我们看一下:
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);
}
}
首先,是 window 初始化完成后处理的。开始运用 SDL_CreateRenderer 来初始化渲染器。其中函数中的第一个参数 window 是渲染器关联的窗口,第二个参数 -1 是驱动的索引,通常为-1,第三个参数是设置渲染器的属性。
然后判断初始化渲染器是否成功,如果没有成功,则打印初始化失败的信息,并且尝试重新初始化一个不带任何属性的渲染器。
如果初始化渲染器成功,就打印渲染器的名字信息。这个我们不深究。
最后是判断看看各项内容有没有初始化成功的。看看一下代码
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);
}
如果没有初始化窗口、渲染器、渲染器信息(render_info.num_texture_formats)成功,就打印失败信息并退出程序。
好了,这段代码我分为两篇讲完了。大家结合两篇好好理解一下。最后还剩一点代码,下一篇讲。
欲知后事如何,请听下回分解。