大疆行业无人机接入音视频平台协议详解
前言
从事大疆行业应用开发有一段时间了,看到很多厂商在做视频回传的时候,都要装个自己的APP,界面很丑不说,还经常卡死,但是大疆其实已经在视频流中携带了很多信息,很多人都不知道,现在把自己的直播开发经验分享出来
文章目录
- 前言
- 一、安防视频平台介绍
- 二、DJI Pilot机型匹配表及回传流程
- 1. 视频流选择
- 2. 视频回传的码流格式
- 3. GB28181业务流程
- 4. 传输和控制要求(基于 GB/T 28181)
- 5. 功能列表
- 三、DJI Pilot H264 SEI帧 Metadata协议解析
- 1. Metadata 数据列表
- 2. DJI Metadata protobuf解析文件
- 3. Metadata 解析指导
- 四、DJI GB28181 协议信令详解
- 总结
一、安防视频平台介绍
二、DJI Pilot机型匹配表及回传流程
APP 版本 | DJI Pilot V1.9 及以上版本 | DJI Pilot PE V1.6.1 |
---|---|---|
适配机型 |
经纬 M300 RTK 经纬 M200 V2 系列 御 Mavic 2 行业变焦版 御 Mavic 2 行业双光版 精灵 Phantom 4 RTK(SDK 遥控器版本) |
经纬 M200 V1 系列 经纬 M600 系列 悟 Inspire 2 御 Mavic Pro 精灵 Phantom 4 精灵 Phantom 4 Pro( 除精灵 4 Pro+) 精灵 Phantom 4 Advanced(除精灵 4 Advanced+) |
Pilot APP 下载:https://www.dji.com/cn/downloads/djiapp/dji-pilot
Pilot PE V1.6.1 下载:https://service-adhoc.dji.com/download/app/android/321b585b-e217-4c95-9192-09eee6e02630
1. 视频流选择
M300RTK 最多可以挂载 3 个相机负载,可以通过遥控器上的 APP 从三路相机视频流
中选择某一路视频流进行回传到服务端。
- FPV 视频流:无人机前置摄像头第一视角视频流。
- 1 号/2 号/3 号负载相机视频流:无人机上的 3 个云台口,可以任意挂载大疆的官方负载 H20T/ H20/ Z30/ XTS 相机,以及三方合作伙伴的相机。
- H20T/H20 相机负载:多光组合相机,具备 1200 万像素广角、2000 万像素 23 倍光学变焦、1200 米激光测距、红外(H20T 有)。
- Z30 相机负载:30 倍光学变焦相机。
- XTS 相机负载:红外相机。
2. 视频回传的码流格式
- 编码格式:H264。
- 质量调节:流畅 540P 30FPS 512Kbps, 均衡 720P 30FPS 1Mbps, 高清 720P 30FPS 1.5 Mbps。
- 传输格式:根据 GB/T28181-2016 传输要求,采用基于 RTP 的视频数据 PS 封装。
3. GB28181业务流程
4. 传输和控制要求(基于 GB/T 28181)
- SIP 信令通信采用 UDP 协议,端口自定义,默认 5060。
- RTP 数据通信采用 UDP 协议,多路流分别采用不同的端口分别传输,点播时通过SDP 协商,端口自定义。
- RTCP 传输控制协议可选,默认 RTP 端口号加 1,需要收发双方同时支持才可,目前仅适用于网络质量反馈,暂不支持丢包重传机制。
- 无人机视频编码格式为 H264,封装成 PS 流,再用 RTP 打包传输;不支持音频。
- 接入网络应为 WiFi/有线/4G/VPDN 的一种,并在现场为遥控器提供 WiFi 热点。
- 遥控器到服务器端的网络带宽应满足以下标准:流畅 512Kbps,均衡 1Mbps,高清1.5Mbps。
- 接收端应具备 jitterbuffer 接收缓冲,以消除网络抖动和乱序造成的视频卡顿和花屏 ,建议缓冲不要超过 1 秒。
5. 功能列表
功能点 | 功能描述 | 协议接口 | 备注 |
---|---|---|---|
设备注册注销 | 采用基于账号口令认证的设备登录与注销;采用定时心跳保活机制,在心跳超时离线后,自动重登录。 | ||
设备信息查询 | 支持远程查询无人机名称,ID,无人机型号,生产厂商,固件版本等信息 | ||
设备状态查询 | 支持远程查询无人机工作状态,视频流状态,录像状态,UTC时间等。 | ||
设备列表查询 | 支持远程查询摄像头列表,即具备多通道视频传输的能力。 | ||
实时视频点播与停止 | 设备上线后,采用点播即传的策略,按需上传,节省通信带宽和流量。 | ||
设备控制强制发送关键帧 | 当视频流丢帧或切换分辨率时,可通过设备控制信令,强制无人机立即编码发送一个 H264 关键帧,减少播放等待时间。 |
三、DJI Pilot H264 SEI帧 Metadata协议解析
目前无人机直播所用的 RTMP 协议只支持标准 RTMP 视频流及其内置的媒体控制命令,没有其他定制化
功能。
- 编码格式:H.264,有 SEI 帧(SEI 帧主要是用于存放 Metadta 信息)
- 传输格式:采用 RTMP 的 chunk 方式进行传输
- 码流质量调节:
- 不支持服务器进行质量设置调节。
- 支持 APP 手动设置,参数如下:
- 流畅 540P 30FPS 512Kbps
- 均衡 720P 30FPS 1Mbps
- 高清 720P 30FPS 1.5Mbps
- 默认端口:默认使用 1935 端口,若服务器指定其他端口的话,需要先 PING 测试。
- Metadata 数据项:
- 飞机经纬高
- 遥控器经纬高
- 目标点位置信息
1. Metadata 数据列表
根据大疆内部文件列出,经实测有改动,具体以proto文件为准
类别 | Metadata 名称 | 类型 | 单位 | 推送频率 |
---|---|---|---|---|
飞机信息 | 飞机位置-经度 | double | 度 | 10Hz |
飞机信息 | 飞机位置-纬度 | double | 度 | 10Hz |
飞机信息 | 飞机位置-椭球高 | float | 米 | 10Hz |
飞机信息 | 飞机姿态-roll | Int32 | 0.1 度 | 10Hz |
飞机信息 | 飞机姿态-yaw | Int32 | 0.1 度 | 10Hz |
飞机信息 | 飞机姿态-pitch | Int32 | 0.1 度 | 10Hz |
飞机信息 | Home 点-经度 | Double | 度 | 1Hz |
飞机信息 | Home 点-纬度 | Double | 度 | 1Hz |
飞机信息 | Home 点-椭球高 | float | 米 | 1Hz |
遥控器信息 | 遥控器角色 | enum | 0.2Hz | |
遥控器信息 | 遥控器位置-经度 | double | 度 | 0.2Hz |
遥控器信息 | 遥控器位置-纬度 | double | 度 | 0.2Hz |
遥控器信息 | 遥控器位置-椭球高 | float | 米 | 0.2Hz |
目标点 | TargetPoint-版本 | Uint32 | 2Hz | |
目标点 | TargetPoint-Source | Char * | 2Hz | |
目标点 | TargetPoint-数据[数组] | 2Hz |
TargetPoint-数据[数组]
参数名 | 类型 | 单位 |
---|---|---|
type | Enum | |
index | Uint32 | |
latitude | Double | 度 |
longitude | Double | 度 |
altitude_ellipsoid | Float | 米 |
altitude_relative | Float | 米 |
video_stream_window_x | Float | |
video_stream_window_y | Float | |
flags | Uint32 |
2. DJI Metadata protobuf解析文件
DJI对Metadata采用protobuf进行封装,以下是proto文件,已经本人验证并修改了部分BUG
dvtm_library.proto
// DJI Video Timed Metadata Format using Protobuf 3// version = 3syntax = "proto3";
// basic message defin ==========================
enum DIRECTION_TYPE {RESERVED = 0;NORTH = 1;NORTHEAST = 2;EAST = 3;SOUTHEAST = 4;SOUTH = 5;SOUTHWEST = 6;WEST = 7;NORTHWEST = 8;
}message DjiUTC {uint32 year = 1; // The year, like 2020.uint32 month = 2; // The month in the year, in the range 1 to 12.uint32 day = 3; // The day of the month, in the range 1 to 31.uint32 hour = 4; // The number of hours past midnight, in the range 0 to 23.uint32 min = 5; // The number of minutes after the hour, in the range 0 to 59.uint32 sec = 6; // The number of seconds after the minute, normally in the range 0 to 59.uint32 nsec = 7; // The number of nanoseconds after the second.
}message DeviceIdentify {string serial_number = 1; // limited to 32 characters
}message DjiInherentInfoBase {DeviceIdentify device_identify = 1; // Include sn now.string module_name = 2; // limited to 32 charactersstring firmware_version = 3; // limited to 32 charactersstring manufacture_id = 4; // limited to 18 charactersstring product_type = 5; // limited to 32 characters
}// [end] basic message defin ==========================// Global Information, only appear once in whole video ==========================
message DjiModuleInfo {enum ModuleType {// The body of any kinds of camera which generate this video,// including gimbal camera, payload camera, or fly camera with// non-removable drone.MODULE_CAMERA_BODY = 0;// interchangeable droneMODULE_DRONE = 1;// interchangeable lensMODULE_LENS = 2;}ModuleType module_type = 1;string model_name = 2; // limited to 32 charactersstring serial_number = 3; // limited to 32 charactersstring firmware_version = 4; // limited to 32 characters
}message DjiVideoGlobalInfo {repeated DjiModuleInfo module_info = 1;// The video full path file name, limited to 800 charactersstring file_name = 3;fixed32 video_uuid = 4; // the video unique IDstring record_start_time = 5; // uses RFC 3339uint32 resolution_height = 6; // unit: pixeluint32 resolution_width = 7; // unit: pixelfloat video_framerate = 8;enum VideoType {VIDEO_NORMAL = 0;VIDEO_DELAY = 1;VIDEO_SLOW_MOTION = 2;VIDEO_QUICK_MOVIE = 3;VIDEO_TIMELAPSE = 4;VIDEO_MOTIONLAPSE = 5;VIDEO_HYPERLAPSE = 6;VIDEO_HDR = 7;VIDEO_LOOP_RECORD = 8;}VideoType video_type = 9;enum VideoEncoder {ENCODER_H264 = 0;ENCODER_H265 = 1;}VideoEncoder video_encoder = 10;uint32 library_proto_version = 11; // version of dvtm_library.protouint32 product_proto_version = 12; // version of product corresponding proto file
}
// [end] Global Information, only appear once in whole video ====================// Describe every data source as a message ===================================// All device_id field in messages is internal reserved at present.
// User should not care about or depends on this field.message DjiCameraBasic {uint32 device_id = 1;int64 timestamp = 2;uint32 frame_id = 3;// reserved for future usestring camera_name = 4; // limited to 32 characterssint32 exposure_bias_tenfold = 5; // exposure bias, tenfold expression, reserved for IR camerafloat exposure_time = 6; // exposure time (uint: s)uint32 iso = 7; // photographic sensitivity, reserved for IR camerauint32 fnumber_tenfold = 8; // F-Number, tenfold expressionfloat focal_length = 9; // actual focal length in mmfloat digital_zoom_ratio = 10;
}message DjiLaserRanging {uint32 device_id = 1;int64 timestamp = 2;uint32 frame_id = 3;// processed data of laser ranging function, fields 5-10 is only valid// if ranging_enabled is true, which means you enable this function// by yourself on APP. fields 6-8 is only valid if gps_status in DjiGpsBasic// message is not GPS_INVALID.bool ranging_enabled = 4;uint32 target_distance = 5; // mmfloat target_longitude = 6; // degreefloat target_latitude = 7; // degreeuint32 target_altitude = 8; // height relative to takeoff point in mmuint32 screen_offset_x = 9; // target offset on horizontal direction of screen in permillageuint32 screen_offset_y = 10; // target offset on vertical direction of screen in permillage// raw sensor data, always on. fields 12-19 is only valid if laser_status is LASER_NORMAL.enum LaserStatus {LASER_NORMAL = 0; // laser ranging finder works fine.LASER_TOO_CLOSE = 1; // target distance is less than minimum range of finder.LASER_TOO_FAR = 2; // target distance is larger than maximum range of finder.LASER_CLOSED = 3; // laser module is closed.}LaserStatus laser_status = 11;uint32 distance1 = 12; // unit: mmuint32 intensity1 = 13; // signal intensity, range: 0~255uint32 distance2 = 14; // unit: mmuint32 intensity2 = 15; // signal intensity, range: 0~255uint32 distance3 = 16; // unit: mmuint32 intensity3 = 17; // signal intensity, range: 0~255uint32 distance4 = 18; // unit: mmuint32 intensity4 = 19; // signal intensity, range: 0~255uint32 target_abs_alt = 20; // absolute height of target point in mm
}message DjiGpsBasic {uint32 device_id = 1;int64 timestamp = 2;uint32 frame_id = 3;double gps_latitude = 4; // unit: rad, WGS-84 coordinate systemdouble gps_longitude = 5; // unit: rad, WGS-84 coordinate systemint32 gps_altitude_mm = 6; // unit mm, refer to gps_altitude_type for detailsenum GpsStatus {GPS_NORMAL = 0; // working with non-RTK GPSGPS_INVALID = 1; // GPS signal is non-available, measurement interruptedGPS_RTK = 2; // working with RTK-GPS}GpsStatus gps_status = 7;// Specify type of gps_altitude_mm and altitudes in other messages. For versions that don't support this fields,// use gps_status to get the type. If gps_status is GPS_RTK, gps_altitude_type is RTK_ALTITUDE, otherwise,// gps_altitude_type is PRESSURE_ALTITUDE.enum GpsAltType {PRESSURE_ALTITUDE = 0; // altitude is mainly provided by barometer which has different origin with ellipsoidal heightGPS_FUSION_ALTITUDE = 1; // fused height by GPS and barometer, which based on ellipsoidal coordinateRTK_ALTITUDE = 2; // altitude is ellipsoidal height provided by RTK}GpsAltType gps_altitude_type = 8;enum COORDINATE_TYPE {WGS84 = 0;CGCS2000 = 1;}COORDINATE_TYPE coordinate = 9; // In rtk or gps mode, it indicate the coordinate of the lat, lon, alti.DjiUTC utc_time = 10;DeviceIdentify device_identify = 11;
}message DjiFlyingState {uint32 device_id = 1;int64 timestamp = 2;uint32 frame_id = 3;// drone body speed components in NED coordinate system.int32 speed_x_dms = 4; // north direction, unit: 0.1 m/sint32 speed_y_dms = 5; // east direction, unit: 0.1 m/sint32 speed_z_dms = 6; // vertical direction, unit: 0.1 m/s// The Euler angles of drone body relative to the NED (North, East, Down)// coordinate system. Rotation sequence of the Euler angle is// ZYX (yaw, pitch, roll), intrinsic.sint32 pitch_decidegree = 7; // unit: 0.1 degreesint32 roll_decidegree = 8; // unit: 0.1 degreesint32 yaw_decidegree = 9; // unit: 0.1 degree// height relative to home point, unit: 0.1msint32 relative_height_decimeter = 10;DjiUTC utc_time = 11;int32 heading = 12; // unit: 0.1 degree
}message DjiGimbal {uint32 device_id = 1;int64 timestamp = 2;uint32 frame_id = 3;enum GimbalPosition {GIMBAL_POS_NORMAL = 0;GIMBAL_POS_REVERSE = 1;}GimbalPosition gimbal_position = 4;enum GimbalMode {GIMBAL_MODE_FREE = 0;GIMBAL_MODE_FPV = 1;GIMBAL_MODE_FOLLOW = 2;}GimbalMode gimbal_mode = 5;// The Euler angles of gimbal relative to the NED (North, East, Down)// coordinate system. Rotation sequence of the Euler angle is// ZXY (yaw, roll, pitch), intrinsic. For upward gimbal, the Euler// angles translate from the real quaternion of gimbal after rotate// 180 degree around the X axis of moving body.sint32 pitch_decidegree = 6; // unit: 0.1 degreesint32 roll_decidegree = 7; // unit: 0.1 degreesint32 yaw_decidegree = 8; // unit: 0.1 degreeDjiUTC utc_time = 9;DeviceIdentify device_identify = 10; // Include sn now.
}// [end] Describe every data source as a message =============================message DjiRealTimeTargetPoint {int64 timestamp = 1;uint32 frame_id = 2;DjiUTC utc_time = 3;repeated string source = 4; // The description of the one which create this point.message DjiTargetPointStruct {enum TARGET_POINT_TYPE {NO_USED = 0;TARGET_POINT = 1; // The target point create in local client.RNG_POINT = 2; // The The laser ranging point is different from the target point. // This point is the center point of the screen detected by laser ranging in real time.*/ST_POINT = 3; // Spotlight tracking point, the target position calculated in the camera automatic tracking mode,// on the screen display, mutually exclusive with Rng, if there is this point, // the Rng point may not be displayed.}TARGET_POINT_TYPE type = 1; // The point type.uint32 index = 2; // The point index.double latitude = 3; // unit: rad.double longitude = 4; // unit: rad.float altitude_ellipsoid = 5; // unit: m. In ellipsoidal coordinate system.float altitude_relative = 6; // unit: m. The altitude relatived to take-off point.float video_stream_window_x = 7; // 0~1, Relative to the current position of the current stream viewport x,// the upper left corner of the screen is 0, and negative numbers are used to indicate illegal values// and are not displayed on the viewport.float video_stream_window_y = 8; // 0~1, Relative to the current position of the current stream viewport x,// the upper left corner of the screen is 0, and negative numbers are used to indicate illegal values// and are not displayed on the viewport.bool altitude_ellipsoid_can_use = 9;}repeated DjiTargetPointStruct TargetPointStruct = 5;
}message DjiFlyingWindState {int64 timestamp = 1;uint32 frame_id = 2;DjiUTC utc_time = 3;float wind_speed = 4; // unit:m/s, precision:one decimal placeDIRECTION_TYPE wind_dir = 5; // The direction of the wind
}message DjiFlyingHomePoint {DjiGpsBasic point_pos_info = 3;
}message DjiFlyingInherentInfo {DjiInherentInfoBase base_info = 1;
}message DjiFlyingFlyOrderID {string order_id = 1; // limited to 48 characters
}message DjiRCInherentInfo {DjiInherentInfoBase base_info = 1;enum REMOTE_CONTROL_ROLES {RC_ROLES_A = 0;RC_ROLES_B = 1;}REMOTE_CONTROL_ROLES rc_roles = 2; // [only remote control] The remote control position index
}message DjiPayloadInherentInfo {DIRECTION_TYPE base_info = 1;enum PAYLOAD_PHY_POS {INDEX_1 = 0;INDEX_2 = 1;INDEX_3 = 2;}PAYLOAD_PHY_POS payload_phy_pos = 2; // [only payload] The payload devices physical position index
}
dji_video_metadata.proto
// DJI Media Metadata using Protobuf 3// version = 1syntax = "proto3";
import "dvtm_library.proto";message DjiVideoMetadata {DjiVideoGlobalInfo video_global_info = 1;repeated DjiCameraBasic camera_basic = 5;repeated DjiGpsBasic gps_basic = 6; // The old flying pos in camera, not suggest to use any more.repeated DjiFlyingState flying_state = 7; // Push frequency: 10Hz, Include flying speed and flying attitude.repeated DjiGimbal gimbal = 8; // Push frequency: Hz.repeated DjiLaserRanging laser_ranging = 9;DjiPayloadInherentInfo payload_inherent_info = 10; // Push frequency: 1Hz.repeated DjiFlyingWindState flying_wind_state = 50; // Push frequency: 10Hz.repeated DjiGpsBasic flying_pos = 51; // Push frequency: 10Hz, The position information of the flying, using GPS/RTK, etc.repeated DjiFlyingHomePoint flying_home_point = 52; // Push frequency: 10Hz.DjiRealTimeTargetPoint dji_rt_target_point = 53; // Push frequency: 2Hz.DjiFlyingInherentInfo flying_inherent_info = 54; // Push frequency: 1Hz.DjiFlyingFlyOrderID flying_order_id = 55; // Event trigger.repeated DjiGpsBasic flying_rc_pos = 100; // Push frequency: Hz. The position information of the remote control which control this flying.DjiRCInherentInfo flying_rc_inherent_info = 101; // Push frequency: 1Hz.
}
Metadata 封装成一个单独 NALU,附加在每个 H264 视频 I 帧或 P 帧的末尾,NAL 类型为
0x06,其中 UUID 固定为
{0x81, 0x6d, 0x38, 0x4e, 0x99, 0x8c, 0x11, 0xea, 0xb2, 0x94, 0x02, 0xfc, 0xdc, 0x4e, 0x74, 0x12}
3. Metadata 解析指导
- 将 metadata 数据,通过 protobuf 工具,序列化成二进制数据。
- 根据 Metadta in H264 介绍的格式,将 metadata protobuf 二进制数据封装到H264/H265 的 SEI 帧里,紧随着每一个 I/P 帧传输。
- 解析端收取的时候也是先收取到码流,根据码流解析出一个个帧,然后识别到 SEI帧,按照格式解析得到 metadata protobuf 二进制数据。最后根据 protobuf 格式(protobuf 支持多种语言多种平台),解析出 metadata 数据结构体。
- 解析这个环节最关键的三个要素:metadata protobuf file,protobuf 对应平台的编译工具,H264/H265 SEI 帧。
四、DJI GB28181 协议信令详解
抽空再写
总结
本文大部分资源来自于大疆内部文档,本人仅对其中的文件缺失进行了补全,最终解释权归大疆所有
双重加密的WeChat号,很简单的啦
MzkyODdmMTlhZWQzYzNmMTZjMWUxN2E0MDlmOWI0MDY
大疆行业无人机接入音视频平台协议详解相关推荐
- 音视频SDP协议详解(描述会话的协议)
前言 ①SDP协议是会话描述协议(Session Description Protocol)的缩写,是一种会话描述格式,一种描述流媒体初始化参数的格式,为描述多媒体数据而设计. 文末卡片领取音视频免费 ...
- 移动端实时音视频直播技术详解(一):开篇
移动端实时音视频直播技术详解(一):开篇 1.引言 随着互联网用户消费内容和交互方式的升级,支撑这些内容和交互方式的基础设施也正在悄悄发生变革.手机设备拍摄视频能力和网络的升级催生了大家对视频直播领域 ...
- 【音视频第6天】基础知识-移动端实时音视频直播技术详解和开源工程WebRTC的技术原理和使用浅析
本文是系列文章中的第1篇,本系列文章的大纲如下: <移动端实时音视频直播技术详解(一):开篇> <移动端实时音视频直播技术详解(二):采集> <移动端实时音视频直播技术详 ...
- 音视频开发-FFmpeg详解
音视频开发是个非常复杂的,庞大的开发话题,初涉其中,先看一下结合 OEIP(开源项目) 新增例子. 可以打开flv,mp4类型文件,以及rtmp协议音视频数据,声音的播放使用SDL. 把采集的麦/声卡 ...
- 消防部队应急通信保障---多链路聚合通信系统音视频图传方案详解
近年来,灭火救援工作呈现出突发性强.技术要求高.处置难度大.作战时间长等特点,尤其是跨区域协同作战越来越频繁,作为综合应急救援队伍的主力军,公安消防部队往往需要公安消防部队调集多个队伍联合作战,作战方 ...
- RTP协议封装音视频媒体数据详解
RTP协议对媒体数据(包括音频和视频)的封装是由指定的的协议文档规定. 1. RTP封装H.264视频编码数据 1.1 H.264 基本流的结构 H.264 的基本流(elementary strea ...
- 超级简单的大疆tello无人机视频实现(很少代码)
大疆tello无人机出来有1年时间了,使用pc查看视频的功能也只是今年才开放,经过2天的摸索,终于用简单的方法实现,不敢独享,分享出来. 1.连接tello的wifi: 2.使用udp组件发送打开视频 ...
- 大疆DJI无人机GoPro运动相机MOV或MP4视频文件恢复后花屏解决技术思路方法
从事数据恢复的工作人员.航拍录像从业人员.摄影爱好者等有时会遇到视频文件损坏问题,下面分析的就是常见的情况:大疆DJI无人机GoPro运动相机MOV或MP4视频文件丢失之后(删除.病毒感染或者格式化等 ...
- 试玩系列 | 真香!大疆TT无人机编程初体验,教你对它为所欲为!
先放个项目演示视频镇帖(点击小程序查看演示视频): 认识我的朋友,大概都知道,我是一个"运气爆棚"的人,经常能"捡"到一些好玩的东西.这不,前两天在家门口&qu ...
最新文章
- ios玩全民奇迹不显示服务器,全民奇迹关于IOS充值游戏物品不到账公告
- python找字符串_Python如何实现查找字符串
- openocd调试Linux内核,Ubuntu下配置OpenOCD+FT2232
- del rd命令行下删除文件不需要确认
- Angular Component的DOM级别的单元测试方法
- css3 卡片hover3D效果
- 面试:MySQL InnoDB 事务隔离
- 「Linux」VMware安装centos7(一)
- 面向对象的三个基本特征_杂谈:JavaScript面向对象
- knx智能照明控制系统电路图_KNX智能控制系统(20100928)解析
- 打印时显示rpc服务器不可用,打印时出现RPC服务器不可用 ?
- jquery衬衣产品内容详情页
- python flask web_Python Web开发之Flask
- python多重插补_5.4 缺失值插补
- 使用helm部署kubeapps
- 【Cherno的OpenGL视频】Welcome to OpenGL
- 分解质因数-Pollard‘s Rho
- 【Spring Security】安全框架学习(十三)
- centos7重启或关机卡死
- 【实战佳作】微软的《编程之美》
热门文章
- 如何查看当前项目的spring版本号
- oracle给账号添加权限
- PdfjsAnnotate批注集成富文本编辑器源码
- 模仿网易新闻做的新闻软件
- php 获取checkbox是否选中,javascript操作html复选框checkbox:如何判断复选框是否被选中...
- 【云原生】具体指什么呢---此文和大伙儿分享答案
- python自动更新excel_Python办公自动化|自动更新表格,告别繁琐
- 【Redis】聊一下缓存雪崩、击穿、穿透、预热
- tabindex属性_tabindex(HTML属性)
- ffmpeg教程 如何从视频中提取音频文件?