HarmonyOS学习第18天:多媒体功能全解析
一、开篇引入
在当今数字化时代,多媒体已经深度融入我们的日常生活。无论是在工作中通过视频会议进行沟通协作,还是在学习时借助在线课程的音频讲解加深理解,亦或是在休闲时光用手机播放音乐放松身心、观看视频打发时间,多媒体功能都无处不在,成为我们生活中不可或缺的一部分。对于应用开发者而言,为 HarmonyOS 应用增添音频和视频功能,不仅能够满足用户日益增长的多样化需求,还能显著提升应用的竞争力和用户体验。接下来,就让我们一起深入探索如何在 HarmonyOS 应用中实现音频和视频的播放、录制功能,以及处理多媒体文件的格式转换和编辑。
二、音频播放功能实现
(一)MediaPlayer 基本介绍
在 HarmonyOS 多媒体开发中,MediaPlayer 是一个极为核心的类,承担着播放音频和视频的重要职责。它就像是一位专业的 “演奏家”,能够识别多种常见的音频格式,如 MP3、AAC、WAV 等 ,并将这些音频文件中的数字信号转化为美妙的声音。无论是播放本地存储的音乐文件,还是从网络上实时获取的音频流,MediaPlayer 都能游刃有余地应对,为用户带来丰富的听觉体验。通过它,开发者可以轻松实现音频的播放、暂停、停止、跳转等操作,为应用增添强大的音频交互功能。
(二)创建 MediaPlayer 实例
创建 MediaPlayer 实例是实现音频播放的第一步。在 HarmonyOS 中,我们可以通过以下代码简单地创建一个 MediaPlayer 对象:
MediaPlayer mediaPlayer = new MediaPlayer(); |
需要注意的是,创建实例时应确保在合适的生命周期方法中进行,比如在 Ability 的 onStart 方法中。这样可以保证 MediaPlayer 在应用启动时被正确初始化,避免出现空指针异常等问题。同时,要记得为 MediaPlayer 对象添加必要的异常处理机制,以应对可能出现的错误情况,确保应用的稳定性。
(三)设置音频源
设置音频源是告诉 MediaPlayer 要播放的音频文件来自哪里。MediaPlayer 提供了多种设置音频源的方式,常见的有以下两种:
使用本地文件路径:如果音频文件存储在本地设备上,可以直接使用文件路径来设置音频源。例如:
try { mediaPlayer.setDataSource("/data/local/tmp/your_audio_file.mp3"); } catch (Exception e) { e.printStackTrace(); } |
这里的/data/local/tmp/your_audio_file.mp3需要替换为实际的音频文件路径。在使用本地文件路径时,要确保应用具有访问该文件的权限,否则会导致设置音频源失败。
使用 URI:当音频文件的位置可以通过统一资源标识符(URI)来表示时,我们可以使用setDataSource(Context context, Uri uri)方法来设置音频源。例如,从应用的资源目录中获取音频文件:
Uri uri = Uri.parse("dataability:///resource/raw/your_audio_file.mp3"); try { mediaPlayer.setDataSource(getContext(), uri); } catch (Exception e) { e.printStackTrace(); } |
其中dataability:///resource/raw/your_audio_file.mp3是音频文件在资源目录下的 URI,开发者需要根据实际的资源路径进行修改。使用 URI 的方式更加灵活,适用于从不同来源获取音频文件的场景。
(四)准备与播放音频
在设置好音频源后,需要调用prepareAsync()方法来准备音频文件。这个方法是异步的,它会在后台线程中进行音频文件的准备工作,避免阻塞主线程,从而保证应用的流畅运行。当音频准备完成后,会触发OnPreparedListener回调。在这个回调中,我们可以调用start()方法来启动音频播放。示例代码如下:
mediaPlayer.prepareAsync(); mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { @Override public void onPrepared(MediaPlayer mp) { mp.start(); } }); |
这种异步准备和回调机制,使得音频播放的过程更加高效和稳定,尤其是在处理较大的音频文件或网络音频流时,能够避免因长时间的准备工作而导致应用界面卡顿,为用户提供更优质的播放体验。
(五)释放资源
当音频播放完成或者不再需要播放音频时,务必调用release()方法来释放 MediaPlayer 占用的资源。这是一个非常重要的步骤,如果不及时释放资源,可能会导致内存泄漏,影响应用的性能,甚至导致应用崩溃。释放资源的代码如下:
if (mediaPlayer != null) { mediaPlayer.stop(); mediaPlayer.release(); mediaPlayer = null; } |
通常在 Ability 的 onStop 或 onDestroy 方法中进行资源释放操作,以确保在应用暂停或销毁时,MediaPlayer 占用的资源能够被正确回收,为其他应用或系统进程腾出宝贵的资源空间。
三、音频录制功能实现
(一)权限申请
在 HarmonyOS 应用中实现音频录制功能,首先必须申请麦克风权限,这是获取音频输入的关键前提。因为音频录制涉及到对用户声音的采集,属于敏感操作,所以 HarmonyOS 将麦克风权限归类为用户授权类型。这意味着应用不仅要在配置文件中声明该权限,还需要在运行时动态请求用户授权。
在使用的模块下的module.json5中添加权限声明,示例代码如下:
{ "name": "ohos.permission.MICROPHONE", "reason": "$string:permission_desc_for_MICROPHONE", "usedScene": { "abilities": ["EntryAbility"], "when": "inuse" } } |
其中,reason字段用于说明申请权限的原因,会在向用户请求授权时展示,所以要填写清晰明了的描述,让用户能够理解应用为什么需要该权限;usedScene字段指定了权限的使用场景,这里表明在EntryAbility中使用,并且是在使用相关功能时才申请。
在代码中动态申请授权,可以参考以下示例:
import abilityAccessCtrl from '@ohos.abilityAccessCtrl'; import common from '@ohos.app.ability.common'; export function requestMicrophonePermission(context: common.UIAbilityContext, permissionResult: (allow: boolean) => void): void { let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager(); let permissions: Array<string> = ['ohos.permission.MICROPHONE']; atManager.requestPermissionsFromUser(context, permissions).then((data) => { let grantStatus: Array<number> = data.authResults; let length: number = grantStatus.length; for (let i = 0; i < length; i++) { if (grantStatus[i] === 0) { permissionResult(true); console.debug("麦克风授权成功:用户授权"); } else { permissionResult(false); console.debug("麦克风授权失败:用户拒绝"); return; } } }).catch((err: BusinessError) => { permissionResult(false); console.error(`Failed to request permissions from user. Code is ${err.code}, message is ${err.message}`); }); } |
在上述代码中,首先创建了AtManager实例,然后调用requestPermissionsFromUser方法向用户请求麦克风权限。该方法会返回一个 Promise,通过then方法处理授权成功的情况,通过catch方法处理请求权限过程中可能出现的错误。当用户授权成功时,grantStatus[i]的值为 0,此时调用permissionResult(true)通知调用者权限已被授予;如果用户拒绝授权,grantStatus[i]的值不为 0,调用permissionResult(false)并提示用户拒绝授权。
(二)AVRecorder 配置
AVRecorder 是 HarmonyOS 中用于音频和视频录制的重要类,在使用它进行音频录制前,需要进行一系列关键配置。以下是一些主要的配置参数:
音频源类型(audioSourceType):用于指定音频输入源,通常设置为media.AudioSourceType.AUDIO_SOURCE_TYPE_MIC,表示使用麦克风作为音频输入源。这是最常见的音频录制场景,例如录制语音备忘录、会议记录等。
采样率(audioSampleRate):它决定了每秒采集的音频样本数量,单位是赫兹(Hz)。常见的采样率有 44100Hz、48000Hz 等 。较高的采样率可以更准确地还原声音,但会占用更多的存储空间和处理资源。在选择采样率时,需要根据实际需求和应用场景进行权衡。例如,对于一般的语音录制,44100Hz 已经足够;而对于高质量的音乐录制,可能需要选择 48000Hz 甚至更高的采样率。
编码格式(audioCodec):指定音频的编码方式,当前 HarmonyOS 中 AVRecorder 支持的音频编码格式如media.CodecMimeType.AUDIO_AAC 。不同的编码格式在压缩比、音质和兼容性等方面存在差异。AAC 是一种广泛应用的音频编码格式,它在保持较高音质的同时,能够实现较好的压缩效果,文件体积相对较小,因此在很多场景中都被优先选用。
封装格式(fileFormat):确定录制生成的音频文件的封装格式,例如media.ContainerFormatType.CFT_MPEG_4A表示生成的音频文件为 M4A 格式 。封装格式决定了音频数据如何存储在文件中,以及文件的结构和元数据信息。M4A 格式是一种常见的音频封装格式,它与 AAC 编码格式配合良好,能够有效地存储和传输音频数据。
以下是一个 AVRecorder 配置的示例代码:
import media from '@ohos.multimedia.media'; let avProfile = { audioBitrate: 100000, // 音频比特率 audioChannels: 2, // 音频声道数 audioCodec: media.CodecMimeType.AUDIO_AAC, // 音频编码格式,当前只支持aac audioSampleRate: 48000, // 音频采样率 fileFormat: media.ContainerFormatType.CFT_MPEG_4A // 封装格式,当前只支持m4a }; let avConfig = { audioSourceType: media.AudioSourceType.AUDIO_SOURCE_TYPE_MIC, // 音频输入源,这里设置为麦克风 profile: avProfile, url: 'fd://35' // 参考应用文件访问与管理中的开发示例获取创建的音频文件fd填入此处 }; |
在这个示例中,首先定义了一个avProfile对象,设置了音频录制的各项参数,包括音频比特率、声道数、编码格式、采样率和封装格式。然后创建了avConfig对象,将音频源类型设置为麦克风,并关联了前面定义的avProfile对象。同时,还需要指定录制文件的存储位置,这里使用fd://35的形式,其中35需要替换为实际通过文件操作获取到的文件描述符(fd)。在实际应用中,获取文件描述符的过程需要参考 HarmonyOS 的文件访问与管理相关文档和示例代码,确保能够正确创建和访问用于存储录制音频的文件。
(三)录音操作控制
完成权限申请和 AVRecorder 配置后,就可以进行录音操作控制了。这包括开始、暂停、恢复和停止录音等操作,同时要妥善处理录音过程中可能出现的异常情况,以保证录音功能的稳定性和可靠性。
开始录音:调用 AVRecorder 的start()方法开始录音。在调用该方法前,需要确保 AVRecorder 已经完成配置并处于prepared状态。示例代码如下:
avRecorder.start().then(() => { console.log('录音开始成功'); }).catch((err) => { console.error(`录音开始失败,错误信息:${err.message}`); }); |
在这个代码片段中,start()方法返回一个 Promise,通过then方法处理录音开始成功的情况,在控制台打印 “录音开始成功”;通过catch方法捕获可能出现的错误,并在控制台输出错误信息,以便开发者进行调试和问题排查。
暂停录音:当需要暂停录音时,调用pause()方法。但要注意,只有在 AVRecorder 处于started状态时,调用pause()方法才是合理的状态切换。示例代码如下:
if (avRecorder.state ==='started') { avRecorder.pause().then(() => { console.log('录音暂停成功'); }).catch((err) => { console.error(`录音暂停失败,错误信息:${err.message}`); }); } |
这里首先检查 AVRecorder 的当前状态是否为started,如果是,则调用pause()方法。同样,通过then和catch方法分别处理暂停成功和失败的情况。
恢复录音:如果之前暂停了录音,可以调用resume()方法恢复录音。只有在 AVRecorder 处于paused状态时,才能成功调用该方法。示例代码如下:
if (avRecorder.state === 'paused') { avRecorder.resume().then(() => { console.log('录音恢复成功'); }).catch((err) => { console.error(`录音恢复失败,错误信息:${err.message}`); }); } |
此代码逻辑与暂停录音类似,先检查状态,再进行恢复操作,并处理相应的结果。
停止录音:当录音完成或需要停止录音时,调用stop()方法。停止录音后,通常还需要调用reset()方法重置 AVRecorder 的状态,使其回到idle状态,以便进行下一次录音配置和操作;最后调用release()方法释放 AVRecorder 占用的资源,避免内存泄漏。示例代码如下:
if (avRecorder.state ==='started' || avRecorder.state === 'paused') { avRecorder.stop().then(() => { console.log('录音停止成功'); avRecorder.reset().then(() => { console.log('AVRecorder已重置'); avRecorder.release().then(() => { console.log('AVRecorder资源已释放'); }).catch((err) => { console.error(`释放AVRecorder资源失败,错误信息:${err.message}`); }); }).catch((err) => { console.error(`重置AVRecorder失败,错误信息:${err.message}`); }); }).catch((err) => { console.error(`录音停止失败,错误信息:${err.message}`); }); } |
这段代码展示了停止录音的完整流程,先判断 AVRecorder 的状态是否为started或paused,如果是,则依次调用stop()、reset()和release()方法,并在每个操作成功或失败时进行相应的日志记录和错误处理。
在录音过程中,还可能出现各种异常情况,例如设备故障、权限被收回等。为了及时处理这些异常,可以为 AVRecorder 添加错误监听事件。示例代码如下:
avRecorder.on('error', (err) => { console.error(`录音过程中出现错误,错误代码:${err.code},错误信息:${err.message}`); // 这里可以添加一些错误处理逻辑,比如提示用户、尝试重新录制等 }); |
通过on('error', callback)方法,当 AVRecorder 在录音过程中发生错误时,会调用传入的回调函数callback,在回调函数中可以获取到错误信息,包括错误代码和详细的错误描述,开发者可以根据这些信息进行针对性的处理,例如向用户显示友好的错误提示,或者尝试重新初始化 AVRecorder 并进行录音操作,以提高应用的稳定性和用户体验。
四、视频播放功能实现
(一)播放框架概述
HarmonyOS 的视频播放框架旨在为开发者提供高效、便捷且强大的视频播放能力。其设计目标围绕着低消耗、简单易用和灵活扩展展开。低消耗意味着在播放视频时,框架能够优化资源的使用,降低设备的功耗,确保即使在长时间播放视频的情况下,设备也能保持良好的性能表现,不会出现过热、卡顿等问题。简单易用体现在框架提供了简洁明了的 API,无论是对于经验丰富的开发者还是初学者,都能快速上手并实现基本的视频播放功能。同时,它还提供了多种接口形式,如 JS 接口和结合 ArkUI 提供的 UI 控件接口,满足不同开发场景和习惯的需求。灵活扩展则使得框架能够适应不断发展的视频技术和多样化的应用需求,开发者可以根据实际情况对播放引擎进行增强、扩展或替换,以实现更丰富的功能和更好的播放效果。
从架构上看,播放框架主要由中间件和硬件适配层组成。中间件的核心是基于引擎提供各种各样的服务能力,目前 HarmonyOS 提供了 GStreamer 引擎和 HiStreamer 引擎 ,这两套引擎功能都较为齐全,能够支持多种常见的视频格式和编码方式。例如,GStreamer 引擎是一个功能强大的多媒体框架,它具有丰富的插件生态系统,能够处理各种复杂的多媒体任务;HiStreamer 引擎则以其轻量化和高效性著称,基于传统的 pipeline,通过插件化机制增强了音视频的编解码和解析能力,在处理一些对性能要求较高的视频播放场景时表现出色。在硬件适配层,即 HDF(Hardware Driver Foundation)层,提供了兼容设计,能够适配不同的硬件设备,确保视频播放功能在各种终端设备上都能稳定运行。这种分层架构的设计,使得播放框架具有良好的可维护性和可扩展性,开发者可以专注于应用层的开发,而无需过多关注底层硬件的差异和复杂的多媒体处理细节。
(二)使用 MediaPlayer 播放视频
使用 MediaPlayer 播放视频的步骤与播放音频有相似之处,但也存在一些关键的区别。在创建 MediaPlayer 实例方面,与音频播放一致,通过MediaPlayer mediaPlayer = new MediaPlayer();即可创建。然而,在设置视频源时,同样可以使用本地文件路径或 URI 的方式。例如,使用本地文件路径设置视频源:
try { mediaPlayer.setDataSource("/data/local/tmp/your_video_file.mp4"); } catch (Exception e) { e.printStackTrace(); } |
这里的/data/local/tmp/your_video_file.mp4需替换为实际的视频文件路径,并且要确保应用具有访问该文件的权限。使用 URI 设置视频源时,示例如下:
Uri uri = Uri.parse("dataability:///resource/raw/your_video_file.mp4"); try { mediaPlayer.setDataSource(getContext(), uri); } catch (Exception e) { e.printStackTrace(); } |
其中dataability:///resource/raw/your_video_file.mp4是视频文件在资源目录下的 URI,开发者需根据实际资源路径修改。
与音频播放最大的不同在于,视频播放需要设置一个 Surface 用于显示视频画面。Surface 是一个可以在其上绘制图形的对象,在视频播放中,它充当了视频画面的载体。我们可以通过创建 SurfaceView 来获取 Surface,然后将其设置给 MediaPlayer。首先,在 XML 布局文件中添加 SurfaceView:
<ohos.agp.components.SurfaceView ohos:id="$+id:surface_view" ohos:height="match_parent" ohos:width="match_parent" /> |
然后在代码中获取 SurfaceView 并设置给 MediaPlayer:
SurfaceView surfaceView = (SurfaceView) findComponentById(ResourceTable.Id_surface_view); Surface surface = surfaceView.getSurface(); mediaPlayer.setVideoSurface(surface); |
在准备和播放视频阶段,与音频播放类似,调用prepareAsync()方法异步准备视频,当准备完成后,通过OnPreparedListener回调中的start()方法启动播放:
mediaPlayer.prepareAsync(); mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { @Override public void onPrepared(MediaPlayer mp) { mp.start(); } }); |
通过以上步骤,就可以实现基本的视频播放功能,将视频文件的内容在设备屏幕上展示出来。
(三)处理视频播放的交互
为了提升用户体验,视频播放应用通常需要实现一系列交互功能,如播放进度控制、音量调节、暂停与播放切换等。
播放进度控制可以通过 SeekBar 组件和 MediaPlayer 的seekTo(int msec)方法来实现。SeekBar 是一个拖动条组件,用户可以通过拖动它来改变视频的播放位置。首先,在 XML 布局文件中添加 SeekBar:
<ohos.agp.components.SeekBar ohos:id="$+id:seek_bar" ohos:height="wrap_content" ohos:width="match_parent" /> |
然后在代码中获取 SeekBar 并为其添加进度改变监听器。当用户拖动 SeekBar 时,监听器会获取当前的进度值,并调用seekTo(int msec)方法将视频播放位置调整到对应的时间点。示例代码如下:
SeekBar seekBar = (SeekBar) findComponentById(ResourceTable.Id_seek_bar); seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { if (fromUser) { mediaPlayer.seekTo(progress); } } @Override public void onStartTrackingTouch(SeekBar seekBar) { // 开始拖动时的操作 } @Override public void onStopTrackingTouch(SeekBar seekBar) { // 停止拖动时的操作 } }); |
同时,为了实时更新 SeekBar 的进度,使其与视频的实际播放进度保持一致,可以通过一个定时任务来获取视频的当前播放位置,并更新 SeekBar 的进度。例如,使用 Handler 实现定时更新:
Handler handler = new Handler(); Runnable runnable = new Runnable() { @Override public void run() { if (mediaPlayer!= null) { int currentPosition = mediaPlayer.getCurrentPosition(); seekBar.setProgress(currentPosition); } handler.postDelayed(this, 1000); } }; handler.post(runnable); |
这样,每隔 1 秒就会获取一次视频的当前播放位置,并更新 SeekBar 的进度,让用户能够直观地了解视频的播放进度。
音量调节可以通过 AudioManager 类来实现。AudioManager 是 HarmonyOS 中用于管理音频相关设置的类,我们可以通过它来获取当前的音量,并实现音量的增加和减少操作。首先获取 AudioManager 实例:
AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); |
然后通过getStreamVolume(int streamType)方法获取当前的音量,streamType参数指定音频流类型,对于视频播放,通常使用AudioManager.STREAM_MUSIC。例如:
int currentVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC); |
实现音量增加和减少的操作可以通过adjustVolume(int direction, int flags)方法,direction参数指定调节方向,AudioManager.ADJUST_RAISE表示增加音量,AudioManager.ADJUST_LOWER表示减少音量。示例代码如下:
// 增加音量 audioManager.adjustVolume(AudioManager.ADJUST_RAISE, AudioManager.FLAG_SHOW_UI); // 减少音量 audioManager.adjustVolume(AudioManager.ADJUST_LOWER, AudioManager.FLAG_SHOW_UI); |
这里的AudioManager.FLAG_SHOW_UI标志表示在调节音量时显示系统的音量调节 UI,让用户能够直观地看到音量的变化。
暂停与播放切换是视频播放中最基本的交互功能之一,通过 MediaPlayer 的pause()和start()方法即可实现。可以在界面上添加一个按钮,当用户点击按钮时,根据当前视频的播放状态来决定执行暂停还是播放操作。示例代码如下:
Button playPauseButton = (Button) findComponentById(ResourceTable.Id.play_pause_button); playPauseButton.setOnClickListener(new Component.OnClickListener() { @Override public void onClick(Component component) { if (mediaPlayer.isPlaying()) { mediaPlayer.pause(); playPauseButton.setText("播放"); } else { mediaPlayer.start(); playPauseButton.setText("暂停"); } } }); |
通过以上对播放进度控制、音量调节、暂停与播放切换等交互功能的实现,能够为用户提供更加丰富和便捷的视频播放体验,满足用户在观看视频过程中的各种操作需求。
五、视频录制功能实现
(一)相机权限与配置
在 HarmonyOS 应用中实现视频录制功能,首先需要申请相机权限。相机权限属于敏感权限,HarmonyOS 对其管理较为严格,应用不仅要在module.json5文件中声明权限,还需要在运行时动态请求用户授权。在module.json5文件中添加相机权限声明的示例代码如下:
{ "name": "ohos.permission.CAMERA", "reason": "$string:permission_desc_for_CAMERA", "usedScene": { "abilities": ["EntryAbility"], "when": "inuse" } } |
这里的reason字段用于向用户解释申请权限的原因,usedScene字段指定了权限的使用场景,表明在EntryAbility中使用该权限,并且是在使用相关功能时才申请。
在运行时动态请求相机权限,可以使用abilityAccessCtrl模块中的requestPermissionsFromUser方法。示例代码如下:
import abilityAccessCtrl from '@ohos.abilityAccessCtrl'; import common from '@ohos.app.ability.common'; export function requestCameraPermission(context: common.UIAbilityContext, permissionResult: (allow: boolean) => void): void { let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager(); let permissions: Array<string> = ['ohos.permission.CAMERA']; atManager.requestPermissionsFromUser(context, permissions).then((data) => { let grantStatus: Array<number> = data.authResults; let length: number = grantStatus.length; for (let i = 0; i < length; i++) { if (grantStatus[i] === 0) { permissionResult(true); console.debug("相机授权成功:用户授权"); } else { permissionResult(false); console.debug("相机授权失败:用户拒绝"); return; } } }).catch((err: BusinessError) => { permissionResult(false); console.error(`Failed to request permissions from user. Code is ${err.code}, message is ${err.message}`); }); } |
在上述代码中,首先创建了AtManager实例,然后调用requestPermissionsFromUser方法向用户请求相机权限。该方法返回一个 Promise,通过then方法处理授权成功的情况,通过catch方法处理请求权限过程中可能出现的错误。当用户授权成功时,grantStatus[i]的值为 0,此时调用permissionResult(true)通知调用者权限已被授予;如果用户拒绝授权,grantStatus[i]的值不为 0,调用permissionResult(false)并提示用户拒绝授权。
配置相机参数是实现高质量视频录制的关键步骤。相机参数包括分辨率、帧率、对焦模式、曝光模式等 。不同的参数设置会对视频的质量和性能产生显著影响。例如,较高的分辨率可以提供更清晰的图像细节,但会占用更多的存储空间和网络带宽;较高的帧率可以使视频播放更加流畅,但也会增加设备的处理负担。因此,在配置相机参数时,需要根据实际需求和设备性能进行权衡和选择。
以设置分辨率和帧率为例,在 HarmonyOS 中可以使用CameraConfiguration类来配置相机参数。示例代码如下:
import ohos.media.camera.CameraConfiguration; import ohos.media.camera.CameraDevice; CameraDevice cameraDevice = getCameraDevice(); // 获取相机设备实例 CameraConfiguration configuration = new CameraConfiguration(cameraDevice); configuration.setPreviewSize(1920, 1080); // 设置预览分辨率为1920x1080 configuration.setPreviewFpsRange(new int[]{30, 30}); // 设置预览帧率为30fps cameraDevice.applyConfiguration(configuration); // 应用配置 |
在上述代码中,首先获取相机设备实例,然后创建CameraConfiguration对象,并通过setPreviewSize和setPreviewFpsRange方法分别设置预览分辨率和帧率。最后,调用applyConfiguration方法将配置应用到相机设备上。除了分辨率和帧率,还可以通过CameraConfiguration类设置其他相机参数,如对焦模式、曝光模式等 。例如,设置自动对焦模式的代码如下:
configuration.setFocusMode(CameraConfiguration.FOCUS_MODE_CONTINUOUS_PICTURE); |
设置自动曝光模式的代码如下:
configuration.setExposureMode(CameraConfiguration.EXPOSURE_MODE_AUTO); |
通过合理配置这些相机参数,可以满足不同场景下的视频录制需求,为用户提供高质量的视频录制体验。
(二)使用 Camera 进行视频录制
在 HarmonyOS 中,使用 Camera 进行视频录制的核心步骤是获取视频流并结合 AVRecorder 进行录制。首先,需要创建相机输入和输出流。相机输入流用于获取相机采集的数据,相机输出流则用于将视频数据输出到 AVRecorder 进行录制。
创建相机输入流的示例代码如下:
import camera from '@ohos.multimedia.camera'; // 获取相机管理器 let cameraManager: camera.CameraManager = camera.getCameraManager(context); // 获取相机列表 let cameraArray: Array<camera.CameraDevice> = cameraManager.getSupportedCameras(); // 创建相机输入 let cameraInput: camera.CameraInput = cameraManager.createCameraInput(cameraArray[0]); |
在上述代码中,首先通过camera.getCameraManager(context)获取相机管理器,然后使用getSupportedCameras方法获取设备支持的相机列表。最后,选择第一个相机设备并通过createCameraInput方法创建相机输入流。
创建相机预览输出流和视频输出流的示例代码如下:
// 创建预览输出流 let previewOutput: camera.PreviewOutput = cameraManager.createPreviewOutput(previewProfilesArray[0], surfaceId); // 创建视频输出流 let videoProfile: undefined | camera.VideoProfile = videoProfilesArray.find((profile: camera.VideoProfile) => { return profile.size.width === aVRecorderProfile.videoFrameWidth && profile.size.height === aVRecorderProfile.videoFrameHeight; }); let videoOutput: camera.VideoOutput | undefined = undefined; if (videoProfile) { videoOutput = cameraManager.createVideoOutput(videoProfile, videoSurfaceId); } |
在这段代码中,首先创建预览输出流,其中previewProfilesArray是相机支持的预览配置文件数组,surfaceId是用于显示预览画面的 Surface 的 ID。然后,从相机支持的视频配置文件数组videoProfilesArray中找到与 AVRecorder 配置的视频分辨率相匹配的视频配置文件videoProfile,并使用createVideoOutput方法创建视频输出流,videoSurfaceId是 AVRecorder 用于接收视频数据的 Surface 的 ID。
创建好相机输入和输出流后,需要配置相机会话,将输入流和输出流添加到会话中,并启动会话。示例代码如下:
// 创建会话 let videoSession: camera.CaptureSession | undefined = undefined; videoSession = cameraManager.createCaptureSession(); videoSession.beginConfig(); // 添加相机输入流 videoSession.addInput(cameraInput); // 添加预览输出流 videoSession.addOutput(previewOutput); // 添加视频输出流 if (videoOutput) { videoSession.addOutput(videoOutput); } // 提交会话配置 videoSession.commitConfig(); // 启动会话 videoSession.start(); |
在上述代码中,首先创建相机会话videoSession,然后使用beginConfig方法开始配置会话。接着,将相机输入流、预览输出流和视频输出流添加到会话中。完成配置后,调用commitConfig方法提交配置,并使用start方法启动会话。此时,相机开始采集视频数据,并将数据输出到预览输出流和视频输出流中。
AVRecorder 是 HarmonyOS 中用于音视频录制的重要类,它负责将相机输出的视频流进行编码、封装,并保存为视频文件。在使用 AVRecorder 进行视频录制前,需要进行一系列配置,包括设置视频源类型、编码格式、封装格式、视频分辨率、帧率等参数。配置 AVRecorder 的示例代码如下:
import media from '@ohos.multimedia.media'; // 创建AVRecorder实例 let avRecorder: media.AVRecorder = await media.createAVRecorder(); // 配置AVRecorder参数 let aVRecorderProfile: media.AVRecorderProfile = { fileFormat: media.ContainerFormatType.CFT_MPEG_4, // 视频文件封装格式,只支持MP4 videoBitrate: 2000000, // 视频比特率 videoCodec: media.CodecMimeType.VIDEO_AVC, // 视频文件编码格式,支持avc格式 videoFrameWidth: 640, // 视频分辨率的宽 videoFrameHeight: 480, // 视频分辨率的高 videoFrameRate: 30 // 视频帧率 }; let aVRecorderConfig: media.AVRecorderConfig = { videoSourceType: media.VideoSourceType.VIDEO_SOURCE_TYPE_SURFACE_YUV, // 视频源类型,支持YUV和ES两种格式 profile: aVRecorderProfile, url: 'fd://' + file.fd, // 参考应用文件访问与管理中的开发示例获取创建的音频文件fd填入此处 rotation: 0 // 视频旋转角度,默认为0不旋转,支持的值为0、90、180、270 }; // 准备AVRecorder await avRecorder.prepare(aVRecorderConfig); |
在上述代码中,首先创建 AVRecorder 实例,然后配置录制参数。aVRecorderProfile对象设置了视频的封装格式、比特率、编码格式、分辨率和帧率等参数;aVRecorderConfig对象设置了视频源类型、配置文件、录制文件的存储路径(url)和视频旋转角度。最后,调用prepare方法准备 AVRecorder,使其处于可录制状态。
完成上述步骤后,相机采集的视频流就会通过视频输出流传递给 AVRecorder,AVRecorder 根据配置的参数对视频流进行编码、封装,并将录制的视频保存到指定的文件路径中。
(三)录制控制与文件保存
实现录制的开始、暂停、停止操作是视频录制功能的基本需求。在 HarmonyOS 中,通过 AVRecorder 和相机输出流的相关方法可以轻松实现这些控制操作。
开始录制时,需要同时启动相机的视频输出流和 AVRecorder 的录制功能。示例代码如下:
// 启动相机视频输出流 if (videoOutput) { videoOutput.start(); } // 启动AVRecorder录制 avRecorder.start().then(() => { console.log('视频录制开始成功'); }).catch((err) => { console.error(`视频录制开始失败,错误信息:${err.message}`); }); |
在上述代码中,首先判断videoOutput是否存在,如果存在则调用其start方法启动相机视频输出流。然后,调用 AVRecorder 的start方法开始录制视频,start方法返回一个 Promise,通过then方法处理录制开始成功的情况,通过catch方法捕获并处理可能出现的错误。
暂停录制时,需要同时暂停相机的视频输出流和 AVRecorder 的录制功能。示例代码如下:
// 暂停相机视频输出流 if (videoOutput) { videoOutput.stop(); } // 暂停AVRecorder录制 if (avRecorder.state ==='started') { avRecorder.pause().then(() => { console.log('视频录制暂停成功'); }).catch((err) => { console.error(`视频录制暂停失败,错误信息:${err.message}`); }); } |
在这段代码中,首先判断videoOutput是否存在,如果存在则调用其stop方法暂停相机视频输出流。然后,检查 AVRecorder 的当前状态是否为started,如果是则调用pause方法暂停录制,并通过then和catch方法处理暂停操作的结果。
停止录制时,同样需要停止相机的视频输出流和 AVRecorder 的录制功能,并释放相关资源。示例代码如下:
// 停止相机视频输出流 if (videoOutput) { videoOutput.stop(); } // 停止AVRecorder录制 if (avRecorder.state ==='started' || avRecorder.state === 'paused') { avRecorder.stop().then(() => { console.log('视频录制停止成功'); avRecorder.reset().then(() => { console.log('AVRecorder已重置'); avRecorder.release().then(() => { console.log('AVRecorder资源已释放'); }).catch((err) => { console.error(`释放AVRecorder资源失败,错误信息:${err.message}`); }); }).catch((err) => { console.error(`重置AVRecorder失败,错误信息:${err.message}`); }); }).catch((err) => { console.error(`视频录制停止失败,错误信息:${err.message}`); }); } |
在上述代码中,首先停止相机视频输出流。然后,检查 AVRecorder 的状态,如果处于started或paused状态,则调用stop方法停止录制。停止录制后,依次调用reset方法重置 AVRecorder 的状态,使其回到初始状态,以便进行下一次录制配置和操作;最后调用release方法释放 AVRecorder 占用的资源,避免内存泄漏,并通过then和catch方法处理每个操作的结果。
将录制的视频保存到指定路径是视频录制功能的最终目标。在配置 AVRecorder 时,通过aVRecorderConfig对象的url参数指定了录制文件的存储路径,例如url: 'fd://' + file.fd ,其中file.fd是通过文件操作获取到的文件描述符(fd)。在实际应用中,需要根据具体的文件访问与管理方式获取文件描述符,并确保应用具有对该文件的读写权限。
在录制完成后,视频文件就会保存到指定的路径中。为了方便用户管理和使用录制的视频,还可以在应用中提供一些文件管理功能,例如显示录制视频的列表、提供视频的播放和分享功能等。通过这些功能,用户可以更加便捷地查看和使用自己录制的视频,提升应用的实用性和用户体验。
六、多媒体文件格式转换和编辑
(一)格式转换的必要性
在多媒体应用开发中,不同设备和平台对多媒体格式的支持存在显著差异。例如,某些老旧设备可能仅支持常见的 MP3 音频格式和 MP4 视频格式,而对于一些新兴的、高压缩比或特殊用途的格式,如 FLAC 音频格式、AV1 视频格式等则无法识别和播放。在不同的平台上,像 Windows 系统原生支持的多媒体格式与 HarmonyOS、iOS 系统所支持的格式也不尽相同。这就导致当我们开发的应用需要在多种设备和平台上运行时,如果多媒体文件格式不兼容,就会出现无法播放或显示异常的问题。因此,为了确保多媒体内容能够在各种设备和平台上稳定、流畅地运行,实现多媒体文件格式转换是非常必要的。它能够使我们的应用适应不同的环境,满足更广泛用户的需求,提升应用的通用性和用户体验。
(二)HarmonyOS 的格式转换工具与 API
在 HarmonyOS 中,AVCodec Kit 是实现多媒体文件格式转换的重要工具。它提供了丰富的 API,能够实现音频、视频格式的转换。以视频格式转换为例,我们可以使用AVTranscoder类来完成转换操作。
首先,需要创建AVTranscoder实例,代码如下:
import { media } from '@ohos.multimedia.media'; let avTranscoder: media.AVTranscoder; media.createAVTranscoder().then((transcoder: media.AVTranscoder) => { avTranscoder = transcoder; }, (error) => { console.error(`createAVTranscoder failed`); }); |
在创建实例后,需要设置转码的源文件和目标文件。这里的源文件和目标文件可以通过文件描述符(fd)来指定。例如,设置源文件属性fdSrc和目标文件属性fdDst:
// 设置转码的源文件属性fdSrc avTranscoder.fdSrc = sourceFileFd; // 设置转码的目标文件属性fdDst avTranscoder.fdDst = targetFileFd; |
其中sourceFileFd和targetFileFd需要根据实际情况获取,比如使用本地资源转码时,要确认资源文件可用,并使用应用沙箱路径访问对应资源;如果使用ResourceManager.getRawFd打开 HAP 资源文件描述符,可参考ResourceManager API 参考。
接下来,配置视频转码参数,调用prepare()接口。配置参数时要注意,prepare接口的入参avConfig中仅设置转码相关的配置参数,示例代码如下:
let avConfig: media.AVTranscoderConfig = { audioBitrate: 100000, // 音频比特率 audioCodec: media.CodecMimeType.AUDIO_AAC, fileFormat: media.ContainerFormatType.CFT_MPEG_4A, videoBitrate: 2000000, // 视频比特率 videoCodec: media.CodecMimeType.VIDEO_AVC, videoFrameWidth: 640, // 视频分辨率的宽 videoFrameHeight: 480 // 视频分辨率的高 }; avTranscoder.prepare(avConfig).then(() => { console.log('Invoke prepare succeeded.'); }, (err) => { console.error(`Invoke prepare failed, code is ${err.code}, message is ${err.message}`); }); |
完成上述配置后,就可以调用start()方法开始转码:
avTranscoder.start(); |
通过以上步骤,利用 AVCodec Kit 提供的AVTranscoder类及其相关 API,就能够在 HarmonyOS 应用中实现视频格式的转换。对于音频格式转换,原理和步骤类似,只需根据音频的特点和需求,合理配置相关参数即可。
(三)多媒体文件编辑功能
HarmonyOS 提供了一系列 API 来实现多媒体文件的剪辑、合并等编辑操作。以视频剪辑为例,我们可以利用AVTranscoder类结合时间轴的概念来实现。通过设置起始时间和结束时间,AVTranscoder可以从原始视频中提取出指定时间段的内容,从而实现剪辑功能。例如,假设我们要剪辑一个视频,从第 5 秒开始,到第 10 秒结束,代码实现如下:
// 设置转码参数时,添加剪辑相关参数 let avConfig: media.AVTranscoderConfig = { // 其他转码参数... startTime: 5000, // 起始时间,单位毫秒 endTime: 10000 // 结束时间,单位毫秒 }; // 配置转码参数 avTranscoder.prepare(avConfig).then(() => { // 开始转码,此时输出的视频即为剪辑后的视频 avTranscoder.start(); }, (err) => { console.error(`Invoke prepare failed, code is ${err.code}, message is ${err.message}`); }); |
对于视频合并操作,可以通过将多个视频的轨道数据进行合并来实现。首先,需要使用解封装器(如AVDemuxer)将每个视频文件解封装,获取其视频流数据和音频流数据。然后,将这些流数据按照一定的顺序合并到一个新的视频轨道和音频轨道中。最后,使用封装器(如AVMuxer)将合并后的轨道数据封装成一个新的视频文件。在 HarmonyOS 中,虽然没有直接提供一个简单的合并 API,但通过组合使用这些音视频处理类,可以实现视频合并的功能。具体实现过程涉及到对音视频数据的读取、处理和重新封装,需要开发者具备一定的音视频处理知识和编程技巧。音频文件的剪辑和合并操作原理与视频类似,也是通过对音频数据的读取、处理和重新封装来实现。例如,音频剪辑可以通过解封装音频文件,定位到指定的时间点,读取该时间范围内的音频数据,然后重新封装成新的音频文件;音频合并则是将多个音频文件的音频数据依次合并到一个新的音频文件中。通过这些 API 和操作,开发者可以在 HarmonyOS 应用中实现丰富的多媒体文件编辑功能,满足用户对多媒体内容个性化处理的需求。
七、常见问题与解决方案
在 HarmonyOS 应用开发中,实现音频和视频功能时可能会遇到各种问题,下面为大家列举一些常见问题及解决方案:
格式不支持:当使用 MediaPlayer 播放音频或视频时,可能会遇到不支持的文件格式,导致无法播放。解决方案是在播放前对文件格式进行检查和转换。可以通过查询 HarmonyOS 支持的多媒体格式列表,确认文件格式是否在支持范围内。对于不支持的格式,利用 AVCodec Kit 提供的转码工具和 API,将其转换为支持的格式。例如,将 FLAC 音频格式转换为 MP3 格式,将 AVI 视频格式转换为 MP4 格式等。
权限不足:在进行音频录制、视频录制或访问多媒体文件时,如果权限不足,会导致操作失败。对于权限问题,首先要在module.json5文件中正确声明所需权限,如麦克风权限(ohos.permission.MICROPHONE)、相机权限(ohos.permission.CAMERA)、读取音频文件权限(ohos.permission.READ_AUDIO)等 。然后在运行时,使用abilityAccessCtrl模块中的requestPermissionsFromUser方法动态请求用户授权。在请求授权时,要向用户清晰地解释申请权限的原因,提高用户授权的成功率。同时,在权限申请成功或失败时,要进行相应的逻辑处理,比如权限申请失败时,提示用户开启权限的方法,引导用户进行操作。
资源冲突:当多个组件同时使用多媒体资源时,可能会出现资源冲突的情况。例如,同时有两个音频播放任务在竞争音频输出设备,或者视频录制和相机预览同时占用相机资源等。为了避免资源冲突,在开发过程中,要合理规划多媒体资源的使用。可以使用单例模式来管理多媒体资源,确保同一时间只有一个组件能够访问和使用特定的资源。例如,创建一个音频播放管理器类,使用单例模式来控制音频播放的实例,当有新的音频播放请求时,先检查当前是否有正在播放的音频,如果有,则暂停或停止当前播放,再进行新的播放操作。在进行视频录制和相机预览等操作时,也要进行资源的协调和管理,避免冲突的发生。
八、总结与展望
在 HarmonyOS 应用开发中,实现音频和视频功能为应用带来了丰富的交互体验和更广阔的应用场景。通过 MediaPlayer、AVRecorder、Camera 等关键 API,我们能够轻松实现音频和视频的播放、录制功能,并且利用 AVCodec Kit 等工具完成多媒体文件的格式转换和编辑操作。在这个过程中,我们需要关注权限申请、资源管理以及各种异常情况的处理,以确保应用的稳定性和可靠性。
随着技术的不断发展,未来多媒体开发的趋势将更加注重用户体验的提升、跨平台兼容性以及与新兴技术的融合。例如,随着 5G 技术的普及,高清、流畅的视频流传输将成为常态,这对视频播放和录制功能提出了更高的要求;人工智能技术在多媒体内容分析、智能编辑等方面的应用也将日益广泛;虚拟现实(VR)和增强现实(AR)技术与多媒体的结合,将为用户带来沉浸式的体验,开辟新的应用领域。
希望本文能够为大家在 HarmonyOS 多媒体开发的道路上提供有价值的参考和帮助。相信大家在实践过程中,能够不断探索和创新,开发出更多功能强大、体验优秀的多媒体应用。
相关文章:
HarmonyOS学习第18天:多媒体功能全解析
一、开篇引入 在当今数字化时代,多媒体已经深度融入我们的日常生活。无论是在工作中通过视频会议进行沟通协作,还是在学习时借助在线课程的音频讲解加深理解,亦或是在休闲时光用手机播放音乐放松身心、观看视频打发时间,多媒体功…...
多模态融合的分类、跨模态对齐的方法
两者的主要区别 维度扩模态对齐扩模态融合目标对齐模态间的表示,使其语义一致融合模态间的信息,生成联合表示关注点模态间的相似性和语义一致性模态间的互补性和信息整合空间映射到共享的公共语义空间生成新的联合特征空间方法对比学习、共享空间、注意…...
软件高级架构师 - 软件工程
补充中 测试 测试类型 静态测试 动态测试 测试阶段 单元测试中,包含性能测试,如下: 集成测试中,包含以下: 维护 遗留系统处置 高水平低价值:采取集成 对于这类系统,采取 集成 的方式&…...
Uniapp项目运行到微信小程序、H5、APP等多个平台教程
摘要:Uniapp作为一款基于Vue.js的跨平台开发框架,支持“一次开发,多端部署”。本文将手把手教你如何将Uniapp项目运行到微信小程序、H5、APP等多个平台,并解析常见问题。 一、环境准备 在开始前,请确保已安装以下工具…...
【JavaWeb12】数据交换与异步请求:JSON与Ajax的绝妙搭配是否塑造了Web的交互革命?
文章目录 🌍一. 数据交换--JSON❄️1. JSON介绍❄️2. JSON 快速入门❄️3. JSON 对象和字符串对象转换❄️4. JSON 在 java 中使用❄️5. 代码演示 🌍二. 异步请求--Ajax❄️1. 基本介绍❄️2. JavaScript 原生 Ajax 请求❄️3. JQuery 的 Ajax 请求 &a…...
2025-03-10 吴恩达机器学习1——机器学习概述
文章目录 1 监督学习1.1 回归1.2 分类 2 无监督学习2.1 聚类2.2 异常检测2.3 降维 3 使用 Jupyter Notebook 1959 年,Arthur Samuel 将机器学习定义如下: Field of study that gives computers the ability to learn without being explicitly pro…...
Spring Boot整合WebSocket
目录 ?引言 1.WebSocket 基础知识 ?1.1 什么是 WebSocket? ?1.2 WebSocket 的应用场景 ?2.Spring Boot WebSocket 整合步骤 2.1 创建 Spring Boot 项目 2.2 添加 Maven 依赖 2.3 配置 WebSocket 2.4 创建 WebSocket 控制器 2.5 创建前端页面 引言 在…...
PostgreSQL - Windows PostgreSQL 下载与安装
Windows PostgreSQL 下载与安装 1、PostgreSQL 下载 下载地址:https://www.enterprisedb.com/downloads/postgres-postgresql-downloads 2、PostgreSQL 安装 启动安装程序 -> 点击 【Next】 指定安装路径 -> 点击 【Next】 默认勾选 -> 点击 【Next】 指…...
【Java面试题汇总】Java面试100道最新合集!
1.说说你对面向对象的理解 得分点 封装,继承,多态、概念、实现方式和优缺点 面向对象的三大基本特征是:封装、继承、多态。 封装:将对象的状态和行为包装在一个类中并对外界隐藏实现的细节,可以通过访问修饰符控制成员的访问权限,…...
【LLM】kimi 1.5模型架构和训练流程
note 推出两个多模态模型,深度思考模型 long-CoT 对标 o1,通用模型 short-CoT 模型对标 gpt-4o。 文章目录 note一、kimi 1.5模型训练流程预训练SFT训练long-CoT SFTRL训练long2short 小结Reference 一、kimi 1.5模型训练流程 推出两个多模态模型&…...
Android Studio 配置国内镜像源
Android Studio版本号:2022.1.1 Patch 2 1、配置gradle国内镜像,用腾讯云 镜像源地址:https\://mirrors.cloud.tencent.com/gradle 2、配置Android SDK国内镜像 地址:Index of /AndroidSDK/...
永洪科技深度分析实战,零售企业的销量预测
随着人工智能技术的不断发展,智能预测已经成为各个领域的重要应用之一。现在,智能预测技术已经广泛应用于金融、零售、医疗、能源等领域,为企业和个人提供决策支持。 智能预测技术通过分析大量的数据,利用机器学习和深度学习算法…...
Pytorch实现之利用CGAN鉴别真假图像
简介 简介:利用生成对抗网络来鉴别是真图像还是假图像。 论文题目:Detection and Identification of Fake Images Using Conditional Generative Adversarial Networks (CGANs) (基于条件生成对抗网络(CGAN)的假图像检测与识别) 会议:16th IEEE International Confer…...
开源模型时代的 AI 开发革命:Dify 技术深度解析
开源模型时代的AI开发革命:Dify技术深度解析 引言:AI开发的开源新纪元 在生成式AI技术突飞猛进的2025年,开源模型正成为推动行业创新的核心力量。据统计,全球超过80%的AI开发者正在使用开源模型构建应用,这一趋势不仅…...
网络DNS怎么更改?
访问速度慢或某些网站无法打开?改变网络DNS设置可能会帮助解决这些问题。本文将详细介绍如何更改网络DNS,包括更改的原因、具体步骤。 一、为什么要更改DNS? 更改DNS的原因有很多,以下是一些主要的考虑因素:某些公共DNS服务器的响应速度比…...
计算机网络篇:基础知识总结与基于长期主义的内容更新
基础知识总结 和 MySQL 类似,我同样花了一周左右的时间根据 csview 对计算机网络部分的八股文进行了整理,主要的内容包括:概述、TCP 与 UDP、IP、HTTP,其中我个人认为最重要的是 TCP 这部分的内容。 在此做一篇目录索引…...
使用miniforge安装python并用pycharm打开使用
1.安装miniforge 参考文章:https://blog.csdn.net/loujiand/article/details/119976302 https://blog.csdn.net/qq_41946216/article/details/129481760 下载地址: 先从github下载miniforge:https://github.com/conda-forge/miniforge 2.使用conda命令…...
如何实现wordpress搜索自字义字段内容
有些网站需要根据自定义段字的内容来做为搜索项,比如,房产中介公司wordpress网站,需要搜索同一区域内容的楼盘,然后展示出内容。 不废话了,在function.php直接加上代码 add_action(posts_search, function($search, …...
【华为OD机考真题】- 星际篮球争霸赛(Java)
1. 题目描述 具体题目描述如下: 在星球争霸篮球赛对抗赛中,最大的宇宙战队希望每个人都能拿到 MVP,MVP 的条件是单场最高分得分获得者。 可以并列,所以宇宙战队决定在比赛中,尽可能让更多队员上场,并且让所有得分的选手…...
LeetCode 376. 摆动序列 java题解
https://leetcode.cn/problems/wiggle-subsequence/description/ 只要不满足摆动条件,就不更新count和prediff 当 prevDiff 取等号时,比如 prevDiff 0,在这种情况下,如果 currDiff > 0,说明从持平状态转变为上升…...
PyCharm 接入 DeepSeek、OpenAI、Gemini、Mistral等大模型完整版教程(通用)!
PyCharm 接入 DeepSeek、OpenAI、Gemini、Mistral等大模型完整版教程(通用)! 当我们成功接入大模型时,可以选中任意代码区域进行解答,共分为三个区域,分别是选中区域、提问区域以及回答区域,我…...
使用RabbitMQ实现流量削峰填谷
原理 流量削峰填谷是指在面对突发的高流量时,通过消息队列将瞬时大量请求暂时存储起来,并逐步处理这些请求,从而避免系统过载。RabbitMQ 作为消息中间件可以很好地支持这一需求,特别是结合其延时消息插件(rabbitmq_de…...
Apache Commons Lang3 和 Commons Net 详解
目录 1. Apache Commons Lang3 1.1 什么是 Apache Commons Lang3? 1.2 主要功能 1.3 示例代码 2. Commons Net 2.1 什么是 Commons Net? 2.2 主要功能 2.3 示例代码 3. 总结 3.1 Apache Commons Lang3 3.2 Commons Net 3.3 使用建议 4. 参考…...
ACE学习2——write transaction
用于处理缓存行的数据更新到主内存(main memory)的操作。 以下是用于更新主内存的几种事务类型: WriteBack: WriteBack事务用于将cache中的dirty态的cacheline写回主存,以释放cache中的cacheline,用于存…...
mac本地安装运行Redis-单机
记录一下我以前用的连接服务器的跨平台SSH客户端。 因为还要准备毕设...... 服务器又过期了,只能把redis安装下载到本地了。 目录 1.github下载Redis 2.安装homebrew 3.更新GCC 4.自行安装Redis 5.通过 Homebrew 安装 Redis 安装地址:https://git…...
sparkTTS window 安装
SparkTTS 的简介 Spark-TTS是一种基于SpardAudio团队提出的 BiCodec 构建的新系统,BiCodec 是一种单流语音编解码器,可将语音策略性地分解为两种互补的标记类型:用于语言内容的低比特率语义标记和用于说话者特定属性的固定长度全局标记。这种…...
颠覆语言认知的革命!神经概率语言模型如何突破人类思维边界?
颠覆语言认知的革命!神经概率语言模型如何突破人类思维边界? 一、传统模型的世纪困境:当n-gram遇上"月光族难题" 令人震惊的案例:2012年Google语音识别系统将 用户说:“我要还信用卡” 系统识别ÿ…...
大语言模型从理论到实践(第二版)-学习笔记(绪论)
大语言模型的基本概念 1.理解语言是人工智能算法获取知识的前提 2.语言模型的目标就是对自然语言的概率分布建模 3.词汇表 V 上的语言模型,由函数 P(w1w2 wm) 表示,可以形式化地构建为词序列 w1w2 wm 的概率分布,表示词序列 w1w2 wm…...
2.1 Vite + Vue 3 + TS 项目脚手架深度配置
文章目录 **一、环境准备与技术选型****二、项目初始化与基础架构****三、工程化配置深度优化****四、代码规范与质量保障****五、Vue 3 深度集成****六、TypeScript 高级配置****七、第三方库集成****八、构建优化策略****九、企业级最佳实践****十、扩展配置参考****本章核心…...
deepin安装rust
一、环境 操作系统:deepin V23 二、下载离线安装包 下载链接: https://forge.rust-lang.org/infra/other-installation-methods.html https://static.rust-lang.org/dist/rust-1.85.0-x86_64-unknown-linux-gnu.tar.xz 当时最新稳定版本为1.85。 三、解…...
【愚公系列】《Python网络爬虫从入门到精通》045-Charles的SSL证书的安装
标题详情作者简介愚公搬代码头衔华为云特约编辑,华为云云享专家,华为开发者专家,华为产品云测专家,CSDN博客专家,CSDN商业化专家,阿里云专家博主,阿里云签约作者,腾讯云优秀博主&…...
UniApp 运行的微信小程序如何进行深度优化
UniApp 运行的微信小程序如何进行深度优化 目录 引言性能优化 1. 减少包体积2. 优化页面加载速度3. 减少 setData 调用4. 使用分包加载 代码优化 1. 减少不必要的代码2. 使用条件编译3. 优化图片资源 用户体验优化 1. 优化交互体验2. 预加载数据3. 使用骨架屏 调试与监控 1. …...
Hadoop安装文件解压报错:无法创建符号链接。。。
您可能需要管理员身份运行winRAR; 客户端没有所需的特权; cmd进入该目录下,输入命令(本地解压):start winrar x -y hadoop-2.10.1.tar.gz...
Redis6.2.6下载和安装
简介 Redis 是一种开源(BSD 许可)、内存中数据结构存储,用作数据库、缓存和消息代理。Redis 提供了数据结构,例如字符串、散列、列表、集合、带有范围查询的排序集合、位图、超级日志、地理空间索引和流。Redis 内置复制、Lua 脚…...
【AI】神经网络|机器学习——图解Transformer(完整版)
Transformer是一种基于注意力机制的序列模型,最初由Google的研究团队提出并应用于机器翻译任务。与传统的循环神经网络(RNN)和卷积神经网络(CNN)不同,Transformer仅使用自注意力机制(self-attention)来处理输入序列和输出序列,因此可以并行计算,极大地提高了计算效率…...
超过 37000 台 VMwareESXi 服务器可能受到持续攻击威胁
近日,威胁监测平台影子服务器基金会(The Shadowserver Foundation)发布报告,指出超 3.7 万个互联网暴露的威睿(VMware)ESXi 实例存在严重安全隐患,极易受到 CVE-2025-22224 漏洞的攻击。该漏洞属…...
多宠识别:基于计算机视觉的智能宠物管理系统架构解析
一、行业痛点与技术方案演进 在多宠家庭场景中,传统方案面临三大技术瓶颈: 1. 生物特征混淆:同品种/毛色宠物识别准确率低于65% 2. 动态场景适应:进食/奔跑状态下的误检率达30% 3. 数据孤岛问题:离线设备无法实现持续…...
mobaxterm,闪退处理方法
mobaxterm,使用过程中突然闪退, 具体表现为:登录远程服务器成功,开始闪退 登录失败不闪退 一开始以为是,服务器做了控制,后来才发现是mobaxterm软件的问题。 问题解决方法: 勾选工具ssh&…...
文件系统文件管理
文件缓冲区(内核级,OS内部的)存在的意义:系统调用将数据写入缓冲区后函数即可返回,是从内存到内存的,提高了程序的效率。之后将缓冲区数据刷新到硬盘则是操作系统的事了。无论读写,OS都会把数据…...
Vue 实现AI对话和AI绘图(AIGC)人工智能
我司是主要是负责AIGC人工智能化平台的项目,俗称内容创作及智能工具平台。 授人以鱼不如授人以渔 首先我们要明白AIGC中前端需要做什么 会用到哪些技术栈 。 AIGC前端需要用到的技术栈:Vue,Markdown,SSE。就这个三件套。 前沿:有人觉得AI对…...
Python | 机器学习中最常用的超参数及使用示例
在机器学习中,超参数是用于控制机器学习模型训练过程的外部配置。它们是在训练开始之前配置的设置参数,并在整个过程中保持不变。您应该了解一些常用于优化机器学习模型的超参数。本文将带您了解机器学习中最常用的超参数以及如何在Python中使用它们。 …...
本地部署DeepSeek R1大数据模型知识库
DeepSeek-V3 的综合能力 DeepSeek-V3 在推理速度上相较历史模型有了大幅提升。在目前大模型主流榜单中,DeepSeek-V3 在开源模型中位列榜首,与世界上最先进OpenAI 闭源模型不分伯仲。 1、下载Ollama运行大数据库 Ollama支持 Llama 3.3, DeepSeek-R1, Phi-…...
【C++】C++入门基础
C(C plus plus) 是一种计算机高级程序设计语言,既可以进行 C语言 的过程化程序设计,又可以进行以抽象数据类型为特点的基于对象的程序设计,还可以进行以继承和多态为特点的面向对象的程序设计。 文章目录 前言一、C 的…...
【Linux文件IO】标准IO详情(1)
目录 一、前言 1.1 文件类型 1.2 流(FILE)介绍 1.3 文本流和二进制流的区别 二、相关API介绍 2.1 fopen 2.2 fclose 2.3 perror 2.4 fgetc 2.5 fputc 2.6 fgets 2.7 fputs 2.8 fread 2.9 fwrite 一、前言 标准IO基于系统IO实现,通过缓冲机制减少系统调…...
店匠科技携手 PayPal 升级支付体验,助力独立站商家实现全球增长
在全球化电商竞争加剧的背景下,独立站为无数商户插上了通向事业成功的翅膀。然而,搭建店铺框架容易,真正实现有效运营却充满挑战。只有当各个环节如齿轮般严丝合缝,独立站运营才能更好地助推行进,实现稳健增长。如今,独立站商家面临着全链路运营的多重挑战。从品牌塑造、营销推…...
使用 Elastic-Agent 或 Beats 将 Journald 中的 syslog 和 auth 日志导入 Elastic Stack
作者:来自 Elastic TiagoQueiroz 我们在 Elastic 一直努力将更多 Linux 发行版添加到我们的支持矩阵中,现在 Elastic-Agent 和 Beats 已正式支持 Debian 12! 本文演示了我们正在开发的功能,以支持使用 Journald 存储系统和身份验…...
模板方法模式的C++实现示例
核心思想 模板方法设计模式是一种行为设计模式,它定义了一个算法的框架,并将某些步骤的具体实现延迟到子类中。通过这种方式,模板方法模式允许子类在不改变算法结构的情况下重新定义算法的某些步骤。 模板方法模式的核心在于: …...
docker无法pull镜像问题解决for win10
docker无法pull镜像问题解决for win10 问题原因分析解决方法 问题 在win10系统上安装好doker-desktop后ping registry-1.docker.io不同,并且也无法登陆hub.docker.com, 使用docker pull xx也无法正常下载 原因分析 hub.docker.com在2024年5月之后,国内…...
Docker数据管理,端口映射与容器互联
1.Docker 数据管理 在生产环境中使用 Docker,往往需要对数据进行持久化,或者需要在多个容器之间进行数据共享,这必然涉及容器的数据管理操作。 容器中的管理数据主要有两种方式: 数据卷(Data Volumns)&a…...
R语言使用scitable包交互效应深度挖掘一个陌生数据库
很多新手刚才是总是觉得自己没什么可以写的,自己不知道选什么题材进行分析,使用scitable包后这个完全不用担心,选题多到你只会担心你写不完,写得不够快。 今天演示一下使用scitable包深度挖掘一个陌生数据库 先导入R包和数据 li…...