当前位置: 首页 > 编程日记 > 正文

VLC架构及流程分析

0x00 前置信息

VLC是一个非常庞大的工程,我从它的架构及流程入手进行分析,涉及到一些很细的概念先搁置一边,日后详细分析。

0x01 源码结构(Android Java相关的暂未分析)

# build-android-arm-linux-androideabi/:第三方库。
# modules/:模块代码。
# modules/demux:      解复用模块代码。
# modules/codec:       解码模块相关代码。
# modules/access:    访问模块相关代码。
# 其他:未详细分析。
# src/: VLC架构核心代码。
# src/config/:           从命令行和配置文件加载配置,提供功能模块的读取和写入配置。
# src/control/:            提供动作控制功能,如播放/暂停,音量管理,全屏,日志等。
# src/extras/:             平台特殊性相关代码。
# src/modules/:          模块管理。
# src/network/:           提供网络接口。
# src/posix/:               多线程相关。
# src/osd/:                 显示屏幕上的操作。
# src/interface/ :         提供代码中可以调用的接口中,如按键后硬件作出反应。
# src/playlist/:            管理播放功能,如停止,播放,下一首,随机播放等。
# src/text/:                 字符集。
# src/input/:               输入流相关代码。
# src/video_output/ :   初始化视频播放器,把从解码器获得的数据处理后播放。
# src/audio_output/ :   初始化音频混合器,把从解码器获得的数据处理后播放。
# src/stream_output/:  输出音频流和视频流到网络。
# src/test/:                  libvlc测试模块。
# src/misc/:                libvlc使用的其他部分功能,如线程系统,消息队列,CPU的检测,对象查找系统,或平台的特定代码。
# 其他:未详细分析。

0x02 基础概念

对于一个视频的播放,播放器的执行步骤大致如下:

  1. 读取原始数据
  2. 解复用
  3. 解码
  4. 显示

VLC在包含以上概念的基础上,又抽象出几个其他概念,先列出VLC中抽象出来的重要概念:

  1. playlist: playlist表示播放列表,VLC在启动后,即创建一个playlist thread,用户输入后,动态创建input。
  2. input: input表示输入,当用户通过界面输入一个文件或者流地址时,input thread 被动态创建,该线程的生命周期直到本次播放结束。
  3. access: access表示访问,是VLC抽象的一个层,该层向下直接使用文件或网络IO接口,向上为stream层服务,提供IO接口。
  4. stream: stream表示流,是VLC抽象的一个层,该层向下直接使用access层提供的IO接口,向上为demux层服务,提供IO接口。
  5. demux: demux表示解复用,是视频技术中的概念,该层向下直接使用stream层提供的IO接口,数据出来后送es_out。
  6. es_out: es_out表示输出,是VLC抽象的一个层,该层获取demux后的数据,送decode解码。
  7. decode: decode表示解码,是视频技术中的概念,获取es_out出来的数据(通过一个fifo交互),解码后送output。
  8. output: output表示输出,获取从decode出来的数据,送readerer。
  9. readerer: readerer表示显示,获取从output出来的数据(通过一个fifo交互),然后显示。

下图显示了这些抽象的概念的关系,其中蓝色表示VLC抽象的概念。
vlc_flowpath_analysis2.png

0x04 架构综述

VLC的整体框架是设计成一套module的管理机制,将功能分类并抽象成modules。

VLC main: player的main。初始化libVLC 并加载用户界面。
libVLCcore:libvlc的核心,抽象出了一个libvlc_instance_t 对象,提供modules的装载/卸载机制。
modules: modules提供具体的功能,比如上面的access,demux,decode就是以一个模块的形式存在。
External libraries:外部开源库。

模块的加载方式:
首先模块先将自身注册到VLC中,代码片段如:

vlc_module_begin()
...
vlc_module_end()

然后在需要加载模块的时候,调用module_need接口,去找到合适的模块。找到合适的模块后,会执行注册中设置的回调方法,诸如Open*名字的方法。
同样自己可以实现模块,只需要按照VLC模块的标准即可。VLC中很多模块就是通过外部的开源库实现的。

vlc中模块大致分类:
1364359619_6154.jpg

0x05 流程分析

首先,给出流程图,参照该图,再继续下面的流程分析,绿色线表示打开VLC后的执行操作;黑色线表示用户输入一个视频后的执行操作;蓝色线从红色圈开始,表示开始播放输入流后的数据流向。
vlc_flowpath_analysis.png

(1) main函数(vlc/bin/vlc.c)
  1. 参数信号处理相关,不详分析。
  2. 调用libvlc_new()初始化一个libvlc_instance_t实例。(libvlc_instance_t is opaque. It represents a libvlc instance)
    2.1 调用libvlc_InternalCreate创建一个libvlc_int_t。(This structure is a LibVLC instance, for use by libvlc core and plugins.)
    2.2 调用libvlc_InternalInit初始化libvlc_int_t实例。
    2.3 初始化libvlc_instance_t其他成员。
  3. 调用libvlc_set_exit_handler设置VLC退出时的回调函数。
  4. 调用libvlc_add_intf添加模块。
    4.1 获取playlist,如果为空,则调用playlist_Create创建一个playlist结构,并调用playlist_Activate创建新的playlist线程Thread(src/playlist/thread.c)。
    4.2 调用intf_Create创建一个默认的interface。
    4.2.1 调用vlc_custom_create创建一个vlc object(intf_thread_t)。
    4.2.2 注册一个添加interface的回调方法。
    4.2.3 调用module_need加载一个interface模块。
  5. 调用libvlc_playlist_play,如果播放列表不为空,并且被设置为自动播放,则播放播放列表内容。
  6. 信号处理相关,不详分析。
(2) 创建一个输入
  1. 初始化成功后,程序运行在playlist的线程Thread(src/playlist/thread.c)中,循环接收界面输入的请求。
  2. 当输入一个新的文件或者流地址,在PlaylistVAControl获得信号,并发送该信号。
  3. Thread接收到播放请求后,在LoopRequest中调用PlayItem方法。
    3.1 调用input_Create创建一个input结构,并初始化各种成员,其中包括调用input_EsOutNew创建p_es_out_display(es_out)。
    3.2 调用input_Start创建一个input线程Run(src/input/input.c)。
(3) 初始化输入

调用Run(src/input/input.c)中的Init方法,开始初始化。

  1. 调用input_EsOutTimeshiftNew新建一个50M的Timeshift(暂停缓存),包括创建并初始化p_es_out(es_out),与后续步骤9相关。
  2. 设置input的状态为OPENING_S。
  3. 调用InputSourceInit。
    3.1 调用input_SplitMRL分解输入uri。
    3.2 以stream形参为NULL调用demux_New加载"access_demux"模块。
    3.3 如果没有合适的"access_demux"模块,则调用access_New创建一个实际的access。
    3.3.1 调用vlc_custom_create创建access_t结构体。
    3.3.2 调用module_need加载合适的access模块。
    3.3.3 调用access模块的Open*方法,以avio模块为例。
    3.3.3.1 调用vlc_init_avformat初始化VLC即avformat环境。
    3.3.3.2 调用avio_open2打开该uri。
    3.3.3.3 设置access的IO方法指针。
    3.4 调用stream_AccessNew创建一个stream。
    3.4.1 根据模式(stream/block)设置steam层的IO方法指针。stream层的IO方法实际指向access层对应的IO方法指针。
    3.4.2 为stream层的缓冲申请并初始化内存。
    3.4.3 调用AStreamPrebufferStream执行一次读操作。
    3.5 调用stream_FilterChainNew,Add stream filters(源码描述)。
    3.6 调用demux_New创建一个demux。
    3.6.1 调用vlc_custom_create创建demux_t结构体。
    3.6.2 调用module_need加载合适的demux模块。
    3.6.3 调用demux模块的Open*方法,以avformat/demux模块为例。
    3.6.3.1 调用stream_Peek从stream层获取数据,用于分析输入的文件格式。
    3.6.3.2 调用av_probe_input_format分析输入的文件格式。
    3.6.3.3 设置demux_sys_t结构体部分变量的值。
    3.6.3.4 调用avformat_alloc_context分配AVFormatContext结构体。
    3.6.3.5 调用avio_alloc_context设置AVFormatContext结构体的AVIOContext类型成员pb,并设置read和seek方法指针。
    3.6.3.6 调用avformat_open_input打开一个输入,这里的input与VLC中的input不是一个概念,关于avformat_open_input的分析详见我的另一篇文章《avformat_open_input详细分析》链接地址。
    3.6.3.7 调用avformat_find_stream_info分析流信息,该方法通过读取数据初始化流以及流解码信息。
    3.6.3.8 根据分析的流信息,设置fmt变量,并调用es_out_Add。
    3.6.3.9 实际调用EsOutAdd(src/input/es_out.c),添加一个es_out,有几个流就做几次es_out_Add操作,比如该输入中有一个视频流和一个音频流,则作两次es_out_Add操作。
    3.6.3.10 nb_chapters相关未详细分析。
    3.7 设置record相关。
    3.8 调用demux_Control设置demux pts delay。
    3.9 调用demux_Control设置fps。
  4. 调用demux_Control获取输入的长度。
  5. 调用StartTitle显示标题。
  6. 调用LoadSubtitles加载字幕。
  7. 调用LoadSlaves,含义不详。
  8. 调用InitPrograms,设置es_out和decoder相关。
    8.1 调用UpdatePtsDelay计算正确的pts_delay值。
    8.2 sout相关可选,暂不分析。
    8.3 调用es_out_SetMode,设置es_out的mode为ES_OUT_MODE_AUTO。
    8.4 以DEMUX_SET_GROUP指令调用demux_Control,DEMUX_SET_GROUP/SET_ES only a hint for demuxer (mainly DVB) to allow not reading everything。
  9. 续8.3,实际调用EsOutControlLocked进入case ES_OUT_SET_MODE分支。
    9.1 设置es_out_sys_t 的b_active和i_mode。
    9.2 调用EsOutSelect方法,根据指定模块选择一个es_out。
    9.3 在EsOutSelect方法中进入ES_OUT_MODE_AUTO分支,进一步调用EsSelect方法,再进一步调用EsCreateDecoder方法创建decoder。
    9.3.1 调用input_DecoderNew创建一个新的decoder。
    9.3.2 如果需要缓存,调用input_DecoderStartWait发送信号,开始线程等待。
    9.3.3 调用EsOutDecoderChangeDelay设置decode delay。
  10. 续9.3.1进入decoder_New方法。
    10.1 调用CreateDecoder创建decoder配置结构体。
    10.1.1 调用vlc_custom_create创建一个vlc object(decoder_t)。
    10.1.2 新建decode fifo。
    10.1.3 调用module_need加载适配的解码模块。
    10.1.3.1 调用decode模块的OpenDecoder方法,以codec/avcodec模块为例。
    10.1.3.2 调用GetFfmpegCodec方法 determine codec type(源码描述)。
    10.1.3.3 调用vlc_init_avcodec方法初始化解码环境。
    10.1.3.4 调用avcodec_find_decoder设置AVCodec。
    10.1.3.5 调用avcodec_alloc_context3分配一个AVCodecContext。
    10.1.3.6 调用Init*Dec系列初始化解码环境。
    10.1.4 初始化decoder_t结构体其他成员。
    10.2 调用vlc_clone创建解码线程DecoderThread。
  11. 续10.1.3.5,以InitVideoDec为例。
    12.1 为decoder_sys_t结构分配内存。
    12.2 设置相关回调方法。
    12.3 设置解码线程类型。
    12.4 调用ffmpeg_InitCodec初始化extradata相关数据。
    12.5 调用OpenVideoCodec方法,设置解码的长宽及采用率,进一步调用avcodec_open2打开codec。
  12. 根据需要,设置线程优先级。
  13. 设置meta相关。
  14. 初始化完成,设置该input的状态为PLAYING_S。
(4) 播放输入

MainLoop(src/input/input.c)

  1. 调用MainLoopDemux访问demuxer去demux数据。
  2. 进一步调用在加载demux模块时设置的demux方法,同样以avformat/demux模块为例,实际调用Demux方法(module/demux/avformat/demux.c)。
    2.1 调用av_read_frame读取一帧数据。
    2.2 判断读取无误时,则为block_t结构分配内存,并将这一帧从AVPacket中拷贝至block_t结构中。
    2.3 如果该帧是I帧,则设置I帧标致位。
    2.4 时间戳处理相关,未深入分析。
    2.5 根据需要调用es_out_Control设置PCR,未深入分析。
    2.6 调用es_out_Send将这一帧数据发送给es_out。
    2.7 调用av_free_packet释放这一帧数据。
  3. 调用es_out_Send后,实际调用EsOutSend(src/input/es_out.c)方法。
    3.1 调用stats_Update更新相关状态,具体未详分析。
    3.2 设置预读相关,如果需要预读,并且到的数据的pts小于预读需要的时间,则设置BLOCK_FLAG_PREROLL标志位。
    3.3 检查sout mode,具体有sync 和async mode,异同未详细分析。
    3.4 如果设置record,将数据dup后送decoder。
    3.5 调用input_DecoderDecode将block_t的数据送至decode fifo中。
    3.5.1 判断控制速度线程等待相关信息,具体未详细分析。
    3.5.2 如果decode fifo超过最大长度,则清空重置decode fifo。
    3.5.3 调用block_FifoPut将该block_t的数据压入decode fifo,并通知读取线程。
    3.6 格式变化判断处理相关,未详细分析。
    3.7 字幕处理相关,未详细分析。
  4. 续3.5进入decode read thread,即DecoderThread(src/input/decoder.c)。
    4.1 调用block_FifoGet方法,从decode fifo中获取数据。
    4.2 基于某些条件,发送停止等待消息给其他线程,未详细分析。
    4.3 调用DecoderProcess方法开始decode a block。
    4.4 判断输入流的格式,调用不同的方法,这里以视频流为例,调用DecoderProcessVideo方法。
    4.5 packetizer相关为深入分析,在DecoderProcessVideo方法中进一步调用DecoderDecodeVideo方法。
  5. 续4.5调用pf_decode_video,这里以avcodec模块的decoder为例,即DecodeVideo(modules/codec/avcodec/video.c)方法,在该方法中,开始真正的解码。
    5.1 如果在Demux中获取的流信息中包含新的extradata,并且原来的extradata数据为空,则调用ffmpeg_InitCodec初始化 codec,如果b_delayed_open为true,则调用OpenVideoCodec重新打开codec。
    5.2 调用av_init_packet初始化解码数据包。
    5.3 调用avcodec_decode_video2解码数据。
    5.4 调用av_free_packet释放内存。
    5.5 计算pts值,返回解码后的数据。
    5.6 如果opaque为空,则调用ffmpeg_NewPictBuf方法创建一个新的picture buffer。具体调用回调指针pf_vout_buffer_new指向的vout_new_buffer,进一步调用 input_resource_RequestVout最终调用VoutCreate。
    5.6.1 调用vlc_custom_create创建一个vlc object(vout_thread_t)。
    5.6.2 调用spu_Create初始化sub picture unit。
    5.6.3 调用vlc_clone创建一个output线程Thread(src/video_output/video_output.c)。
    5.6.4 output线程循环调用vout_control_Pop,首次进入ThreadControl方法中,执行ThreadStart方向,创建picture fifo(p->decoder_fifo)。
  6. pf_decode_video返回后,解码后的数据保存在p_pic中,进一步调用DecoderPlayVideo方法,在该方法中调用vout_PutPicture将解码后的数据压入picture fifo中。
  7. 当picture fifo中有数据后,vout线程调用ThreadDisplayPicture中的ThreadDisplayPreparePicture方法。
    7.1 调用picture_fifo_Pop从picture fifo中获取解码后的数据。
    7.2 如果延迟太大,并且设置延迟丢帧,则丢掉该帧数据。
  8. 调用ThreadDisplayRenderPicture显示图像。
0x06 总结

对VLC的流程分析,主要通过跟踪数据流向的方式展开。对于最后显示部分的分析还不足,另外很多细节尚未深入。

参考:

    1. http://blog.csdn.net/tx3344/article/details/8517062
    2. http://my.oschina.net/xiaot99/blog/197555

来源:http://blog.csdn.net/hpb21/article/details/43271095

转载于:https://www.cnblogs.com/sunminmin/p/4502602.html

相关文章:

eclipse运行程序时只有run on server

最近写jsp的程序比较多,写java程序时,发现一点击运行按钮就开始启动服务器了, 这是因为没有写主函数的原因 注意这个问题

自动生成小学四则运算题目的程序.心得体会

http://t.cn/RAS67B0 源代码 #include<stdio.h> #include<stdlib.h>#include<time.h>main(){int a,b,op,os; printf(" [天天练&#xff0c;Baby们来挑战吧!]\n");aq1: printf("选择您想挑战的运算法则\n");printf("1.加法 2.减法 3…

试图运行项目时出错,无法启动调试。没有正确安装调试器,请运行安装程序安装或恢复调试器。...

用Visual Studio.net 2003调试项目时&#xff0c;出现错误对话框&#xff0c;显示如下&#xff1a;试图运行项目时出错&#xff0c;无法启动调试。没有正确安装调试器&#xff0c;请运行安装程序安装或恢复调试器。解决方法如下&#xff1a; 1、在命令行中尝试重新注册m…

Memcached, Redis, MongoDB区别

mongodb和memcached不是一个范畴内的东西。mongodb是文档型的非关系型数据库&#xff0c;其优势在于查询功能比较强大&#xff0c;能存储海量数据。mongodb和memcached不存在谁替换谁的问题。和memcached更为接近的是redis。它们都是内存型数据库&#xff0c;数据保存在内存中&…

idea使用maven创建java工程log4j的配置

错误&#xff1a;在pom.xml文件中 project下有下划线&#xff0c;报错 改正&#xff1a; <!-- 配置日志 --><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.12</version></dependency&g…

kaggle预测

两个预测kaggle比赛 一 .https://www.kaggle.com/c/web-traffic-time-series-forecasting/overview Arthur Suilin•(1st in this Competition)•a year ago•Options github&#xff1a;https://github.com/sjvasquez/web-traffic-forecasting My model is basically RNN seq2…

PHP开发中,让var_dump调试函数输出更美观 ^_^#

前提&#xff1a;php必须安装Xdebug模块。 用var_dump打印输出时&#xff0c;输出的内容没有被格式化。如下图&#xff1a; 通常使用var_dump打印的内容是被格式化后输出的&#xff0c;如下图&#xff1a; 造成没有格式化输出的原因是因为php.ini设置的问题&#xff0c;使用php…

@Override is not allowed when implementing interface method

用idea打开项目&#xff0c;有下划线 解决办法&#xff1a; 选中出现红色下划线的项目&#xff0c;右键单击&#xff0c;选择open module settings 将language level改为8-Lambdas… 点击apply 选择projects&#xff0c;进行更改 点击apply 点击ok 即可

C#发现之旅第一讲 C#-XML开发

C#发现之旅第一讲 C#&#xff0d;XML开发 袁永福 2008-5-15 系列课程说明 为了让大家更深入的了解和使用C#&#xff0c;我们将开始这一系列的主题为“C#发现之旅”的技术讲座。考虑到各位大多是进行WEB数据库开发的&#xff0c;而所谓发现就是发现我们所不熟悉的领域&#xff…

页面的前进/后退/刷新方法

前进一页 οnclick"javascript:window.history.forward()" 后退一页 οnclick"javascript:window.history.back();" 前进/后退 n页 n为正是前进,负数是后退 onclick"javascript:window.history.go(n);" 刷新 οnclick"window.location.re…

25. javacript高级程序设计-新兴的API

1. 新兴的API requestAnimationFrame()&#xff1a;是一个着眼于优化js动画的api&#xff0c;能够在动画运行期间发出信号。通过这种机制&#xff0c;浏览器就能够自动优化屏幕重绘操作 Page Visibility API&#xff1a;让开发人员知道用户什么时候正在看着页面&#xff0c;而什…

Git-remote Incorrect username or password ( access token )

码云上传错误 错误原因&#xff1a;输入git clone https://地址&#xff1b;回车之后弹框输入码云的用户名和密码&#xff0c;用户名我输入的是码云的昵称&#xff0c;应该输入注册时的电子邮箱地址&#xff0c;当我关闭命令框&#xff0c;重新输入输入git clone https://地址&…

jquery选择器的使用方式

1.基本选择器选择器描述返回示例代码说明1id选择器根据指定的id匹配元素单个元素$("#one").css("background","#bbffaa");找到id为one的元素&#xff0c;改变其background属性2class选择器根据给定的类名匹配元素集合元素$(".mini").c…

互动网计算机频道图书7日销售排行(05.20-05.26)

互动网计算机频道图书7日销售排行&#xff08;05.20-05.26&#xff09; 1、Hadoop权威指南&#xff08;中文版&#xff09; 2、人人都是产品经理 3、演讲之禅&#xff1a;一位技术演讲家的自白 内容简介 本书既实用又引人入胜。作为职业演讲家&#xff0c;作者斯科特博克顿为…

Xtreme.Toolkit.Pro编译简单教程

前面介绍了Codejock.Xtreme.Toolkit.Pro&#xff0c;下面介绍一下它的安装和编译。 1.先下载Codejock.Xtreme.Toolkit.Pro 2.安装&#xff1a;一路“下一步”&#xff0c;很简单 3.安装完以后会出一个新的“codejock deployment wizard”窗口&#xff0c;这里你可以跟据需要&am…

上传代码到码云(第一次)

下载git&#xff1b; 注册码云的账号&#xff1b; ssh创建&#xff08;参考百度&#xff0c;较简单&#xff09; 新建仓库&#xff1b; 在电脑上新建文件夹gitcode&#xff1b; 在gitcode文件夹下右键 git bash&#xff1b; 输入git clone https://地址&#xff1b;&#xff0…

《JavaScript编程实战》

《JavaScript编程实战》 基本信息 原书名&#xff1a;JavaScript programming: pushing the limits 作者&#xff1a; (美)Jon Raasch 译者&#xff1a; 吴海星 丛书名&#xff1a; 图灵程序设计丛书 出版社&#xff1a;人民邮电出版社 ISBN&#xff1a;9787115345486 上架时…

再识C中的结构体

在前面认识C中的结构体中我介绍了结构体的基础知识&#xff0c;下面通过这段代码来回顾一下&#xff1a; 1 #include<stdio.h>2 #define LEN 203 4 struct Student{ //定义结构体5 char name[LEN];6 char address[LEN];7 int age;8 };9 10 int m…

《妙解Hibernate 3.X》读书笔记一-Hibernate概述及环境搭建

很早就想开始Hibernate的系统学习&#xff0c;但是一是工作原因&#xff0c;二是苦于找不到合适的书籍。Hibernate更新较快&#xff0c;一些被称为经典的书籍&#xff0c;如<深入浅出Hibernate>、《Hibernate实战》等都过于年老&#xff0c;介绍的为Hibernate2.1&#xf…

ssm框架实现学生成绩管理系统

学习ssm框架&#xff0c;写的一个小项目&#xff0c;参考 实现的功能有&#xff1a;学生信息增删改查&#xff0c;成绩信息查询&#xff0c;修改&#xff0c;求平均值&#xff0c; 附上链接&#xff0c;欢迎下载 git clone https://gitee.com/LOL_toulan/SpringBootProject.gi…

如何查找特定目录下最大的文件及文件夹

如何查看特定目录下大小在前10位的文件 find 目录 -ls |sort -nrk7 |head 参数说明如下&#xff1a; -ls True; list current file in ls -dils format on standard output. 没加-ls之前&#xff0c;输出的只是文件名&#xff0c;类似于 /u01/app/oracle/oradata/test/…

LightOJ 1364 Expected Cards(概率+DP)

题目链接&#xff1a;http://lightoj.com/volume_showproblem.php?problem1364 题意&#xff1a;一副牌。依次在桌面上放牌。求放了四种花色的牌为C,D,H,S张时放的牌数的期望。大小王出现时必须将其指定为某种花色。指定时要使最后的期望最小。 思路&#xff1a;DP&#xff0c…

会计科目中英文对照表

现金 Cash in hand 银行存款 Cash in bank 其他货币资金-外埠存款Other monetary assets - cash in other cities 其他货币资金-银行本票 Other monetary assets - cashier‘s check 其他货币资金-银行汇票 Other monetary assets - bank draft 其他货币资金-信用卡 Other…

关于get和post两种提交方式

Get请求&#xff1a; 1.可携带的数据量小 2.只能存放字符串类型的数据&#xff0c;不能存放bean对象 3.安全性差&#xff0c;例如如果在登录上使用get请求&#xff0c;在地址栏中会显 示输入的username和password 4.客户端在接收到get请求后&#xff0c;浏览器会自动的缓存响应…

数据库原理与设计 P75作业 学号2013211466 班级0401302

习题5 2. (1)写出关系模式&#xff1a; 学生:R1 U1{学号,姓名,出生日期,系名,班号,宿舍区}; F1{学号->(姓名,出生日期,系名,班号,宿舍区)&#xff0c;班号->系名&#xff0c;系名->宿舍区}&#xff1b; 班级:R2 U2{班号,专业名,系名,人数,入校年份}; F2{班号->(专业…

Windows DDK介绍,选择和安装

windows的文档工作还是非常不错的&#xff0c;所有的信息都可以从windows DDK主页和DDK自带的帮助文档中获得&#xff0c;本文只是一个总结。 今天开始正式接触DDK&#xff0c;首先来到DDK主页&#xff0c;有如下信息有用&#xff1a; 1. 选择安装什么版本的DDK。目前DDK的推荐…

关于jsp基础知识题目(一)

1.为了标识一个HTML文件&#xff0c;应该使用标记 html 2.form表单中提交数据的目的地址的属性是 action 3.关于post&#xff1a;安全性较好&#xff0c;地址栏看不到提交的数据&#xff0c;超链接标识post提交方式&#xff0c;可以传输大量数据 4.表单的提交方式有 2 种 5…

GO环境变量设置

GOROOT就是go的安装路径在~/.bash_profile中添加下面语句: GOROOT/usr/local/go export GOROOT 当然, 要执行go命令和go工具, 就要配置go的可执行文件的路径:操作如下:在~/.bash_profile中配置如下:export $PATH:$GOROOT/bin如果是windows需要使用;符号分割两个路径, mac和类un…

Camera+销量突破200万 创始人分享成功经验

Camera 突破了200万份销量大关&#xff0c;开发商tap tap tap分享了成功经验。 创始人John Casasanta指出&#xff0c;他们花了6个多月实现销量突破100万大关&#xff0c;而接下来3个月就销售了200万份&#xff0c;照这个趋势下去&#xff0c;300万销售大关也许只需要1个半月。…

计算机组成原理习题(一)

1.计算机系统包括&#xff1a;硬件系统和软件系统 2.计算机的软件系统包括&#xff1a;系统软件和应用软件 3.冯诺依曼计算机的核心思想是&#xff1a;存储程序 4.计算机的五大功能部件&#xff1a;运算器&#xff0c;控制器&#xff0c;存储器&#xff0c;输入设备&#xf…