Android轻量级RTSP服务使用场景分析和设计探讨

news2024/9/20 5:29:53

技术背景

好多开发者,对我们Android平台轻量级RTSP服务模块有些陌生,不知道这个模块具体适用于怎样的场景,有什么优缺点,实际上,我们的Android平台轻量级RTSP服务模块更适用于内网环境下、对并发要求不高的场景,实现低成本、低延迟的音视频实时传输。本文就上述问题,做个技术探讨,先说适用场景:

1. 内网环境

  • 无纸化/电子教室:在这些环境中,需要实现音视频的低延迟传输,而轻量级RTSP服务能够避免单独部署RTSP或RTMP服务器,简化部署流程,同时满足对并发要求不高的场景。
  • 车载自组网:在多辆车组成的网络中,轻量级RTSP服务可以确保车辆间实时视频传输,帮助驾驶员了解前方路况等信息。
  • 视频监控记录仪:把Android终端做成类似于网络摄像头的执法记录类设备,更便携。
  • 智能安全帽:用于内网自组网环境智能安全帽,实时巡检时可录像可快照,指挥中心还可实时查看现场情况。

2. 本地音视频数据传输

  • 摄像头和麦克风数据:将本地的摄像头和麦克风采集的音视频数据编码后,通过轻量级RTSP服务汇聚并对外提供可供拉流的RTSP URL,实现音视频数据的实时传输。
  • 屏幕共享:除了摄像头和麦克风,轻量级RTSP服务还支持屏幕共享功能,可以将设备屏幕内容编码后通过RTSP服务进行传输。

3. 低成本解决方案

  • 避免额外服务器部署:轻量级RTSP服务直接在Android设备上实现,无需额外部署RTSP或RTMP服务器,降低了成本。
  • 简化产品设计:对于需要实时音视频传输但不想增加产品复杂度的开发者来说,轻量级RTSP服务是一个理想的选择。

4. 特定功能支持

  • 支持多种音视频格式:轻量级RTSP服务通常支持H.264/H.265视频编码和AAC音频编码,满足不同的音视频传输需求。
  • 鉴权、单播和组播模式:支持RTSP鉴权功能,保障传输安全;同时支持单播和组播模式,满足不同的传输需求。
  • 多服务并发:考虑到单个服务承载能力,支持同时创建多个RTSP服务,并支持获取当前RTSP服务会话连接数。

Android轻量级RTSP服务优缺点探讨

优点

  1. 低成本与简化部署
    • 轻量级RTSP服务直接在Android设备上实现,无需额外部署RTSP或RTMP服务器,从而降低了硬件和运营成本。
    • 简化了产品设计和部署流程,使得开发者能够更快速地集成实时音视频传输功能。
  2. 高效与低延迟
    • RTSP协议本身对实时性有较好的支持,能够提供低延迟的音视频传输服务。
    • 轻量级RTSP服务通过优化传输机制和减少中间环节,进一步提高了传输效率。
  3. 灵活性与可扩展性
    • 支持多种音视频编码格式,如H.264/H.265视频编码和AAC音频编码,满足不同场景下的传输需求。
    • 支持RTSP鉴权功能,保障传输安全;同时支持单播和组播模式,满足不同的传输需求。
    • 考虑到单个服务承载能力,支持同时创建多个RTSP服务,并支持获取当前RTSP服务会话连接数,便于管理和扩展。
  4. 内网环境友好
    • 特别适用于内网环境下的音视频传输,如企业内网、校园网络等。
    • 在这些环境中,轻量级RTSP服务能够避免网络延迟和带宽限制等问题,提供稳定的音视频传输服务。
  5. 易于集成与调试
    • 提供了丰富的接口和文档支持,便于开发者进行集成和调试工作。
    • 开发者可以根据实际需求进行定制开发,实现更加个性化的功能。

缺点

  1. 并发能力有限
    1. 轻量级RTSP服务通常适用于对并发要求不高的场景。在高并发场景下,可能需要考虑增加服务器数量或使用更高级的流媒体服务器解决方案。
  2. 功能相对单一
    • 相比于专业的流媒体服务器解决方案,轻量级RTSP服务的功能可能相对单一。如果需要实现更复杂的音视频处理功能(如转码、录制等),可能需要结合其他工具或服务来实现。

如何实现Android轻量级RTSP服务

在Android平台上实现轻量级RTSP服务,主要涉及到视频和音频的采集、编码、封装成RTSP流,并通过网络进行传输。由于Android原生API并不直接支持RTSP服务器的功能,因此通常需要使用第三方库或自行实现RTSP服务器的逻辑。以下是一个基本的实现步骤和思路:

1. 自行开发

如果你对RTSP协议有较深的理解,并希望实现自定义的RTSP服务器,你可以考虑使用Java或C++(通过JNI)来编写RTSP服务器的核心逻辑。这通常涉及到解析RTSP请求、管理会话、控制音视频流等。

2. 音视频采集与编码

在Android上,你可以使用MediaCodec API来进行音视频数据的编码。MediaCodec是Android提供的一个强大的API,支持多种音视频编码格式,如H.264、AAC等。

  • 视频采集:可以使用Camera2 API(Android 5.0及以上)或Camera API(较旧的Android版本)来捕获视频帧。
  • 音频采集:可以使用AudioRecord API来捕获音频数据。

3. 封装成RTSP流

将编码后的音视频数据封装成RTSP流需要遵循RTSP协议。这通常涉及到将音视频数据封装成RTP(Real-time Transport Protocol)包,并通过RTSP协议控制这些包的传输。

  • RTP封装:RTP是用于在互联网上传输音频和视频数据的协议。你需要将编码后的音视频数据按照RTP包的格式进行封装。
  • RTSP控制:RTSP协议用于控制音频/视频的播放停止等。你需要实现RTSP服务器以处理这些控制请求。

4. 网络传输

使用Socket编程在Android上进行网络传输。你可以使用TCP或UDP协议来传输RTP包。RTSP控制信令通常使用TCP,而RTP数据包则常使用UDP。

5. 集成与测试

将上述所有组件集成到你的Android应用中,并进行充分的测试以确保RTSP服务的稳定性和性能。测试应包括不同的网络环境、设备性能以及并发请求等场景。

6. 注意事项

  • 性能优化:音视频处理和网络传输都是资源密集型的任务,因此需要注意性能优化,如合理使用线程、避免内存泄漏等。
  • 兼容性:由于Android设备的多样性和不同版本的API差异,你的RTSP服务需要尽可能兼容更多的设备和Android版本。
  • 权限:确保你的应用已正确声明了所有必要的权限,以便进行音视频采集和网络通信。

轻量级RTSP服务设计示例

文本以大牛直播SDK的Android平台轻量级RTSP服务模块为例,介绍下我们的开发思路和功能设计。

数据接入类型

轻量级RTSP服务数据源,支持编码前、编码后数据对接:

  • 编码前数据(目前支持的有YV12/NV21/NV12/I420/RGB24/RGBA32/RGB565等数据类型);
  • 编码后数据(如无人机等264/HEVC数据,或者本地解析的MP4音视频数据);
  • 拉取RTSP或RTMP流并注入轻量级RTSP服务模块,组合形成内置RTSP网关模块。

接口设计

我们的接口,RTSP服务和流发布分离,并添加了获取RTSP Session链接数接口,便于轻量级RTSP服务模块统计实时并发连接数。

Android内置轻量级RTSP服务SDK接口详解

调用描述

接口

接口描述

SmartRTSPServerSDK

初始化RTSP Server

InitRtspServer

Init rtsp server(和UnInitRtspServer配对使用,即便是启动多个RTSP服务,也只需调用一次InitRtspServer,请确保在OpenRtspServer之前调用)

创建一个rtsp server

OpenRtspServer

创建一个rtsp server,返回rtsp server句柄

设置端口

SetRtspServerPort

设置rtsp server 监听端口, 在StartRtspServer之前必须要设置端口

设置鉴权用户名、密码

SetRtspServerUserNamePassword

设置rtsp server 鉴权用户名和密码, 这个可以不设置,只有需要鉴权的再设置

获取rtsp server当前会话数

GetRtspServerClientSessionNumbers

获取rtsp server当前的客户会话数, 这个接口必须在StartRtspServer之后再调用

启动rtsp server

StartRtspServer

启动rtsp server

停止rtsp server

StopRtspServer

停止rtsp server

关闭rtsp server

CloseRtspServer

关闭rtsp server

UnInit rtsp server

UnInitRtspServer

UnInit rtsp server(和InitRtspServer配对使用,即便是启动多个RTSP服务,也只需调用一次UnInitRtspServer)

SmartRTSPServerSDK供Publisher调用的接口

设置rtsp的流名称

SetRtspStreamName

设置rtsp的流名称

给要发布的rtsp流设置rtsp server

AddRtspStreamServer

给要发布的rtsp流设置rtsp server, 一个流可以发布到多个rtsp server上,rtsp server的创建启动请参考OpenRtspServer和StartRtspServer接口

清除设置的rtsp server

ClearRtspStreamServer

清除设置的rtsp server

启动rtsp流

StartRtspStream

启动rtsp流

停止rtsp流

StopRtspStream

停止rtsp流

功能支持

  •  ​[视频格式]H.264/H.265(Android H.265硬编码);
  •  [音频格式]G.711 A律、AAC;
  • 协议:RTSP;
  •  [音量调节]Android平台采集端支持实时音量调节;
  •  [H.264硬编码]支持H.264特定机型硬编码;
  •  [H.265硬编码]支持H.265特定机型硬编码;
  • [音视频]支持纯音频/纯视频/音视频;
  • [摄像头]支持采集过程中,前后摄像头实时切换;
  • 支持帧率、关键帧间隔(GOP)、码率(bit-rate)设置;
  • [实时水印]支持动态文字水印、png水印;
  • [实时快照]支持实时快照;
  • [降噪]支持环境音、手机干扰等引起的噪音降噪处理、自动增益、VAD检测;
  • [外部编码前视频数据对接]支持YUV数据对接;
  • [外部编码前音频数据对接]支持PCM对接;
  • [外部编码后视频数据对接]支持外部H.264、H.265数据对接;
  • [外部编码后音频数据对接]外部AAC数据对接;
  • [扩展录像功能]支持和录像SDK组合使用,录像相关功能。​
  • 支持RTSP端口设置;
  • 支持RTSP鉴权用户名、密码设置;
  • 支持获取当前RTSP服务会话连接数;
  • 支持Android 5.1及以上版本。

接口调用示例

本文以大牛直播SDK Android平台Camera2Demo为例,启动RTSP服务、发布RTSP流之前,可以先选择视频分辨率、软编还是硬编码,音频是PCMA还是AAC编码等基础设置,其他参数的设置,可以参考下面InitAndSetConfig()。

以Android平台Camera2对接为例,先初始化RTSP Server:

/*
 * MainActivity.java
 * Author: daniusdk.com
 * WeChat: xinsheng120
 */
@Override
protected void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setContentView(R.layout.activity_main);
	
	...

	context_ = this.getApplicationContext();
	
	libPublisher = new SmartPublisherJniV2();

	libPublisher.InitRtspServer(context_);      //和UnInitRtspServer配对使用,即便是启动多个RTSP服务,也只需调用一次InitRtspServer,请确保在OpenRtspServer之前调用
}

启动、停止RTSP服务:

//启动/停止RTSP服务
class ButtonRtspServiceListener implements View.OnClickListener {
	public void onClick(View v) {
		if (isRTSPServiceRunning) {
			stopRtspService();

			btnRtspService.setText("启动RTSP服务");
			btnRtspPublisher.setEnabled(false);

			isRTSPServiceRunning = false;
			return;
		}

		Log.i(TAG, "onClick start rtsp service..");

		rtsp_handle_ = libPublisher.OpenRtspServer(0);

		if (rtsp_handle_ == 0) {
			Log.e(TAG, "创建rtsp server实例失败! 请检查SDK有效性");
		} else {
			int port = 8554;
			if (libPublisher.SetRtspServerPort(rtsp_handle_, port) != 0) {
				libPublisher.CloseRtspServer(rtsp_handle_);
				rtsp_handle_ = 0;
				Log.e(TAG, "创建rtsp server端口失败! 请检查端口是否重复或者端口不在范围内!");
			}

			if (libPublisher.StartRtspServer(rtsp_handle_, 0) == 0) {
				Log.i(TAG, "启动rtsp server 成功!");
			} else {
				libPublisher.CloseRtspServer(rtsp_handle_);
				rtsp_handle_ = 0;
				Log.e(TAG, "启动rtsp server失败! 请检查设置的端口是否被占用!");
			}

			btnRtspService.setText("停止RTSP服务");
			btnRtspPublisher.setEnabled(true);

			isRTSPServiceRunning = true;
		}
	}
}

stopRtspService()实现如下:

//停止RTSP服务
private void stopRtspService() {
	if(!isRTSPServiceRunning)
	{
		return;
	}
	if (libPublisher != null && rtsp_handle_ != 0) {
		libPublisher.StopRtspServer(rtsp_handle_);
		libPublisher.CloseRtspServer(rtsp_handle_);
		rtsp_handle_ = 0;
	}
}

发布、停止RTSP流:

//发布/停止RTSP流
class ButtonRtspPublisherListener implements View.OnClickListener {
	public void onClick(View v) {
		if (stream_publisher_.is_rtsp_publishing()) {
			stopRtspPublisher();

			btnRtspPublisher.setText("发布RTSP流");
			btnGetRtspSessionNumbers.setEnabled(false);
			btnRtspService.setEnabled(true);
			return;
		}

		Log.i(TAG, "onClick start rtsp publisher..");

		InitAndSetConfig();

		String rtsp_stream_name = "stream1";
		stream_publisher_.SetRtspStreamName(rtsp_stream_name);
		stream_publisher_.ClearRtspStreamServer();

		stream_publisher_.AddRtspStreamServer(rtsp_handle_);

		if (!stream_publisher_.StartRtspStream()) {
			stream_publisher_.try_release();
			Log.e(TAG, "调用发布rtsp流接口失败!");
			return;
		}

		startAudioRecorder();
		startLayerPostThread();

		btnRtspPublisher.setText("停止RTSP流");
		btnGetRtspSessionNumbers.setEnabled(true);
		btnRtspService.setEnabled(false);
	}
}

stopRtspPublisher()实现如下:

//停止发布RTSP流
private void stopRtspPublisher() {
	stream_publisher_.StopRtspStream();
	stream_publisher_.try_release();

	if (!stream_publisher_.is_publishing())
		stopAudioRecorder();
}

其中,InitAndSetConfig()实现如下,通过调研SmartPublisherOpen()接口,生成推送实例句柄。

/*
 * MainActivity.java
 * Author: daniusdk.com
 */
private void InitAndSetConfig() {
	if (null == libPublisher)
		return;

	if (!stream_publisher_.empty())
		return;

	Log.i(TAG, "InitAndSetConfig video width: " + video_width_ + ", height" + video_height_ + " imageRotationDegree:" + cameraImageRotationDegree_);

	int audio_opt = 1;
	long handle = libPublisher.SmartPublisherOpen(context_, audio_opt, 3,  video_width_, video_height_);
	if (0==handle) {
		Log.e(TAG, "sdk open failed!");
		return;
	}

	Log.i(TAG, "publisherHandle=" + handle);

	int fps = 25;
	int gop = fps * 3;

	initialize_publisher(libPublisher, handle, video_width_, video_height_, fps, gop);

	stream_publisher_.set(libPublisher, handle);
}

对应的initialize_publisher()实现如下,设置软硬编码、帧率、关键帧间隔等。

private boolean initialize_publisher(SmartPublisherJniV2 lib_publisher, long handle, int width, int height, int fps, int gop) {
	if (null == lib_publisher) {
		Log.e(TAG, "initialize_publisher lib_publisher is null");
		return false;
	}

	if (0 == handle) {
		Log.e(TAG, "initialize_publisher handle is 0");
		return false;
	}

	if (videoEncodeType == 1) {
		int kbps = LibPublisherWrapper.estimate_video_hardware_kbps(width, height, fps, true);
		Log.i(TAG, "h264HWKbps: " + kbps);
		int isSupportH264HWEncoder = lib_publisher.SetSmartPublisherVideoHWEncoder(handle, kbps);
		if (isSupportH264HWEncoder == 0) {
			lib_publisher.SetNativeMediaNDK(handle, 0);
			lib_publisher.SetVideoHWEncoderBitrateMode(handle, 1); // 0:CQ, 1:VBR, 2:CBR
			lib_publisher.SetVideoHWEncoderQuality(handle, 39);
			lib_publisher.SetAVCHWEncoderProfile(handle, 0x08); // 0x01: Baseline, 0x02: Main, 0x08: High

			// lib_publisher.SetAVCHWEncoderLevel(handle, 0x200); // Level 3.1
			// lib_publisher.SetAVCHWEncoderLevel(handle, 0x400); // Level 3.2
			// lib_publisher.SetAVCHWEncoderLevel(handle, 0x800); // Level 4
			lib_publisher.SetAVCHWEncoderLevel(handle, 0x1000); // Level 4.1 多数情况下,这个够用了
			//lib_publisher.SetAVCHWEncoderLevel(handle, 0x2000); // Level 4.2

			// lib_publisher.SetVideoHWEncoderMaxBitrate(handle, ((long)h264HWKbps)*1300);

			Log.i(TAG, "Great, it supports h.264 hardware encoder!");
		}
	} else if (videoEncodeType == 2) {
		int kbps = LibPublisherWrapper.estimate_video_hardware_kbps(width, height, fps, false);
		Log.i(TAG, "hevcHWKbps: " + kbps);
		int isSupportHevcHWEncoder = lib_publisher.SetSmartPublisherVideoHevcHWEncoder(handle, kbps);
		if (isSupportHevcHWEncoder == 0) {
			lib_publisher.SetNativeMediaNDK(handle, 0);
			lib_publisher.SetVideoHWEncoderBitrateMode(handle, 1); // 0:CQ, 1:VBR, 2:CBR
			lib_publisher.SetVideoHWEncoderQuality(handle, 39);

			// libPublisher.SetVideoHWEncoderMaxBitrate(handle, ((long)hevcHWKbps)*1200);

			Log.i(TAG, "Great, it supports hevc hardware encoder!");
		}
	}

	boolean is_sw_vbr_mode = true;
	//H.264 software encoder
	if (is_sw_vbr_mode) {
		int is_enable_vbr = 1;
		int video_quality = LibPublisherWrapper.estimate_video_software_quality(width, height, true);
		int vbr_max_kbps = LibPublisherWrapper.estimate_video_vbr_max_kbps(width, height, fps);
		lib_publisher.SmartPublisherSetSwVBRMode(handle, is_enable_vbr, video_quality, vbr_max_kbps);
	}

	if (is_pcma_) {
		lib_publisher.SmartPublisherSetAudioCodecType(handle, 3);
	} else {
		lib_publisher.SmartPublisherSetAudioCodecType(handle, 1);
	}

	lib_publisher.SetSmartPublisherEventCallbackV2(handle, new EventHandlerPublisherV2().set(handler_, record_executor_));

	lib_publisher.SmartPublisherSetSWVideoEncoderProfile(handle, 3);

	lib_publisher.SmartPublisherSetSWVideoEncoderSpeed(handle, 2);

	lib_publisher.SmartPublisherSetGopInterval(handle, gop);

	lib_publisher.SmartPublisherSetFPS(handle, fps);

	// lib_publisher.SmartPublisherSetSWVideoBitRate(handle, 600, 1200);

	boolean is_noise_suppression = true;
	lib_publisher.SmartPublisherSetNoiseSuppression(handle, is_noise_suppression ? 1 : 0);

	boolean is_agc = false;
	lib_publisher.SmartPublisherSetAGC(handle, is_agc ? 1 : 0);

	int echo_cancel_delay = 0;
	lib_publisher.SmartPublisherSetEchoCancellation(handle, 1, echo_cancel_delay);

	return true;
}

发布RTSP流成功后,会回调上来可供拉流的RTSP URL:

private static class EventHandlerPublisherV2 implements NTSmartEventCallbackV2 {
	@Override
	public void onNTSmartEventCallbackV2(long handle, int id, long param1, long param2, String param3, String param4, Object param5) {

		switch (id) {
			...
			case NTSmartEventID.EVENT_DANIULIVE_ERC_PUBLISHER_RTSP_URL:
				publisher_event = "RTSP服务URL: " + param3;
				break;
		}
	}
}

获取RTSP Session会话数:

//获取RTSP会话数
class ButtonGetRtspSessionNumbersListener implements View.OnClickListener {
	public void onClick(View v) {
		if (libPublisher != null && rtsp_handle_ != 0) {
			int session_numbers = libPublisher.GetRtspServerClientSessionNumbers(rtsp_handle_);

			Log.i(TAG, "GetRtspSessionNumbers: " + session_numbers);

			PopRtspSessionNumberDialog(session_numbers);
		}
	}
}

//当前RTSP会话数弹出框
private void PopRtspSessionNumberDialog(int session_numbers) {
	final EditText inputUrlTxt = new EditText(this);
	inputUrlTxt.setFocusable(true);
	inputUrlTxt.setEnabled(false);

	String session_numbers_tag = "RTSP服务当前客户会话数: " + session_numbers;
	inputUrlTxt.setText(session_numbers_tag);

	AlertDialog.Builder builderUrl = new AlertDialog.Builder(this);
	builderUrl
			.setTitle("内置RTSP服务")
			.setView(inputUrlTxt).setNegativeButton("确定", null);
	builderUrl.show();
}

总结

Android平台轻量级RTSP服务模块,除了可以对接编码前音视频数据外,还还需要支持对接编码后音视频数据,并实现本地录像、快照等。实现一个完整的轻量级RTSP服务是一个相对复杂的任务,需要对音视频处理、网络编程和RTSP协议有深入的理解。如果你没有这些经验,使用现成的第三方库可能是一个更好的选择。感兴趣的开发者,可以单独跟我们探讨。

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

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

相关文章

golang操作mysql利器-gorm

1、傻瓜示例 GORM通过将数据库表中的数据映射到面向对象的模型中,简化了数据库操作,使得开发者可以很方便的使用代码来操作数据库,而无需编写SQL语句。 目前有个mysql表:miniprogram_orders,其存储了所有用户对应的订…

PyCharm和VS Code 安装通义灵码,可本地安装包安装,解决插件安装不上问题

PyCharm和VS Code 安装通义灵码,可本地安装包安装,解决插件安装不上问题 PyCharm、VS Code 安装通义灵码介绍主要应用场景支持编程语言安装指南JetBrains IDEs 中安装指南步骤 1:准备工作步骤 2:在 JetBrains IDEs 中安装通义灵码…

实验3 Hadoop集群运行环境搭建和使用

实验3 Hadoop集群运行环境搭建和使用 一、实验介绍 本节实验旨在引导学生通过实际操作搭建一个基本的Hadoop集群,并进行基本的使用验证。实验包括在集群节点上添加域名映射以实现节点间的相互识别,配置免密SSH登录以便无密码访问各节点,安装和配置JDK以满足Hadoop的运行需求…

Flink1.18.1 Standalone模式集群搭建

Flink1.18.1 Standalone模式集群搭建 Flink1.18.1 Standalone模式集群搭建1. 环境准备1.1 Flink下载地址1.2 集群角色分配 2. Flink 集群安装步骤2.1 下载并解压 Flink2.2 解压安装包2.3 配置环境变量2.4 配置 SSH 免密登录 3. 配置 Flink 集群3.1 修改 flink-conf.yaml 配置文…

jmeter得到的文档数据处理

通过前面jmeter得到的输出文档,这里是txt文档,里面包含了很多条数据,每条数据的结构如下: 【request】 uuid:xxxxxxx timestamp:xxxxxxxx No.x question:xxxxxxx 【response】 code&#…

DMA学习

一、DMA简介 DMA是一种无需CPU的参与就可以让外设与系统内存之间进行双向数据传输的硬件机制。使用DMA可以使系统CPU从实际的I/O数据传输过程中摆脱出来,从而大大提高系统的吞吐率。 DMA方式的数据传输由DMA控制器(DMAC)控制,在传…

sensitive-word 敏感词 v0.20.0 数字全部匹配,而不是部分匹配

敏感词系列 sensitive-word-admin 敏感词控台 v1.2.0 版本开源 sensitive-word-admin v1.3.0 发布 如何支持分布式部署? 01-开源敏感词工具入门使用 02-如何实现一个敏感词工具?违禁词实现思路梳理 03-敏感词之 StopWord 停止词优化与特殊符号 04-…

AAAI2024--频谱在多模态表示和融合中的作用更为有效:A Multimodal Spectrum Rumor Detector

https://github.com/dm4m/FSRU 多模态内容,如将文本与图像混合,对社交媒体中的谣言检测提出了重大挑战。现有的多模态谣言检测侧重于在空间和序列位置之间混合令牌进行单模态表示,或者在模态间融合谣言真实性的线索。然而,它们受…

将本地离线Jar包上传到Maven远程私库上,供项目编译使用

背景 因项目对接需求,需对接第三方Jar(海康人脸识别服务网关API),在项目集成时,处于本地编译、远程持续构建的需要将离线Jar推送到远程Maven仓库。 实施步骤 进入到离线Jar包同文件夹下 配置Maven配置文件中远程账户信息 需要在Idea配置的…

Java 数据类型转换详解:隐式转换(自动转换)与强制转换(手动转换)

目录 前言 取值范围从小到大的关系: 隐式转换(自动转换) 📜示例 1:基本类型隐式转换 📜示例 2:算术运算中的类型提升 📜示例 3:byte、short 和 char 的自动转换 隐…

Hive基本原理与数据开发

目录 1.什么是Hive 2.Hive的特点和优势 2.1.Hive的特点 2.1.1.易用性 2.1.2.高效性 2.1.3.兼容性 2.1.4.可扩展性 2.1.5.容错性 2.2.与传统数据库的区别 3.hive的架构 3.1.hive的核心组件(如 Metastore、Driver、Query Compiler、Execution Engine 等) 3.1.1.用户接…

Apache的ab压力测试工具与性能监控

【图书介绍】《软件性能测试、分析与调优实践之路(第2版)》_软件性能测试分析与调优实践之路-CSDN博客《软件性能测试、分析与调优实践之路(第2版)》(张永清)【摘要 书评 试读】- 京东图书 (jd.com) Apache的ab压力测试工具 A…

go语言中的切片详解

1.概念 在Go语言中,切片(Slice)是一种基于数组的更高级的数据结构,它提供了一种灵活、动态的方式来处理序列数据。切片在Go中非常常用,因为它们可以动态地增长和缩小,这使得它们比固定大小的数组更加灵活。…

电子看板实时监控数据可视化助力工厂精细化管理

在当今竞争激烈的制造业领域,工厂的精细化管理成为提高竞争力的关键。而电子看板实时监控数据可视化作为一种先进的管理工具,正为工厂的精细化管理带来巨大的助力。 一、工厂精细化管理的挑战 随着市场需求的不断变化和客户对产品质量要求的日益提高&am…

记一次键盘f2和f5键被自动触发情况

背景: 联想小新笔记本电脑内置键盘,其中f2键和f5键一直被自动触发,已尝试过更换输入法,重装系统,拆开键帽清灰依旧无效。考虑维修费或者更换键盘(内置)费都挺贵的,而且f2和f5作用也…

音视频入门基础:AAC专题(10)——FFmpeg源码中计算AAC裸流每个packet的pts、dts、pts_time、dts_time的实现

音视频入门基础:AAC专题系列文章: 音视频入门基础:AAC专题(1)——AAC官方文档下载 音视频入门基础:AAC专题(2)——使用FFmpeg命令生成AAC裸流文件 音视频入门基础:AAC…

uniapp小程序使用canvas画圆

<view class"container"><canvas canvas-id"arcCanvas" id"arcCanvas" class"arc-canvas" width"300" height"300"></canvas> </view> 最开始我使用…

【华为杯】第二十一届中国研究生数学建模竞赛

“华为杯”第二十一届中国研究生数学建模竞赛即将开始&#xff0c;梦想科研社给大家整理一些比赛信息&#xff0c;在正式开赛后&#xff0c;我们也会持续分享一些课题的分析以及代码&#xff0c;有需要的可以联系我们获取资料信息哦 一、时间节点 1.加密赛题开始下载时间&…

DPDK 简易应用开发之路 1:数据包接收与解析

本机环境为 Ubuntu20.04 &#xff0c;dpdk-stable-20.11.10 DPDK 应用基础 DPDK应用程序的一般处理流程如下&#xff1a; 初始化DPDK环境&#xff1a;调用rte_eal_init()初始化DPDK环境抽象层&#xff08;EAL&#xff09;&#xff0c;设置运行时环境和配置。 配置和绑定网卡…

2024最新版 Tuxera NTFS for Mac 2023绿色版图文安装教程

​ 在数字化时代&#xff0c;数据的存储和传输变得至关重要。Mac用户经常需要在Windows NTFS格式的移动硬盘上进行读写操作&#xff0c;然而&#xff0c;由于MacOS系统默认不支持NTFS的写操作&#xff0c;这就需要我们寻找一款高效的读写软件。Tuxera NTFS for Mac 2023便是其中…