织梦CMS - 轻松建站从此开始!

罗索

Mplayer源码学习

落鹤生 发布于 2012-02-16 15:28 点击:次 
尽管自己看mplayer源码时日已久,也有些心得,但从未在网页上做过归纳和总结。倒是常常用笔在记事本上画画,只因为那样来的简单。下面分别抄自不同的地方,而之所以要贴在这里,因为和他们一样,都是在认识mplayer源码过程中的同路人,也是对他们所取得认识的肯定和赞赏
TAG:

尽管自己看mplayer源码时日已久,也有些心得,但从未在网页上做过归纳和总结。倒是常常用笔在记事本上画画,只因为那样来的简单。下面分别抄 自不同的地方,而之所以要贴在这里,因为和他们一样,都是在认识mplayer源码过程中的同路人,也是对他们所取得认识的肯定和赞赏。没有保持原文的完 整性,望作者不要生气。我会把链接附上,如果有朋友要追本溯源,直接顺着去了就可以 :)

-----------------------------------------------------  

    Mplayer中关于Framebuffer设备相关的流程

 

    原文地址: http://browser.bokee.com/2171300.html

   

  注:本文只关注FBDEV相关的内容,其他的或不提,或略过。[由于时间比较紧,许多地方肯定还有不足的地方,欢迎指教]
首先从Mplayer.c中的main函数开始,
注意到
//================== Init VIDEO (codec & libvo) ==========================
current_module=”preinit_libvo”;
if(!(video_out=init_best_video_out(video_driver_list)))

这将跳进Video_out.c
for(i=0;video_out_drivers[i];i++){
if(!video_driver->preinit(vo_subdevice))
如果你的FBDEV打开的话,即若有
#ifdef HAVE_FBDEV
&video_out_fbdev,
&video_out_fbdev2,
那么,video_driver->preinit(vo_subdevice)这句话将跳进Vo_fbdev.c中执行preinit操作。
Preinit中进行了
fb_dev_fd = open(fb_dev_name, O_RDWR)
和一些ioctl对framebuffer设备的信息进行读取:
ioctl(fb_dev_fd, FBIOGET_VSCREENINFO, &fb_vinfo)
至此,FBDEV相关的pre初始化操作基本结束。

。。。省略其他无关的信息
进入
/*========================== PLAY VIDEO =============
这里面最重要的一个操作就是解出一帧:
//——————– Decode a frame: ———————-
// get it!
current_module=”video_read_frame”;
具体如何解赞不提,但应关注一下结果:
in_size=video_read_frame(sh_video,&next_frame_time,&start,force_fps);
其中video_read_frame是Video.c中的函数,这个操作得到了这一帧的数据信息在
内存区的起始值start和长度in_size;

由于现在得到的帧还只是未解码的信息,
下一步就是要进行解码操作:
// decode:
current_module=”decode_video”;
blit_frame=decode_video(sh_video,start,in_size,drop_frame);
执行时将跳进Dec_video.c中的decode_video函数,
mpi=mpvdec->decode(sh_video, start, in_size, drop_frame);
之后,得到了这一帧的原始的mp_image_t的图像格式,基本上可以说是最终可用的数据了。
下一步就是如何将数据刷进Fb设备中了。
vf=sh_video->vfilter;
ret = vf->put_image(vf,mpi); // apply video filters and call the leaf vo/ve
这段实际上就是我们想要的。
原来的作者曾有一句注释掉的,则更为清晰:
//vo_draw_image(video_out,mpi);
意思则是说将mpi数据直接刷到已经初始化好的video_out中去。
Vf_vo.c中实现了上述一段的主要功能:
#define video_out ((vo_functions_t*)(vf->priv)) 定义了video_out实际为vo_functions_t类型,
而vf->put_image(vf,mpi)的实现中
video_out->draw_slice(mpi->planes,mpi->stride,mpi->w,mpi->h,mpi->x,mpi->y);
调用draw_slice函数的原型为在Video_out.h中的
/*
* Draw a planar YUV slice to the buffer:
* params:
* src[3] = source image planes (Y,U,V)
* stride[3] = source image planes line widths (in bytes)
* w,h = width*height of area to be copied (in Y pixels)
* x,y = position at the destination image (in Y pixels)
*/
uint32_t (*draw_slice)(uint8_t *src[], int stride[], int w,int h, int x,int y);
也就是此时将调用Vo_fbdev.c中的
static uint32_t draw_slice(uint8_t *src[], int stride[], int w, int h, int x, int y)
{
uint8_t *d;
uint8_t *s;

d = center + (fb_line_len * y + x) * fb_pixel_size;

s = src[0];
while (h) {
memcpy(d, s, w * fb_pixel_size);
d += fb_line_len;
s += stride[0];
h–;
}

return 0;
}
从而完成从mpi到framebuffer的内存拷贝!

 

 

---------------------------------------------------

 

 Mplayer 中的版本管理

原文地址: http://kware.blogbus.com/logs/17613567.html

  1. Mplayer 中的版本管理
   1) 文件 Makefile 中处理
      depend: help_mp.h
        ./version.sh `$(CC) -dumpversion`
      # 这里将编译器的版本号也追加在整体版本号

   2) 文件中 version.sh 中的处理
      #!/bin/sh
      echo "#define VERSION /"1.0pre7try2-$1-josa1.0/"" > version.h
      #自动生成 version.h 文件。这里增加了 josa 版本号
      #文件 version.h 里只有一行:#define VERSION "1.0pre7try2-3.2.3-josa1.0"

   3) 版本号使用
      // 初始化,消息系统 …… mplayer.c 中
      mp_msg(MSGT_CPLAYER, MSGL_INFO, "MPlayer " VERSION " (C) 2000-2005 Yifang NTT Team/n");

   4) 编解码器的版本号问题 libancodec/utils.c
      unsigned avcodec_version( void ) { return LIBAVCODEC_VERSION_INT; }
      unsigned avcodec_build( void ) { return LIBAVCODEC_BUILD; }

2. Mplayer 安全禁用函数的使用
   错误:“utils.c: undefined reference to `time_is_forbidden_due_to_security_issues'”
   解决方案:

   #undef fprintf
   #undef time
     josaf = fopen(fn, "wt");
     time(&rawtime);                       // 获取当地时间
     fprintf(josaf, "Josa Begin! " VERSION ", Yuchun Ji, %s/n", ctime(&rawtime));
     av_log_callback = josa;
   #define fprintf please_use_av_log
   #define time time_is_forbidden_due_to_security_issues

3. 原始技术资料文本
   F:/MPlayer-1.0pre7try2/DOCS/tech/libmpcodecs.txt
   The libMPcodecs API details, hints - by A'rpi
   ==================================
   See also: colorspaces.txt, codec-devel.txt, dr-methods.txt, codecs.conf.txt

       [MPlayer core]
             | (1)
        _____V______   (2)  /~~~~~~~~~~/    (3,4)  |~~~~~~|
        |          | -----> | vd_XXX.c |  -------> | vd.c |
        | decvideo |        /__________/  <-(3a)-- |______|
        |          | -----,  ,.............(3a,4a).....:
        ~~~~~~~~~~~~  (6) V  V
          /~~~~~~~~/     /~~~~~~~~/  (8)
          | vf_X.c | --> | vf_Y.c | ---->  vf_vo.c / ve_XXX.c
          /________/     /________/
              |              ^
          (7) |   |~~~~~~|   : (7a)
              `-> | vf.c |...:
                  |______|

4. 音视频解码器选择
   1) 在 libmpcodec/dec_audio.c 文件 init_best_audio_codec() 函数中
      // 输出的三项信息分别为“编解码器名称、驱动程序、描述信息”
      tprintf("/nACD:%s AFM:%s(%s)",
        sh_audio->codec->name, sh_audio->codec->drv, sh_audio->codec->info);

   2) 在 libmpcodec/dec_video.c 文件 init_best_video_codec() 函数中
      // 输出的三项信息分别为“编解码器名称、驱动程序、描述信息”
      tprintf("/nVCD:%s VFM:%s(%s)/n",
        sh_video->codec->name, sh_video->codec->drv, sh_video->codec->info);

5. 文件 codecs.conf.h 的自动生成机制
   1) 元工具 codec_cfg.exe 的生成,在 Makefile 文件里
      PRG_CFG = codec-cfg

      $(PRG_CFG): version.h codec-cfg.c codec-cfg.h
        $(HOST_CC) $(HOST_CFLAGS) -I. -g codec-cfg.c mp_msg.c -o $(PRG_CFG) -DCODECS2HTML /
          $(EXTRA_LIB) $(EXTRA_INC) $(I18NLIBS)

   2) 使用生成的 codec_cfg.exe 工具生成 codecs.conf.h 头文件,在 Makefile 文件里
      codecs.conf.h: $(PRG_CFG) etc/codecs.conf
        ./$(PRG_CFG) ./etc/codecs.conf > $@

   3) 元工具 codec-cfg.c 分析
      目的是将编解码器配置文件 etc/codecs.conf 转化为 codecs.conf.h 文件。源配置格式见下节,目标格
      式如下:

      /* GENERATED FROM ./etc/codecs.conf, DO NOT EDIT! */

      codecs_t builtin_video_codecs[] = {
      {{0x10000001, 0x10000002, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},  /* fourcc */
       {0x10000001, 0x10000002, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
        0,0,0,0,0,0,0,0,0,0,0,0,0},                                 /* fourccmap */
       {0x4D504553, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},  /* outfmt */
       {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},                           /* outflags */
       {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},           /* infmt */
       {0,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 0, 0 },                   /* inflags */
       "mpegpes",                                                   /* name */
       "MPEG-PES output (.mpg or DXR3/DVB card)",                   /* info */
       "for hardware decoding",                                     /* comment */
       NULL,                                                        /* dll */
       "mpegpes",                                                   /* drv */
       {0x00000000,0,0,{0, 0, 0, 0, 0, 0, 0, 0}},                   /* GUID */
       0, 1, 0                                                      /* flags, status, cpuflags */
      }

   4) 编解码器配置文件 etc/codecs.conf 分析
      ;=============================================================================
      ;  Default codecs config file. It replaces the old codecs.c file!
      ;  Before editing this file, please read DOCS/tech/codecs.conf.txt !
      ;=============================================================================
      release 20030724

      ; MPEG-1/2 decoding:
      ; Note: mpegpes is preferred for hw decoders:

      videocodec mpegpes
        info "MPEG-PES output (.mpg or DXR3/DVB card)"
        comment "for hardware decoding"
        status working
        format 0x10000001  ; mpeg 1
        format 0x10000002  ; mpeg 2
        driver mpegpes
        out MPES

6. 打包源代码 MPlayer-1.0pre7try2-josa1.0.rar
   原始容量 33.20MB, 234,832,312 字节, 2341 个文件 115 个目录;
   压 缩 后  8.99MB    9,432,977 字节

 

 

   这篇文章讲的时间比较早了,其实内容可以用粗旷形容。尽管说的基本上都是对的,但我还是不懂他想说些什么。题目起的莫名其妙哦~,还有,作者有版权声明的 “版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
http://kware.blogbus.com/logs/17613567.html”,要是转载的话要注意了哈。

  

----------------------------------------------------

 Mplayer代码阅读

原文地址: http://qzone.qq.com/blog/81182980-1228458373

此文还有另外版本的链接:http://uthz.com/tag/%E8%A7%86%E9%A2%91/

 从Mplayer.c的main开始
处理参数
mconfig = m_config_new();
m_config_register_options(mconfig,mplayer_opts);
// TODO : add something to let modules register their options
mp_input_register_options(mconfig);
parse_cfgfiles(mconfig);
初始化mpctx结构体,mpctx应该是mplayer context的意思,顾名思义是一个统筹全局的变量。
static MPContext *mpctx = &mpctx_s;
// Not all functions in mplayer.c take the context as an argument yet
static MPContext mpctx_s = {
.osd_function = OSD_PLAY,
.begin_skip = MP_NOPTS_VALUE,
.play_tree_step = 1,
.global_sub_pos = -1,
.set_of_sub_pos = -1,
.file_format = DEMUXER_TYPE_UNKNOWN,
.loop_times = -1,
#ifdef HAS_DVBIN_SUPPORT
.last_dvb_step = 1,
#endif
};
原型
typedef struct MPContext {
int osd_show_percentage;
int osd_function;
ao_functions_t *audio_out;
play_tree_t *playtree;
play_tree_iter_t *playtree_iter;
int eof;
int play_tree_step;
int loop_times;
stream_t *stream;
demuxer_t *demuxer;
sh_audio_t *sh_audio;
sh_video_t *sh_video;
demux_stream_t *d_audio;
demux_stream_t *d_video;
demux_stream_t *d_sub;
mixer_t mixer;
vo_functions_t *video_out;
// Frames buffered in the vo ready to flip. Currently always 0 or 1.
// This is really a vo variable but currently there’s no suitable vo
// struct.
int num_buffered_frames;
// AV sync: the next frame should be shown when the audio out has this
// much (in seconds) buffered data left. Increased when more data is
// written to the ao, decreased when moving to the next frame.
// In the audio-only case used as a timer since the last seek
// by the audio CPU usage meter.
double delay;
float begin_skip; ///< start time of the current skip while on edlout mode
// audio is muted if either EDL or user activates mute
short edl_muted; ///< Stores whether EDL is currently in muted mode.
short user_muted; ///< Stores whether user wanted muted mode.
int global_sub_size; // this encompasses all subtitle sources
int global_sub_pos; // this encompasses all subtitle sources
int set_of_sub_pos;
int set_of_sub_size;
int global_sub_indices[SUB_SOURCES];
一些GUI相关的操作
打开字幕流
打开音视频流
mpctx->stream=open_stream(filename,0,&mpctx->file_format);
fileformat文件还是TV流DEMUXER_TYPE_PLAYLIST或DEMUXER_TYPE_UNKNOWN DEMUXER_TYPE_TV
current_module记录状态vobsub  open_stream handle_playlist dumpstream
stream_reset(mpctx->stream);
stream_seek(mpctx->stream,mpctx->stream->start_pos);
f=fopen(stream_dump_name,”wb”); dump文件流
stream->type==STREAMTYPE_DVD
//============ Open DEMUXERS — DETECT file type ======================
Demux。分离视频流和音频流
mpctx->demuxer=demux_open(mpctx->stream,mpctx->file_format,audio_id,video_id,dvdsub_id,filename);
Demux过程
demux_open
get_demuxer_type_from_name
……
mpctx->d_audio=mpctx->demuxer->audio;
mpctx->d_video=mpctx->demuxer->video;
mpctx->d_sub=mpctx->demuxer->sub;
mpctx->sh_audio=mpctx->d_audio->sh;
mpctx->sh_video=mpctx->d_video->sh;
分离了之后就开始分别Play audio和video
这里只关心play video
/*========================== PLAY VIDEO ============================*/
vo_pts=mpctx->sh_video->timer*90000.0;
vo_fps=mpctx->sh_video->fps;
if (!mpctx->num_buffered_frames) {
double frame_time = update_video(&blit_frame);
mp_dbg(MSGT_AVSYNC,MSGL_DBG2,”*** ftime=%5.3f ***/n”,frame_time);
if (mpctx->sh_video->vf_inited < 0) {
mp_msg(MSGT_CPLAYER,MSGL_FATAL, MSGTR_NotInitializeVOPorVO);
mpctx->eof = 1; goto goto_next_file;
}
if (frame_time < 0)
mpctx->eof = 1;
else {
// might return with !eof && !blit_frame if !correct_pts
mpctx->num_buffered_frames += blit_frame;
time_frame += frame_time / playback_speed;  // for nosound
}
}
关键的函数是update_video
根据pts是否正确调整一下同步并在必要的时候丢帧处理。
最终调用decode_video开始解码(包括generate_video_frame里)。
mpi = mpvdec->decode(sh_video, start, in_size, drop_frame);
mpvdec是在main里通过reinit_video_chain的一系列调用动态选定的解码程序。
其实就一结构体。它的原型是
typedef struct vd_functions_s
{
vd_info_t *info;
int (*init)(sh_video_t *sh);
void (*uninit)(sh_video_t *sh);
int (*control)(sh_video_t *sh,int cmd,void* arg, …);
mp_image_t* (*decode)(sh_video_t *sh,void* data,int len,int flags);
} vd_functions_t;
这是所有解码器必须实现的接口。
int (*init)(sh_video_t *sh);是一个名为init的指针,指向一个接受sh_video_t *类型参数,并返回int类型值的函数地址。
那些vd_开头的文件都是解码相关的。随便打开一个vd文件以上几个函数和info变量肯定都包含了。
mpi被mplayer用来存储解码后的图像。在mp_image.h里定义。
typedef struct mp_image_s {
unsigned short flags;
unsigned char type;
unsigned char bpp;  // bits/pixel. NOT depth! for RGB it will be n*8
unsigned int imgfmt;
int width,height;  // stored dimensions
int x,y,w,h;  // visible dimensions
unsigned char* planes[MP_MAX_PLANES];
int stride[MP_MAX_PLANES];
char * qscale;
int qstride;
int pict_type; // 0->unknown, 1->I, 2->P, 3->B
int fields;
int qscale_type; // 0->mpeg1/4/h263, 1->mpeg2
int num_planes;
/* these are only used by planar formats Y,U(Cb),V(Cr) */
int chroma_width;
int chroma_height;
int chroma_x_shift; // horizontal
int chroma_y_shift; // vertical
/* for private use by filter or vo driver (to store buffer id or dmpi) */
void* priv;
} mp_image_t;
图 像在解码以后会输出到显示器,mplayer本来就是一个视频播放器么。但也有可能作为输入提供给编码器进行二次编码,MP附带的 mencoder.exe就是专门用来编码的。在这之前可以定义filter对图像进行处理,以实现各种效果。所有以vf_开头的文件,都是这样的 filter。
图像的显示是通过vo,即video out来实现的。解码器只负责把解码完成的帧传给vo,怎样显示就不用管了。这也是平台相关性最大的部分,单独分出来的好处是不言而喻的,像在 Windows下有通过direcx实现的vo,Linux下有输出到X的vo。vo_*文件是各种不同的vo实现,只是他们不都是以显示为目的,像 vo_md5sum.c只是计算一下图像的md5值。
在解码完成以后,即得到mpi以后,filter_video被调用,其结果是整个filter链上的所有filter都被调用了一遍,包括最后的VO,在vo的put_image里把图像输出到显示器。这个时候需要考虑的是图像存储的方法即用哪种色彩空间。
[MPlayer core]
| (1)
_____V______   (2)  /~~~~~~~~~~/    (3,4)  |~~~~~~|
|          | —–> | vd_XXX.c |  ——-> | vd.c |
| decvideo |        /__________/  <-(3a)– |______|
|          | —–,  ,………….(3a,4a)…..:
~~~~~~~~~~~~  (6) V  V
/~~~~~~~~/     /~~~~~~~~/  (8)
| vf_X.c | –> | vf_Y.c | —->  vf_vo.c / ve_XXX.c
/________/     /________/
|              ^
(7) |   |~~~~~~|   : (7a)
`-> | vf.c |…:
|______|
感觉Mplayer的开发人员们都是无比的牛,硬是用原始的C实现了很多OO语言才支持的特性,带来不好的结果是代码看起来比较费劲.

这位兄弟说出了俺的心里话:"感觉Mplayer的开发人员们都是无比的牛".哦,他还有一篇大作在下面,嘿嘿。

 

Mplayer的目录结构和子文件夹说明

原文地址:http://qzone.qq.com/blog/81182980-1235106011

 libavcodec libavformat libavutil三个文件夹来自ffmpeg的库 ;
libfaad2 libao2 liba52 libmpg2 mp3lib vidix几个文件夹是其它的三方库 ;
libmpcodecs libmpdemux 文件夹中为mplayer 的 demux 和codecs。 ;
  其中demux_XXX.c为处理各种不同的container.
  vd_XXX.c为mplayer的内置视频解码器,ad_xxx.c是音频解码器。
  vf_XXX.c 和af_XXX.c 为视,音频的各种filter。
  vo_XXX.c 为解码后视频输出。
libvo  视频输出模块的 Make 文件配置部分头
libao2  音频输出模块的 Make 文件配置部分头
drivers    使用 VIDIX 技术用到的直接硬件访问驱动程序

  

怎么样,还是很注重条理的吧?不过,vo_XXX.c是在libvo下说的哦

(houdiney)
本站文章除注明转载外,均为本站原创或编译欢迎任何形式的转载,但请务必注明出处,尊重他人劳动,同学习共成长。转载请注明:文章转载自:罗索实验室 [http://www.rosoo.net/a/201202/15726.html]
本文出处:CSDN博客 作者:houdiney 原文
顶一下
(0)
0%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
将本文分享到微信
织梦二维码生成器
推荐内容