为了在屏幕上显示,我们将使用SDL.SDL是Simple Direct Layer的缩写。它是一个出色的多媒体库,适用于多平台,并且被用在许多工程中。你可以从它的官方网站的网址 http://www.libsdl.org/ 上来得到这个库的源代码或者如果有可能的话你可以直接下载开发包到你的操作系统中。按照这个指导,你将需要编译这个库。(剩下的几个指导中也是一样)
SDL_Init()函数告诉�?span lang="EN-US">SDL库,哪些特性我们将要用到。当�?span lang="EN-US">SDL_GetError()是一个用来手工除错的函数�?span lang="EN-US">
创建一个显�?span lang="EN-US">
现在我们需要在屏幕上的一个地方放上一些东西。在SDL中显示图像的基本区域叫做surface�?/span>
这就创建了一个给定高度和宽度的屏幕。下一个选项是屏幕的颜色深度―�?span lang="EN-US">0表示使用和当前一样的深度。(这个�?span lang="EN-US">OS X系统上不能正常工作,原因请看源代码)
现在我们在屏幕上来创建一�?span lang="EN-US">YUV覆盖以便于我们输入视频上去:
SDL_Overlay *bmp;
bmp = SDL_CreateYUVOverlay(pCodecCtx->width, pCodecCtx->height, SDL_YV12_OVERLAY, screen);
正如前面我们所说的,我们使�?span lang="EN-US">YV12来显示图像�?span lang="EN-US">
显示图像
前面那些都是很简单的。现在我们需要来显示图像。让我们看一下是如何来处理完成后的帧的。我们将原来�?span lang="EN-US">RGB处理的方式,并且替换 SaveFrame() 为显示到屏幕上的代码。为了显示到屏幕上,我们将先建立一�?span lang="EN-US">AVPicture结构体并且设置其数据指针和行尺寸来为我们�?span lang="EN-US">YUV覆盖服务�?/span>
首先,我们锁定这个覆盖,因为我们将要去改写它。这是一个避免以后发生问题的好习惯。正如前面所示的,这�?span lang="EN-US">AVPicture结构体有一个数据指针指向一个有4个元素的指针数据。由于我们处理的�?span lang="EN-US">YUV420P,所以我们只需�?span lang="EN-US">3个通道即只要三组数据。其它的格式可能需要第四个指针来表�?span lang="EN-US">alpha通道或者其它参数。行尺寸正如它的名字表示的意义一样。在YUV覆盖中相同功能的结构体是像素pixel和程�?span lang="EN-US">pitch。(程度pitch是在SDL里用来表示指定行数据宽度的值)。所以我们现在做的是让我们的覆盖中的pict.data中的三个指针有一个指向必要的空间的地址。类似的,我们可以直接从覆盖中得到行尺寸信息。像前面一样我们使�?span lang="EN-US">img_convert来把格式转换�?span lang="EN-US">PIX_FMT_YUV420P�?/span>
绘制图像
但我们仍然需要告�?span lang="EN-US">SDL如何来实际显示我们给的数据。我们也会传递一个表明电影位置、宽度、高度和缩放大小的矩形参数给SDL的函数。这样,SDL为我们做缩放并且它可以通过显卡的帮忙来进行快速缩放�?/span>
让我们再花一点时间来看一�?span lang="EN-US">SDL的特性:它的事件驱动系统�?span lang="EN-US">SDL被设置成当你�?span lang="EN-US">SDL中点击或者移动鼠标或者向它发送一个信号它都将产生一个事件的驱动方式。如果你的程序想要处理用户输入的话,它就会检测这些事件。你的程序也可以产生事件并且传递给SDL事件系统。当使用SDL进行多线程编程的时候,这相当有用,这方面代码我们可以在指导4中看到。在这个程序中,我们将在处理完包以后就立即轮询事件。现在而言,我们将处理SDL_QUIT事件以便于我们退出:
让我们去掉旧的冗余代码,开始编译。如果你使用的是Linux或者其变体,使�?span lang="EN-US">SDL库进行编译的最好方式为�?/span>
gcc -o tutorial02 tutorial02.c -lavutil -lavformat -lavcodec -lz -lm / sdl-config --cflags --libs`
这里�?span lang="EN-US">sdl-config命令会打印出用于gcc编译的包含正�?span lang="EN-US">SDL库的适当参数。为了进行编译,在你自己的平台你可能需要做的有点不同:请查阅一�?span lang="EN-US">SDL文档中关于你的系统的那部分。一旦可以编译,就马上运行它�?span lang="EN-US">
当运行这个程序的时候会发生什么呢?电影简直跑疯了!实际上,我们只是以我们能从文件中解码帧的最快速度显示了所有的电影的帧。现在我们没有任何代码来计算出我们什么时候需要显示电影的帧。最后(在指�?span lang="EN-US">5),我们将花足够的时间来探讨同步问题。但一开始我们会先忽略这个,因为我们有更加重要的事情要处理:音频�?/span>
img_convert不存在?好吧,最新版本的确删除了这个函数,这里我们再实现一遍就ok了
int img_convert(AVPicture *dst, int dst_pix_fmt,
const AVPicture *src, int src_pix_fmt,
int src_width, int src_height)
{
int w;
int h;
SwsContext *pSwsCtx;
w = src_width;
h = src_height;
pSwsCtx = sws_getContext(w, h, (PixelFormat)src_pix_fmt,
w, h, (PixelFormat)dst_pix_fmt,
SWS_BICUBIC, NULL, NULL, NULL);
sws_scale(pSwsCtx, src->data, src->linesize,
0, h, dst->data, dst->linesize);
//这里释放掉pSwsCtx的内存
return 0;
}