Chinaunix首页 | 论坛 | 博客
  • 博客访问: 310195
  • 博文数量: 78
  • 博客积分: 3635
  • 博客等级: 中校
  • 技术积分: 1115
  • 用 户 组: 普通用户
  • 注册时间: 2010-10-28 09:35
文章分类

全部博文(78)

文章存档

2011年(13)

2010年(65)

我的朋友

分类:

2010-12-20 09:32:24

linux下面最好用的播放器当属mplayer了。一些多媒体的嵌入式产品都有用到mplayer。有的“方案“提供商,也会
在mplayer上面开发,增加自己的解码器和输出驱动,然后提供下它的代理公司。究其原因还是mplayer开放的架构,
很适合去些二次开发的工作,你可以增加自己的解码模块,输出驱动模块,视频滤镜等而不会破坏mplayer的整体架构。
     目前有一个需求,用mplayer来作为另一个软件的后端视频播放器。
     mplayer自身有提供一个slave模式作为后台进程,而不去拦截窗口事件。-wid可以为mplayer指定输出窗口。
可以这样来调用mplayer. mplayer -wid  窗口ID  -slave。
     xwininfo可以得到窗口ID的信息──先启动xwininfo,然后再其它窗口点一下,窗口ID就会被show出来。
     但是,这个方法只能作些简单应用,不能再播放窗口上面叠加其它UI内容,特别是前端软件如果使用了openGL,
那些一些效果就出不来了。为了然mplayer更好地融入前端软件,我决定给mplayer编写一个视频驱动,让mplayer
通过共享内存的方式把解码后的数据传输给前端软件。前端软件再对这些视频数据来做处理。
      mplayer的视频输出驱动源文件全部在libvo/目录下,vo_xx.c里面对应着各种视频驱动,以插件的形式被组织起来。
const vo_functions_t* const video_out_drivers[] ,定义着所有的视频驱动,
mpcodecs_config_vo这个函数选择合适的视频驱动和解码的输出视频格式,
       out_fmt=sh->codec->outfmt[i];  ---得到解码器的输出格式
    if(out_fmt==(unsigned int)0xFFFFFFFF) continue;
    flags=vf->query_format(vf,out_fmt);  ---将调用vo_xx.c的query_format函数。
    ..
     j=i; vo_flags=flags; if(flags&VFCAP_CSP_SUPPORTED_BY_HW) break;
    如果有硬件支持那是相当地好,立刻返回。这样解码器和输出配上对了。
    如果配不上呢?那也不用发愁,mplayer会调用vf_scale这个视频滤镜来进行格式转换。
      if(j<0){
    // TODO: no match - we should use conversion...
    if(strcmp(vf->info->name,"scale") && palette!=-1){
     如此,这般,mplayer 就配上了解码器和视频输出。
     新增加视频驱动过程如下
     1)首先定义插件的接口。
        LIBVO_EXTERN这个宏就是用来做这个事情地。这个宏定义了一系列的vo接口。只需要简单地
       LIBVO_EXTERN(xx)就可以了。当然还需要定义这么一个结构vo_info_t info  来给出vo_xx驱动的信息。
     2)实现LIBVO_EXTERN里面定义的函数接口,大部分可以从其它的vo_xx.c里面抄过来。
        query_format 这个函数很重要,mplayer初始化输出vo的时候,会依次调用各个vo驱动的query_format,
来判断该vo驱动是否支持,从而选择合适的vo驱动。
      3)为前端软件,选择合适的视频数据格式。视频数据格式有两大类,RGB和YUV,其中各自都有好多的变种,如果
前端软件使用openGl来做视频的render,最好让mplayer输出的视频数据限定为YV12格式。这个会不会很麻烦呢??
放心吧,mplayer已经为我们准备好了。 -vf format=fmt=yv12,这个参数就是让mplayer选定视频数据格式的。
是真牛鼻而不是吹牛比吧!
      4)主战场。
         我们的主战场在draw_image 和 draw_slice这两个个函数里面,当mplayer需要输出一帧数据的时候,
它会分别调用这两个函数,根据不同的视频文件。当然,一次只调用一个。
         在进入主战场前,先要做一件事情,分配共享内存。
         static void alocate_share_memory(int stride[],int h)
        {
        
        uint32_t chroma_h = h >> 1;
        size_t size = stride[0]*h+stride[1]*chroma_h+stride[2]*chroma_h;
        shmm_xbmc = shmat(
        shmget(ftok("/etc/group",0),   ---指定一个文件linux会生成一个key值
           size,
           IPC_CREAT | S_IRUSR | S_IWUSR),
         NULL,
        SHM_RND
         );
    
         }
       接下来,当然就是copy数据了。
      static void copy_YV12_to_shmm(uint8_t *src[], int stride[], int w, int h, int x, int y)
{
    uint8_t* dst = (uint8_t *)shmm_xbmc;
    uint32_t chroma_h = image_height >> 1;
  
    fast_memcpy(dst,src[0],stride[0]*h);
    dst += stride[0]*h;
    fast_memcpy(dst,src[1],stride[1]*chroma_h);
    dst += stride[1]*chroma_h;
    fast_memcpy(dst,src[2],stride[2]*chroma_h);
    ...
    OK,这个就搞掂了。收工!!!哦,还有同步机制没做了。
    这这里我们可以使用fifo来进行同步。
    fifo也是个好东西,一端以只读方式打开,另一段以只写的方式打开。则双方分别会在open 和 read ,wirte的时候阻塞,直到另一端执行执行相应的动作,我们把视频数据的相关信息,如h,w,bpp,等信息,用fifo来传送,
这样就可以让两个进程同步了。
    draw_slice 与draw_image的区别是,draw_slice是把一帧数据分成多个分组,一次传送一小块数据,用y和h这
两个参数来决定数据块在一帧数据里面的位置。
   static void copy_slice_to_shmm(uint8_t *src[], int stride[], int w, int h, int x, int y){
    uint8_t* dst = (uint8_t *)shmm_xbmc+y*stride[0];
    uint32_t chroma_h = image_height >> 1;
    fast_memcpy(dst,src[0],stride[0]*h);
    y = y/2;
    h = h/2;
    dst = (uint8_t *)shmm_xbmc + stride[0]*image_height + y*stride[1];
    fast_memcpy(dst,src[1],stride[1]*h);
    dst = (uint8_t *)shmm_xbmc + stride[0]*image_height + stride[1]*chroma_h + y*stride[2];
    fast_memcpy(dst,src[2],stride[2]*h);
在draw_slice里面要做个判断
       if(y+h >= image_height){   ---  一帧数据准备就续
    //printf("joni_debug send data to xxx\n");
         wirte_fifo ---写如视频信息到fifo,通知前端软件。
    }
   其中 fast_memcpy根据不同的平台来定义。一般等同于  memcpy
    这样mplayer,就只负责解码不再显示数据了。
    前端软件调用mplayer时, 需要传入参数 mplayer -vo vo_xx  -slave -quiet  --input file=就可以了!
    不知道说清楚没有,也不知道有没有人看。

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/kartorz/archive/2010/11/26/6037671.aspx
阅读(1700) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~