音视频基础及海思sample_venc解读

news2024/11/16 19:32:57

1、sample的整体架构

(1)sample其实是很多个例程,所以有很多个main

(2)每一个例程面向一个典型应用,common是通用性主体函数,我们只分析venc

(3)基本的架构是:venc中的main调用venc中的功能函数,再调用common中的功能函数,再调用mpp中的API,再调用HI3518E内部的硬件单元。

(4)sample的配置和编译,重点注意很多环境变量,目录结构不要乱动。

2、sample代码学习的关键

(1)得理解很多基础概念,譬如图像采集原理、模拟数字、通道、绑定、组、视频缓冲池、在线/离线模式等等

(2)得从宏观上理解整个视频采集、内部传递、处理、编码输出、网络传输等的过程。

(3)得反复看代码,熟才能生巧,才能帮助理解整个代码。

(4)得查阅mpp手册,熟悉海思这一套API的规矩和一般用法。

3、sample_venc的大体分析

(1)从main入手,main的传参分析

(2)几个重要的基本概念:

H.264 H.265 MJPEG 视频编码规范标准

1080P、720P、VGA、D1 视频分辨率(清晰度)

fps(frame per second) 帧率:每秒多少帧

4、图像像素格式深度理解

4.1、颜色的学问

(1)颜色是主观还是客观存在?是主观存在的,颜色的本质是光的波长,这些不同波长的光映射到人的眼中就成了不同的颜色,正因为有人去看才有了颜色这个概念

(2)颜色的三个关键:亮度、色度、饱和度

(3)人的眼睛并非理想完美的颜色识别器件,图像表达也有清晰度和质量高低的差异

(4)科学研究如何定义(或者表达、记录、计算)一种颜色?色彩空间的概念

色彩空间:如何用数字表达一种颜色,例如rgb888,rgb565等

4.2、rawRGB和图像采集过程

(1)图像采集的过程:光照在成像物体被反射->镜头汇聚->Sensor光电转换->ADC为rawRGB

光照到成像物体上被反射到镜头汇聚起来传到焦点,Sensor就在焦点处,Sensor是一个平面,被分成很多区域,每一个最小区域就是一个像素,这一路像素就是一路单独的光电转换器,转出来的电信号是一个模拟值,光照到每个像素上就生成了这个像素的模拟电压。

Sensor有个参数叫做分辨率,或者说叫做像素个数,比如买手机时经常说多少w像素,指的就是这里的意思。

这些模拟电信号再由ADC转换成数字的电信号(rawRGB)

(2)sensor上每个像素只采集一种颜色的光,因此sensor每个像素只能为R或G或B

也就是说手机摄像头上一个像素点是rgb的一个颜色。

而手机的LCD显示屏,一个像素点里面有三个小灯,rgb。
​​在这里插入图片描述

​​也就是说光电转换只能转换一种颜色分量,不可能一个点转换R、G、B三种分量。

(3)rawRGB和RGB都是用来描述图像的,图像采集时RGB是由rawRGB计算而来的

由rawRGB进行联合附近的分量进行加权平均计算得到RGB

(4)因为图像颜色本身有一定连贯性,而且人眼是非理想的,因此图像采集和再显示给人这整个构成中有三个要素:sensor分辨率、pitch(两个像素点中心的距离)、观看距离

(5)如果是视频,质量好坏还要加上帧率framerate

(6)图像的表达、压缩、修整等相关技术,就发生在rawRGB进来以后的各个环节

表达:rgb565、rgb888、1080p等

压缩:bmp、jpg、png等

修整:锐化、曝光等

5、RGB和YUV详解

5.1、RGB方式表示颜色

(1)RGB有RGB565和RGB888,ARGB等多种子分类

(2)RGB的本质:将色度分解为R、G、B三部分,然后记录下亮度数据,也就是说RGB没有记录颜色的色度,色度是固定的红绿蓝。

(3)RGB的优势:方便数字化表达,广泛用于数字化彩色显示器,计算机编程等领域。

(4)RGB的劣势:和传统的灰度图兼容不好,表达颜色的效率不高

灰度图只有亮度,没有颜色,而RGB又默认分解成三种基色,所以会兼容不好

5.2、YUV

(1)YUV是一种色彩空间,Y表示亮度,U和V表示色度。只有Y就是黑白图像,也就是灰度图,再加上UV就是彩色图像了。YUV的一个好处就是让彩色系统和传统黑白系统很好的兼容。

(2)YUV和RGB的相同点是:都是用来表达颜色的数学方法;不同点是:对颜色的描述思路和方法不同。RGB将一个颜色拆解为3个纯色的亮度组合,YUV将一个颜色分解为一个亮度和2个色度的组合。

(3)RGB和YUV之间可以用数学方法互相换算,是个典型的浮点运算过程。

(4)YUV和YCbCr几乎可以看做一个概念,详细的区分以后再去慢慢体会。

(5)YUV格式分为packed和planar两种。具体参考:http://blog.csdn.net/sunnylgz/article/details/7580628
​​在这里插入图片描述
(6)有多种YUV相关的概念需要弄清楚(以下均为planar格式)

YUV

YUV422(YUYV)

YUV420(YUV411)

YUV422 planar(YUV422P)

[Y1,Y2,Y3,Y4,Y5,Y6,Y7,Y8],[U1,U2,U3,U4],[V1,V2,V3,V4]

YUV420 Planar(YUV420P)

[Y1,Y2,Y3,Y4,Y5,Y6,Y7,Y8],[U1,U2],[V1,V2]

YUV422 semi planar(YUV422SP)

[Y1,Y2,Y3,Y4,Y5,Y6,Y7,Y8],[U1,V1],[U2,V2],[U3,V3],[U4,V4]

YUV420 semi Planar(YUV420SP)

[Y1,Y2,Y3,Y4,Y5,Y6,Y7,Y8],[U1,V1],[U2,V2]

参考:http://blog.csdn.net/bingqingsuimeng/article/details/50716390
和https://www.2cto.com/kf/201303/198023.html

6、海思MPP功能模块和视频缓存池

6.1、MPP功能模块框图

(1)找到MPP手册

麦克风声电转换AD转换采样-》AI音频输入并降噪-》AENC编码-》音频码流

音频码流-》ADEC解码-》AO音频输出-》喇叭放大

镜头-》Sensor光电转换得到模拟电信号-》AD转换得到rawRGB-》VI视频输入-》VPSS接收并输出多路分辨率不同的图像-》VENC编码成H.264码流

(2)详见系统概述1.3部分
在这里插入图片描述

6.2、sample中SAMPLE_VENC_1080P_CLASSIC函数开始看

(1)PAYLOAD_TYPE_E

(2)PIC_SIZE_E

(3)VB_CONF_S

7、视频缓存池

7.1、什么是视频缓冲池

(1)视频的本质是多帧图片,图片的本质是RGB或rawRGB数据,要占用一段连续内存

(2)视频的裁剪、缩放、修正处理(马赛克)等各种操作,本质上就是对内存中的数据进行运算

(3)视频缓存池(VB, video buffer)就是一段很大,又被合理划分和管理的内存,用来做视频数据的暂存和运算场地

(4)公共视频缓存池的公共2字,可以理解为全局变量,也就是各个模块都能访问的一段内存

(5)看似视频缓存块在各个模块之间流转,实际上并没有内存复制,而是指针在传递

(6)视频缓存池的内存由MPP来维护,我们在系统启动时就把整个SDRAM分成了2部分:系统部分(由linux kernel来维护管理)和mpp部分(由mpp系统来维护管理)

(7)缓存池需要几个,每个中包含几个缓存块,每个缓存块多大,都是可以由用户程序设置好参数,然后调用MPP的相应API来向MPP申请分配的。

7.2、相关的数据结构和API

(1)VB_CONF_S结构体
在这里插入图片描述
(2)HI_MPI_VB_SetConf
(3)HI_MPI_VB_Init

8、VI部分 知识要点

(1)常用Sensor的接口有三种:MIPI、LVDS、DC
(2)WDR宽动态:一副图像里面,局部曝光和其它地方是不一样的
(3)isp就是image signal process,图像信号处理。
(4)HI3518E内部的ISP单元是隶属于VI模块的。VI模块就包含3大部分:第一部分是和Sensor对接的部分(Sensor是什么接口的,mipi,dc等,怎么去操作),第二部分就是ISP,第三部分就是VI dev和channel
dev:就是用来采集图像的一个硬件单元

9、VPSS部分 知识要点

9.1、VPSS的手册部分解读

VI/VPSS 离/在线模式
VI 和 VPSS 的协作模式分为以下 2 种(模式切换由 load 脚本参数控制,对应 sys 模块
参数 vi_vpss_online):

VI/VPSS 离线模式是指 VI 进行时序解析后将图像数据写出到 DDR,VPSS 从
DDR 中载入 VI 采集的数据进行图像处理,是传统 Hi3518/Hi3520D 等芯片的
VI/VPSS 的协作模式。

VI/VPSS 在线模式是指 VI 进行时序解析后直接在芯片内部将数据传递到 VPSS,
中间无 DDR 写出的过程。在线模式可以省一定的带宽和内存,降低端到端的延
时。需要注意的是,在线模式时,因为 VI 不写出数据到 DDR,无法进行
CoverEx、OverlayEx、Rotate、LDC 等操作,需要在 VPSS 各通道写出后再进行
Rotate/LDC 等处理,而且有些功能只在离线下能支持,比如 DIS。

总结:
离线模式:公共视频缓冲池-》VI模块处理缓冲池那一份-》复制到DDR-》VPSS处理DDR中的那一份
在线模式:公共视频缓冲池-》VI模块处理缓冲池那一份-》VI模块将缓冲池的指针传递给VPSS,VPSS处理缓冲池中的那一份

10、VENC部分 知识要点

有了以上,VENC部分代码就很简单

学习博文:

LCD常用接口:
https://blog.csdn.net/wocao1226/article/details/23870149

yuv格式:
http://blog.csdn.net/sunnylgz/article/details/7580628
http://blog.csdn.net/bingqingsuimeng/article/details/50716390
https://www.2cto.com/kf/201303/198023.html

图像编码原理:
http://blog.csdn.net/newchenxf/article/details/51693753

Qp:
http://blog.csdn.net/u013354805/article/details/51988171

VI、VPSS、VENC数据流向图

​​在这里插入图片描述

海思示例代码 函数调用关系

sample_venc.c
main
	SAMPLE_VENC_1080P_CLASSIC
		SAMPLE_COMM_VI_GetSizeBySensor(step1)		//获取Sensor采集图像的大小---》720P
		SAMPLE_COMM_SYS_CalcPicVbBlkSize			//计算缓冲块大小---》1280 * 768 * 1.5+HeaderSize		1.5是yuv420图像中一个像素的大小
			SAMPLE_COMM_SYS_GetPicSize		//获取Sensor图像的大小---》1280 * 720
			VB_PIC_HEADER_SIZE			//计算图像头的大小---》HeaderSize	
		SAMPLE_COMM_SYS_Init(step2)			//MPP系统初始化
			HI_MPI_SYS_Exit				//去除 MPP 系统。禁用一切模块
			HI_MPI_VB_Exit				//去除 MPP 视频缓存池
			HI_MPI_VB_SetConf				//设置 MPP 视频缓存池属性---》最大缓冲池个数为128,实际缓冲池个数为16,每个缓冲块的大小和个数
			HI_MPI_VB_Init				//初始化 MPP 视频缓存池
			HI_MPI_SYS_SetConf				//配置系统控制参数---》64字节对齐
			HI_MPI_SYS_Init				//初始化 MPP 系统
		SAMPLE_COMM_VI_StartVi(step3)			//启动vi dev & CHN进行捕获
			IsSensorInput				//传感器输入是 电视或Sensor
			SAMPLE_COMM_VI_StartIspAndVi		//启动Isp
				SAMPLE_COMM_VI_StartMIPI(1//mipi接口的配置---》3.3V
					SAMPLE_COMM_VI_SetMipiAttr				//mipi接口的配置
						fd = open("/dev/hi_mipi", O_RDWR);				//打开mipi的设备文件
						ioctl(fd, HI_MIPI_SET_DEV_ATTR, pstcomboDevAttr)		//应用层操作Sensor的驱动,对Sensor做一些必要的初始化
				SAMPLE_COMM_ISP_Init(2//配置传感器和ISP(包括WDR宽动态模式)。  目的是启动3518e芯片内部的ISP单元
					sensor_register_callback	//传感器寄存器回调
					HI_MPI_AE_Register		//注册AE库,自动曝光
					HI_MPI_AWB_Register	//注册AWB库,自动白平衡
					HI_MPI_AF_Register		//注册AF库,自动对焦
					HI_MPI_ISP_MemInit	//初始化 ISP 外部寄存器
					HI_MPI_ISP_SetWDRMode	//设置 ISP 宽动态的模式---》不启用
					HI_MPI_ISP_SetPubAttr	//配置 ISP 属性---》rawRGB的排列顺序---GRBG、帧率为30、图像区域的起始点、图像区域的宽和高
					HI_MPI_ISP_Init		//初始化ISP系统
				SAMPLE_COMM_ISP_Run(3//运行isp线程  
					pthread_create(&gs_IspPid, &attr, (void* (*)(void*))Test_ISP_Run, NULL)	//创建线程
						Test_ISP_Run		//线程函数
							HI_MPI_ISP_Run	//开始运行ISP系统
				SAMPLE_COMM_VI_StartDev(4//配置并打开Dev
					HI_MPI_VI_SetDevAttr	//配置 Dev的属性---》接口模式为DC,单路工作方式,图像的扫描模式是逐行扫描,转换成yuv420,使用内部ISP,输入数据类型为RGB,不启用数据逆向
					HI_MPI_ISP_GetWDRMode	//获取 ISP 宽动态模式
					HI_MPI_VI_SetWDRAttr	//配置 WDR宽动态模式的 工作属性---》都不开启
					HI_MPI_VI_EnableDev	//启用Dev
				SAMPLE_COMM_VI_StartChn(5//配置并打开通道chn(最多1个)
					HI_MPI_VI_SetChnAttr	//设置 VI 通道chn属性---》通道支持的图像属性是720P,像素存储格式是yuv420sp,原始图像不镜像不翻转,不进行帧率控制,不压缩
					HI_MPI_VI_SetRotate	//设置 VI 图像旋转属性--》图像从通道中出来后的旋转角度---不旋转
					HI_MPI_VI_EnableChn	//启用通道chn			
		SAMPLE_COMM_SYS_GetPicSize(step4)		//获取Sensor图像的大小---》1280 * 720
		SAMPLE_COMM_VPSS_StartGroup			//启动VPSS的Group
			HI_MPI_VPSS_CreateGrp			//创建Group
			HI_MPI_VPSS_GetNRParam			//获取 vpss 3DNR 参数
			HI_MPI_VPSS_SetNRParam			//设置 vpss 3DNR 参数
			HI_MPI_VPSS_StartGrp			//启用Group
		SAMPLE_COMM_VI_BindVpss				//Group绑定VI模块中的Dev0中的chn0
			SAMPLE_COMM_VI_Mode2Param		//获取VI的参数---》是有1个Dev和chn
			HI_MPI_SYS_Bind				//VI通道chn0 绑定 vpss组Group0
		SAMPLE_COMM_VPSS_EnableChn			//在Group内部创建几路自己所用的chn
			HI_MPI_VPSS_SetChnAttr			//设置 VPSS 通道属性---》不进行帧率控制
			HI_MPI_VPSS_SetChnMode			//设置 VPSS 通道工作模式---》VPSS通道工作模式为USER模式,目标图像的像素格式是yuv420sp,目标图像的宽度是720,目标图像的高是1280,设置 256byte 段式压缩
			HI_MPI_VPSS_EnableChn			//打开chn
		SAMPLE_COMM_VENC_Start(step5)			//启动venc流模式(h264, mjpeg)  
			SAMPLE_COMM_SYS_GetPicSize		//获取Sensor图像的大小---》1280x720
			HI_MPI_VENC_CreateChn			//创建VENC chn---》编码通道的宽度是720、高度是1280,要编码的图片的宽度是720、高度是1280,流缓冲区的大小是1280x720,编码出的视频流的图像质量是高清还是啥啥,获取流的模式是切片模式,不支持B帧,设置码率控制模式:CBR、FIXQF、VBR,以及码率控制相关的参数;
			HI_MPI_VENC_StartRecvPic			//开始接收图片
		SAMPLE_COMM_VENC_BindVpss			//VENC的Dev绑定VPSS的chn
			HI_MPI_SYS_Bind				//VENC的Dev绑定VPSS的chn
		SAMPLE_COMM_VENC_StartGetStream(step6)		//获取流,然后将其保存到文件。 
			SAMPLE_COMM_VENC_GetVencStreamProc	//线程函数
				HI_MPI_VENC_GetChnAttr		//获取编码通道的编码属性。
				SAMPLE_COMM_VENC_GetFilePostfix	//获取文件名后缀--->.h.264
				HI_MPI_VENC_GetFd		//mpp内部把VENC编码好的视频流数据做成文件,然后把文件描述符通过这个API获取
				HI_MPI_VENC_Query		//查询编码通道状态---》判断当前这帧图像的码流包个数是否为0,为0则退出程序
				HI_MPI_VENC_GetStream		//获取编码码流。
				SAMPLE_COMM_VENC_SaveStream	//将帧保存到文件
					SAMPLE_COMM_VENC_SaveH264
						fwrite
				HI_MPI_VENC_ReleaseStream		//释放码流缓存。
		SAMPLE_COMM_VENC_StopGetStream(step7)		//退出程序

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

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

相关文章

python基于DeeplabV3Plus开发构建裂缝分割识别系统,并实现裂缝宽度计算测量

在我之前的文章中已经有不少基于裂缝场景的数据开发构建的模型了,感兴趣的话可以自行移步阅读,如下: 《基于yolov5sbifpn实践隧道裂缝裂痕检测》 《基于YOLOV7的桥梁基建裂缝检测》 《水泥路面、桥梁基建、隧道裂痕裂缝检测数据集》 《基…

SpringBoot异步执行方法

1. 源码跟踪 1.简单描述 在SpringBoot2.0.9之前需要手动自定义线程池(如下2.1), 然后指定线程池的名称 SpringBoot2.0.9以及之前的版本,使用的线程池默认是SimpleAsyncTaskExcutor, , 之后的版本使用的是ThreadpoolTaskExecutor 并且不需要手动的创建当前线程池(但往往我们…

多线程基础(五)ThreadLocal与四种引用

一、ThreadLocal ThreadLocal:解决每个线程绑定自己的值,存放线程的私有数据。 public class ThreadLocalTest {public static ThreadLocal local new ThreadLocal();public static void main(String[] args) {if(local.get() null){local.set("…

加成序列 dfs 迭代加深 java

🍑 加成序列 满足如下条件的序列 X X X(序列中元素被标号为 1 、 2 、 3 … m 1、2、3…m 1、2、3…m)被称为“加成序列”: KaTeX parse error: Undefined control sequence: \[ at position 2: X\̲[̲1\]1KaTeX parse error…

一文读懂MVCC:数据库中的并发读写利器!

大家好,我是你们的小米,一个积极活泼、喜好分享技术的小伙伴。今天,我想和大家聊一聊数据库领域的一个重要话题——MVCC多版本并发控制。MVCC是MySQL和其他一些数据库系统中常用的并发控制技术,通过它,我们可以在高并发…

如何用 Python 实现所有算法?

学会了 Python 基础知识,想进阶一下,那就来点算法吧!毕竟编程语言只是工具,结构算法才是灵魂。 新手如何入门 Python 算法? 几位印度小哥在 GitHub 上建了一个各种 Python 算法的新手入门大全。从原理到代码&#xff0…

milkV-duo的Linux的开发环境搭建

目录 写在前面 内核编译 烧录失败的示例(这种情况下就和插上空卡一样) 进入系统 串口进入 SSH接入 写在前面 基本上大部分的问题都能在开源社区上得到答案,记录下我遇到的问题. 附上开源社区 MilkV Community 这里的引脚图和板子的丝印有点对不上&#xff…

竞赛中常用的Python 标准库

对竞赛中常用得标准库进行解析和给出代码模板 目录 1.functools 1.1 cmp_to_key 1.2 lru_cache(记忆化存储,加快递归速度) 2.collections 2.1 deque 2.1.1 单调对列实现 2.1.2 BFS广搜 3.sys 3.1 sys.maxsize 3.2 sys.exit() 3.…

使用python的plot绘制loss、acc曲线,并存储成图片

使用 python的plot 绘制网络训练过程中的的 loss 曲线以及准确率变化曲线,这里的主要思想就时先把想要的损失值以及准确率值保存下来,保存到 .txt 文件中,待网络训练结束,我们再拿这存储的数据绘制各种曲线。 其大致步骤为&#x…

代码自动生成工具——TableGo(实例演示)

一、常用的代码生成器工具介绍 在SpringBoot项目开发中,为了提高开发效率,我们经常需要使用代码自动生成工具来生成一些重复性的代码,比如实体类、DAO、Service、Controller等等。下面介绍几个常用的代码自动生成工具: ①、MyBat…

如何在Linux 启用组播

第一章: 前言 多播技术,也被称为“组播”,是一种网络通信机制,它允许一个节点(发送者)向一组特定的节点(接收者)发送信息。这种方式在网络编程中非常有用,因为它可以大大提高效率和…

深度学习(Pytorch):Softmax回归

Softmax简介 Softmax回归是一个用于多类分类问题的线性模型,它是从Logistic回归模型演变而来的。Softmax回归与Logistic回归类似,但是输出不再是二元的,而是多类的。Softmax回归引入了softmax激活函数来将输出转换为合理的概率分布。与线性回…

HCIE-Cloud Computing LAB备考--第五题:规划--Type13练习--记忆技巧+默写

对LLD表,交换机接口表,ensp配置进行练习,如下图,设置答案和空白表,进行默写,汇总自己的容易犯的错误 LLD表默写思路 交换机接口配置表默写思路 以Type3为例,同颜色复制即可,共用ST.P0是A25,ST.P2是A21,FS是ST.P0是A21,ST.P2是A21。 ensp配置默写思路 特点: 所…

一步一步学习 Stable Diffusion

一步一步学习 Stable Diffusion 0. 背景1. 安装2. 汉化3. 安装 sd-webui-controlnet 插件4. 安装 sd-webui-segment-anything 插件5. 安装 ultimate-upscale 插件6. 安装 SadTalker 插件7. 下载和配置 VAE 模型8. 使用 ChilloutMix 模型99. 未完待续 0. 背景 网上看了很多 Sta…

priority_queue(优先级队列)

priority_queue 1. priority_queue的介绍及使用1.1 priority_queue的介绍1.2 priority_queue的使用1.2.1 constructor(构造)1.2.2 empty1.2.3 size1.2.4 top1.2.5 emplace1.2.6 push、pop、swap 1.3 数组中第K个大的元素 2.priority_queue的深度剖析及模拟实现 1. priority_que…

Makerbase SimpleFOC ESP32例程4 双电机闭环速度测试

Makerbase SimpleFOC ESP32例程4 双电机闭环速度测试 第一部分 硬件介绍 1.1 硬件清单 序号品名数量1ESP32 FOC V1.0 主板12YT2804电机2312V电源适配器14USB 线156pin杜邦线2 注意:YT2804是改装的云台无刷电机,带有AS5600编码器,可实现360连续运转。…

柔性作业车间调度

1柔性车间作业调度 个工件 要在 台机器 上加工。每个工件包含一道或多道工序,工序顺序是预先确定的,每道工序可以在多台不同加工机器上进行加工,工序的加工时间随加工机器的不同而不同。调度目标是为每道工序选择最合适的机器、确定每台机器…

【C语言】语言篇——数组和字符串

C站的小伙伴们,大家好呀😝😝!我最近在阅读学习刘汝佳老师的《算法竞赛入门经典》,今天将整理本书的第三章——数组和字符串的一些习题,本章习题较多,下选取部分习题进行练习总结,在这…

200道面试题(附答案)

最近有不少小伙伴跑来咨询: 想找网络安全工作,应该要怎么进行技术面试准备?工作不到 2 年,想跳槽看下机会,有没有相关的面试题呢? 为了更好地帮助大家高薪就业,今天就给大家分享两份网络安全工…

ubuntu20.04 ffmpeg mp4转AES加密的m3u8分片视频

样本视频(时长2分35秒): 大雄兔_百度百科 大雄兔_百度百科不知大家否看过世界上第一部开源电影:Elephants Dream(大象之梦)。这是一部由主要由开源软件Blender制作的电影短片,证明了用开源软件也能制作出效果媲美大公司的作品。…