zoukankan      html  css  js  c++  java
  • (转)Mplayer分析

    注:本文只关注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初始化操作基本结束。

    。。。省略其他无关的信息
    进入
    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 文件。源配置格式见下节,目标格
          式如下:

         

          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},
           {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},                                
           {0x4D504553, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
           {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},                          
           {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},          
           {0,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 0, 0 },                  
           "mpegpes",                                                  
           "MPEG-PES output (.mpg or DXR3/DVB card)",                  
           "for hardware decoding",                                    
           NULL,                                                       
           "mpegpes",                                                  
           {0x00000000,0,0,{0, 0, 0, 0, 0, 0, 0, 0}},                  
           0, 1, 0                                                     
          }

       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
    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;
    int chroma_width;
    int chroma_height;
    int chroma_x_shift; // horizontal
    int chroma_y_shift; // vertical
    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下说的哦

  • 相关阅读:
    Kafka usecase
    kafka 的quick start(windows平台)
    kafka介绍
    问题记录 为ubuntu16.04添加windows字体(解决JIRA图表乱码的问题)
    问题记录,如何解决confluence的office预览的时候的乱码问题
    为gitlab10.x增加使用remote_user HTTP头的方式登录
    基于spring-cloud的微服务(4)API网关zuul
    基于spring-cloud的微服务(3)eureka的客户端如何使用IP地址来进行注册
    基于spring-cloud的微服务(2) eureka服务提供方的注册和消费方的消费
    WebView 上传文件 WebChromeClient之openFileChooser函数
  • 原文地址:https://www.cnblogs.com/juncent/p/2082825.html
Copyright © 2011-2022 走看看