From 53230dbe1648e9e3e14b699e7e8f3b7352a33bb5 Mon Sep 17 00:00:00 2001 From: zhouxinyu <392298118@qq.com> Date: Thu, 25 Dec 2025 09:20:56 +0800 Subject: [PATCH 1/5] =?UTF-8?q?README.md=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 02da325..f1bd50d 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ -# 基于HarmonyOS媒体子系统实现媒体直播功能 +# 基于媒体子系统实现媒体直播连麦功能 ## 项目简介 -本示例基于媒体子系统,实现媒体直播的开直播端、看播端和直播连麦。本示例实现了直播场景常用的音视频采集、音视频播放、音频焦点管理、ROI、 +本示例基于媒体子系统,实现媒体直播的开直播端、看播端和直播连麦模块。实现了直播场景常用的音视频采集、音视频播放、音频焦点管理、ROI、 背景音乐添加、前后摄像头翻转等功能。基于本示例可帮助应用开发开启直播和观看直播的场景。 - 看播端是通过播放视频文件来模拟的,主要流程是将直播端录制的视频文件通过AvPlayer播放。 -- Gitee From a75d68382484991c9a1201f3db143cb52c3ac02b Mon Sep 17 00:00:00 2001 From: zhouxinyu <392298118@qq.com> Date: Thu, 25 Dec 2025 09:45:37 +0800 Subject: [PATCH 2/5] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E8=A7=84=E8=8C=83?= =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- entry/src/main/cpp/types/libaudioplayer/index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/entry/src/main/cpp/types/libaudioplayer/index.d.ts b/entry/src/main/cpp/types/libaudioplayer/index.d.ts index 46c74df..8af45a5 100644 --- a/entry/src/main/cpp/types/libaudioplayer/index.d.ts +++ b/entry/src/main/cpp/types/libaudioplayer/index.d.ts @@ -22,7 +22,7 @@ export const startPlay: ( inputFileFd: number, inputFileOffset: number, inputFileSize: number, - cbFn: (status:number) => void + cbFn: (status: number) => void ) => void; export const stopPlay: (objAddr: bigint) => void \ No newline at end of file -- Gitee From 413c4358334c45d58f3f55b7d3f9f7050e6fc851 Mon Sep 17 00:00:00 2001 From: zhouxinyu <392298118@qq.com> Date: Thu, 25 Dec 2025 10:31:38 +0800 Subject: [PATCH 3/5] =?UTF-8?q?README.md=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index f1bd50d..39cf231 100644 --- a/README.md +++ b/README.md @@ -83,13 +83,11 @@ │ │ │ │ ├──Muxer.h // 封装接口 │ │ │ │ ├──VideoDecoder.h // 视频解码接口 │ │ │ │ └──VideoEncoder.h // 视频编码接口 -│ │ │ ├──AudioBgmQueue.cpp // 音频bgm播放接口实现 │ │ │ ├──AudioCapturer.cpp // 音频采集接口实现 │ │ │ ├──AudioDecoder.cpp // 音频解码接口实现 │ │ │ ├──AudioEncoder.cpp // 音频编码接口实现 │ │ │ ├──AudioRender.cpp // 音频播放接口实现 │ │ │ ├──CodecCallback.cpp // 编解码回调接口实现 -│ │ │ ├──CodecInfo.cpp // 编解码信息接口实现 │ │ │ ├──Demuxer.cpp // 解封装接口实现 │ │ │ ├──Muxer.cpp // 封装接口实现 │ │ │ ├──VideoDecoder.cpp // 视频解码接口实现 @@ -103,15 +101,21 @@ │ │ │ │ ├──shader_program.h // 封装 OpenGL ES 着色器程序的接口 │ │ │ │ ├──VideoRender.h // 视频渲染接口 │ │ │ │ └──VideoRenderThread.h // 视频渲染线程接口 -│ │ │ ├──egl_render_context.cpp // EGL渲染上下文接口实现 │ │ │ ├──PluginManager.cpp // surface渲染管理接口实现 │ │ │ ├──PluginRender.cpp // surface渲染接口实现 -│ │ │ ├──render_thread.cpp // 渲染线程接口实现 -│ │ │ ├──shader_program.cpp // 封装 OpenGL ES 着色器程序的接口实现 +│ │ │ ├──RecorderRender.cpp // 渲染线程接口实现 +│ │ │ ├──RecorderRenderThread.cpp // EGL渲染上下文接口实现 +│ │ │ ├──ShaderProgram.cpp // 封装 OpenGL ES 着色器程序的接口实现 │ │ │ ├──VideoRender.cpp // 视频渲染接口实现 │ │ │ └──VideoRenderThread.cpp // 视频渲染线程接口实现 │ ├──common // 公共模块 │ │ ├──dfx // 日志 +│ │ │ ├──error // 错误日志 +│ │ │ │ ├──AVCodecSampleError.h // 编解码错误日志 +│ │ │ │ └──SampleError.h // 功能实现错误日志 +│ │ │ ├──log // 打印日志 +│ │ │ │ ├──AVCodecSampleLog.cpp // 编解码日志 +│ │ │ │ └──SampleLog.cpp // 功能实现日志 │ │ ├──ApiCompatibility.h // API兼容性 │ │ ├──SampleCallback.cpp // 功能实现回调接口实现 │ │ ├──SampleCallback.h // 功能实现回调接口 @@ -124,8 +128,9 @@ │ │ ├──Recorder.cpp // Native层录制功能调用逻辑的实现 │ │ └──RecorderNative.cpp // Native层 录制的入口 │ ├──types // Native层提供上来的接口 -│ │ ├──libplayer // 播放模块提供给UI层的接口 -│ │ └──librecorder // 录制模块提供给UI层的接口 +│ │ ├──libaudioplayer // 音频播放模块提供给UI层的接口 +│ │ ├──librecorder // 录制模块提供给UI层的接口 +│ │ └──libvideoplayer // 视频播放模块提供给UI层的接口 │ ├──videoPlayer // 音频播放能力接口和实现 │ │ ├──include // 音频播放能力接口 │ │ │ ├──videoPlayer.h // 视频播放接口 -- Gitee From c8f466718f7478dbe5b6156194332cc83cc47c0c Mon Sep 17 00:00:00 2001 From: zhouxinyu <392298118@qq.com> Date: Thu, 25 Dec 2025 11:47:27 +0800 Subject: [PATCH 4/5] =?UTF-8?q?=E5=90=8D=E7=A7=B0=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- entry/src/main/cpp/capbilities/render/RecorderRender.cpp | 2 +- .../src/main/cpp/capbilities/render/RecorderRenderThread.cpp | 2 +- entry/src/main/cpp/capbilities/render/ShaderProgram.cpp | 2 +- .../render/include/{render_thread.h => RecorderRender.h} | 4 ++-- .../include/{egl_render_context.h => RecorderRenderThread.h} | 0 .../render/include/{shader_program.h => ShaderProgram.h} | 0 .../main/cpp/capbilities/render/include/VideoRenderThread.h | 2 +- entry/src/main/cpp/recorder/include/Recorder.h | 2 +- 8 files changed, 7 insertions(+), 7 deletions(-) rename entry/src/main/cpp/capbilities/render/include/{render_thread.h => RecorderRender.h} (98%) rename entry/src/main/cpp/capbilities/render/include/{egl_render_context.h => RecorderRenderThread.h} (100%) rename entry/src/main/cpp/capbilities/render/include/{shader_program.h => ShaderProgram.h} (100%) diff --git a/entry/src/main/cpp/capbilities/render/RecorderRender.cpp b/entry/src/main/cpp/capbilities/render/RecorderRender.cpp index 6457055..2aa8fda 100644 --- a/entry/src/main/cpp/capbilities/render/RecorderRender.cpp +++ b/entry/src/main/cpp/capbilities/render/RecorderRender.cpp @@ -13,7 +13,7 @@ * limitations under the License. */ -#include "include/egl_render_context.h" +#include "include/RecorderRenderThread.h" namespace NativeXComponentSample { constexpr uint32_t LOG_PRINT_DOMAIN = 0xFF00; diff --git a/entry/src/main/cpp/capbilities/render/RecorderRenderThread.cpp b/entry/src/main/cpp/capbilities/render/RecorderRenderThread.cpp index 5ebd1f3..169bc1e 100644 --- a/entry/src/main/cpp/capbilities/render/RecorderRenderThread.cpp +++ b/entry/src/main/cpp/capbilities/render/RecorderRenderThread.cpp @@ -13,7 +13,7 @@ * limitations under the License. */ -#include "include/render_thread.h" +#include "include/RecorderRender.h" #include #include #include diff --git a/entry/src/main/cpp/capbilities/render/ShaderProgram.cpp b/entry/src/main/cpp/capbilities/render/ShaderProgram.cpp index d717f2a..726bca0 100644 --- a/entry/src/main/cpp/capbilities/render/ShaderProgram.cpp +++ b/entry/src/main/cpp/capbilities/render/ShaderProgram.cpp @@ -13,7 +13,7 @@ * limitations under the License. */ -#include "include/shader_program.h" +#include "include/ShaderProgram.h" namespace NativeXComponentSample { constexpr uint32_t LOG_PRINT_DOMAIN = 0xFF00; diff --git a/entry/src/main/cpp/capbilities/render/include/render_thread.h b/entry/src/main/cpp/capbilities/render/include/RecorderRender.h similarity index 98% rename from entry/src/main/cpp/capbilities/render/include/render_thread.h rename to entry/src/main/cpp/capbilities/render/include/RecorderRender.h index d369e08..2789324 100644 --- a/entry/src/main/cpp/capbilities/render/include/render_thread.h +++ b/entry/src/main/cpp/capbilities/render/include/RecorderRender.h @@ -27,8 +27,8 @@ #include #include -#include "egl_render_context.h" -#include "shader_program.h" +#include "RecorderRenderThread.h" +#include "ShaderProgram.h" namespace NativeXComponentSample { using RenderTask = std::function; diff --git a/entry/src/main/cpp/capbilities/render/include/egl_render_context.h b/entry/src/main/cpp/capbilities/render/include/RecorderRenderThread.h similarity index 100% rename from entry/src/main/cpp/capbilities/render/include/egl_render_context.h rename to entry/src/main/cpp/capbilities/render/include/RecorderRenderThread.h diff --git a/entry/src/main/cpp/capbilities/render/include/shader_program.h b/entry/src/main/cpp/capbilities/render/include/ShaderProgram.h similarity index 100% rename from entry/src/main/cpp/capbilities/render/include/shader_program.h rename to entry/src/main/cpp/capbilities/render/include/ShaderProgram.h diff --git a/entry/src/main/cpp/capbilities/render/include/VideoRenderThread.h b/entry/src/main/cpp/capbilities/render/include/VideoRenderThread.h index 1c492de..b746baf 100644 --- a/entry/src/main/cpp/capbilities/render/include/VideoRenderThread.h +++ b/entry/src/main/cpp/capbilities/render/include/VideoRenderThread.h @@ -22,7 +22,7 @@ #include #include #include "VideoRender.h" -#include "shader_program.h" +#include "ShaderProgram.h" namespace NativeXComponentSample { using RenderTask = std::function; diff --git a/entry/src/main/cpp/recorder/include/Recorder.h b/entry/src/main/cpp/recorder/include/Recorder.h index 847de23..a2185d3 100644 --- a/entry/src/main/cpp/recorder/include/Recorder.h +++ b/entry/src/main/cpp/recorder/include/Recorder.h @@ -31,7 +31,7 @@ #include "../../capbilities/codec/include/AudioBgmQueue.h" #include "../../capbilities/codec/include/VideoEncoder.h" #include "../../capbilities/codec/include/AudioCapturer.h" -#include "../../capbilities/render/include/render_thread.h" +#include "../../capbilities/render/include/RecorderRender.h" #include "videoPlayer/include/VideoPlayer.h" class Recorder { -- Gitee From 396455850d1107a55799f0e237bab9bdc623c0af Mon Sep 17 00:00:00 2001 From: zhouxinyu <392298118@qq.com> Date: Thu, 25 Dec 2025 16:33:00 +0800 Subject: [PATCH 5/5] =?UTF-8?q?ux=E6=A3=80=E8=A7=86=E6=84=8F=E8=A7=81?= =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 224 +++++++++--------- .../src/main/ets/common/utils/WindowUtil.ets | 35 ++- .../main/ets/entryability/EntryAbility.ets | 11 + entry/src/main/ets/pages/Index.ets | 19 ++ .../main/ets/pages/StartConnectLiveStream.ets | 21 +- entry/src/main/ets/pages/StartLiveStream.ets | 9 +- entry/src/main/ets/pages/WatchLiveStream.ets | 9 - entry/src/main/ets/view/AvplayerView.ets | 4 - .../main/ets/view/StartLiveDecorationView.ets | 36 +-- .../src/main/ets/view/StartLiveRenderView.ets | 1 - 10 files changed, 204 insertions(+), 165 deletions(-) diff --git a/README.md b/README.md index 39cf231..4d415f5 100644 --- a/README.md +++ b/README.md @@ -62,122 +62,122 @@ ## 工程目录 ``` -├──entry/src/main/cpp // Native层 -│ ├──audioPlayer // 音频播放能力接口和实现 -│ │ ├──include // 音频播放能力接口 -│ │ │ ├──AudioPlayer.h // 音频播放接口 -│ │ │ └──AudioPlayerNative.h // 音频播放入口 -│ │ ├──AudioPlayer.cpp // 音频播放接口实现 -│ │ └──AudioPlayerNative.cpp // 音频播放入口实现 -│ ├──capbilities // 能力接口和实现 -│ │ ├──codec // 音视频采集编解码 -│ │ │ ├──include // 音视频采集编解码接口 -│ │ │ │ ├──AudioBgmQueue.h // 音频bgm播放接口 -│ │ │ │ ├──AudioCapturer.h // 音频采集接口 -│ │ │ │ ├──AudioDecoder.h // 音频解码接口 -│ │ │ │ ├──AudioEncoder.h // 音频编码接口 -│ │ │ │ ├──AudioRender.h // 音频播放接口 -│ │ │ │ ├──CodecCallback.h // 编解码回调接口 -│ │ │ │ ├──CodecInfo.h // 编解码信息接口 -│ │ │ │ ├──Demuxer.h // 解封装接口 -│ │ │ │ ├──Muxer.h // 封装接口 -│ │ │ │ ├──VideoDecoder.h // 视频解码接口 -│ │ │ │ └──VideoEncoder.h // 视频编码接口 -│ │ │ ├──AudioCapturer.cpp // 音频采集接口实现 -│ │ │ ├──AudioDecoder.cpp // 音频解码接口实现 -│ │ │ ├──AudioEncoder.cpp // 音频编码接口实现 -│ │ │ ├──AudioRender.cpp // 音频播放接口实现 -│ │ │ ├──CodecCallback.cpp // 编解码回调接口实现 -│ │ │ ├──Demuxer.cpp // 解封装接口实现 -│ │ │ ├──Muxer.cpp // 封装接口实现 -│ │ │ ├──VideoDecoder.cpp // 视频解码接口实现 -│ │ │ └──VideoEncoder.cpp // 视频编码入口实现 -│ │ ├──render // 送显模块接口和实现 -│ │ │ ├──include // 送显模块接口 -│ │ │ │ ├──egl_render_context.h // EGL渲染上下文接口 -│ │ │ │ ├──PluginManager.h // surface渲染管理接口 -│ │ │ │ ├──PluginRender.h // surface渲染接口 -│ │ │ │ ├──render_thread.h // 渲染线程接口 -│ │ │ │ ├──shader_program.h // 封装 OpenGL ES 着色器程序的接口 -│ │ │ │ ├──VideoRender.h // 视频渲染接口 -│ │ │ │ └──VideoRenderThread.h // 视频渲染线程接口 -│ │ │ ├──PluginManager.cpp // surface渲染管理接口实现 -│ │ │ ├──PluginRender.cpp // surface渲染接口实现 -│ │ │ ├──RecorderRender.cpp // 渲染线程接口实现 -│ │ │ ├──RecorderRenderThread.cpp // EGL渲染上下文接口实现 -│ │ │ ├──ShaderProgram.cpp // 封装 OpenGL ES 着色器程序的接口实现 -│ │ │ ├──VideoRender.cpp // 视频渲染接口实现 -│ │ │ └──VideoRenderThread.cpp // 视频渲染线程接口实现 -│ ├──common // 公共模块 -│ │ ├──dfx // 日志 -│ │ │ ├──error // 错误日志 -│ │ │ │ ├──AVCodecSampleError.h // 编解码错误日志 -│ │ │ │ └──SampleError.h // 功能实现错误日志 -│ │ │ ├──log // 打印日志 -│ │ │ │ ├──AVCodecSampleLog.cpp // 编解码日志 -│ │ │ │ └──SampleLog.cpp // 功能实现日志 -│ │ ├──ApiCompatibility.h // API兼容性 -│ │ ├──SampleCallback.cpp // 功能实现回调接口实现 -│ │ ├──SampleCallback.h // 功能实现回调接口 -│ │ └──SampleInfo.h // 功能实现公共类 -│ ├──libboundcheck // 安全函数三方库 -│ ├──recorder // Native层录制接口和实现 -│ │ ├──include // Native层录制功能调用逻辑的实现 -│ │ │ ├──Recorder.h // Native层录制功能调用逻辑的接口 -│ │ │ └──RecorderNative.h // Native层 录制入口的接口 -│ │ ├──Recorder.cpp // Native层录制功能调用逻辑的实现 -│ │ └──RecorderNative.cpp // Native层 录制的入口 -│ ├──types // Native层提供上来的接口 -│ │ ├──libaudioplayer // 音频播放模块提供给UI层的接口 -│ │ ├──librecorder // 录制模块提供给UI层的接口 -│ │ └──libvideoplayer // 视频播放模块提供给UI层的接口 -│ ├──videoPlayer // 音频播放能力接口和实现 -│ │ ├──include // 音频播放能力接口 -│ │ │ ├──videoPlayer.h // 视频播放接口 -│ │ │ └──videoPlayerNative.h // 视频播放入口 -│ │ ├──videoPlayer.cpp // 视频播放接口实现 -│ │ └──videoPlayer.cpp // 视频播放入口实现 -│ └──CMakeLists.txt // 编译入口 -├──ets // UI层 -│ ├──common // 公共模块 -│ │ ├──utils // 共用的工具类 -│ │ │ ├──BackgroundTaskManager.ets // 后台任务工具类 -│ │ │ ├──CameraCheck.ets // 检查相机参数是否支持 -│ │ │ ├──DateTimeUtils.ets // 时间转换工具类 -│ │ │ ├──ImageUtil.ets // 图片处理工具类 -│ │ │ ├──Logger.ets // 日志工具 -│ │ │ ├──PermissionUtil.ets // 权限校验工具 -│ │ │ └──WindowUtil.ets // 窗口工具 -│ │ ├──GlobalConstants.ets // 全局变量名称 -│ │ └──CommonConstants.ets // 参数常量 -│ ├──components // 组件目录 -│ │ ├──SaveFileDialog.ets // 安全弹框组件 -│ │ └──SettingPopupDialog.ets // 设置相关数据类 -│ ├──controller // 控制器 -│ │ ├──BgmController.ets // 背景音乐控制器 -│ │ ├──CameraController.ets // 相机控制器 -│ │ ├──DistributeFileManager.ets // 分布式文件管理器 -│ │ ├──VideoPlayerController.ets // 本地音视频播放控制器 -│ │ └──VideoSessionController.ets // 音频会话控制器 -│ ├──entryability // 应用的入口 +├──entry/src/main/cpp // Native层 +│ ├──audioPlayer // 音频播放能力接口和实现 +│ │ ├──include // 音频播放能力接口 +│ │ │ ├──AudioPlayer.h // 音频播放接口 +│ │ │ └──AudioPlayerNative.h // 音频播放入口 +│ │ ├──AudioPlayer.cpp // 音频播放接口实现 +│ │ └──AudioPlayerNative.cpp // 音频播放入口实现 +│ ├──capbilities // 能力接口和实现 +│ │ ├──codec // 音视频采集编解码 +│ │ │ ├──include // 音视频采集编解码接口 +│ │ │ │ ├──AudioBgmQueue.h // 音频bgm播放接口 +│ │ │ │ ├──AudioCapturer.h // 音频采集接口 +│ │ │ │ ├──AudioDecoder.h // 音频解码接口 +│ │ │ │ ├──AudioEncoder.h // 音频编码接口 +│ │ │ │ ├──AudioRender.h // 音频播放接口 +│ │ │ │ ├──CodecCallback.h // 编解码回调接口 +│ │ │ │ ├──CodecInfo.h // 编解码信息接口 +│ │ │ │ ├──Demuxer.h // 解封装接口 +│ │ │ │ ├──Muxer.h // 封装接口 +│ │ │ │ ├──VideoDecoder.h // 视频解码接口 +│ │ │ │ └──VideoEncoder.h // 视频编码接口 +│ │ │ ├──AudioCapturer.cpp // 音频采集接口实现 +│ │ │ ├──AudioDecoder.cpp // 音频解码接口实现 +│ │ │ ├──AudioEncoder.cpp // 音频编码接口实现 +│ │ │ ├──AudioRender.cpp // 音频播放接口实现 +│ │ │ ├──CodecCallback.cpp // 编解码回调接口实现 +│ │ │ ├──Demuxer.cpp // 解封装接口实现 +│ │ │ ├──Muxer.cpp // 封装接口实现 +│ │ │ ├──VideoDecoder.cpp // 视频解码接口实现 +│ │ │ └──VideoEncoder.cpp // 视频编码入口实现 +│ │ ├──render // 送显模块接口和实现 +│ │ │ ├──include // 送显模块接口 +│ │ │ │ ├──PluginManager.h // surface渲染管理接口 +│ │ │ │ ├──PluginRender.h // surface渲染接口 +│ │ │ │ ├──RecorderRender.cpp // 渲染线程接口 +│ │ │ │ ├──RecorderRenderThread.cpp // EGL渲染上下文接口 +│ │ │ │ ├──ShaderProgram.cpp // 封装 OpenGL ES 着色器程序的接口 +│ │ │ │ ├──VideoRender.h // 视频渲染接口 +│ │ │ │ └──VideoRenderThread.h // 视频渲染线程接口 +│ │ │ ├──PluginManager.cpp // surface渲染管理接口实现 +│ │ │ ├──PluginRender.cpp // surface渲染接口实现 +│ │ │ ├──RecorderRender.cpp // 渲染线程接口实现 +│ │ │ ├──RecorderRenderThread.cpp // EGL渲染上下文接口实现 +│ │ │ ├──ShaderProgram.cpp // 封装 OpenGL ES 着色器程序的接口实现 +│ │ │ ├──VideoRender.cpp // 视频渲染接口实现 +│ │ │ └──VideoRenderThread.cpp // 视频渲染线程接口实现 +│ ├──common // 公共模块 +│ │ ├──dfx // 日志 +│ │ │ ├──error // 错误日志 +│ │ │ │ ├──AVCodecSampleError.h // 编解码错误日志 +│ │ │ │ └──SampleError.h // 功能实现错误日志 +│ │ │ ├──log // 打印日志 +│ │ │ │ ├──AVCodecSampleLog.cpp // 编解码日志 +│ │ │ │ └──SampleLog.cpp // 功能实现日志 +│ │ ├──ApiCompatibility.h // API兼容性 +│ │ ├──SampleCallback.cpp // 功能实现回调接口实现 +│ │ ├──SampleCallback.h // 功能实现回调接口 +│ │ └──SampleInfo.h // 功能实现公共类 +│ ├──libboundcheck // 安全函数三方库 +│ ├──recorder // Native层录制接口和实现 +│ │ ├──include // Native层录制功能调用逻辑的实现 +│ │ │ ├──Recorder.h // Native层录制功能调用逻辑的接口 +│ │ │ └──RecorderNative.h // Native层 录制入口的接口 +│ │ ├──Recorder.cpp // Native层录制功能调用逻辑的实现 +│ │ └──RecorderNative.cpp // Native层 录制的入口 +│ ├──types // Native层提供上来的接口 +│ │ ├──libaudioplayer // 音频播放模块提供给UI层的接口 +│ │ ├──librecorder // 录制模块提供给UI层的接口 +│ │ └──libvideoplayer // 视频播放模块提供给UI层的接口 +│ ├──videoPlayer // 音频播放能力接口和实现 +│ │ ├──include // 音频播放能力接口 +│ │ │ ├──videoPlayer.h // 视频播放接口 +│ │ │ └──videoPlayerNative.h // 视频播放入口 +│ │ ├──videoPlayer.cpp // 视频播放接口实现 +│ │ └──videoPlayer.cpp // 视频播放入口实现 +│ └──CMakeLists.txt // 编译入口 +├──ets // UI层 +│ ├──common // 公共模块 +│ │ ├──utils // 共用的工具类 +│ │ │ ├──BackgroundTaskManager.ets // 后台任务工具类 +│ │ │ ├──CameraCheck.ets // 检查相机参数是否支持 +│ │ │ ├──DateTimeUtils.ets // 时间转换工具类 +│ │ │ ├──ImageUtil.ets // 图片处理工具类 +│ │ │ ├──Logger.ets // 日志工具 +│ │ │ ├──PermissionUtil.ets // 权限校验工具 +│ │ │ └──WindowUtil.ets // 窗口工具 +│ │ ├──GlobalConstants.ets // 全局变量名称 +│ │ └──CommonConstants.ets // 参数常量 +│ ├──components // 组件目录 +│ │ ├──SaveFileDialog.ets // 安全弹框组件 +│ │ └──SettingPopupDialog.ets // 设置相关数据类 +│ ├──controller // 控制器 +│ │ ├──BgmController.ets // 背景音乐控制器 +│ │ ├──CameraController.ets // 相机控制器 +│ │ ├──DistributeFileManager.ets // 分布式文件管理器 +│ │ ├──VideoPlayerController.ets // 本地音视频播放控制器 +│ │ └──VideoSessionController.ets // 音频会话控制器 +│ ├──entryability // 应用的入口 │ │ └──EntryAbility.ets │ ├──entrybackupability │ │ └──EntryBackupAbility.ets │ ├──model -│ │ ├──CameraDataModel.ets // 相机参数数据类 -│ │ └──SettingPopupOptionItem.ets // 设置的数据类 -│ ├──pages // EntryAbility 包含的页面 -│ │ ├──Index.ets // 首页 -│ │ ├──StartConnectLiveStream.ets // 直播连麦页面 -│ │ ├──StartLiveStream.ets // 直播端页面 -│ │ └──WatchLiveStream.ets // 看播端页面 -│ └──view // EntryAbility 包含的页面 -│ ├──AvplayerView.ets // 看播端AvPlayer音视频播放 -│ ├──StartLiveDecorationView.ets // 直播端数据页面 -│ ├──StartLiveRenderView.ets // 直播端渲染器 -│ └──WatchLiveDecorationView.ets // 看播端数据页面 -├──resources // 存放应用的资源文件 -└──module.json5 // 模块配置信息 +│ │ ├──CameraDataModel.ets // 相机参数数据类 +│ │ └──SettingPopupOptionItem.ets // 设置的数据类 +│ ├──pages // EntryAbility 包含的页面 +│ │ ├──Index.ets // 首页 +│ │ ├──StartConnectLiveStream.ets // 直播连麦页面 +│ │ ├──StartLiveStream.ets // 直播端页面 +│ │ └──WatchLiveStream.ets // 看播端页面 +│ └──view // EntryAbility 包含的页面 +│ ├──AvplayerView.ets // 看播端AvPlayer音视频播放 +│ ├──StartLiveDecorationView.ets // 直播端数据页面 +│ ├──StartLiveRenderView.ets // 直播端渲染器 +│ └──WatchLiveDecorationView.ets // 看播端数据页面 +├──resources // 存放应用的资源文件 +└──module.json5 // 模块配置信息 ``` ## 具体实现 diff --git a/entry/src/main/ets/common/utils/WindowUtil.ets b/entry/src/main/ets/common/utils/WindowUtil.ets index 6a375e0..937eed7 100644 --- a/entry/src/main/ets/common/utils/WindowUtil.ets +++ b/entry/src/main/ets/common/utils/WindowUtil.ets @@ -26,11 +26,11 @@ export function setFullScreen() { } try { windowStage.getMainWindowSync().setWindowLayoutFullScreen(true).catch((err: BusinessError) => { - Logger.error(TAG, `setWindowKeepScreenOn failed, errCode = ${err.code}, errMessage = ${err.message}.`); + Logger.error(TAG, `setWindowLayoutFullScreen failed, errCode = ${err.code}, errMessage = ${err.message}.`); }); } catch (error) { let err = error as BusinessError; - Logger.error(TAG, `setWindowKeepScreenOn failed, errCode = ${err.code}, errMessage = ${err.message}.`); + Logger.error(TAG, `setWindowLayoutFullScreen failed, errCode = ${err.code}, errMessage = ${err.message}.`); } } @@ -62,4 +62,35 @@ export function hideStatusBar() { let err = error as BusinessError; Logger.error(TAG, `setWindowKeepScreenOn failed, errCode = ${err.code}, errMessage = ${err.message}.`); } +} + + +export function getTopAvoidArea(): window.AvoidArea | undefined { + let windowStage: window.WindowStage | undefined = AppStorage.get('windowStage'); + if (!windowStage) { + return; + } + try { + let avoidArea = windowStage.getMainWindowSync().getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM); + return avoidArea; + } catch (error) { + let err = error as BusinessError; + Logger.error(TAG, `setWindowKeepScreenOn failed, errCode = ${err.code}, errMessage = ${err.message}.`); + return; + } +} + +export function getBottomAvoidArea(): window.AvoidArea | undefined { + let windowStage: window.WindowStage | undefined = AppStorage.get('windowStage'); + if (!windowStage) { + return; + } + try { + let avoidArea = windowStage.getMainWindowSync().getWindowAvoidArea(window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR); + return avoidArea; + } catch (error) { + let err = error as BusinessError; + Logger.error(TAG, `setWindowKeepScreenOn failed, errCode = ${err.code}, errMessage = ${err.message}.`); + return; + } } \ No newline at end of file diff --git a/entry/src/main/ets/entryability/EntryAbility.ets b/entry/src/main/ets/entryability/EntryAbility.ets index d3697c0..f4b8c81 100644 --- a/entry/src/main/ets/entryability/EntryAbility.ets +++ b/entry/src/main/ets/entryability/EntryAbility.ets @@ -18,6 +18,7 @@ import { BusinessError } from '@kit.BasicServicesKit'; import { hilog } from '@kit.PerformanceAnalysisKit'; import { window } from '@kit.ArkUI'; import Logger from '../common/utils/Logger'; +import { setFullScreen } from '../common/utils/WindowUtil'; const TAG = '[EntryAbility]'; @@ -51,11 +52,21 @@ export default class EntryAbility extends UIAbility { windowStage.getMainWindowSync().setWindowKeepScreenOn(true).catch((err: BusinessError) => { Logger.error(TAG, `setWindowKeepScreenOn failed, errCode = ${err.code}, errMessage = ${err.message}.`); }); + } catch (error) { let err = error as BusinessError; Logger.error(TAG, `setWindowKeepScreenOn failed, errCode = ${err.code}, errMessage = ${err.message}.`); } + try { + windowStage.getMainWindowSync().setWindowLayoutFullScreen(true).catch((err: BusinessError) => { + Logger.error(TAG, `setWindowLayoutFullScreen failed, errCode = ${err.code}, errMessage = ${err.message}.`); + }); + } catch (error) { + let err = error as BusinessError; + Logger.error(TAG, `setWindowLayoutFullScreen failed, errCode = ${err.code}, errMessage = ${err.message}.`); + } + windowStage.loadContent('pages/Index', (err) => { if (err.code) { hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? ''); diff --git a/entry/src/main/ets/pages/Index.ets b/entry/src/main/ets/pages/Index.ets index d8377b2..116350a 100644 --- a/entry/src/main/ets/pages/Index.ets +++ b/entry/src/main/ets/pages/Index.ets @@ -23,6 +23,7 @@ import { DistributeFileManager } from '../controller/DistributeFileManager'; import { SaveFileDialog } from '../components/SaveFileDialog'; import Logger from '../common/utils/Logger'; import { isPermissionGranted } from '../common/utils/PermissionUtil'; +import { getBottomAvoidArea, getTopAvoidArea } from '../common/utils/WindowUtil'; @Entry @Component @@ -39,6 +40,8 @@ struct Player { @State isConnect: boolean = false; @Provide connectFilePath: string = '' private cameraData: CameraDataModel = new CameraDataModel(); + @State statusBarHeight: number = 0; + @State navBarHeight: number = 0; context: UIContext = this.getUIContext(); dialogController: CustomDialogController | undefined = new CustomDialogController({ builder: SaveFileDialog({ @@ -47,6 +50,18 @@ struct Player { customStyle: true, }) + aboutToAppear(): void { + let topAvoidArea = getTopAvoidArea(); + if (topAvoidArea && topAvoidArea.topRect) { + this.statusBarHeight = this.getUIContext().px2vp(topAvoidArea.topRect.height); + } + let bottomAvoidArea = getBottomAvoidArea(); + if (bottomAvoidArea && bottomAvoidArea.bottomRect) { + this.navBarHeight = this.getUIContext().px2vp(bottomAvoidArea.bottomRect.height); + } + Logger.info(`statusBarHeight is ${this.statusBarHeight} navBarHeight is ${this.navBarHeight}`) + } + aboutToDisappear(): void { if (this.cameraData.outputFd !== undefined && this.cameraData.outputFd >= 0) { // Close file fd. @@ -142,6 +157,10 @@ struct Player { .justifyContent(FlexAlign.End) .visibility(this.isLoading ? Visibility.None : Visibility.Visible) .height('100%') + .padding({ + top: this.statusBarHeight, + bottom: this.navBarHeight + }) LoadingProgress() .width(50) diff --git a/entry/src/main/ets/pages/StartConnectLiveStream.ets b/entry/src/main/ets/pages/StartConnectLiveStream.ets index 2dda7ba..88b4c51 100644 --- a/entry/src/main/ets/pages/StartConnectLiveStream.ets +++ b/entry/src/main/ets/pages/StartConnectLiveStream.ets @@ -20,6 +20,7 @@ import { fileIo } from '@kit.CoreFileKit'; import videoPlayer from 'libvideoplayer.so'; import Logger from '../common/utils/Logger'; import { CommonConstants } from '../common/CommonConstants'; +import { setFullScreen } from '../common/utils/WindowUtil'; @Builder export function StartConnectLiveStreamBuilder() { @@ -40,13 +41,6 @@ export struct StartConnectLiveStream { this.connect() } - aboutToDisappear(): void { - if (this.isStartConnect) { - videoPlayer.stopNative() - fileIo.closeSync(this.fd) - } - } - connect() { if (!this.connectFilePath) { try { @@ -80,7 +74,12 @@ export struct StartConnectLiveStream { Stack() { StartLiveRenderView(); StartLiveDecorationView() - .padding(10); + .padding({ + top: 30, + bottom: 10, + right: 10, + left: 10 + }); } .border({ width: 2, @@ -120,12 +119,6 @@ export struct StartConnectLiveStream { .height('100%') .width('100%') } - .onWillHide(() => { - if (this.isStartConnect) { - videoPlayer.stopNative(); - } - }) - .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM]) .hideTitleBar(true) .backgroundColor(Color.Black) } diff --git a/entry/src/main/ets/pages/StartLiveStream.ets b/entry/src/main/ets/pages/StartLiveStream.ets index 64baa27..9295243 100644 --- a/entry/src/main/ets/pages/StartLiveStream.ets +++ b/entry/src/main/ets/pages/StartLiveStream.ets @@ -21,7 +21,6 @@ import { StartLiveDecorationView } from '../view/StartLiveDecorationView'; import { StartLiveRenderView } from '../view/StartLiveRenderView'; import { BgmController } from '../controller/BgmController'; import { DistributeFileManager } from '../controller/DistributeFileManager'; -import { setFullScreen, unSetFullScreen } from '../common/utils/WindowUtil'; import { backgroundTaskManager } from '@kit.BackgroundTasksKit'; const TAG: string = '[StartLiveStream]'; @@ -67,9 +66,8 @@ struct StartLiveStream { right: 24, top: 32, bottom: 32 - }); + }) } - .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM]) .width('100%') .height('100%') .backgroundColor(Color.Black) @@ -81,11 +79,7 @@ struct StartLiveStream { this.pageStack.pop() return true; }) - .onWillHide(() => { - unSetFullScreen(); - }) .onAppear(() => { - setFullScreen(); BackgroundTaskManager.startContinuousTask(backgroundTaskManager.BackgroundMode.AUDIO_RECORDING, uiContext?.getHostContext() as common.UIAbilityContext); }) @@ -95,7 +89,6 @@ struct StartLiveStream { await distributeFileManager.copyFileToDistribute(uiContext?.getHostContext() as common.UIAbilityContext, this.fileNameSandbox); }) - .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM]) .hideTitleBar(true) } diff --git a/entry/src/main/ets/pages/WatchLiveStream.ets b/entry/src/main/ets/pages/WatchLiveStream.ets index 00ca956..61d9217 100644 --- a/entry/src/main/ets/pages/WatchLiveStream.ets +++ b/entry/src/main/ets/pages/WatchLiveStream.ets @@ -13,7 +13,6 @@ * limitations under the License. */ -import { setFullScreen, unSetFullScreen } from '../common/utils/WindowUtil'; import { AvplayerView } from '../view/AvplayerView'; import { WatchLiveDecorationView } from '../view/WatchLiveDecorationView'; @@ -49,22 +48,14 @@ struct WatchLiveStream { }) .hitTestBehavior(HitTestMode.Transparent) } - .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM]) .width('100%') .height('100%') .backgroundColor(Color.Black) } - .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM]) .onBackPressed(() => { this.pageStack.pop(); return true; }) - .onWillAppear(() => { - setFullScreen(); - }) - .onWillHide(() => { - unSetFullScreen(); - }) .hideTitleBar(true) .onReady((context: NavDestinationContext) => { this.filePath = context.pathInfo.param as string; diff --git a/entry/src/main/ets/view/AvplayerView.ets b/entry/src/main/ets/view/AvplayerView.ets index 041c970..eb8132c 100644 --- a/entry/src/main/ets/view/AvplayerView.ets +++ b/entry/src/main/ets/view/AvplayerView.ets @@ -183,10 +183,6 @@ export struct AvplayerView { 'middle': { 'anchor': '__container__', 'align': HorizontalAlign.Center }, 'center': { 'anchor': '__container__', 'align': VerticalAlign.Center } }) - .expandSafeArea( - [SafeAreaType.SYSTEM, SafeAreaType.CUTOUT], - [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM] - ) } .backgroundColor(Color.Black); } diff --git a/entry/src/main/ets/view/StartLiveDecorationView.ets b/entry/src/main/ets/view/StartLiveDecorationView.ets index 5434caf..0f4085b 100644 --- a/entry/src/main/ets/view/StartLiveDecorationView.ets +++ b/entry/src/main/ets/view/StartLiveDecorationView.ets @@ -164,21 +164,27 @@ export struct StartLiveDecorationView { BottomBar() { Stack({ alignContent: Alignment.BottomStart }) { Row() { - Image($r('app.media.toggle_position')) - .width('48vp') - .height('48vp') - .onClick(() => { - // Camera rotation / switching between front and rear cameras - let cameraPosition = this.cameraController.getCameraPosition() - if (cameraPosition === camera.CameraPosition.CAMERA_POSITION_FRONT) { - cameraPosition = camera.CameraPosition.CAMERA_POSITION_BACK; - } else { - cameraPosition = camera.CameraPosition.CAMERA_POSITION_FRONT; - } - this.cameraController.setCameraPosition(cameraPosition); - this.cameraController.releaseCamera(); - this.cameraController.createRecorder(); - }) + Button() { + Image($r('app.media.toggle_position')) + .width('32vp') + .height('32vp') + } + .width('48vp') + .height('48vp') + .type(ButtonType.Circle) + .backgroundColor($r('sys.color.comp_background_tertiary')) + .onClick(() => { + // Camera rotation / switching between front and rear cameras + let cameraPosition = this.cameraController.getCameraPosition() + if (cameraPosition === camera.CameraPosition.CAMERA_POSITION_FRONT) { + cameraPosition = camera.CameraPosition.CAMERA_POSITION_BACK; + } else { + cameraPosition = camera.CameraPosition.CAMERA_POSITION_FRONT; + } + this.cameraController.setCameraPosition(cameraPosition); + this.cameraController.releaseCamera(); + this.cameraController.createRecorder(); + }) Button() { Image($r('app.media.gearshape')) diff --git a/entry/src/main/ets/view/StartLiveRenderView.ets b/entry/src/main/ets/view/StartLiveRenderView.ets index fa7dfb1..e3c76a3 100644 --- a/entry/src/main/ets/view/StartLiveRenderView.ets +++ b/entry/src/main/ets/view/StartLiveRenderView.ets @@ -38,6 +38,5 @@ export struct StartLiveRenderView { .width('100%') .height('100%') } - .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM]) } } \ No newline at end of file -- Gitee