codec engine代码阅读1~3:根目录package.xdc,release notes和example文件夹

本文主要是介绍codec engine代码阅读1~3:根目录package.xdc,release notes和example文件夹,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!


codec engine代码阅读1~3:
http://www.usr.cc/thread-52029-1-3.html
http://www.usr.cc/thread-52030-1-3.html
http://www.usr.cc/thread-52032-1-3.html

codec engine代码阅读一---根目录下的package.xdc
codec engine代码是适用于XDC tools而写的,因此看代码之前要对XDC tools有一些基本的了解,可以参考: TI XDC工具入门简介

Package.xdc -------------描述该包的名称,版本信息,依赖文件,模块信息等

不看版权声明部分,正文的第一行应该是:

/* This "requires" list describes what packages to import into this bundle */
requires ti.sdo.ce;
requires ti.sdo.ce.node;
requires ti.sdo.ce.ipc;
requires ti.sdo.ce.ipc.bios;
requires ti.sdo.ce.ipc.dsplink;
requires ti.sdo.ce.ipc.dsplink.dsp;
requires ti.sdo.ce.ipc.linux;
requires ti.sdo.ce.ipc.noOS;

下面是好多行的requires语句。注释内部说:这个requires列表描述的是要包含到这个bundle里面的包们。
requires列表下面也没什么内容了,全部内容是:

/*!
* ======== codec_engine ========
* The Codec Engine product package. //codec engine产品包
*
* This package is a "bundle" of packages required to use the Codec Engine//这个包是一个要使用codec engine api来运行
* API's to run algorithms. It also includes packages required to add new //算法所需要的包的bundle.这也包含了一些
* algorithms to a system using the Codec Engine. //加使用codec engine的系统增加新算法所需的包.
*
*/
package codec_engine_2_23_01 [1, 0, 0] {
} //这个结构的含义还不了解.

bundle本意是包,捆.实际上这里说的就是包的集合.

然后我们看都require一些什么:

requires ti.sdo.ce; //ce-codec engine
requires ti.sdo.ce.node; //codec engine节点
requires ti.sdo.ce.ipc; //ipc=inter process communication 进程间通信的包.
requires ti.sdo.ce.ipc.bios; //进程间通信的bios部分
requires ti.sdo.ce.ipc.dsplink; //进程间通信用到的dsplink
requires ti.sdo.ce.ipc.dsplink.dsp; //进程间通信用到的dsplink中的dsp部分
requires ti.sdo.ce.ipc.linux; //进程间通信的linux部分
requires ti.sdo.ce.ipc.noOS; //无操作系统情况下的进程间通信.
requires ti.sdo.ce.osal; //这个不懂 //osal 是将ce的代码和操作系统隔开的层,只留出几个接口供应用程序使用
requires ti.sdo.ce.osal.bios;
requires ti.sdo.ce.osal.linux;
requires ti.sdo.ce.osal.noOS;
requires ti.sdo.ce.alg; //alg=algorithm 算法
requires ti.sdo.ce.trace; //调试追踪
requires ti.sdo.ce.speech; //语音部分
requires ti.sdo.ce.speech1;
requires ti.sdo.ce.video; //视频部分
requires ti.sdo.ce.video1;
requires ti.sdo.ce.video2;
requires ti.sdo.ce.audio; //音频部分
requires ti.sdo.ce.audio1;
requires ti.sdo.ce.global; //全局部分
requires ti.sdo.ce.image; //图像部分
requires ti.sdo.ce.image1;
requires ti.sdo.ce.universal;
requires ti.sdo.ce.vidtranscode; //视频转码
requires ti.sdo.ce.vidanalytics; //视频分析
requires ti.sdo.ce.video2.split; //视频分割

requires ti.sdo.ce.bioslog; //bios日志

requires ti.sdo.ce.utils; //附加工具
requires ti.sdo.ce.utils.trace;//附加工具的调试部分
requires ti.sdo.ce.utils.xdm;

requires ti.dsplink.utils.lad;
requires ti.dsplink.utils.ladclient;

requires ti.sdo.ce.examples.codecs;//示例编解码器
requires ti.sdo.ce.examples.codecs.viddec1_copy;//示例视频编码器
requires ti.sdo.ce.examples.codecs.videnc1_copy;
requires ti.sdo.ce.examples.codecs.imgdec1_copy;//示例图像编解码器
requires ti.sdo.ce.examples.codecs.imgenc1_copy;
requires ti.sdo.ce.examples.codecs.sphdec1_copy;//示例语音编解码器
requires ti.sdo.ce.examples.codecs.sphenc1_copy;
requires ti.sdo.ce.examples.codecs.auddec1_copy;//示例音频编解码器
requires ti.sdo.ce.examples.codecs.audenc1_copy;
requires ti.sdo.ce.examples.codecs.auddec1_ires; //音频资源
requires ti.sdo.ce.examples.codecs.viddec2_copy;

requires ti.sdo.ce.examples.codecs.viddec_copy;
requires ti.sdo.ce.examples.codecs.videnc_copy;
requires ti.sdo.ce.examples.codecs.imgdec_copy;
requires ti.sdo.ce.examples.codecs.imgenc_copy;
requires ti.sdo.ce.examples.codecs.sphdec_copy;
requires ti.sdo.ce.examples.codecs.sphenc_copy;
requires ti.sdo.ce.examples.codecs.auddec_copy;
requires ti.sdo.ce.examples.codecs.audenc_copy;

requires ti.sdo.ce.examples.codecs.g711;
requires ti.sdo.ce.examples.codecs.scale;
requires ti.sdo.ce.examples.codecs.vidtranscode_copy;
requires ti.sdo.ce.examples.codecs.vidanalytics_copy;

requires ti.sdo.ce.examples.codecs.viddec2split_copy;
requires ti.sdo.ce.examples.codecs.universal_copy;

requires ti.sdo.ce.examples.extensions;//扩展部分
requires ti.sdo.ce.examples.extensions.scale;

requires ti.sdo.ce.examples.servers;//服务器部分
requires ti.sdo.ce.examples.servers.all_codecs;
requires ti.sdo.ce.examples.servers.all_codecs_new_config;
requires ti.sdo.ce.examples.servers.video_copy;
requires ti.sdo.ce.examples.servers.video_copy.evmDM6446;
requires ti.sdo.ce.examples.servers.video_copy.evmDM6467;
requires ti.sdo.ce.examples.servers.video_copy.evm2530;
requires ti.sdo.ce.examples.servers.video_copy.evm3530;
requires ti.sdo.ce.examples.servers.video_copy.evmOMAPL137;
requires ti.sdo.ce.examples.servers.server_api_example;
requires ti.sdo.ce.examples.servers.audio1_ires;

requires ti.sdo.ce.examples.buildutils;
requires ti.sdo.ce.examples.apps;//应用部分
requires ti.sdo.ce.examples.apps.video_copy.singlecpu;
requires ti.sdo.ce.examples.apps.video_copy.singlecpu_configuro.evmDM365;
requires ti.sdo.ce.examples.apps.video_copy.dualcpu;
requires ti.sdo.ce.examples.apps.video_copy.dualcpu.evmDM6446;
requires ti.sdo.ce.examples.apps.video_copy.dualcpu.evmDM6467;
requires ti.sdo.ce.examples.apps.video_copy.dualcpu.evm2530;
requires ti.sdo.ce.examples.apps.video_copy.dualcpu.evm3530;
requires ti.sdo.ce.examples.apps.video_copy.dualcpu.evmOMAPL137;
requires ti.sdo.ce.examples.apps.video_copy.dualcpu_separateconfig;
requires ti.sdo.ce.examples.apps.video_copy.dualcpu_separateconfig_dll;
requires ti.sdo.ce.examples.apps.image_copy;
requires ti.sdo.ce.examples.apps.speech_copy;
requires ti.sdo.ce.examples.apps.audio_copy.singlecpu;
requires ti.sdo.ce.examples.apps.audio_copy.dualcpu;
requires ti.sdo.ce.examples.apps.audio_copy.dualcpu.evmDM6446;
requires ti.sdo.ce.examples.apps.audio_copy.dualcpu.evmDM6467;
requires ti.sdo.ce.examples.apps.audio_copy.dualcpu.evm2530;
requires ti.sdo.ce.examples.apps.audio_copy.dualcpu.evm3530;
requires ti.sdo.ce.examples.apps.server_api_example;
requires ti.sdo.ce.examples.apps.server_trace;

requires ti.sdo.ce.examples.apps.video2_copy;
requires ti.sdo.ce.examples.apps.video1_copy;
requires ti.sdo.ce.examples.apps.image1_copy;
requires ti.sdo.ce.examples.apps.speech1_copy;
requires ti.sdo.ce.examples.apps.audio1_copy.sync;
requires ti.sdo.ce.examples.apps.audio1_copy.async;
requires ti.sdo.ce.examples.apps.audio1_ires;

requires ti.sdo.ce.examples.apps.video2split_copy;

requires ti.sdo.ce.examples.apps.vidtranscode;
requires ti.sdo.ce.examples.apps.vidanalytics;

requires ti.sdo.ce.examples.apps.universal_copy;
requires ti.sdo.ce.examples.apps.scale;
requires ti.sdo.ce.examples.apps.speech;
requires ti.sdo.ce.examples.apps.speech_copy_LAD;

requires ti.sdo.ce.wizards.genserver;



codec engine代码阅读二---根目录下的release notes

release notes的前两段是非常值得看的:

This Codec Engine Release is targetted to DaVinci and OMAP platforms, enabling users to instantiate and utilize both local and remote codecs. In addition to heterogenous devices (e.g. DM644x, DM6467, OMAP2530, OMAP3530, etc.), it supports single processor environments as well; specifically C64+ devices (e.g. DM643x, and DM648), ARM devices running Linux (e.g. DM355, DM365, OMAP3503) and x86 devices running Linux.

[i] 此发行版本适用对象为DaVinci和OMAP平台, 它使得用户可以实例化并利于本地的和远程的编解码器. 除了指定的如DM644x等处理器之外, 它也支持单处理器环境,如C64+的DSP,跑linux系统的ARM设备(DM355等)和跑Linux的x86设备.

Introduction

The Codec Engine is a software platform for algorithm execution that satisfies the following, high-level goals:

Robust - drives pre-integrated components with fully characterized performance.
Easy to use - app developers specify what needs to be run, but not how or where.
Extensible and Configurable - new algorithms can be added by anyone, using standard tools and techniques.
Portable - API's are target, platform, and in many cases even codec independant.


简介
Codec Enigne一个算法执行的软件平台,它可以满足以下的高层次的目标:
强状性   易用性   可扩展和配置   可移植  


Primary packages in this Codec Engine release are briefly described here. (There are others, see the Configuration Reference Guide documentation for a complete package list.)

下面Codec Engine中的基本包进行了描述(其它的包可以参考Configuration Reference Guide ,这里有一个完整的包列表)

ti.sdo.ce - The Codec Engine runtime.
//Codec Engine的运行时程序
ti.sdo.ce.video2 - The Codec Engine video component (supporting the XDM IVIDDEC2 interface). An example is also provided.  
//视频组件,支持XDM的 IVIDDEC2接口,并提供了一个示例程序.
ti.sdo.ce.video1 - The Codec Engine video component (supporting the XDM IVIDDEC1 and IVIDENC1 interfaces). An example is also provided.
//视频组件,支持XDM的 IVIDDEC1和IVIDENC1接口,并提供了一个示例程序.
ti.sdo.ce.image1 - The Codec Engine image component (supporting the XDM IIMGDEC1 and IIMGENC1 interfaces). An example is also provided.
//图像组件,支持XDM的IIMGDEC1和IIMGENC1接口,并提供了一个示例程序.
ti.sdo.ce.speech1 - The Codec Engine speech component (supporting the XDM ISPHDEC1 and ISPHENC1 interfaces). An example is also provided.
//语音组件,支持XDM的 ISPHDEC1和ISPHDEC1接口,并提供了一个示例程序.
ti.sdo.ce.audio1 - The Codec Engine audio component (supporting the XDM IAUDDEC1 and IAUDENC1 interfaces). An example is also provided.
//音频组件,支持XDM的 IAUDDEC1和IAUDENC1接口,并提供了一个示例程序.
ti.sdo.ce.osal - The Codec Engine OS Abstraction Layer. This package insulates CE from the OS it's running on, and provides a few Modules for customers to use (e.g. Memory).
//Codec Engine的系统抽象层,它把CE和操作系统分离开,并提供了几个用户可以使用的模块,如内存.
ti.sdo.ce.utils.trace - The Codec Engine utility package for trace. This includes the TraceUtils module. This makes tracing features easier to use by an application. It will be supported in this release, but may be replaced in a future release with an incompatible implementation.

//CE的追踪调试工具.包括TraceUtils模块.它使得应用可以轻易的使用追踪特性.它在本版本中支持,但将来可以会被替换为一个不兼容的实现.
Additionally, this release of the Codec Engine continues to support the deprecated XDM interfaces included in xDAIS 5.00. This support is provided in the following packages:

//此外,这个发行版继续支持xDAIS 5.00中的XDM接口.包括如下的包:
[i] (注:下面的内容不写,似乎是说XDM也有多个版本,上面讲的是2和1版本,接口后面都有一个1或2,而下面的则是原始版本.)
ti.sdo.ce.video - The Codec Engine video component (supporting the XDM IVIDDEC and IVIDENC interfaces). An example is also provided.
ti.sdo.ce.image - The Codec Engine image component (supporting the XDM IIMGDEC and IIMGENC interfaces). An example is also provided.
ti.sdo.ce.speech - The Codec Engine speech/voice component (supporting the XDM ISPHDEC and ISPHENC interfaces). An example is also provided.
ti.sdo.ce.audio - The Codec Engine audio component (supporting the XDM IAUDDEC and IAUDENC interfaces). An example is also provided.

Codec Engine is provided as non-rebuildable libraries. Source is provided for debugging and educational value, but is not intended to be modified. Modified sources will not be supported.

//CE是以不可重新编译的方式发布的.虽然我们也提供了原码,但是那只是为了调试和教育目的而用的,并非用于修改. 修改后的原码将得不到支持.
Some distributions of this product include a "cetools" directory containing some dependent products for convenience. Products included in this release are:

//有些发行版包含了一个cetools文件夹,里面是一个方便使用的独立产品,本发行版的包含的有:


XDAIS 6.23
EDMA3 Resource Manager 1.06.00.01 (from the EDMA3 Low Level Driver product). //EDMA3资源管理器
Framework Components 2.23.01
Linux Utils 2.23.01
LPM 1.23.01
DSP/BIOS Link 1.61.03 configured for the DM6446, DM6467, OMAP-L137, OMAP2530, and OMAP3530 EVMs
See this Codec Engine cetools explanation for further details.  
详情请见cetools文档.

还有一些其他的文档可供参考:
  • Codec Engine Application Developer User's Guide (文件夹下有本地文档 | latest) //CE应用开发人员指南
  • Codec Engine Server Integrator User's Guide (文件夹下有本地文档 | latest) //CE服务器集成人员指南
  • Codec Engine Algorithm Creator User's Guide (文件夹下有本地文档 | latest) //CE算法创建人员指南
  • Codec Engine Application Programming Interface (API) Reference Guide (HTML | CHM//CE应用编程接口参考
  • Codec Engine System Programming Interface (SPI) Reference Guide (HTML | CHM//CE系统编程接口参考
  • Package Reference Guide - includes configuration details  //包参考手册,包含配置方面的详细信息.
  • Using Adapters to Run Existing XDAIS Algorithms with Codec Engine App Note //应用笔记: 使用适配器来在CE上运行己有的XDAIS算法.
In addition, users are encouraged to monitor (and contribute to!) the TI Embedded Processors Wiki. //
另外,我们鼓励用户关注我们的wiki,也欢迎大家贡献内容.




codec engine代码阅读三---example文件夹

这个文件夹是示例代码,目录下有user.bld   xdcpaths.mk 和config.bld三个文件,xdcpaths.mk里面保存了编译代码所需的所有工具和库所在的路径,没什么好说的.
config.bld:

NOTE FOR THE USER:
* 用户注意
* 1) Generally there is no need to edit this file
* 2) It is best to keep it in the same directory where the file "user.bld" is
* 通常没必要修改这个文件,最好把这个文件放到和user.bld同一级的文件夹里.
* In more details:
*
* This file controls compiler options for the Arm and the DSP when
* building programs with XDC. It affects only the binaries that are built
* through "package.bld" XDC files. The XDC tools pick up this file along
* the package path; this file then finds "user.bld" file with further options
* that are specific for the user's build environment.
*这个文件控制ARM和DSP的编译器使用XDC编译程序时的选项,它只影响通过package.bld文件编译的
*的二进制文件.XDC工具顺着包的路径找到这个文件,这个文件再找到user.bld文件,添加进一步的选项来
*指定用户编译环境的选项(因为它会包含user.bld,所以要改什么在user.bld里改就可以,不用改这个文件).
* The contents of this file usually doesn't change, but having it in your
* ownership allows you to tweak your compler options. If you do change
* this file, however, on the next upgrade to Codec Engine we recommend
* that you take "config.bld" file as supplied by the upgrade and then merge
* your changes with it.
*这个文件的内容通常不变,但是你是文件的主人,改不改随你的意.如果你改了这个文件.
*在升级CE时,建议你使用升级的config.bld文件,并把你的改变merge到里面.
* Also note that the XDC tools pick up the first config.bld file they find
* along the package path; to make sure it is this file that gets picked,
* make the directory where this file is the first in the package path.
* You can verify that this file is being included by checking that
* the build process for each package prints the "Running the version
* from Codec Engine Examples" message.
*注间:XDC工具只沿着路径找第一个config.bld文件,为了保证这个文件能被找到,把这个文件所在的路径
*放在第一个包路径的位置上.要查看这个文件有没有被包含,可以查看编译过程中的"Running
*the version from Comdec Engine Examples"消息.
*/

所以说这个文件不用管.然后看 user.bld,这个文件是要修改的:
/*
*  ======== user.bld ========
*
* User note: YOU MUST MODIFY THIS FILE TO SPECIFY THE COMPILER TOOL PATHS.
*用户注意:你必须修改这个来件来指定编译器路径.
*/

// This table list the targets for which to build libraries and programs, and for
// each target it lists where the compiler tools are and for what platforms
// the programs should be built. For all build variants where you specify
// that "doBuild" is "true", you must specify the compiler tools, and it is
// desirable to comment out unwanted platforms.
// Example: if you are only interested in building Arm-side examples for
// evmDM6446 running Montavista Arm Linux, set doBuild: false everywhere
// except for the first Arm "doBuild"; then, specify your Montavista Arm
// tools directory, and comment out all platforms for that build except
// for '{ platform: "evmDM6446" }'.
//下面的表列出了库和程序编译运行的目标,每个目标都指明了其编译器所在路径和程序编译的平台.
//对于每一个构架变体,你都必须指定其编译器,并注释掉不需要的平台.
//例如:如果你只关心编译DM6446上跑Montavista linux的ARM端的示例程序,则在除第一个Arm外的每
//一处设定doBuild为false.然后指定你的montavista arm 编译器的路径,注释掉除{
//platform:"evmDM6446"}以外的所有平台.

下面我们为DM6446修改后的buildtabe变量的值:

var buildTable = {
"Arm": [{doBuild: true, // standard build for Linux这里doBuild为true,因为DM6446上有ARM
target: "gnu.targets.arm.GCArmv5T", //DM6446上的ARM是ARVv5核的

// Arm tools. NOTE: make sure the directory you specify has a "bin" subdirectory
cgtoolsRootDir: "/usr/local/montavista/pro/devkit/arm/v5t_le", //ARM编译器路径在这里设

platforms: [ // NOTE: comment out platforms (boards) below for which you don't want to build



var targets = []; //这里通过脚本,从buildTable里面提取信息,赋值给targets和userbldBuildPlatforms变量.
var userbldBuildPlatforms = {};

for each (var cpu in buildTable) {//对于buildTable中的每一个cpu表项,
for (var t = 0; t < cpu.length; t++) {
if (cpu[t].doBuild) {//如果某个cpu的doBuild值为true,
var targ = xdc.useModule(cpu[t].target);
targets.push(targ); //targets里就加上cpu[t].target项通过xdc.useModule转化的内容.
targ.rootDir = cpu[t].cgtoolsRootDir;
userbldBuildPlatforms[targ.name] = cpu[t].platforms;//这里加上平台信息.
}
}
}

Build.targets = targets;

上一节中指定了编译器的路径,但编译器的具体文件名叫什么呢?对arm平台来说是不一样的,这里要指定你所有的名字是什么,比如arm-linux-gcc,但montavista自带的编译器gcc名字是arm_v5t_le-gcc在这里指定.

这篇关于codec engine代码阅读1~3:根目录package.xdc,release notes和example文件夹的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/991218

相关文章

利用Python调试串口的示例代码

《利用Python调试串口的示例代码》在嵌入式开发、物联网设备调试过程中,串口通信是最基础的调试手段本文将带你用Python+ttkbootstrap打造一款高颜值、多功能的串口调试助手,需要的可以了... 目录概述:为什么需要专业的串口调试工具项目架构设计1.1 技术栈选型1.2 关键类说明1.3 线程模

Python Transformers库(NLP处理库)案例代码讲解

《PythonTransformers库(NLP处理库)案例代码讲解》本文介绍transformers库的全面讲解,包含基础知识、高级用法、案例代码及学习路径,内容经过组织,适合不同阶段的学习者,对... 目录一、基础知识1. Transformers 库简介2. 安装与环境配置3. 快速上手示例二、核心模

Java的栈与队列实现代码解析

《Java的栈与队列实现代码解析》栈是常见的线性数据结构,栈的特点是以先进后出的形式,后进先出,先进后出,分为栈底和栈顶,栈应用于内存的分配,表达式求值,存储临时的数据和方法的调用等,本文给大家介绍J... 目录栈的概念(Stack)栈的实现代码队列(Queue)模拟实现队列(双链表实现)循环队列(循环数组

使用Java将DOCX文档解析为Markdown文档的代码实现

《使用Java将DOCX文档解析为Markdown文档的代码实现》在现代文档处理中,Markdown(MD)因其简洁的语法和良好的可读性,逐渐成为开发者、技术写作者和内容创作者的首选格式,然而,许多文... 目录引言1. 工具和库介绍2. 安装依赖库3. 使用Apache POI解析DOCX文档4. 将解析

C++使用printf语句实现进制转换的示例代码

《C++使用printf语句实现进制转换的示例代码》在C语言中,printf函数可以直接实现部分进制转换功能,通过格式说明符(formatspecifier)快速输出不同进制的数值,下面给大家分享C+... 目录一、printf 原生支持的进制转换1. 十进制、八进制、十六进制转换2. 显示进制前缀3. 指

使用Python实现全能手机虚拟键盘的示例代码

《使用Python实现全能手机虚拟键盘的示例代码》在数字化办公时代,你是否遇到过这样的场景:会议室投影电脑突然键盘失灵、躺在沙发上想远程控制书房电脑、或者需要给长辈远程协助操作?今天我要分享的Pyth... 目录一、项目概述:不止于键盘的远程控制方案1.1 创新价值1.2 技术栈全景二、需求实现步骤一、需求

Java中Date、LocalDate、LocalDateTime、LocalTime、时间戳之间的相互转换代码

《Java中Date、LocalDate、LocalDateTime、LocalTime、时间戳之间的相互转换代码》:本文主要介绍Java中日期时间转换的多种方法,包括将Date转换为LocalD... 目录一、Date转LocalDateTime二、Date转LocalDate三、LocalDateTim

jupyter代码块没有运行图标的解决方案

《jupyter代码块没有运行图标的解决方案》:本文主要介绍jupyter代码块没有运行图标的解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录jupyter代码块没有运行图标的解决1.找到Jupyter notebook的系统配置文件2.这时候一般会搜索到

Python通过模块化开发优化代码的技巧分享

《Python通过模块化开发优化代码的技巧分享》模块化开发就是把代码拆成一个个“零件”,该封装封装,该拆分拆分,下面小编就来和大家简单聊聊python如何用模块化开发进行代码优化吧... 目录什么是模块化开发如何拆分代码改进版:拆分成模块让模块更强大:使用 __init__.py你一定会遇到的问题模www.

springboot循环依赖问题案例代码及解决办法

《springboot循环依赖问题案例代码及解决办法》在SpringBoot中,如果两个或多个Bean之间存在循环依赖(即BeanA依赖BeanB,而BeanB又依赖BeanA),会导致Spring的... 目录1. 什么是循环依赖?2. 循环依赖的场景案例3. 解决循环依赖的常见方法方法 1:使用 @La