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=就可以了。

MPlayer软件研究篇(一)──输出驱动相关推荐

  1. 软件 3.0:人工智能驱动下的未来

    [CSDN 编者按]软件 3.0 有望改变我们构建技术以及与技术交互的方式.这场革命的核心在于人工智能驱动的开发,以实现无缝的.类似人与人的软件交互. 原文链接:https://divgarg.sub ...

  2. 学习笔记---程序员练级攻略(入门篇、修养篇、专业基础篇、软件设计篇、高手成长篇)

    根据极客时间 左耳朵耗子 整理,请忽略每一行最后的数字 文章目录 1. 入门篇 47 2. 修养篇 51 3. 专业基础篇 56 4. 软件设计篇 60 5. 高手养成 63 1. 入门篇 47 1. ...

  3. 物联网BLE裸机程序开发 -- (1)nRF52840配置GPIO输出驱动LED

    nRF52840配置GPIO输出驱动LED 在大部分的开发板例程里面,都以点亮一个LED作为开发板软件开发例程的起始例程."点亮一个LED"."LED流水灯"似 ...

  4. 联盛德 HLK-W806 (九): 软件SPI和硬件SPI驱动ST7789V液晶LCD

    目录 联盛德 HLK-W806 (一): Ubuntu20.04下的开发环境配置, 编译和烧录说明 联盛德 HLK-W806 (二): Win10下的开发环境配置, 编译和烧录说明 联盛德 HLK-W ...

  5. 三代测序纠错软件汇总篇

    三代测序纠错软件汇总篇 原创: 李海滨 诺禾科服 2017-12-21 在之前推出的一篇微信中,已经介绍过了三代测序下机数据"三代全长转录组测序常见问题说明".那么我们拿到数据后是 ...

  6. 基于stm32的两轮自平衡小车4(软件调试篇)

    本篇是软件调试篇,接上一篇硬件篇:基于stm32的两轮自平衡小车3(硬件篇),本篇内容是对硬件部分的软件实现,具体模块详见目录.这里先上效果:转B站 目录 定时器PWM驱动程序 定时器编码器模式驱动程 ...

  7. 驱动篇:底层驱动移植(四)(摘录)

    驱动篇:底层驱动移植(四)(摘录) 时钟驱动 在一个 SoC 中,晶振. PLL .驱动和门等会形成一个时钟树形结构,在 Linux 2.6 中,也存有clk_get_rate ().clk_set_ ...

  8. 寻找最好的笔记软件:三强篇(EverNote、Mybase、Surfulater)

    寻找最好的笔记软件:三强篇(EverNote.Mybase.Surfulater) (v1.0) 寻找最好的笔记软件:三强篇(EverNote.Mybase.Surfulater) v1.0 作者:S ...

  9. 驱动篇:底层驱动移植(三)(摘录)

    驱动篇:底层驱动移植(三)(摘录) GPIO 驱动 在 drivers/gpio 下实现了通用的基于 gpiolib 的 GPIO 驱动,其中定义了一个通用的用于描述底层 GPIO 控制器的gpio_ ...

最新文章

  1. 自己动手设计RESTful API
  2. boost::core模块实现分配器解除分配
  3. 【机器学习】Bagging和Boosting的区别(面试准备)
  4. AAAI 2018 论文 | 蚂蚁金服公开最新基于笔画的中文词向量算法
  5. 对外经贸大学计算机应用基础,对外经贸大学计算机应用基础试题.doc
  6. NavigationDuplicated vue-router 路由重复点击报错的问题
  7. 调试安装php源码,Xdebug的安装与配置,帮助调试PHP程序
  8. 【精选】Java高频面试题278道附答案,通关中大型互联网企业工程师必备
  9. 2019-05-22 Java学习日记 day12
  10. webpack 生产环境下插件用途
  11. anaconda版本选择_Anaconda简介
  12. vue 2.0项目中使用tinymce富文本框遇到的问题
  13. “RFID射频识别技术”简介
  14. php案例:批量重命名图片
  15. ipad未能与itunes连接到服务器,ipad无法连接itunes store怎么办
  16. 疯狂java笔记(七) - Java集合之Map
  17. windows Redis设置密码和取消密码
  18. 《重说中国近代史》—张鸣——(2)战争的开始
  19. 到欧特克应用程序商店发布程序(一个100美金), 参加欧特克编程大赛, 有奖又学习!
  20. 【2022·合辑】Python量化从入门到精通

热门文章

  1. 对于LIMITE,Mysql优化器导致的有时候不走索引而是走全表查询
  2. python中的getattr的用法_python - 究竟是什么getattr()以及如何使用它?
  3. 互联网交流英文缩略语
  4. C 与 C++ 的 static 关键字全解
  5. 计算机著作的写作方法,写作手法概念解析:写作手法大致分为哪几类? -备考资料...
  6. 深圳计算机中级职称如何申请,深圳中级职称评定有何流程
  7. mysql密码一般设置什么格式_mysql更改密码_如何更改mysql root用户密码
  8. 数据预处理过程中处理方法
  9. Bribe the Prisoners
  10. python中stacked_Python:如何在stacked mod中生成可重复的结果