mplayer安装记录 源码分析

mplayer源码下载地址:

http://www.mplayerhq.hu/MPlayer/releases/

下载最新的MPlayer-1.0rc4

#mkdir /usr/local/mplayer

#mkdir /usr/local/codecs

#cd MPlayer-1.0rc4

#./configure --prefix=/usr/local/mplayer --codecsdir=/usr/local/    codecs --language=zh_CN

这里有的网上加了参数:--enable-gui (开启图形界面),但是我编译的时候会出现如下错误:mplayer dereferencing pointer to incomplete type

据网上说是结构体没有定义出现的错误。

我们不需要gui的界面所以去掉。

#make

#make install

#/usr/local/mplayer/bin/mplayer     /media/hp-v245/nobody.avi

发现没有声音,提示:

audio_setup: Can't open audio device /dev/dsp: No such file or directory

#ls /dev/dsp

发现果然没有此文件

#sudo su

#modprobe snd_pcm_oss

创建dsp文件

再播放就可正常播放,

#ls mplayer

发现有10M,这是没有裁剪的mplayer很大,下面做的工作就是要裁剪mplayer。

 

交叉编译MPlayer-1.0rc2,到3210板子上运行,交叉编译工具链:gcc-3.4.6

./configure --enable-cross-compile --cc=mipsel-linux-gcc --target=mips-linux --as=mipsel-linux-as --ar=mipsel-linux-ar --host-cc=gcc --disable-gui --disable-ivtv

没有加-disable-ivtv出现如下错误:
vo_ivtv.c:79: error: storage size of 'sd' isn't known
vo_ivtv.c:80: error: storage size of 'sd1' isn't known
。。。。。。。

这几天在学习mplayer以下是在网上搜集到的关于mplayer的文章,主要是源码分析这块。首先感谢这些文章的作者,有些没有标明原文出处,实在表示抱歉。

 

从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 
}; 
一些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); 
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流程

 

int c_mplay_main(int argc,char* argv[])
{
**调用 AddExcept()注册异常处理函数
** initmplayer();   //初始化,创建快进和暂停的信号量
**InitTimer();初始化计时器
**mp_msg_init();初始化消息系统
**set_path_env();设置路径、环境
**ipu_image_start();ipu初始化
**mplayer_showmode(1);设置显示模式
**parse_codec_cfg(NULL);解析codec配置寄存器
**打开数据流
**分析播放树
**添加播放树列表
**初始化预填充缓存
**打开播放的文件
**创建buffer
**打开数据流
**检测数据流类型(音频格式和视频格式)
**分析音频流视频流的信息(原始视频尺寸、分辨率、帧频率、码流大小)
**启动相应的分离器
**分析剪辑信息
**初始化codec(多媒体数字信号编解码器)
**选择打开相应的视频解码器
**初始化视频解码器,分析视频流信息
**选择打开相应的音频解码器
**初始化音频解码器、PCM,分析音频信息
**同步音频视频输出
**开始播放

}
   main函数中的入口如下~ 
/*========================== PLAY AUDIO ============================*/ 
if (mpctx->sh_audio) 
     if (!fill_audio_out_buffers()) 
     // at eof, all audio at least written to ao 
     //由mpctx->sh_audio引出,我想重点强调一下sh_audio_t结构,这是音频流头部结构~ 
// Stream headers: 
typedef struct { 
   int aid; 
   demux_stream_t *ds; 
   struct codecs_st *codec; 
   unsigned int format; 
   int initialized; 
   float stream_delay; // number of seconds stream should be delayed (according 
to dwStart or similar) 
   // output format: 
   int sample_format; 
   int samplerate; 
   int samplesize; 
   int channels; 
   int o_bps; // == samplerate*samplesize*channels   (uncompr. bytes/sec) 
   int i_bps; // == bitrate   (compressed bytes/sec) 
   // in buffers: 
   int audio_in_minsize;         // max. compressed packet size (== min. in buffer size 

   char* a_in_buffer; 
   int a_in_buffer_len; 
   int a_in_buffer_size; 
   // decoder buffers: 
   int audio_out_minsize; // max. uncompressed packet size (==min. out buffsize 

   char* a_buffer; 
   int a_buffer_len; 
   int a_buffer_size; 
   // output buffers: 
   char* a_out_buffer; 
   int a_out_buffer_len; 
   int a_out_buffer_size; 
   struct af_stream_s *afilter;           // the audio filter stream 
   struct ad_functions_s* ad_driver; 
#ifdef DYNAMIC_PLUGINS 
   void *dec_handle; 
#endif 
   // win32-compatible codec parameters: 
   AVIStreamHeader audio; 
   WAVEFORMATEX* wf; 
   // codec-specific: 
   void* context; // codec-specific stuff (usually HANDLE or struct pointer) 
   unsigned char* codecdata; // extra header data passed from demuxer to codec 

   int codecdata_len; 
   double pts;   // last known pts value in output from decoder 
   int pts_bytes; // bytes output by decoder after last known pts 
   char* lang; // track language 
   int default_track; 
} sh_audio_t; 

三.step by step 
   1.下面我们来分析fill_audio_out_buffers()函数 
   static int fill_audio_out_buffers(void) 

     1.1查看音频驱动有多大的空间可以填充解码后的音频数据 
     bytes_to_write = mpctx->audio_out->get_space(); 

     这里是查看音频驱动还有多少空闲空间(即pcm缓冲区队列的可用空间),如果有空闲的空间,就调用ao->play()
函数来填充这个buffer,并播放音频数据。(pcm缓冲区的数据会被dma自动送去播放,我们不能让pcm缓冲区为空,否则声音就没了!)这个音频驱动的buffer的大小要设置合适,太小会导致一帧图像还没播放完,buffer就已经空了,会导致音视频严重不同步;太大会导致Mplayer需要不停地解析媒体文件来填充这个音频buffer,而视频可能还来不及播放。。。 

     1.2 对音频流进行解码 
     if (decode_audio(sh_audio, playsize) < 0) 
     注:这里的decode_audio只是一个接口,并不是具体的解码api。这个函数从sh_audio->a_out_buffer获得至少playsize bytes的解码或过滤后的音频数据,成功返回0,失败返回-1 

     1.3 将解码后的音频数据进行播放 
     playsize = mpctx->audio_out->play(sh_audio->a_out_buffer, playsize, playflags); 
     注:从sh_audio->a_out_buffer中copy playsize bytes数据,注意这里一定要copy出来,因为当play调用后,这部分数据就会被覆盖了。这些数据不一定要用完,返回的值是用掉的数据长度。另外当flags|AOPLAY_FINAL_CHUNK的值是真时,说明音频文件快结束了。(play()函数把音频数据写到pcm缓冲区 。)


     1.4 if (playsize > 0) { 
             sh_audio->a_out_buffer_len -= playsize; 
             memmove(sh_audio->a_out_buffer, &sh_audio->a_out_buffer[playsize], 
                     sh_audio->a_out_buffer_len); 
             mpctx->delay += playback_speed*playsize/(double)ao_data.bps; 
         } 
     播放成功后就从sh_audio->a_out_buffer中移出这段数据,同时减去sh_audio->a_out_buffer_len的长度 . 


     2.刚才说了,decode_audio()函数并不是真正的解码函数,它只是提供一个接口,下面我们就来看看这个函数到底做了哪些事情. 
     int decode_audio(sh_audio_t *sh_audio, int minlen) 

     2.1 解码后的视频数据都被cut成大小相同的一个个区间~ 
     int unitsize = sh_audio->channels * sh_audio->samplesize * 16; 

     2.2 如果解码器设置了audio_out_minsize,解码可以等价于 
     while (output_len < target_len) output_len += audio_out_minsize; 
     因此我们必需保证a_buffer_size大于我们需要的解码数据长度加上audio_out_minsize,所以我们最大解码长度也就有了如下的限制:(是不是有点绕口?~~) 
     int max_decode_len = sh_audio->a_buffer_size - sh_audio->audio_out_minsize; 

     2.3 如果a_out_buffer中没有我们需要的足够多的解码后数据,我们当然要继续解码撒~ 只不过我们要注意, 
a_out_buffer中的数据是经过filter过滤了的(长度发生了变化),这里会有一个过滤系数,我们反方向求过滤前的数据长度,所以要除以这个系数。 
     while (sh_audio->a_out_buffer_len < minlen) { 
         int declen = (minlen - sh_audio->a_out_buffer_len) / filter_multiplier 
             + (unitsize << 5); // some extra for possible filter buffering 
         declen -= declen % unitsize; 
         if (filter_n_bytes(sh_audio, declen) < 0) 
             return -1; 
     } 


     3.我们来看看这个filter_n_bytes函数 
   static int filter_n_bytes(sh_audio_t *sh, int len) 

     3.1 还记得我们刚才说的那个最大解码长度吗? 这里是要确保不会发生解码后数据溢出。 

     assert(len-1 + sh->audio_out_minsize <= sh->a_buffer_size); 

     3.2 按需要解码更多的数据 
     while (sh->a_buffer_len < len) { 
         unsigned char *buf = sh->a_buffer + sh->a_buffer_len; 
         int minlen = len - sh->a_buffer_len; 
         int maxlen = sh->a_buffer_size - sh->a_buffer_len; 
         //这里才是调用之前确定的音频解码器进行真正音频解码 
         int ret = sh->ad_driver->decode_audio(sh, buf, minlen, maxlen); 
         if (ret <= 0) { 
             error = -1; 
             len = sh->a_buffer_len; 
             break; 
         } 
         //解码之后a_buffer_len增加 
         sh->a_buffer_len += ret; 
     } 

     3.3 在前面我们提到过过滤这个步骤,下面的图描述了整个过程 
     filter_output = af_play(sh->afilter, &filter_input); 
     注:这里实际上做的是过滤这部分的工作 
     ------------         ----------           ------------ 
     |             |   解码 |           |   过滤   |             |   播放 
     | 未解码数据 | ----->|解码后数据| ------>| 播放的数据 | ------> 
     | a_in_buffer|       | a_buffer |         |a_out_buffer| 
     ------------         ----------           ------------ 

     3.4 if (sh->a_out_buffer_size < sh->a_out_buffer_len + filter_output->len) 
     注:如果过滤后的数据长度太长,需要扩展a_out_buffer_size 

     3.5 将过滤后的数据从decoder buffer移除: 
     sh->a_buffer_len -= len; 
     memmove(sh->a_buffer, sh->a_buffer + len, sh->a_buffer_len); 

四.结语 
     回顾一下今天的内容,我们从sh_audio_t结构体出发,依次分析了fill_audio_out_buffers()函数, 
decode_audio()函数,filter_n_bytes()函数,但是并没有分析具体的decode和play函数。 
     顺便说点题外话,看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下。



本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/454500.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python人脸识别代码百度ai_python百度AI人脸识别API测试

1、注册账号 2、创建应用 3、得到AK和SK 4、用AK SK获取access_token 可用下面的代码&#xff1a; #!/usr/bin/python3.5 # encoding:utf-8 import requests # client_id 你的AK client_secret 你的SK host https://aip.baidubce.com/oauth/2.0/token?grant_typeclient_crede…

Flask 第三方组件之 SQLAlchemy

一、介绍 SQLAlchemy是一个基于Python实现的ORM框架。该框架建立在 DB API之上&#xff0c;使用关系对象映射进行数据库操作&#xff0c;简言之便是&#xff1a;将类和对象转换成SQL&#xff0c;然后使用数据API执行SQL并获取执行结果。 安装&#xff1a;pip3 install sqlalc…

httpservlet获取请求端IP地址

request.getRemoteAddr(); 转载于:https://www.cnblogs.com/panxuejun/p/7623850.html

html 中怎样显示enum,JavaScript如何枚举?

JavaScript中对象的属性分为两种&#xff1a;数据属性和访问器属性。然后根据具体的上下文环境的不同&#xff0c;又可以将属性分为&#xff1a;原型属性和实例属性。原型属性是定义在对象的原型(prototype)中的属性&#xff0c;而实例属性一方面来自构造的函数中&#xff0c;然…

iperf测试网卡性能

Iperf是一个网络性能测试工具。可以测试TCP和UDP带宽质量&#xff0c;可以测量最大TCP带宽&#xff0c;具有多种参数和UDP特性&#xff0c;可以报告带宽&#xff0c;延迟抖动和数据包丢失 因为产品上确定要要用的&#xff30;&#xff28;&#xff39;是千&#xff2d;的&a…

acrobat 控件可以发布吗_短视频可以同时在多个平台发布吗?

我们在做自媒体内容创业中&#xff0c;很多人都在做视频版块&#xff0c;那么一个短视频到底能不能多平台同时发布呢&#xff1f;那么今天&#xff0c;我来分享给大家&#xff0c;希望能够帮到你解决困惑。1.作品可以多平台分发&#xff1a;大家不确定是否能多平台分发&#xf…

红河学院计算机科学与技术,2016年红河学院计算机科学与技术专业最低分是多少?...

类似问题答案2016年厦门理工学院计算机类(含计算机科学与技术、网络工程、空间信息与专业最低分...学校 地 区 专业 年份 批次 类型 分数 厦门理工学院 福建 计算机类(含计算机科学与技术、网络工程、空间信息与 2016 一批 理科 491 学校 地 区 专业 年份 批次 类型 分数 厦门理…

Flask 第三方组件之 script

Flask Script扩展提供向Flask插入外部脚本的功能&#xff0c;包括运行一个开发用的服务器&#xff0c;一个定制的Python shell&#xff0c;设置数据库的脚本&#xff0c;cronjobs&#xff0c;及其他运行在web应用之外的命令行任务&#xff1b;使得脚本和系统分开&#xff1b; …

CentOS四种方法自建yum仓库

将ISO光盘镜像作为yum本地仓库&#xff08;适用于不能联外网的环境&#xff09;&#xff1a; 1、 禁用所有可用的yum仓库&#xff0c;为方便演示&#xff0c;直接全部删除&#xff1a; # cd /etc/yum.repos.d # ls # rm -rf * 2、 创建光盘挂载点&#xff0c;挂载光盘&#x…

python substr_python数据分析-数据对象(一)

Python基本数据类型一般分为&#xff1a;数字、字符串、列表、元组、字典、集合这六种基本数据类型。不可变&#xff08;3 个&#xff09;&#xff1a;Number&#xff08;数字&#xff09;、String&#xff08;字符串&#xff09;、Tuple&#xff08;元组&#xff09;&#xff…

VLC框架分析

功能部份: VLC媒体播放器的核心是libvlc &#xff0c;它提供了界面&#xff0c;应用处理功能&#xff0c;如播放列表管理&#xff0c;音频和视频解码和输出&#xff0c;线程系统。所有libvlc源文件设在的/src目录及其子目录&#xff1a; # config/ &#xff1a;从命令行和配置…

html表格里的超链接点不了,Excel如何添加和取消超链接 Excel超链接打不开是怎么回事...

很多用户在制作excel表格的时候都会添加一些超链接&#xff0c;在制作完成后发布到网页&#xff0c;阅读者可以通过超链接打开指引的网页或者文件&#xff0c;超链接对制作excel表格的用户有非常大的帮助&#xff0c;虽然添加超链接的步骤非常简单&#xff0c;不过还是有些exce…

yum 安装apache php mysql

安装&#xff1a; yum install -y httpd php 查看版本&#xff1a;、 rpm -qa httpd php httpd-2.2.15-54.el6.centos.x86_64 php-5.3.3-48.el6_8.x86_64 修改apache配置文件&#xff1a; vim /etc/httpd/conf/httpd.conf 在#ServerName www.example.com:80行下添加一行 Server…

Python 散点图线性拟合_机器学习之利用Python进行简单线性回归分析

前言&#xff1a;在利用机器学习方法进行数据分析时经常要了解变量的相关性&#xff0c;有时还需要对变量进行回归分析。本文首先对人工智能/机器学习/深度学习、相关分析/因果分析/回归分析等易混淆的概念进行区分&#xff0c;最后结合案例介绍如何利用Python进行简单线性回归…

Flask 第三方组件之 Migrate

flask-migrate是flask的一个扩展模块,主要是扩展数据库表结构的.类似于Django的python manage.py migrate 官方文档: http://flask-migrate.readthedocs.io/en/latest/ 安装 pip install flask-migrate 使用举例 from flask import Flask from flask_sqlalchemy import SQLA…

html section 布局,section标签的用法

标签的用法由于昨晚发了一篇文章http://www.zcool.com.cn/article/ZMzA3MzI.html&#xff0c;有一个网友评论问 的用法。所以现在举例来说明一下&#xff1a;html5引入了标签&#xff0c;用于描述文档的结构&#xff0c;它同标签的意思一样。但是在特定环境中&#xff0c;两者又…

清北学堂Day4

&#xff08;1&#xff09;第一题 财富(treasure) Time Limit:1000ms Memory Limit:128MB 题目描述 LYK有n个小伙伴。每个小伙伴有一个身高hi。 这个游戏是这样的&#xff0c;LYK生活的环境是以身高为美的环境&#xff0c;因此在这里的每个人都羡慕比自己身高高的人&#xff…

Falsk session 源码解析

Falsk框架session请求流程 from flask import Flask # 1. 实例化Flask对象 app Flask(__name__) # 2. 设置路由 app.route(/index) def index(): return "index" if __name__ __main__: # 3. 启动socket服务端 app.run() # 4. 用户请求到来 ap…

vlc内部运行机制以及架构分析

VLC架构剖析1. VideoLan简介1.1 videolan组成Videolan有以下两部分组成:VLC:一个最主要的部分&#xff0c;它可以播放各种类型的媒体文件和流vlc架构剖析 1. VideoLan简介 1.1 videolan组成 Videolan有以下两部分组成: VLC:一个最主要的部分&#xff0c;它可以播放各种类型的媒…

visio中公式太小_visio绘图中的数据计算

在绘流程图时&#xff0c;我们有时候会想直接在流程图上做计算&#xff0c;比如化工设计时精馏塔计算理论塔板数。在VISIO中&#xff0c;实现这个功能还是比较容易&#xff0c;举一个最简单的例子。如下图所示&#xff0c;等号后面的数字可以根据前面的数字变化。实现过程如下&…