如何设计开发RTSP直播播放器?

技术背景

我们在对接RTSP直播播放器相关技术诉求的时候,好多开发者,除了选用成熟的RTSP播放器外,还想知其然知其所以然,对RTSP播放器的整体开发有个基础的了解,方便方案之作和技术延伸。本文抛砖引玉,做个大概的介绍。

技术实现

技术难点

在探讨RTSP直播播放器技术实现之前,我们先来看,为什么RTSP播放器的开发看似简单,实则复杂,或者说做播放器容易,做个好的播放器,为什么就那么难?

协议复杂性
  1. 理解 RTSP 协议规范
    • RTSP 协议本身比较复杂,包含多种请求方法(如 OPTIONS、DESCRIBE、SETUP、PLAY、PAUSE、TEARDOWN 等)、状态码和头部字段。开发者需要深入理解这些规范,以便正确地与服务器进行交互。
    • 例如,在处理 DESCRIBE 请求时,需要解析服务器返回的媒体描述信息,其中可能包含复杂的 SDP(Session Description Protocol)格式,包括媒体类型、编码方式、帧率、分辨率等参数的描述。理解和解析这些信息需要对协议规范有深入的了解。
  2. 处理不同的协议变种和扩展
    • 在实际应用中,可能会遇到不同的 RTSP 服务器实现,它们可能会有一些协议变种或自定义的扩展。开发者需要能够处理这些差异,确保播放器能够与各种服务器兼容。
    • 例如,某些服务器可能会在 RTSP 响应中添加自定义的头部字段,或者对标准的请求方法有不同的处理方式。开发者需要能够识别这些差异,并进行相应的处理,以保证播放器的兼容性。
网络环境的不确定性
  1. 适应不同的网络条件
    • RTSP 播放器需要在各种网络环境下工作,包括不同的带宽、延迟、丢包率等。开发者需要考虑如何适应这些不同的网络条件,以确保视频的流畅播放。
    • 例如,在低带宽环境下,可能需要采用自适应比特率技术,根据网络状况动态调整视频的码率,以避免卡顿和缓冲。在高延迟网络中,需要优化播放控制算法,减少播放延迟,提高用户体验。
  2. 处理网络错误和异常情况
    • 网络环境中可能会出现各种错误和异常情况,如连接中断、服务器故障、丢包等。开发者需要能够处理这些情况,进行适当的错误恢复和重试机制,以保证播放器的稳定性。
    • 例如,当连接中断时,播放器需要能够自动尝试重新连接服务器,并在重新连接成功后继续播放。当出现丢包情况时,需要采用适当的错误隐藏技术,如帧间插值或重复上一帧,以减少视频的卡顿和花屏现象。
视频解码和播放的复杂性
  1. 支持多种视频编码格式
    • RTSP 流可以使用多种视频编码格式,如 H.264、H.265、MPEG-4 等。开发者需要选择合适的视频解码器,并确保播放器能够支持各种常见的编码格式。
    • 不同的编码格式具有不同的特点和复杂性,需要对其进行深入了解和处理。例如,H.265 编码具有更高的压缩率,但解码复杂度也更高。开发者需要选择高效的解码器,并进行优化,以确保在不同设备上的性能表现。
  2. 处理视频同步问题
    • 在播放视频时,需要确保音频和视频的同步播放。这涉及到处理视频和音频的时间戳、帧率、采样率等参数,以及进行适当的同步调整。
    • 视频和音频的同步是一个复杂的问题,需要考虑多种因素,如网络延迟、解码时间、播放设备的性能等。开发者需要采用适当的同步算法,确保音频和视频的同步播放,提高用户体验。
跨平台开发的挑战
  1. 适应不同的操作系统和设备
    • RTSP 播放器需要在不同的操作系统和设备上运行,如 Windows、Linux、Android、iOS 等。开发者需要考虑如何进行跨平台开发,确保播放器在各种平台上都能正常工作。
    • 不同的平台具有不同的开发环境、编程语言和多媒体框架,需要进行相应的适配和优化。例如,在 Android 平台上,可能需要使用 Java 或 Kotlin 进行开发,并利用 Android 的多媒体框架;在 iOS 平台上,可能需要使用 Objective-C 或 Swift 进行开发,并利用 iOS 的 AVFoundation 框架。
  2. 处理不同的硬件特性
    • 不同的设备具有不同的硬件特性,如处理器性能、内存大小、图形处理能力等。开发者需要考虑如何优化播放器的性能,以适应不同设备的硬件特性。
    • 例如,在性能较低的设备上,可能需要采用更高效的解码算法和播放控制策略,以减少资源占用和提高播放流畅性。在具有硬件加速功能的设备上,可以利用硬件加速来提高解码和播放性能。

技术选型

编程语言和平台
  • 选择适合的编程语言和开发平台。常见的选择包括 C++、Java、Python等编程语言,以及 Android、iOS、Windows、Linux 等操作系统平台。
  • 例如,在 Android平台上可以使用 Java 或 Kotlin 进行开发,利用 Android SDK 提供的多媒体框架和网络功能来实现 RTSP 播放器。,也可以通过jni接口封装,核心业务在底层,对上提供jni调用接口。
多媒体框架和库
  • 选择合适的多媒体框架和库来实现视频解码和播放功能。一些常用的多媒体框架和库包括 FFmpeg、GStreamer、VLC 等。
  • 这些框架和库提供了丰富的功能,如视频解码、音频解码、流媒体协议支持等,可以大大简化 RTSP 播放器的开发过程。例如,FFmpeg 是一个广泛使用的开源多媒体框架,支持众多的视频和音频格式以及流媒体协议,可以在多个平台上使用。
了解RTSP协议
  1. 协议结构和工作原理
    • 深入了解 RTSP 协议的结构和工作原理。RTSP 是一个应用层协议,用于控制实时流媒体的传输。它使用 TCP 或 UDP 作为传输层协议,通过发送请求和接收响应来实现对媒体流的控制。
    • RTSP 协议的主要功能包括媒体流的播放、暂停、快进、快退等操作,以及媒体流的描述、设置和传输控制等。了解 RTSP 协议的请求和响应格式、状态码、方法等内容,对于开发 RTSP 播放器至关重要。
  2. 协议交互过程
    • 熟悉 RTSP 协议的交互过程。当播放器连接到 RTSP 服务器时,首先发送 OPTIONS 请求以获取服务器支持的方法列表。然后,播放器发送 DESCRIBE 请求获取媒体流的描述信息,包括媒体格式、编码方式、帧率等。
    • 根据媒体流的描述信息,播放器选择合适的解码器进行视频和音频解码。接下来,播放器发送 SETUP 请求建立媒体流的传输连接,并发送 PLAY 请求开始播放媒体流。在播放过程中,播放器可以发送 PAUSE、TEARDOWN 等请求来控制媒体流的播放状态。

实现播放器功能

网络连接和数据接收
  • 实现与 RTSP 服务器的网络连接和数据接收功能。使用所选编程语言的网络编程库,建立与 RTSP 服务器的 TCP 或 UDP 连接,并接收服务器发送的媒体流数据。
  • 在接收数据时,需要处理网络错误、丢包等情况,确保数据的完整性和准确性。可以使用缓冲区来存储接收到的数据,以便后续的解码和播放操作。
视频解码和播放
  • 选择合适的视频解码器对接收的媒体流数据进行解码,并将解码后的视频帧显示在屏幕上。根据所选的多媒体框架和库,配置解码器参数,如视频格式、分辨率、帧率等。
  • 对于视频播放,可以使用图形库或多媒体框架提供的显示功能,将解码后的视频帧绘制在窗口或视图中。同时,需要处理视频的同步问题,确保音频和视频的同步播放。
音频解码和播放
  • 对接收的媒体流数据中的音频部分进行解码,并通过音频设备播放出来。选择合适的音频解码器,配置解码器参数,如音频格式、采样率、声道数等。
  • 使用音频输出库或多媒体框架提供的音频播放功能,将解码后的音频数据发送到音频设备进行播放。同样,需要处理音频的同步问题,确保音频和视频的同步播放。
播放控制和用户界面
  • 实现播放控制功能,如播放、暂停、快进、快退等操作。通过发送相应的 RTSP 请求来控制媒体流的播放状态,并在用户界面上提供相应的控制按钮。
  • 设计用户界面,包括视频显示区域、播放控制按钮、进度条等。使用图形用户界面库或开发平台提供的界面设计工具,创建直观、易用的用户界面。

SmartPlayer设计实现

以大牛直播SDK的SmartPlayer RTSP直播播放模块为例,我们来看看,如何实现低延迟的RTSP播放器。大牛直播SDK自2015年发布RTSP、RTMP直播播放模块,迭代从未停止,SmartPlayer功能强大、性能强劲、高稳定、超低延迟、超低资源占用。无需赘述,全自研内核,行业内一致认可的跨平台RTSP、RTMP直播播放器。先说功能设计,如不单独说明,Windows、Linux(x86_64|aarch64架构)、Android、iOS全平台支持。

  •  [多实例播放]支持多实例播放;
  •  [事件回调]支持网络状态、buffer状态等回调;
  •  [视频格式]支持H.265、H.264,此外,还支持RTSP MJPEG播放;
  •  [音频格式]支持AAC/PCMA/PCMU;
  •  [H.264/H.265软解码]支持H.264/H.265软解;
  •  [H.264硬解码]Windows/Android/iOS支持特定机型H.264硬解;
  •  [H.265硬解]Windows/Android/iOS支持特定机型H.265硬解;
  •  [H.264/H.265硬解码]Android支持设置Surface模式硬解和普通模式硬解码;
  •  [RTSP模式设置]支持RTSP TCP/UDP模式设置;
  •  [RTSP TCP/UDP自动切换]支持RTSP TCP、UDP模式自动切换;
  •  [RTSP超时设置]支持RTSP超时时间设置,单位:秒;
  •  [RTSP 401认证处理]支持上报RTSP 401事件,如URL携带鉴权信息,会自动处理;
  •  [缓冲时间设置]支持buffer time设置;
  •  [首屏秒开]支持首屏秒开模式;
  •  [复杂网络处理]支持断网重连等各种网络环境自动适配;
  •  [快速切换URL]支持播放过程中,快速切换其他URL,内容切换更快;
  •  [音视频多种render机制]Android平台,视频:surfaceview/OpenGL ES,音频:AudioTrack/OpenSL ES;
  •  [实时静音]支持播放过程中,实时静音/取消静音;
  •  [实时音量调节]支持播放过程中实时调节音量;
  •  [实时快照]支持播放过程中截取当前播放画面;
  •  [只播关键帧]Windows平台支持实时设置是否只播放关键帧;
  •  [渲染角度]支持0°,90°,180°和270°四个视频画面渲染角度设置;
  •  [渲染镜像]支持水平反转、垂直反转模式设置;
  •  [等比例缩放]支持图像等比例缩放绘制(Android设置surface模式硬解模式不支持);
  •  [实时下载速度更新]支持当前下载速度实时回调(支持设置回调时间间隔);
  •  [解码前视频数据回调]支持H.264/H.265数据回调;
  •  [解码后视频数据回调]支持解码后YUV/RGB数据回调;
  •  [解码前音频数据回调]支持AAC/PCMA/PCMU数据回调;
  •  [音视频自适应]支持播放过程中,音视频信息改变后自适应;
  •  [扩展录像功能]完美支持和录像SDK组合使用。
RTSP播放器设计要点

1. 低延迟:大多数RTSP的播放都面向直播场景,所以,如果延迟过大,严重影响体验,所以,低延迟是衡量一个好的RTSP播放器非常重要的指标,目前大牛直播SDK的RTSP直播播放延迟比开源播放器更优异,而且长时间运行下,不会造成延迟累积;

2. 音视频同步处理有些播放器为了追求低延迟,甚至不做音视频同步,拿到audio video直接播放,导致a/v不同步,还有就是时间戳乱跳等各种问题,大牛直播SDK提供的播放器,具备好的时间戳同步和异常时间戳矫正机制;

3. 支持多实例:大牛直播SDK提供的播放器支持同时播放多路音视频数据,比如4-8-9窗口,大多开源播放器对多实例支持不太友好;

4. 支持buffer time设置:在一些有网络抖动的场景,播放器需要支持buffer time设置,一般来说,以毫秒计,开源播放器对此支持不够友好;

5. TCP/UDP模式设定自动切换:考虑到好多服务器仅支持TCP或UDP模式,一个好的RTSP播放器需要支持TCP/UDP模式设置,如链接不支持TCP或UDP,大牛直播SDK可自动切换,,开源播放器不具备自动切换TCP/UDP能力;

6. 实时静音:比如,多窗口播放RTSP流,如果每个audio都播放出来,体验非常不好,所以实时静音功能非常必要,开源播放器不具备实时静音功能;

7. 视频view旋转:好多摄像头由于安装限制,导致图像倒置,所以一个好的RTSP播放器应该支持如视频view实时旋转(0° 90° 180° 270°)、水平反转、垂直反转,开源播放器不具备此功能;

8. 支持解码后audio/video数据输出:大牛直播SDK接触到好多开发者,希望能在播放的同时,获取到YUV或RGB数据,进行人脸匹配等算法分析,开源播放器不具备此功能;

9. 实时快照:感兴趣或重要的画面,实时截取下来非常必要,一般播放器不具备快照能力,开源播放器不具备此功能;

10. 网络抖动处理(如断网重连):稳定的网络处理机制、支持如断网重连等,开源播放器对网络异常处理支持较差;

11. 长期运行稳定性:不同于市面上的开源播放器,大牛直播SDK提供的Windows平台RTSP直播播放SDK适用于数天长时间运行,开源播放器对长时间运行稳定性支持较差;

12. log信息记录:整体流程机制记录到LOG文件,确保出问题时,有据可依,开源播放器几无log记录。

13. 实时下载速度反馈:大牛直播SDK提供音视频流实时下载回调,并可设置回调时间间隔,确保实时下载速度反馈,以此来监听网络状态,开源播放器不具备此能力;

14. 异常状态处理Event状态回调如播放的过程中,断网、网络抖动、等各种场景,大牛直播SDK提供的播放器可实时回调相关状态,确保上层模块感知处理,开源播放器对此支持不好;

15. 关键帧/全帧播放实时切换:特别是播放多路画面的时候,如果路数过多,全部解码、绘制,系统资源占用会加大,如果能灵活的处理,可以随时只播放关键帧,全帧播放切换,对系统性能要求大幅降低。

Android平台RTSP播放示例

下面以Android平台多实例RTSP播放为例,探讨下接口设计和调用说明。

我们针对的功能展示,主要是播放和录像这块,先说播放:

/*
 * SmartPlayer.java
 * Author: https://daniusdk.com
 * WeChat: xinsheng120
 * Created by DaniuLive on 2015/09/26.
 */
class ButtonPlayback1Listener implements View.OnClickListener {
	public void onClick(View v) {
		if (stream_player_1_.is_playing()) {
			Log.i(TAG, "Stop player1..");

			boolean iRet = stream_player_1_.StopPlayer();

			if (!iRet) {
				Log.e(TAG, "Call StopPlayer failed..");
				return;
			}

			stream_player_1_.try_release();
			btn_playback1.setText("开始播放1");
			SetViewVisibility(surface_view_1_);
		} else {
			Log.i(TAG, "Start playback stream1++");

			int play_buffer = 0;
			int is_using_tcp = 0;
			if(!stream_player_1_.OpenPlayerHandle(playback_url_1_, play_buffer, is_using_tcp))
				return;

			stream_player_1_.SetView(surface_view_1_);

			boolean is_mute = false;
			boolean iPlaybackRet = stream_player_1_.StartPlayer(isHardwareDecoder, is_enable_hardware_render_mode, is_mute);
			if (!iPlaybackRet) {
				Log.e(TAG, "Call StartPlayer failed..");
				return;
			}

			btn_playback1.setText("停止播放1");
		}
	}
}

对应的OpenPlayerHandle()实现如下:

/*
 * LibPlayerWrapper.java.java
 * Author: https://daniusdk.com
 */
public boolean OpenPlayerHandle(String playback_url, int play_buffer, int is_using_tcp) {

	if (check_native_handle())
		return true;

	if(!isValidRtspOrRtmpUrl(playback_url))
		return false;

	long handle = lib_player_.SmartPlayerOpen(application_context());
	if (0==handle) {
		Log.e(TAG, "sdk open failed!");
		return false;
	}

	lib_player_.SetSmartPlayerEventCallbackV2(handle, new EventHandleV2());

	lib_player_.SmartPlayerSetBuffer(handle, play_buffer);

	// set report download speed(默认2秒一次回调 用户可自行调整report间隔)
	lib_player_.SmartPlayerSetReportDownloadSpeed(handle, 1, 4);

	boolean isFastStartup = true;
	lib_player_.SmartPlayerSetFastStartup(handle, isFastStartup ? 1 : 0);

	//设置RTSP超时时间
	int rtsp_timeout = 10;
	lib_player_.SmartPlayerSetRTSPTimeout(handle, rtsp_timeout);

	//设置RTSP TCP/UDP模式自动切换
	int is_auto_switch_tcp_udp = 1;
	lib_player_.SmartPlayerSetRTSPAutoSwitchTcpUdp(handle, is_auto_switch_tcp_udp);

	lib_player_.SmartPlayerSaveImageFlag(handle, 1);

	// It only used when playback RTSP stream..
	lib_player_.SmartPlayerSetRTSPTcpMode(handle, is_using_tcp);

	lib_player_.DisableEnhancedRTMP(handle, 0);

	lib_player_.SmartPlayerSetUrl(handle, playback_url);

	set(handle);

	return true;
}

对应的开始播放、停止播放设计:

/*
 * LibPlayerWrapper.java
 * Author: https://daniusdk.com
 */
public boolean StartPlayer(boolean is_hardware_decoder, boolean is_enable_hardware_render_mode, boolean is_mute) {
	if (is_playing()) {
		Log.e(TAG, "already playing, native_handle:" + get());
		return false;
	}

	SetPlayerParam(is_hardware_decoder, is_enable_hardware_render_mode, is_mute);

	int ret = lib_player_.SmartPlayerStartPlay(get());
	if (ret != OK) {
		Log.e(TAG, "call StartPlay failed, native_handle:" + get() + ", ret:" + ret);
		return false;
	}

	write_lock_.lock();
	try {
		this.is_playing_ = true;
	} finally {
		write_lock_.unlock();
	}

	Log.i(TAG, "call StartPlayer OK, native_handle:" + get());
	return true;
}

public boolean StopPlayer() {
	if (!check_native_handle())
		return false;

	if (!is_playing()) {
		Log.w(TAG, "it's not playing, native_handle:" + get());
		return false;
	}

	boolean is_need_call = false;
	write_lock_.lock();
	try {
		if (this.is_playing_) {
			this.is_playing_ = false;
			is_need_call = true;
		}
	} finally {
		write_lock_.unlock();
	}

	if (is_need_call)
		lib_player_.SmartPlayerStopPlay(get());

	return true;
}

录像设计:

/*
 * SmartPlayer.java
 * Author: https://daniusdk.com
 */
class ButtonRecorder1Listener implements View.OnClickListener {
	public void onClick(View v) {
		if (stream_player_1_.is_recording()) {
			Log.i(TAG, "Stop recorder1..");

			boolean iRet = stream_player_1_.StopRecorder();

			if (!iRet) {
				Log.e(TAG, "Call StopRecorder failed..");
				return;
			}

			stream_player_1_.try_release();
			btn_recorder1.setText("开始录像1");
		} else {
			Log.i(TAG, "Start recorder stream1++");

			int play_buffer = 0;
			int is_using_tcp = 0;

			if(!stream_player_1_.OpenPlayerHandle(playback_url_1_, play_buffer, is_using_tcp))
				return;

			stream_player_1_.ConfigRecorderParam(recDir, 400, 1, 1, 1);

			boolean iRecRet = stream_player_1_.StartRecorder();
			if (!iRecRet) {
				Log.e(TAG, "Call StartRecorder failed..");
				return;
			}

			btn_recorder1.setText("停止录像1");
		}
	}
}

录像参数配置选项:

/*
 * LibPlayerWrapper.java
 * Author: https://daniusdk.com
 */
public boolean ConfigRecorderParam(String rec_dir, int file_max_size, int is_transcode_aac,
								   int is_record_video, int is_record_audio) {

	if(!check_native_handle())
		return false;

	if (null == rec_dir || rec_dir.isEmpty())
		return false;

	int ret = lib_player_.SmartPlayerCreateFileDirectory(rec_dir);
	if (ret != 0) {
		Log.e(TAG, "Create record dir failed, path:" + rec_dir);
		return false;
	}

	if (lib_player_.SmartPlayerSetRecorderDirectory(get(), rec_dir) != 0) {
		Log.e(TAG, "Set record dir failed , path:" + rec_dir);
		return false;
	}

	if (lib_player_.SmartPlayerSetRecorderFileMaxSize(get(),file_max_size) != 0) {
		Log.e(TAG, "SmartPlayerSetRecorderFileMaxSize failed.");
		return false;
	}

	lib_player_.SmartPlayerSetRecorderAudioTranscodeAAC(get(), is_transcode_aac);

	// 更细粒度控制录像的, 一般情况无需调用
	lib_player_.SmartPlayerSetRecorderVideo(get(), is_record_video);
	lib_player_.SmartPlayerSetRecorderAudio(get(), is_record_audio);
	return true;
}

开始录像、结束录像:

/*
 * LibPlayerWrapper.java
 * Author: https://daniusdk.com
 */
public boolean StartRecorder() {

	if (is_recording()) {
		Log.e(TAG, "already recording, native_handle:" + get());
		return false;
	}

	int ret = lib_player_.SmartPlayerStartRecorder(get());
	if (ret != OK) {
		Log.e(TAG, "call SmartPlayerStartRecorder failed, native_handle:" + get() + ", ret:" + ret);
		return false;
	}

	write_lock_.lock();
	try {
		this.is_recording_ = true;
	} finally {
		write_lock_.unlock();
	}

	Log.i(TAG, "call SmartPlayerStartRecorder OK, native_handle:" + get());
	return true;
}

public boolean StopRecorder() {
	if (!check_native_handle())
		return false;

	if (!is_recording()) {
		Log.w(TAG, "it's not recording, native_handle:" + get());
		return false;
	}

	boolean is_need_call = false;
	write_lock_.lock();
	try {
		if (this.is_recording_) {
			this.is_recording_ = false;
			is_need_call = true;
		}
	} finally {
		write_lock_.unlock();
	}

	if (is_need_call)
		lib_player_.SmartPlayerStopRecorder(get());

	return true;
}

总结

做RTSP播放器容易,做个可以稳定用于实际场景的低延迟RTSP播放器,真的非常困难,首先,RTSP协议本身的复杂度,如果不涉及底层协议栈,只是开源的项目编译调试小修小改,遇到问题,很难处理。还有就是网络环境的不确定性,视频解码和播放的复杂性,视频同步问题的复杂性及考虑因素。最后在跨平台开发的挑战,不同操作系统和设备以及处理不同硬件特性,都需要考虑。以上抛砖引玉,感兴趣的开发者,可以单独跟我沟通探讨。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

万户ezEIP企业管理系统 productlist.aspx SQL注入漏洞复现

0x01 产品简介 万户ezEIP是一种企业资源规划软件,旨在帮助企业管理其各个方面的业务流程。它提供了一套集成的解决方案,涵盖了财务、供应链管理、销售和市场营销、人力资源等各个领域。 0x02 漏洞概述 万户ezEIP企业管理系统 productlist.aspx 接口存在SQL注入漏洞,未经身…

【学术会议-6】激发灵感-计算机科学与技术学术会议邀您参与,共享学术盛宴,塑造明天的科技梦想!

【学术会议-6】激发灵感-计算机科学与技术学术会议邀您参与,共享学术盛宴,塑造明天的科技梦想! 【学术会议-6】激发灵感-计算机科学与技术学术会议邀您参与,共享学术盛宴,塑造明天的科技梦想! 文章目录 【…

【Linux】进程ID和线程ID在日志中的体现

在分析内核打印日志流程的时候,发现有时候同一个进程函数调用关系比较混乱(因为只打印了进程号),现象就是一个函数走着走着不知道走哪里去了。 另一个现象是,在Linux启动Firefox的时候,启了大概80个进程&…

Rocky linux 修改ip地址, rocky服务器修改静态地址, rocky虚拟机修改ip

1. 更新yum yum update 2. 安装ifconfig yum install net-tools 3. 修改配置 vi /etc/NetworkManager/system-connections/ens33.nmconnection 将ipv4内容修改如下: # 自动改为手动 methodmanual # 网关为vm ware 查看网关地址 address你想改为的ip/24,网关 #dns不…

Linux基础-shell的简单实现

个人主页:C忠实粉丝 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 C忠实粉丝 原创 Linux基础-shell的简单实现 收录于专栏[Linux学习] 本专栏旨在分享学习Linux的一点学习笔记,欢迎大家在评论区交流讨论💌 目录 1, 全局变…

MatLab Desired port was :31515解决方案

前言:使用的MatLabR2022b今天突然出现了错误,在程序中打不开文件。后尝试了下面的方法,可以解决。 解决方法一: 搜索栏输入:firewall.cpl 找到相关项,右键属性,设置为允许。 之后就可以了…

超声波清洗机双十一值得买吗?2024四款顶级超声波清洗机推荐!

许多朋友们可能还在犹豫不决,思考着在双十一这个购物狂欢节里,究竟应该选择哪一款品牌的超声波清洗机来购买呢?不用担心,今天我将为大家详细解读2024年四款备受瞩目的顶级超声波清洗机,让你在双十一的购物狂欢中不再感…

地理空间与交通流量数据集:TaxiNYC、TaxiBJ、BikeDC和BikeNYC

目录 TaxiNYC数据集TaxiBJ数据集BikeDC数据集1. **数据来源与时间范围**2. **数据内容**3. **区域划分与站点处理**4. **图结构构建**5. **人群流动计算**6. **数据集的应用场景**7. **预测任务设置**8. **图的构建** BikeNYC数据集1. **数据来源与时间范围**2. **数据内容**3.…

单位评职称需要在指定媒体上投稿发表文章看我如何轻松应对

在职场中,晋升与评职称是一项不可或缺的任务,而在这个过程中,完成相关的投稿更是至关重要。作为单位的一名员工,当我得知自己需要在指定的媒体上发表文章以满足职称评审要求时,心中既期待又忐忑。起初,我选择了传统的邮箱投稿方式,然而却没想到,这条路竟让我倍感挫折。 刚开始,…

FlexMatch: Boosting Semi-Supervised Learning with Curriculum Pseudo Labeling

FlexMatch: Boosting Semi-Supervised Learning with Curriculum Pseudo Labeling 摘要:引言:背景3 flexMatch3.1 Curriculum Pseudo Labeling3.2 阈值预热3.3非线性映射函数实验4.1 主要结果4.2 ImageNet上的结果4.3收敛速度加速4.4 消融研究5 相关工作摘要: 最近提出的Fi…

◇【论文_20150225】 DQN_2015(nature) 〔Google DeepMind〕

整理代码 1:DQN CartPole_v1.ipynb https://www.nature.com/articles/nature14236 Human-level control through deep reinforcement learning 文章目录 摘要主体:要做什么 如何做的 要点keypoints实验 与 评估2 个指标和 各游戏的最好方法比较t-S…

数据湖新突破:Hudi让实时数据分析更高效!

开源数据湖对比 Hudi的使用收益 Hudi使用成效 Hudi内部机制 增量摄入与更新 Hudi使用一种混合日志存储模式(称为Copy-on-Write),可以同时处理基础数据文件(Parquet)和增量日志(HoodieLogFile)。以 MergeOnReadTable 的 upsert 操作为例,当有新数据到来时,Hudi会先将数据以行…

【OpenMMLab】MMagic入门

1. 概述 OpenMMLab 概述:OpenMMLab 是上海人工智能实验室的计算机视觉算法开源体系,是深度学习时代全球领域最全面、最具影响力的视觉算法开源项目,也是全球最大最全的开源计算机视觉算法库。特点: 丰富的算法库:已累…

第三天-128.最长连续序列

这道题我完全没有思路,求助gpt,让它给我思路: 这个问题要求找出数组中数字连续的最长序列,并且时间复杂度必须是 O(n),可以采用 哈希集(HashSet)来帮助我们高效地判断数字是否存在。以下是解决…

AI周报(10.13-10.19)

AI应用-清华校友用AI破解162个高数定理 加州理工、斯坦福和威大的研究人员提出了LeanAgent——一个终身学习,并能证明定理的AI智能体。LeanAgent会根据数学难度优化的学习轨迹课程,来提高学习策略。并且,它还有一个动态数据库,有效…

Ubuntu如何显示pcl版本

终端输入: apt-cache show libpcl-dev可以看到,Ubuntu20.04,下载的pcl,应该都是1.10版本的

百易云资产管理运营系统 ufile.api.php SQL注入漏洞复现

0x01 产品描述: 百易云资产管理运营系统,是专门针对企业不动产资产管理和运营需求而设计的一套综合解决方案。该系统能够覆盖资产的全生命周期管理,包括资产的登记、盘点、评估、处置等多个环节,同时提供强大的运营分析功能&#…

执行php artisan storage:link报错

php artisan storage:link Call to undefined function Illuminate\Filesystem\symlink() 参考文章 https://learnku.com/laravel/t/73729

基于web的酒店客房管理系统【附源码】

基于web的酒店客房管理系统(源码L文说明文档) 目录 4 系统设计 4.1 系统概述 4.2系统结构 4.3.数据库设计 4.3.1数据库实体 4.3.2数据库设计表 5系统详细实现 5.1 用户信息管理 5.2 会员信息管理 5.3 客房信息管理 5.…

基于SpringBoot健康生活助手微信小程序【附源码】

基于SpringBoot健康生活助手微信小程序 效果如下: 管理员登录界面 管理员主界面 用户管理界面 健康记录管理界面 健康目标管理界面 微信小程序首页界面 活动信息界面 留言反馈界面 研究背景 近年来,由于计算机技术和互联网技术的飞速发展,…