diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/.gitignore b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..fbabf771011fe78f9919db0b1195ab6cadffc2b0 --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/.gitignore @@ -0,0 +1,11 @@ +/node_modules +/oh_modules +/local.properties +/.idea +**/build +/.hvigor +.cxx +/.clangd +/.clang-format +/.clang-tidy +**/.test \ No newline at end of file diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/AppScope/app.json5 b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/AppScope/app.json5 new file mode 100644 index 0000000000000000000000000000000000000000..cea7a13cc28d01b878df19b20d74f21215373b04 --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/AppScope/app.json5 @@ -0,0 +1,10 @@ +{ + "app": { + "bundleName": "com.example.avcodecsample2", + "vendor": "example", + "versionCode": 1000000, + "versionName": "1.0.0", + "icon": "$media:app_icon", + "label": "$string:app_name" + } +} diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/AppScope/resources/base/element/string.json b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/AppScope/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..c1f0ee9c3e781575636c33899c3d277e3e6f78a5 --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/AppScope/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "app_name", + "value": "LowPowerAVSinkDemo" + } + ] +} diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/AppScope/resources/base/media/app_icon.png b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/AppScope/resources/base/media/app_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..cd45accb1dfd2fd0da16c732c72faa6e46b26521 Binary files /dev/null and b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/AppScope/resources/base/media/app_icon.png differ diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/README_zh.md b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/README_zh.md new file mode 100644 index 0000000000000000000000000000000000000000..76c5959f1dca2cd42c39ad9d2f9c0f47f27ffbb5 --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/README_zh.md @@ -0,0 +1,85 @@ +# LowPowerAVSinkSample + +### 介绍 +LowPoweAVSink 部件示例 Sample,提供基础的视频播放的功能。 +- 视频播放的主要流程是将视频文件通过解封装->解码->送显/播放。 +### 效果预览 + +![image-20250704144549540](screenshots/image-202507041445495401.png) + +### 使用说明 + +#### 播放 + +1. 点击选择视频按钮,从文件管理或从图库选取视频,点击确定。 +2. 点击准备,将进行播放前的准备 +3. 点击解码,将启动解码器 +4. 点击首帧,将解码器输出的首帧上屏 +5. 点击音视频,将进行视频播放 +6. 播放过程中可以点击暂停/继续,或者拖动进度条选择播放进度,设置倍速以及音量 +7. 停止播放,可以点击停止,重置,释放操作 + +### 目录 + +仓目录结构如下: + +``` +lpp_demo-sample/entry/src/main/ +├── cpp # Native层 +│ ├── capbilities # 能力接口和实现 +│ │ ├── include # 能力接口 +│ │ ├── demuxer.cpp # 解封装实现 +│ │ ├── lpp_audio_streamer.cpp # 低功耗音频流实现 +│ │ └── lpp_video_streamer.cpp # 低功耗视频流实现 +│ ├── common # 公共模块 +│ │ ├── dfx # 日志 +│ │ ├── lpp_callback.cpp # 低功耗音视频回调实现 +│ │ ├── lpp_callback.h # 低功耗音视频回调接口 +│ │ └── sample_info.h # 功能实现公共类 +│ ├── render # 送显模块接口和实现 * window player设置 +│ │ ├── include # 送显模块接口 +│ │ ├── egl_core.cpp # 送显参数设置 * +│ │ ├── plugin_manager.cpp # 送显模块管理实现 +│ │ └── plugin_render.cpp # 送显逻辑实现 +│ ├── sample # Native层 +│ │ ├── player # Native层播放接口和实现 +│ │ │ ├── Player.cpp # Native层播放功能调用逻辑的实现 +│ │ │ ├── Player.h # Native层播放功能调用逻辑的接口 +│ │ │ ├── PlayerNative.cpp # Native层 播放的入口 +│ │ │ └── PlayerNative.h # Native层暴露上来的接口 +│ ├── types # +│ │ └── libplayer # 播放模块暴露给UI层的接口 +│ └── CMakeLists.txt # 编译入口 +├── ets # UI层 +│ ├── common # 公共模块 +│ │ ├── utils # 共用的工具类 +│ │ │ ├── DateTimeUtils.ets # 获取当前时间 +│ │ │ └── Logger.ts # 日志工具 +│ | └───CommonConstants.ets # 参数常量 +│ ├── entryability # 应用的入口 +│ │ └── EntryAbility.ts # 申请权限弹窗实现 +│ ├── pages # EntryAbility 包含的页面 +│ │ └── Index.ets # 首页/播放页面 +├── resources # 用于存放应用所用到的资源文件 +│ ├── base # 该目录下的资源文件会被赋予唯一的ID +│ │ ├── element # 用于存放字体和颜色 +│ │ ├── media # 用于存放图片 +│ │ └── profile # 应用入口首页 +│ ├── en_US # 设备语言是美式英文时,优先匹配此目录下资源 +│ └── zh_CN # 设备语言是简体中文时,优先匹配此目录下资源 +└── module.json5 # 模块配置信息 +``` + +### 相关权限 +不涉及 + +### 依赖 +不涉及。 + +### 约束与限制 + +1.本示例仅支持在nashville芯片手机平台上运行; + +2.本示例仅支持 API20 及以上版本SDK, SDK版本号(API Version 20 Release); + +3.本示例需要使用DevEco Studio 5.0 才可编译运行。 \ No newline at end of file diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/build-profile.json5 b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..724d6b92a797a459eb51905a580039f627884c28 --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/build-profile.json5 @@ -0,0 +1,59 @@ +{ + "app": { + "products": [ + { + "name": "default", + "signingConfig": "default", + "compatibleSdkVersion": "5.0.0(12)", + //指定HarmonyOS应用/服务兼容的最低版本。注意使用英文.和() + "targetSdkVersion": "5.0.0(12)", + //指定HarmonyOS应用/服务目标版本。若没有设置,默认为compatibleSdkVersion + "runtimeOS": "HarmonyOS", + "buildOption": { + "strictMode": { + "caseSensitiveCheck": true, + "useNormalizedOHMUrl": true + } + } + //指定为HarmonyOS + } + ], + "buildModeSet": [ + { + "name": "debug" + }, + { + "name": "release" + } + ], + "signingConfigs": [ + { + "name": "default", + "type": "HarmonyOS", + "material": { + "certpath": "C:\\Users\\h00916961\\.ohos\\config\\default_lpp_demp_Xq2qcNd5sb_cAEfsdAu5HSWI9RQSO0qxOHcPOa5JI8c=.cer", + "storePassword": "000000195E9836A3034954B4995E15014EE7A68F25F1DCCC4DAC0462C6D04813BB85894450A9392054", + "keyAlias": "debugKey", + "keyPassword": "0000001958CD712E9B303F433FEDFC2E0B9B664E268F34BED3551F8F88811788F08D978612E84DE114", + "profile": "C:\\Users\\h00916961\\.ohos\\config\\default_lpp_demp_Xq2qcNd5sb_cAEfsdAu5HSWI9RQSO0qxOHcPOa5JI8c=.p7b", + "signAlg": "SHA256withECDSA", + "storeFile": "C:\\Users\\h00916961\\.ohos\\config\\default_lpp_demp_Xq2qcNd5sb_cAEfsdAu5HSWI9RQSO0qxOHcPOa5JI8c=.p12" + } + } + ] + }, + "modules": [ + { + "name": "entry", + "srcPath": "./entry", + "targets": [ + { + "name": "default", + "applyToProducts": [ + "default" + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/.gitignore b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..e2713a2779c5a3e0eb879efe6115455592caeea5 --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/.gitignore @@ -0,0 +1,6 @@ +/node_modules +/oh_modules +/.preview +/build +/.cxx +/.test \ No newline at end of file diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/build-profile.json5 b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..4284436e687906bbbacd940c3fc75e0b00088d16 --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/build-profile.json5 @@ -0,0 +1,20 @@ +{ + "apiType": 'stageMode', + "buildOption": { + "externalNativeOptions": { + "abiFilters": ["arm64-v8a", "x86_64"], + "path": "./src/main/cpp/CMakeLists.txt", + "arguments": "", + "cppFlags": "", + } + }, + "targets": [ + { + "name": "default", + "runtimeOS": "HarmonyOS" + }, + { + "name": "ohosTest", + } + ] +} \ No newline at end of file diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/hvigorfile.ts b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..80e4ec5b81689f238c34614b167a0b9e9c83e8d9 --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/hvigorfile.ts @@ -0,0 +1,2 @@ +// Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently. +export { hapTasks } from '@ohos/hvigor-ohos-plugin'; diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/oh-package-lock.json5 b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/oh-package-lock.json5 new file mode 100644 index 0000000000000000000000000000000000000000..4e436cde504d82c4dcc9d47f65226dd915be485f --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/oh-package-lock.json5 @@ -0,0 +1,18 @@ +{ + "meta": { + "stableOrder": true + }, + "lockfileVersion": 3, + "ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.", + "specifiers": { + "libplayer.so@src/main/cpp/types/libplayer": "libplayer.so@src/main/cpp/types/libplayer" + }, + "packages": { + "libplayer.so@src/main/cpp/types/libplayer": { + "name": "libplayer.so", + "version": "1.0.0", + "resolved": "src/main/cpp/types/libplayer", + "registryType": "local" + } + } +} \ No newline at end of file diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/oh-package.json5 b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..c9793421bec94e68ffcbc5e3e569a53f86fd45f5 --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/oh-package.json5 @@ -0,0 +1,12 @@ +{ + "license": "", + "devDependencies": {}, + "author": "", + "name": "entry", + "description": "Please describe the basic information.", + "main": "", + "version": "1.0.0", + "dependencies": { + "libplayer.so": "file:./src/main/cpp/types/libplayer", + } +} diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/CMakeLists.txt b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..5b018f52a3a53d3a35d65a3a2c1d9218afdac882 --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/CMakeLists.txt @@ -0,0 +1,34 @@ +# the minimum version of CMake. +cmake_minimum_required(VERSION 3.4.1) +project(videoCodecSample) + +set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}) + +include_directories(${NATIVERENDER_ROOT_PATH} + ${NATIVERENDER_ROOT_PATH}/capbilities/include + ${NATIVERENDER_ROOT_PATH}/common + ${NATIVERENDER_ROOT_PATH}/common/dfx/err + ${NATIVERENDER_ROOT_PATH}/common/dfx/log + ${NATIVERENDER_ROOT_PATH}/render/include + ${NATIVERENDER_ROOT_PATH}/sample/player +) + +set(BASE_LIBRARY + libace_napi.z.so libEGL.so libGLESv3.so libace_ndk.z.so libuv.so libhilog_ndk.z.so + libnative_media_codecbase.so libnative_media_core.so libnative_media_vdec.so libnative_window.so + libnative_media_venc.so libnative_media_acodec.so libnative_media_avdemuxer.so libnative_media_avsource.so libnative_media_avmuxer.so + libohaudio.so + liblowpower_avsink.so +) +add_library(player SHARED sample/player/PlayerNative.cpp + sample/player/Player.cpp + capbilities/demuxer.cpp + capbilities/lpp_audio_streamer.cpp + capbilities/lpp_video_streamer.cpp + render/egl_core.cpp + render/plugin_render.cpp + render/plugin_manager.cpp + common/lppCallback.cpp +) + +target_link_libraries(player PUBLIC ${BASE_LIBRARY}) \ No newline at end of file diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/capbilities/demuxer.cpp b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/capbilities/demuxer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c086dc873221cce6cea3860779c951fd5dd37707 --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/capbilities/demuxer.cpp @@ -0,0 +1,153 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved. + */ +/* + * Copyright (C) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "demuxer.h" + +#undef LOG_TAG +#define LOG_TAG "Demuxer" + +Demuxer::~Demuxer() +{ + Release(); +} + +int32_t Demuxer::Create(SampleInfo &info) +{ + source_ = OH_AVSource_CreateWithFD(info.inputFd, info.inputFileOffset, info.inputFileSize); + CHECK_AND_RETURN_RET_LOG(source_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, + "Create demuxer source failed, fd: %{public}d, offset: %{public}" PRId64 ", file size: %{public}" PRId64, + info.inputFd, info.inputFileOffset, info.inputFileSize); + demuxer_ = OH_AVDemuxer_CreateWithSource(source_); + CHECK_AND_RETURN_RET_LOG(demuxer_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Create demuxer failed"); + + auto sourceFormat = std::shared_ptr(OH_AVSource_GetSourceFormat(source_), OH_AVFormat_Destroy); + CHECK_AND_RETURN_RET_LOG(sourceFormat != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Get source format failed"); + + int32_t ret = GetTrackInfo(sourceFormat, info); + CHECK_AND_RETURN_RET_LOG(ret == AVCODEC_SAMPLE_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Get video track info failed"); + + return AVCODEC_SAMPLE_ERR_OK; +} + +int32_t Demuxer::ReadSample(int32_t trackId, OH_AVBuffer *buffer, OH_AVCodecBufferAttr &attr) +{ + CHECK_AND_RETURN_RET_LOG(demuxer_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Demuxer is null"); + int32_t ret = OH_AVDemuxer_ReadSampleBuffer(demuxer_, trackId, buffer); + CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Read sample failed"); + ret = OH_AVBuffer_GetBufferAttr(buffer, &attr); + CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "GetBufferAttr failed"); + return AVCODEC_SAMPLE_ERR_OK; +} + +int32_t Demuxer::Release() +{ + AVCODEC_SAMPLE_LOGI("====== Demuxer::Release ======"); + if (demuxer_ != nullptr) { + OH_AVDemuxer_Destroy(demuxer_); + demuxer_ = nullptr; + } + if (source_ != nullptr) { + OH_AVSource_Destroy(source_); + source_ = nullptr; + } + return AVCODEC_SAMPLE_ERR_OK; +} + +int32_t Demuxer::GetTrackInfo(std::shared_ptr sourceFormat, SampleInfo &info) +{ + int32_t trackCount = 0; + OH_AVFormat_GetIntValue(sourceFormat.get(), OH_MD_KEY_TRACK_COUNT, &trackCount); + OH_AVFormat_GetLongValue(sourceFormat.get(), OH_MD_KEY_DURATION, &info.duration); +// AVCODEC_SAMPLE_LOGI("Seek over duration fem %{public}ld",info.duration); + for (int32_t index = 0; index < trackCount; index++) { + int trackType = -1; + auto trackFormat = + std::shared_ptr(OH_AVSource_GetTrackFormat(source_, index), OH_AVFormat_Destroy); + OH_AVFormat_GetIntValue(trackFormat.get(), OH_MD_KEY_TRACK_TYPE, &trackType); + if (trackType == MEDIA_TYPE_VID) { + info.format_video = OH_AVSource_GetTrackFormat(source_, index); + OH_AVDemuxer_SelectTrackByID(demuxer_, index); + OH_AVFormat_GetIntValue(trackFormat.get(), OH_MD_KEY_WIDTH, &info.videoWidth); + OH_AVFormat_GetIntValue(trackFormat.get(), OH_MD_KEY_HEIGHT, &info.videoHeight); + OH_AVFormat_GetDoubleValue(trackFormat.get(), OH_MD_KEY_FRAME_RATE, &info.frameRate); + OH_AVFormat_GetLongValue(trackFormat.get(), OH_MD_KEY_BITRATE, &info.bitrate); + OH_AVFormat_GetIntValue(trackFormat.get(), OH_MD_KEY_ROTATION, &info.rotation); + + char *videoCodecMime; + OH_AVFormat_GetStringValue(trackFormat.get(), + OH_MD_KEY_CODEC_MIME, const_cast(&videoCodecMime)); + info.videoCodecMime = videoCodecMime; + OH_AVFormat_GetIntValue(trackFormat.get(), OH_MD_KEY_PROFILE, &info.hevcProfile); + videoTrackId_ = index; + + AVCODEC_SAMPLE_LOGI("====== Demuxer Video config ======"); + AVCODEC_SAMPLE_LOGI("Mime: %{public}s", videoCodecMime); + AVCODEC_SAMPLE_LOGI("%{public}d*%{public}d, %{public}.1ffps, %{public}" PRId64 "kbps", info.videoWidth, + info.videoHeight, info.frameRate, info.bitrate / 1024); + AVCODEC_SAMPLE_LOGI("====== Demuxer Video config ======"); + } else if (trackType == MEDIA_TYPE_AUD) { + info.format_audio = OH_AVSource_GetTrackFormat(source_, index); + OH_AVDemuxer_SelectTrackByID(demuxer_, index); + OH_AVFormat_GetIntValue(trackFormat.get(), OH_MD_KEY_AUDIO_SAMPLE_FORMAT, &info.audioSampleForamt); + OH_AVFormat_GetIntValue(trackFormat.get(), OH_MD_KEY_AUD_CHANNEL_COUNT, &info.audioChannelCount); + OH_AVFormat_GetLongValue(trackFormat.get(), OH_MD_KEY_CHANNEL_LAYOUT, &info.audioChannelLayout); + OH_AVFormat_GetIntValue(trackFormat.get(), OH_MD_KEY_AUD_SAMPLE_RATE, &info.audioSampleRate); + uint8_t *addr = nullptr; + OH_AVFormat_GetBuffer(trackFormat.get(), "codec_config", &addr, &info.audioCodecSize); + + if (addr != nullptr) { + if (info.audioCodecConfig != nullptr) { + delete[] info.audioCodecConfig; + } + info.audioCodecConfig = new uint8_t[info.audioCodecSize]; + memcpy((void *)info.audioCodecConfig, (void *)addr, info.audioCodecSize); + } + + char *audioCodecMime; + OH_AVFormat_GetStringValue(trackFormat.get(), + OH_MD_KEY_CODEC_MIME, const_cast(&audioCodecMime)); + info.audioCodecMime = audioCodecMime; + audioTrackId_ = index; + + AVCODEC_SAMPLE_LOGI("====== Demuxer Audio config ======"); + AVCODEC_SAMPLE_LOGI("Mime: %{public}s", audioCodecMime); + AVCODEC_SAMPLE_LOGI("audioMime:%{public}s sampleForamt:%{public}d " + "sampleRate:%{public}d channelCount:%{public}d channelLayout:%{public}d", info.audioCodecMime.c_str(), + info.audioSampleForamt, info.audioSampleRate, info.audioChannelCount, info.audioChannelLayout); + AVCODEC_SAMPLE_LOGI("====== Demuxer Audio config ======"); + } + } + + return AVCODEC_SAMPLE_ERR_OK; +} + +int32_t Demuxer::GetVideoTrackId() +{ + return videoTrackId_; +} +int32_t Demuxer::GetAudioTrackId() +{ + return audioTrackId_; +} + +int32_t Demuxer::Seek(int64_t millisecond, OH_AVSeekMode mode) +{ + int32_t ret = OH_AVDemuxer_SeekToTime(demuxer_, millisecond, mode); + CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "seek failed"); + return AVCODEC_SAMPLE_ERR_OK; +} diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/capbilities/include/demuxer.h b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/capbilities/include/demuxer.h new file mode 100644 index 0000000000000000000000000000000000000000..63dea6f880550f0fc442d701e6f9982c62627cb5 --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/capbilities/include/demuxer.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved. + */ +/* + * Copyright (C) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef DEMUXER_H +#define DEMUXER_H + +#include +#include "napi/native_api.h" +#include "multimedia/player_framework/native_avdemuxer.h" +#include "sample_info.h" +#include "dfx/error/av_codec_sample_error.h" +#include "av_codec_sample_log.h" + + +class Demuxer { +public: + Demuxer() = default; + ~Demuxer(); + int32_t Create(SampleInfo &sampleInfo); + int32_t ReadSample(int32_t trackId, OH_AVBuffer *buffer, OH_AVCodecBufferAttr &attr); + int32_t Release(); + int32_t GetVideoTrackId(); + int32_t GetAudioTrackId(); + int32_t Seek(int64_t millisecond, OH_AVSeekMode mode); + +private: + int32_t GetTrackInfo(std::shared_ptr sourceFormat, SampleInfo &info); + + OH_AVSource *source_; + OH_AVDemuxer *demuxer_; + int32_t videoTrackId_; + int32_t audioTrackId_; +}; + +#endif // DEMUXER_H \ No newline at end of file diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/capbilities/include/lpp_audio_streamer.h b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/capbilities/include/lpp_audio_streamer.h new file mode 100644 index 0000000000000000000000000000000000000000..9d5a1248d9e89e90e0666221316d288433862549 --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/capbilities/include/lpp_audio_streamer.h @@ -0,0 +1,63 @@ +// +// Created on 2025/2/26. +// +// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found, +// please include "napi/native_api.h". + +#ifndef AVCODECSAMPLE_MASTER_LPP_AUDIO_STREAMER_H +#define AVCODECSAMPLE_MASTER_LPP_AUDIO_STREAMER_H + +#include +#include +#include +// #include "multimedia/player_framework/native_avbuffer_info.h" +#include "dfx/error/av_codec_sample_error.h" +#include "av_codec_sample_log.h" +#include "sample_info.h" + +class LppAudioStreamer { +public: + LppAudioStreamer() = default; + ~LppAudioStreamer(); + + int32_t Create(const std::string &codecMime); + + int32_t SetCallback(LppUserData *lppUserData); + + int32_t Start(); + + int32_t SetParameter(const SampleInfo &sampleInfo); + + int32_t Prepare(); + + int32_t Resume(); + + int32_t Pause(); + + int32_t Flush(); + + int32_t Stop(); + + int32_t Reset(); + + int32_t Destroy(); + + int32_t SetVolume(const float volume); + + int32_t SetPlayBackSpeed(const float speed); + + int32_t Release(); + + + + int32_t returnFrames(LppUserData *lppUserData); + + + int32_t Configure(); + + bool isAVBufferMode_ = true; + OH_LowPowerAudioSink *lppAudioStreamer_; + OH_LowPowerAudioSinkCallback *lppAudioStreamerCallback_; +}; + +#endif //AVCODECSAMPLE_MASTER_LPP_AUDIO_STREAMER_H diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/capbilities/include/lpp_video_streamer.h b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/capbilities/include/lpp_video_streamer.h new file mode 100644 index 0000000000000000000000000000000000000000..e14c61df713562b9c74fe191556affa8d892feba --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/capbilities/include/lpp_video_streamer.h @@ -0,0 +1,68 @@ +// +// Created on 2025/2/26. +// +// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found, +// please include "napi/native_api.h". + +#ifndef AVCODECSAMPLE_MASTER_LPP_VIDEO_STREAMER_H +#define AVCODECSAMPLE_MASTER_LPP_VIDEO_STREAMER_H + +// #include "multimedia/player_framework/native_avbuffer_info.h" +#include "dfx/error/av_codec_sample_error.h" +#include "av_codec_sample_log.h" +#include +#include +#include +#include "sample_info.h" + +class LppVideoStreamer { +public: + LppVideoStreamer() = default; + ~LppVideoStreamer(); + + int32_t Create(const std::string &codecMime); + + int32_t Configure(const SampleInfo &sampleInfo); + + int32_t SetParameter(const SampleInfo &sampleInfo); + + int32_t SetVideoSurface(const SampleInfo &sampleInfo); + + int32_t Prepare(); + + int32_t StartDecode(bool flag); + + int32_t StartRender(); + + int32_t Pause(); + + int32_t Resume(); + + int32_t Flush(); + + int32_t Stop(); + + int32_t Reset(); + + int32_t Destroy(); + + int32_t Release(); + + int32_t SetSyncAudioStreamer(OH_LowPowerAudioSink *audioStreamer); + + int32_t SetTargetStartFrame(const long framePts, OH_LowPowerVideoSink_OnTargetArrived OnTargetArrived, const long timeoutMs, LppUserData *lppUserData); + + int32_t SetPlaybackSpeed(const float speed); + + int32_t returnFrames(LppUserData *lppUserData); + + int32_t SetCallback(LppUserData *lppUserData); + + int32_t RenderFirstFrame(); + + bool isAVBufferMode_ = true; + OH_LowPowerVideoSink *lppVideoStreamer_; + OH_LowPowerVideoSinkCallback *lppVideoStreamerCallback_; +}; + +#endif //AVCODECSAMPLE_MASTER_LPP_AUDIO_STREAMER_H diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/capbilities/lpp_audio_streamer.cpp b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/capbilities/lpp_audio_streamer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4ebab84236fdd1ec2fc5e20c37f47fe6d06314f5 --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/capbilities/lpp_audio_streamer.cpp @@ -0,0 +1,203 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved. + */ +/* + * Copyright (C) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lpp_audio_streamer.h" +#include "lppCallback.h" +#include "multimedia/player_framework/lowpower_audio_sink_base.h" +#include "multimedia/player_framework/lowpower_audio_sink.h" + +#undef LOG_TAG +#define LOG_TAG "LppAudioStreamer" + +LppAudioStreamer::~LppAudioStreamer() +{ + if(lppAudioStreamer_!=nullptr){ + Release(); + } +} + +int32_t LppAudioStreamer::Create(const std::string &codecMime) +{ + lppAudioStreamer_ = OH_LowPowerAudioSink_CreateByMime(codecMime.c_str()); + AVCODEC_SAMPLE_LOGI("codecMime.c_str() %{public}s", codecMime.c_str()); + CHECK_AND_RETURN_RET_LOG(lppAudioStreamer_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Create failed"); + return AVCODEC_SAMPLE_ERR_OK; +} + +int32_t LppAudioStreamer::SetCallback(LppUserData *lppUserData) +{ + int32_t ret = AV_ERR_OK; + lppAudioStreamerCallback_ = OH_LowPowerAudioSinkCallback_Create(); + OH_LowPowerAudioSinkCallback_SetDataNeededListener(lppAudioStreamerCallback_, LppCallback::OnDataNeeded, lppUserData); + OH_LowPowerAudioSinkCallback_SetErrorListener(lppAudioStreamerCallback_, LppCallback::OnError, lppUserData); + OH_LowPowerAudioSinkCallback_SetPositionUpdateListener(lppAudioStreamerCallback_, LppCallback::OnPositionUpdated, lppUserData); + OH_LowPowerAudioSinkCallback_SetInterruptListener(lppAudioStreamerCallback_, LppCallback::OnInterrupted, lppUserData); + ret = OH_LowPowerAudioSink_RegisterCallback(lppAudioStreamer_, lppAudioStreamerCallback_); + CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Set callback failed, ret: %{public}d", ret); + return AVCODEC_SAMPLE_ERR_OK; +} + +int32_t LppAudioStreamer::Configure() +{ + OH_AVFormat *format = OH_AVFormat_Create(); + int ret = OH_LowPowerAudioSink_Configure(lppAudioStreamer_, format); + CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Configure failed, ret: %{public}d", ret); + return AVCODEC_SAMPLE_ERR_OK; +} + +int32_t LppAudioStreamer::SetVolume(const float volume) +{ + int ret = OH_LowPowerAudioSink_SetVolume(lppAudioStreamer_, volume); + CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "SetVolume failed, ret: %{public}d", ret); + return AVCODEC_SAMPLE_ERR_OK; +} + +int32_t LppAudioStreamer::SetPlayBackSpeed(const float speed) +{ + int ret = OH_LowPowerAudioSink_SetPlaybackSpeed(lppAudioStreamer_, speed); + CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "SetSpeed failed, ret: %{public}d", ret); + return AVCODEC_SAMPLE_ERR_OK; +} + + +int32_t LppAudioStreamer::Start() +{ + int ret = OH_LowPowerAudioSink_Start(lppAudioStreamer_); + CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Start failed, ret: %{public}d", ret); + return AVCODEC_SAMPLE_ERR_OK; +} + +int32_t LppAudioStreamer::returnFrames(LppUserData *lppUserData) +{ + OH_LowPowerAudioSink_ReturnSamples(lppAudioStreamer_, lppUserData->framePacket_); + return AVCODEC_SAMPLE_ERR_OK; +} + +int32_t LppAudioStreamer::SetParameter(const SampleInfo &sampleInfo) +{ + OH_AVFormat *format = OH_AVFormat_Create(); + if (sampleInfo.audioCodecConfig != nullptr) { + OH_AVFormat_SetBuffer(format, "codec_config", sampleInfo.audioCodecConfig, sampleInfo.audioCodecSize); + } +// OH_AudioStreamBuilder_SetLatencyMode(builder_, AUDIOSTREAM_LATENCY_MODE_NORMAL); +// // 设置音频采样率 +// OH_AudioStreamBuilder_SetSamplingRate(builder_, sampleInfo_.audioSampleRate); +// // 设置音频声道 +// OH_AudioStreamBuilder_SetChannelCount(builder_, sampleInfo_.audioChannelCount); +// // 设置音频采样格式 +// OH_AudioStreamBuilder_SetSampleFormat(builder_, AUDIOSTREAM_SAMPLE_S16LE); +// // 设置音频流的编码类型 +// OH_AudioStreamBuilder_SetEncodingType(builder_, AUDIOSTREAM_ENCODING_TYPE_RAW); +// // 设置输出音频流的工作场景 +// OH_AudioStreamBuilder_SetRendererInfo(builder_, AUDIOSTREAM_USAGE_MUSIC); + +// Format format; +// (void)format.PutIntValue(PlayerKeys::STREAM_USAGE, streamUsage); +// (void)format.PutIntValue(PlayerKeys::CONTENT_TYPE, 0); +// (void)format.PutIntValue(PlayerKeys::RENDERER_FLAG, 0); +// 音频送显 +// OH_AVFormat_SetIntValue(format, "CONTENT_TYPE", 0); + // STREAM_USAGE_MOVIE = 10, +// OH_AVFormat_SetIntValue(format, "STREAM_USAGE", 10); +// OH_AVFormat_SetIntValue(format, "SAMPLE_RATE", sampleInfo.audioSampleRate); +// AVCODEC_SAMPLE_LOGI("audioSampleRate %{public}d", sampleInfo.audioSampleRate); +// OH_AVFormat_SetIntValue(format, "RENDERER_FLAG", 5); +// // ENCODING_PCM = 0, +// OH_AVFormat_SetIntValue(format, "ENCODING", 0); +// // SAMPLE_S16LE = 1, +// OH_AVFormat_SetIntValue(format, "SAMPLE_FORMAT", SAMPLE_S16LE); +// // CHANNEL_6 = 6, +// OH_AVFormat_SetIntValue(format, "CHANNEL", sampleInfo.audioChannelCount); + +// 音频解码 +// const char *OH_MD_KEY_AUDIO_SAMPLE_FORMAT = "audio_sample_format"; + OH_AVFormat_SetIntValue(format, "audio_sample_format", SAMPLE_S16LE); + OH_AVFormat_SetIntValue(format, "audio.raw.sample.format", 24); +// OH_AVFormat_SetIntValue(format, "audio_sample_format", sampleInfo.audioSampleForamt); +// const char *OH_MD_KEY_AUD_CHANNEL_COUNT = "channel_count"; + OH_AVFormat_SetIntValue(format, "channel_count", sampleInfo.audioChannelCount); + AVCODEC_SAMPLE_LOGI("audioChannelCount %{public}d", sampleInfo.audioChannelCount); +// const char *OH_MD_KEY_AUD_SAMPLE_RATE = "sample_rate"; + OH_AVFormat_SetIntValue(format, "sample_rate", sampleInfo.audioSampleRate); +// const char *OH_MD_KEY_CHANNEL_LAYOUT = "channel_layout"; + OH_AVFormat_SetLongValue(format, "channel_layout", sampleInfo.audioChannelLayout); + OH_LowPowerAudioSink_Configure(lppAudioStreamer_, format); +// OH_LowPowerAudioSink_SetParameter(lppAudioStreamer_, format); + return AVCODEC_SAMPLE_ERR_OK; +} + +int32_t LppAudioStreamer::Prepare() +{ + auto ret = OH_LowPowerAudioSink_Prepare(lppAudioStreamer_); + CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Prepare failed."); + return AVCODEC_SAMPLE_ERR_OK; +} + +int32_t LppAudioStreamer::Pause() +{ + auto ret = OH_LowPowerAudioSink_Pause(lppAudioStreamer_); + CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Pause failed."); + return AVCODEC_SAMPLE_ERR_OK; +} + +int32_t LppAudioStreamer::Resume() +{ + auto ret = OH_LowPowerAudioSink_Resume(lppAudioStreamer_); + CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Resume failed."); + return AVCODEC_SAMPLE_ERR_OK; +} + +int32_t LppAudioStreamer::Flush() +{ + auto ret = OH_LowPowerAudioSink_Flush(lppAudioStreamer_); + CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Flush failed."); + return AVCODEC_SAMPLE_ERR_OK; +} + +int32_t LppAudioStreamer::Stop() +{ + auto ret = OH_LowPowerAudioSink_Stop(lppAudioStreamer_); + CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Stop failed."); + return AVCODEC_SAMPLE_ERR_OK; +} + +int32_t LppAudioStreamer::Reset() +{ + AVCODEC_SAMPLE_LOGI("reset in3"); + auto ret = OH_LowPowerAudioSink_Reset(lppAudioStreamer_); + CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Reset failed."); + AVCODEC_SAMPLE_LOGI("reset in6"); + return AVCODEC_SAMPLE_ERR_OK; +} + +int32_t LppAudioStreamer::Destroy() +{ + AVCODEC_SAMPLE_LOGI("====== LppAudioStreamer Destroy ======"); + auto ret = OH_LowPowerAudioSink_Destroy(lppAudioStreamer_); + CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Destroy failed."); + lppAudioStreamer_ = nullptr; + return AVCODEC_SAMPLE_ERR_OK; +} + +int32_t LppAudioStreamer::Release() +{ + Stop(); + Destroy(); + return AVCODEC_SAMPLE_ERR_OK; +} + diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/capbilities/lpp_video_streamer.cpp b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/capbilities/lpp_video_streamer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4e772a0ff7a947f209c3d8ac8bc5186ac9670dea --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/capbilities/lpp_video_streamer.cpp @@ -0,0 +1,220 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved. + */ +/* + * Copyright (C) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lpp_video_streamer.h" +#include "lppCallback.h" +#include "multimedia/player_framework/lowpower_audio_sink_base.h" +#include "multimedia/player_framework/lowpower_audio_sink.h" +#include "multimedia/player_framework/lowpower_video_sink.h" +#include "multimedia/player_framework/lowpower_video_sink_base.h" +#include "multimedia/player_framework/lowpower_avsink_base.h" +// #include + +#undef LOG_TAG +#define LOG_TAG "LppVideoStreamer" + +LppVideoStreamer::~LppVideoStreamer() +{ + if(lppVideoStreamer_!=nullptr){ + Release(); + } +} + +int32_t LppVideoStreamer::Create(const std::string &codecMime) +{ + lppVideoStreamer_ = OH_LowPowerVideoSink_CreateByMime(codecMime.c_str()); + CHECK_AND_RETURN_RET_LOG(lppVideoStreamer_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Create failed"); + return AVCODEC_SAMPLE_ERR_OK; +} + +int32_t LppVideoStreamer::SetCallback(LppUserData *lppUserData) +{ + int32_t ret = AV_ERR_OK; + lppVideoStreamerCallback_ = OH_LowPowerVideoSinkCallback_Create(); + OH_LowPowerVideoSinkCallback_SetDataNeededListener(lppVideoStreamerCallback_, LppCallback::OnDataNeededVideo, lppUserData); + OH_LowPowerVideoSinkCallback_SetErrorListener(lppVideoStreamerCallback_, LppCallback::OnError, lppUserData); + OH_LowPowerVideoSinkCallback_SetStreamChangedListener(lppVideoStreamerCallback_, LppCallback::OH_LowPowerVideoSink_OnStreamChanged, lppUserData); + ret = OH_LowPowerVideoSink_RegisterCallback(lppVideoStreamer_, lppVideoStreamerCallback_); + CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Set callback failed, ret: %{public}d", ret); + + return AVCODEC_SAMPLE_ERR_OK; +} + +int32_t LppVideoStreamer::Configure(const SampleInfo &sampleInfo) +{ + OH_AVFormat *format = OH_AVFormat_Create(); + CHECK_AND_RETURN_RET_LOG(format != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "AVFormat create failed"); + format = sampleInfo.format_video; + OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, sampleInfo.videoWidth); + OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, sampleInfo.videoHeight); + OH_AVFormat_SetDoubleValue(format, OH_MD_KEY_FRAME_RATE, sampleInfo.frameRate); + OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, sampleInfo.pixelFormat); + OH_AVFormat_SetIntValue(format, OH_MD_KEY_ROTATION, sampleInfo.rotation); + OH_AVFormat_SetIntValue(format, "lpp", true); + AVCODEC_SAMPLE_LOGI("====== VideoDecoder config ======"); + AVCODEC_SAMPLE_LOGI("%{public}d*%{public}d, %{public}.1ffps, %{public}d,%{public}d", sampleInfo.videoWidth, sampleInfo.videoHeight, + sampleInfo.frameRate,sampleInfo.pixelFormat,sampleInfo.rotation); + AVCODEC_SAMPLE_LOGI("====== VideoDecoder config ======"); + int ret = OH_LowPowerVideoSink_Configure(lppVideoStreamer_, format); + CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Configure failed, ret: %{public}d", ret); + return AVCODEC_SAMPLE_ERR_OK; +} + +int32_t LppVideoStreamer::returnFrames(LppUserData *lppUserData) +{ + auto ret = OH_LowPowerVideoSink_ReturnSamples(lppVideoStreamer_, lppUserData->framePacket_); + CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "returnFrames failed."); + return AVCODEC_SAMPLE_ERR_OK; +} + +int32_t LppVideoStreamer::SetParameter(const SampleInfo &sampleInfo) +{ + + OH_AVFormat *format = OH_AVFormat_Create(); + CHECK_AND_RETURN_RET_LOG(format != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "AVFormat create failed"); + + OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, sampleInfo.videoWidth); + OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, sampleInfo.videoHeight); + OH_AVFormat_SetDoubleValue(format, OH_MD_KEY_FRAME_RATE, sampleInfo.frameRate); + OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, sampleInfo.pixelFormat); + OH_AVFormat_SetIntValue(format, OH_MD_KEY_ROTATION, sampleInfo.rotation); + + AVCODEC_SAMPLE_LOGI("====== VideoDecoder config ======"); + AVCODEC_SAMPLE_LOGI("%{public}d*%{public}d, %{public}.1ffps", sampleInfo.videoWidth, sampleInfo.videoHeight, + sampleInfo.frameRate); + AVCODEC_SAMPLE_LOGI("====== VideoDecoder config ======"); + int ret = OH_LowPowerVideoSink_SetParameter(lppVideoStreamer_, format); + CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Configure failed, ret: %{public}d", ret); + return AVCODEC_SAMPLE_ERR_OK; +} + +int32_t LppVideoStreamer::Prepare() +{ + auto ret = OH_LowPowerVideoSink_Prepare(lppVideoStreamer_); + CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Prepare failed."); + return AVCODEC_SAMPLE_ERR_OK; +} + +int32_t LppVideoStreamer::Resume() +{ + auto ret = OH_LowPowerVideoSink_Resume(lppVideoStreamer_); + CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Prepare failed."); + return AVCODEC_SAMPLE_ERR_OK; +} + +int32_t LppVideoStreamer::Flush() +{ + auto ret = OH_LowPowerVideoSink_Flush(lppVideoStreamer_); + CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Prepare failed."); + return AVCODEC_SAMPLE_ERR_OK; +} + +int32_t LppVideoStreamer::Stop() +{ + auto ret = OH_LowPowerVideoSink_Stop(lppVideoStreamer_); + CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Prepare failed."); + return AVCODEC_SAMPLE_ERR_OK; +} + +int32_t LppVideoStreamer::Reset() +{ +// AVCODEC_SAMPLE_LOGI("reset in4"); + auto ret = OH_LowPowerVideoSink_Reset(lppVideoStreamer_); + CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Prepare failed."); +// AVCODEC_SAMPLE_LOGI("reset in5"); + return AVCODEC_SAMPLE_ERR_OK; +} + +int32_t LppVideoStreamer::Destroy() +{ + auto ret = OH_LowPowerVideoSink_Destroy(lppVideoStreamer_); + CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Prepare failed."); + lppVideoStreamer_ = nullptr; + return AVCODEC_SAMPLE_ERR_OK; +} + +int32_t LppVideoStreamer::StartDecode(bool flag) +{ + auto ret = OH_LowPowerVideoSink_StartDecoder(lppVideoStreamer_); + CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Prepare failed."); + return AVCODEC_SAMPLE_ERR_OK; +} + +int32_t LppVideoStreamer::StartRender() +{ + auto ret = OH_LowPowerVideoSink_StartRenderer(lppVideoStreamer_); + CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Prepare failed."); + return AVCODEC_SAMPLE_ERR_OK; +} + +int32_t LppVideoStreamer::Pause() +{ + auto ret = OH_LowPowerVideoSink_Pause(lppVideoStreamer_); + CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Prepare failed."); + return AVCODEC_SAMPLE_ERR_OK; +} + +int32_t LppVideoStreamer::SetVideoSurface(const SampleInfo &sampleInfo) +{ +// sampleInfo.window = NativeXComponentSample::PluginManager::GetInstance()->pluginWindow_; + if (sampleInfo.window != nullptr) { + auto ret = OH_LowPowerVideoSink_SetVideoSurface(lppVideoStreamer_, sampleInfo.window); + CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Prepare failed."); + } + return AVCODEC_SAMPLE_ERR_OK; +} + +int32_t LppVideoStreamer::SetSyncAudioStreamer(OH_LowPowerAudioSink *audioStreamer) +{ + auto ret = OH_LowPowerVideoSink_SetSyncAudioSink(lppVideoStreamer_, audioStreamer); + CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Prepare failed."); + return AVCODEC_SAMPLE_ERR_OK; +} + +int32_t LppVideoStreamer::SetTargetStartFrame(const long framePts, OH_LowPowerVideoSink_OnTargetArrived onTargetArrived, const long timeoutMs, LppUserData *lppUserData) +{ + auto ret = OH_LowPowerVideoSink_SetTargetStartFrame(lppVideoStreamer_, framePts, onTargetArrived, timeoutMs, lppUserData); + CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Prepare failed."); + return AVCODEC_SAMPLE_ERR_OK; +} + +int32_t LppVideoStreamer::SetPlaybackSpeed(const float speed) +{ + auto ret = OH_LowPowerVideoSink_SetPlaybackSpeed(lppVideoStreamer_, speed); + CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Prepare failed."); + return AVCODEC_SAMPLE_ERR_OK; +} + +int32_t LppVideoStreamer::Release() +{ + Stop(); + Destroy(); + return AVCODEC_SAMPLE_ERR_OK; +} + +int32_t LppVideoStreamer::RenderFirstFrame() +{ + auto ret = OH_LowPowerVideoSink_RenderFirstFrame(lppVideoStreamer_); + CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Prepare failed."); + return AVCODEC_SAMPLE_ERR_OK; +} + +// int32_t LppVideoStreamer::StartDecode(bool flag) +// { +// OH_LowPowerVideoSink_StartDecode(lppVideoStreamer_, flag); +// } diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/common/dfx/error/av_codec_sample_error.h b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/common/dfx/error/av_codec_sample_error.h new file mode 100644 index 0000000000000000000000000000000000000000..243380754cabfd20d5c35dedd32c18b335dd8870 --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/common/dfx/error/av_codec_sample_error.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved. + */ +/* + * Copyright (C) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef AVCODEC_SAMPLE_ERROE_H +#define AVCODEC_SAMPLE_ERROE_H + +enum AVCodecSampleError : int { + AVCODEC_SAMPLE_ERR_OK = 0, + AVCODEC_SAMPLE_ERR_ERROR = -1, +}; + +#endif // AVCODEC_SAMPLE_ERROE_H \ No newline at end of file diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/common/dfx/log/av_codec_sample_log.h b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/common/dfx/log/av_codec_sample_log.h new file mode 100644 index 0000000000000000000000000000000000000000..6da1a6dc302ca88e713bd7c6044334437c2b78e7 --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/common/dfx/log/av_codec_sample_log.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved. + */ +/* + * Copyright (C) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef AVCODEC_SAMPLE_LOG_H +#define AVCODEC_SAMPLE_LOG_H + +#include +#include + +#undef LOG_DOMAIN +#define LOG_DOMAIN 0x0002B66 + +#define AVCODEC_SAMPLE_LOG_FREQ_LIMIT(frequency) \ + if (1) { \ + thread_local uint64_t currentTimes = 0; \ + if (currentTimes++ % ((uint64_t)(frequency)) != 0) { \ + break; \ + } \ + } + +#define AVCODEC_SAMPLE_LOG(func, fmt, args...) \ + do { \ + (void)func(LOG_APP, "{%{public}s():%{public}d} " fmt, __FUNCTION__, __LINE__, ##args); \ + } while (0) + +#define AVCODEC_SAMPLE_LOGF(fmt, ...) AVCODEC_SAMPLE_LOG(OH_LOG_FATAL, fmt, ##__VA_ARGS__) +#define AVCODEC_SAMPLE_LOGE(fmt, ...) AVCODEC_SAMPLE_LOG(OH_LOG_ERROR, fmt, ##__VA_ARGS__) +#define AVCODEC_SAMPLE_LOGW(fmt, ...) AVCODEC_SAMPLE_LOG(OH_LOG_WARN, fmt, ##__VA_ARGS__) +#define AVCODEC_SAMPLE_LOGI(fmt, ...) AVCODEC_SAMPLE_LOG(OH_LOG_INFO, fmt, ##__VA_ARGS__) +#define AVCODEC_SAMPLE_LOGD(fmt, ...) AVCODEC_SAMPLE_LOG(OH_LOG_DEBUG, fmt, ##__VA_ARGS__) +#define AVCODEC_SAMPLE_LOGD_LIMIT(frequency, fmt, ...) \ + do { \ + AVCODEC_SAMPLE_LOG_FREQ_LIMIT(frequency); \ + AVCODEC_SAMPLE_LOGD(fmt, ##__VA_ARGS__); \ + } while (0) + +#define CHECK_AND_RETURN_RET_LOG(cond, ret, fmt, ...) \ + do { \ + if (!(cond)) { \ + AVCODEC_SAMPLE_LOGE(fmt, ##__VA_ARGS__); \ + return ret; \ + } \ + } while (0) + +#define CHECK_AND_RETURN_LOG(cond, fmt, ...) \ + do { \ + if (!(cond)) { \ + AVCODEC_SAMPLE_LOGE(fmt, ##__VA_ARGS__); \ + return; \ + } \ + } while (0) + +#define CHECK_AND_BREAK_LOG(cond, fmt, ...) \ + if (1) { \ + if (!(cond)) { \ + AVCODEC_SAMPLE_LOGW(fmt, ##__VA_ARGS__); \ + break; \ + } \ + } else void (0) + +#define CHECK_AND_CONTINUE_LOG(cond, fmt, ...) \ + if (1) { \ + if (!(cond)) { \ + AVCODEC_SAMPLE_LOGW(fmt, ##__VA_ARGS__); \ + continue; \ + } \ + } else void (0) + +#endif // AVCODEC_SAMPLE_LOG_H \ No newline at end of file diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/common/lppCallback.cpp b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/common/lppCallback.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0a31eda78b7a78f5b3b5ed4739838ce20d704671 --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/common/lppCallback.cpp @@ -0,0 +1,150 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved. + */ +/* + * Copyright (C) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "av_codec_sample_log.h" +#include "lppCallback.h" +#include "sample_info.h" + +namespace { +constexpr int LIMIT_LOGD_FREQUENCY = 50; +} + +#undef LOG_TAG +#define LOG_TAG "lppcallback" + +void LppCallback::OnDataNeeded(OH_LowPowerAudioSink *decoder, OH_AVSamplesBuffer *framePacket, void *userData) +{ +// AVCODEC_SAMPLE_LOGI("OnDataNeeded"); + LppUserData *lppUserData = static_cast(userData); + std::unique_lock lock(lppUserData->inputMutex); + if(lppUserData->framePacket_==nullptr) + { +// AVCODEC_SAMPLE_LOGI("ggggfd"); + } + lppUserData->framePacket_ = framePacket; + if(lppUserData->framePacket_==nullptr) + { +// AVCODEC_SAMPLE_LOGI("ggdfsd"); + } + lppUserData->count++; + lppUserData->returnFrame = true; + lppUserData->inputCond.notify_all(); + lock.unlock(); +} + +void LppCallback::OnPositionUpdated(OH_LowPowerAudioSink *decoder, long currentPosition, void *userData) +{ + AVCODEC_SAMPLE_LOGI("currentPosition %{public}ld",currentPosition); + LppUserData *lppUserData = static_cast(userData); + std::unique_lock lock(lppUserData->inputMutex); + lppUserData->position = currentPosition; + lock.unlock(); +} + +void LppCallback::OnError(OH_LowPowerAudioSink *decoder, OH_AVErrCode errCode, const char *errorMsg, void *userData) +{ + AVCODEC_SAMPLE_LOGI("errCode %{public}d",errCode); +} + +void LppCallback::OnInterrupted(OH_LowPowerAudioSink *decoder, OH_AudioInterrupt_ForceType type, OH_AudioInterrupt_Hint hint, void *userData) +{ + AVCODEC_SAMPLE_LOGI("callback OnInterrupted %{public}d", type); + LppUserData *lppUserData = static_cast(userData); + std::unique_lock lock(lppUserData->inputMutex); + lppUserData->audioCallback(lppUserData->audioCallbackData); + lock.unlock(); + +} + +void LppCallback::OnDeviceChanged(OH_LowPowerAudioSink *decoder, OH_AudioStream_DeviceChangeReason reason, void *userData) +{ + AVCODEC_SAMPLE_LOGI("reason %{public}d",reason); +} + +void LppCallback::OnEos(OH_LowPowerAudioSink *decoder, void * userData) +{ +// AVCODEC_SAMPLE_LOGI("reason %{public}d",reason); +} + +void LppCallback::OnDataNeededVideo(OH_LowPowerVideoSink *streamer, OH_AVSamplesBuffer *framePacket, void *userData) +{ + AVCODEC_SAMPLE_LOGI("OH_LowPowerVideoSink OnDataNeeded"); + LppUserData *lppUserData = static_cast(userData); + std::unique_lock lock(lppUserData->inputMutex); + if(lppUserData->framePacket_==nullptr) + { +// AVCODEC_SAMPLE_LOGI("ggggfd"); + } + lppUserData->framePacket_ = framePacket; + if(lppUserData->framePacket_==nullptr) + { +// AVCODEC_SAMPLE_LOGI("ggdfsd"); + } +// AVCODEC_SAMPLE_LOGI("OH_LowPowerVideoSink OnDataNeeded"); + lppUserData->count++; + lppUserData->returnFrame = true; + lppUserData->inputCond.notify_all(); +// AVCODEC_SAMPLE_LOGI("OH_LowPowerVideoSink OnDataNeeded notify"); +// AVCODEC_SAMPLE_LOGI("OH_LowPowerVideoSink num %{public}d",lppUserData->num); +} + +void LppCallback::OnAnchorUpdated(OH_LowPowerVideoSink *streamer, long *anchorPts, long *anchorClock, void *userData) +{ + +} + +void LppCallback::OnError(OH_LowPowerVideoSink *streamer, OH_AVErrCode errCode, const char *errMsg, void *userData) +{ + AVCODEC_SAMPLE_LOGI("errCode %{public}d",errCode); +} + +void LppCallback::OnTargetArrived(OH_LowPowerVideoSink *streamer, const long targetPts, const bool isTimeout, void *userData) +{ + LppUserData *lppUserData = static_cast(userData); + std::unique_lock lock(lppUserData->seekMutex_); + AVCODEC_SAMPLE_LOGI("OnTargetArrived accSeek"); + if(isTimeout){ + AVCODEC_SAMPLE_LOGI("OnTargetArrived timeout"); + } + lppUserData->inputCond.notify_all(); +} + +void LppCallback::OH_LowPowerVideoSink_OnStreamChanged(OH_LowPowerVideoSink *streamer, OH_AVFormat *format, void *userData) +{ + if(format == nullptr){ + AVCODEC_SAMPLE_LOGI("OnOutputFormatChanged format nullptr"); + return; + } + int32_t width = 0; + OH_AVFormat_GetIntValue(format, "video_picture_width", &width); + int32_t height = 0; + OH_AVFormat_GetIntValue(format, "video_picture_height", &height); + AVCODEC_SAMPLE_LOGI("OnOutputFormatChanged width= %{public}d height= %{public}d",width, height); +} + +void LppCallback::OnRenderStarted(OH_LowPowerVideoSink *streamer, void *userData) +{ + +} + +void LppCallback::OnEos(OH_LowPowerVideoSink *streamer, void *userData) +{ + +} + + diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/common/lppCallback.h b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/common/lppCallback.h new file mode 100644 index 0000000000000000000000000000000000000000..2b24f5a3f68ad9606b4f07dbc86b95e4cc6b4d7c --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/common/lppCallback.h @@ -0,0 +1,44 @@ +// +// Created on 2025/2/26. +// +// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found, +// please include "napi/native_api.h". + +#ifndef AVCODECSAMPLE_MASTER_LPPCALLBACK_H +#define AVCODECSAMPLE_MASTER_LPPCALLBACK_H + +#include +#include +#include +class LppCallback { +public: + static void OnDataNeeded(OH_LowPowerAudioSink *decoder, OH_AVSamplesBuffer *framePacket, void *userData); + + static void OnPositionUpdated(OH_LowPowerAudioSink *decoder, long currentPosition, void *userData); + + static void OnError(OH_LowPowerAudioSink *decoder, OH_AVErrCode errCode, const char *errorMsg, void *userData); + + static void OnInterrupted(OH_LowPowerAudioSink *decoder, OH_AudioInterrupt_ForceType type, OH_AudioInterrupt_Hint hint, void *userData); + + static void OnDeviceChanged(OH_LowPowerAudioSink *decoder, OH_AudioStream_DeviceChangeReason reason, void *userData); + + static void OnEos(OH_LowPowerAudioSink *decoder, void * userData); + + // + static void OnDataNeededVideo(OH_LowPowerVideoSink *streamer, OH_AVSamplesBuffer *framePacket, void *userData); + + static void OnAnchorUpdated(OH_LowPowerVideoSink *streamer, long *anchorPts, long *anchorClock, void *userData); + + static void OnError(OH_LowPowerVideoSink *streamer, OH_AVErrCode errCode, const char *errMsg, void *userData); + + static void OnTargetArrived(OH_LowPowerVideoSink *streamer, const long targetPts, const bool isTimeout, void *userData); + + static void OnRenderStarted(OH_LowPowerVideoSink *streamer, void *userData); + + static void OnEos(OH_LowPowerVideoSink *streamer, void *userData); + + static void OH_LowPowerVideoSink_OnStreamChanged(OH_LowPowerVideoSink *streamer, OH_AVFormat *format, void *userData); + +}; + +#endif //AVCODECSAMPLE_MASTER_LPPCALLBACK_H diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/common/sample_info.h b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/common/sample_info.h new file mode 100644 index 0000000000000000000000000000000000000000..adf2922064695bfc5d52095dae5a9762c2e37b06 --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/common/sample_info.h @@ -0,0 +1,126 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved. + */ +/* + * Copyright (C) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef AVCODEC_SAMPLE_INFO_H +#define AVCODEC_SAMPLE_INFO_H +#include +#include +#include +#include +#include +#include +#include "multimedia/player_framework/native_avdemuxer.h" +#include +#include +#include +#include +#include +#include "multimedia/player_framework/native_avcodec_base.h" +#include "multimedia/player_framework/native_avbuffer.h" + +const std::string_view MIME_VIDEO_AVC = "video/avc"; +const std::string_view MIME_VIDEO_HEVC = "video/hevc"; +const std::string_view MIME_AUDIO_MPEG = "audio/mpeg"; + +constexpr int32_t BITRATE_10M = 10 * 1024 * 1024; // 10Mbps +constexpr int32_t BITRATE_20M = 20 * 1024 * 1024; // 20Mbps +constexpr int32_t BITRATE_30M = 30 * 1024 * 1024; // 30Mbps + +struct SampleInfo { + OH_AVFormat* format_audio; + OH_AVFormat* format_video; + int32_t inputFd = -1; + int32_t outputFd = -1; + int64_t inputFileOffset = 0; + int64_t inputFileSize = 0; + std::string inputFilePath; + std::string videoCodecMime = ""; + std::string audioCodecMime = ""; + int32_t videoWidth = 0; + int32_t videoHeight = 0; + double frameRate = 0.0; + int64_t bitrate = 10 * 1024 * 1024; // 10Mbps; + int64_t frameInterval = 0; + OH_AVPixelFormat pixelFormat = AV_PIXEL_FORMAT_NV12; + uint32_t bitrateMode = CBR; + int32_t iFrameInterval = 100; + int32_t rangFlag = 1; + + int32_t audioSampleForamt = 0; + int32_t audioSampleRate = 0; + int32_t audioChannelCount = 0; + int64_t audioChannelLayout = 0; + int64_t duration = 0; + uint8_t* audioCodecConfig = nullptr; + size_t audioCodecSize = 0; + bool isInit = false; + + + int32_t isHDRVivid = 0; + int32_t hevcProfile = HEVC_PROFILE_MAIN; + OH_ColorPrimary primary = COLOR_PRIMARY_BT2020; + OH_TransferCharacteristic transfer = TRANSFER_CHARACTERISTIC_HLG; + OH_MatrixCoefficient matrix = MATRIX_COEFFICIENT_BT2020_CL; + + int32_t rotation = 0; + OHNativeWindow *window = nullptr; + + void (*playDoneCallback)(void *context) = nullptr; + void (*audioCallback)(void *context) = nullptr; + void *playDoneCallbackData = nullptr; + void *audioCallbackData = nullptr; +}; + +struct CodecBufferInfo { + uint32_t bufferIndex = 0; + uintptr_t *buffer = nullptr; + uint8_t *bufferAddr = nullptr; + OH_AVCodecBufferAttr attr = {0, 0, 0, AVCODEC_BUFFER_FLAGS_NONE}; + + explicit CodecBufferInfo(uint8_t *addr) : bufferAddr(addr){}; + CodecBufferInfo(uint8_t *addr, int32_t bufferSize) + : bufferAddr(addr), attr({0, bufferSize, 0, AVCODEC_BUFFER_FLAGS_NONE}){}; + CodecBufferInfo(uint32_t argBufferIndex, OH_AVBuffer *argBuffer) + : bufferIndex(argBufferIndex), buffer(reinterpret_cast(argBuffer)) + { + OH_AVBuffer_GetBufferAttr(argBuffer, &attr); + }; +}; + +struct LppUserData { +public: + std::mutex inputMutex; + std::condition_variable inputCond; + std::condition_variable eosCond_; + std::mutex eosMutex; + std::mutex eosFlagMutex; + bool eosFlag_ {false}; + OH_AVSamplesBuffer *framePacket_ = nullptr; + std::queue cacheQueue; + bool returnFrame = false; + int32_t num = 0; + int32_t count = 0; + std::mutex seekMutex_; + std::condition_variable seekCond_; + bool seekReturn_ = false; + int64_t position = 0; + void (*audioCallback)(void *context) = nullptr; + void *audioCallbackData = nullptr; + +}; +#endif // AVCODEC_SAMPLE_INFO_H \ No newline at end of file diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/render/egl_core.cpp b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/render/egl_core.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b76ac01ca65e3fedda7c996091301a78c0e9a7f9 --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/render/egl_core.cpp @@ -0,0 +1,385 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved. + */ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "egl_core.h" + +#include +#include +#include +#include +#include +#include + +#include "plugin_render.h" + +#undef LOG_TAG +#define LOG_TAG "EGLCORE" + +namespace NativeXComponentSample { +namespace { +constexpr uint32_t LOG_PRINT_DOMAIN = 0xFF00; +constexpr int32_t NUM_4 = 4; +/** + * Vertex shader. + */ +const char VERTEX_SHADER[] = "#version 300 es\n" + "layout(location = 0) in vec4 a_position;\n" + "layout(location = 1) in vec4 a_color; \n" + "out vec4 v_color; \n" + "void main() \n" + "{ \n" + " gl_Position = a_position; \n" + " v_color = a_color; \n" + "} \n"; + +/** + * Fragment shader. + */ +const char FRAGMENT_SHADER[] = "#version 300 es\n" + "precision mediump float; \n" + "in vec4 v_color; \n" + "out vec4 fragColor; \n" + "void main() \n" + "{ \n" + " fragColor = v_color; \n" + "} \n"; + +/** + * Background color #f4f4f4. + */ +const GLfloat BACKGROUND_COLOR[] = {244.0f / 255, 244.0f / 255, 244.0f / 255, 1.0f}; + +/** + * Draw color #7E8FFB. + */ +const GLfloat DRAW_COLOR[] = {126.0f / 255, 143.0f / 255, 251.0f / 255, 1.0f}; + +/** + * Change color #92D6CC. + */ +const GLfloat CHANGE_COLOR[] = {146.0f / 255, 214.0f / 255, 204.0f / 255, 1.0f}; + +/** + * Background area. + */ +const GLfloat BACKGROUND_RECTANGLE_VERTICES[] = { + -1.0f, 1.0f, + 1.0f, 1.0f, + 1.0f, -1.0f, + -1.0f, -1.0f}; + +/** + * Get context parameter count. + */ +const size_t GET_CONTEXT_PARAM_CNT = 1; + +/** + * Fifty percent. + */ +const float FIFTY_PERCENT = 0.5; + +/** + * Pointer size. + */ +const GLint POINTER_SIZE = 2; + +/** + * Triangle fan size. + */ +const GLsizei TRIANGLE_FAN_SIZE = 4; + +/** + * Egl red size default. + */ +const int EGL_RED_SIZE_DEFAULT = 8; + +/** + * Egl green size default. + */ +const int EGL_GREEN_SIZE_DEFAULT = 8; + +/** + * Egl blue size default. + */ +const int EGL_BLUE_SIZE_DEFAULT = 8; + +/** + * Egl alpha size default. + */ +const int EGL_ALPHA_SIZE_DEFAULT = 8; + +/** + * Default x position. + */ +const int DEFAULT_X_POSITION = 0; + +/** + * Default y position. + */ +const int DEFAULT_Y_POSITION = 0; + +/** + * Gl red default. + */ +const GLfloat GL_RED_DEFAULT = 0.0; + +/** + * Gl green default. + */ +const GLfloat GL_GREEN_DEFAULT = 0.0; + +/** + * Gl blue default. + */ +const GLfloat GL_BLUE_DEFAULT = 0.0; + +/** + * Gl alpha default. + */ +const GLfloat GL_ALPHA_DEFAULT = 1.0; + +/** + * Program error. + */ +const GLuint PROGRAM_ERROR = 0; + +/** + * Shape vertices size. + */ +const int SHAPE_VERTICES_SIZE = 8; + +/** + * Position handle name. + */ +const char POSITION_NAME[] = "a_position"; + +/** + * Position error. + */ +const GLint POSITION_ERROR = -1; + +/** + * Config attribute list. + */ +const EGLint ATTRIB_LIST[] = { + // Key,value. + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RED_SIZE, EGL_RED_SIZE_DEFAULT, + EGL_GREEN_SIZE, EGL_GREEN_SIZE_DEFAULT, + EGL_BLUE_SIZE, EGL_BLUE_SIZE_DEFAULT, + EGL_ALPHA_SIZE, EGL_ALPHA_SIZE_DEFAULT, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + // End. + EGL_NONE}; + +/** + * Context attributes. + */ +const EGLint CONTEXT_ATTRIBS[] = { + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_NONE}; +} // namespace +bool EGLCore::EglContextInit(void* window, int width, int height) +{ + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "EGLCore", "EglContextInit execute"); + if ((window == nullptr) || (width <= 0) || (height <= 0)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "EglContextInit: param error"); + return false; + } + + UpdateSize(width, height); + eglWindow_ = reinterpret_cast(window); + + // Init display. + eglDisplay_ = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (eglDisplay_ == EGL_NO_DISPLAY) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "eglGetDisplay: unable to get EGL display"); + return false; + } + + EGLint majorVersion; + EGLint minorVersion; + if (!eglInitialize(eglDisplay_, &majorVersion, &minorVersion)) { + OH_LOG_Print( + LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "eglInitialize: unable to get initialize EGL display"); + return false; + } + + // Select configuration. + const EGLint maxConfigSize = 1; + EGLint numConfigs; + if (!eglChooseConfig(eglDisplay_, ATTRIB_LIST, &eglConfig_, maxConfigSize, &numConfigs)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "eglChooseConfig: unable to choose configs"); + return false; + } + + return CreateEnvironment(); +} + +bool EGLCore::CreateEnvironment() +{ + // Create surface. + if (!eglWindow_) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "eglWindow_ is null"); + return false; + } + eglSurface_ = eglCreateWindowSurface(eglDisplay_, eglConfig_, eglWindow_, NULL); + if (eglSurface_ == nullptr) { + OH_LOG_Print( + LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "eglCreateWindowSurface: unable to create surface"); + return false; + } + // Create context. + eglContext_ = eglCreateContext(eglDisplay_, eglConfig_, EGL_NO_CONTEXT, CONTEXT_ATTRIBS); + if (!eglMakeCurrent(eglDisplay_, eglSurface_, eglSurface_, eglContext_)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "eglMakeCurrent failed"); + return false; + } + // Create program. + program_ = CreateProgram(VERTEX_SHADER, FRAGMENT_SHADER); + if (program_ == PROGRAM_ERROR) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "CreateProgram: unable to create program"); + return false; + } + return true; +} + +GLuint EGLCore::LoadShader(GLenum type, const char* shaderSrc) +{ + if ((type <= 0) || (shaderSrc == nullptr)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "glCreateShader type or shaderSrc error"); + return PROGRAM_ERROR; + } + + GLuint shader = glCreateShader(type); + if (shader == 0) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "glCreateShader unable to load shader"); + return PROGRAM_ERROR; + } + + // The gl function has no return value. + glShaderSource(shader, 1, &shaderSrc, nullptr); + glCompileShader(shader); + + GLint compiled; + glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); + if (compiled != 0) { + return shader; + } + + GLint infoLen = 0; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); + if (infoLen <= 1) { + glDeleteShader(shader); + return PROGRAM_ERROR; + } + + char* infoLog = (char*)malloc(sizeof(char) * (infoLen + 1)); + if (infoLog != nullptr) { + memset(infoLog, 0, infoLen + 1); + glGetShaderInfoLog(shader, infoLen, nullptr, infoLog); + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "glCompileShader error = %s", infoLog); + free(infoLog); + infoLog = nullptr; + } + glDeleteShader(shader); + return PROGRAM_ERROR; +} + +GLuint EGLCore::CreateProgram(const char* vertexShader, const char* fragShader) +{ + if ((vertexShader == nullptr) || (fragShader == nullptr)) { + OH_LOG_Print( + LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "createProgram: vertexShader or fragShader is null"); + return PROGRAM_ERROR; + } + + GLuint vertex = LoadShader(GL_VERTEX_SHADER, vertexShader); + if (vertex == PROGRAM_ERROR) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "createProgram vertex error"); + return PROGRAM_ERROR; + } + + GLuint fragment = LoadShader(GL_FRAGMENT_SHADER, fragShader); + if (fragment == PROGRAM_ERROR) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "createProgram fragment error"); + return PROGRAM_ERROR; + } + + GLuint program = glCreateProgram(); + if (program == PROGRAM_ERROR) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "createProgram program error"); + glDeleteShader(vertex); + glDeleteShader(fragment); + return PROGRAM_ERROR; + } + + // The gl function has no return value. + glAttachShader(program, vertex); + glAttachShader(program, fragment); + glLinkProgram(program); + + GLint linked; + glGetProgramiv(program, GL_LINK_STATUS, &linked); + if (linked != 0) { + glDeleteShader(vertex); + glDeleteShader(fragment); + return program; + } + + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "createProgram linked error"); + GLint infoLen = 0; + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLen); + if (infoLen > 1) { + char* infoLog = (char*)malloc(sizeof(char) * (infoLen + 1)); + memset(infoLog, 0, infoLen + 1); + glGetProgramInfoLog(program, infoLen, nullptr, infoLog); + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "glLinkProgram error = %s", infoLog); + free(infoLog); + infoLog = nullptr; + } + glDeleteShader(vertex); + glDeleteShader(fragment); + glDeleteProgram(program); + return PROGRAM_ERROR; +} + +void EGLCore::UpdateSize(int width, int height) +{ + width_ = width; + height_ = height; + if (width_ > 0) { + widthPercent_ = FIFTY_PERCENT * height_ / width_; + } +} + +void EGLCore::Release() +{ + if ((eglDisplay_ == nullptr) || (eglSurface_ == nullptr) || (!eglDestroySurface(eglDisplay_, eglSurface_))) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Release eglDestroySurface failed"); + } + + if ((eglDisplay_ == nullptr) || (eglContext_ == nullptr) || (!eglDestroyContext(eglDisplay_, eglContext_))) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Release eglDestroyContext failed"); + } + + if ((eglDisplay_ == nullptr) || (!eglTerminate(eglDisplay_))) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Release eglTerminate failed"); + } +} +} // namespace NativeXComponentSample diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/render/include/egl_core.h b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/render/include/egl_core.h new file mode 100644 index 0000000000000000000000000000000000000000..3f3980f6a299283952c7b2f1f52544861a662ac5 --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/render/include/egl_core.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved. + */ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef NATIVE_XCOMPONENT_EGL_CORE_H +#define NATIVE_XCOMPONENT_EGL_CORE_H + +#include +#include +#include + +namespace NativeXComponentSample { +class EGLCore { +public: + explicit EGLCore() {}; + ~EGLCore() {} + bool EglContextInit(void* window, int width, int height); + bool CreateEnvironment(); + void Release(); + void UpdateSize(int width, int height); + +private: + GLuint LoadShader(GLenum type, const char* shaderSrc); + GLuint CreateProgram(const char* vertexShader, const char* fragShader); + +private: + EGLNativeWindowType eglWindow_; + EGLDisplay eglDisplay_ = EGL_NO_DISPLAY; + EGLConfig eglConfig_ = EGL_NO_CONFIG_KHR; + EGLSurface eglSurface_ = EGL_NO_SURFACE; + EGLContext eglContext_ = EGL_NO_CONTEXT; + GLuint program_; + bool flag_ = false; + int width_; + int height_; + GLfloat widthPercent_; +}; +} // namespace NativeXComponentSample +#endif // NATIVE_XCOMPONENT_EGL_CORE_H diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/render/include/plugin_manager.h b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/render/include/plugin_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..92e61fa460a5ee5100532c7e2ca9e9bd4e7109cd --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/render/include/plugin_manager.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved. + */ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef NATIVE_XCOMPONENT_PLUGIN_MANAGER_H +#define NATIVE_XCOMPONENT_PLUGIN_MANAGER_H + +#include +#include +#include +#include +#include +#include +#include "native_window/external_window.h" + +#include "plugin_render.h" + +namespace NativeXComponentSample { +class PluginManager { +public: + ~PluginManager(); + + static PluginManager* GetInstance() + { + return &PluginManager::pluginManager_; + } + + static napi_value GetContext(napi_env env, napi_callback_info info); + + void SetNativeXComponent(std::string& id, OH_NativeXComponent* nativeXComponent); + PluginRender* GetRender(std::string& id); + void Export(napi_env env, napi_value exports); + OHNativeWindow *pluginWindow_; + +private: + static PluginManager pluginManager_; + + std::unordered_map nativeXComponentMap_; + std::unordered_map pluginRenderMap_; +}; +} // namespace NativeXComponentSample +#endif // NATIVE_XCOMPONENT_PLUGIN_MANAGER_H diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/render/include/plugin_render.h b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/render/include/plugin_render.h new file mode 100644 index 0000000000000000000000000000000000000000..28883e38d62aeb033d4c74bb0fdf45197a113d9d --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/render/include/plugin_render.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved. + */ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef NATIVE_XCOMPONENT_PLUGIN_RENDER_H +#define NATIVE_XCOMPONENT_PLUGIN_RENDER_H + +#include +#include +#include +#include + +#include "egl_core.h" + +namespace NativeXComponentSample { +class PluginRender { +public: + explicit PluginRender(std::string& id); + ~PluginRender() + { + if (eglCore_ != nullptr) { + eglCore_->Release(); + delete eglCore_; + eglCore_ = nullptr; + } + } + static PluginRender* GetInstance(std::string& id); + static void Release(std::string& id); + void Export(napi_env env, napi_value exports); + void OnSurfaceChanged(OH_NativeXComponent* component, void* window); + void OnTouchEvent(OH_NativeXComponent* component, void* window); + void RegisterCallback(OH_NativeXComponent* nativeXComponent); + +public: + static std::unordered_map instance_; + EGLCore* eglCore_; + std::string id_; + static int32_t hasDraw_; + static int32_t hasChangeColor_; + +private: + OH_NativeXComponent_Callback renderCallback_; + OH_NativeXComponent_MouseEvent_Callback mouseCallback_; +}; +} // namespace NativeXComponentSample +#endif // NATIVE_XCOMPONENT_PLUGIN_RENDER_H diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/render/plugin_manager.cpp b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/render/plugin_manager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..26bdd7d3a75f86efa5e71305c7e2bbb695978c91 --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/render/plugin_manager.cpp @@ -0,0 +1,166 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved. + */ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "plugin_manager.h" + +#include +#include +#include +#include +#include + +#undef LOG_TAG +#define LOG_TAG "PLUGINMANAGER" + +namespace NativeXComponentSample { +constexpr uint32_t LOG_PRINT_DOMAIN = 0xFF00; +PluginManager PluginManager::pluginManager_; + +PluginManager::~PluginManager() +{ + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback", "~PluginManager"); + for (auto iter = nativeXComponentMap_.begin(); iter != nativeXComponentMap_.end(); ++iter) { + if (iter->second != nullptr) { + delete iter->second; + iter->second = nullptr; + } + } + nativeXComponentMap_.clear(); + + for (auto iter = pluginRenderMap_.begin(); iter != pluginRenderMap_.end(); ++iter) { + if (iter->second != nullptr) { + delete iter->second; + iter->second = nullptr; + } + } + pluginRenderMap_.clear(); +} + +napi_value PluginManager::GetContext(napi_env env, napi_callback_info info) +{ + if ((env == nullptr) || (info == nullptr)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginManager", "GetContext env or info is null"); + return nullptr; + } + + size_t argCnt = 1; + napi_value args[1] = { nullptr }; + if (napi_get_cb_info(env, info, &argCnt, args, nullptr, nullptr) != napi_ok) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginManager", "GetContext napi_get_cb_info failed"); + } + + if (argCnt != 1) { + napi_throw_type_error(env, NULL, "Wrong number of arguments"); + return nullptr; + } + + napi_valuetype valuetype; + if (napi_typeof(env, args[0], &valuetype) != napi_ok) { + napi_throw_type_error(env, NULL, "napi_typeof failed"); + return nullptr; + } + + if (valuetype != napi_number) { + napi_throw_type_error(env, NULL, "Wrong type of arguments"); + return nullptr; + } + + int64_t value; + if (napi_get_value_int64(env, args[0], &value) != napi_ok) { + napi_throw_type_error(env, NULL, "napi_get_value_int64 failed"); + return nullptr; + } + + napi_value exports; + if (napi_create_object(env, &exports) != napi_ok) { + napi_throw_type_error(env, NULL, "napi_create_object failed"); + return nullptr; + } + + return exports; +} + +void PluginManager::Export(napi_env env, napi_value exports) +{ + if ((env == nullptr) || (exports == nullptr)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginManager", "Export: env or exports is null"); + return; + } + + napi_value exportInstance = nullptr; + if (napi_get_named_property(env, exports, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance) != napi_ok) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginManager", "Export: napi_get_named_property fail"); + return; + } + + OH_NativeXComponent* nativeXComponent = nullptr; + if (napi_unwrap(env, exportInstance, reinterpret_cast(&nativeXComponent)) != napi_ok) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginManager", "Export: napi_unwrap fail"); + return; + } + + char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = { '\0' }; + uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; + if (OH_NativeXComponent_GetXComponentId(nativeXComponent, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { + OH_LOG_Print( + LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginManager", "Export: OH_NativeXComponent_GetXComponentId fail"); + return; + } + + std::string id(idStr); + auto context = PluginManager::GetInstance(); + if ((context != nullptr) && (nativeXComponent != nullptr)) { + context->SetNativeXComponent(id, nativeXComponent); + auto render = context->GetRender(id); + if (render != nullptr) { + render->RegisterCallback(nativeXComponent); + render->Export(env, exports); + } + } +} + +void PluginManager::SetNativeXComponent(std::string& id, OH_NativeXComponent* nativeXComponent) +{ + if (nativeXComponent == nullptr) { + return; + } + + if (nativeXComponentMap_.find(id) == nativeXComponentMap_.end()) { + nativeXComponentMap_[id] = nativeXComponent; + return; + } + + if (nativeXComponentMap_[id] != nativeXComponent) { + OH_NativeXComponent* tmp = nativeXComponentMap_[id]; + delete tmp; + tmp = nullptr; + nativeXComponentMap_[id] = nativeXComponent; + } +} + +PluginRender* PluginManager::GetRender(std::string& id) +{ + if (pluginRenderMap_.find(id) == pluginRenderMap_.end()) { + PluginRender* instance = PluginRender::GetInstance(id); + pluginRenderMap_[id] = instance; + return instance; + } + + return pluginRenderMap_[id]; +} +} // namespace NativeXComponentSample diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/render/plugin_render.cpp b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/render/plugin_render.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8792110813700c7be1942d7493c9086834f6841f --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/render/plugin_render.cpp @@ -0,0 +1,242 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved. + */ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +#include "plugin_manager.h" +#include "plugin_render.h" + +#undef LOG_TAG +#define LOG_TAG "PLUGINRENDER" + +namespace NativeXComponentSample { +namespace { +constexpr uint32_t LOG_PRINT_DOMAIN = 0xFF00; + +void OnSurfaceCreatedCB(OH_NativeXComponent* component, void* window) +{ + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "Callback", "OnSurfaceCreatedCB"); + if ((component == nullptr) || (window == nullptr)) { + OH_LOG_Print( + LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback", "OnSurfaceCreatedCB: component or window is null"); + return; + } + + char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = { '\0' }; + uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; + if (OH_NativeXComponent_GetXComponentId(component, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { + OH_LOG_Print( + LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback", "OnSurfaceCreatedCB: Unable to get XComponent id"); + return; + } + + std::string id(idStr); + auto render = PluginRender::GetInstance(id); + uint64_t width; + uint64_t height; + int32_t xSize = OH_NativeXComponent_GetXComponentSize(component, window, &width, &height); + if ((xSize == OH_NATIVEXCOMPONENT_RESULT_SUCCESS) && (render != nullptr)) { + if (render->eglCore_->EglContextInit(window, width, height)) { + auto context = PluginManager::GetInstance(); + context->pluginWindow_ = (OHNativeWindow *)window; + OH_NativeWindow_NativeWindowSetScalingModeV2(context->pluginWindow_, OH_SCALING_MODE_SCALE_FIT_V2); + uint8_t metadataType = OH_VIDEO_HDR_HLG; + (void)OH_NativeWindow_SetMetadataValue(context->pluginWindow_, OH_HDR_METADATA_TYPE, sizeof(uint8_t), &metadataType); + OH_NativeBuffer_ColorSpace colorSpace = OH_COLORSPACE_BT2020_HLG_LIMIT; + (void)OH_NativeWindow_SetColorSpace(context->pluginWindow_, colorSpace); + } + } +} + +void OnSurfaceChangedCB(OH_NativeXComponent* component, void* window) +{ + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "Callback", "OnSurfaceChangedCB"); + if ((component == nullptr) || (window == nullptr)) { + OH_LOG_Print( + LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback", "OnSurfaceChangedCB: component or window is null"); + return; + } + + char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = { '\0' }; + uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; + if (OH_NativeXComponent_GetXComponentId(component, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { + OH_LOG_Print( + LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback", "OnSurfaceChangedCB: Unable to get XComponent id"); + return; + } + + std::string id(idStr); + auto render = PluginRender::GetInstance(id); + if (render != nullptr) { + render->OnSurfaceChanged(component, window); + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "Callback", "surface changed"); + } +} + +void OnSurfaceDestroyedCB(OH_NativeXComponent* component, void* window) +{ + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "Callback", "OnSurfaceDestroyedCB"); + if ((component == nullptr) || (window == nullptr)) { + OH_LOG_Print( + LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback", "OnSurfaceDestroyedCB: component or window is null"); + return; + } + + char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = { '\0' }; + uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; + if (OH_NativeXComponent_GetXComponentId(component, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { + OH_LOG_Print( + LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback", "OnSurfaceDestroyedCB: Unable to get XComponent id"); + return; + } + + std::string id(idStr); + PluginRender::Release(id); +} + +void DispatchTouchEventCB(OH_NativeXComponent* component, void* window) +{ + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "Callback", "DispatchTouchEventCB"); + if ((component == nullptr) || (window == nullptr)) { + OH_LOG_Print( + LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback", "DispatchTouchEventCB: component or window is null"); + return; + } + + char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = { '\0' }; + uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; + if (OH_NativeXComponent_GetXComponentId(component, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { + OH_LOG_Print( + LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback", "DispatchTouchEventCB: Unable to get XComponent id"); + return; + } + + std::string id(idStr); + PluginRender* render = PluginRender::GetInstance(id); + if (render != nullptr) { + render->OnTouchEvent(component, window); + } +} +} // namespace + +std::unordered_map PluginRender::instance_; +int32_t PluginRender::hasDraw_ = 0; +int32_t PluginRender::hasChangeColor_ = 0; + +PluginRender::PluginRender(std::string& id) +{ + this->id_ = id; + this->eglCore_ = new EGLCore(); +} + +PluginRender* PluginRender::GetInstance(std::string& id) +{ + if (instance_.find(id) == instance_.end()) { + PluginRender* instance = new PluginRender(id); + instance_[id] = instance; + return instance; + } else { + return instance_[id]; + } +} + +void PluginRender::Export(napi_env env, napi_value exports) +{ + if ((env == nullptr) || (exports == nullptr)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginRender", "Export: env or exports is null"); + return; + } + + napi_property_descriptor desc[] = {}; + if (napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc) != napi_ok) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginRender", "Export: napi_define_properties failed"); + } +} + +void PluginRender::Release(std::string& id) +{ + PluginRender* render = PluginRender::GetInstance(id); + if (render != nullptr) { + render->eglCore_->Release(); + delete render->eglCore_; + render->eglCore_ = nullptr; + delete render; + render = nullptr; + instance_.erase(instance_.find(id)); + } +} + +void PluginRender::OnSurfaceChanged(OH_NativeXComponent* component, void* window) +{ + char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = { '\0' }; + uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; + if (OH_NativeXComponent_GetXComponentId(component, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback", "OnSurfaceChanged: Unable to get XComponent id"); + return; + } + + std::string id(idStr); + PluginRender* render = PluginRender::GetInstance(id); + double offsetX; + double offsetY; + OH_NativeXComponent_GetXComponentOffset(component, window, &offsetX, &offsetY); + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "OH_NativeXComponent_GetXComponentOffset", + "offsetX = %{public}lf, offsetY = %{public}lf", offsetX, offsetY); + uint64_t width; + uint64_t height; + OH_NativeXComponent_GetXComponentSize(component, window, &width, &height); + if (render != nullptr) { + render->eglCore_->UpdateSize(width, height); + } +} + +void PluginRender::OnTouchEvent(OH_NativeXComponent* component, void* window) +{ + char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = { '\0' }; + uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; + if (OH_NativeXComponent_GetXComponentId(component, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { + OH_LOG_Print( + LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback", "DispatchTouchEventCB: Unable to get XComponent id"); + return; + } + OH_NativeXComponent_TouchEvent touchEvent; + OH_NativeXComponent_GetTouchEvent(component, window, &touchEvent); + float tiltX = 0.0f; + float tiltY = 0.0f; + OH_NativeXComponent_TouchPointToolType toolType = + OH_NativeXComponent_TouchPointToolType::OH_NATIVEXCOMPONENT_TOOL_TYPE_UNKNOWN; + OH_NativeXComponent_GetTouchPointToolType(component, 0, &toolType); + OH_NativeXComponent_GetTouchPointTiltX(component, 0, &tiltX); + OH_NativeXComponent_GetTouchPointTiltY(component, 0, &tiltY); + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "OnTouchEvent", + "touch info: toolType = %{public}d, tiltX = %{public}lf, tiltY = %{public}lf", toolType, tiltX, tiltY); +} + +void PluginRender::RegisterCallback(OH_NativeXComponent *nativeXComponent) +{ + renderCallback_.OnSurfaceCreated = OnSurfaceCreatedCB; + renderCallback_.OnSurfaceChanged = OnSurfaceChangedCB; + renderCallback_.OnSurfaceDestroyed = OnSurfaceDestroyedCB; + renderCallback_.DispatchTouchEvent = DispatchTouchEventCB; + OH_NativeXComponent_RegisterCallback(nativeXComponent, &renderCallback_); +} +} // namespace NativeXComponentSample diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/sample/player/Player.cpp b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/sample/player/Player.cpp new file mode 100644 index 0000000000000000000000000000000000000000..469e6d628b6719bab9cef8f615f7097185e0e7c1 --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/sample/player/Player.cpp @@ -0,0 +1,631 @@ +#include "Player.h" +#include +#include +#include +#include "av_codec_sample_log.h" +#include "dfx/error/av_codec_sample_error.h" +#include "lppCallback.h" + +#undef LOG_TAG +#define LOG_TAG "playerDemo" + +namespace { +constexpr int BALANCE_VALUE = 5; +using namespace std::chrono_literals; +static const int MS_TO_S = 1000; +constexpr int64_t WAIT_TIME_US_THRESHOLD_WARNING = -1 * 40 * 1000; // warning threshold 40ms +constexpr int64_t WAIT_TIME_US_THRESHOLD = 1 * 1000 * 1000; // max sleep time 1s +constexpr int64_t SINK_TIME_US_THRESHOLD = 100000; // max sink time 100ms +constexpr int32_t BYTES_PER_SAMPLE_2 = 2; // 2 bytes per sample +constexpr double VSYNC_TIME = 1000 / 60; // frame time +constexpr double LIP_SYNC_BALANCE_VALUE = 2; // the balance value of sync sound and picture +constexpr int32_t MAX_BUFFER_SIZE = 2*1024*1024; +constexpr int32_t WAIT_OUT_TIME = 50000; // 等待时间MS +constexpr int32_t VIDEO_FRAME_COUNT = 1; //视频聚包帧数 +constexpr int32_t AUDIO_FRAME_COUNT = 10; //视频聚包帧数 +} // namespace + +Player::~Player() +{ + Player::StartRelease(); +} + +bool Player::Intercept() +{ + if(demuxer_ == nullptr || lppVideoStreamer_ == nullptr || lppAudioStreamer_ == nullptr){ + return true; + } + return false; +} + +int32_t Player::CreateLppAudioStreamer() +{ + AVCODEC_SAMPLE_LOGW("CreateLppAudioStreamer IN"); + if(lppAudioStreamer_ == nullptr){ + AVCODEC_SAMPLE_LOGE("lppAudioStreamer_ is Release, should init"); + return -1; + } + auto ret = lppAudioStreamer_->Create(sampleInfo_.audioCodecMime); + CHECK_AND_RETURN_RET_LOG(ret == AVCODEC_SAMPLE_ERR_OK , AVCODEC_SAMPLE_ERR_ERROR, "CreateLppAudioStreamer failed."); + lppContext_ = new LppUserData; + lppContext_->audioCallback = sampleInfo_.audioCallback; + lppContext_->audioCallbackData = sampleInfo_.audioCallbackData; + ret = lppAudioStreamer_->SetCallback(lppContext_); + CHECK_AND_RETURN_RET_LOG(ret == AVCODEC_SAMPLE_ERR_OK , AVCODEC_SAMPLE_ERR_ERROR, "SetCallback failed."); + ret = lppAudioStreamer_->SetParameter(sampleInfo_); + CHECK_AND_RETURN_RET_LOG(ret == AVCODEC_SAMPLE_ERR_OK , AVCODEC_SAMPLE_ERR_ERROR, "SetParameter failed."); + AVCODEC_SAMPLE_LOGW("CreateLppAudioStreamer OUT"); + return AVCODEC_SAMPLE_ERR_OK; +} + +int32_t Player::CreateLppVideoStreamer() +{ + AVCODEC_SAMPLE_LOGI("CreateLppVideoStreamer IN"); + if(lppVideoStreamer_ == nullptr){ + AVCODEC_SAMPLE_LOGE("lppVideoStreamer_ is Release, should init"); + return -1; + } + AVCODEC_SAMPLE_LOGI("FORMAT : %{public}s", sampleInfo_.videoCodecMime.c_str()); + sampleInfo_.window = NativeXComponentSample::PluginManager::GetInstance()->pluginWindow_; +// video/avc + lppVideoStreamer_->Create(sampleInfo_.videoCodecMime.c_str()); + lppVideoContext_ = new LppUserData; + lppVideoContext_->num = 100012; + lppVideoStreamer_->SetCallback(lppVideoContext_); + OH_AVFormat *format = OH_AVFormat_Create(); + lppVideoStreamer_->Configure(sampleInfo_); + lppVideoStreamer_->SetVideoSurface(sampleInfo_); + AVCODEC_SAMPLE_LOGI("CreateLppVideoStreamer OUT"); + return AVCODEC_SAMPLE_ERR_OK; +} + +int32_t Player::Init(SampleInfo &sampleInfo) +{ + Stop(); + Reset(); + StartRelease(); + std::unique_lock lock(mutex_); + CHECK_AND_RETURN_RET_LOG(!isStarted_, AVCODEC_SAMPLE_ERR_ERROR, "Already started."); + sampleInfo_ = sampleInfo; + sampleInfo_.isInit = true; + CHECK_AND_RETURN_RET_LOG(demuxer_ == nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Already started."); + demuxer_ = std::make_unique(); + AVCODEC_SAMPLE_LOGI("Create lppAudioStreamer_ SUCC"); + lppAudioStreamer_ = std::make_shared(); + lppVideoStreamer_ = std::make_shared(); + isReleased_ = false; + AVCODEC_SAMPLE_LOGI("Succeed"); + return AVCODEC_SAMPLE_ERR_OK; +} + +int32_t Player::Prepare() +{ + AVCODEC_SAMPLE_LOGW("Prepare IN"); + if(!sampleInfo_.isInit){ + return 0; + } + std::unique_lock lock(mutex_); + if (demuxer_ == nullptr){ + demuxer_ = std::make_unique(); + } + int32_t ret = demuxer_->Create(sampleInfo_); + + ret = CreateLppAudioStreamer(); + CHECK_AND_RETURN_RET_LOG(ret == AVCODEC_SAMPLE_ERR_OK , AVCODEC_SAMPLE_ERR_ERROR, "CreateLppAudioStreamer failed."); + + ret = CreateLppVideoStreamer(); + CHECK_AND_RETURN_RET_LOG(ret == AVCODEC_SAMPLE_ERR_OK , AVCODEC_SAMPLE_ERR_ERROR, "CreateLppVideoStreamer failed."); + + lppVideoStreamer_->SetSyncAudioStreamer(lppAudioStreamer_->lppAudioStreamer_); + lppVideoStreamer_->Prepare(); + lppAudioStreamer_->Prepare(); + + isReleased_ = false; + isStarted_ = true; + if(lppVideoContext_){ + if (lppVideoDataNeededThread_ == nullptr){ + lppVideoDataNeededThread_ = std::make_unique(&Player::LppVideoDataNeededThread, this); + } + } + if(lppContext_){ + if (LppDataNeededThread_ == nullptr){ + LppDataNeededThread_ = std::make_unique(&Player::LppDataNeededThread1, this); + } + } + AVCODEC_SAMPLE_LOGW("Prepare OUT"); + return 0; +} + +int32_t Player::StartDecoder() +{ + isStarted_ = true; + state_ = PLAYING; + CHECK_AND_RETURN_RET_LOG(lppVideoContext_ != nullptr , AVCODEC_SAMPLE_ERR_ERROR, "CreateLppAudioStreamer failed."); + return lppVideoStreamer_->StartDecode(true); +} + +int32_t Player::RenderFirstFrame() +{ + CHECK_AND_RETURN_RET_LOG(lppVideoContext_ != nullptr && lppVideoStreamer_ != nullptr , AVCODEC_SAMPLE_ERR_ERROR, "lppVideoStreamer_ nullptr."); + return lppVideoStreamer_->RenderFirstFrame(); +} + +int32_t Player::StartRender() +{ + isStarted_ = true; + state_ = PLAYING; + CHECK_AND_RETURN_RET_LOG(lppVideoContext_ != nullptr && lppVideoStreamer_ != nullptr , AVCODEC_SAMPLE_ERR_ERROR, "lppVideoStreamer_ nullptr."); + return lppVideoStreamer_->StartRender(); +} + +int32_t Player::StartAudio() +{ + isStarted_ = true; + state_ = PLAYING; + CHECK_AND_RETURN_RET_LOG(lppContext_ != nullptr && lppAudioStreamer_ != nullptr , AVCODEC_SAMPLE_ERR_ERROR, "lppAudioStreamer_ nullptr."); + return lppAudioStreamer_->Start(); +} + +int32_t Player::Stop() +{ + std::unique_lock lock(mutex_); + CHECK_AND_RETURN_RET_LOG(!Intercept(), AVCODEC_SAMPLE_ERR_ERROR, "Intercept nullptr."); + AVCODEC_SAMPLE_LOGI("stop in"); + isStarted_ = false; + if (lppAudioStreamer_ != nullptr) { + lppAudioStreamer_->Stop(); + } + if (lppVideoStreamer_ != nullptr) { + lppVideoStreamer_->Stop(); + } + AVCODEC_SAMPLE_LOGI("stop out"); + lock.unlock(); + return 0; +} + +int32_t Player::Reset() +{ + std::unique_lock lock(mutex_); + CHECK_AND_RETURN_RET_LOG(!Intercept(), AVCODEC_SAMPLE_ERR_ERROR, "Intercept nullptr."); + isStarted_ = false; + ReleaseThread(); + AVCODEC_SAMPLE_LOGD("reset in"); + if (demuxer_ != nullptr) { + demuxer_->Release(); + demuxer_.reset(); + } + if (lppAudioStreamer_ != nullptr) { + lppAudioStreamer_->Reset(); + } + if (lppVideoStreamer_ != nullptr) { + lppVideoStreamer_->Reset(); + } + AVCODEC_SAMPLE_LOGD("reset out"); + lock.unlock(); + return 0; +} + +int32_t Player::Pause() +{ + std::unique_lock lock(mutex_); + CHECK_AND_RETURN_RET_LOG(!Intercept(), AVCODEC_SAMPLE_ERR_ERROR, "Intercept nullptr."); + AVCODEC_SAMPLE_LOGD("Pause in"); + if (lppAudioStreamer_ != nullptr) { + lppAudioStreamer_->Pause(); + } + if (lppVideoStreamer_ != nullptr) { + lppVideoStreamer_->Pause(); + } + AVCODEC_SAMPLE_LOGD("Pause out"); + lock.unlock(); + return 0; +} + +int32_t Player::Resume() +{ + std::unique_lock lock(mutex_); + CHECK_AND_RETURN_RET_LOG(!Intercept(), AVCODEC_SAMPLE_ERR_ERROR, "Intercept nullptr."); + state_ = PLAYING; + if (lppAudioStreamer_ != nullptr) { + lppAudioStreamer_->Resume(); + } + if (lppVideoStreamer_ != nullptr) { + lppVideoStreamer_->Resume(); + } + lock.unlock(); + return 0; +} + +int32_t Player::Flush() +{ + std::unique_lock lock(mutex_); + CHECK_AND_RETURN_RET_LOG(!Intercept(), AVCODEC_SAMPLE_ERR_ERROR, "Intercept nullptr."); + state_ = PAUSE; + if (lppAudioStreamer_ != nullptr) { + lppAudioStreamer_->Flush(); + } + if (lppVideoStreamer_ != nullptr) { + lppVideoStreamer_->Flush(); + } + lock.unlock(); + return 0; +} + +int32_t Player::SetSpeed(double speed) +{ + std::unique_lock lock(mutex_); + CHECK_AND_RETURN_RET_LOG(!Intercept(), AVCODEC_SAMPLE_ERR_ERROR, "Intercept nullptr."); + if (lppAudioStreamer_ != nullptr) { + lppAudioStreamer_->SetPlayBackSpeed(speed); + } + if (lppVideoStreamer_ != nullptr) { + lppVideoStreamer_->SetPlaybackSpeed(speed); + } + lock.unlock(); + return 0; +} + +int32_t Player::SetSurface(int64_t surfaceId) +{ + std::unique_lock lock(mutex_); + CHECK_AND_RETURN_RET_LOG(!Intercept(), AVCODEC_SAMPLE_ERR_ERROR, "Intercept nullptr."); + AVCODEC_SAMPLE_LOGD("SetSurface in %{public}d", surfaceId); + if (lppVideoStreamer_ != nullptr) { + OHNativeWindow *oHNativeWindow; + OH_NativeWindow_CreateNativeWindowFromSurfaceId(surfaceId,&oHNativeWindow); + sampleInfo_.window = oHNativeWindow; + lppVideoStreamer_->SetVideoSurface(sampleInfo_); + } + AVCODEC_SAMPLE_LOGD("SetSurface out"); + lock.unlock(); + return 0; +} + +int32_t Player::SetVolume(double volume) +{ + std::unique_lock lock(mutex_); + CHECK_AND_RETURN_RET_LOG(!Intercept(), AVCODEC_SAMPLE_ERR_ERROR, "Intercept nullptr."); + CHECK_AND_RETURN_RET_LOG(lppAudioStreamer_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "lppAudioStreamer_ nullptr."); + if (lppAudioStreamer_ != nullptr) { + lppAudioStreamer_->SetVolume(volume); + } + lock.unlock(); + return 0; +} + +// pause/flush/seek/resume +int32_t Player::Seek(int64_t seekTime, int32_t mode, bool acc) +{ + std::unique_lock seekLock(SeekMutex); + auto start = std::chrono::high_resolution_clock::now(); + CHECK_AND_RETURN_RET_LOG(!Intercept(), AVCODEC_SAMPLE_ERR_ERROR, "Intercept nullptr."); + lppContext_->position = -1; + if(sampleInfo_.duration(mode); + AVCODEC_SAMPLE_LOGI("OH_AVSeekMode %{public}d", mode); + int32_t aa = demuxer_->Seek(seekTime, enumNum); + if (aa != 0){ + AVCODEC_SAMPLE_LOGD("Seek failed."); + demuxer_->Seek(seekTime, SEEK_MODE_CLOSEST_SYNC); + } + // Seek后唤醒 + { + std::unique_lock eosFlagMutexLock(lppContext_->eosFlagMutex); + lppContext_->eosFlag_ = false; + lppContext_->returnFrame = false; + AVCODEC_SAMPLE_LOGI("AUDIO eosFlag_ %{public}d",lppContext_->eosFlag_); + lppContext_->eosCond_.notify_all(); + eosFlagMutexLock.unlock(); + } + { + std::unique_lock eosFlagMutexLock(lppVideoContext_->eosFlagMutex); + lppVideoContext_->eosFlag_ = false; + lppVideoContext_->returnFrame = false; + AVCODEC_SAMPLE_LOGI("VIDEO eosFlag_ %{public}d",lppContext_->eosFlag_); + lppVideoContext_->eosCond_.notify_all(); + eosFlagMutexLock.unlock(); + } + Flush(); + StartDecoder(); + StartRender(); + StartAudio(); + auto end = std::chrono::high_resolution_clock::now(); + auto duration = std::chrono::duration_cast(end - start).count(); + AVCODEC_SAMPLE_LOGI("seek duration %lld",duration); + return 0; +} + +int64_t Player::ReadToAudioTargetPts(int64_t targetPts) +{ + + OH_AVBuffer * avbuffer = OH_AVBuffer_Create(MAX_BUFFER_SIZE); + CodecBufferInfo bufferInfo(11, avbuffer); + while (true) + { + demuxer_->ReadSample(demuxer_->GetAudioTrackId(), reinterpret_cast(bufferInfo.buffer), + bufferInfo.attr); + if(targetPts<=bufferInfo.attr.pts) + { + break; + } + if(bufferInfo.attr.flags & AVCODEC_BUFFER_FLAGS_EOS){ + break; + } + } + AVCODEC_SAMPLE_LOGI("ReadToAudioTargetPts Last pts is %{public}ld",bufferInfo.attr.pts); + return bufferInfo.attr.pts; +} + +void Player::SeekInner(int64_t seekTime, int32_t mode) +{ + AVCODEC_SAMPLE_LOGI("============== Seek ACC IN ==============="); + int64_t targetPts = seekTime*1000; + AVCODEC_SAMPLE_LOGI("SetTargetStartFrame %{public}ld",targetPts); + //暂停 + Pause(); + { + std::unique_lock eosFlagMutexLock(lppContext_->eosFlagMutex); + lppContext_->eosFlag_ = false; + lppContext_->returnFrame = false; + AVCODEC_SAMPLE_LOGI("AUDIO eosFlag_ %{public}d",lppContext_->eosFlag_); + lppContext_->eosCond_.notify_all(); + eosFlagMutexLock.unlock(); + } + { + std::unique_lock eosFlagMutexLock(lppVideoContext_->eosFlagMutex); + lppVideoContext_->eosFlag_ = false; + lppVideoContext_->returnFrame = false; + AVCODEC_SAMPLE_LOGI("VIDEO eosFlag_ %{public}d",lppContext_->eosFlag_); + lppVideoContext_->eosCond_.notify_all(); + eosFlagMutexLock.unlock(); + } + Flush(); + demuxer_->Seek(seekTime, SEEK_MODE_PREVIOUS_SYNC); + //音频读取到对应帧 + ReadToAudioTargetPts(targetPts); + //给视频设置回调和TargetPts + if (lppVideoStreamer_ != nullptr) { + lppVideoStreamer_->SetTargetStartFrame(targetPts, LppCallback::OnTargetArrived, WAIT_OUT_TIME, lppVideoContext_); + StartDecoder(); + StartRender(); + } + //等待返回 + std::unique_lock lock(lppVideoContext_->seekMutex_); +// lppVideoContext_->seekCond_.wait_for(lock, 10000s, [this]() { return lppVideoContext_->seekReturn_; }); + usleep(50*1000); + lppVideoContext_->seekReturn_ = false; + lock.unlock(); + //返回成功,启动音频 + if (lppAudioStreamer_ != nullptr) { + lppAudioStreamer_->Start(); + } + AVCODEC_SAMPLE_LOGI("============== Seek ACC OUT ==============="); +} + +void Player::StartRelease() +{ + CHECK_AND_RETURN_LOG(!Intercept(), "Intercept nullptr."); + std::unique_lock lock(doneMutex); + if (!isReleased_) { + isReleased_ = true; + Release(); + } + lock.unlock(); +} + +int64_t Player::GetDurationTime() +{ + AVCODEC_SAMPLE_LOGD("GetDurationTime %{public}ld",sampleInfo_.duration); + return sampleInfo_.duration; +} + +int64_t Player::GetProgressTime() +{ + std::unique_lock seekLock(SeekMutex); + if(lppContext_ == nullptr || lppContext_->position == -1){ + return 0; + } + AVCODEC_SAMPLE_LOGD("GetProgressTime position %{public}ld",lppContext_->position); + int64_t tmp = sampleInfo_.duration/1000000 < (lppContext_->position / 1000) ? sampleInfo_.duration : ( (lppContext_->position /1000) * 1000000); + return tmp; +} + +void Player::ReleaseThread() +{ + if(lppContext_){ + std::unique_lock eosFlagMutexLock(lppContext_->eosFlagMutex); + lppContext_->eosFlag_ = false; + lppContext_->eosCond_.notify_all(); + eosFlagMutexLock.unlock(); + std::unique_lock lock(lppContext_->inputMutex); + lppContext_->returnFrame =true; + lppContext_->inputCond.notify_all(); + lock.unlock(); + } + + if(lppVideoContext_){ + std::unique_lock eosFlagMutexLock(lppVideoContext_->eosFlagMutex); + lppVideoContext_->eosFlag_ = false; + lppVideoContext_->eosCond_.notify_all(); + eosFlagMutexLock.unlock(); + std::unique_lock lockVideo(lppVideoContext_->inputMutex); + lppVideoContext_->returnFrame = true; + lppVideoContext_->inputCond.notify_all(); + lockVideo.unlock(); + } + + if (LppDataNeededThread_ && LppDataNeededThread_->joinable()) { + LppDataNeededThread_->join(); + LppDataNeededThread_.reset(); + } + if (lppVideoDataNeededThread_ && lppVideoDataNeededThread_->joinable()) { + lppVideoDataNeededThread_->join(); + lppVideoDataNeededThread_.reset(); + } +} + +void Player::Release() +{ + std::lock_guard lock(mutex_); + isStarted_ = false; + isAudioDone = false; + isVideoDone = false; + ReleaseThread(); + if (demuxer_ != nullptr) { + demuxer_->Release(); + demuxer_.reset(); + } + if (lppAudioStreamer_ != nullptr) { + lppAudioStreamer_->Release(); + lppAudioStreamer_.reset(); + } + if (lppContext_ != nullptr) { + delete lppContext_; + lppContext_ = nullptr; + } + if (lppVideoStreamer_ != nullptr) { + lppVideoStreamer_->Release(); + lppVideoStreamer_.reset(); + } + if (lppVideoContext_ != nullptr) { + delete lppVideoContext_; + lppVideoContext_ = nullptr; + } + doneCond_.notify_all(); + // 触发回调 + if(sampleInfo_.playDoneCallback != nullptr){ + sampleInfo_.playDoneCallback(sampleInfo_.playDoneCallbackData); + } + AVCODEC_SAMPLE_LOGI("Succeed"); +} + +void Player::LppDataNeededThread1() +{ + int32_t total_size = 4467270; + AVCODEC_SAMPLE_LOGI("====== AVBUFFER1234 CREATE ======"); + OH_AVBuffer * avbuffer = OH_AVBuffer_Create(total_size); + while (true) { + CHECK_AND_BREAK_LOG(isStarted_, "Decoder input thread out"); + // 到达EOS帧后不再送数据,直到Seek + std::unique_lock eosLock(lppContext_->eosMutex); + lppContext_->eosCond_.wait_for( + eosLock, 150000s, [this]() { return !lppContext_->eosFlag_; }); + eosLock.unlock(); + // 等待数据回调到达 + std::unique_lock lock(lppContext_->inputMutex); + lppContext_->inputCond.wait_for( + lock, 150000s, [this]() { return lppContext_->returnFrame; }); + lppContext_->returnFrame = false; + + CHECK_AND_BREAK_LOG(isStarted_, "VD Decoder output thread out"); + + lppContext_->count = 1; + // 聚包数量 + int count = AUDIO_FRAME_COUNT; + while (count>0) + { + CHECK_AND_BREAK_LOG(!lppContext_->eosFlag_, "AUDIO is EOS"); + count--; + CodecBufferInfo bufferInfo(11, avbuffer); + demuxer_->ReadSample(demuxer_->GetAudioTrackId(), reinterpret_cast(bufferInfo.buffer), + bufferInfo.attr); + this->progress = bufferInfo.attr.pts; + int32_t remain = OH_AVSamplesBuffer_GetRemainedCapacity(lppContext_->framePacket_); + AVCODEC_SAMPLE_LOGD("AUDIO pts %{public}ld",bufferInfo.attr.pts); + // EOS帧置位 + if ((bufferInfo.attr.flags & AVCODEC_BUFFER_FLAGS_EOS)){ + AVCODEC_SAMPLE_LOGI("Catch EOS, audio thread out"); + OH_AVBuffer_SetBufferAttr(reinterpret_cast(bufferInfo.buffer), &bufferInfo.attr); + std::unique_lock eosFlagMutexLock(lppContext_->eosFlagMutex); + lppContext_->eosFlag_ = true; + eosFlagMutexLock.unlock(); + } + OH_AVSamplesBuffer_AppendOneBuffer(lppContext_->framePacket_, reinterpret_cast(bufferInfo.buffer)); + } + if(count == AUDIO_FRAME_COUNT){ + continue; + } + if(state_ == PLAYING){ + lppAudioStreamer_->returnFrames(lppContext_); + } + // 一次回调处理完再下一次 + lock.unlock(); + } + AVCODEC_SAMPLE_LOGI("====== AVBUFFER DESTROY ======"); + OH_AVBuffer_Destroy(avbuffer); +} + +void Player::LppVideoDataNeededThread() +{ + bool eosFlag = 0; + int32_t total_size = 4467270; + AVCODEC_SAMPLE_LOGI("====== AVBUFFER1234 CREATE1 ======"); + OH_AVBuffer * avbuffer = OH_AVBuffer_Create(total_size); + while (true) { + CHECK_AND_BREAK_LOG(isStarted_, "Decoder input thread out"); + + std::unique_lock eosLock(lppVideoContext_->eosMutex); + lppVideoContext_->eosCond_.wait_for( + eosLock, 150000s, [this]() { return !lppVideoContext_->eosFlag_; }); + + std::unique_lock lock(lppVideoContext_->inputMutex); + lppVideoContext_->inputCond.wait_for( + lock, 150000s, [this]() { return lppVideoContext_->returnFrame; }); + CHECK_AND_BREAK_LOG(isStarted_, "VD Decoder output thread out"); + lppVideoContext_->returnFrame = false; + CHECK_AND_BREAK_LOG(isStarted_, "Work done, thread out"); + + + lppVideoContext_->count = VIDEO_FRAME_COUNT; + AVCODEC_SAMPLE_LOGI("LppVideoDataNeededThread count %{public}d", lppVideoContext_->count); + while (lppVideoContext_->count>0) + { + CHECK_AND_BREAK_LOG(!lppVideoContext_->eosFlag_, "VIDEO is EOS"); + CodecBufferInfo bufferInfo(11, avbuffer); + if(seekFlag_){ + seekFlag_ = false; + bufferInfo = videoBufferInfo_.front(); + videoBufferInfo_.pop(); + } + else{ + demuxer_->ReadSample(demuxer_->GetVideoTrackId(), reinterpret_cast(bufferInfo.buffer), + bufferInfo.attr); + } + AVCODEC_SAMPLE_LOGI("LppVideoDataNeededThread size %{public}d",bufferInfo.attr.size); + AVCODEC_SAMPLE_LOGI("LppVideoDataNeededThread ptsacc %{public}ld",bufferInfo.attr.pts); + AVCODEC_SAMPLE_LOGI("LppVideoDataNeededThread isIFrame %u",bufferInfo.attr.flags & AVCODEC_BUFFER_FLAGS_SYNC_FRAME); + int32_t remain = OH_AVSamplesBuffer_GetRemainedCapacity(lppVideoContext_->framePacket_); + if ((bufferInfo.attr.flags & AVCODEC_BUFFER_FLAGS_EOS)){ + AVCODEC_SAMPLE_LOGI("Catch EOS, video thread out"); + OH_AVBuffer_SetBufferAttr(reinterpret_cast(bufferInfo.buffer), &bufferInfo.attr); + std::unique_lock eosFlagMutexLock(lppVideoContext_->eosFlagMutex); + lppVideoContext_->eosFlag_ = true; + AVCODEC_SAMPLE_LOGI("VIDEO eosFlag_ %{public}d",lppContext_->eosFlag_); + eosFlagMutexLock.unlock(); + } + OH_AVSamplesBuffer_AppendOneBuffer(lppVideoContext_->framePacket_, reinterpret_cast(bufferInfo.buffer)); + lppVideoContext_->count--; + AVCODEC_SAMPLE_LOGI("LppVideoDataNeededThread count %{public}d", lppVideoContext_->count); + } + AVCODEC_SAMPLE_LOGI("LppVideoDataNeededThread count %{public}d", lppVideoContext_->count); + if(lppVideoContext_->count == VIDEO_FRAME_COUNT){ + continue; + } + if(state_ == PLAYING){ + lppVideoStreamer_->returnFrames(lppVideoContext_); + } + AVCODEC_SAMPLE_LOGD("LppVideoDataNeededThread returnFrames end"); + lock.unlock(); + } + AVCODEC_SAMPLE_LOGI("====== AVBUFFER1234 DESTROY1 ======"); + OH_AVBuffer_Destroy(avbuffer); +} + diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/sample/player/Player.h b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/sample/player/Player.h new file mode 100644 index 0000000000000000000000000000000000000000..1400c29986f9c94da5769ef01f41d11341a6cae4 --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/sample/player/Player.h @@ -0,0 +1,125 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved. + */ +/* + * Copyright (C) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef VIDEO_CODEC_PLAYER_H +#define VIDEO_CODEC_PLAYER_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "lpp_audio_streamer.h" +#include "lpp_video_streamer.h" +#include "multimedia/player_framework/native_avbuffer.h" +#include "demuxer.h" +#include "sample_info.h" +#include "plugin_manager.h" +enum AVSinkState { + IDLE, + INIT, + PREPARED, + PLAYING, + PAUSE, + STOP, +}; +class Player { +public: + Player(){}; + ~Player(); + + static Player& GetInstance() + { + static Player player; + return player; + } + + int32_t Init(SampleInfo &sampleInfo); + int32_t Stop(); + int32_t Reset(); + int32_t Pause(); + int32_t Resume(); + int32_t SetSpeed(double speed); + int32_t SetSurface(int64_t surfaceId); + int32_t SetVolume(double volume); + int32_t Flush(); + int32_t Seek(int64_t seekTime, int32_t mode, bool acc); + int32_t Prepare(); + int32_t StartDecoder(); + int32_t RenderFirstFrame(); + int32_t StartRender(); + int32_t StartAudio(); + void Release(); + void StartRelease(); + int64_t GetDurationTime(); + int64_t GetProgressTime(); + +private: + void LppDataNeededThread1(); + void LppVideoDataNeededThread(); + void SeekInner(int64_t seekTime, int32_t mode); + void ReleaseThread(); + int32_t CreateLppAudioStreamer(); + int32_t CreateLppVideoStreamer(); + bool Intercept(); + + int64_t ReadToAudioTargetPts(int64_t pts); + + std::shared_ptr lppAudioStreamer_ = nullptr; + std::shared_ptr lppVideoStreamer_ = nullptr; + std::unique_ptr demuxer_ = nullptr; + + std::mutex mutex_; + std::atomic isStarted_ { false }; + std::atomic isReleased_ { false }; + std::atomic isAudioDone { false }; + std::atomic isVideoDone { false }; + std::condition_variable doneCond_; + std::mutex doneMutex; + SampleInfo sampleInfo_; + + LppUserData *lppContext_ = nullptr; + // 等回调消费数据 + std::unique_ptr LppDataNeededThread_ = nullptr; + // 生产数据,Max + std::unique_ptr LppDataProducerThread_ = nullptr; + + LppUserData *lppVideoContext_ = nullptr; + std::unique_ptr lppVideoDataNeededThread_ = nullptr; + std::unique_ptr lppSeekThread_ = nullptr; + + int64_t progress = 0; + int64_t nowTimeStamp = 0; + int64_t audioTimeStamp = 0; + int64_t writtenSampleCnt = 0; + int64_t audioBufferPts = 0; + std::mutex SeekMutex; + OH_AVBuffer *audioBuffer_ = nullptr; + OH_AVBuffer *videoBuffer_ = nullptr; + std::queue videoBufferInfo_; + bool seekFlag_ = false; + AVSinkState state_ = IDLE; + static constexpr int64_t MICROSECOND_TO_S = 1000000; + static constexpr int64_t NANO_TO_S = 1000000000; +}; + +#endif // VIDEO_CODEC_PLAYER_H \ No newline at end of file diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/sample/player/PlayerNative.cpp b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/sample/player/PlayerNative.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3ac41d075b0534c225808a3440cf6c0700569402 --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/sample/player/PlayerNative.cpp @@ -0,0 +1,277 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2025-2025. All rights reserved. + */ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "PlayerNative.h" +#include + +#undef LOG_DOMAIN +#undef LOG_TAG +#define LOG_DOMAIN 0xFF00 +#define LOG_TAG "playerNative" + +struct CallbackContext { + napi_env env = nullptr; + napi_ref callbackRef = nullptr; +}; + +void Callback(void *asyncContext) +{ + uv_loop_s *loop = nullptr; + CallbackContext *context = (CallbackContext *)asyncContext; + napi_get_uv_event_loop(context->env, &loop); + uv_work_t *work = new uv_work_t; + work->data = context; + uv_queue_work( + loop, work, [](uv_work_t *work) {}, + [](uv_work_t *work, int status) { + CallbackContext *context = (CallbackContext *)work->data; + napi_handle_scope scope = nullptr; + // 管理 napi_value 的生命周期,防止内存泄露 + napi_open_handle_scope(context->env, &scope); + napi_value callback = nullptr; + napi_get_reference_value(context->env, context->callbackRef, &callback); + // 回调至UI侧 + napi_call_function(context->env, nullptr, callback, 0, nullptr, nullptr); + napi_close_handle_scope(context->env, scope); + delete work; + }); +} + +napi_value PlayerNative::Play(napi_env env, napi_callback_info info) +{ + SampleInfo sampleInfo; + size_t argc = 5; // 参数个数,这里ArkTS往native测传递了两个参数,故此处赋值为4 + napi_value args[5] = {nullptr}; // napi_value类型数组,用于存储接收的ArkTS侧参数 + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); // 从info中获取参数信息到参数数组args[] + + int32_t two = 2; + int32_t three = 3; + napi_get_value_int32(env, args[0], &sampleInfo.inputFd); + napi_get_value_int64(env, args[1], &sampleInfo.inputFileOffset); + napi_get_value_int64(env, args[two], &sampleInfo.inputFileSize); + + AVCODEC_SAMPLE_LOGI("inputFilePath %{public}s",sampleInfo.inputFilePath.c_str()); + AVCODEC_SAMPLE_LOGI("inputFilePath %{public}ld",sampleInfo.inputFileSize); + + auto asyncContext = new CallbackContext(); + asyncContext->env = env; + napi_create_reference(env, args[three], 1, &asyncContext->callbackRef); + + sampleInfo.playDoneCallback = &Callback; + sampleInfo.playDoneCallbackData = asyncContext; + auto asyncContextB = new CallbackContext(); + asyncContextB->env = env; + napi_create_reference(env, args[4], 1, &asyncContextB->callbackRef); + sampleInfo.audioCallback = &Callback; + sampleInfo.audioCallbackData = asyncContextB; + int32_t ret = Player::GetInstance().Init(sampleInfo); + return nullptr; +} + +napi_value PlayerNative::Stop(napi_env env, napi_callback_info info) +{ + AVCODEC_SAMPLE_LOGD("NativeStop"); + Player::GetInstance().Stop(); + AVCODEC_SAMPLE_LOGD("NativeStop1"); + return nullptr; +} + +napi_value PlayerNative::Release(napi_env env, napi_callback_info info) +{ + AVCODEC_SAMPLE_LOGD("NativeRelease in"); + Player::GetInstance().StartRelease(); + AVCODEC_SAMPLE_LOGD("NativeRelease out"); + return nullptr; +} + +napi_value PlayerNative::Reset(napi_env env, napi_callback_info info) +{ + AVCODEC_SAMPLE_LOGD("resetNative in"); + Player::GetInstance().Reset(); + AVCODEC_SAMPLE_LOGD("resetNative out"); + return nullptr; +} + +napi_value PlayerNative::Pause(napi_env env, napi_callback_info info) +{ + AVCODEC_SAMPLE_LOGD("PauseNative in"); + Player::GetInstance().Pause(); + AVCODEC_SAMPLE_LOGD("PauseNative out"); + return nullptr; +} + +napi_value PlayerNative::Resume(napi_env env, napi_callback_info info) +{ + AVCODEC_SAMPLE_LOGD("ResumeNative in"); + Player::GetInstance().Resume(); + AVCODEC_SAMPLE_LOGD("ResumeNative out"); + return nullptr; +} + +napi_value PlayerNative::Speed(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value args[1] = {nullptr}; + double speed = 1.0; + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + napi_get_value_double(env, args[0], &speed); + AVCODEC_SAMPLE_LOGD("ResumeNative in"); + Player::GetInstance().SetSpeed(speed); + AVCODEC_SAMPLE_LOGD("ResumeNative out"); + return nullptr; +} + +napi_value PlayerNative::SetSurface(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value args[1] = {nullptr}; + char surfaceId[30] = ""; + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + napi_get_value_string_utf8(env, args[0], surfaceId, 30, 0); + char* endptr; + int64_t value = std::strtoll(surfaceId, &endptr, 10); + AVCODEC_SAMPLE_LOGD("SetSurface In %{public}ld %{public}s", value, surfaceId); + Player::GetInstance().SetSurface(value); + AVCODEC_SAMPLE_LOGD("SetSurface out"); + return nullptr; +} + +napi_value PlayerNative::Seek(napi_env env, napi_callback_info info) +{ + int32_t seekTime = 0; + int32_t mode = 0; + bool acc = false; + size_t seekArgc = 3; // 参数个数,这里ArkTS往native测传递了两个参数,故此处赋值为4 + napi_value seekArgs[3] = {nullptr}; // napi_value类型数组,用于存储接收的ArkTS侧参数 + napi_get_cb_info(env, info, &seekArgc, seekArgs, nullptr, nullptr); // 从info中获取参数信息到参数数组args[] + napi_get_value_int32(env, seekArgs[0], &seekTime); + napi_get_value_int32(env, seekArgs[1], &mode); + napi_get_value_bool(env, seekArgs[0], &acc); + AVCODEC_SAMPLE_LOGI("Seek in"); + Player::GetInstance().Seek(seekTime, mode, acc); + AVCODEC_SAMPLE_LOGI("Seek out"); + return nullptr; +} + +napi_value PlayerNative::Prepare(napi_env env, napi_callback_info info) +{ + AVCODEC_SAMPLE_LOGI("Prepare in"); + napi_value result; + int32_t ret = Player::GetInstance().Prepare(); + napi_create_int32(env, ret, &result); + AVCODEC_SAMPLE_LOGI("Prepare out"); + return result; +} + +napi_value PlayerNative::StartDecoder(napi_env env, napi_callback_info info) +{ + AVCODEC_SAMPLE_LOGI("StartDecoder in"); + Player::GetInstance().StartDecoder(); + AVCODEC_SAMPLE_LOGI("StartDecoder out"); + return nullptr; +} +napi_value PlayerNative::RenderFirstFrame(napi_env env, napi_callback_info info) +{ + AVCODEC_SAMPLE_LOGI("RenderFirstFrame in"); + Player::GetInstance().RenderFirstFrame(); + AVCODEC_SAMPLE_LOGI("RenderFirstFrame out"); + return nullptr; +} +napi_value PlayerNative::StartRender(napi_env env, napi_callback_info info) +{ + AVCODEC_SAMPLE_LOGI("StartRender in"); + Player::GetInstance().StartRender(); + AVCODEC_SAMPLE_LOGI("StartRender out"); + return nullptr; +} +napi_value PlayerNative::StartAudio(napi_env env, napi_callback_info info) +{ + AVCODEC_SAMPLE_LOGI("StartAudio in"); + Player::GetInstance().StartAudio(); + AVCODEC_SAMPLE_LOGI("StartAudio out"); + return nullptr; +} + +napi_value PlayerNative::GetDurationTime(napi_env env, napi_callback_info info) { + napi_value result; + int64_t duration = Player::GetInstance().GetDurationTime(); + napi_create_int64(env, duration, &result); + return result; +} + +napi_value PlayerNative::GetProgressTime(napi_env env, napi_callback_info info) { + napi_value result; + int64_t progress = Player::GetInstance().GetProgressTime(); + napi_create_int64(env, progress, &result); + return result; +} + +napi_value PlayerNative::SetVolume(napi_env env, napi_callback_info info) { + size_t argc = 1; + napi_value args[1] = {nullptr}; + double volume = 0; + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + napi_get_value_double(env, args[0], &volume); + AVCODEC_SAMPLE_LOGD("SetVolume in"); + Player::GetInstance().SetVolume(volume); + AVCODEC_SAMPLE_LOGD("SetVolume out"); + return nullptr; +} +EXTERN_C_START +static napi_value Init(napi_env env, napi_value exports) { + napi_property_descriptor classProp[] = { + {"playNative", nullptr, PlayerNative::Play, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"stopNative", nullptr, PlayerNative::Stop, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"releaseNative", nullptr, PlayerNative::Release, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"resetNative", nullptr, PlayerNative::Reset, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"pauseNative", nullptr, PlayerNative::Pause, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"resumeNative", nullptr, PlayerNative::Resume, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"speedNative", nullptr, PlayerNative::Speed, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"setSurfaceNative", nullptr, PlayerNative::SetSurface, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"seekNative", nullptr, PlayerNative::Seek, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"getDurationTime", nullptr, PlayerNative::GetDurationTime, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"getProgressTime", nullptr, PlayerNative::GetProgressTime, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"prepareNative", nullptr, PlayerNative::Prepare, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"startDecoderNative", nullptr, PlayerNative::StartDecoder, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"renderFirstFrameNative", nullptr, PlayerNative::RenderFirstFrame, nullptr, nullptr, nullptr, napi_default, + nullptr}, + {"startRenderNative", nullptr, PlayerNative::StartRender, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"startAudioNative", nullptr, PlayerNative::StartAudio, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"setVolumeNative", nullptr, PlayerNative::SetVolume, nullptr, nullptr, nullptr, napi_default, nullptr}, + }; + + NativeXComponentSample::PluginManager::GetInstance()->Export(env, exports); + napi_define_properties(env, exports, sizeof(classProp) / sizeof(classProp[0]), classProp); + return exports; +} +EXTERN_C_END + +static napi_module PlayerModule = { + .nm_version = 1, + .nm_flags = 0, + .nm_filename = nullptr, + .nm_register_func = Init, + .nm_modname = "player", + .nm_priv = ((void *)0), + .reserved = { 0 }, +}; + +extern "C" __attribute__((constructor)) void RegisterPlayerModule(void) +{ + napi_module_register(&PlayerModule); +} \ No newline at end of file diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/sample/player/PlayerNative.h b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/sample/player/PlayerNative.h new file mode 100644 index 0000000000000000000000000000000000000000..eb007684aa5a756cf19ca11e3206517f97bd046d --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/sample/player/PlayerNative.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2025-2025. All rights reserved. + */ +/* + * Copyright (C) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LPP_SAMPLE_PLAYER_NATIVE_H +#define LPP_SAMPLE_PLAYER_NATIVE_H + +#include +#include +#include +#include +#include "napi/native_api.h" +#include "Player.h" +#include "dfx/error/av_codec_sample_error.h" +#include "av_codec_sample_log.h" +#include "plugin_manager.h" + +class PlayerNative { +public: + static napi_value Play(napi_env env, napi_callback_info info); + static napi_value Stop(napi_env env, napi_callback_info info); + static napi_value Release(napi_env env, napi_callback_info info); + static napi_value Reset(napi_env env, napi_callback_info info); + static napi_value Pause(napi_env env, napi_callback_info info); + static napi_value Resume(napi_env env, napi_callback_info info); + static napi_value Speed(napi_env env, napi_callback_info info); + static napi_value SetSurface(napi_env env, napi_callback_info info); + static napi_value Seek(napi_env env, napi_callback_info info); + static napi_value SetVolume(napi_env env, napi_callback_info info); + static napi_value Prepare(napi_env env, napi_callback_info info); + static napi_value StartDecoder(napi_env env, napi_callback_info info); + static napi_value RenderFirstFrame(napi_env env, napi_callback_info info); + static napi_value StartRender(napi_env env, napi_callback_info info); + static napi_value StartAudio(napi_env env, napi_callback_info info); + static napi_value GetDurationTime(napi_env env, napi_callback_info info); + static napi_value GetProgressTime(napi_env env, napi_callback_info info); +}; +#endif // LPP_SAMPLE_PLAYER_NATIVE_H \ No newline at end of file diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/types/libplayer/index.d.ts b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/types/libplayer/index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..93c4d627eed4830943fb4905d14e129c677ab140 --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/types/libplayer/index.d.ts @@ -0,0 +1,57 @@ +export const playNative: ( + inputFileFd: number, + inputFileOffset: number, + inputFileSize: number, + cbFn: () => void, + audioCbFn: () => void +) => void; + +export const stopNative: () => void + +export const releaseNative: () => void + +export const resetNative: () => void + +export const pauseNative: () => void + +export const resumeNative: () => void + +export const speedNative: ( + speed: number +) => void + +export const setSurfaceNative: ( + surfaceId: string +) => void + +export const seekNative: ( + seekTime: number, + mode: number, + acc: boolean, +) => void + +export const setVolumeNative: ( + volume: number, +) => void + +export const getDurationTime: ( +) => number + +export const getProgressTime: ( +) => number + +export const startNative: () => void + +export const prepareNative: () => number + +export const startDecoderNative: () => void + +export const renderFirstFrameNative: () => void + +export const startRenderNative: () => void + +export const startAudioNative: () => void + + + + diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/types/libplayer/oh-package.json5 b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/types/libplayer/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..31f8de6b1f5a2dd14e1514cba2ad0a50f8b44a80 --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/cpp/types/libplayer/oh-package.json5 @@ -0,0 +1,6 @@ +{ + "name": "libplayer.so", + "types": "./index.d.ts", + "version": "1.0.0", + "decription": "Player interface." +} \ No newline at end of file diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/ets/common/CommonConstants.ets b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/ets/common/CommonConstants.ets new file mode 100644 index 0000000000000000000000000000000000000000..6fa05947281e73436f8ab7cf2203f8dc263d46d4 --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/ets/common/CommonConstants.ets @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { camera } from '@kit.CameraKit'; + +export class CommonConstants { + /** + * Full size. + */ + static readonly FULL_SIZE: string = '100%' + /** + * Default width. + */ + static readonly DEFAULT_WIDTH: number = 1920 + /** + * Default height. + */ + static readonly DEFAULT_HEIGHT: number = 1080 + /** + * Button width. + */ + static readonly BUTTON_WIDTH: number = 100 + /** + * Duration. + */ + static readonly DURATION: number = 2000 + /** + * The distance between toast dialog box and the bottom of screen. + */ + static readonly BOTTOM: number = 200 + /** + * Image width. + */ + static readonly IMAGE_WIDTH: number = 50 + /** + * Image height. + */ + static readonly IMAGE_HEIGHT: number = 50 + /** + * Video mime type. + */ + static readonly VIDEO_MIMETYPE: string[] = ['HDRVivid', 'H264', 'H265'] + /** + * Video resolution. + */ + static readonly VIDEO_RESOLUTION: string[] = ['4K', '1080P', '720P'] + /** + * Video framerate. + */ + static readonly VIDEO_FRAMERATE: string[] = ['30Fps', '60Fps'] + /** + * Video recorderInfo. + */ + static readonly RECORDER_INFO: string[][] = [ + CommonConstants.VIDEO_MIMETYPE, CommonConstants.VIDEO_RESOLUTION, CommonConstants.VIDEO_FRAMERATE + ] + /** + * Default value. + */ + static readonly DEFAULT_VALUE: number = 0 + /** + * Video avc mime type. + */ + static readonly MIME_VIDEO_AVC: string = 'video/avc' + /** + * Video hevc mime type. + */ + static readonly MIME_VIDEO_HEVC: string = 'video/hevc' + /** + * 10M bitrate. + */ + static readonly BITRATE_VIDEO_10M: number = 10 * 1024 * 1024 + /** + * 20M bitrate. + */ + static readonly BITRATE_VIDEO_20M: number = 20 * 1024 * 1024 + /** + * 30M bitrate. + */ + static readonly BITRATE_VIDEO_30M: number = 30 * 1024 * 1024 + /** + * 30 FPS. + */ + static readonly FRAMERATE_VIDEO_30FPS: number = 30 + /** + * 60 FPS. + */ + static readonly FRAMERATE_VIDEO_60FPS: number = 60 + /** + * Row space. + */ + static readonly ROW_SPACE: number = 10 + /** + * Default picker item height. + */ + static readonly DEFAULT_PICKER_ITEM_HEIGHT: number = 30 + /** + * Selected text style font size. + */ + static readonly SELECTED_TEXT_STYLE_FONT_SIZE: number = 15 + /** + * The number corresponding to true. + */ + static readonly TRUE: number = 1 + /** + * The number corresponding to false. + */ + static readonly FALSE: number = 0 + /** + * 4K video width. + */ + static readonly VIDEO_WIDTH_4K: number = 3840 + /** + * 1080P video width. + */ + static readonly VIDEO_WIDTH_1080P: number = 1920 + /** + * 720P video width. + */ + static readonly VIDEO_WIDTH_720P: number = 1280 + /** + * 4K video height. + */ + static readonly VIDEO_HEIGHT_4K: number = 2160 + /** + * 1080P video height. + */ + static readonly VIDEO_HEIGHT_1080P: number = 1080 + /** + * 720P video height. + */ + static readonly VIDEO_HEIGHT_720P: number = 720 + /** + * Album, photo, video, and camera switch icons size. + */ + static readonly ICON_SIZE: number = 200; + /** + * Bottom position. + */ + static readonly BOTTOM_POSITION: number = 0.8 + /** + * PX. + */ + static readonly PX: string = 'px'; + /** + * Default profile. + */ + static readonly DEFAULT_PROFILE: camera.Profile = { + format: camera.CameraFormat.CAMERA_FORMAT_YUV_420_SP, + size: { + width: 1920, + height: 1080 + } + }; +} \ No newline at end of file diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/ets/common/utils/DateTimeUtils.ets b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/ets/common/utils/DateTimeUtils.ets new file mode 100644 index 0000000000000000000000000000000000000000..2f0a95d6c5db9557371c5beb8ce6e8b4a9d427ef --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/ets/common/utils/DateTimeUtils.ets @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export default class DateTimeUtil { + getTime(): string { + const DATETIME = new Date(); + return this.concatTime(DATETIME.getHours(), DATETIME.getMinutes(), DATETIME.getSeconds()) + } + + getDate(): string { + const DATETIME = new Date(); + return this.concatDate(DATETIME.getFullYear(), DATETIME.getMonth() + 1, DATETIME.getDate()) + } + + fill(value: number): string { + return (value > 9 ? '' : '0') + value; + } + + concatDate(year: number, month: number, date: number): string { + return `${year}${month}${date}`; + } + + concatTime(hour: number, minute: number, second: number): string { + return `${this.fill(hour)}${this.fill(minute)}${this.fill(second)}`; + } +} + +export function getShownTimer(ms: number): string { + let seconds: number = Math.round(ms / 1000); + let sec: number = seconds % 60; + let min: number = (seconds - sec) / 60; + let secStr = (sec >= 0 && sec < 10) ? ('0' + sec) : sec; + let minStr = (min >= 0 && min < 10) ? ('0' + min) : min; + return (minStr + ':' + secStr); +} + +export function dateTime(t: number): string { + let minute: number = Math.floor(t / 60) % 60 + let m = minute < 10 ? '0' + minute : minute + let second: number = t % 60 + let s = second < 10 ? '0' + second : second + return m + ':' + s; +} \ No newline at end of file diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/ets/common/utils/Logger.ets b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/ets/common/utils/Logger.ets new file mode 100644 index 0000000000000000000000000000000000000000..149765ff21ecd016d6bc3e7da1b632e1906fa543 --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/ets/common/utils/Logger.ets @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License") + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import hilog from '@ohos.hilog' + +class Logger { + private domain: number + private prefix: string + private format: string = '%{public}s, %{public}s' + + constructor(prefix: string) { + this.prefix = prefix + this.domain = 0xFF00 + } + + debug(...args: string[]): void { + hilog.debug(this.domain, this.prefix, this.format, args) + } + + info(...args: string[]): void { + hilog.info(this.domain, this.prefix, this.format, args) + } + + warn(...args: string[]): void { + hilog.warn(this.domain, this.prefix, this.format, args) + } + + error(...args: string[]): void { + hilog.error(this.domain, this.prefix, this.format, args) + } +} + +export default new Logger('AVRecorderSample') \ No newline at end of file diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/ets/entryability/EntryAbility.ets b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/ets/entryability/EntryAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..6d32df7f25b0139349469f9dc403e1f0d56eebb6 --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/ets/entryability/EntryAbility.ets @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License") + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit' +import { BusinessError } from '@kit.BasicServicesKit' +import { window } from '@kit.ArkUI' +import abilityAccessCtrl from '@ohos.abilityAccessCtrl' +import Logger from '../common/utils/Logger' +import { hilog } from '@kit.PerformanceAnalysisKit' + +const TAG: string = 'EntryAbility' + +function requestPre() { + let atManager = abilityAccessCtrl.createAtManager() + try { + atManager.requestPermissionsFromUser(globalThis.context, + ['ohos.permission.CAMERA',]) + .then((data) => { + Logger.info("requestPre() data: " + JSON.stringify(data)) + }).catch((err:BusinessError) => { + Logger.info("requestPre() data: " + JSON.stringify(err)) + }) + } catch (err) { + Logger.error("requestPre() data: " + JSON.stringify(err)) + } +} + +export default class EntryAbility extends UIAbility { + onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) { + Logger.info('Ability onCreate') + globalThis.context = this.context + requestPre() + } + + onDestroy() { + Logger.info('Ability onDestroy') + } + + onWindowStageCreate(windowStage: window.WindowStage) { + // Main window is created, set main page for this ability + Logger.info('Ability onWindowStageCreate') + + windowStage.getMainWindowSync().setWindowKeepScreenOn(true) + windowStage.loadContent('pages/Index', (err, data) => { + if (err.code) { + Logger.error('Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '') + return + } + Logger.info('Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '') + }) + let windowClass: window.Window = windowStage.getMainWindowSync() // 获取应用主窗口 + // Set the window to full screen + let isLayoutFullScreen = true + windowClass.setWindowLayoutFullScreen(isLayoutFullScreen) + .then(() => { + hilog.info(0x0000, TAG, 'Succeeded in setting the window layout to full-screen mode. Data: %{public}s') + }) + .catch((err: BusinessError) => { + hilog.error(0x0000, TAG, 'Failed to set the window layout to full-screen mode. Cause: %{public}s', + JSON.stringify(err) ?? '') + }) + // Set the font color of the status bar. + let SystemBarProperties: window.SystemBarProperties = { + statusBarContentColor: '#FFFFFF' + } + windowStage.getMainWindowSync().setWindowSystemBarProperties(SystemBarProperties) + } + + onWindowStageDestroy() { + // Main window is destroyed, release UI related resources + Logger.info('Ability onWindowStageDestroy') + } + + onForeground() { + // Ability has brought to foreground + Logger.info('Ability onForeground') + } + + onBackground() { + // Ability has back to background + Logger.info('Ability onBackground') + } +} diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/ets/pages/Index.ets b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/ets/pages/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..3b3bf57fa7220af781688a81d97e8f50aa56e30c --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/ets/pages/Index.ets @@ -0,0 +1,685 @@ +import { fileIo } from '@kit.CoreFileKit'; +import { display, promptAction, router, window } from '@kit.ArkUI'; +import { photoAccessHelper } from '@kit.MediaLibraryKit'; +import player from 'libplayer.so'; +import Logger from '../common/utils/Logger'; +import { CommonConstants as Const } from '../common/CommonConstants'; +import picker from '@ohos.file.picker' +import { common } from '@kit.AbilityKit'; + +const TAG: string = 'Sample_Player' +const PLAY_STATUS = ['initial', 'selected', 'prepared', 'ready', 'playing', 'pausing'] + + +@Entry +@Component +export struct Player { + private surfaceId1: string = ''; + private surfaceId2: string = ''; + @StorageProp('topRectHeight') + topRectHeight: number = 0; + @State duration:string = '--:--:--' + @State progress:string = '--:--:--' + @State progressBarNumber:number = 0; + @State surfaceWidth:string = "100%" + @State surfaceHeight:string = "400" + @State speedMode:number = 1.0; + @State playStatus:string = 'initial'; + @State isPausing:boolean = false; + @State xComponentStatus:Visibility = Visibility.Visible; + @State controlStatus:Visibility = Visibility.Hidden; + @State surfaceId:string = "1"; + private intervalId:number = -1; + private showIntervalId:number = -1; + private selectFilePath: string | null = null; + private sourcePath: string[] = ['从文件管理选取', '从图库选取'] + private durationTime:number = 0; + private progressTime:number = 0; + private volume:number = 100; + private touchX:number = -1; + private seekMode:number = 0; + private xComponentController: XComponentController = new XComponentController(); + private xComponentController2: XComponentController = new XComponentController(); + private scroller = new Scroller() + private operationRet:number = 0; + private seekFlag:number = 0; + private context = getContext(this) as common.AbilityStageContext; + + selectFile() { + TextPickerDialog.show({ + range: this.sourcePath, + canLoop: false, + selected: 0, + onAccept: (value: TextPickerResult) => { + clearInterval(this.intervalId); + switch (value.value) { + case '从文件管理选取': + this.selectDocFile() + break + case '从图库选取': + this.selectAlbumFile() + break + default: + this.selectAlbumFile() + break + } + } + }) + } + + selectDocFile() { + let documentSelectOptions = new picker.DocumentSelectOptions + let documentViewPicker = new picker.DocumentViewPicker + documentViewPicker.select(documentSelectOptions) + .then((documentSelectResult) => { + this.selectFilePath = documentSelectResult[0] + if (this.selectFilePath == null) { + promptAction.showToast({ + message: $r('app.string.alert'), + duration: Const.DURATION, + bottom: Const.BOTTOM + }); + } else { + this.play(); + Logger.info(TAG, 'documentViewPicker.select to file succeed and URI is:' + this.selectFilePath); + } + }) + } + + selectAlbumFile() { + let photoPicker = new photoAccessHelper.PhotoViewPicker(); + photoPicker.select({ + MIMEType: photoAccessHelper.PhotoViewMIMETypes.VIDEO_TYPE, + maxSelectNumber: 1 + }) + .then((photoSelectResult) => { + this.selectFilePath = photoSelectResult.photoUris[0]; + if (this.selectFilePath == null) { + promptAction.showToast({ + message: $r('app.string.alert'), + duration: Const.DURATION, + bottom: Const.BOTTOM + }); + } else { + this.play(); + Logger.info(TAG, 'documentViewPicker.select to file succeed and URI is:' + this.selectFilePath); + } + }) + } + + formatDuration(durationInMicroseconds: number): string { + const totalSeconds = Math.floor(durationInMicroseconds / 1000000); + const hours = Math.floor(totalSeconds / 3600); + const minutes = Math.floor((totalSeconds % 3600) / 60); + const seconds = totalSeconds % 60; + return `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`; + } + + + play() { + let inputFile = fileIo.openSync(this.selectFilePath, fileIo.OpenMode.READ_ONLY); + if (!inputFile) { + Logger.error(TAG, 'player inputFile is null'); + } + let inputFileState = fileIo.statSync(inputFile.fd); + if (inputFileState.size <= 0) { + Logger.error(TAG, 'player inputFile size is 0'); + } + player.playNative(inputFile.fd, Const.DEFAULT_VALUE, inputFileState.size, + () => { + Logger.info(TAG, 'player JSCallback'); + fileIo.close(inputFile); + }, + () => { + Logger.info(TAG, 'audio JSCallback'); + player.pauseNative(); + this.playStatus = 'pausing'; + }) + this.playStatus = 'selected'; + } + + playTest() { + let filesDir = this.context.resourceDir; + Logger.info(TAG, 'documentViewPicker.select to file succeed and URI is2:' + filesDir); + let inputFile = fileIo.openSync(filesDir+"/fuzztest.mp4", fileIo.OpenMode.READ_ONLY); + Logger.info(TAG, 'documentViewPicker.select to file succeed and URI is2:' + inputFile); + if (!inputFile) { + return; + } + let inputFileState = fileIo.statSync(inputFile.fd); + if (inputFileState.size <= 0) { + return; + } + player.playNative(inputFile.fd, Const.DEFAULT_VALUE, inputFileState.size, + () => { + Logger.info(TAG, 'player JSCallback'); + fileIo.close(inputFile); + }, + () => { + Logger.info(TAG, 'audio JSCallback'); + player.pauseNative(); + this.playStatus = 'pausing'; + }) + player.prepareNative(); + player.startDecoderNative(); + setTimeout(() => { + player.renderFirstFrameNative(); + player.startRenderNative(); + player.startAudioNative(); + this.playStatus = "playing" + }, 300); + } + + + updateProgress(progressTime:number){ + this.progressTime = progressTime; + this.progress = this.formatDuration(this.progressTime); + this.progressBarNumber = 260*(this.progressTime/this.durationTime); + } + + onPageShow() { + player.resumeNative(); + } + + onPageHide() { + player.pauseNative(); + } + setOrientation(flag: boolean) { + if(this.surfaceHeight == "400"){ + window.getLastWindow(getContext(this)).then((win) => { + win.setPreferredOrientation(window.Orientation.LANDSCAPE); + this.surfaceHeight = "100%"; + }) + } else { + window.getLastWindow(getContext(this)).then((win) => { + win.setPreferredOrientation(window.Orientation.PORTRAIT); + this.surfaceHeight = "400"; + }) + } + } + + + build() { + Scroll(this.scroller) { + Column() { + Row() { + XComponent({ + id: 'player', + type: XComponentType.SURFACE, + libraryname: 'player', + controller: this.xComponentController + }) + .height(Const.FULL_SIZE) + .width(Const.FULL_SIZE) + .visibility(this.surfaceId == "1" ? this.xComponentStatus : Visibility.None) + .onLoad(() => { + this.surfaceId1 = this.xComponentController.getXComponentSurfaceId(); + }) + XComponent({ + id: 'player2', + type: XComponentType.SURFACE, + libraryname: 'player', + controller: this.xComponentController2 + }) + .height(Const.FULL_SIZE) + .width(Const.FULL_SIZE) + .visibility(this.surfaceId == "2" ? this.xComponentStatus : Visibility.None) + .onLoad(() => { + this.surfaceId2 = this.xComponentController2.getXComponentSurfaceId(); + }) + Text(this.surfaceId) + .height(18) + .fontSize(25) + .fontColor("white") + .position({ "left": 20, "bottom": 20 }) + .onClick(() => { + if (this.surfaceId == "1") { + player.setSurfaceNative(this.surfaceId2); + this.surfaceId = "2"; + } else { + player.setSurfaceNative(this.surfaceId1); + this.surfaceId = "1"; + } + }) + Image($r("app.media.full")) + .height(18) + .position({ "right": 10, "bottom": 10 }) + .visibility(this.controlStatus) + .onClick(() => { + this.setOrientation(true); + }) + } + .id("screen") + .width(this.surfaceWidth) + .height(this.surfaceHeight) + // .aspectRatio(16/9) + // .backgroundColor('black') + .onTouch((event: TouchEvent) => { + const type: TouchType = event.type; + if (type == TouchType.Down) { + const x: number = event.touches[0].x; + this.touchX = x; + } + if (type == TouchType.Up) { + const x: number = event.touches[0].x; + if (x > this.touchX) { + let seekTime = this.progressTime / 1000 + 10000 + if (seekTime > this.durationTime / 1000) { + seekTime = this.durationTime / 1000; + } + player.seekNative(seekTime, this.seekMode, false); + } else if (x < this.touchX) { + let seekTime = this.progressTime / 1000 - 10000 + if (seekTime < 0) { + seekTime = 0; + } + player.seekNative(seekTime, this.seekMode, false); + } + } + }) + .onClick(() => { + clearInterval(this.showIntervalId); + this.showIntervalId = -1; + if (this.playStatus == "playing" || this.playStatus == 'pausing') { + this.controlStatus = Visibility.Visible; + this.showIntervalId = setTimeout(() => { + this.controlStatus = Visibility.Hidden; + }, 3000) + } + }) + + Row() { + Row() { + } + .width(260) + .height(8) + .backgroundColor('white') + .position({ left: 6, top: 12 }) + .onTouch((event: TouchEvent) => { + const type: TouchType = event.type; + if (type == TouchType.Move) { + const x: number = event.touches[0].x; + clearInterval(this.intervalId); + this.intervalId = -1; + this.progressTime = Math.floor(this.durationTime * (x / 260)) + this.progress = this.formatDuration(this.progressTime); + this.progressBarNumber = Math.floor(260 * (this.progressTime / this.durationTime)); + } + if (type == TouchType.Up) { + const x: number = event.touches[0].x; + const seekTime = Math.floor(this.durationTime * (x / 260) / 1000) + player.seekNative(seekTime, this.seekMode, false); + if (this.intervalId == -1) { + this.intervalId = setInterval(() => { + this.progressTime = player.getProgressTime(); + this.progress = this.formatDuration(this.progressTime); + this.progressBarNumber = Math.floor(260 * (this.progressTime / this.durationTime)); + }, 500); + } + } + }) + + Row() { + } + .id('Slider') + .width(this.progressBarNumber) + .height(8) + .backgroundColor('red') + .position({ left: 4, top: 12 }) + .onTouch((event: TouchEvent) => { + const type: TouchType = event.type; + if (type == TouchType.Move) { + const x: number = event.touches[0].x; + clearInterval(this.intervalId); + this.intervalId = -1; + this.progressTime = Math.floor(this.durationTime * (x / 260)) + this.progress = this.formatDuration(this.progressTime); + this.progressBarNumber = Math.floor(260 * (this.progressTime / this.durationTime)); + } + if (type == TouchType.Up) { + const x: number = event.touches[0].x; + const seekTime = Math.floor(this.durationTime * (x / 260) / 1000) + player.seekNative(seekTime, this.seekMode, false); + if (this.intervalId == -1) { + this.intervalId = setInterval(() => { + this.progressTime = player.getProgressTime(); + this.progress = this.formatDuration(this.progressTime); + this.progressBarNumber = Math.floor(260 * (this.progressTime / this.durationTime)); + }, 500); + } + } + }) + + Text(this.progress + "/" + this.duration) { + } + .align(Alignment.End) + .fontSize(12) + .fontColor("white") + .position({ right: 4, top: 8 }) + } + .width("100%") + .height("30") + .backgroundColor('black') + .margin({ top: 20 }) + + Row() { + Row() { + Text("0.5x") { + } + .fontColor(this.speedMode == 0.5 ? 'red' : 'white') + .margin({ left: 20 }) + .fontSize(18) + .onClick(() => { + if (!(this.playStatus == 'playing')) { + return; + } + player.speedNative(0.5); + this.speedMode = 0.5; + }) + + Text("1x") { + } + .fontColor(this.speedMode == 1.0 ? 'red' : 'white') + .margin({ left: 20 }) + .fontSize(18) + .onClick(() => { + if (!(this.playStatus == 'playing')) { + return; + } + player.speedNative(1.0); + this.speedMode = 1.0; + }) + + Text("2x") { + } + .fontColor(this.speedMode == 2.0 ? 'red' : 'white') + .margin({ left: 20 }) + .fontSize(18) + .onClick(() => { + if (!(this.playStatus == 'playing')) { + return; + } + player.speedNative(2.0); + this.speedMode = 2.0; + }) + + Text("4x") { + } + .fontColor(this.speedMode == 4.0 ? 'red' : 'white') + .margin({ left: 20 }) + .fontSize(18) + .onClick(() => { + if (!(this.playStatus == 'playing')) { + return; + } + player.speedNative(4.0); + this.speedMode = 4.0; + }) + } + .width("70%") + .height("100%") + + Row() { + Button('选择视频') + .onClick(() => { + this.selectFile(); + }) + .width('90%') + .height("80%") + .backgroundColor('#FF4500') + } + .width("30%") + .height("100%") + } + .width("100%") + .height("30") + .backgroundColor('black') + .margin({ top: 20 }) + + Row() { + Column() { + Button('准备') + .enabled(this.playStatus == 'selected') + .onClick(() => { + player.prepareNative(); + this.playStatus = 'prepared' + }) + .width('80%') + .height("80%") + .backgroundColor('#FF4500') + .margin({ top: 3 }) + } + .width('25%') + .height('100%') + + Column() { + Button('解码') + .enabled(this.playStatus == 'prepared') + .onClick(() => { + player.startDecoderNative(); + this.durationTime = player.getDurationTime(); + this.duration = this.formatDuration(this.durationTime); + this.playStatus = 'ready' + }) + .width('80%') + .height("80%") + .backgroundColor('#FF4500') + .margin({ top: 3 }) + } + .width('25%') + .height('100%') + + Column() { + Button('首帧') + .enabled(this.playStatus == 'prepared' || this.playStatus == 'ready') + .onClick(() => { + player.renderFirstFrameNative(); + this.durationTime = player.getDurationTime(); + this.duration = this.formatDuration(this.durationTime); + // this.xComponentStatus = Visibility.Visible; + this.playStatus = 'ready' + }) + .width('80%') + .height("80%") + .backgroundColor('#FF4500') + .margin({ top: 3 }) + } + .width('25%') + .height('100%') + + Column() { + Select([ + { value: '视频' }, + { value: '音频' }, + { value: '音视频' }, + ]) + .value('播放') + .controlSize(ControlSize.SMALL) + .enabled(this.playStatus == 'ready') + .backgroundColor('#FF4500') + .onSelect((index: number, text?: string | undefined) => { + console.info('Select:' + index) + // this.xComponentStatus = Visibility.Visible; + if (index === 0) { + player.startRenderNative() + } else if (index === 1) { + player.startAudioNative() + } else if (index === 2) { + player.startRenderNative() + player.startAudioNative() + } + this.intervalId = setInterval(() => { + this.progressTime = player.getProgressTime(); + this.progress = this.formatDuration(this.progressTime); + this.progressBarNumber = Math.floor(260 * (this.progressTime / this.durationTime)); + }, 300); + this.playStatus = 'playing' + }) + } + .width('25%') + .height('100%') + } + .width("100%") + .height("30") + .margin({ top: 20 }) + + Row() { + Column() { + Button(this.playStatus == 'pausing' ? '继续' : '暂停') + .enabled(this.playStatus == 'playing' || this.playStatus == 'pausing') + .id('Pause') + .onClick(() => { + if (this.playStatus == 'pausing') { + setTimeout(() => { + player.resumeNative(); + this.playStatus = 'playing'; + }, 0) + } else if (this.playStatus == 'playing') { + setTimeout(() => { + player.pauseNative(); + this.playStatus = 'pausing' + }, 0) + } + }) + .width('80%') + .height("80%") + .backgroundColor('#FF4500') + .margin({ top: 3 }) + } + .width('25%') + .height('100%') + + Column() { + Button('重置') + .enabled(this.playStatus == 'playing' || this.playStatus == 'pausing') + .id('Reset') + .onClick(() => { + // this.xComponentStatus = Visibility.Hidden; + player.resetNative(); + }) + .width('80%') + .height("80%") + .backgroundColor('#FF4500') + .margin({ top: 3 }) + } + .width('25%') + .height('100%') + + Column() { + Button('释放') + .enabled(this.playStatus == 'playing' || this.playStatus == 'pausing') + .id('Release') + .onClick(() => { + // this.xComponentStatus = Visibility.Hidden; + player.releaseNative(); + }) + .width('80%') + .height("80%") + .backgroundColor('#FF4500') + .margin({ top: 3 }) + } + .width('25%') + .height('100%') + + Column() { + Button('停止') + .enabled(this.playStatus == 'playing' || this.playStatus == 'pausing') + .onClick(() => { + player.stopNative(); + }) + .width('80%') + .height("80%") + .backgroundColor('#FF4500') + .margin({ top: 3 }) + } + .width('25%') + .height('100%') + } + .width("100%") + .height("30") + .margin({ top: 20 }) + + Row() { + Column() { + Button('音量-') + .enabled(this.playStatus == 'playing' || this.playStatus == 'pausing') + .onClick(() => { + this.volume = this.volume - 10; + if (this.volume <= 0) { + this.volume = 0; + } + player.setVolumeNative(this.volume / 100); + }) + .width('80%') + .height("80%") + .backgroundColor('#FF4500') + .margin({ top: 3 }) + } + .width('25%') + .height('100%') + + Column() { + Button('音量+') + .enabled(this.playStatus == 'playing' || this.playStatus == 'pausing') + .onClick(() => { + this.volume = this.volume + 10; + if (this.volume >= 100) { + this.volume = 100; + } + player.setVolumeNative(this.volume / 100); + }) + .width('80%') + .height("80%") + .backgroundColor('#FF4500') + .margin({ top: 3 }) + } + .width('25%') + .height('100%') + + Column() { + Select([ + { value: '前向关键帧' }, + { value: '后向关键帧' }, + { value: '最近关键帧' }, + ]) + .value('前向关键帧') + .controlSize(ControlSize.SMALL) + .backgroundColor('#FF4500') + .onSelect((index: number, text?: string | undefined) => { + console.info('Select:' + index) + if (index === 0) { + this.seekMode = 1; //前向 + } else if (index === 1) { + this.seekMode = 0; //后向 + } else if (index === 2) { + this.seekMode = 2; //最近 + } + }) + } + .width('25%') + .height('100%') + Column() { + Button('启动播放') + .onClick(() => { + this.playTest(); + }) + .id('Start') + .width('80%') + .height("80%") + .backgroundColor('#FF4500') + .margin({ top: 3 }) + } + .width('25%') + .height('100%') + } + .width("100%") + .height("30") + .margin({ top: 20 }) + } + } + // .backgroundColor('white') + .width('100%') + .height('100%') + .padding({top: px2vp(this.topRectHeight)}) + } +} \ No newline at end of file diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/module.json5 b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..1f65dfe0ac41a9f456aa2d04ca86b26c233741e1 --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/module.json5 @@ -0,0 +1,37 @@ +{ + "module": { + "name": "entry", + "type": "entry", + "description": "$string:module_desc", + "mainElement": "EntryAbility", + "deviceTypes": [ + "default", + "tablet" + ], + "deliveryWithInstall": true, + "installationFree": false, + "pages": "$profile:main_pages", + "abilities": [ + { + "name": "EntryAbility", + "srcEntry": "./ets/entryability/EntryAbility.ets", + "description": "$string:EntryAbility_desc", + "icon": "$media:icon", + "label": "$string:EntryAbility_label", + "startWindowIcon": "$media:icon", + "startWindowBackground": "$color:start_window_background", + "exported": true, + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ] + } + ], + } +} \ No newline at end of file diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/resources/base/element/color.json b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/resources/base/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..0d98b5c17780f121191f2768bdf0cd0bc6e9b9e7 --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/resources/base/element/color.json @@ -0,0 +1,28 @@ +{ + "color": [ + { + "name": "start_window_background", + "value": "#FFFFFF" + }, + { + "name": "button_background", + "value": "#FFFFFF" + }, + { + "name": "homepage_background", + "value": "#F1F3F5" + }, + { + "name": "title_color", + "value": "#000000" + }, + { + "name": "button_color", + "value": "#007DFF" + }, + { + "name": "divider_color", + "value": "#182431" + } + ] +} \ No newline at end of file diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/resources/base/element/float.json b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/resources/base/element/float.json new file mode 100644 index 0000000000000000000000000000000000000000..9dbe4cf7ee7fd4fc771a44ede454e93f6555caa2 --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/resources/base/element/float.json @@ -0,0 +1,44 @@ +{ + "float": [ + { + "name": "font_size", + "value": "20vp" + }, + { + "name": "button_height", + "value": "50vp" + }, + { + "name": "button_margin_1", + "value": "30vp" + }, + { + "name": "button_margin_2", + "value": "10vp" + }, + { + "name": "image_margin_1", + "value": "30vp" + }, + { + "name": "set_row_height", + "value": "40vp" + }, + { + "name": "set_row_margin_top", + "value": "8vp" + }, + { + "name": "button_margin_bottom", + "value": "12vp" + }, + { + "name": "index_button_height", + "value": "40vp" + }, + { + "name": "index_column_height", + "value": "200vp" + } + ] +} \ No newline at end of file diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/resources/base/element/string.json b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..80997951e39aff74dc45094cc68c03e91eba7706 --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/resources/base/element/string.json @@ -0,0 +1,64 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "This module template implements List functions." + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "AVCodec" + }, + { + "name": "ability_desc", + "value": "This ability loads ListPage" + }, + { + "name": "reason", + "value": "label" + }, + { + "name": "playing", + "value": "playing" + }, + { + "name": "play", + "value": "play" + }, + { + "name": "alert", + "value": "None video selected" + }, + { + "name": "alert1", + "value": "This device camera does not support this type of video stream, it will switch to the default configuration" + }, + { + "name": "record", + "value": "record" + }, + { + "name": "saveButtonNote", + "value": "Allow AVCodecVideo to save captured video to gallery?" + }, + { + "name": "saveButtonCancel", + "value": "Cancel" + }, + { + "name": "saveButtonTitle", + "value": "Confirm the video storage location" + }, + { + "name": "full_width", + "value": "100%" + }, + { + "name": "full_height", + "value": "100%" + } + ] +} \ No newline at end of file diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/resources/base/media/full.png b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/resources/base/media/full.png new file mode 100644 index 0000000000000000000000000000000000000000..cb2367f53dcce6ef769917447aed7783e8d5b3cc Binary files /dev/null and b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/resources/base/media/full.png differ diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/resources/base/media/icon.png b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/resources/base/media/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..8a354ba394b7575c510700847d6473ecd0b1e740 Binary files /dev/null and b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/resources/base/media/icon.png differ diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/resources/base/media/setting.png b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/resources/base/media/setting.png new file mode 100644 index 0000000000000000000000000000000000000000..9e8dd39f05f6572ddf85cd9984f17e5ddd4eeb60 Binary files /dev/null and b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/resources/base/media/setting.png differ diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/resources/base/profile/main_pages.json b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/resources/base/profile/main_pages.json new file mode 100644 index 0000000000000000000000000000000000000000..55c3f007f87b7ce5206d325f968cc56f2f79441f --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/resources/base/profile/main_pages.json @@ -0,0 +1,5 @@ +{ + "src": [ + "pages/Index" + ] +} \ No newline at end of file diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/resources/en_US/element/string.json b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/resources/en_US/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..2128c8d33bd5b565b2d6dc91887bc7297a55a564 --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/resources/en_US/element/string.json @@ -0,0 +1,60 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "This module template implements List functions." + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "AVCodec" + }, + { + "name": "reason", + "value": "label" + }, + { + "name": "playing", + "value": "playing" + }, + { + "name": "play", + "value": "play" + }, + { + "name": "alert", + "value": "None video selected" + }, + { + "name": "alert1", + "value": "This device camera does not support this type of video stream, it will switch to the default configuration" + }, + { + "name": "record", + "value": "record" + }, + { + "name": "saveButtonNote", + "value": "Allow AVCodecVideo to save captured video to gallery?" + }, + { + "name": "saveButtonCancel", + "value": "Cancel" + }, + { + "name": "saveButtonTitle", + "value": "Confirm the video storage location" + }, + { + "name": "full_width", + "value": "100%" + }, + { + "name": "full_height", + "value": "100%" + } + ] +} \ No newline at end of file diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/resources/zh_CN/element/string.json b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/resources/zh_CN/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..f12ac6d66fc83f474254454f627a3be5802d0287 --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/main/resources/zh_CN/element/string.json @@ -0,0 +1,60 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "该模板实现了列表页的功能" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "AVCodec" + }, + { + "name": "reason", + "value": "label" + }, + { + "name": "playing", + "value": "重新选择资源(Release后" + }, + { + "name": "play", + "value": "初始化资源" + }, + { + "name": "alert", + "value": "未选择视频!" + }, + { + "name": "alert1", + "value": "本设备相机不支持此类型录像流,将切换至默认配置" + }, + { + "name": "record", + "value": "录制" + }, + { + "name": "saveButtonNote", + "value": "是否允许AVCodecVideo保存拍摄的视频到图库?" + }, + { + "name": "saveButtonCancel", + "value": "取消" + }, + { + "name": "saveButtonTitle", + "value": "视频保存位置确认" + }, + { + "name": "full_width", + "value": "100%" + }, + { + "name": "full_height", + "value": "100%" + } + ] +} \ No newline at end of file diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/ohosTest/ets/test/Ability.test.ets b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/ohosTest/ets/test/Ability.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..d3e8a2d54fd2e7a6b604ebc73a82762b6b15349a --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/ohosTest/ets/test/Ability.test.ets @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'; +import { Driver, ON } from '@ohos.UiTest'; +import AbilityDelegatorRegistry from '@ohos.app.ability.abilityDelegatorRegistry'; + +export default function abilityTest() { + const TAG = '[Sample_LowPowerAVSink]'; + const DOMAIN = 0xF811; + const driver = Driver.create(); + const abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator(); + const bundleName = AbilityDelegatorRegistry.getArguments().bundleName; + + describe('ActsAbilityTest', () => { + + // Defines a test suite. Two parameters are supported: test suite name and test suite function. + beforeAll(() => { + // Presets an action, which is performed only once before all test cases of the test suite start. + // This API supports only one parameter: preset action function. + }) + beforeEach(() => { + // Presets an action, which is performed before each unit test case starts. + // The number of execution times is the same as the number of test cases defined by **it**. + // This API supports only one parameter: preset action function. + }) + afterEach(() => { + // Presets a clear action, which is performed after each unit test case ends. + // The number of execution times is the same as the number of test cases defined by **it**. + // This API supports only one parameter: clear action function. + }) + afterAll(() => { + // Presets a clear action, which is performed after all test cases of the test suite end. + // This API supports only one parameter: clear action function. + }) + + + /** + * 打开应用 + */ + it('StartAbility_001', 0, async (done: Function) => { + console.info(TAG, 'StartAbility_001 begin'); + + try { + await abilityDelegator.startAbility({ + bundleName: bundleName, + abilityName: 'EntryAbility' + }); + } catch (exception) { + hilog.error(DOMAIN, TAG, `StartAbility_001 exception = ${JSON.stringify(exception)}`); + expect().assertFail(); + } + await driver.delayMs(3000); + done(); + console.info(TAG, 'StartAbility_001 end'); + }) + + /** + * 播放、暂停、继续 + */ + it('Play_001', 0, async (done: Function) => { + hilog.info(DOMAIN, TAG, 'Play_001 begin'); + + await driver.delayMs(3000); + + // 点播放 + await driver.assertComponentExist(ON.id('Start')); + let stack = await driver.findComponent(ON.id('Start')); + await stack.click(); + await driver.delayMs(3000); + + // 暂停 + await driver.assertComponentExist(ON.id('Pause')); + let pause = await driver.findComponent(ON.id('Pause')); + await pause.click(); + await driver.delayMs(3000); + + // 继续 + await driver.assertComponentExist(ON.id('Pause')); + let resume = await driver.findComponent(ON.id('Pause')); + await resume.click(); + await driver.delayMs(3000); + + done(); + hilog.info(DOMAIN, TAG, 'Play_001 end'); + }) + + /** + * 暂停并退出 + */ + it('Exit_001', 0, async (done: Function) => { + hilog.info(DOMAIN, TAG, 'Exit_001 begin'); + + // 暂停 + await driver.delayMs(8000); + await driver.assertComponentExist(ON.id('Reset')); + let reset = await driver.findComponent(ON.id('Reset')); + await reset.click(); + await driver.delayMs(2000); + + await driver.assertComponentExist(ON.id('Release')); + let release = await driver.findComponent(ON.id('Release')); + await release.click(); + await driver.delayMs(2000); + + done(); + hilog.info(DOMAIN, TAG, 'Exit_001 end'); + }) + }) +} \ No newline at end of file diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/ohosTest/ets/test/List.test.ets b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/ohosTest/ets/test/List.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..c64e0b06938d246ce044186d4b2d02b500a89e14 --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/ohosTest/ets/test/List.test.ets @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import abilityTest from './Ability.test'; + +export default function testsuite() { + abilityTest(); +} \ No newline at end of file diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/ohosTest/module.json5 b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/ohosTest/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..8825ebe3b87a1cfae3f6acf12444d808395c4145 --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/ohosTest/module.json5 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "module": { + "name": "entry_test", + "type": "feature", + "deviceTypes": [ + "default", + "tablet" + ], + "deliveryWithInstall": true, + "installationFree": false + } +} \ No newline at end of file diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/ohosTest/resources/base/element/color.json b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/ohosTest/resources/base/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..3c712962da3c2751c2b9ddb53559afcbd2b54a02 --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/ohosTest/resources/base/element/color.json @@ -0,0 +1,8 @@ +{ + "color": [ + { + "name": "start_window_background", + "value": "#FFFFFF" + } + ] +} \ No newline at end of file diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/ohosTest/resources/base/element/string.json b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/ohosTest/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..65d8fa5a7cf54aa3943dcd0214f58d1771bc1f6c --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/ohosTest/resources/base/element/string.json @@ -0,0 +1,16 @@ +{ + "string": [ + { + "name": "module_test_desc", + "value": "test ability description" + }, + { + "name": "TestAbility_desc", + "value": "the test ability" + }, + { + "name": "TestAbility_label", + "value": "test label" + } + ] +} \ No newline at end of file diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/ohosTest/resources/base/media/icon.png b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/ohosTest/resources/base/media/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c Binary files /dev/null and b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/ohosTest/resources/base/media/icon.png differ diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/ohosTest/resources/base/profile/test_pages.json b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/ohosTest/resources/base/profile/test_pages.json new file mode 100644 index 0000000000000000000000000000000000000000..b7e7343cacb32ce982a45e76daad86e435e054fe --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/entry/src/ohosTest/resources/base/profile/test_pages.json @@ -0,0 +1,5 @@ +{ + "src": [ + "testability/pages/Index" + ] +} diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/hvigor/hvigor-config.json5 b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/hvigor/hvigor-config.json5 new file mode 100644 index 0000000000000000000000000000000000000000..f70ecd4112d94f9aa555adf898d53f18bf58f3e9 --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/hvigor/hvigor-config.json5 @@ -0,0 +1,5 @@ +{ + "modelVersion": "5.0.0", + "dependencies": { + } +} \ No newline at end of file diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/hvigor/hvigor-wrapper.js b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/hvigor/hvigor-wrapper.js new file mode 100644 index 0000000000000000000000000000000000000000..372eae8eb4a124095936f9cd78df5c6756746f3f --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/hvigor/hvigor-wrapper.js @@ -0,0 +1 @@ +"use strict";var u=require("path"),D=require("os"),e=require("fs"),t=require("crypto"),r=require("child_process"),n="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},i={},C={},F=n&&n.__importDefault||function(u){return u&&u.__esModule?u:{default:u}};Object.defineProperty(C,"__esModule",{value:!0}),C.maxPathLength=C.isMac=C.isLinux=C.isWindows=void 0;const E=F(D),A="Windows_NT",o="Darwin";function a(){return E.default.type()===A}function c(){return E.default.type()===o}C.isWindows=a,C.isLinux=function(){return"Linux"===E.default.type()},C.isMac=c,C.maxPathLength=function(){return c()?1016:a()?259:4095},function(e){var t=n&&n.__createBinding||(Object.create?function(u,D,e,t){void 0===t&&(t=e);var r=Object.getOwnPropertyDescriptor(D,e);r&&!("get"in r?!D.__esModule:r.writable||r.configurable)||(r={enumerable:!0,get:function(){return D[e]}}),Object.defineProperty(u,t,r)}:function(u,D,e,t){void 0===t&&(t=e),u[t]=D[e]}),r=n&&n.__setModuleDefault||(Object.create?function(u,D){Object.defineProperty(u,"default",{enumerable:!0,value:D})}:function(u,D){u.default=D}),i=n&&n.__importStar||function(u){if(u&&u.__esModule)return u;var D={};if(null!=u)for(var e in u)"default"!==e&&Object.prototype.hasOwnProperty.call(u,e)&&t(D,u,e);return r(D,u),D};Object.defineProperty(e,"__esModule",{value:!0}),e.WORK_SPACE=e.HVIGOR_PROJECT_WRAPPER_HOME=e.HVIGOR_PROJECT_ROOT_DIR=e.HVIGOR_PROJECT_CACHES_HOME=e.HVIGOR_PNPM_STORE_PATH=e.HVIGOR_WRAPPER_PNPM_SCRIPT_PATH=e.PROJECT_CACHES=e.HVIGOR_WRAPPER_TOOLS_HOME=e.HVIGOR_USER_HOME=e.DEFAULT_PACKAGE_JSON=e.DEFAULT_HVIGOR_CONFIG_JSON_FILE_NAME=e.PNPM=e.HVIGOR=e.NPM_TOOL=e.PNPM_TOOL=e.HVIGOR_ENGINE_PACKAGE_NAME=void 0;const F=i(D),E=i(u),A=C;e.HVIGOR_ENGINE_PACKAGE_NAME="@ohos/hvigor",e.PNPM_TOOL=(0,A.isWindows)()?"pnpm.cmd":"pnpm",e.NPM_TOOL=(0,A.isWindows)()?"npm.cmd":"npm",e.HVIGOR="hvigor",e.PNPM="pnpm",e.DEFAULT_HVIGOR_CONFIG_JSON_FILE_NAME="hvigor-config.json5",e.DEFAULT_PACKAGE_JSON="package.json",e.HVIGOR_USER_HOME=E.resolve(F.homedir(),".hvigor"),e.HVIGOR_WRAPPER_TOOLS_HOME=E.resolve(e.HVIGOR_USER_HOME,"wrapper","tools"),e.PROJECT_CACHES="project_caches",e.HVIGOR_WRAPPER_PNPM_SCRIPT_PATH=E.resolve(e.HVIGOR_WRAPPER_TOOLS_HOME,"node_modules",".bin",e.PNPM_TOOL),e.HVIGOR_PNPM_STORE_PATH=E.resolve(e.HVIGOR_USER_HOME,"caches"),e.HVIGOR_PROJECT_CACHES_HOME=E.resolve(e.HVIGOR_USER_HOME,e.PROJECT_CACHES),e.HVIGOR_PROJECT_ROOT_DIR=process.cwd(),e.HVIGOR_PROJECT_WRAPPER_HOME=E.resolve(e.HVIGOR_PROJECT_ROOT_DIR,e.HVIGOR),e.WORK_SPACE="workspace"}(i);var s={},l={};Object.defineProperty(l,"__esModule",{value:!0}),l.logInfoPrintConsole=l.logErrorAndExit=void 0,l.logErrorAndExit=function(u){u instanceof Error?console.error(u.message):console.error(u),process.exit(-1)},l.logInfoPrintConsole=function(u){console.log(u)};var B=n&&n.__createBinding||(Object.create?function(u,D,e,t){void 0===t&&(t=e);var r=Object.getOwnPropertyDescriptor(D,e);r&&!("get"in r?!D.__esModule:r.writable||r.configurable)||(r={enumerable:!0,get:function(){return D[e]}}),Object.defineProperty(u,t,r)}:function(u,D,e,t){void 0===t&&(t=e),u[t]=D[e]}),d=n&&n.__setModuleDefault||(Object.create?function(u,D){Object.defineProperty(u,"default",{enumerable:!0,value:D})}:function(u,D){u.default=D}),f=n&&n.__importStar||function(u){if(u&&u.__esModule)return u;var D={};if(null!=u)for(var e in u)"default"!==e&&Object.prototype.hasOwnProperty.call(u,e)&&B(D,u,e);return d(D,u),D};Object.defineProperty(s,"__esModule",{value:!0});var _=s.executeBuild=void 0;const p=f(e),O=f(u),h=l;_=s.executeBuild=function(u){const D=O.resolve(u,"node_modules","@ohos","hvigor","bin","hvigor.js");try{const u=p.realpathSync(D);require(u)}catch(e){(0,h.logErrorAndExit)(`Error: ENOENT: no such file ${D},delete ${u} and retry.`)}};var P={},v={};!function(u){var D=n&&n.__importDefault||function(u){return u&&u.__esModule?u:{default:u}};Object.defineProperty(u,"__esModule",{value:!0}),u.hashFile=u.hash=u.createHash=void 0;const r=D(t),i=D(e);u.createHash=(u="MD5")=>r.default.createHash(u);u.hash=(D,e)=>(0,u.createHash)(e).update(D).digest("hex");u.hashFile=(D,e)=>{if(i.default.existsSync(D))return(0,u.hash)(i.default.readFileSync(D,"utf-8"),e)}}(v);var g={},m={},R={};Object.defineProperty(R,"__esModule",{value:!0}),R.Unicode=void 0;class y{}R.Unicode=y,y.SPACE_SEPARATOR=/[\u1680\u2000-\u200A\u202F\u205F\u3000]/,y.ID_START=/[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u0860-\u086A\u08A0-\u08B4\u08B6-\u08BD\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u09FC\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C80\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D54-\u0D56\u0D5F-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u1884\u1887-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1C80-\u1C88\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312E\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FEA\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AE\uA7B0-\uA7B7\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA8FD\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDE80-\uDE9C\uDEA0-\uDED0\uDF00-\uDF1F\uDF2D-\uDF4A\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCB0-\uDCD3\uDCD8-\uDCFB\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE4\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2]|\uD804[\uDC03-\uDC37\uDC83-\uDCAF\uDCD0-\uDCE8\uDD03-\uDD26\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE2B\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEDE\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF50\uDF5D-\uDF61]|\uD805[\uDC00-\uDC34\uDC47-\uDC4A\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDD80-\uDDAE\uDDD8-\uDDDB\uDE00-\uDE2F\uDE44\uDE80-\uDEAA\uDF00-\uDF19]|\uD806[\uDCA0-\uDCDF\uDCFF\uDE00\uDE0B-\uDE32\uDE3A\uDE50\uDE5C-\uDE83\uDE86-\uDE89\uDEC0-\uDEF8]|\uD807[\uDC00-\uDC08\uDC0A-\uDC2E\uDC40\uDC72-\uDC8F\uDD00-\uDD06\uDD08\uDD09\uDD0B-\uDD30\uDD46]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD81C-\uD820\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50\uDF93-\uDF9F\uDFE0\uDFE1]|\uD821[\uDC00-\uDFEC]|\uD822[\uDC00-\uDEF2]|\uD82C[\uDC00-\uDD1E\uDD70-\uDEFB]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB]|\uD83A[\uDC00-\uDCC4\uDD00-\uDD43]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|\uD87E[\uDC00-\uDE1D]/,y.ID_CONTINUE=/[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u0800-\u082D\u0840-\u085B\u0860-\u086A\u08A0-\u08B4\u08B6-\u08BD\u08D4-\u08E1\u08E3-\u0963\u0966-\u096F\u0971-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09F1\u09FC\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AEF\u0AF9-\u0AFF\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BEF\u0C00-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58-\u0C5A\u0C60-\u0C63\u0C66-\u0C6F\u0C80-\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2\u0D00-\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D44\u0D46-\u0D48\u0D4A-\u0D4E\u0D54-\u0D57\u0D5F-\u0D63\u0D66-\u0D6F\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DE6-\u0DEF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E4E\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F47\u0F49-\u0F6C\u0F71-\u0F84\u0F86-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1049\u1050-\u109D\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135D-\u135F\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1877\u1880-\u18AA\u18B0-\u18F5\u1900-\u191E\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19D9\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1AB0-\u1ABD\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1C80-\u1C88\u1CD0-\u1CD2\u1CD4-\u1CF9\u1D00-\u1DF9\u1DFB-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u203F\u2040\u2054\u2071\u207F\u2090-\u209C\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D7F-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u2E2F\u3005-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099\u309A\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312E\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FEA\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66F\uA674-\uA67D\uA67F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AE\uA7B0-\uA7B7\uA7F7-\uA827\uA840-\uA873\uA880-\uA8C5\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA8FD\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uA9E0-\uA9FE\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABEA\uABEC\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE00-\uFE0F\uFE20-\uFE2F\uFE33\uFE34\uFE4D-\uFE4F\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDDFD\uDE80-\uDE9C\uDEA0-\uDED0\uDEE0\uDF00-\uDF1F\uDF2D-\uDF4A\uDF50-\uDF7A\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCA0-\uDCA9\uDCB0-\uDCD3\uDCD8-\uDCFB\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00-\uDE03\uDE05\uDE06\uDE0C-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE38-\uDE3A\uDE3F\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE6\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2]|\uD804[\uDC00-\uDC46\uDC66-\uDC6F\uDC7F-\uDCBA\uDCD0-\uDCE8\uDCF0-\uDCF9\uDD00-\uDD34\uDD36-\uDD3F\uDD50-\uDD73\uDD76\uDD80-\uDDC4\uDDCA-\uDDCC\uDDD0-\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE37\uDE3E\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEEA\uDEF0-\uDEF9\uDF00-\uDF03\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3C-\uDF44\uDF47\uDF48\uDF4B-\uDF4D\uDF50\uDF57\uDF5D-\uDF63\uDF66-\uDF6C\uDF70-\uDF74]|\uD805[\uDC00-\uDC4A\uDC50-\uDC59\uDC80-\uDCC5\uDCC7\uDCD0-\uDCD9\uDD80-\uDDB5\uDDB8-\uDDC0\uDDD8-\uDDDD\uDE00-\uDE40\uDE44\uDE50-\uDE59\uDE80-\uDEB7\uDEC0-\uDEC9\uDF00-\uDF19\uDF1D-\uDF2B\uDF30-\uDF39]|\uD806[\uDCA0-\uDCE9\uDCFF\uDE00-\uDE3E\uDE47\uDE50-\uDE83\uDE86-\uDE99\uDEC0-\uDEF8]|\uD807[\uDC00-\uDC08\uDC0A-\uDC36\uDC38-\uDC40\uDC50-\uDC59\uDC72-\uDC8F\uDC92-\uDCA7\uDCA9-\uDCB6\uDD00-\uDD06\uDD08\uDD09\uDD0B-\uDD36\uDD3A\uDD3C\uDD3D\uDD3F-\uDD47\uDD50-\uDD59]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD81C-\uD820\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDE60-\uDE69\uDED0-\uDEED\uDEF0-\uDEF4\uDF00-\uDF36\uDF40-\uDF43\uDF50-\uDF59\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50-\uDF7E\uDF8F-\uDF9F\uDFE0\uDFE1]|\uD821[\uDC00-\uDFEC]|\uD822[\uDC00-\uDEF2]|\uD82C[\uDC00-\uDD1E\uDD70-\uDEFB]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99\uDC9D\uDC9E]|\uD834[\uDD65-\uDD69\uDD6D-\uDD72\uDD7B-\uDD82\uDD85-\uDD8B\uDDAA-\uDDAD\uDE42-\uDE44]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB\uDFCE-\uDFFF]|\uD836[\uDE00-\uDE36\uDE3B-\uDE6C\uDE75\uDE84\uDE9B-\uDE9F\uDEA1-\uDEAF]|\uD838[\uDC00-\uDC06\uDC08-\uDC18\uDC1B-\uDC21\uDC23\uDC24\uDC26-\uDC2A]|\uD83A[\uDC00-\uDCC4\uDCD0-\uDCD6\uDD00-\uDD4A\uDD50-\uDD59]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|\uD87E[\uDC00-\uDE1D]|\uDB40[\uDD00-\uDDEF]/,Object.defineProperty(m,"__esModule",{value:!0}),m.JudgeUtil=void 0;const I=R;m.JudgeUtil=class{static isIgnoreChar(u){return"string"==typeof u&&("\t"===u||"\v"===u||"\f"===u||" "===u||" "===u||"\ufeff"===u||"\n"===u||"\r"===u||"\u2028"===u||"\u2029"===u)}static isSpaceSeparator(u){return"string"==typeof u&&I.Unicode.SPACE_SEPARATOR.test(u)}static isIdStartChar(u){return"string"==typeof u&&(u>="a"&&u<="z"||u>="A"&&u<="Z"||"$"===u||"_"===u||I.Unicode.ID_START.test(u))}static isIdContinueChar(u){return"string"==typeof u&&(u>="a"&&u<="z"||u>="A"&&u<="Z"||u>="0"&&u<="9"||"$"===u||"_"===u||"‌"===u||"‍"===u||I.Unicode.ID_CONTINUE.test(u))}static isDigitWithoutZero(u){return/[1-9]/.test(u)}static isDigit(u){return"string"==typeof u&&/[0-9]/.test(u)}static isHexDigit(u){return"string"==typeof u&&/[0-9A-Fa-f]/.test(u)}};var N=n&&n.__importDefault||function(u){return u&&u.__esModule?u:{default:u}};Object.defineProperty(g,"__esModule",{value:!0}),g.parseJsonText=g.parseJsonFile=void 0;const b=N(e),S=N(D),w=N(u),H=m;var x;!function(u){u[u.Char=0]="Char",u[u.EOF=1]="EOF",u[u.Identifier=2]="Identifier"}(x||(x={}));let M,T,V,G,j,J,W="start",U=[],L=0,$=1,k=0,K=!1,z="default",q="'",Z=1;function X(u,D=!1){T=String(u),W="start",U=[],L=0,$=1,k=0,G=void 0,K=D;do{M=Q(),nu[W]()}while("eof"!==M.type);return G}function Q(){for(z="default",j="",q="'",Z=1;;){J=Y();const u=Du[z]();if(u)return u}}function Y(){if(T[L])return String.fromCodePoint(T.codePointAt(L))}function uu(){const u=Y();return"\n"===u?($++,k=0):u?k+=u.length:k++,u&&(L+=u.length),u}g.parseJsonFile=function(u,D=!1,e="utf-8"){const t=b.default.readFileSync(w.default.resolve(u),{encoding:e});try{return X(t,D)}catch(D){if(D instanceof SyntaxError){const e=D.message.split("at");if(2===e.length)throw new Error(`${e[0].trim()}${S.default.EOL}\t at ${u}:${e[1].trim()}`)}throw new Error(`${u} is not in valid JSON/JSON5 format.`)}},g.parseJsonText=X;const Du={default(){switch(J){case"/":return uu(),void(z="comment");case void 0:return uu(),eu("eof")}if(!H.JudgeUtil.isIgnoreChar(J)&&!H.JudgeUtil.isSpaceSeparator(J))return Du[W]();uu()},start(){z="value"},beforePropertyName(){switch(J){case"$":case"_":return j=uu(),void(z="identifierName");case"\\":return uu(),void(z="identifierNameStartEscape");case"}":return eu("punctuator",uu());case'"':case"'":return q=J,uu(),void(z="string")}if(H.JudgeUtil.isIdStartChar(J))return j+=uu(),void(z="identifierName");throw Eu(x.Char,uu())},afterPropertyName(){if(":"===J)return eu("punctuator",uu());throw Eu(x.Char,uu())},beforePropertyValue(){z="value"},afterPropertyValue(){switch(J){case",":case"}":return eu("punctuator",uu())}throw Eu(x.Char,uu())},beforeArrayValue(){if("]"===J)return eu("punctuator",uu());z="value"},afterArrayValue(){switch(J){case",":case"]":return eu("punctuator",uu())}throw Eu(x.Char,uu())},end(){throw Eu(x.Char,uu())},comment(){switch(J){case"*":return uu(),void(z="multiLineComment");case"/":return uu(),void(z="singleLineComment")}throw Eu(x.Char,uu())},multiLineComment(){switch(J){case"*":return uu(),void(z="multiLineCommentAsterisk");case void 0:throw Eu(x.Char,uu())}uu()},multiLineCommentAsterisk(){switch(J){case"*":return void uu();case"/":return uu(),void(z="default");case void 0:throw Eu(x.Char,uu())}uu(),z="multiLineComment"},singleLineComment(){switch(J){case"\n":case"\r":case"\u2028":case"\u2029":return uu(),void(z="default");case void 0:return uu(),eu("eof")}uu()},value(){switch(J){case"{":case"[":return eu("punctuator",uu());case"n":return uu(),tu("ull"),eu("null",null);case"t":return uu(),tu("rue"),eu("boolean",!0);case"f":return uu(),tu("alse"),eu("boolean",!1);case"-":case"+":return"-"===uu()&&(Z=-1),void(z="numerical");case".":case"0":case"I":case"N":return void(z="numerical");case'"':case"'":return q=J,uu(),j="",void(z="string")}if(void 0===J||!H.JudgeUtil.isDigitWithoutZero(J))throw Eu(x.Char,uu());z="numerical"},numerical(){switch(J){case".":return j=uu(),void(z="decimalPointLeading");case"0":return j=uu(),void(z="zero");case"I":return uu(),tu("nfinity"),eu("numeric",Z*(1/0));case"N":return uu(),tu("aN"),eu("numeric",NaN)}if(void 0!==J&&H.JudgeUtil.isDigitWithoutZero(J))return j=uu(),void(z="decimalInteger");throw Eu(x.Char,uu())},zero(){switch(J){case".":case"e":case"E":return void(z="decimal");case"x":case"X":return j+=uu(),void(z="hexadecimal")}return eu("numeric",0)},decimalInteger(){switch(J){case".":case"e":case"E":return void(z="decimal")}if(!H.JudgeUtil.isDigit(J))return eu("numeric",Z*Number(j));j+=uu()},decimal(){switch(J){case".":j+=uu(),z="decimalFraction";break;case"e":case"E":j+=uu(),z="decimalExponent"}},decimalPointLeading(){if(H.JudgeUtil.isDigit(J))return j+=uu(),void(z="decimalFraction");throw Eu(x.Char,uu())},decimalFraction(){switch(J){case"e":case"E":return j+=uu(),void(z="decimalExponent")}if(!H.JudgeUtil.isDigit(J))return eu("numeric",Z*Number(j));j+=uu()},decimalExponent(){switch(J){case"+":case"-":return j+=uu(),void(z="decimalExponentSign")}if(H.JudgeUtil.isDigit(J))return j+=uu(),void(z="decimalExponentInteger");throw Eu(x.Char,uu())},decimalExponentSign(){if(H.JudgeUtil.isDigit(J))return j+=uu(),void(z="decimalExponentInteger");throw Eu(x.Char,uu())},decimalExponentInteger(){if(!H.JudgeUtil.isDigit(J))return eu("numeric",Z*Number(j));j+=uu()},hexadecimal(){if(H.JudgeUtil.isHexDigit(J))return j+=uu(),void(z="hexadecimalInteger");throw Eu(x.Char,uu())},hexadecimalInteger(){if(!H.JudgeUtil.isHexDigit(J))return eu("numeric",Z*Number(j));j+=uu()},identifierNameStartEscape(){if("u"!==J)throw Eu(x.Char,uu());uu();const u=ru();switch(u){case"$":case"_":break;default:if(!H.JudgeUtil.isIdStartChar(u))throw Eu(x.Identifier)}j+=u,z="identifierName"},identifierName(){switch(J){case"$":case"_":case"‌":case"‍":return void(j+=uu());case"\\":return uu(),void(z="identifierNameEscape")}if(!H.JudgeUtil.isIdContinueChar(J))return eu("identifier",j);j+=uu()},identifierNameEscape(){if("u"!==J)throw Eu(x.Char,uu());uu();const u=ru();switch(u){case"$":case"_":case"‌":case"‍":break;default:if(!H.JudgeUtil.isIdContinueChar(u))throw Eu(x.Identifier)}j+=u,z="identifierName"},string(){switch(J){case"\\":return uu(),void(j+=function(){const u=Y(),D=function(){switch(Y()){case"b":return uu(),"\b";case"f":return uu(),"\f";case"n":return uu(),"\n";case"r":return uu(),"\r";case"t":return uu(),"\t";case"v":return uu(),"\v"}return}();if(D)return D;switch(u){case"0":if(uu(),H.JudgeUtil.isDigit(Y()))throw Eu(x.Char,uu());return"\0";case"x":return uu(),function(){let u="",D=Y();if(!H.JudgeUtil.isHexDigit(D))throw Eu(x.Char,uu());if(u+=uu(),D=Y(),!H.JudgeUtil.isHexDigit(D))throw Eu(x.Char,uu());return u+=uu(),String.fromCodePoint(parseInt(u,16))}();case"u":return uu(),ru();case"\n":case"\u2028":case"\u2029":return uu(),"";case"\r":return uu(),"\n"===Y()&&uu(),""}if(void 0===u||H.JudgeUtil.isDigitWithoutZero(u))throw Eu(x.Char,uu());return uu()}());case'"':case"'":if(J===q){const u=eu("string",j);return uu(),u}return void(j+=uu());case"\n":case"\r":case void 0:throw Eu(x.Char,uu());case"\u2028":case"\u2029":!function(u){console.warn(`JSON5: '${Fu(u)}' in strings is not valid ECMAScript; consider escaping.`)}(J)}j+=uu()}};function eu(u,D){return{type:u,value:D,line:$,column:k}}function tu(u){for(const D of u){if(Y()!==D)throw Eu(x.Char,uu());uu()}}function ru(){let u="",D=4;for(;D-- >0;){const D=Y();if(!H.JudgeUtil.isHexDigit(D))throw Eu(x.Char,uu());u+=uu()}return String.fromCodePoint(parseInt(u,16))}const nu={start(){if("eof"===M.type)throw Eu(x.EOF);iu()},beforePropertyName(){switch(M.type){case"identifier":case"string":return V=M.value,void(W="afterPropertyName");case"punctuator":return void Cu();case"eof":throw Eu(x.EOF)}},afterPropertyName(){if("eof"===M.type)throw Eu(x.EOF);W="beforePropertyValue"},beforePropertyValue(){if("eof"===M.type)throw Eu(x.EOF);iu()},afterPropertyValue(){if("eof"===M.type)throw Eu(x.EOF);switch(M.value){case",":return void(W="beforePropertyName");case"}":Cu()}},beforeArrayValue(){if("eof"===M.type)throw Eu(x.EOF);"punctuator"!==M.type||"]"!==M.value?iu():Cu()},afterArrayValue(){if("eof"===M.type)throw Eu(x.EOF);switch(M.value){case",":return void(W="beforeArrayValue");case"]":Cu()}},end(){}};function iu(){const u=function(){let u;switch(M.type){case"punctuator":switch(M.value){case"{":u={};break;case"[":u=[]}break;case"null":case"boolean":case"numeric":case"string":u=M.value}return u}();if(K&&"object"==typeof u&&(u._line=$,u._column=k),void 0===G)G=u;else{const D=U[U.length-1];Array.isArray(D)?K&&"object"!=typeof u?D.push({value:u,_line:$,_column:k}):D.push(u):D[V]=K&&"object"!=typeof u?{value:u,_line:$,_column:k}:u}!function(u){if(u&&"object"==typeof u)U.push(u),W=Array.isArray(u)?"beforeArrayValue":"beforePropertyName";else{const u=U[U.length-1];W=u?Array.isArray(u)?"afterArrayValue":"afterPropertyValue":"end"}}(u)}function Cu(){U.pop();const u=U[U.length-1];W=u?Array.isArray(u)?"afterArrayValue":"afterPropertyValue":"end"}function Fu(u){const D={"'":"\\'",'"':'\\"',"\\":"\\\\","\b":"\\b","\f":"\\f","\n":"\\n","\r":"\\r","\t":"\\t","\v":"\\v","\0":"\\0","\u2028":"\\u2028","\u2029":"\\u2029"};if(D[u])return D[u];if(u<" "){const D=u.charCodeAt(0).toString(16);return`\\x${`00${D}`.substring(D.length)}`}return u}function Eu(u,D){let e="";switch(u){case x.Char:e=void 0===D?`JSON5: invalid end of input at ${$}:${k}`:`JSON5: invalid character '${Fu(D)}' at ${$}:${k}`;break;case x.EOF:e=`JSON5: invalid end of input at ${$}:${k}`;break;case x.Identifier:k-=5,e=`JSON5: invalid identifier character at ${$}:${k}`}const t=new Au(e);return t.lineNumber=$,t.columnNumber=k,t}class Au extends SyntaxError{}var ou={},au=n&&n.__createBinding||(Object.create?function(u,D,e,t){void 0===t&&(t=e);var r=Object.getOwnPropertyDescriptor(D,e);r&&!("get"in r?!D.__esModule:r.writable||r.configurable)||(r={enumerable:!0,get:function(){return D[e]}}),Object.defineProperty(u,t,r)}:function(u,D,e,t){void 0===t&&(t=e),u[t]=D[e]}),cu=n&&n.__setModuleDefault||(Object.create?function(u,D){Object.defineProperty(u,"default",{enumerable:!0,value:D})}:function(u,D){u.default=D}),su=n&&n.__importStar||function(u){if(u&&u.__esModule)return u;var D={};if(null!=u)for(var e in u)"default"!==e&&Object.prototype.hasOwnProperty.call(u,e)&&au(D,u,e);return cu(D,u),D},lu=n&&n.__importDefault||function(u){return u&&u.__esModule?u:{default:u}};Object.defineProperty(ou,"__esModule",{value:!0}),ou.isFileExists=ou.offlinePluginConversion=ou.executeCommand=ou.getNpmPath=ou.hasNpmPackInPaths=void 0;const Bu=r,du=lu(e),fu=su(u),_u=i,pu=l;ou.hasNpmPackInPaths=function(u,D){try{return require.resolve(u,{paths:[...D]}),!0}catch(u){return!1}},ou.getNpmPath=function(){const u=process.execPath;return fu.join(fu.dirname(u),_u.NPM_TOOL)},ou.executeCommand=function(u,D,e){0!==(0,Bu.spawnSync)(u,D,e).status&&(0,pu.logErrorAndExit)(`Error: ${u} ${D} execute failed.See above for details.`)},ou.offlinePluginConversion=function(u,D){return D.startsWith("file:")||D.endsWith(".tgz")?fu.resolve(u,_u.HVIGOR,D.replace("file:","")):D},ou.isFileExists=function(u){return du.default.existsSync(u)&&du.default.statSync(u).isFile()};var Ou=n&&n.__createBinding||(Object.create?function(u,D,e,t){void 0===t&&(t=e);var r=Object.getOwnPropertyDescriptor(D,e);r&&!("get"in r?!D.__esModule:r.writable||r.configurable)||(r={enumerable:!0,get:function(){return D[e]}}),Object.defineProperty(u,t,r)}:function(u,D,e,t){void 0===t&&(t=e),u[t]=D[e]}),hu=n&&n.__setModuleDefault||(Object.create?function(u,D){Object.defineProperty(u,"default",{enumerable:!0,value:D})}:function(u,D){u.default=D}),Pu=n&&n.__importStar||function(u){if(u&&u.__esModule)return u;var D={};if(null!=u)for(var e in u)"default"!==e&&Object.prototype.hasOwnProperty.call(u,e)&&Ou(D,u,e);return hu(D,u),D},vu=n&&n.__importDefault||function(u){return u&&u.__esModule?u:{default:u}};Object.defineProperty(P,"__esModule",{value:!0});var gu=P.initProjectWorkSpace=void 0;const mu=Pu(e),Ru=vu(D),yu=Pu(u),Iu=v,Nu=i,bu=g,Su=l,wu=ou;let Hu,xu,Mu;function Tu(u,D,e){return void 0!==e.dependencies&&(0,wu.offlinePluginConversion)(Nu.HVIGOR_PROJECT_ROOT_DIR,D.dependencies[u])===yu.normalize(e.dependencies[u])}function Vu(){const u=yu.join(Mu,Nu.WORK_SPACE);if((0,Su.logInfoPrintConsole)("Hvigor cleaning..."),!mu.existsSync(u))return;const D=mu.readdirSync(u);if(!D||0===D.length)return;const e=yu.resolve(Mu,"node_modules","@ohos","hvigor","bin","hvigor.js");mu.existsSync(e)&&(0,wu.executeCommand)(process.argv[0],[e,"--stop-daemon"],{});try{D.forEach((D=>{mu.rmSync(yu.resolve(u,D),{recursive:!0})}))}catch(D){(0,Su.logErrorAndExit)(`The hvigor build tool cannot be installed. Please manually clear the workspace directory and synchronize the project again.\n\n Workspace Path: ${u}.`)}}gu=P.initProjectWorkSpace=function(){if(Hu=function(){const u=yu.resolve(Nu.HVIGOR_PROJECT_WRAPPER_HOME,Nu.DEFAULT_HVIGOR_CONFIG_JSON_FILE_NAME);mu.existsSync(u)||(0,Su.logErrorAndExit)(`Error: Hvigor config file ${u} does not exist.`);return(0,bu.parseJsonFile)(u)}(),Mu=function(u){let D;D=function(u){let D=u.hvigorVersion;if(D.startsWith("file:")||D.endsWith(".tgz"))return!1;const e=u.dependencies,t=Object.getOwnPropertyNames(e);for(const u of t){const D=e[u];if(D.startsWith("file:")||D.endsWith(".tgz"))return!1}if(1===t.length&&"@ohos/hvigor-ohos-plugin"===t[0])return D>"2.5.0";return!1}(u)?function(u){let D=`${Nu.HVIGOR_ENGINE_PACKAGE_NAME}@${u.hvigorVersion}`;const e=u.dependencies;if(e){Object.getOwnPropertyNames(e).sort().forEach((u=>{D+=`,${u}@${e[u]}`}))}return(0,Iu.hash)(D)}(u):(0,Iu.hash)(process.cwd());return yu.resolve(Ru.default.homedir(),".hvigor","project_caches",D)}(Hu),xu=function(){const u=yu.resolve(Mu,Nu.WORK_SPACE,Nu.DEFAULT_PACKAGE_JSON);return mu.existsSync(u)?(0,bu.parseJsonFile)(u):{dependencies:{}}}(),!(0,wu.hasNpmPackInPaths)(Nu.HVIGOR_ENGINE_PACKAGE_NAME,[yu.join(Mu,Nu.WORK_SPACE)])||(0,wu.offlinePluginConversion)(Nu.HVIGOR_PROJECT_ROOT_DIR,Hu.hvigorVersion)!==xu.dependencies[Nu.HVIGOR_ENGINE_PACKAGE_NAME]||!function(){function u(u){const D=null==u?void 0:u.dependencies;return void 0===D?0:Object.getOwnPropertyNames(D).length}const D=u(Hu),e=u(xu);if(D+1!==e)return!1;for(const u in null==Hu?void 0:Hu.dependencies)if(!(0,wu.hasNpmPackInPaths)(u,[yu.join(Mu,Nu.WORK_SPACE)])||!Tu(u,Hu,xu))return!1;return!0}()){Vu();try{!function(){(0,Su.logInfoPrintConsole)("Hvigor installing...");for(const u in Hu.dependencies)Hu.dependencies[u]&&(Hu.dependencies[u]=(0,wu.offlinePluginConversion)(Nu.HVIGOR_PROJECT_ROOT_DIR,Hu.dependencies[u]));const u={dependencies:{...Hu.dependencies}};u.dependencies[Nu.HVIGOR_ENGINE_PACKAGE_NAME]=(0,wu.offlinePluginConversion)(Nu.HVIGOR_PROJECT_ROOT_DIR,Hu.hvigorVersion);const D=yu.join(Mu,Nu.WORK_SPACE);try{mu.mkdirSync(D,{recursive:!0});const e=yu.resolve(D,Nu.DEFAULT_PACKAGE_JSON);mu.writeFileSync(e,JSON.stringify(u))}catch(u){(0,Su.logErrorAndExit)(u)}(function(){const u=["config","set","store-dir",Nu.HVIGOR_PNPM_STORE_PATH],D={cwd:yu.join(Mu,Nu.WORK_SPACE),stdio:["inherit","inherit","inherit"]};(0,wu.executeCommand)(Nu.HVIGOR_WRAPPER_PNPM_SCRIPT_PATH,u,D)})(),function(){const u=["install"],D={cwd:yu.join(Mu,Nu.WORK_SPACE),stdio:["inherit","inherit","inherit"]};(0,wu.executeCommand)(Nu.HVIGOR_WRAPPER_PNPM_SCRIPT_PATH,u,D)}(),(0,Su.logInfoPrintConsole)("Hvigor install success.")}()}catch(u){Vu()}}return Mu};var Gu={};!function(t){var C=n&&n.__createBinding||(Object.create?function(u,D,e,t){void 0===t&&(t=e);var r=Object.getOwnPropertyDescriptor(D,e);r&&!("get"in r?!D.__esModule:r.writable||r.configurable)||(r={enumerable:!0,get:function(){return D[e]}}),Object.defineProperty(u,t,r)}:function(u,D,e,t){void 0===t&&(t=e),u[t]=D[e]}),F=n&&n.__setModuleDefault||(Object.create?function(u,D){Object.defineProperty(u,"default",{enumerable:!0,value:D})}:function(u,D){u.default=D}),E=n&&n.__importStar||function(u){if(u&&u.__esModule)return u;var D={};if(null!=u)for(var e in u)"default"!==e&&Object.prototype.hasOwnProperty.call(u,e)&&C(D,u,e);return F(D,u),D},A=n&&n.__importDefault||function(u){return u&&u.__esModule?u:{default:u}};Object.defineProperty(t,"__esModule",{value:!0}),t.executeInstallPnpm=t.isPnpmInstalled=t.environmentHandler=t.checkNpmConifg=t.PNPM_VERSION=void 0;const o=r,a=E(e),c=A(D),s=E(u),B=i,d=l,f=ou;t.PNPM_VERSION="7.30.0",t.checkNpmConifg=function(){const u=s.resolve(B.HVIGOR_PROJECT_ROOT_DIR,".npmrc"),D=s.resolve(c.default.homedir(),".npmrc");if((0,f.isFileExists)(u)||(0,f.isFileExists)(D))return;const e=(0,f.getNpmPath)(),t=(0,o.spawnSync)(e,["config","get","prefix"],{cwd:B.HVIGOR_PROJECT_ROOT_DIR});if(0!==t.status||!t.stdout)return void(0,d.logErrorAndExit)("Error: The hvigor depends on the npmrc file. Configure the npmrc file first.");const r=s.resolve(`${t.stdout}`.replace(/[\r\n]/gi,""),".npmrc");(0,f.isFileExists)(r)||(0,d.logErrorAndExit)("Error: The hvigor depends on the npmrc file. Configure the npmrc file first.")},t.environmentHandler=function(){process.env["npm_config_update-notifier"]="false"},t.isPnpmInstalled=function(){return!!a.existsSync(B.HVIGOR_WRAPPER_PNPM_SCRIPT_PATH)&&(0,f.hasNpmPackInPaths)("pnpm",[B.HVIGOR_WRAPPER_TOOLS_HOME])},t.executeInstallPnpm=function(){(0,d.logInfoPrintConsole)(`Installing pnpm@${t.PNPM_VERSION}...`);const u=(0,f.getNpmPath)();!function(){const u=s.resolve(B.HVIGOR_WRAPPER_TOOLS_HOME,B.DEFAULT_PACKAGE_JSON);try{a.existsSync(B.HVIGOR_WRAPPER_TOOLS_HOME)||a.mkdirSync(B.HVIGOR_WRAPPER_TOOLS_HOME,{recursive:!0});const D={dependencies:{}};D.dependencies[B.PNPM]=t.PNPM_VERSION,a.writeFileSync(u,JSON.stringify(D))}catch(D){(0,d.logErrorAndExit)(`Error: EPERM: operation not permitted,create ${u} failed.`)}}(),(0,f.executeCommand)(u,["install","pnpm"],{cwd:B.HVIGOR_WRAPPER_TOOLS_HOME,stdio:["inherit","inherit","inherit"],env:process.env}),(0,d.logInfoPrintConsole)("Pnpm install success.")}}(Gu),function(){Gu.checkNpmConifg(),Gu.environmentHandler(),Gu.isPnpmInstalled()||Gu.executeInstallPnpm();const D=gu();_(u.join(D,i.WORK_SPACE))}(); \ No newline at end of file diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/hvigorfile.ts b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..6478186902c0c1ad7c966a929c7d6b7d8ae7a9f3 --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/hvigorfile.ts @@ -0,0 +1,2 @@ +// Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently. +export { appTasks } from '@ohos/hvigor-ohos-plugin'; \ No newline at end of file diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/oh-package-lock.json5 b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/oh-package-lock.json5 new file mode 100644 index 0000000000000000000000000000000000000000..0eb15ad13647e2b5a8027cca619f6496b59e5e3d --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/oh-package-lock.json5 @@ -0,0 +1,20 @@ +{ + "meta": { + "stableOrder": true + }, + "lockfileVersion": 3, + "ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.", + "specifiers": { + "@ohos/hypium@1.0.11": "@ohos/hypium@1.0.11" + }, + "packages": { + "@ohos/hypium@1.0.11": { + "name": "@ohos/hypium", + "version": "1.0.11", + "integrity": "sha512-KawcLnv43C3QIYv1UbDnKCFX3MohtDxGuFvzlUxT/qf2DBilR56Ws6zrj90LdH6PjloJQwOPESuBQIHBACAK7w==", + "resolved": "https://mirrors.tools.huawei.com/ohpm/@ohos/hypium/-/@ohos/hypium-1.0.11.har", + "shasum": "fa799d273fa7d921701578c5e7084849354a4af0", + "registryType": "ohpm" + } + } +} \ No newline at end of file diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/oh-package.json5 b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..aaba9ce31628886c0b1f79ce108a19cb771522be --- /dev/null +++ b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/oh-package.json5 @@ -0,0 +1,13 @@ +{ + "modelVersion": "5.0.0", + "license": "", + "devDependencies": { + "@ohos/hypium": "1.0.11" + }, + "author": "", + "name": "avcodecsample", + "description": "Please describe the basic information.", + "main": "", + "version": "1.0.0", + "dependencies": {} +} \ No newline at end of file diff --git a/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/screenshots/image-202507041445495401.png b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/screenshots/image-202507041445495401.png new file mode 100644 index 0000000000000000000000000000000000000000..91c98b538198766a6d8dd9366fed935a3a5bef9d Binary files /dev/null and b/MediaKit/LowPowerAVSInk/lowPowerAVSinkSample/screenshots/image-202507041445495401.png differ