分类: LINUX
2013-11-18 16:23:58
饮水思源
使用ffmpeg解码h.264得到的图片都是YUV格式(准确来说是YV12格式),不是RGB格式。如果直接使用GTK提供的库函数,效率将比较低,不能充分发挥显卡的性能。在LINUX下,为了充分发挥显卡的性能,降低CPU的负载,可以使用vx接口来播放图片。
xv又叫X-Video,是X-Window的一个扩展,为视频播放提供高速的接口。由于xv依赖显卡驱动,某些显卡可能不能提供播放YUV的接口,但大部分显卡应该没有这个问题。
为了减少麻烦,可以选用ubuntu作为开发平台,选择“新立得软件包管理器”来安装开发需要的软件包。需要安装的开发包有:libgtk-3-dev、libX11-dev和libxv-dev。
如何现实YUV图片呢?需要先从XvCreateImage这函数说起。
XvImage * XvCreateImage (Display *dpy,XvPortID port,int id, char *data,int width, int height);
需要包含的头文件有:
#include
#include
#include
#include
需要使用到的参数以及获取方法:
static GtkWidget *drawing_area1; //GTK3的用来画图的一个控件
//以下参数应该在gtk_widget_show (pTopWindow);后获取
static Display *display; //通过GDK_WINDOW_XDISPLAY(gtk_widget_get_window(drawing_area1));获取;这个值对于每个进程来说是唯一的。
static int screen; //通过GDK_SCREEN_XNUMBER(gtk_widget_get_screen(drawing_area1));获取
static Window window; //通过GDK_WINDOW_XID(gtk_widget_get_window(drawing_area1));获取
static Drawable d; //通过GDK_WINDOW_XID(gtk_widget_get_window(drawing_area1));获取
static XvPortID xv_port; //比较麻烦,稍后详解
static GC gc=NULL; //通过XCreateGC (display, d, 0, NULL);获取
static int iWidth; //drawing_area1的宽度,通过config_event signal中的iWidth = event->configure.width;获取
static int iHeight;//drawing_area1的高度,通过config_event signal中的iHeight = event->configure.height;获取
xv_port的获取比较麻烦,也不好解析,下面贴上源码:
static int open_yv12_port (XvPortID port)
{
XvImageFormatValues *formatValues;
int formats;
int i;
int ret;
formatValues = XvListImageFormats (display, port, &formats);
for (i = 0; i < formats; i++)
{
if(formatValues[i].type==XvYUV && (strcmp (formatValues[i].guid, "YV12")==0))
{
if(XvGrabPort(display, port, 0)==Success)
{
ret = 0; // OK
goto OnExit;
}
}
}
ret = -1; // Fail
OnExit:
XFree (formatValues);
return ret;
}
static int xv_autodetect_port(XvPortID* pOut)
{
int ret;
int i;
unsigned int ver,rel,req,ev,err;
XvAdaptorInfo *adaptor_info=NULL;
unsigned int adaptor_num;
ret = XvQueryExtension(display, &ver,&rel, &req, &ev,&err);
if(ret!=Success)
{
g_print("XvQueryExtension failed,xv is not present.\n");
goto OnError;
}
g_print("xv version %u,release %u,request_base %u,event_base %u,error_base=%u\n",
ver,rel,req,ev,err);
ret = XvQueryAdaptors(display,window,&adaptor_num,&adaptor_info);
if(ret!=Success)
{
g_print("XvQueryAdaptors failed.\n");
goto OnError;
}
for(i=0; i
int j;
for(j=0; j
ret = open_yv12_port(adaptor_info[i].base_id+j);
if(ret==0)
{
* pOut = adaptor_info[i].base_id+j;
goto OnError; // OK
}
}
}
ret = -1; // Fail
OnError:
if(adaptor_info) XvFreeAdaptorInfo(adaptor_info);
return ret;
}
通过xv_autodetect_port函数就可以获取到xv_port的值,返回0表示成功。这里只取YV12的port。取到的值和xvinfo命令显示的一致,否则可能有误。
在图文界面的命令行终端输入:xvinfo ,(ssh或者telnet的会提示“xvinfo: Unable to open display”)
得到如下结果:
X-Video Extension version 2.2
screen #0
Adaptor #0: "Intel(R) Textured Video"
number of ports: 16 // 这是可以使用的xv_port的总共个数
port base: 163 // 这是xv_port的基值
operations supported: PutImage
supported visuals:
depth 24, visualID 0x69
no port attributes defined
maximum XvImage size: 2048 x 2048
Number of image formats: 5
id: 0x32595559 (YUY2)
guid: 59555932-0000-0010-8000-00aa00389b71
bits per pixel: 16
number of planes: 1
type: YUV (packed)
id: 0x32315659 (YV12)
guid: 59563132-0000-0010-8000-00aa00389b71
bits per pixel: 12
number of planes: 3
type: YUV (planar)
id: 0x30323449 (I420)
guid: 49343230-0000-0010-8000-00aa00389b71
bits per pixel: 12
number of planes: 3
type: YUV (planar)
id: 0x59565955 (UYVY)
guid: 55595659-0000-0010-8000-00aa00389b71
bits per pixel: 16
number of planes: 1
type: YUV (packed)
id: 0x434d5658 (XVMC)
guid: 58564d43-0000-0010-8000-00aa00389b71
bits per pixel: 12
number of planes: 3
type: YUV (planar)
ffmpeg的图片现实:
把解压到的frame的数据拷贝到一个unsigned char sBuf[LARGE_ENOUGH]里面,然后创建一个image,然后显示:
// 数据拷贝
dst = sBuf;
i=0;
do
{
int width,height;
unsigned char* src;
if (i==0)
{
height = picture->height;
width = picture->width;
}
else
{
height = picture->height/2;
width = picture->width/2;
}
src = picture->data[i];
for (j=0; j
memcpy(dst,src,width);
dst+=width;
src+=picture->linesize[i];
}
if(i==0) i=2;
else if(i==2) i=1;
else break;
} while(1);
//创建image
xv_image=XvCreateImage(display,xv_port,0x32315659/*"YV12"*/,sBuf,codeccontext->width,codeccontext->height);
//显示image
XvPutImage(display,xv_port,window, gc, xv_image,
0, 0, codeccontext->width, codeccontext->height,
0, 0, iWidth, iHeight);
XFree(xv_image);
最后,有些资源是需要自己释放,别忘记了。