diff --git a/code/DocsSample/Media/AVPlayer/AVPlayerNDK/.gitignore b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..d2ff20141ceed86d87c0ea5d99481973005bab2b --- /dev/null +++ b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/.gitignore @@ -0,0 +1,12 @@ +/node_modules +/oh_modules +/local.properties +/.idea +**/build +/.hvigor +.cxx +/.clangd +/.clang-format +/.clang-tidy +**/.test +/.appanalyzer \ No newline at end of file diff --git a/code/DocsSample/Media/AVPlayer/AVPlayerNDK/AppScope/app.json5 b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/AppScope/app.json5 new file mode 100644 index 0000000000000000000000000000000000000000..e3cfafdcbfa313b430369030b0feedf194c3a80c --- /dev/null +++ b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/AppScope/app.json5 @@ -0,0 +1,24 @@ +/* + * 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. + */ +{ + "app": { + "bundleName": "com.samples.AVPlayerNDKVideo", + "vendor": "example", + "versionCode": 1000000, + "versionName": "1.0.0", + "icon": "$media:layered_image", + "label": "$string:app_name" + } +} diff --git a/code/DocsSample/Media/AVPlayer/AVPlayerNDK/AppScope/resources/base/element/string.json b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/AppScope/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..85412c2d7882e6fb6372bae233c03af499d84d28 --- /dev/null +++ b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/AppScope/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "app_name", + "value": "AVPlayerNDKVideo" + } + ] +} diff --git a/code/DocsSample/Media/AVPlayer/AVPlayerNDK/AppScope/resources/base/media/background.png b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/AppScope/resources/base/media/background.png new file mode 100644 index 0000000000000000000000000000000000000000..923f2b3f27e915d6871871deea0420eb45ce102f Binary files /dev/null and b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/AppScope/resources/base/media/background.png differ diff --git a/code/DocsSample/Media/AVPlayer/AVPlayerNDK/AppScope/resources/base/media/foreground.png b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/AppScope/resources/base/media/foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..97014d3e10e5ff511409c378cd4255713aecd85f Binary files /dev/null and b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/AppScope/resources/base/media/foreground.png differ diff --git a/code/DocsSample/Media/AVPlayer/AVPlayerNDK/AppScope/resources/base/media/layered_image.json b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/AppScope/resources/base/media/layered_image.json new file mode 100644 index 0000000000000000000000000000000000000000..fb49920440fb4d246c82f9ada275e26123a2136a --- /dev/null +++ b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/AppScope/resources/base/media/layered_image.json @@ -0,0 +1,7 @@ +{ + "layered-image": + { + "background" : "$media:background", + "foreground" : "$media:foreground" + } +} \ No newline at end of file diff --git a/code/DocsSample/Media/AVPlayer/AVPlayerNDK/README.md b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/README.md new file mode 100644 index 0000000000000000000000000000000000000000..e758cfccbe2cb3f9a6b197eece21956c262b64fb --- /dev/null +++ b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/README.md @@ -0,0 +1,80 @@ +# AVPlayerNDKVideo + +## 介绍 + +本示例为媒体->Media Kit(媒体服务)->[使用AVPlayer播放视频(C/C++)](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/media/media/using-ndk-avplayer-for-video-playback.md)的配套示例工程。 + +本示例展示了如何使用AVPlayer组件完整地播放一个视频。 + +## 效果预览 + +| 播放效果 | +| -------------------------------------------- | + + +## 使用说明 + +1. 安装编译生成的hap包,并打开应用; +2. 点击播放按钮,视频正常播放; +3. 拖动视频下方的进度条,视频将从拖动结束后最近的视频帧处开始播放; +4. 点击暂停按钮,视频暂停播放,再次点击后视频恢复播放; +5. 点击视频右下角按钮,可以选择视频倍速播放的方式,视频支持以1.0、1.25、1.75、2.0倍速度进行播放。 + +## 工程目录 + +``` +AVPlayerNDKVideo +entry/src/main/ets/ +└── pages + └── Index.ets (播放界面) +entry/src/main/ +├── cpp +│ ├── types +│ │ └── libentry +│ │ └── Index.d.ts (NDK函数对应的js映射) +│ ├── CMakeLists.txt (CMake脚本) +│ └── napi_init.cpp (NDK函数) +└── resources + ├── base + │ ├── element + │ │ ├── color.json + │ │ ├── float.json + │ │ └── string.json + │ └── media + │ ├── ic_video_play.svg (播放键图片资源) + │ └── ic_video_pause.svg (暂停键图片资源) + └── rawfile + └── test1.mp4 (视频资源) +entry/src/ohosTest/ets/ +└── test + ├── Ability.test.ets (UI测试代码) + └── List.test.ets (测试套件列表) +``` + +## 相关权限 + +不涉及 + +## 依赖 + +不涉及 + +## 约束和限制 + +1. 本示例支持标准系统上运行,支持设备:RK3568; + +2. 本示例支持API15版本SDK,版本号:5.0.3.135; + +3. 本示例已支持使DevEco Studio 5.0.3 Release (构建版本:5.0.8.300,构建 2025年3月19日)编译运行 + +## 下载 + +如需单独下载本工程,执行如下命令: + +``` +git init +git config core.sparsecheckout true +echo code/DocsSample/Media/AVPlayer/AVPlayerNDKVideo/ > .git/info/sparse-checkout +git remote add origin OpenHarmony/applications_app_samples +git pull origin master +``` \ No newline at end of file diff --git a/code/DocsSample/Media/AVPlayer/AVPlayerNDK/build-profile.json5 b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..6139d47e0705a555fa752be6dc71326f0d512f89 --- /dev/null +++ b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/build-profile.json5 @@ -0,0 +1,50 @@ +/* + * 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. + */ +{ + "app": { + "products": [ + { + "name": "default", + "signingConfig": "default", + "compileSdkVersion": 15, + "targetSdkVersion": 15, + "compatibleSdkVersion": 15, + "runtimeOS": "OpenHarmony" + } + ], + "buildModeSet": [ + { + "name": "debug" + }, + { + "name": "release" + } + ] + }, + "modules": [ + { + "name": "entry", + "srcPath": "./entry", + "targets": [ + { + "name": "default", + "applyToProducts": [ + "default" + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/.gitignore b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..e2713a2779c5a3e0eb879efe6115455592caeea5 --- /dev/null +++ b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/.gitignore @@ -0,0 +1,6 @@ +/node_modules +/oh_modules +/.preview +/build +/.cxx +/.test \ No newline at end of file diff --git a/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/build-profile.json5 b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..cff3c16ef337d5ed6b207c7e28be6aad4b0dfeeb --- /dev/null +++ b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/build-profile.json5 @@ -0,0 +1,54 @@ +/* + * 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. + */ +{ + "apiType": "stageMode", + "buildOption": { + "externalNativeOptions": { + "path": "./src/main/cpp/CMakeLists.txt", + "arguments": "", + "cppFlags": "", + "abiFilters": ["arm64-v8a", "x86_64"] + } + }, + "buildOptionSet": [ + { + "name": "release", + "arkOptions": { + "obfuscation": { + "ruleOptions": { + "enable": false, + "files": [ + "./obfuscation-rules.txt" + ] + } + } + }, + "nativeLib": { + "debugSymbol": { + "strip": true, + "exclude": [] + } + } + }, + ], + "targets": [ + { + "name": "default" + }, + { + "name": "ohosTest", + } + ] +} \ No newline at end of file diff --git a/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/hvigorfile.ts b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..8774588471ede4c1563f09d9a1d22f764bb1fd9e --- /dev/null +++ b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/hvigorfile.ts @@ -0,0 +1,20 @@ +/* + * 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 { hapTasks } from '@ohos/hvigor-ohos-plugin'; + +export default { + system: hapTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ + plugins:[] /* Custom plugin to extend the functionality of Hvigor. */ +} diff --git a/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/obfuscation-rules.txt b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/obfuscation-rules.txt new file mode 100644 index 0000000000000000000000000000000000000000..272efb6ca3f240859091bbbfc7c5802d52793b0b --- /dev/null +++ b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/obfuscation-rules.txt @@ -0,0 +1,23 @@ +# Define project specific obfuscation rules here. +# You can include the obfuscation configuration files in the current module's build-profile.json5. +# +# For more details, see +# https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/source-obfuscation-V5 + +# Obfuscation options: +# -disable-obfuscation: disable all obfuscations +# -enable-property-obfuscation: obfuscate the property names +# -enable-toplevel-obfuscation: obfuscate the names in the global scope +# -compact: remove unnecessary blank spaces and all line feeds +# -remove-log: remove all console.* statements +# -print-namecache: print the name cache that contains the mapping from the old names to new names +# -apply-namecache: reuse the given cache file + +# Keep options: +# -keep-property-name: specifies property names that you want to keep +# -keep-global-name: specifies names that you want to keep in the global scope + +-enable-property-obfuscation +-enable-toplevel-obfuscation +-enable-filename-obfuscation +-enable-export-obfuscation \ No newline at end of file diff --git a/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/oh-package.json5 b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..5b21e253af246edab8b6ef4f10938f4417e8bc25 --- /dev/null +++ b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/oh-package.json5 @@ -0,0 +1,25 @@ +/* + * 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. + */ +{ + "name": "entry", + "version": "1.0.0", + "description": "Please describe the basic information.", + "main": "", + "author": "", + "license": "", + "dependencies": { + "libentry.so": "file:./src/main/cpp/types/libentry" + } +} \ No newline at end of file diff --git a/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/cpp/CMakeLists.txt b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/cpp/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..7e4f56090d549471728c04a69225ec95c90e1963 --- /dev/null +++ b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/cpp/CMakeLists.txt @@ -0,0 +1,26 @@ +# the minimum version of CMake. +cmake_minimum_required(VERSION 3.5.0) +project(AVPlayerNDK) + +set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}) + +if(DEFINED PACKAGE_FIND_FILE) + include(${PACKAGE_FIND_FILE}) +endif() + +include_directories(${NATIVERENDER_ROOT_PATH} + ${NATIVERENDER_ROOT_PATH}/include) + +add_library(entry SHARED napi_init.cpp) + +target_link_libraries(entry PUBLIC + libohaudio.so + libace_napi.z.so + libhilog_ndk.z.so + libace_ndk.z.so + libnative_window.so + libnative_drm.so + libavplayer.so + libohfileuri.so + libnative_media_core.so +) diff --git a/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/cpp/napi_init.cpp b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/cpp/napi_init.cpp new file mode 100644 index 0000000000000000000000000000000000000000..579a2ead0287075e359d8961ed763865a49c925e --- /dev/null +++ b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/cpp/napi_init.cpp @@ -0,0 +1,787 @@ +/* + * Copyright (c) 2023-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 "napi/native_api.h" +#include +#include +#include "multimedia/player_framework/avplayer_base.h" +#include "multimedia/player_framework/native_averrors.h" +#include +#include +#include + +#define LOG_MSG_TAG "AVPlayerNDK" + +#define LOG(format, ...) ((void)OH_LOG_Print(LOG_APP, LOG_INFO, 0xFF00, LOG_MSG_TAG, format, ##__VA_ARGS__)) +#define LOGE(format, ...) ((void)OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, LOG_MSG_TAG, format, ##__VA_ARGS__)) + +void OnSurfaceCreatedCB(OH_NativeXComponent *component, void *window); +void OnSurfaceDestroyedCB(OH_NativeXComponent *component, void *window); + +class SampleRenderer { +public: + SampleRenderer(std::string &id) { this->id_ = id; } + ~SampleRenderer() {} + static SampleRenderer *GetInstance(std::string &id) { + if (instance_.find(id) == instance_.end()) { + SampleRenderer *instance = new SampleRenderer(id); + instance_[id] = instance; + return instance; + } else { + return instance_[id]; + } + } + static void Release(std::string &id) { + SampleRenderer *render = SampleRenderer::GetInstance(id); + if (render != nullptr) { + instance_.erase(instance_.find(id)); + } + } + void RegisterCallback(OH_NativeXComponent *nativeXComponent) { + renderCallback_.OnSurfaceCreated = OnSurfaceCreatedCB; + renderCallback_.OnSurfaceDestroyed = OnSurfaceDestroyedCB; + OH_NativeXComponent_RegisterCallback(nativeXComponent, &renderCallback_); + } + +public: + static std::unordered_map instance_; + std::string id_; + +private: + OH_NativeXComponent_Callback renderCallback_; +}; +std::unordered_map SampleRenderer::instance_; + +class SampleManager { +public: + ~SampleManager() { + LOG("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(); + } + static SampleManager *GetInstance() { return &SampleManager::pluginManager_; } + void SetNativeXComponent(std::string &id, OH_NativeXComponent *nativeXComponent) { + if (nativeXComponent == nullptr) { + return; + } + surfaceId_ = &id; + nativeXComponentMap_[id] = nativeXComponent; + } + void SetNativeWindow(OHNativeWindow *nativeWindow, uint64_t width, uint64_t height) { + nativeWindow_ = nativeWindow; + height_ = height; + width_ = width; + } + void SetAVPlayer(OH_AVPlayer *player) { player_ = player; } + void Export(napi_env env, napi_value exports) { + LOG("Call PluginManager::Export"); + if ((env == nullptr) || (exports == nullptr)) { + LOG("PluginManager %{public}s", "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) { + LOG("PluginManager %{public}s", "Export: napi_get_named_property fail"); + return; + } + OH_NativeXComponent *nativeXComponent = nullptr; + if (napi_unwrap(env, exportInstance, reinterpret_cast(&nativeXComponent)) != napi_ok) { + LOG("PluginManager %{public}s", "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) { + LOG("PluginManager Export: OH_NativeXComponent_GetXComponentId fail"); + return; + } + LOG("Call PluginManager::Export surfaceID=%{public}s", idStr); + std::string id(idStr); + auto context = SampleManager::GetInstance(); + if ((context != nullptr) && (nativeXComponent != nullptr)) { + context->SetNativeXComponent(id, nativeXComponent); + auto render = context->GetRender(id); + if (render != nullptr) { + render->RegisterCallback(nativeXComponent); + } + } + } + SampleRenderer *GetRender(std::string &id) { + if (pluginRenderMap_.find(id) == pluginRenderMap_.end()) { + SampleRenderer *instance = SampleRenderer::GetInstance(id); + pluginRenderMap_[id] = instance; + return instance; + } + return pluginRenderMap_[id]; + } + +public: + static SampleManager pluginManager_; + std::unordered_map pluginRenderMap_; + std::unordered_map nativeXComponentMap_; + std::string *surfaceId_; + OHNativeWindow *nativeWindow_ = nullptr; + uint64_t height_; + uint64_t width_; + OH_AVPlayer *player_ = nullptr; + OH_NativeXComponent_Callback renderCallback_; +}; +SampleManager SampleManager::pluginManager_; + +void OnSurfaceCreatedCB(OH_NativeXComponent *component, void *window) { + LOG("OnSurfaceCreatedCB"); + if ((component == nullptr) || (window == nullptr)) { + 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) { + return; + } + uint64_t width; + uint64_t height; + OH_NativeXComponent_GetXComponentSize(component, window, &width, &height); + auto context = SampleManager::GetInstance(); + OHNativeWindow *nativeWindow = static_cast(window); + if ((context != nullptr) && (nativeWindow != nullptr)) { + context->SetNativeWindow(nativeWindow, width, height); + } +} +void OnSurfaceDestroyedCB(OH_NativeXComponent *component, void *window) { + LOG("OnSurfaceDestroyedCB"); + if ((component == nullptr) || (window == nullptr)) { + 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) { + return; + } + std::string id(idStr); + SampleRenderer::Release(id); +} + +void OHAVPlayerOnInfoCallback(OH_AVPlayer *player, AVPlayerOnInfoType type, OH_AVFormat *infoBody, void *userData) { + int32_t ret; + int32_t value = -1; + + int32_t state = -1; + int32_t stateChangeReason = -1; + AVPlayerState avState = AV_IDLE; + + float volume = 0.0; + + int32_t width = -1; + int32_t height = -1; + + int32_t bufferType = -1; + int32_t bufferValue = -1; + + uint8_t *bitRates; + size_t size; + + int32_t interruptType = -1; + int32_t interruptForce = -1; + int32_t interruptHint = -1; + switch (type) { + case AV_INFO_TYPE_STATE_CHANGE: + LOG("AVPlayerOnInfoType AV_INFO_TYPE_STATE_CHANGE"); + OH_AVFormat_GetIntValue(infoBody, OH_PLAYER_STATE, &state); + OH_AVFormat_GetIntValue(infoBody, OH_PLAYER_STATE_CHANGE_REASON, &stateChangeReason); + OH_AVPlayer_GetState(player, &avState); // 获取当前播放状态 + LOG("OHAVPlayerOnInfoCallback AV_INFO_TYPE_STATE_CHANGE state: %{public}d ,stateChangeReason: %{public}d", + state, stateChangeReason); + avState = static_cast(state); + switch (avState) { + case AV_IDLE: // 成功调用reset接口后触发该状态机上报 + LOG("AVPlayerState AV_IDLE"); + break; + case AV_INITIALIZED: { + LOG("AVPlayerState AV_INITIALIZED"); + auto context = SampleManager::GetInstance(); + ret = OH_AVPlayer_SetVideoSurface(player, context->nativeWindow_); + LOG("OH_AVPlayer_SetVideoSurface ret:%{public}d", ret); + ret = OH_AVPlayer_Prepare(player); // 设置播放源后触发该状态上报 + if (ret != AV_ERR_OK) { + // 处理异常 + LOG("player %{public}s", "OH_AVPlayer_Prepare Err"); + } + } break; + case AV_PREPARED: + LOG("AVPlayerState AV_PREPARED"); + ret = OH_AVPlayer_SetAudioEffectMode(player, EFFECT_NONE); // 设置音频音效模式 + LOG("OH_AVPlayer_SetAudioEffectMode ret:%{public}d", ret); + ret = OH_AVPlayer_Play(player); // 调用播放接口开始播放 + LOG("OH_AVPlayer_Play ret:%{public}d", ret); + break; + case AV_PLAYING: + LOG("AVPlayerState AV_PLAYING"); + break; + case AV_PAUSED: + LOG("AVPlayerState AV_PAUSED"); + break; + case AV_STOPPED: + LOG("AVPlayerState AV_STOPPED"); + break; + case AV_COMPLETED: + LOG("AVPlayerState AV_COMPLETED"); + break; + case AV_ERROR: + LOG("AVPlayerState AV_ERROR"); + break; + case AV_RELEASED: + LOG("AVPlayerState AV_RELEASED"); + break; + default: + break; + } + break; + case AV_INFO_TYPE_SEEKDONE: + OH_AVFormat_GetIntValue(infoBody, OH_PLAYER_SEEK_POSITION, &value); + LOG("OHAVPlayerOnInfoCallback AV_INFO_TYPE_SEEKDONE value: %{public}d", value); + break; + case AV_INFO_TYPE_SPEEDDONE: + OH_AVFormat_GetIntValue(infoBody, OH_PLAYER_PLAYBACK_SPEED, &value); + LOG("OHAVPlayerOnInfoCallback AV_INFO_TYPE_SPEEDDONE value: %{public}d", value); + break; + case AV_INFO_TYPE_BITRATEDONE: + OH_AVFormat_GetIntValue(infoBody, OH_PLAYER_BITRATE, &value); + LOG("OHAVPlayerOnInfoCallback AV_INFO_TYPE_BITRATEDONE value: %{public}d", value); + break; + case AV_INFO_TYPE_EOS: + LOG("OHAVPlayerOnInfoCallback AV_INFO_TYPE_EOS"); + break; + case AV_INFO_TYPE_POSITION_UPDATE: + OH_AVFormat_GetIntValue(infoBody, OH_PLAYER_CURRENT_POSITION, &value); + // 以下log会频繁打印 + // LOG("OHAVPlayerOnInfoCallback AV_INFO_TYPE_POSITION_UPDATE value: %{public}d", value); + break; + case AV_INFO_TYPE_MESSAGE: + OH_AVFormat_GetIntValue(infoBody, OH_PLAYER_MESSAGE_TYPE, &value); + LOG("OHAVPlayerOnInfoCallback AV_INFO_TYPE_MESSAGE value: %{public}d", value); + break; + case AV_INFO_TYPE_VOLUME_CHANGE: + OH_AVFormat_GetFloatValue(infoBody, OH_PLAYER_VOLUME, &volume); + LOG("OHAVPlayerOnInfoCallback AV_INFO_TYPE_VOLUME_CHANGE value: %{public}f", volume); + break; + case AV_INFO_TYPE_RESOLUTION_CHANGE: + OH_AVFormat_GetIntValue(infoBody, OH_PLAYER_VIDEO_WIDTH, &width); + OH_AVFormat_GetIntValue(infoBody, OH_PLAYER_VIDEO_HEIGHT, &height); + LOG("OHAVPlayerOnInfoCallback AV_INFO_TYPE_RESOLUTION_CHANGE width: %{public}d, height: %{public}d", + width, height); + break; + case AV_INFO_TYPE_BUFFERING_UPDATE: + OH_AVFormat_GetIntValue(infoBody, OH_PLAYER_BUFFERING_TYPE, &bufferType); + OH_AVFormat_GetIntValue(infoBody, OH_PLAYER_BUFFERING_VALUE, &bufferValue); + // 以下log会频繁打印 +// LOG("OHAVPlayerOnInfoCallback AV_INFO_TYPE_BUFFERING_UPDATE bufferType: %{public}d, bufferValue: %{public}d", +// bufferType, bufferValue); + break; + case AV_INFO_TYPE_BITRATE_COLLECT: + OH_AVFormat_GetBuffer(infoBody, OH_PLAYER_BITRATE_ARRAY, &bitRates, &size); + LOG("OHAVPlayerOnInfoCallback AV_INFO_TYPE_BITRATE_COLLECT size: %{public}zu", size); + for (size_t i = 0, cnt = size / sizeof(uint32_t); i < cnt; i++) { + LOG("OHAVPlayerOnInfoCallback AV_INFO_TYPE_BITRATE_COLLECT bitRates[%{public}zu]: %{public}u", i, + *(static_cast(static_cast(bitRates)) + i)); + } + break; + case AV_INFO_TYPE_INTERRUPT_EVENT: + OH_AVFormat_GetIntValue(infoBody, OH_PLAYER_AUDIO_INTERRUPT_TYPE, &interruptType); + OH_AVFormat_GetIntValue(infoBody, OH_PLAYER_AUDIO_INTERRUPT_FORCE, &interruptForce); + OH_AVFormat_GetIntValue(infoBody, OH_PLAYER_AUDIO_INTERRUPT_HINT, &interruptHint); + LOG("OHAVPlayerOnInfoCallback AV_INFO_TYPE_INTERRUPT_EVENT interruptType: %{public}d, " + "interruptForce: %{public}d, interruptHint: %{public}d", interruptType, interruptForce, interruptHint); + break; + case AV_INFO_TYPE_DURATION_UPDATE: + OH_AVFormat_GetIntValue(infoBody, OH_PLAYER_DURATION, &value); + LOG("OHAVPlayerOnInfoCallback AV_INFO_TYPE_DURATION_UPDATE value: %{public}d", value); + break; + case AV_INFO_TYPE_IS_LIVE_STREAM: + OH_AVFormat_GetIntValue(infoBody, OH_PLAYER_IS_LIVE_STREAM, &value); + LOG("OHAVPlayerOnInfoCallback AV_INFO_TYPE_IS_LIVE_STREAM value: %{public}d", value); + break; + case AV_INFO_TYPE_TRACKCHANGE: + LOG("OHAVPlayerOnInfoCallback AV_INFO_TYPE_TRACKCHANGE value: %{public}d", value); + break; + case AV_INFO_TYPE_TRACK_INFO_UPDATE: + LOG("OHAVPlayerOnInfoCallback AV_INFO_TYPE_TRACK_INFO_UPDATE value: %{public}d", value); + break; + case AV_INFO_TYPE_SUBTITLE_UPDATE: + LOG("OHAVPlayerOnInfoCallback AV_INFO_TYPE_SUBTITLE_UPDATE value: %{public}d", value); + break; + case AV_INFO_TYPE_AUDIO_OUTPUT_DEVICE_CHANGE: + OH_AVFormat_GetIntValue(infoBody, OH_PLAYER_AUDIO_DEVICE_CHANGE_REASON, &value); + LOG("OHAVPlayerOnInfoCallback AV_INFO_TYPE_AUDIO_OUTPUT_DEVICE_CHANGE value: %{public}d", value); + break; + default: + break; + } +} +void OHAVPlayerOnErrorCallback(OH_AVPlayer *player, int32_t errorCode, const char *errorMsg, void *userData) { + LOG("OHAVPlayerOnErrorCallback errorCode: %{public}d ,errorMsg: %{public}s", errorCode, errorMsg); +} +static napi_value NAPI_Global_Setup(napi_env env, napi_callback_info info) { + + LOG("Call NAPI AVPlayer setup"); + size_t argc = 4; + napi_value args[4] = {nullptr}; + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + // 获取参数类型 + napi_valuetype stringType; + if (napi_ok != napi_typeof(env, args[0], &stringType)) { + // 处理异常 + LOG("参数异常"); + return nullptr; + } + // 参数校验 + if (napi_null == stringType) { + // 处理异常 + LOG("参数异常 null"); + return nullptr; + } + // 获取传递的string长度 + size_t length = 0; + if (napi_ok != napi_get_value_string_utf8(env, args[0], nullptr, 0, &length)) { + // 处理异常 + LOG("参数长度异常"); + return nullptr; + } + // 如果传入的是"",则直接返回 + if (length == 0) { + // 处理异常 + LOG("参数空字符"); + return nullptr; + } + // 读取传入的string放入buffer中 + char *url = new char[length + 1]; + if (napi_ok != napi_get_value_string_utf8(env, args[0], url, length + 1, &length)) { + delete[] url; + url = nullptr; + // 处理异常 + LOG("url 异常"); + return nullptr; + } + int pType; + napi_get_value_int32(env, args[1], &pType); + LOG("fd type %{public}d", pType); + int pOffset; + napi_get_value_int32(env, args[2], &pOffset); + LOG("fd size %{public}d", pOffset); + int pSize; + napi_get_value_int32(env, args[3], &pSize); + LOG("fd size %{public}d", pSize); + + // 创建播放实例 + if(SampleManager::GetInstance()->player_) { + OH_AVPlayer_Release(SampleManager::GetInstance()->player_); + } + OH_AVPlayer *player = OH_AVPlayer_Create(); + SampleManager::GetInstance()->SetAVPlayer(player); + // 设置回调,监听信息 + LOG("call OH_AVPlayer_SetPlayerOnInfoCallback"); + int32_t ret = OH_AVPlayer_SetOnInfoCallback(player, OHAVPlayerOnInfoCallback, nullptr); + LOG("OH_AVPlayer_SetPlayerOnInfoCallback ret:%{public}d", ret); + LOG("call OH_AVPlayer_SetPlayerOnErrorCallback"); + ret = OH_AVPlayer_SetOnErrorCallback(player, OHAVPlayerOnErrorCallback, nullptr); + LOG("OH_AVPlayer_SetPlayerOnErrorCallback ret:%{public}d", ret); + { + LOG("player %{public}s >> fd: %{public}d offset: %{public}d fileSize: %{public}d", + url, pType, pOffset, pSize); + LOG("call %{public}s", "OH_AVPlayer_SetFDSource"); + ret = OH_AVPlayer_SetFDSource(player, pType, pOffset, pSize); + LOG("OH_AVPlayer_SetFDSource ret:%{public}d", ret); + } + // 设置音频流类型 + LOG("call %{public}s", "OH_AVPlayer_SetAudioRendererInfo"); + OH_AudioStream_Usage streamUsage = OH_AudioStream_Usage::AUDIOSTREAM_USAGE_UNKNOWN; + ret = OH_AVPlayer_SetAudioRendererInfo(player, streamUsage); + LOG("OH_AVPlayer_SetAudioRendererInfo ret:%{public}d", ret); + // 设置音频流打断模式 + LOG("call OH_AVPlayer_SetAudioInterruptMode"); + OH_AudioInterrupt_Mode interruptMode = OH_AudioInterrupt_Mode::AUDIOSTREAM_INTERRUPT_MODE_INDEPENDENT; + ret = OH_AVPlayer_SetAudioInterruptMode(player, interruptMode); + LOG("OH_AVPlayer_SetAudioInterruptMode ret:%{public}d", ret); + napi_value value; + napi_create_int32(env, 0, &value); + return value; +} +static napi_value NAPI_Global_Play(napi_env env, napi_callback_info info) { + int ret = -1; + auto context = SampleManager::GetInstance(); + if (context->player_ != NULL) { + ret = OH_AVPlayer_Play(context->player_); + LOG("OH_AVPlayer_Play ret:%{public}d", ret); + bool isPlaying = false; + isPlaying = OH_AVPlayer_IsPlaying(context->player_); + LOG("OH_AVPlayer_IsPlaying :%{public}d", isPlaying); + } else { + LOG("no found Player Instances"); + } + napi_value value; + napi_create_int32(env, ret, &value); + return value; +} +static napi_value NAPI_Global_SetSpeed(napi_env env, napi_callback_info info) { + size_t argc = 1; + napi_value args[1] = {nullptr}; + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + int speed_code; + napi_get_value_int32(env, args[0], &speed_code); + int ret = -1; + auto context = SampleManager::GetInstance(); + if (context->player_ != NULL) { + switch (speed_code) { + case 0: + LOG("OH_AVPlayer_SetPlaybackSpeed AV_SPEED_FORWARD_0_75_X"); + ret = OH_AVPlayer_SetPlaybackSpeed(context->player_, AV_SPEED_FORWARD_0_75_X); + break; + case 1: + LOG("OH_AVPlayer_SetPlaybackSpeed AV_SPEED_FORWARD_1_00_X"); + ret = OH_AVPlayer_SetPlaybackSpeed(context->player_, AV_SPEED_FORWARD_1_00_X); + break; + case 2: + LOG("OH_AVPlayer_SetPlaybackSpeed AV_SPEED_FORWARD_1_25_X"); + ret = OH_AVPlayer_SetPlaybackSpeed(context->player_, AV_SPEED_FORWARD_1_25_X); + break; + case 3: + LOG("OH_AVPlayer_SetPlaybackSpeed AV_SPEED_FORWARD_1_75_X"); + ret = OH_AVPlayer_SetPlaybackSpeed(context->player_, AV_SPEED_FORWARD_1_75_X); + break; + case 4: + LOG("OH_AVPlayer_SetPlaybackSpeed AV_SPEED_FORWARD_2_00_X"); + ret = OH_AVPlayer_SetPlaybackSpeed(context->player_, AV_SPEED_FORWARD_2_00_X); + break; + case 5: + LOG("OH_AVPlayer_SetPlaybackSpeed AV_SPEED_FORWARD_0_50_X"); + ret = OH_AVPlayer_SetPlaybackSpeed(context->player_, AV_SPEED_FORWARD_0_50_X); + break; + case 6: + LOG("OH_AVPlayer_SetPlaybackSpeed AV_SPEED_FORWARD_1_50_X"); + ret = OH_AVPlayer_SetPlaybackSpeed(context->player_, AV_SPEED_FORWARD_1_50_X); + break; + default: + LOG("OH_AVPlayer_SetPlaybackSpeed AV_SPEED_FORWARD_1_00_X"); + ret = OH_AVPlayer_SetPlaybackSpeed(context->player_, AV_SPEED_FORWARD_1_00_X); + break; + } + LOG("OH_AVPlayer_SetPlaybackSpeed ret:%{public}d", ret); + } else { + LOG("no found Player Instances"); + } + napi_value value; + napi_create_int32(env, ret, &value); + return value; +} +static napi_value NAPI_Global_GetSpeed(napi_env env, napi_callback_info info) { + auto context = SampleManager::GetInstance(); + AVPlaybackSpeed speed; + if (context->player_ != NULL) { + OH_AVPlayer_GetPlaybackSpeed(context->player_, &speed); + } else { + LOG("no found Player Instances"); + } + napi_value value; + napi_create_int32(env, speed, &value); + return value; +} +static napi_value NAPI_Global_GetCurrentTrack(napi_env env, napi_callback_info info) { + auto context = SampleManager::GetInstance(); + int currentTrack = 0; // 媒体类型。0:音频,1:视频 + int index; + if (context->player_ != NULL) { + OH_AVPlayer_GetCurrentTrack(context->player_, currentTrack, &index); + } else { + LOG("no found Player Instances"); + } + napi_value value; + napi_create_int32(env, index, &value); + return value; +} +static napi_value NAPI_Global_Pause(napi_env env, napi_callback_info info) { + int ret = 100; + auto context = SampleManager::GetInstance(); + if (context->player_ != NULL) { + ret = OH_AVPlayer_Pause(context->player_); + LOG("OH_AVPlayer_Pause ret:%{public}d", ret); + } else { + LOG("no found Player Instances"); + } + napi_value value; + napi_create_int32(env, ret, &value); + return value; +} +static napi_value NAPI_Global_Stop(napi_env env, napi_callback_info info) { + int ret = 100; + auto context = SampleManager::GetInstance(); + if (context->player_ != NULL) { + ret = OH_AVPlayer_Stop(context->player_); + LOG("OH_AVPlayer_Stop ret:%{public}d", ret); + } else { + LOG("no found Player Instances"); + } + napi_value value; + napi_create_int32(env, ret, &value); + return value; +} +static napi_value NAPI_Global_Reset(napi_env env, napi_callback_info info) { + int ret = 100; + auto context = SampleManager::GetInstance(); + if (context->player_ != NULL) { + ret = OH_AVPlayer_Reset(context->player_); + LOG("OH_AVPlayer_Pause ret:%{public}d", ret); + } else { + LOG("no found Player Instances"); + } + napi_value value; + napi_create_int32(env, ret, &value); + return value; +} +static napi_value NAPI_Global_Seek(napi_env env, napi_callback_info info) { + size_t argc = 2; + napi_value args[2] = {nullptr}; + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + int seekValue; + napi_get_value_int32(env, args[0], &seekValue); + int mode; + napi_get_value_int32(env, args[1], &mode); + auto context = SampleManager::GetInstance(); + if (context->player_ != NULL) { + int ret; + switch (mode) { + case 0: + LOG("call NAPI_Global_Seek value:%{public}d mode:AV_SEEK_NEXT_SYNC", seekValue); + ret = OH_AVPlayer_Seek(context->player_, seekValue, AV_SEEK_NEXT_SYNC); + break; + case 1: + LOG("call NAPI_Global_Seek value:%{public}d mode:AV_SEEK_PREVIOUS_SYNC", seekValue); + ret = OH_AVPlayer_Seek(context->player_, seekValue, AV_SEEK_PREVIOUS_SYNC); + break; + case 2: + LOG("call NAPI_Global_Seek value:%{public}d mode:AV_SEEK_CLOSEST", seekValue); + ret = OH_AVPlayer_Seek(context->player_, seekValue, AV_SEEK_CLOSEST); + break; + default: + LOG("call NAPI_Global_Seek value:%{public}d mode:AV_SEEK_PREVIOUS_SYNC", seekValue); + ret = OH_AVPlayer_Seek(context->player_, seekValue, AV_SEEK_PREVIOUS_SYNC); + break; + } + LOG("OH_AVPlayer_Seek ret:%{public}d", ret); + } else { + LOG("no found Player Instances"); + } + napi_value value; + napi_create_int32(env, 0, &value); + return value; +} +static napi_value NAPI_Global_GetDuration(napi_env env, napi_callback_info info) { + auto context = SampleManager::GetInstance(); + int ret; + int32_t duration; + if (context->player_ != NULL) { + ret = OH_AVPlayer_GetDuration(context->player_, &duration); + if (ret != AV_ERR_OK) { + LOG("OH_AVPlayer_GetDuration fail"); + } + } else { + LOG("no found Player Instances"); + } + napi_value value; + napi_create_int32(env, duration, &value); + return value; +} +static napi_value NAPI_Global_GetCurrentTime(napi_env env, napi_callback_info info) { + auto context = SampleManager::GetInstance(); + int ret; + int32_t currentTime; + if (context->player_ != NULL) { + ret = OH_AVPlayer_GetCurrentTime(context->player_, ¤tTime); + if (ret != AV_ERR_OK) { + LOG("OH_AVPlayer_GetCurrentTime fail"); + } + } else { + LOG("no found Player Instances"); + } + napi_value value; + napi_create_int32(env, currentTime, &value); + return value; +} +static napi_value NAPI_Global_GetVideoHeight(napi_env env, napi_callback_info info) { + int ret = -1; + auto context = SampleManager::GetInstance(); + if (context->player_ != NULL) { + int32_t videoHeight; + ret = OH_AVPlayer_GetVideoHeight(context->player_, &videoHeight); + LOG("OH_AVPlayer_GetVideoHeight ret:%{public}d videoHeight:%{public}d ", ret, videoHeight); + } else { + LOG("no found Player Instances"); + } + napi_value value; + napi_create_int32(env, ret, &value); + return value; +} +static napi_value NAPI_Global_GetVideoWidth(napi_env env, napi_callback_info info) { + int ret = -1; + auto context = SampleManager::GetInstance(); + if (context->player_ != NULL) { + int32_t videoWidth; + ret = OH_AVPlayer_GetVideoWidth(context->player_, &videoWidth); + LOG("OH_AVPlayer_GetVideoWidth ret:%{public}d videoWidth:%{public}d ", ret, videoWidth); + } else { + LOG("no found Player Instances"); + } + napi_value value; + napi_create_int32(env, ret, &value); + return value; +} +static napi_value NAPI_Global_SelectTrack(napi_env env, napi_callback_info info) { + int ret = -1; + int32_t index; + auto context = SampleManager::GetInstance(); + if (context->player_ != NULL) { + ret = OH_AVPlayer_SelectTrack(context->player_, index); + LOG("OH_AVPlayer_SelectTrack index:%{public}d ", index); + } else { + LOG("no found Player Instances"); + } + napi_value value; + napi_create_int32(env, index, &value); + return value; +} +static napi_value NAPI_Global_DeselectTrack(napi_env env, napi_callback_info info) { + int ret = -1; + int32_t index; + auto context = SampleManager::GetInstance(); + if (context->player_ != NULL) { + ret = OH_AVPlayer_DeselectTrack(context->player_, index); + LOG("OH_AVPlayer_DeselectTrack index:%{public}d ", index); + } else { + LOG("no found Player Instances"); + } + napi_value value; + napi_create_int32(env, index, &value); + return value; +} +static napi_value NAPI_Global_SelectBitRate(napi_env env, napi_callback_info info) { + int ret = -1; + uint32_t bitRate; + auto context = SampleManager::GetInstance(); + if (context->player_ != NULL) { + ret = OH_AVPlayer_SelectBitRate(context->player_, bitRate); + LOG("OH_AVPlayer_SelectBitRate bitRate:%{public}d ", bitRate); + } else { + LOG("no found Player Instances"); + } + napi_value value; + napi_create_int32(env, bitRate, &value); + return value; +} +static napi_value NAPI_Global_SetLooping(napi_env env, napi_callback_info info) { + int ret = -1; + auto context = SampleManager::GetInstance(); + bool loop = true; + if (context->player_ != NULL) { + ret = OH_AVPlayer_SetLooping(context->player_, loop); + LOG("OH_AVPlayer_SetLooping ret:%{public}d", ret); + bool isLooping = false; + isLooping = OH_AVPlayer_IsLooping(context->player_); + LOG("OH_AVPlayer_IsLooping :%{public}d", isLooping); + } else { + LOG("no found Player Instances"); + } + napi_value value; + napi_create_int32(env, ret, &value); + return value; +} +static napi_value NAPI_Global_Release(napi_env env, napi_callback_info info) { + int ret = -1; + auto context = SampleManager::GetInstance(); + if (context->player_ != NULL) { + ret = OH_AVPlayer_Release(context->player_); + LOG("OH_AVPlayer_Release ret:%{public}d", ret); + } else { + LOG("no found Player Instances"); + } + napi_value value; + napi_create_int32(env, ret, &value); + return value; +} +static napi_value NAPI_Global_ReleaseSync(napi_env env, napi_callback_info info) { + int ret = -1; + auto context = SampleManager::GetInstance(); + if (context->player_ != NULL) { + ret = OH_AVPlayer_ReleaseSync(context->player_); + LOG("OH_AVPlayer_ReleaseSync ret:%{public}d", ret); + } else { + LOG("no found Player Instances"); + } + napi_value value; + napi_create_int32(env, ret, &value); + return value; +} +EXTERN_C_START +static napi_value Init(napi_env env, napi_value exports) +{ + napi_property_descriptor desc[] = { + {"setup", nullptr, NAPI_Global_Setup, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"play", nullptr, NAPI_Global_Play, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"setSpeed", nullptr, NAPI_Global_SetSpeed, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"getSpeed", nullptr, NAPI_Global_GetSpeed, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"getCurrentTrack", nullptr, NAPI_Global_GetCurrentTrack, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"pause", nullptr, NAPI_Global_Pause, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"stop", nullptr, NAPI_Global_Stop, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"reset", nullptr, NAPI_Global_Reset, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"seek", nullptr, NAPI_Global_Seek, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"getDuration", nullptr, NAPI_Global_GetDuration, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"getCurrentTime", nullptr, NAPI_Global_GetCurrentTime, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"getVideoHeight", nullptr, NAPI_Global_GetVideoHeight, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"getVideoWidth", nullptr, NAPI_Global_GetVideoWidth, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"selectTrack", nullptr, NAPI_Global_SelectTrack, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"deselectTrack", nullptr, NAPI_Global_DeselectTrack, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"selectBitrate", nullptr, NAPI_Global_SelectBitRate, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"setLooping", nullptr, NAPI_Global_SetLooping, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"release", nullptr, NAPI_Global_Release, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"releaseSync", nullptr, NAPI_Global_ReleaseSync, nullptr, nullptr, nullptr, napi_default, nullptr}, + }; + napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); + SampleManager::GetInstance()->Export(env, exports); + return exports; +} +EXTERN_C_END + +static napi_module demoModule = { + .nm_version = 1, + .nm_flags = 0, + .nm_filename = nullptr, + .nm_register_func = Init, + .nm_modname = "entry", + .nm_priv = ((void*)0), + .reserved = { 0 }, +}; + +extern "C" __attribute__((constructor)) void RegisterEntryModule(void) +{ + napi_module_register(&demoModule); +} diff --git a/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/cpp/types/libentry/Index.d.ts b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/cpp/types/libentry/Index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..657b19adc017a786f8a4fa913bc64ad3bc5d0320 --- /dev/null +++ b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/cpp/types/libentry/Index.d.ts @@ -0,0 +1,25 @@ +/* + * 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. + */ +export const setup: (filePath: string, type: number, offset: number, size: number) => number; +export const play: () => void; +export const setSpeed: (sp: number) => void; +export const getSpeed: () => number +export const pause: () => void; +export const seek: (value: number, seekMode: number) => void; +export const getDuration: () => number; +export const getCurrentTime: () => number; +export const getVideoHeight: () => number; +export const getVideoWidth: () => number; +export const release: () => number; \ No newline at end of file diff --git a/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/cpp/types/libentry/oh-package.json5 b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/cpp/types/libentry/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..77052c679533e45a066030a9fc21cdbf9cbcf995 --- /dev/null +++ b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/cpp/types/libentry/oh-package.json5 @@ -0,0 +1,20 @@ +/* + * 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. + */ +{ + "name": "libentry.so", + "types": "./Index.d.ts", + "version": "1.0.0", + "description": "Please describe the basic information." +} \ No newline at end of file diff --git a/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/ets/entryability/EntryAbility.ets b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/ets/entryability/EntryAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..843c7f0c1f7b9a460e3dbbd2689e5b34016027d1 --- /dev/null +++ b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/ets/entryability/EntryAbility.ets @@ -0,0 +1,58 @@ +/* + * 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 { AbilityConstant, ConfigurationConstant, UIAbility, Want } from '@kit.AbilityKit'; +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { window } from '@kit.ArkUI'; + +const DOMAIN = 0x0000; + +export default class EntryAbility extends UIAbility { + onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { + this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET); + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onCreate'); + } + + onDestroy(): void { + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onDestroy'); + } + + onWindowStageCreate(windowStage: window.WindowStage): void { + // Main window is created, set main page for this ability + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); + + windowStage.loadContent('pages/Index', (err) => { + if (err.code) { + hilog.error(DOMAIN, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err)); + return; + } + hilog.info(DOMAIN, 'testTag', 'Succeeded in loading the content.'); + }); + } + + onWindowStageDestroy(): void { + // Main window is destroyed, release UI related resources + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageDestroy'); + } + + onForeground(): void { + // Ability has brought to foreground + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onForeground'); + } + + onBackground(): void { + // Ability has back to background + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onBackground'); + } +} \ No newline at end of file diff --git a/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..4ce6449f0e91914e73d4502c9f2e8e9a395ea4b1 --- /dev/null +++ b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets @@ -0,0 +1,30 @@ +/* + * 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 { BackupExtensionAbility, BundleVersion } from '@kit.CoreFileKit'; + +const DOMAIN = 0x0000; + +export default class EntryBackupAbility extends BackupExtensionAbility { + async onBackup() { + hilog.info(DOMAIN, 'testTag', 'onBackup ok'); + await Promise.resolve(); + } + + async onRestore(bundleVersion: BundleVersion) { + hilog.info(DOMAIN, 'testTag', 'onRestore ok %{public}s', JSON.stringify(bundleVersion)); + await Promise.resolve(); + } +} \ No newline at end of file diff --git a/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/ets/pages/Index.ets b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/ets/pages/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..bdca7c1744ec5025f7caa601e35fad1efdde9ec1 --- /dev/null +++ b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/ets/pages/Index.ets @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2023-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 display from '@ohos.display'; +import { common } from '@kit.AbilityKit'; +import media from '@ohos.multimedia.media'; +import avPlayerNDK from 'libentry.so'; + +const SURFACE_W = 0.9; // 表面宽比例 +const SURFACE_H = 1.78; // 表面高比例 +const SET_INTERVAL = 300; // interval间隔时间 +const TIME_ONE = 60000; +const TIME_TWO = 1000; +const SPEED_COUNT = 4; + +@Entry +@Component +struct Index { + tag: string = 'AVPlayManager'; + private context: common.UIAbilityContext | undefined = undefined; + + @State title: Resource = $r('app.string.EntryAbility_label'); + @State fileName: string = 'test1.mp4'; + @State isPaused: boolean = true; // 暂停播放 + @State speedSelect: number = 0; // 倍速选择 + @State speedList: Resource[] = [$r('app.string.video_speed_1_0X'), $r('app.string.video_speed_1_25X'), $r('app.string.video_speed_1_75X'), $r('app.string.video_speed_2_0X')]; + @StorageLink('durationTime') durationTime: number = 0; // 视频总时长 + @StorageLink('currentTime') currentTime: number = 0; // 视频当前时间 + @StorageLink('speedName') speedName: Resource = $r('app.string.video_speed_1_0X'); + @StorageLink('speedIndex') speedIndex: number = 0; // 倍速索引 + @State surfaceW: number | null = null; + @State surfaceH: number | null = null; + @State percent: number = 0; + @State windowWidth: number = 300; + @State windowHeight: number = 200; + + updateTimer(): void { + setInterval(() => { // 更新当前时间 + if (this.isPaused) { + let duration = avPlayerNDK.getDuration() + let currentTime = avPlayerNDK.getCurrentTime() + if (duration > 0) { + this.durationTime = duration + } + if (currentTime > 0) { + this.currentTime = currentTime + } + if(currentTime == duration) { + this.isPaused = false; + } + console.log(`${this.tag}: getDuration ${this.durationTime}`) + console.log(`${this.tag}: getPlaybackSpeed enum ${avPlayerNDK.getSpeed()}`) + console.log(`${this.tag}: IsPlaying ${!this.isPaused}`) + } + }, SET_INTERVAL); + } + + getDurationTime(): number { + return this.durationTime; + } + + getCurrentTime(): number { + return this.currentTime; + } + + timeConvert(time: number): string { + let min: number = Math.floor(time / TIME_ONE); + let second: string = ((time % TIME_ONE) / TIME_TWO).toFixed(0); + // return `${min}:${(+second < TIME_THREE ? '0' : '') + second}`; + second = second.padStart(2, '0'); + return `${min}:${second}`; + } + + aboutToAppear() { + this.windowWidth = display.getDefaultDisplaySync().width; + this.windowHeight = display.getDefaultDisplaySync().height; + this.surfaceW = this.windowWidth * SURFACE_W; + this.surfaceH = this.surfaceW / SURFACE_H; + this.isPaused = true; + this.context = getContext(this) as common.UIAbilityContext; + } + + aboutToDisappear() { + avPlayerNDK.release(); + } + + onPageHide() { + avPlayerNDK.pause(); + this.isPaused = false; + } + + onPageShow() { + } + + async avSetup() { + if (this.context == undefined) return; + let fileDescriptor = await this.context.resourceManager.getRawFd(this.fileName); + avPlayerNDK.setup('sss', fileDescriptor.fd, fileDescriptor.offset, fileDescriptor.length); + this.updateTimer(); + } + + build() { + Column() { + Stack() { + Column() { + XComponent({ + // 装载视频容器 + id: 'componentVideo', + type: XComponentType.SURFACE, + libraryname: "entry", + }) + .id('VideoView') + .onLoad(() => { + if(this.context) { + this.avSetup(); + } + }) + .height(`${this.surfaceH}px`) + .width(`${this.surfaceW}px`) + } + .align(Alignment.TopStart) + .margin({ top: 80 }) + .id('VideoView') + .justifyContent(FlexAlign.Center) + + Column() { + Blank() + Column() { + // 进度条 + Row() { + Row() { + // 播放、暂停键 + Image(this.isPaused ? $r("app.media.ic_video_play") : $r("app.media.ic_video_pause")) // 暂停/播放 + .id(this.isPaused ? 'pause' : 'play') + .width($r('app.float.size_40')) + .height($r('app.float.size_40')) + .onClick(() => { + if (this.isPaused) { + avPlayerNDK.pause(); + this.isPaused = false; + } else { + avPlayerNDK.play(); + this.isPaused = true; + } + }) + + // 左侧时间 + Text(this.timeConvert(this.currentTime)) + .id("currentTimeText") + .fontColor(Color.White) + .textAlign(TextAlign.End) + .fontWeight(FontWeight.Regular) + .margin({ left: $r('app.float.size_10') }) + } + + // 进度条 + Row() { + Slider({ + value: this.currentTime, + min: 0, + max: this.durationTime, + style: SliderStyle.OutSet + }) + .id('Slider') + .blockColor(Color.White) + .trackColor(Color.Gray) + .selectedColor($r("app.color.slider_selected")) + .showTips(false) + .onChange((value: number, mode: SliderChangeMode) => { + if (this.currentTime !== value) { + this.currentTime = value; + avPlayerNDK.seek(Number.parseInt(value.toFixed(0)), 2); + } + }) + } + .layoutWeight(1) + + Row() { + // 右侧时间 + Text(this.timeConvert(this.durationTime)) + .id("durationTimeText") + .fontColor(Color.White) + .fontWeight(FontWeight.Regular) + + // 倍速按钮 + Button(this.speedName, { type: ButtonType.Normal }) + .border({ width: $r('app.float.size_1'), color: Color.White }) + .width(75) + .height($r('app.float.size_40')) + .fontSize($r('app.float.size_15')) + .borderRadius($r('app.float.size_24')) + .fontColor(Color.White) + .backgroundColor(Color.Black) + .opacity($r('app.float.size_1')) + .margin({ left: $r('app.float.size_10') }) + .id('Speed') + .onClick(() => { + this.speedIndex = (this.speedIndex + 1) % SPEED_COUNT; + this.speedSelect = this.speedIndex; + this.speedName = this.speedList[this.speedIndex]; + switch (this.speedSelect) { + case 0: + avPlayerNDK.setSpeed(media.PlaybackSpeed.SPEED_FORWARD_1_00_X); + break; + case 1: + avPlayerNDK.setSpeed(media.PlaybackSpeed.SPEED_FORWARD_1_25_X); + break; + case 2: + avPlayerNDK.setSpeed(media.PlaybackSpeed.SPEED_FORWARD_1_75_X); + break; + case 3: + avPlayerNDK.setSpeed(media.PlaybackSpeed.SPEED_FORWARD_2_00_X); + break; + } + }) + } + } + .justifyContent(FlexAlign.Center) + .padding({ left: $r('app.float.size_25'), right: $r('app.float.size_30') }) + .width('100%') + } + .width('100%') + .justifyContent(FlexAlign.Center) + } + .width('100%') + .height('100%') + } + .backgroundColor(Color.Black) + .height('90%') + .width('100%') + + Row() { + Text(this.title) + .fontSize($r('app.float.size_20')) + .fontColor(Color.White) + .opacity($r('app.float.size_zero_six')) + .fontWeight(FontWeight.Regular) + .textAlign(TextAlign.Center) + } + }.backgroundColor(Color.Black) + .height('100%') + .width('100%') + } +} diff --git a/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/module.json5 b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..c75d702e2d350523978ecaf801c22762ce7d40c0 --- /dev/null +++ b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/module.json5 @@ -0,0 +1,65 @@ +/* + * 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", + "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:layered_image", + "label": "$string:EntryAbility_label", + "startWindowIcon": "$media:startIcon", + "startWindowBackground": "$color:start_window_background", + "exported": true, + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ] + } + ], + "extensionAbilities": [ + { + "name": "EntryBackupAbility", + "srcEntry": "./ets/entrybackupability/EntryBackupAbility.ets", + "type": "backup", + "exported": false, + "metadata": [ + { + "name": "ohos.extension.backup", + "resource": "$profile:backup_config" + } + ] + } + ] + } +} \ No newline at end of file diff --git a/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/resources/base/element/color.json b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/resources/base/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..419aa49d53413d68acdd73edc8d2b80d01ef60e9 --- /dev/null +++ b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/resources/base/element/color.json @@ -0,0 +1,24 @@ +{ + "color": [ + { + "name": "start_window_background", + "value": "#FFFFFF" + }, + { + "name": "slider_selected", + "value": "#007DFF" + }, + { + "name": "speed_dialog", + "value": "#33bab4b4" + }, + { + "name": "video_play", + "value": "#333333" + }, + { + "name": "video_play_selected", + "value": "#5c5c5c" + } + ] +} \ No newline at end of file diff --git a/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/resources/base/element/float.json b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/resources/base/element/float.json new file mode 100644 index 0000000000000000000000000000000000000000..09ea9cdfd57c520f94abc39a9ecb6cdecee137b0 --- /dev/null +++ b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/resources/base/element/float.json @@ -0,0 +1,92 @@ +{ + "float": [ + { + "name": "page_text_font_size", + "value": "50fp" + }, + { + "name": "size_zero_five", + "value": "0.5" + }, + { + "name": "size_zero_six", + "value": "0.6" + }, + { + "name": "size_zero", + "value": "0" + }, + { + "name": "size_1", + "value": "1" + }, + { + "name": "size_5", + "value": "5" + }, + { + "name": "size_10", + "value": "10" + }, + { + "name": "size_12", + "value": "12" + }, + { + "name": "size_15", + "value": "15" + }, + { + "name": "size_16", + "value": "16" + }, + { + "name": "size_18", + "value": "18" + }, + { + "name": "size_20", + "value": "20" + }, + { + "name": "size_down_20", + "value": "-20" + }, + { + "name": "size_24", + "value": "24" + }, + { + "name": "size_25", + "value": "25" + }, + { + "name": "size_30", + "value": "30" + }, + { + "name": "size_32", + "value": "32" + }, + { + "name": "size_35", + "value": "35" + }, + { + "name": "size_40", + "value": "40" + }, + { + "name": "size_45", + "value": "45" + }, + { + "name": "size_48", + "value": "48" + }, + { + "name": "size_50", + "value": "50" + } + ] +} \ No newline at end of file diff --git a/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/resources/base/element/string.json b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..91e3c4bfbe2bcf2699e1a3bacb1d0b71be81ee43 --- /dev/null +++ b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/resources/base/element/string.json @@ -0,0 +1,56 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "C++播放视频示例" + }, + { + "name": "video_speed_1_0X", + "value": "1.0X" + }, + { + "name": "video_speed_1_25X", + "value": "1.25X" + }, + { + "name": "video_speed_1_75X", + "value": "1.75X" + }, + { + "name": "video_speed_2_0X", + "value": "2.0X" + }, + { + "name": "video_warn", + "value": "退出程序,请检查网络是否连接或可用!" + }, + { + "name": "dialog_play_speed", + "value": "播放倍速" + }, + { + "name": "dialog_cancel", + "value": "取消" + }, + { + "name": "playing", + "value": "当前播放" + }, + { + "name": "reason", + "value": "video" + }, + { + "name": "playing_now", + "value": "立即播放" + } + ] +} \ No newline at end of file diff --git a/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/resources/base/media/background.png b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/resources/base/media/background.png new file mode 100644 index 0000000000000000000000000000000000000000..923f2b3f27e915d6871871deea0420eb45ce102f Binary files /dev/null and b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/resources/base/media/background.png differ diff --git a/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/resources/base/media/foreground.png b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/resources/base/media/foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..97014d3e10e5ff511409c378cd4255713aecd85f Binary files /dev/null and b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/resources/base/media/foreground.png differ diff --git a/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/resources/base/media/ic_video_pause.svg b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/resources/base/media/ic_video_pause.svg new file mode 100644 index 0000000000000000000000000000000000000000..b18a4a3d00cf2f80fe90c55faef56b39ed485a1b --- /dev/null +++ b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/resources/base/media/ic_video_pause.svg @@ -0,0 +1,13 @@ + + + Public/ic_public_play + + + + + + + + + + \ No newline at end of file diff --git a/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/resources/base/media/ic_video_play.svg b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/resources/base/media/ic_video_play.svg new file mode 100644 index 0000000000000000000000000000000000000000..675bf7f87b66ed5011191b77c1f3f678625be68a --- /dev/null +++ b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/resources/base/media/ic_video_play.svg @@ -0,0 +1,13 @@ + + + Public/ic_public_pause + + + + + + + + + + \ No newline at end of file diff --git a/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/resources/base/media/layered_image.json b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/resources/base/media/layered_image.json new file mode 100644 index 0000000000000000000000000000000000000000..fb49920440fb4d246c82f9ada275e26123a2136a --- /dev/null +++ b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/resources/base/media/layered_image.json @@ -0,0 +1,7 @@ +{ + "layered-image": + { + "background" : "$media:background", + "foreground" : "$media:foreground" + } +} \ No newline at end of file diff --git a/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/resources/base/media/startIcon.png b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/resources/base/media/startIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..205ad8b5a8a42e8762fbe4899b8e5e31ce822b8b Binary files /dev/null and b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/resources/base/media/startIcon.png differ diff --git a/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/resources/base/profile/backup_config.json b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/resources/base/profile/backup_config.json new file mode 100644 index 0000000000000000000000000000000000000000..78f40ae7c494d71e2482278f359ec790ca73471a --- /dev/null +++ b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/resources/base/profile/backup_config.json @@ -0,0 +1,3 @@ +{ + "allowToBackupRestore": true +} \ No newline at end of file diff --git a/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/resources/base/profile/main_pages.json b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/resources/base/profile/main_pages.json new file mode 100644 index 0000000000000000000000000000000000000000..1898d94f58d6128ab712be2c68acc7c98e9ab9ce --- /dev/null +++ b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/resources/base/profile/main_pages.json @@ -0,0 +1,5 @@ +{ + "src": [ + "pages/Index" + ] +} diff --git a/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/resources/dark/element/color.json b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/resources/dark/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..79b11c2747aec33e710fd3a7b2b3c94dd9965499 --- /dev/null +++ b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/resources/dark/element/color.json @@ -0,0 +1,8 @@ +{ + "color": [ + { + "name": "start_window_background", + "value": "#000000" + } + ] +} \ No newline at end of file diff --git a/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/resources/rawfile/test1.mp4 b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/resources/rawfile/test1.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..417649af1c7deea97e41abac156462e99e17b78d --- /dev/null +++ b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/resources/rawfile/test1.mp4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6b92bd019ee0b002b8f7f665e75401cc45190c94e396423494b53f25800354f9 +size 21780300 diff --git a/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/resources/rawfile/test_01.mp3 b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/resources/rawfile/test_01.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..1d8c675e3062dd3260e849ee2a1eaa1de5a4b07c Binary files /dev/null and b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/main/resources/rawfile/test_01.mp3 differ diff --git a/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/mock/Libentry.mock.ets b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/mock/Libentry.mock.ets new file mode 100644 index 0000000000000000000000000000000000000000..82fa70b5693ddab96d237d2d17d943d866b61465 --- /dev/null +++ b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/mock/Libentry.mock.ets @@ -0,0 +1,21 @@ +/* + * 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. + */ +const NativeMock: Record = { + 'add': (a: number, b: number) => { + return a + b; + }, +}; + +export default NativeMock; \ No newline at end of file diff --git a/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/mock/mock-config.json5 b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/mock/mock-config.json5 new file mode 100644 index 0000000000000000000000000000000000000000..98b0ae79f0090e1fc381d54c959fb32c9f7563f4 --- /dev/null +++ b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/mock/mock-config.json5 @@ -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. + */ +{ + "libentry.so": { + "source": "src/mock/Libentry.mock.ets" + } +} \ No newline at end of file diff --git a/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/ohosTest/ets/test/Ability.test.ets b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/ohosTest/ets/test/Ability.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..c78d8926c4ae08670a763eb341b4fccc42d0954a --- /dev/null +++ b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/ohosTest/ets/test/Ability.test.ets @@ -0,0 +1,117 @@ +/* + * 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_AVPlayerArkTS]'; + 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('Slider_001', 0, async (done: Function) => { + hilog.info(DOMAIN, TAG, 'Slider_001 begin'); + + // 点播放 + await driver.delayMs(2000); + await driver.assertComponentExist(ON.type('Image')); + let stack = await driver.findComponent(ON.type('Image')); + + // 暂停 + await stack.click(); + await driver.delayMs(3000); + + // 滑动滑块 + await driver.assertComponentExist(ON.id('Slider')); + let Slider = await driver.findComponent(ON.id('Slider')); + let point = await Slider.getBoundsCenter(); + await driver.drag(point.x - 50, point.y, point.x + 50, point.y, 800); + await driver.delayMs(1000); + + // 播放 + await stack.click(); + await driver.delayMs(1000); + + done(); + hilog.info(DOMAIN, TAG, 'Slider_001 end'); + }) + + /** + * 暂停并退出 + */ + it('Exit_001', 0, async (done: Function) => { + hilog.info(DOMAIN, TAG, 'Exit_001 begin'); + + // 暂停 + await driver.delayMs(8000); + await driver.assertComponentExist(ON.type('Image')); + let stack = await driver.findComponent(ON.type('Image')); + await stack.click(); + await driver.delayMs(2000); + + done(); + hilog.info(DOMAIN, TAG, 'Exit_001 end'); + }) + }) +} \ No newline at end of file diff --git a/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/ohosTest/ets/test/List.test.ets b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/ohosTest/ets/test/List.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..c64e0b06938d246ce044186d4b2d02b500a89e14 --- /dev/null +++ b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/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/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/ohosTest/module.json5 b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/ohosTest/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..f6bdce9946cb02c0385e5a8836c133c93945013d --- /dev/null +++ b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/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 + } +} diff --git a/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/test/List.test.ets b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/test/List.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..a60c87c5cbb0badf7c3fd8975034590e6fafa992 --- /dev/null +++ b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/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 localUnitTest from './LocalUnit.test'; + +export default function testsuite() { + localUnitTest(); +} \ No newline at end of file diff --git a/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/test/LocalUnit.test.ets b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/test/LocalUnit.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..321f9be81fd772a5af6e71dafebf7ed905a6ccff --- /dev/null +++ b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/entry/src/test/LocalUnit.test.ets @@ -0,0 +1,39 @@ +/* + * 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 { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'; + +export default function localUnitTest() { + describe('localUnitTest', () => { + // 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. + }); + }); +} \ No newline at end of file diff --git a/code/DocsSample/Media/AVPlayer/AVPlayerNDK/hvigor/hvigor-config.json5 b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/hvigor/hvigor-config.json5 new file mode 100644 index 0000000000000000000000000000000000000000..4d435603637cbbfe92ac9865537a0c1051810bb1 --- /dev/null +++ b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/hvigor/hvigor-config.json5 @@ -0,0 +1,36 @@ +/* + * 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. + */ +{ + "modelVersion": "5.0.5", + "dependencies": { + }, + "execution": { + // "analyze": "normal", /* Define the build analyze mode. Value: [ "normal" | "advanced" | false ]. Default: "normal" */ + // "daemon": true, /* Enable daemon compilation. Value: [ true | false ]. Default: true */ + // "incremental": true, /* Enable incremental compilation. Value: [ true | false ]. Default: true */ + // "parallel": true, /* Enable parallel compilation. Value: [ true | false ]. Default: true */ + // "typeCheck": false, /* Enable typeCheck. Value: [ true | false ]. Default: false */ + }, + "logging": { + // "level": "info" /* Define the log level. Value: [ "debug" | "info" | "warn" | "error" ]. Default: "info" */ + }, + "debugging": { + // "stacktrace": false /* Disable stacktrace compilation. Value: [ true | false ]. Default: false */ + }, + "nodeOptions": { + // "maxOldSpaceSize": 8192 /* Enable nodeOptions maxOldSpaceSize compilation. Unit M. Used for the daemon process. Default: 8192*/ + // "exposeGC": true /* Enable to trigger garbage collection explicitly. Default: true*/ + } +} diff --git a/code/DocsSample/Media/AVPlayer/AVPlayerNDK/hvigorfile.ts b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..6b365cacd0191d3b1178eb6b9807b1ae0add6271 --- /dev/null +++ b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/hvigorfile.ts @@ -0,0 +1,20 @@ +/* + * 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 { appTasks } from '@ohos/hvigor-ohos-plugin'; + +export default { + system: appTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ + plugins:[] /* Custom plugin to extend the functionality of Hvigor. */ +} diff --git a/code/DocsSample/Media/AVPlayer/AVPlayerNDK/oh-package.json5 b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..38abfd099681aeb547cf83a4966111dd5f4f6d13 --- /dev/null +++ b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/oh-package.json5 @@ -0,0 +1,24 @@ +/* + * 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. + */ +{ + "modelVersion": "5.0.5", + "description": "Please describe the basic information.", + "dependencies": { + }, + "devDependencies": { + "@ohos/hypium": "1.0.21", + "@ohos/hamock": "1.0.0" + } +} diff --git a/code/DocsSample/Media/AVPlayer/AVPlayerNDK/ohosTest.md b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/ohosTest.md new file mode 100644 index 0000000000000000000000000000000000000000..00240974c1b8554b5747250949063ef4f6249e79 --- /dev/null +++ b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/ohosTest.md @@ -0,0 +1,10 @@ +# AVPlayerNDKVideo测试用例归档 + +## 用例表 + +| 测试功能 | 预置条件 | 输入 | 预期输出 | 是否自动 | 测试结果 | +| ---------------- | ------------------ | -------------------- | ---------------------------- | -------- | -------- | +| 拉起应用 | 设备正常运行 | | 成功拉起应用 | 是 | Pass | +| 播放功能 | 进入示例应用 | 点击播放按钮 | 成功播放资源 | 是 | Pass | +| 拖动功能 | 进入示例应用 | 点击、拖动进度条 | 成功改变播放进度 | 是 | Pass | +| 暂停功能 | 进入示例应用 | 点击移动按钮 | 成功暂停播放 | 是 | Pass | diff --git a/code/DocsSample/Media/AVPlayer/AVPlayerNDK/screenshots/AVPlayerNDKVideo.jpeg b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/screenshots/AVPlayerNDKVideo.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..4c1dd7002024c335b7bdc9c1fce3e3d8e560b774 Binary files /dev/null and b/code/DocsSample/Media/AVPlayer/AVPlayerNDK/screenshots/AVPlayerNDKVideo.jpeg differ