Android下WiFiDisplay功能探究

1 WiFiDisplay简介

1.1WiFiDisplay概述

WiFiDisplay(WFD)是WiFi联盟在已有技术的基础上,为了加速视/音频的传输分享而提出来的一个新概念。WiFi联盟对此成立了一个认证项目:Miracast-- 用来认证一个设备是否支持WiFiDisplay功能。

下图是WiFiDisplay功能的技术支撑体系,实际上最重要的部分就是WiFi Direct:也就是两个设备无需AP(AccessPoint)的情况下直接相连,这就奠定了两个带WiFi功能的设备能够随时传递高质/高清视频的前提。另外,其他深蓝色的技术是必须支持的:

11n:即802.11n协议,支持最高传输速度540Mbit/s;

WMM:即WiFi Multimedia的简称,主要针对不同的数据内容保证其传输的稳定和质量;

WPA2:是WiFi联盟对于采用802.11i协议并采用更为复杂加密算法的认证项目;

WiFi ProtectedSteup:也是一个WiFi联盟的一个认证项目:简化用户安装无线局域网和对安全性能的配置工作;

WiFi Direct:表示设备可以实现直接互联,无需AP的参与;

WiFi Miracast:即为是否可以实现wifi-display功能的认证项目。

图 1 WiFiDisplay技术支撑架构

另外,WiFi联盟还描述了WiFiDisplay的简化工作模型(图2)。在这个工作模型中,Miracast定义传输视/音频数据的一方为source端;接受数据并重新呈现的为sink端。从图中可以看到,source端要有数据内容的存储和下载/生成能力;对数据进行编码能力。而sink端则需要对数据的解码能力;对视/音频进行再度呈现的能力。而Miracast则是定义了这两个设备之间,怎样保持会话;可以传输数据的格式标准;会话控制等内容。

图 2 WiFiDisplay的工作模型

1.2  WiFiDisplay重要规范及标准

WiFi联盟定义了Miracast支持的视/音频格式标准:

图 3 Miracast支持的显示、视频、音频格式标准

同时,Miracast也规范了设备连接后进行协商(图4)、建立会话的流程(图5)。详细描述了设备在建立物理连接后,通过标准步骤来完成WiFi Display的会话建立,然后开始数据传输。关于各个标准步骤的详细信息,请见Miracast官方解释。

图 4  Miracast定义的设备协商标准过程

图5  Miracast定义的显示会话建立过程标准

2  主要模块介绍

由于WFD功能主要涉及wifiP2P功能和display功能,现对Android中涉及的两个模块wifiP2pService和SurfaceFlinger做一些介绍。

2.1  WiFiP2P

2.1.1  WiFiP2P简介

WiFiP2P是WiFi联盟提出的一项重要技术规范,它定义了两个wifi设备如何在没有路由的情形下连接并通信。根据定义,支持WiFiP2P的设备需要扮演P2P GroupOwner或P2P Client角色来形成一个P2P Group:

图6  WiFiP2P工作组模型

其中P2P Group Owner的设备需要发挥传统路由的功能:控制WiFiP2P工作组,使能设备通信等;P2PClient设备则需要连接上P2P Group Owner设备来形成一个工作组来通信。

在以上的工作模型基础上,WiFiP2P细化了以下技术项:

图7  WiFiP2P定义的P2PDiscovery规范

在P2P Discovery规范中,定义了发现设备(Device Discovery )并构建工作组(GroupFormation )的细节。其中发现设备规定设备首先进入扫描阶段(ScanPhase),去发送Probe Request帧;然后进入寻找阶段(Find Phase),在这个阶段中设备会在SearchState和Listen State中切换:两个阶段分别是发送Probe Request帧、监听ProbeRequest帧并发送Probe
Response帧。当找到附近的P2P设备后,就可以来构建一个工作组:包括决定谁是Group Owner的协商(GONegotiation )和设备交换安全配置信息(Provisioning),用于Client设备利用安全配置信息连接GO。

另外,WiFiP2P还定义了GroupOperation技术项,具体描述了和工作组交互的场景和流程:

·P2P Device Join GO(Group Owner)

·P2P Device Join GC(Group Client)

·GC invite P2P Device

·GO invite P2P Device

… …

2.12  Android中WiFiP2P

Android中关于WiFiP2P模块主要涉及以下几个部分:

图8  Android中WiFiP2P涉及模块

WiFiP2PSettings 是用来和用户交互的部分,主要是提供UI给用户选择打开/开闭WiFiP2P功能、呈现搜寻到的P2P设备给用户等;WiFiP2PSettings实现的功能调用的是WiFiP2PManager中的接口;WiFiP2PManager最终会与WiFiP2PService交互,它们依靠Android的Binder机制来实现进程间的通信,WiFiP2PService则是用来管理Android中WiFiP2P功能的核心模块:

图9  Android中WiFiP2P涉及模块

在WiFiP2PService类中有一个内部类P2pStateMachine(状态机)用来管理WiFiP2P的不同状态然后执行不同的操作;另外WiFiP2PService还会创建一个WifiMonitor对象用于接收来自wpa_supplicant的消息并根据接收到的消息给P2pStateMachine传值来推动状态机的工作。从图中可以看到,WiFiP2PService或WifiMonitor交互的是WiFiNative.Java中的接口,这里面的都是一些native函数;这是因为wap_supplicant进程是C语言实现,Android是通过JNI机制调用android_net_wifi_Wifi.cpp
里面的本地接口,这些本地接口来最终和wpa_supplicant交互(wifi.c里面是对发送到wpa_supplicant里面消息的封装)。

wpa_supplicant是一个开源项目,实现了WiFi联盟规范中的众多功能,详见官方文档。下图是wpa_supplicant及与下层部件的一个草图:

图10  wpa_supplicant及底层部件草图

2.2  SurfaceFlinger

总所周知,SurfaceFlinger是Android中对图形画面进行管理并交由FrameBuffer实际显示的重要模块,它需要收集系统中所有应用程序绘制的图像数据,然后集中处理后显示到物理屏幕上。下图是Android下图形显示的一个简略框图:

图11  Android显示系统简略框图

上图描述的是使用OpenGL ES图形开发规范下的情况。首先,每个应用程序在自己的窗口上进行绘图,这里的窗口(Window-2)实际上对应的是一些缓冲区;然后SurfaceFlinger则会对这些缓冲区进行统一管理;最后每一帧的图形数据会被送到FrameBuffer上并实际显示在设备上。

对于上层应用来说,Window-2在Android中的实现为SurfaceTextureClient类。由于是在OpenGL ES的开发框架下,SurfaceTextureClient实际上是继承自ANativeWindow同时在本地实现了一些接口(参见EGL知识):

图12  上层应用的window实现

hook_dequeueBuffer()和hook_queueBuffer()是框架定义中需要实现的本地函数,上层应用作图时需要从缓冲队列得到缓冲区;作图完成后需要把缓冲区送还给缓冲队列。具体情形如下:

图13  本地窗口和缓冲队列交互图

如上图,本地窗口实际上是从BufferQueue来得到缓冲区;画图后再将缓冲区入列到缓冲队列。而BufferQueue是在应用程序创建Surface(在SurfaceFlinger端对应Layer)的时候生成的,本地窗口通过返回的ISurface对象得到ISurfaceTexture对象来最终和BufferQueue交互。

对于SurfaceFlinger侧的本地窗口Window-1(图11)来说,SurfaceTextureClient也是作为本地窗口的功能。不过在SurfaceFlinger端通过标准的OpenGL ES接口进行请求缓冲区操作和入列缓冲区操作的对象就不一样了;而且在入列缓冲区后所进行的操作也不一样:

图14 SurfaceFlinger的本地窗口

如上图,在SurfaceFlinger端的本地窗口Window-1,会有自己的BufferQueue对象,而最终和HAL层的Gralloc模块交互实际分配缓冲区的时候,会根据功用不同来分配不同类型的缓冲区:上层应用分配的缓冲区是给OpenGL绘图用的;SurfaceFlinger这边分配的缓冲区是要送显FrameBuffer的(详见gralloc.h中定义)。

对于上层应用来说,填充好缓冲区后处理端(consumer&producter模型)会调用到Layer文件的onFrameQueued()函数,如果需要渲染图形这时候需要等待一个VSYNC信号(详见Android的Project Butter),收到VSYNC信号后会对需要渲染的Buffer按照Z轴计算可见区域并进行图像混合;而对于SurfaceFlinger端来说,缓冲区入列后consumer会最终调用fb的HAL层接口完成实际显示。

3  Android下实现详述

     Android自从4.2后就支持WiFiDisplay功能了。以下是Miracast官方公布的WFD工作模块框图:

图15WiFiDisplay的工作模块框图

在以上工作模型的基础上,Android主要做了以下工作:

·新加了WiFiDisplay的setting部分,用来为用户提供操作选项;

·新加DisplayDevice类用来描述不同的显示设备,WiFiDisplay作为一个虚拟显示设备;

·修改了SurfaceFlinger模块来支持WiFiDisplay,通过SF把显示内容投放到不同的设备上;

·新加了DisplayManagerService来对系统的显示设备进行统一管理

·根据Miracast规定的会话建立管理流程,实现了source端和sink端的程序

3.1  应用程序端

对于WiFiDisplay功能,Android提供了相应接口给应用程序使用,以实现在第二显示设备上进行显示。具体内容参考官方描述,其中关键步骤见图16:

图16 Android上WFD应用编程简要步骤

可以看到主要包括Presentation和MediaRouter两个class。实际上它们都会调用一个重要的class提供的功能 – DisplayManager,而DisplayManager接口的具体实现在另外一个进程中的DisplayManagerService.java文件中。

3.2  DisplayManagerService及相关

DisplayManagerService是Android中管理WiFiDisplay功能的核心服务:

图17  DisplayManagerService简图

每一种显示设备(LocalDisplayDevice、WiFiDisplayDevice)都有一个对应的DisplayAdapter,DisplayManagerService通过管理这些Adapter来管理不同的显示设备。比如DisplayManager发起的对WiFiDisplay的操作请求,都会由DisplayManagerService转给WifiDisplayAdapter来实际完成。另外DisplayManagerService服务还通过WindowManagerFuncs窗口管理功能接口直接调用WindowManagerService的函数,实现窗口内容的刷新;同样DisplayManagerService服务还通过InputManagerFuncs接口直接调用InputManagerService的函数,用来设置输入系统需要的显示器的显示视图信息。

而WifiDisplayAdapter的操作最终会实现在WifiDisplayController中,去实现设备扫描、设备连接等操作:

图18  WifiDisplayController简图

关于和其他设备的WiFiDirect连接,Android有专门的一个WifiP2pService来管理,这里对于设备的连接就是直接调用WifiP2pManager(和WifiP2pService交互)所提供的接口来完成。

3.3   Source/Sink设备会话管理端

在设备建立WiFi连接后,会在RemoteDisplay上监听RTSP的连接,用于后续创建session和传输实时流数据。

图19  监听RTSP连接流程简图

如上图,实际的监听最终流程会走到RemoteDisplay中,即一个RemoteDisplay对象的创建。通过创建这个本地的RemoteDisplay对象将会创建一个ANetworkSession对象,用于管理网络部分的操作;创建一个ALooper对象,实现各类消息的派发和处理;创建一个WifiDisplaySource对象(由于搭载Android系统的大多数设备在WiFiDisplay场景中,多数会扮演source端的角色,因此这里创建的是WifiDisplaySource对象),具体处理各类消息:

图20  RemoteDisplay简图

另外,Source目录还包括PlaybackSession.cpp、MediaPuller.cpp、Converter.cpp、TSPacketizer.cpp、Sender.cpp等C++类文件和相应的头文件,分别负责Source端的会话过程管理、镜像媒体读取、编码、TS打包及RTP打包发送等过程。Converter 对象中包括一个MediaCodec对象具体负责编码过程,MediaCodec对象实际通过ACodec对象调用IOMX接口使用OPENOMX媒体框架完成镜像数据的编码。

3.4  视/音频数据获取方式

图21  source端的媒体数据获取简图

如图,source设备端程序对要在远端设备进行呈现的视/音频数据通过MediaSource类进行管理。上图中的SurfaceMediaSource和AudioSource都是继承自MediaSource类,它们分别对应视频数据和音频数据,根据不同的情景,source设备端程序可以添加视频或者音频数据源到当前程序中来,而且每一个MediaSource会对应创建一个Converter对象和一个MediaPuller对象,用于媒体数据的编码和数据读取等操作。下图是获取视频数据的程序片段,调用MediaSource的通用接口read来实现。

图22  获取视频数据程序片段

3.4.1  视频数据源

由图22可知,视频数据是从一个BufferQueue中读取的。上层应用正是将需要显示的视频数据放到和这个BufferQueue对应的Surface中,实现视频数据的远端设备投递。

图23  SurfaceFlinger管理不同显示设备简图

较详细来说,上文中的surface是由WiFiDisplayDevice所持有的,这部分内容还和SurfaceFlinger为支持画面投递到不同的设备上而进行的改动有关。如图23,主要是抽象了DisplayDevice来表述本地显示设备和WiFiDisplay等显示设备,在SurfaceFlinger.cpp的handleTransactionLocked函数中可以看到:

图24 SurfaceFlinge对不同显示设备处理代码片段

对于virtualDisplay的话(WiFiDisplay设备),mFramebufferSurface为空;SurfaceTextureClient直接使用了State信息中携带的surface变量。这个Surface正是当RTSP建立后,在回调函数onDisplayConnected中注册到SufaceFlinger中的(3.3节描述监听连接),这样SurfaceFlinger会将上层应用的显示数据投递到这个Surface上面,而source端的程序则会从这个surface上取出数据。

3.4.2  音频数据源

由图21可以看到,音频数据的获取是通过AudioRecod来得到。Android系统对于Audio系统抽象了AudioTrack对象和AudioRecord对象来分别用于音频数据的输出和音频数据的采集/获取。对于WiFiDisplay情景下的音频数据处理,Android也是在不破坏原有架构的情况进行的:

图25 WFD情景下音频简单架构图

AudioRecord通过AudioSystem对象来获得AudioFlinger和AudioPolicyService的远端接口进行操作,最终和HAL层的module交互,实际上完成的是从一个管道中的读取操作;而AndroidTrack也是基于同样的模型,只不过流程相反,完成的是向HAL层的一个对应管道中的写操作。其中AudioPolicyService在Android关于Audio的各个组件中扮演着核心角色:

图26  AudioPolicyService核心与其他组件交互图

如上图,详细来说:AudioPolicyService直接交互的是一个称为‘POLICY’的HAL层模块,这个模块提供了通用接口;然后通用接口会调用到一个具体的策略管理类中提供的接口,对应上图的AudioPolicyManagerALSA;最终,会根据不同的调用参数来获取真正的HAL层模块,和硬件交互,而AudioFlinger得到具体的HAL层模块后,就可以直接对其操作了。

这些具体的HAL模块,ID名称都为AUDIO_HARDWARE_MODULE_ID ,只是被编译成了不同名称的库文件,而对应于WiFiDisplay的HAL层模块不需要和具体的硬件打交道,实际实现为一个管道:

图27  WiFiDisplay的HAL模块程序片段

因此,对于需要通过WiFiDisplay到远端设备进行呈现的音频数据,只需要使用AudioTrack的接口来把音频数据放到上文HAL模块中的管道;而WiFiDisplay的source程序端也只需要调用AudioRecord的接口取出数据即可。最发送前的编码,音频/视频打包则专门去处理,不破坏原有的系统架构。

4 WiFiDisplay应用场景及相关产品

4.1  主要应用场景

WiFiDisplay技术实现视/音频数据的无线远端呈现,目前涉及视/音频数据处理的设备较多,常用的应用场景有:

1、数字播放器和数字电视工作场景:在这个应用场景下,由于source端设备不具有用户交互屏幕,因此sink端设备需要和用户交互完成设备的配对、传输的控制等工作;

图28 WFD应用场景1

2、下图描述的是一个数字机顶盒和DTV加上一个AP的工作模型,source设备在这个模型中同时连接到AP和sink设备,source端的数据此时是从网络获取的。这在WiFiDirect模型中是允许的,对于P2P连接在底层实际上对应的一个虚拟地址。

图28 WFD应用场景2

3、下图是描述的是有两个sink端设备的应用场景,此时source设备需要发现和连接两个sink设备,并发送视频/音频数据到不同的sink设备上。同时两个sink设备也需要彼此通信,来做同步和其他信息交换。

图28 WFD应用场景3

4.2  相关应用产品

WiFiDisplay的应用产品,市场上已经有一些,比如百度推出的百度影音棒、小米盒子等。其中百度影音棒的工作情况如下:(官方说明)

图29  百度影音棒2S工作简图

百度开发出的百度影音棒系列,实际上一种充分考虑现实情况的一套无线视频播放方案。由上图可知,考虑到现有电视的实际情形(大多数只带HDMI功能),这套方案对于TV还是使用HDMI和BaiDu 2S有线连接,而真正的无线模块则是这里的BaiDu 2S。这里的source设备即为手机,sink端设备其实就是BaiDu 2S。

小米盒子和上图的工作模型基本一致,不过根据官方说明支持音乐远端播放以及AirPlay协议和DLNA协议(官方说明)。

5  DLNA技术和AirPlay技术

5.1  DLNA技术

DLNA(Digital Living Network Alliance)是由Sony、Intel、Microsoft等发起成立的一个认证组织,其目的也是实现消费电子产品通过有线/无线网络实现设备互联、数据互通。相比于Miracast认证项目,DLNA有着自己的一套框架和相应标准:首先DLNA将市场上几乎所有的电子产品进行了分类(图30),一方面可以便于DLNA对众多的设备进行规范认证,另一方面也是DLNA为不同设备间进行交互制定标准的基础。

图30  DLNA定义的设备类别和类型

其次DLNA定义了设备工作架构(图31),其中UpnP是实现设备设备发现、连接、控制的重要协议层(参考文章),而媒体数据的传输则是使用HTTP传输协议或者是RTP协议。

图31 DLNA系统架构图

5.2  AirPlay技术

AirPlay是苹果公司实现的在苹果产品或是其认证产品之间传输媒体信息的一套解决方案。AirPlay技术可以实现产品之间自动地互相发现,并且轻松地互相传输音乐、图片及视频文件。

AirPlay以组播DNS(Multicast DomainName Server—mDNS)协议和DNS服务发现(DNS
Service Discovery,简称DNS-SD)协议为基础,它们是IETFn Zeroconf工作组提出的用于自动寻找设备及服务的网络协议,苹果公司以这两个协议为基础,实现了苹果公司数字家庭网络框架。

AirPlay协议消息发送格式及规则基于mDNS协议,mDNS协议基于组播技术,定义了家庭各个设备之间的消息的基本格式和接收/发送规则。该协议以DNS协议为基础,并对其消息格式和消息收发顺序作出了一些修改。例如对DNS消息包头进行了简化,使其专注于实现家庭设备的互相发现;另外,考虑到使用组播技术,mDNS在降低网络拥塞和消息冗余方面也作出了很多改进,使得局域网内设备和服务的发现不会引起过多的消息交互。

在mDNS协议的基础上,DNS-SD协议规定了一个服务宣告及使用的完整过程。即设备必须发送什么样的mDNS消息才能完整地宣告并描述自己服务。DNS-SD协议使用PTR、SRV和TXT三种类型的记录全面描述了一个服务的类型,名称以及所在主机的IP和端口号等。

当使用DNS-SD协议实现了对设备及服务的发现和描述后,苹果公司的AirPlay协议规定了图片、音频及视频的传输和控制消息格式,从而实现了智能设备之间的媒体共享和协同动作。在通过DNS-SD获得了其他设备及服务的信息(即设备或服务的IP地址及端口号)之后,AirPlay使用HTTP消息实现了图片和视频的传输及控制,使用RSTP协议实现了音频的传输和控制

AirPlay工作模型和WiFiDisplay技术和DLNA技术基本一致,只不过它是苹果公司的私有方案,因此没有公开的规范资料(非官方协议协议标准)。

PDF下载:http://download.csdn.net/detail/srw11/7645371

时间: 2024-10-15 14:40:36

Android下WiFiDisplay功能探究的相关文章

Android 下拉刷新上拉加载效果功能,使用开源项目android-pulltorefresh实现

应用场景: 在App开发中,对于信息的获取与演示,不可能全部将其获取与演示,为了在用户使用中,给予用户以友好.方便的用户体验,以滑动.下拉的效果动态加载数据的要求就会出现.为此,该效果功能就需要应用到所需要的展示页面中. 知识点介绍: 本文主要根据开源项目android-pulltorefresh展开介绍. android-pulltorefresh [一个强大的拉动刷新开源项目,支持各种控件下拉刷新 ListView.ViewPager.WevView.ExpandableListView.G

android 下 利用webview实现浏览器功能

android 下 利用webview实现浏览器功能: 1.界面添加WEBVIEW控件. 2.在界面.JAVA代码页面(protected void onCreate(Bundle savedInstanceState) 方法中)添加如下代码: //#region WebView wb=(WebView)findViewById(R.id.Wb_Main); //设置WebView属性,能够执行Javascript脚本 wb.getSettings().setJavaScriptEnabled(

Android 下拉刷新上拉加载效果功能

应用场景: 在App开发中,对于信息的获取与演示,不可能全部将其获取与演示,为了在用户使用中,给予用户以友好.方便的用户体验,以滑动.下拉的效果动态加载数据的要求就会出现.为此,该效果功能就需要应用到所需要的展示页面中. 知识点介绍: 本文主要根据开源项目android-pulltorefresh展开介绍. android-pulltorefresh [一个强大的拉动刷新开源项目,支持各种控件下拉刷新 ListView.ViewPager.WevView.ExpandableListView.G

Android下自写类似系统wifi管理功能的实现

经常有人问到关于Android下WIFI管理的问题,询问个中归于wifi的操作,下面我就写写如何在Android下实现类似Android系统自带wifi管理功能的步骤,通过这个的学习,相信关于android下wifi的操作,我们基本都能掌握了: 第一.说说界面布局 界面很简单: 顶部一个刷新按钮和一个WIFI开关 下部一个listview,每一行就是一个扫描到的wifi信息,显示它的SSID.加密类型,信号强度,是否已经连接 第二.关于列表的获取 如何获取wifi扫描列表呢?wifiManage

Android下拉刷新库,利用viewdraghelper实现,集成了下拉刷新,底部加载更多,数据初始加载显示loading等功能

项目Github地址:https://github.com/sddyljsx/pulltorefresh Android下拉刷新库,利用viewdraghelper实现. 集成了下拉刷新,底部加载更多,以及刚进入加载数据的loadview.包括了listview与gridview的改写. 效果1: 效果2: 效果3: 效果4: 效果5: 使用说明: imageList=(ListView)findViewById(R.id.image_list); imageAdapter=new ImageA

android 布局之滑动探究 scrollTo 和 scrollBy 方法使用说明

涉及到滑动,就涉及到VIEW,大家都知道,android的UI界面都是由一个一个的View以及View的派生类组成,View作为基类,而常用的布局里面的各种布局就是它派生出来的ViewGroup的子类,ViewGroup作为各个组件的容器搭建了整体的UI.以下是android UI的结构示示意图: 查看源码 /** * Implement this to do your drawing. * * @param canvas the canvas on which the background w

fiddler Android下https抓包全攻略

fiddler Android下https抓包全攻略 fiddler的http.https的抓包功能非常强大,可非常便捷得对包进行断点跟踪和回放,但是普通的配置对于像招商银行.支付宝.陌陌这样的APP是抓不到包的,需要一些特殊的配置,本文把fiddler Android下https抓包的详细配置都罗列出来,供大家参考. 一.普通https抓包设置 先对Fiddler进行设置: 勾选“CaptureHTTPS CONNECTs”,接着勾选“Decrypt HTTPS traffic”.同时,由于我

Android类库打包方法探究

转自:Android类库打包方法探究 开发Android应用的时候,对于可用于多个应用的公用的部分,或是打算发布给第三方进行应用集成的部分,要把这部分打包成类库怎么做呢?众所周知,Android应用使用ADT打包成apk,apk中包含了运行程序所需要的一切,包括:class.asset.res.AndroidManifest.xml等.而对于类库项目(library project),ADT生成的jar包里只包含编译生成的class文件,不包含res资源文件,res只能在应用项目打包apk的时候

Android 下拉刷新上拉加载 多种应用场景 超级大放送(上)

转载请标明原文地址:http://blog.csdn.net/yalinfendou/article/details/47707017 关于Android下拉刷新上拉加载,网上的Demo太多太多了,这里不是介绍怎么去实现下拉刷新上拉加载,而是针对下拉刷新上拉加载常用的一些应用场景就行了一些总结,包含了下拉刷新上拉加载过程中遇到的一些手势冲突问题的解决方法(只能算是抛砖引玉). 去年9月的时候,那时自己正在独立做Android项目.记得刚刚写完那个ListView列表页面(木有下拉刷新,上拉加载)