如何快速实现Android平台前端设备接入能力

技术背景

SIP(会话初始化协议)是在 IP网络上进行多媒体通信的应用层控制协议,以几种RFC的形式提供,其中最重要的是包含核心协议规范的RFC3261。该协议用于创建,修改和终止与一个或多个参与者的会话。通过会话,我们了解了一组进行通信的发送方和接收方,以及在通信过程中这些发送方和接收方保持的状态。会话的示例可以包括Internet电话呼叫,多媒体分发,多媒体会议,分布式计算机游戏等。

SIP不是通信设备将需要的唯一协议,也不意味着是通用协议。SIP的目的仅仅是使通信成为可能,通信本身必须通过其他方式(可能还有其他协议)来实现。

与SIP一起最常使用的两种协议是RTP和SDP。 RTP协议用于承载实时多媒体数据(包括音频,视频和文本),该协议可以将数据编码和拆分为数据包,并通过Internet传输此类数据包。

另一个重要的协议是SDP,用于描述和编码会话参与者的功能。 然后,将这种描述用于协商会话的特征,以便所有设备都可以参与(例如,包括协商用于编码媒体的编解码器,以便所有参与者都可以对其进行解码,协商使用的传输协议 等等)。

GB/T28181-2011 《安全防范视频监控联网系统信息传输、交换、控制技术要求》是由公安部科技信息化局提出,由全国安全防范报警系统标准化技术委员会(SAC/TC100)归口,公安部一所等多家单位共同起草的一部国家标准。

该标准规定了城市监控报警联网系统中信息传输、交换、控制的互联结构、通信协议结构,传输、交换、控制的基本要求和安全性要求,以及控制、传输流程和协议接口等技术要求。该标准适用于安全防范监控报警联网系统的方案设计、系统检测、验收以及与之相关的设备研发、生产,其他信息系统可参考采用。
该标准于2012年6月1日正式发布实施,在全国范围内的平安城市项目建设中被普遍推广应用。GB/T28181-2011标准自发布以来,受到了各大视频监控厂商的积极响应。截止2012年底,有近百家视频监控企业通过公安部一所、公安部三所的认证,如深圳宙视达、浙江宇视、超视科技、东方网力、海康威视、高远时代、浙江大华、先进视讯、波粒科技、华为技术、中兴力维、中星电子、科达、天地伟业等。

相关接口

废话不多说,直接上设计接口,好多开发者网上看到的大多是非常简单的接口。极致简单,一直是我们追求的目标,但是更好的参数化配置和可扩展的设计,也是一个规范化产品的必经之路。

除了常规的音视频采集编码接口外,GB28181设备接入模块,主要分信令交互和媒体数据传输两个部分,以大牛直播SDK(官方)分别介绍下相关接口设计。

媒体数据传输相关

	/*+++++++++++++++RTP Sender相关接口+++++++++++++++*//** 创建RTP Sender实例** @param reserve:保留参数传0** @return RTP Sender 句柄,0表示失败*/public native long CreateRTPSender(int reserve);/***设置 RTP Sender传输协议** @param rtp_sender_handle, CreateRTPSender返回值* @param transport_protocol, 0:UDP, 1:TCP, 默认是UDP** @return {0} if successful*/public native int SetRTPSenderTransportProtocol(long rtp_sender_handle, int transport_protocol);/***设置 RTP Sender IP地址类型** @param rtp_sender_handle, CreateRTPSender返回值* @param ip_address_type, 0:IPV4, 1:IPV6, 默认是IPV4, 当前仅支持IPV4** @return {0} if successful*/public native int SetRTPSenderIPAddressType(long rtp_sender_handle, int ip_address_type);/***设置 RTP Sender RTP Socket本地端口** @param rtp_sender_handle, CreateRTPSender返回值* @param port, 必须是偶数,设置0的话SDK会自动分配, 默认值是0** @return {0} if successful*/public native int SetRTPSenderLocalPort(long rtp_sender_handle, int port);/***设置 RTP Sender SSRC** @param rtp_sender_handle, CreateRTPSender返回值* @param ssrc, 如果设置的话,这个字符串要能转换成uint32类型, 否则设置失败** @return {0} if successful*/public native int SetRTPSenderSSRC(long rtp_sender_handle, String ssrc);/***设置 RTP Sender RTP socket 发送Buffer大小** @param rtp_sender_handle, CreateRTPSender返回值* @param buffer_size, 必须大于0, 默认是512*1024, 当前仅对UDP socket有效, 根据视频码率考虑设置合适的值** @return {0} if successful*/public native int SetRTPSenderSocketSendBuffer(long rtp_sender_handle, int buffer_size);/***设置 RTP Sender RTP时间戳时钟频率** @param rtp_sender_handle, CreateRTPSender返回值* @param clock_rate, 必须大于0, 对于GB28181 PS规定是90kHz, 也就是90000** @return {0} if successful*/public native int SetRTPSenderClockRate(long rtp_sender_handle, int clock_rate);/***设置 RTP Sender 目的IP地址, 注意当前用在GB2818推送上,只设置一个地址,将来扩展如果用在其他地方,可能要设置多个目的地址,到时候接口可能会调整** @param rtp_sender_handle, CreateRTPSender返回值* @param address, IP地址* @param port, 端口** @return {0} if successful*/public native int SetRTPSenderDestination(long rtp_sender_handle, String address, int port);/***初始化RTP Sender, 初始化之前先调用上面的接口配置相关参数** @param rtp_sender_handle, CreateRTPSender返回值** @return {0} if successful*/public native int InitRTPSender(long rtp_sender_handle);/***获取RTP Sender RTP Socket本地端口** @param rtp_sender_handle, CreateRTPSender返回值** @return 失败返回0, 成功的话返回响应的端口, 请在InitRTPSender返回成功之后调用*/public native int GetRTPSenderLocalPort(long rtp_sender_handle);/*** UnInit RTP Sender** @param rtp_sender_handle, CreateRTPSender返回值** @return {0} if successful*/public native int UnInitRTPSender(long rtp_sender_handle);/*** 释放RTP Sender, 释放之后rtp_sender_handle就无效了,请不要再使用** @param rtp_sender_handle, CreateRTPSender返回值** @return {0} if successful*/public native int DestoryRTPSender(long rtp_sender_handle);

 信令相关操作

	/*+++++++++++++++GB28181相关接口+++++++++++++++*//*** 设置GB28181 RTP Sender** @param rtp_sender_handle, CreateRTPSender返回值* @param rtp_payload_type, 对于GB28181 PS, 协议定义是96, 具体以SDP为准** @return {0} if successful*/public native int SetGB28181RTPSender(long handle, long rtp_sender_handle, int rtp_payload_type);/*** 启动 GB28181 媒体流** @return {0} if successful*/public native int StartGB28181MediaStream(long handle);/*** 停止 GB28181 媒体流** @return {0} if successful*/public native int StopGB28181MediaStream(long handle);/*---------------GB28181相关接口---------------*/

 启动、停止GB28181

完成视频分辨率等参数配置后,点击“启动GB28181”,即可开始走信令交互流程,设备端主动发送Register,进入后续交互流程。

如需停止GB28181,点停止即可。

GB28181设备端主要实现了按需推送数据到平台端。

    class ButtonGB28181AgentListener implements OnClickListener {public void onClick(View v) {stopGB28181Stream();destoryRTPSender();if (null == gb28181_agent_ ) {if( !initGB28181Agent() )return;}if (gb28181_agent_.isRunning()) {gb28181_agent_.terminateAllPlays(true);// 目前测试下来,发送BYE之后,有些服务器会立即发送INVITE,是否发送BYE根据实际情况看gb28181_agent_.stop();btnGB28181Agent.setText("启动GB28181");}else {if ( gb28181_agent_.start() ) {btnGB28181Agent.setText("停止GB28181");}}}}

注册

当Andriod设备端第一次接入平台端时,设备端将持续向平台端发送 REGISTER消息,直到 Server端回复"200 OK"代表注册成功。

如果设备或系统注册不成功,宜延迟一定的随机时间后重新注册每隔一定时间客户端都会再次向服务器刷新注册,防止注册过期导致连接断开。

以基本注册为例:基本注册采用IETFRFC3261规定的基于数字摘要的挑战应答式安全技术进行注册。

注册流程描述如下:
a) 1:SIP代理向SIP服务器发送 Register请求;
b) 2:SIP服务器向 SIP代理发送响应401,并在响应的消息头 WWW_Authenticate字段中给出适合SIP代理的认证体制和参数;
c) 3:SIP代理重新向SIP服务器发送 Register请求,在请求的 Authorization字段给出信任书, 包含认证信息;
d) 4:SIP 服务器对请求进行验证,如果检查出 SIP 代理身份合法,SIP 代理发送成功响应 200OK,如果身份不合法则发送拒绝服务应答
相关注册反馈:
    @Overridepublic void ntsRegisterOK(String dateString) {Log.i(TAG, "ntsRegisterOK Date: " + (dateString!= null? dateString : ""));}@Overridepublic void ntsRegisterTimeout() {Log.e(TAG, "ntsRegisterTimeout");}@Overridepublic void ntsRegisterTransportError(String errorInfo) {Log.e(TAG, "ntsRegisterTransportError error:" + (errorInfo != null?errorInfo :""));}

信息查询(Catalog)

注册成功后,客户端与服务器之间信息查询操作,如目录查询、历史录像文件查看等,GB28181使用 SIP扩展协议规定的 Message方法实现。目前使用了两种类型的查询命令:Catalog 设备目录查询消息、RecordInfo 历史录像文件查询消息。
本文以Catalog设备目录查询消息为例:平台端向设备端发送Catalog请求,设备端回复200 OK后,发送设备信息,平台端回复200 OK,如遇多个设备信息,切记分次发送。
    private boolean initGB28181Agent(){if ( gb28181_agent_ != null )return  true;String local_ip_addr = IPAddrUtils.getIpAddress(myContext);Log.i(TAG, "initGB28181Agent local ip addr: " + local_ip_addr);if ( local_ip_addr == null || local_ip_addr.isEmpty() ) {Log.e(TAG, "initGB28181Agent local ip is empty");return  false;}gb28181_agent_ = GBSIPAgentFactory.getInstance().create();if ( gb28181_agent_ == null ) {Log.e(TAG, "initGB28181Agent create agent failed");return false;}gb28181_agent_.addListener(this);// 必填信息gb28181_agent_.setLocalAddressInfo(local_ip_addr, gb28181_sip_local_port_);gb28181_agent_.setServerParameter(gb28181_sip_server_addr_, gb28181_sip_server_port_, gb28181_sip_server_id_, gb28181_sip_server_domain_);gb28181_agent_.setUserInfo(gb28181_sip_username_, gb28181_sip_password_);// 可选参数gb28181_agent_.setUserAgent(gb28181_sip_user_agent_filed_);gb28181_agent_.setTransportProtocol(gb28181_sip_trans_protocol_==0?"UDP":"TCP");// GB28181配置gb28181_agent_.config(gb28181_reg_expired_, gb28181_heartbeat_interval_, gb28181_heartbeat_count_);com.gb28181.ntsignalling.Device gb_device = new com.gb28181.ntsignalling.Device("34020000001380000001", "安卓测试设备", Build.MANUFACTURER, Build.MODEL,"宇宙","火星1","火星", true);getLocation(this);gb_device.setLongitude(mLongitude);gb_device.setLatitude(mLatitude);gb28181_agent_.addDevice(gb_device);if (!gb28181_agent_.initialize()) {gb28181_agent_ = null;Log.e(TAG, "initGB28181Agent gb28181_agent_.initialize failed.");return  false;}return true;}

心跳(KeepAlive)

KeepAlive以MESSAGE的形式传递,异常处理如下:
    @Overridepublic void ntsOnHeartBeatException(int exceptionCount,  String lastExceptionInfo) {Log.e(TAG, "ntsOnHeartBeatException heart beat timeout count reached, count:" + exceptionCount+", exception info:" + (lastExceptionInfo!=null?lastExceptionInfo:""));// 10毫秒后,停止信令, 然后重启handler.postDelayed(new Runnable() {@Overridepublic void run() {Log.i(TAG, "gb28281_heart_beart_timeout");stopGB28181Stream();destoryRTPSender();if (gb28181_agent_ != null) {Log.i(TAG, "gb28281_heart_beart_timeout sip stop");gb28181_agent_.stop();Log.i(TAG, "gb28281_heart_beart_timeout sip start");gb28181_agent_.start();}}},10);}

Invite处理

假定整个信令交互流程顺利,Android设备端完成Register、Catalog、KeepAlive消息处理后,平台端发过来Invite请求并携带SDP消息体。

Android设备端可获取到比如deviceid, tcp/udp传输模式、rtp端口,address类型等,并构建200 OK,携带相关的音视频信息。

    @Overridepublic void ntsOnInvitePlay(String deviceId, InvitePlaySessionDescription session_des) {handler.postDelayed(new Runnable() {@Overridepublic void run() {Log.i(TAG,"ntsInviteReceived, device_id:" +device_id_+", is_tcp:" + session_des_.isRTPOverTCP()+ " rtp_port:" + session_des_.getMediaPort() + " ssrc:" + session_des_.getSSRC()+ " address_type:" + session_des_.getAddressType() + " address:" + session_des_.getAddress());// 可以先给信令服务器发送临时振铃响应//sip_stack_android.respondPlayInvite(180, device_id_);long rtp_sender_handle = libPublisher.CreateRTPSender(0);if ( rtp_sender_handle == 0 ) {gb28181_agent_.respondPlayInvite(488, device_id_);Log.i(TAG, "ntsInviteReceived CreateRTPSender failed, response 488, device_id:" + device_id_);return;}gb28181_rtp_payload_type_ = session_des_.getPSRtpMapAttribute().getPayloadType();libPublisher.SetRTPSenderTransportProtocol(rtp_sender_handle, session_des_.isRTPOverUDP()?0:1);libPublisher.SetRTPSenderIPAddressType(rtp_sender_handle, session_des_.isIPv4()?0:1);libPublisher.SetRTPSenderLocalPort(rtp_sender_handle, 0);libPublisher.SetRTPSenderSSRC(rtp_sender_handle, session_des_.getSSRC());libPublisher.SetRTPSenderSocketSendBuffer(rtp_sender_handle, 2*1024*1024); // 设置到2MlibPublisher.SetRTPSenderClockRate(rtp_sender_handle, session_des_.getPSRtpMapAttribute().getClockRate());libPublisher.SetRTPSenderDestination(rtp_sender_handle, session_des_.getAddress(), session_des_.getMediaPort());if ( libPublisher.InitRTPSender(rtp_sender_handle) != 0 ) {gb28181_agent_.respondPlayInvite(488, device_id_);libPublisher.DestoryRTPSender(rtp_sender_handle);return;}int local_port = libPublisher.GetRTPSenderLocalPort(rtp_sender_handle);if (local_port == 0) {gb28181_agent_.respondPlayInvite(488, device_id_);libPublisher.DestoryRTPSender(rtp_sender_handle);return;}Log.i(TAG,"get local_port:" + local_port);String local_ip_addr = IPAddrUtils.getIpAddress(myContext);gb28181_agent_.respondPlayInviteOK(device_id_,local_ip_addr, local_port);gb28181_rtp_sender_handle_ = rtp_sender_handle;}private String device_id_;private InvitePlaySessionDescription session_des_;public Runnable set(String device_id, InvitePlaySessionDescription session_des) {this.device_id_ = device_id;this.session_des_ = session_des;return this;}}.set(deviceId, session_des),0);}

Ack确认

平台端发送Ack确认,设备端收到Ack后,开始发送音视频数据。

    @Overridepublic void ntsOnAckPlay(String deviceId) {handler.postDelayed(new Runnable() {@Overridepublic void run() {Log.i(TAG,"ntsOnACKPlay, device_id:" +device_id_);if (!isRecording && !isRTSPPublisherRunning && !isPushingRtsp && !isPushingRtmp) {InitAndSetConfig();}libPublisher.SetGB28181RTPSender(publisherHandle, gb28181_rtp_sender_handle_, gb28181_rtp_payload_type_);int startRet = libPublisher.StartGB28181MediaStream(publisherHandle);if (startRet != 0) {if (!isRecording && !isRTSPPublisherRunning && !isPushingRtmp && !isPushingRtsp) {if (publisherHandle != 0) {libPublisher.SmartPublisherClose(publisherHandle);publisherHandle = 0;}}destoryRTPSender();Log.e(TAG, "Failed to start GB28181 service..");return;}if (!isRecording && !isRTSPPublisherRunning && !isPushingRtsp && !isPushingRtmp) {if (pushType == 0 || pushType == 1) {CheckInitAudioRecorder();    //enable pure video publisher..}}isGB28181StreamRunning = true;}private String device_id_;public Runnable set(String device_id) {this.device_id_ = device_id;return this;}}.set(deviceId),0);}

BYE

如果客户端需要断开Invite会话,则会发送BYE,客户端返回200 OK。

    @Overridepublic void ntsOnByePlay(String deviceId){handler.postDelayed(new Runnable() {@Overridepublic void run() {Log.i(TAG, "ntsOnByePlay, stop GB28181 media stream, deviceId=" + device_id_);stopGB28181Stream();destoryRTPSender();}private String device_id_;public Runnable set(String device_id) {this.device_id_ = device_id;return this;}}.set(deviceId),0);}

注销

客户端向服务器发送 Register命令消息,消息中的 Expire字段设置为0即是注销。
 

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

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

相关文章

长安渝北工厂机器人_长安工厂探秘!解密CS75 PLUS究竟是怎样造出来的

长安CS75 PLUS自打上市以来,销量真的是有目共睹,仅仅一个半月就有3万多的订单,这辆车真的很火很爆款。但我不仅要提出一些疑问了,CS75 PLUS卖这么好,制造工艺怎么样呢?它又是怎么造出来的呢?带着…

threadlocal存连接对象的目的_终于懂了ThreadLocal,不再害怕面试官问了

ThreadLocal解析synchronized和ThreadLocal的区别:synchronized:以时间换空间,只提供一份变量,让不同的线程排队访问,失去了并发性,降低了程序效率,着重对各线程之间访问资源的同步性ThreadLocal:以空间换时…

主板后置音频接口图解_颜值出众、用料靠谱——华擎(ASRock)Z490 Extreme4极限玩家主板 简析...

一、前言你们能想象嘛,那种主板已经到了,处理器却没抢到的感觉。刚开始看到Plus会员提前抢的时候,我心里面还有一些放心,但当时间刚过秒变无货的时候,一切又已回到当初,难受!居然没有首发抢到10…

中查出所有姓张的学生为啥查不出来_只有笔试成绩没有面试成绩是什么原因 教师资格面试成绩怎么查...

[闽南网]对于很多同学来说,今晚是个不眠夜。就在几个小时前,教师资格证面试成绩查询入口开通了,相比之前发布的消息,成绩公布提前了很多。参加了这次教师资格证考试的同学,一得到消息就忙着查成绩,毕竟面试…

c++用模板实现稀疏多项式_用线性表实现一元多项式及相加运算

“ 本文主要讨论线性表在多项式计算中的应用,讨论内容涉及到一元n次多项式在计算机中的表示,及多项式相加运算。”01在数学上,一个一元n次多项式可以按照升幂写成Pn(x) p0 p1x p2x2 …… pnxn它由n1个系数唯一确定。因此,一个…

cdh mysql sqoop 驱动_大数据技术之Sqoop学习——原理、安装、使用案例、常用命令...

第1章 Sqoop 简介Sqoop 是一款开源的工具,主要用于在 Hadoop(Hive) 与传统的数据库 (mysql,postgresql,...) 间进行数据的高校传递,可以将一个关系型数据库(例如:MySQL,Oracle,Postgres等)中的数据导入到 Hadoop 的 HDFS 中,也可以…

邮票的孔怎么做出来的_金银花茶是怎么做出来的呢

花期爱亦长,变换自然妆。蝶恋金银露,风柔满院香。说起金银花,可能大家都不陌生,它无论是作为观赏性盆景还是作为金银花养生茶都是非常适宜的。金银花被称为夏天第一花,夏天喝不仅能清热解暑,还能去除许多小…

github上成员贡献量_真祖传代码!你的GitHub代码已打包运往北极,传给1000年后人类...

公众号关注 “ML_NLP”设为 “星标”,重磅干货,第一时间送达!晓查 发自 凹非寺 量子位 报道 | 公众号 QbitAI程序员们,激动的消息来了!GitHub刚刚公布了一组照片,你的代码上周已经被打包运往北极保存。只要…

握手失败_主人用吃的训练小柴犬握手,老柯基看到后的表现出了吃货的本能!...

贪吃和贪玩是狗狗的天性,也是作为宠物狗它应该做的事情,没有哪一条狗是不贪吃的,如果有,那么肯定是条假狗!养狗的人肯定都知道,只要在家你发出一丁点儿口袋的声音,你家狗子当时不管在干什么&…

indesign照片放入太大_猪肚鸡做法复杂,量太大,那来个简易版,用上大厨教的妙招更香了...

【猪肚鸡做法复杂,量太大,那来个简易版,用上大厨教的妙招更香了】天气越来越冷了,今天准备炖鸡汤,正好老妈给了小半个已经处理好的猪肚,所以决定炖个简易版胡椒猪肚鸡。说实话外面的胡椒猪肚鸡做法是比较复…

天气预测频繁2项集_986天气| 今年冬天比往年更冷?官方回应来了

4日下午,中国气象局召开新闻发布会,国家气候中心副主任贾小龙介绍,根据会商意见,我国今冬总体冷空气比较频繁,势力偏强,北方可能出现大范围低温雨雪天气过程。1隆冬季节北方或现大范围低温雨雪天气贾小龙表…

anaconda中安装xgboost_Anaconda是什么?Anconda下载安装教程 - python基础入门(16)

文章首发微信公众号,微信搜索:猿说python一.如果从事Python开发,配置环境需要安装两个包:第一个安装开发工具,俗称IDE : 推荐使用 Pycharm第二个安装开发工具包: Anacondaps:Windows 下 Pycharm下载/Anaconda安装详细步…

matlab非同秩矩阵相乘_线性代数精华——讲透矩阵的初等变换与矩阵的秩

这篇文章和大家聊聊矩阵的初等变换和矩阵的秩。矩阵的初等变换这个概念可能在很多人听来有些陌生,但其实我们早在初中的解多元方程组的时候就用过它。只不过在课本当中,这种方法叫做消元法。我们先来看一个课本里的例子:假设我们要解这个方程…

手持巡检仪_专业的三防产品设计-电力巡检仪设计

我个人认为所有科技的发展都是建立在人们的需求而产生的。让人们更加方便快捷舒适。在电力巡检的问题上,为了减少值班员抄表和记录因此设计出这款电力巡检仪设计。用于记录设备的运行、检修、备用状态,可查询当天的漏检项目情况,确保点检内容无遗漏&…

thinkphp v5.0.11漏洞_ThinkPHP5丨远程代码执行漏洞动态分析

ThinkPHP是为了简化企业级应用开发和敏捷WEB应用开发而诞生的,在保持出色的性能和至简代码的同时,也注重易用性。但是简洁易操作也会出现漏洞,之前ThinkPHP官方修复了一个严重的远程代码执行漏洞。这个漏洞的主要原因是由于框架对控制器名没有…

本地提交spark_Spark 数据本地化级别

​​RDD 源码大家可以看到源码中的第五条注释说明,翻译过来的大概意思是提供一系列的最佳计算位置。我之前一直不太清楚 spark 是如何内部实现的,今天就带领大家来看一看 spark 的本地数据化级别在任务执行中的演变过程。1 数据的本地化级别有哪些&#…

街舞中的rolling机器人_首家!爆点!奈雪の茶、蛙小侠..开业倒计时!街舞PK…这个六一就差你来围观了...

说起济南的各大shopping mall世茂广场绝对是最得人心的总能迅速集结当下最火爆的品牌各种线上线下活动也是搞得新颖又有趣五一的“刘看山”还没结束呢这就马不停蹄的要上新活动了前方预警⚠奈雪の茶等一大波新店又要入驻啦 还有 “奔跑吧爸爸”亲子活动、街舞大赛 ……统统都在…

简述isodata算法的原理_基于UWB技术的室内定位方法简述

1. UWB室内定位概述:UWB室内定位技术与传统通信技术有极大的差异,它不需要使用传统通信体制中的载波,而是通过发送和接收具有纳秒或纳秒级以下的极窄脉冲来传输数据,从而具有GHz量级的带宽。超宽带室内定位可用于各个领域的室内精…

slider获取点击 unity_Unity基础 | 70分钟带你轻松入门

Hello . 大家好今天给大家分享Unity3D的基础入门我是麦田这次录制的教程是面向零基础,想上手Unity的同学。所以就做了这一次大串讲。(只此一回,别无分号了。)时长1小时10分钟,我的建议是一口气看完。(因为我也是一口气讲完的)大家可以点击文末…

达梦数据库导入oracle数据_达梦数据库助力加速石油石化行业数字化转型升级

2020中国石油石化企业信息技术交流大会暨数字化转型、智能化发展高峰论坛于10月22日-23日在北京召开,武汉达梦数据库有限公司(简称达梦公司)作为国产数据库代表企业受邀参与此次活动,并以“国产数据库能源行业解决方案”为主题报告,为来宾介绍…