diff --git a/1k/fetch.ps1 b/1k/fetch.ps1 index 0e8709f0de6d..3c7bf6f940f0 100644 --- a/1k/fetch.ps1 +++ b/1k/fetch.ps1 @@ -59,7 +59,12 @@ function fetch_repo($url, $name, $dest, $ext) { } if (!(Test-Path $dest -PathType Container)) { - throw "fetch.ps1: the package name mismatch for $out" + $original_lib_src = Join-Path $prefix $Script:url_pkg_name + if (Test-Path $original_lib_src -PathType Container) { + Rename-Item $original_lib_src $dest + } else { + throw "fetch.ps1: the package name mismatch for $out" + } } } } @@ -114,30 +119,27 @@ if (!$url) { } $url_pkg_ext = $null -$url_pkg_name = $null +$Script:url_pkg_name = $null $match_info = [Regex]::Match($url, '(\.git)|(\.zip)|(\.tar\.(gz|bz2|xz))$') if ($match_info.Success) { $url_pkg_ext = $match_info.Value $url_file_name = Split-Path $url -Leaf - $url_pkg_name = $url_file_name.Substring(0, $url_file_name.Length - $url_pkg_ext.Length) + $Script:url_pkg_name = $url_file_name.Substring(0, $url_file_name.Length - $url_pkg_ext.Length) if (!$name) { - $name = $url_pkg_name + $name = $Script:url_pkg_name } } else { throw "fetch.ps1: invalid url, must be endswith .git, .zip, .tar.xx" } +$lib_src = Join-Path $prefix $name $is_git_repo = $url_pkg_ext -eq '.git' if (!$is_git_repo) { $match_info = [Regex]::Match($url, '(\d+\.)+(-)?(\*|\d+)') if ($match_info.Success) { $version = $match_info.Value } - $lib_src = Join-Path $prefix $url_pkg_name -} -else { - $lib_src = Join-Path $prefix $name } if (!$version) { diff --git a/cmake/Modules/AXBuildHelpers.cmake b/cmake/Modules/AXBuildHelpers.cmake index 9563faf35152..28718fbe4699 100644 --- a/cmake/Modules/AXBuildHelpers.cmake +++ b/cmake/Modules/AXBuildHelpers.cmake @@ -238,7 +238,7 @@ function(ax_sync_target_dlls ax_target) # copy libvlc plugins dir for windows if(AX_ENABLE_VLC_MEDIA) add_custom_command(TARGET ${ax_target} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_directory ${_AX_ROOT}/${_AX_THIRDPARTY_NAME}/vlc/win/lib/vlc/plugins + COMMAND ${CMAKE_COMMAND} -E copy_directory ${_AX_ROOT}/cache/vlc/lib/vlc/plugins $/plugins ) endif() diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 8b801e6b26f7..359b226133d2 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -86,23 +86,16 @@ endif() # print renderer backend profile message(AUTHOR_WARNING "AX_USE_GL=${AX_USE_GL}, AX_USE_METAL=${AX_USE_METAL}, AX_GLES_PROFILE=${AX_GLES_PROFILE}") -option (AX_ENABLE_MFMEDIA "Enabling microsoft media foundation" ON) - -if (NOT WINRT) - option (AX_ENABLE_MSEDGE_WEBVIEW2 "Use Microsoft Edge webview2" ON) -else() # we not support webview2 and vidio player for WINRT target - set(AX_ENABLE_MSEDGE_WEBVIEW2 OFF CACHE BOOL "Use Microsoft Edge webview2" FORCE) - # set(AX_ENABLE_MFMEDIA OFF CACHE BOOL "Enabling microsoft media foundation for windows video player" FORCE) -endif() - if (LINUX) include(CheckIncludeFile) check_include_file(vlc/vlc.h _AX_HAVE_VLC) + cmake_dependent_option(AX_ENABLE_VLC_MEDIA "Enabling vlc media" ON "_AX_HAVE_VLC" OFF) endif() -cmake_dependent_option(AX_ENABLE_VLC_MEDIA "Enabling vlc media" ON "_AX_HAVE_VLC" OFF) +cmake_dependent_option(AX_ENABLE_MSEDGE_WEBVIEW2 "Use Microsoft Edge webview2" ON "WIN32 AND NOT WINRT" OFF) -message(STATUS "AX_ENABLE_VLC_MEDIA=${AX_ENABLE_VLC_MEDIA}") +cmake_dependent_option(AX_ENABLE_MFMEDIA "Enabling microsoft media foundation" ON "WIN32" OFF) +cmake_dependent_option(AX_ENABLE_VLC_MEDIA "Enabling vlc media" OFF "(WIN32 AND NOT WINRT) OR LINUX" OFF) if(NOT APPLE AND (NOT EMSCRIPTEN)) set(AX_USE_ALSOFT ON CACHE BOOL "" FORCE) @@ -110,9 +103,8 @@ else() option(AX_USE_ALSOFT "Use ALSOFT on apple" OFF) endif() - option(AX_ENABLE_PHYSICS "Build Physics support" ON) -option(AX_ENABLE_MEDIA "Build media support" ON) +cmake_dependent_option(AX_ENABLE_MEDIA "Build media support" ON "AX_ENABLE_MFMEDIA OR AX_ENABLE_VLC_MEDIA OR APPLE OR ANDROID" OFF) option(AX_ENABLE_AUDIO "Build audio support" ON) option(AX_ENABLE_CONSOLE "Build axmol debug tool: console support" ON) diff --git a/core/media/AndroidMediaEngine.cpp b/core/media/AndroidMediaEngine.cpp index 2dcf95339205..87d5742defbd 100644 --- a/core/media/AndroidMediaEngine.cpp +++ b/core/media/AndroidMediaEngine.cpp @@ -1,3 +1,27 @@ +/**************************************************************************** + Copyright (c) 2019-present Axmol Engine contributors (see AUTHORS.md). + + https://axmolengine.github.io/ + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + #if defined(__ANDROID__) # include "AndroidMediaEngine.h" # include "platform/android/jni/JniHelper.h" @@ -30,6 +54,30 @@ JNIEXPORT void JNICALL Java_org_axmol_lib_AxmolMediaEngine_nativeHandleVideoSamp mediaEngine->handleVideoSample(sampleData, sampleLen, outputX, outputY, videoX, videoY, rotation); } + +JNIEXPORT void JNICALL Java_org_axmol_lib_AxmolMediaEngine_nativeSetDuration(JNIEnv* env, + jclass, + jlong pME, + double duration) +{ + auto mediaEngine = (ax::AndroidMediaEngine*)((uintptr_t)pME); + if (!mediaEngine) + return; + + mediaEngine->updateDuration(duration); +} + +JNIEXPORT void JNICALL Java_org_axmol_lib_AxmolMediaEngine_nativeSetCurrentTime(JNIEnv* env, + jclass, + jlong pME, + double currentTime) +{ + auto mediaEngine = (ax::AndroidMediaEngine*)((uintptr_t)pME); + if (!mediaEngine) + return; + + mediaEngine->updateCurrentTime(currentTime); +} } NS_AX_BEGIN diff --git a/core/media/AndroidMediaEngine.h b/core/media/AndroidMediaEngine.h index 63949ee455eb..839997263326 100644 --- a/core/media/AndroidMediaEngine.h +++ b/core/media/AndroidMediaEngine.h @@ -1,4 +1,26 @@ +/**************************************************************************** + Copyright (c) 2019-present Axmol Engine contributors (see AUTHORS.md). + https://axmolengine.github.io/ + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ #pragma once #if defined(__ANDROID__) @@ -28,6 +50,8 @@ class AndroidMediaEngine : public MediaEngine bool setLoop(bool bLooping) override; bool setRate(double fRate) override; bool setCurrentTime(double fSeekTimeInSec) override; + double getCurrentTime() override { return _currentTime; } + double getDuration() override { return _duration; } bool play() override; bool pause() override; bool stop() override; @@ -36,6 +60,8 @@ class AndroidMediaEngine : public MediaEngine bool transferVideoFrame() override; void handleVideoSample(const uint8_t* buf, size_t len, int outputX, int outputY, int videoX, int videoY, int rotation); + void updateCurrentTime(double currentTime) { _currentTime = currentTime; } + void updateDuration(double duration) { _duration = duration; } private: void* context{}; // java object strong-refs @@ -49,6 +75,9 @@ class AndroidMediaEngine : public MediaEngine yasio::byte_buffer _frameBuffer1; // for write yasio::byte_buffer _frameBuffer2; // for read mutable std::mutex _frameBuffer1Mtx; + + double _currentTime{}; + double _duration{}; }; struct AndroidMediaEngineFactory : public MediaEngineFactory diff --git a/core/media/AvfMediaEngine.h b/core/media/AvfMediaEngine.h index 2a470334e33b..cd75b1ee35e4 100644 --- a/core/media/AvfMediaEngine.h +++ b/core/media/AvfMediaEngine.h @@ -1,3 +1,26 @@ +/**************************************************************************** + Copyright (c) 2019-present Axmol Engine contributors (see AUTHORS.md). + + https://axmolengine.github.io/ + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ #pragma once #include "MediaEngine.h" @@ -30,6 +53,8 @@ class AvfMediaEngine : public MediaEngine bool setLoop(bool bLooping) override; bool setRate(double fRate) override; bool setCurrentTime(double fSeekTimeInSec) override; + double getCurrentTime() override; + double getDuration() override; bool play() override; bool pause() override; bool stop() override; diff --git a/core/media/AvfMediaEngine.mm b/core/media/AvfMediaEngine.mm index b90af9fcea7d..8525360cf2c8 100644 --- a/core/media/AvfMediaEngine.mm +++ b/core/media/AvfMediaEngine.mm @@ -1,3 +1,27 @@ +/**************************************************************************** + Copyright (c) 2019-present Axmol Engine contributors (see AUTHORS.md). + + https://axmolengine.github.io/ + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + #include "AvfMediaEngine.h" #if defined(__APPLE__) @@ -457,6 +481,29 @@ - (void)observeValueForKeyPath:(NSString*)keyPath [_player seekToTime:CMTimeMake(fSeekTimeInSec, 1)]; return true; } + +double AvfMediaEngine::getCurrentTime() +{ + if (_player != nil) { + CMTime currTime = [_player currentTime]; + if (CMTIME_IS_VALID(currTime)) + return CMTimeGetSeconds(currTime); + } + + return 0.0; +} + +double AvfMediaEngine::getDuration() +{ + if (_player != nil) { + if (_player.currentItem != nil) { + CMTime duration = _player.currentItem.asset.duration; + return CMTimeGetSeconds(duration); + } + } + return 0.0; +} + bool AvfMediaEngine::play() { if (_state != MEMediaState::Playing) diff --git a/core/media/MediaEngine.cpp b/core/media/MediaEngine.cpp index 559918956b42..182623b41db7 100644 --- a/core/media/MediaEngine.cpp +++ b/core/media/MediaEngine.cpp @@ -1,3 +1,27 @@ +/**************************************************************************** + Copyright (c) 2019-present Axmol Engine contributors (see AUTHORS.md). + + https://axmolengine.github.io/ + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + #include "MediaEngine.h" #if defined(WINAPI_FAMILY) @@ -40,7 +64,11 @@ std::unique_ptr MediaEngineFactory::create() { #if defined(WINAPI_FAMILY) # if WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP && !defined(AXME_USE_IMFME) +# if defined(AX_ENABLE_MFMEDIA) return axstd::static_pointer_cast(std::make_unique()); +# elif (AX_ENABLE_VLC_MEDIA) + return axstd::static_pointer_cast(std::make_unique()); +# endif # else return axstd::static_pointer_cast(std::make_unique()); # endif diff --git a/core/media/MediaEngine.h b/core/media/MediaEngine.h index cfedf1a84737..dbbb6557995b 100644 --- a/core/media/MediaEngine.h +++ b/core/media/MediaEngine.h @@ -1,3 +1,26 @@ +/**************************************************************************** + Copyright (c) 2019-present Axmol Engine contributors (see AUTHORS.md). + + https://axmolengine.github.io/ + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ #pragma once @@ -199,6 +222,8 @@ class MediaEngine virtual bool setLoop(bool bLooping) = 0; virtual bool setRate(double fRate) = 0; virtual bool setCurrentTime(double fSeekTimeInSec) = 0; + virtual double getCurrentTime() = 0; + virtual double getDuration() = 0; virtual bool play() = 0; virtual bool pause() = 0; virtual bool stop() = 0; diff --git a/core/media/MfMediaEngine.cpp b/core/media/MfMediaEngine.cpp index 001b6ca41adf..3fe024ceaa3a 100644 --- a/core/media/MfMediaEngine.cpp +++ b/core/media/MfMediaEngine.cpp @@ -3,6 +3,9 @@ // // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +// Copyright (c) 2019-present Axmol Engine contributors (see AUTHORS.md). +// +// https://axmolengine.github.io/ //------------------------------------------------------------------------------------- #include "media/MfMediaEngine.h" @@ -160,7 +163,9 @@ bool MfMediaEngine::play() bool MfMediaEngine::pause() { if (m_mediaEngine) + { return SUCCEEDED(m_mediaEngine->Pause()); + } return false; } @@ -227,6 +232,23 @@ bool MfMediaEngine::setCurrentTime(double fPosInSeconds) return false; } +double MfMediaEngine::getCurrentTime() +{ + if (m_mediaEngine) + return m_mediaEngine->GetCurrentTime(); + + return 0.0; +} + +double MfMediaEngine::getDuration() +{ + if (m_mediaEngine) + return m_mediaEngine->GetDuration(); + + return 0.0; +} + + bool MfMediaEngine::transferVideoFrame() { if (m_mediaEngine != nullptr && m_state == MEMediaState::Playing) diff --git a/core/media/MfMediaEngine.h b/core/media/MfMediaEngine.h index 1beb1b1f08f7..2a988017aec8 100644 --- a/core/media/MfMediaEngine.h +++ b/core/media/MfMediaEngine.h @@ -5,6 +5,9 @@ // // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +// Copyright (c) 2019-present Axmol Engine contributors (see AUTHORS.md). +// +// https://axmolengine.github.io/ //------------------------------------------------------------------------------------- #pragma once @@ -89,6 +92,8 @@ class MfMediaEngine : public IMFNotify, public MediaEngine bool isPlaybackEnded() const override { return m_bPlaybackEnded; } bool setCurrentTime(double fPosInSeconds) override; + double getCurrentTime() override; + double getDuration() override; MEMediaState getState() const override { return m_state; } diff --git a/core/media/VlcMediaEngine.cpp b/core/media/VlcMediaEngine.cpp index d720e262232d..1b663927901e 100644 --- a/core/media/VlcMediaEngine.cpp +++ b/core/media/VlcMediaEngine.cpp @@ -5,6 +5,30 @@ required codec-runtime: ubuntu-restricted-extras (contains intel-media-va-driver sudo apt install ubuntu-restricted-extras */ +/**************************************************************************** + Copyright (c) 2019-present Axmol Engine contributors (see AUTHORS.md). + + https://axmolengine.github.io/ + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + #if defined(AX_ENABLE_VLC_MEDIA) # include "VlcMediaEngine.h" @@ -389,6 +413,17 @@ bool VlcMediaEngine::setCurrentTime(double fSeekTimeInSec) # endif return true; } + +double VlcMediaEngine::getCurrentTime() +{ + return libvlc_media_player_get_time(_mp) / 1000.0; +} + +double VlcMediaEngine::getDuration() +{ + return libvlc_media_player_get_length(_mp) / 1000.0; +} + bool VlcMediaEngine::play() { if (_mlp && _state != MEMediaState::Closed) diff --git a/core/media/VlcMediaEngine.h b/core/media/VlcMediaEngine.h index 00eb78fee592..0b3962be33aa 100644 --- a/core/media/VlcMediaEngine.h +++ b/core/media/VlcMediaEngine.h @@ -1,4 +1,7 @@ // VlcMediaEngine.h +// Copyright (c) 2019-present Axmol Engine contributors (see AUTHORS.md). +// https://axmolengine.github.io/ + #pragma once # include "MediaEngine.h" @@ -31,6 +34,8 @@ class VlcMediaEngine : public MediaEngine bool setLoop(bool bLooping) override; bool setRate(double fRate) override; bool setCurrentTime(double fSeekTimeInSec) override; + double getCurrentTime() override; + double getDuration() override; bool play() override; bool pause() override; bool stop() override; diff --git a/core/media/WmfMediaEngine.cpp b/core/media/WmfMediaEngine.cpp index 3289539a757e..b4db6245a2fb 100644 --- a/core/media/WmfMediaEngine.cpp +++ b/core/media/WmfMediaEngine.cpp @@ -9,6 +9,9 @@ // // Copyright (c) Microsoft Corporation. All rights reserved. // +// Copyright (c) 2019-present Axmol Engine contributors (see AUTHORS.md). +// +// https://axmolengine.github.io/ ////////////////////////////////////////////////////////////////////////// #include "WmfMediaEngine.h" @@ -894,6 +897,16 @@ MFTIME WmfMediaEngine::GetCurrentPosition() const return hnsPosition; } +double WmfMediaEngine::getCurrentTime() +{ + return GetCurrentPosition() / (std::nano::den / 100.0); +} + +double WmfMediaEngine::getDuration() +{ + return GetDuration() / (std::nano::den / 100.0); +} + HRESULT WmfMediaEngine::SetPosition(MFTIME hnsPosition) { AutoLock lock(m_critsec); diff --git a/core/media/WmfMediaEngine.h b/core/media/WmfMediaEngine.h index 5477621c8e4c..1224351ce0b7 100644 --- a/core/media/WmfMediaEngine.h +++ b/core/media/WmfMediaEngine.h @@ -15,6 +15,8 @@ // https://github.com/microsoft/Windows-classic-samples/tree/main/Samples/Win7Samples/multimedia/mediafoundation/protectedplayback // b. https://docs.microsoft.com/en-us/windows/win32/medfound/seeking--fast-forward--and-reverse-play // +// Copyright (c) 2019-present Axmol Engine contributors (see AUTHORS.md). +// https://axmolengine.github.io/ ////////////////////////////////////////////////////////////////////////// #if defined(_WIN32) @@ -160,6 +162,9 @@ class WmfMediaEngine : public IMFAsyncCallback, public MediaEngine return SUCCEEDED(SetPosition(static_cast((std::nano::den / 100) * sec))); } + double getCurrentTime() override; + double getDuration() override; + // Set position in 100ns units, will reply if play ended // see: https://docs.microsoft.com/en-us/windows/win32/medfound/mf-pd-duration-attribute HRESULT SetPosition(MFTIME hnsPosition); diff --git a/core/platform/android/java/src/org/axmol/lib/AxmolMediaEngine.java b/core/platform/android/java/src/org/axmol/lib/AxmolMediaEngine.java index d47411f079ef..2873fb7fd518 100644 --- a/core/platform/android/java/src/org/axmol/lib/AxmolMediaEngine.java +++ b/core/platform/android/java/src/org/axmol/lib/AxmolMediaEngine.java @@ -1,3 +1,26 @@ +/**************************************************************************** + Copyright (c) 2019-present Axmol Engine contributors (see AUTHORS.md). + + https://axmolengine.github.io/ + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ package org.axmol.lib; import android.app.Activity; @@ -82,6 +105,8 @@ public class AxmolMediaEngine extends DefaultRenderersFactory implements Player. /** ------ native methods ------- */ public static native void nativeHandleEvent(long nativeObj, int arg1); public static native void nativeHandleVideoSample(long nativeObj, ByteBuffer sampleData, int sampleLen, int outputX, int outputY, int videoX, int videoY, int rotation); + public static native void nativeSetDuration(long nativeObj, double duration); + public static native void nativeSetCurrentTime(long nativeObj, double currentTime); public static void setContext(Activity activity) { sContext = activity.getApplicationContext(); @@ -251,8 +276,10 @@ public boolean pause() { public boolean stop() { if(mPlayer == null) return false; AxmolEngine.getActivity().runOnUiThread(() -> { - if (mPlayer != null) + if (mPlayer != null) { mPlayer.stop(); + nativeSetDuration(mNativeObj,0.0); + } }); return true; } @@ -317,6 +344,13 @@ public void processVideoFrame(MediaCodecAdapter codec, int index, long presentat ByteBuffer tmpBuffer = codec.getOutputBuffer(index); nativeHandleVideoSample(mNativeObj, tmpBuffer, tmpBuffer.remaining(), mOutputDim.x, mOutputDim.y, mVideoDim.x, mVideoDim.y, mVideoRotation); + + AxmolEngine.getActivity().runOnUiThread(() -> { + if (mPlayer != null) { + long currentPos = mPlayer.getCurrentPosition(); + nativeSetCurrentTime(mNativeObj,currentPos / 1000.0); + } + }); } @Override @@ -351,6 +385,11 @@ public void onPlaybackStateChanged(int playbackState) { switch (playbackState) { case Player.STATE_READY: Log.d(TAG, "[Individual]onPlaybackStateChanged: decoder: " + mVideoRenderer.getCodecName()); + AxmolEngine.getActivity().runOnUiThread(() -> { + if (mPlayer != null) { + nativeSetDuration(mNativeObj,mPlayer.getContentDuration() / 1000.0); + } + }); break; case Player.STATE_ENDED: mPlaybackEnded = true; diff --git a/core/ui/CMakeLists.txt b/core/ui/CMakeLists.txt index dff4a25df132..97e778bfbbfd 100644 --- a/core/ui/CMakeLists.txt +++ b/core/ui/CMakeLists.txt @@ -19,15 +19,6 @@ if(WINDOWS) list(APPEND _AX_UI_SPECIFIC_HEADER ui/UIWebView/UIWebViewImpl-win32.h ui/UIWebView/UIWebView.h) list(APPEND _AX_UI_SPECIFIC_SRC ui/UIWebView/UIWebViewImpl-win32.cpp ui/UIWebView/UIWebView.cpp) endif() - - if (AX_ENABLE_MFMEDIA) - set(_AX_UI_SPECIFIC_HEADER ${_AX_UI_SPECIFIC_HEADER} - ui/UIMediaPlayer.h - ) - set(_AX_UI_SPECIFIC_SRC ${_AX_UI_SPECIFIC_SRC} - ui/UIMediaPlayer.cpp - ) - endif() elseif(APPLE) if(MACOSX) set(_AX_UI_SPECIFIC_HEADER @@ -90,8 +81,6 @@ elseif(APPLE) ) endif() endif() - set(_AX_UI_SPECIFIC_HEADER ui/UIMediaPlayer.h ${_AX_UI_SPECIFIC_HEADER}) - set(_AX_UI_SPECIFIC_SRC ui/UIMediaPlayer.cpp ${_AX_UI_SPECIFIC_SRC}) elseif(LINUX) set(_AX_UI_SPECIFIC_HEADER ui/UIEditBox/UIEditBoxImpl-linux.h @@ -99,10 +88,6 @@ elseif(LINUX) set(_AX_UI_SPECIFIC_SRC ui/UIEditBox/UIEditBoxImpl-linux.cpp ) - if(AX_ENABLE_VLC_MEDIA) - set(_AX_UI_SPECIFIC_HEADER ui/UIMediaPlayer.h ${_AX_UI_SPECIFIC_HEADER}) - set(_AX_UI_SPECIFIC_SRC ui/UIMediaPlayer.cpp ${_AX_UI_SPECIFIC_SRC}) - endif() elseif(EMSCRIPTEN) set(_AX_UI_SPECIFIC_SRC ui/UIEditBox/UIEditBoxImpl-wasm.cpp @@ -119,8 +104,12 @@ elseif(ANDROID) # it's special for android, not a common file ui/UIWebView/UIWebView.cpp ) - set(_AX_UI_SPECIFIC_HEADER ui/UIMediaPlayer.h ${_AX_UI_SPECIFIC_HEADER}) - set(_AX_UI_SPECIFIC_SRC ui/UIMediaPlayer.cpp ${_AX_UI_SPECIFIC_SRC}) + +endif() + +if(AX_ENABLE_MEDIA) + set(_AX_UI_SPECIFIC_HEADER ui/UIMediaPlayer.h ${_AX_UI_SPECIFIC_HEADER}) + set(_AX_UI_SPECIFIC_SRC ui/UIMediaPlayer.cpp ${_AX_UI_SPECIFIC_SRC}) endif() set(_AX_UI_HEADER diff --git a/core/ui/UIMediaPlayer.cpp b/core/ui/UIMediaPlayer.cpp index 3d2f31ed5149..eb4cc161bbaf 100644 --- a/core/ui/UIMediaPlayer.cpp +++ b/core/ui/UIMediaPlayer.cpp @@ -27,7 +27,7 @@ #include "ui/UIMediaPlayer.h" // Now, common implementation based on redesigned MediaEngine is enable for windows and macOS -#if defined(_WIN32) || defined(__APPLE__) || defined(__ANDROID__) || defined(AX_ENABLE_VLC_MEDIA) +#if defined(AX_ENABLE_MEDIA) # include # include # include @@ -37,6 +37,8 @@ # include "ui/UIHelper.h" # include "media/MediaEngine.h" # include "ui/LayoutHelper.h" +# include "UIButton.h" +# include "UILayout.h" # include "yasio/byte_buffer.hpp" //----------------------------------------------------------------------------------------------------------- @@ -136,20 +138,659 @@ struct PrivateVideoDescriptor PS_SET_UNIFORM_R(ps, "colorTransform", colorTransform); } }; + +std::unique_ptr _meFactory = MediaEngineFactory::create(); + +const char* BODY_IMAGE_1_PIXEL_HEIGHT = + "iVBORw0KGgoAAAANSUhEUgAAAAwAAAABCAMAAADdNb8LAAAAA1BMVEX///+nxBvIAAAACklEQVR4AWNABgAADQABYc2cpAAAAABJRU5ErkJggg=="; + +const char* BODY_IMAGE_1_PIXEL_HEIGHT_KEY = "/__bodyImage"; + +constexpr auto TIMELINE_BAR_HEIGHT = 12.f; + +RefPtr g_mediaControlsTexture = nullptr; + +enum class MediaControlButtonId +{ + Play, + Stop, + Pause, + EnterFullscreen, + ExitFullscreen, + TimelineSliderButton +}; + +std::map g_mediaControlTextureRegions; + +void createMediaControlTexture() +{ + if (g_mediaControlsTexture) + return; + + constexpr auto panelW = 64.f; + constexpr auto panelH = 64.f; + constexpr auto iconW = 32.f; + constexpr auto iconH = 32.f; + constexpr auto gap = 10.f; + constexpr auto border = 2; + + auto* drawNode = DrawNode::create(); + + auto DrawStop = [&](const Vec2& middle) -> void { + auto s = Vec2(middle.x - iconW / 2.f, middle.y + iconH / 2.f); + drawNode->drawSolidRect(s, s + Vec2(iconW, -iconH), Color4F::WHITE); + }; + + auto DrawPlay = [&](const Vec2& middle) -> void { + auto p1 = Vec2(middle.x - iconW / 2.f, middle.y + iconH / 2.f); + auto p2 = Vec2(middle.x + iconW / 2.f, middle.y); + auto p3 = Vec2(middle.x - iconW / 2.f, middle.y - iconH / 2.f); + + drawNode->drawTriangle(p1, p2, p3, Color4B::WHITE); + }; + + auto DrawPause = [&](const Vec2& middle) -> void { + auto start = Vec2(middle.x - 3, middle.y + iconH / 2.f); + drawNode->drawSolidRect(start, start + Vec2(-6, -iconH), Color4B::WHITE); + + start = Vec2(middle.x + 3, middle.y + iconH / 2.f); + drawNode->drawSolidRect(start, start + Vec2(6, -iconH), Color4B::WHITE); + }; + + auto DrawEnterFullscreen = [&](const Vec2& middle) -> void { + auto topLeft = Vec2(middle.x - panelW / 2.f + 6, middle.y + panelH / 2.f - 6); + auto topRight = Vec2(middle.x + panelW / 2.f - 6, middle.y + panelH / 2.f - 6); + auto bottomLeft = Vec2(middle.x - panelW / 2.f + 6, middle.y - panelH / 2.f + 6); + auto bottomRight = Vec2(middle.x + panelW / 2.f - 6, middle.y - panelH / 2.f + 6); + + // Top left + drawNode->drawSolidRect(topLeft, topLeft + Vec2(20, -6), Color4B::WHITE); + drawNode->drawSolidRect(topLeft, topLeft + Vec2(6, -20), Color4B::WHITE); + + // Top right + drawNode->drawSolidRect(topRight, topRight + Vec2(-20, -6), Color4B::WHITE); + drawNode->drawSolidRect(topRight, topRight + Vec2(-6, -20), Color4B::WHITE); + + // Bottom left + drawNode->drawSolidRect(bottomLeft, bottomLeft + Vec2(20, 6), Color4B::WHITE); + drawNode->drawSolidRect(bottomLeft, bottomLeft + Vec2(6, 20), Color4B::WHITE); + + // Bottom right + drawNode->drawSolidRect(bottomRight, bottomRight + Vec2(-20, 6), Color4B::WHITE); + drawNode->drawSolidRect(bottomRight, bottomRight + Vec2(-6, 20), Color4B::WHITE); + }; + + auto DrawExitFullScreen = [&](const Vec2& middle) -> void { + auto topLeft = Vec2(middle.x - 4, middle.y + 4); + auto topRight = Vec2(middle.x + 4, middle.y + 4); + auto bottomLeft = Vec2(middle.x - 4, middle.y - 4); + auto bottomRight = Vec2(middle.x + 4, middle.y - 4); + + // Top left + drawNode->drawSolidRect(topLeft, topLeft + Vec2(-20, 6), Color4B::WHITE); + drawNode->drawSolidRect(topLeft, topLeft + Vec2(-6, 20), Color4B::WHITE); + + // Top right + drawNode->drawSolidRect(topRight, topRight + Vec2(20, 6), Color4B::WHITE); + drawNode->drawSolidRect(topRight, topRight + Vec2(6, 20), Color4B::WHITE); + + // Bottom left + drawNode->drawSolidRect(bottomLeft, bottomLeft + Vec2(-20, -6), Color4B::WHITE); + drawNode->drawSolidRect(bottomLeft, bottomLeft + Vec2(-6, -20), Color4B::WHITE); + + // Bottom right + drawNode->drawSolidRect(bottomRight, bottomRight + Vec2(20, -6), Color4B::WHITE); + drawNode->drawSolidRect(bottomRight, bottomRight + Vec2(6, -20), Color4B::WHITE); + }; + + auto DrawSliderControlButton = [&](const Vec2& middle) -> void { + drawNode->drawSolidCircle(middle, panelW / 2, 0, 180, Color4B::WHITE); + }; + + std::map> items = { + {MediaControlButtonId::Play, DrawPlay}, + {MediaControlButtonId::Stop, DrawStop}, + {MediaControlButtonId::Pause, DrawPause}, + {MediaControlButtonId::EnterFullscreen, DrawEnterFullscreen}, + {MediaControlButtonId::ExitFullscreen, DrawExitFullScreen}, + {MediaControlButtonId::TimelineSliderButton, DrawSliderControlButton}}; + + auto nextPow2 = [](int v) -> int { + int p = 1; + while (p < v) + { + p = p * 2; + } + return p; + }; + + auto numItems = static_cast(items.size()); + auto totalWidth = nextPow2(numItems * panelW + (numItems - 1) * gap + (border * 2)); + auto totalHeight = nextPow2(border * 2 + panelH); + auto imageSize = Size(static_cast(totalWidth), static_cast(totalHeight)); + auto* node = Node::create(); + node->setContentSize(imageSize); + node->setIgnoreAnchorPointForPosition(false); + node->setAnchorPoint(Vec2::ANCHOR_BOTTOM_LEFT); + node->setPosition(0, 0); + node->addChild(drawNode); + + auto* rt = RenderTexture::create(totalWidth, totalHeight, PixelFormat::RGBA8, false); + rt->beginWithClear(0, 0, 0, 0); + + g_mediaControlTextureRegions.clear(); + + int i = 0; + for (auto&& item : items) + { + auto midPoint = + Vec2(border + (i * panelW) + (i * gap) + (panelW / 2.f), imageSize.height - border - (panelH / 2.f)); + item.second(midPoint); + g_mediaControlTextureRegions[item.first] = + Rect(border + (panelW * i) + (gap * i), imageSize.height - border - panelH, panelW, panelH); + ++i; + } + + node->visit(); + rt->end(); + Director::getInstance()->getRenderer()->render(); + + g_mediaControlsTexture = rt->getSprite()->getTexture(); +} + } // namespace -static std::unique_ptr _meFactory = MediaEngineFactory::create(); +static const float ZOOM_ACTION_TIME_STEP = 0.05f; + +MediaPlayerControl* MediaPlayerControl::create(SpriteFrame* frame) +{ + auto* widget = new MediaPlayerControl(); + if (widget->init(frame)) + { + widget->autorelease(); + return widget; + } + AX_SAFE_DELETE(widget); + return nullptr; +} + +MediaPlayerControl::~MediaPlayerControl() +{ + AX_SAFE_RELEASE(_overlay); +} + +bool MediaPlayerControl::init(SpriteFrame* frame) +{ + if (!Button::init("")) + { + return false; + } + + if (frame) + { + _overlay = Sprite::createWithSpriteFrame(frame); + AX_SAFE_RETAIN(_overlay); + auto spriteSize = _overlay->getContentSize(); + setContentSize(spriteSize); + _overlay->setAnchorPoint(Vec2::ANCHOR_MIDDLE); + _overlay->setPosition(_contentSize.width * 0.5f, _contentSize.height * 0.5f); + addProtectedChild(_overlay, -2, -1); + + if (!_ignoreSize && _customSize.equals(Vec2::ZERO)) + { + _customSize = _overlay->getContentSize(); + } + this->updateChildrenDisplayedRGBA(); + if (_unifySize) + { + if (!_scale9Enabled) + { + updateContentSizeWithTextureSize(spriteSize); + } + } + else + { + updateContentSizeWithTextureSize(spriteSize); + } + } + + return true; +} + +void MediaPlayerControl::onSizeChanged() +{ + Button::onSizeChanged(); + if (_overlay) + { + _overlay->setPosition(_contentSize.width * 0.5f, _contentSize.height * 0.5f); + } +} + +Vec2 MediaPlayerControl::getVirtualRendererSize() const +{ + if (_unifySize) + { + return this->getNormalSize(); + } + + if (nullptr != _overlay) + { + Vec2 overlaySize = _overlay->getContentSize(); + if (!_normalTextureLoaded) + { + return overlaySize; + } + } + return _normalTextureSize; +} + +Vec2 MediaPlayerControl::getNormalSize() const +{ + if (_overlay) + { + return _overlay->getContentSize(); + } + + return Button::getNormalSize(); +} + +void MediaPlayerControl::onPressStateChangedToNormal() +{ + Button::onPressStateChangedToNormal(); + + if (nullptr != _overlay) + { + _overlay->stopAllActions(); + if (_unifySize) + { + Action* zoomTitleAction = ScaleTo::create(ZOOM_ACTION_TIME_STEP, 1.0f, 1.0f); + _overlay->runAction(zoomTitleAction); + } + else + { + _overlay->setScaleX(1.0f); + _overlay->setScaleY(1.0f); + } + } +} + +void MediaPlayerControl::onPressStateChangedToPressed() +{ + Button::onPressStateChangedToPressed(); + if (nullptr != _overlay) + { + _overlay->stopAllActions(); + Action* zoomTitleAction = ScaleTo::create(ZOOM_ACTION_TIME_STEP, 1.0f + _zoomScale, 1.0f + _zoomScale); + _overlay->runAction(zoomTitleAction); + } +} + +void MediaPlayerControl::onPressStateChangedToDisabled() +{ + Button::onPressStateChangedToDisabled(); + if (nullptr != _overlay) + { + _overlay->setScale(1.0); + } +} + +BasicMediaController::BasicMediaController(MediaPlayer* player) + : MediaController(player) +{ +} + +BasicMediaController* BasicMediaController::create(MediaPlayer* mediaPlayer) +{ + auto* widget = new BasicMediaController(mediaPlayer); + if (widget->init()) + { + widget->autorelease(); + return widget; + } + AX_SAFE_DELETE(widget); + return nullptr; +} + +bool BasicMediaController::init() +{ + createMediaControlTexture(); + + if (!Widget::init()) + { + return false; + } + + setTouchEnabled(true); + setCascadeOpacityEnabled(false); + updateControllerState(); + if (_mediaPlayer) + { + setContentSize(_mediaPlayer->getContentSize()); + } + return true; +} + +void BasicMediaController::initRenderer() +{ + Widget::initRenderer(); + createControls(); +} + +void BasicMediaController::onPressStateChangedToPressed() +{ + _lastTouch = std::chrono::steady_clock::now(); + + if (_controlPanel->getOpacity() == 255) + { + return; + } + + updateControllerState(); + + _mediaOverlay->runAction(Sequence::create(FadeTo::create(0.5f, 150), nullptr)); + _controlPanel->runAction(Sequence::create(FadeIn::create(0.5f), CallFunc::create([this] { + if (_controlPanel->isScheduled("__media_controller_fader"sv)) + return; + + _controlPanel->schedule( + [this](float) { + auto now = std::chrono::steady_clock::now(); + auto deltaTime = std::chrono::duration_cast(now - _lastTouch); + if (deltaTime > std::chrono::milliseconds{2500}) + { + _controlPanel->unschedule("__media_controller_fader"sv); + _controlPanel->runAction(Sequence::create(FadeOut::create(0.5f), nullptr)); + _mediaOverlay->runAction(Sequence::create(FadeOut::create(0.5f), nullptr)); + } + }, 1.f, "__media_controller_fader"sv); + }), nullptr)); +} + +void BasicMediaController::setContentSize(const Vec2& contentSize) +{ + Widget::setContentSize(contentSize); + updateControlsForContentSize(contentSize); + updateControllerState(); +} + +void BasicMediaController::update(float delta) +{ + Widget::update(delta); + updateControls(); +} + +void BasicMediaController::onEnter() +{ + Widget::onEnter(); + scheduleUpdate(); +} + +void BasicMediaController::setGlobalZOrder(float globalZOrder) +{ + Widget::setGlobalZOrder(globalZOrder); + updateControlsGlobalZ(globalZOrder); +} + +void BasicMediaController::updateControllerState() +{ + if (!_mediaPlayer) + return; + + auto state = _mediaPlayer->getState(); + if (state == MediaPlayer::MediaState::LOADING || + state == MediaPlayer::MediaState::CLOSED || + state == MediaPlayer::MediaState::ERROR) + { + _playButton->setVisible(false); + _pauseButton->setVisible(false); + _stopButton->setVisible(false); + _timelineTotal->setVisible(false); + _fullScreenExitButton->setVisible(false); + _fullScreenEnterButton->setVisible(false); + } + else + { + _timelineTotal->setVisible(true); + _fullScreenExitButton->setVisible(_mediaPlayer->isFullScreenEnabled()); + _fullScreenEnterButton->setVisible(!_mediaPlayer->isFullScreenEnabled()); + + switch (state) + { + case MediaPlayer::MediaState::PLAYING: + _playButton->setVisible(false); + _pauseButton->setVisible(true); + _stopButton->setVisible(true); + break; + case MediaPlayer::MediaState::PAUSED: + _playButton->setVisible(true); + _pauseButton->setVisible(false); + _stopButton->setVisible(true); + break; + case MediaPlayer::MediaState::STOPPED: + case MediaPlayer::MediaState::FINISHED: + _playButton->setVisible(true); + _pauseButton->setVisible(false); + _stopButton->setVisible(false); + break; + default:; + } + } +} + +void BasicMediaController::createControls() +{ + const auto& contentSize = getContentSize(); + auto scale = Director::getInstance()->getGLView()->getScaleY(); + + _mediaOverlay = Layout::create(); + _mediaOverlay->setBackGroundColor(Color3B::BLACK); + _mediaOverlay->setBackGroundColorType(Layout::BackGroundColorType::SOLID); + _mediaOverlay->setAnchorPoint(Vec2::ANCHOR_MIDDLE); + _mediaOverlay->setPositionNormalized(Vec2(0.5f, 0.5f)); + _mediaOverlay->setContentSize(contentSize); + _mediaOverlay->setOpacity(0); + addProtectedChild(_mediaOverlay, 1); + + _controlPanel = Widget::create(); + _controlPanel->setContentSize(contentSize); + _controlPanel->setPositionNormalized(Vec2(0.5f, 0.5f)); + _controlPanel->setAnchorPoint(Vec2::ANCHOR_MIDDLE); + _controlPanel->setCascadeOpacityEnabled(true); + _controlPanel->setOpacity(0); + addProtectedChild(_controlPanel, 10); + + _primaryButtonPanel = Widget::create(); + _primaryButtonPanel->setContentSize(Vec2(150, 60)); + _primaryButtonPanel->setAnchorPoint(Vec2::ANCHOR_MIDDLE); + _primaryButtonPanel->setPositionNormalized(Vec2(0.5f, 0.5f)); + _primaryButtonPanel->setScale(1 / scale); + _controlPanel->addProtectedChild(_primaryButtonPanel); + + _playButton = MediaPlayerControl::create(SpriteFrame::createWithTexture( + g_mediaControlsTexture, g_mediaControlTextureRegions[MediaControlButtonId::Play])); + _playButton->addClickEventListener([this](Ref* ref) { + if (_controlPanel->getOpacity() <= 50) + return; + _playRate = 1.f; + _mediaPlayer->setPlayRate(_playRate); + _mediaPlayer->play(); + updateControllerState(); + }); + _playButton->setSwallowTouches(false); + _playButton->setPositionNormalized(Vec2(0.25f, 0.5f)); + _playButton->setCascadeOpacityEnabled(true); + _playButton->setVisible(false); + _primaryButtonPanel->addProtectedChild(_playButton, 1, -1); + + _stopButton = MediaPlayerControl::create(SpriteFrame::createWithTexture( + g_mediaControlsTexture, g_mediaControlTextureRegions[MediaControlButtonId::Stop])); + _stopButton->addClickEventListener([this](Ref* ref) { + if (_controlPanel->getOpacity() <= 50) + return; + _playRate = 1.f; + _mediaPlayer->setPlayRate(_playRate); + _mediaPlayer->stop(); + updateControllerState(); + }); + _stopButton->setSwallowTouches(false); + _stopButton->setPositionNormalized(Vec2(0.75f, 0.5f)); + _stopButton->setCascadeOpacityEnabled(true); + _stopButton->setVisible(false); + _primaryButtonPanel->addProtectedChild(_stopButton, 1, -1); + + _pauseButton = MediaPlayerControl::create(SpriteFrame::createWithTexture( + g_mediaControlsTexture, g_mediaControlTextureRegions[MediaControlButtonId::Pause])); + _pauseButton->addClickEventListener([this](Ref* ref) { + if (_controlPanel->getOpacity() <= 50) + return; + _playRate = 1.f; + _mediaPlayer->setPlayRate(_playRate); + _mediaPlayer->pause(); + updateControllerState(); + }); + _pauseButton->setSwallowTouches(false); + _pauseButton->setPositionNormalized(Vec2(0.25f, 0.5f)); + _pauseButton->setCascadeOpacityEnabled(true); + _pauseButton->setVisible(false); + _primaryButtonPanel->addProtectedChild(_pauseButton, 1, -1); + + _fullScreenEnterButton = MediaPlayerControl::create(SpriteFrame::createWithTexture( + g_mediaControlsTexture, g_mediaControlTextureRegions[MediaControlButtonId::EnterFullscreen])); + _fullScreenEnterButton->addClickEventListener([this](Ref* ref) { + if (_controlPanel->getOpacity() <= 50) + return; + _mediaPlayer->setFullScreenEnabled(true); + updateControllerState(); + }); + _fullScreenEnterButton->setSwallowTouches(false); + _fullScreenEnterButton->setAnchorPoint(Vec2::ANCHOR_TOP_LEFT); + _fullScreenEnterButton->setPositionNormalized(Vec2(0.05f, 0.95f)); + _fullScreenEnterButton->setCascadeOpacityEnabled(true); + _fullScreenEnterButton->setVisible(false); + _fullScreenEnterButton->setScale(1 / scale); + _controlPanel->addProtectedChild(_fullScreenEnterButton, 1, -1); + + _fullScreenExitButton = MediaPlayerControl::create(SpriteFrame::createWithTexture( + g_mediaControlsTexture, g_mediaControlTextureRegions[MediaControlButtonId::ExitFullscreen])); + _fullScreenExitButton->addClickEventListener([this](Ref* ref) { + if (_controlPanel->getOpacity() <= 50) + return; + _mediaPlayer->setFullScreenEnabled(false); + updateControllerState(); + }); + _fullScreenExitButton->setSwallowTouches(false); + _fullScreenExitButton->setAnchorPoint(Vec2::ANCHOR_TOP_LEFT); + _fullScreenExitButton->setPositionNormalized(Vec2(0.15f, 0.95f)); + _fullScreenExitButton->setCascadeOpacityEnabled(true); + _fullScreenExitButton->setVisible(false); + _fullScreenExitButton->setScale(1 / scale); + _controlPanel->addProtectedChild(_fullScreenExitButton, 1, -1); + + _timelineTotal = utils::createSpriteFromBase64Cached(BODY_IMAGE_1_PIXEL_HEIGHT, BODY_IMAGE_1_PIXEL_HEIGHT_KEY); + _timelineTotal->setAnchorPoint(Vec2::ANCHOR_MIDDLE_BOTTOM); + _timelineTotal->setStretchEnabled(true); + _timelineTotal->setPositionNormalized(Vec2(0.5f, 0.1f)); + _timelineTotal->setColor(Color3B::GRAY); + _timelineTotal->setVisible(false); + _timelineTotal->setCascadeOpacityEnabled(true); + _timelineTotal->setContentSize(Size(contentSize.width - 40, TIMELINE_BAR_HEIGHT / scale)); + _controlPanel->addProtectedChild(_timelineTotal, 1); + + _timelinePlayed = utils::createSpriteFromBase64Cached(BODY_IMAGE_1_PIXEL_HEIGHT, BODY_IMAGE_1_PIXEL_HEIGHT_KEY); + _timelinePlayed->setAnchorPoint(Vec2::ANCHOR_MIDDLE_LEFT); + _timelinePlayed->setStretchEnabled(true); + _timelinePlayed->setPositionNormalized(Vec2(0.0f, 0.5f)); + _timelinePlayed->setColor(Color3B::WHITE); + _timelinePlayed->setCascadeOpacityEnabled(true); + _timelineTotal->addChild(_timelinePlayed, 5); + + _timelineSelector = Sprite::createWithTexture( + g_mediaControlsTexture, g_mediaControlTextureRegions[MediaControlButtonId::TimelineSliderButton]); + _timelineSelector->setAnchorPoint(Vec2::ANCHOR_MIDDLE); + _timelineSelector->setPositionNormalized(Vec2(1.f, 0.5f)); + _timelineSelector->setCascadeOpacityEnabled(true); + _timelineSelector->setStretchEnabled(true); + _timelineSelector->setContentSize(Size(TIMELINE_BAR_HEIGHT, TIMELINE_BAR_HEIGHT) * 1.5f / scale); + _timelineSelector->setVisible(false); + _timelinePlayed->addChild(_timelineSelector, 10); + + _timelineTouchListener = EventListenerTouchOneByOne::create(); + _timelineTouchListener->setSwallowTouches(true); + _timelineTouchListener->onTouchBegan = [this](ax::Touch* touch, ax::Event* event) -> bool { + auto target = event->getCurrentTarget(); + const auto locationInNode = target->convertToNodeSpace(touch->getLocation()); + const auto& size = target->getContentSize(); + const auto rect = ax::Rect(0, 0, size.width, size.height); + + if (rect.containsPoint(locationInNode)) + { + auto percent = locationInNode.x / rect.size.x; + auto duration = _mediaPlayer->getDuration(); + auto newTime = percent * duration; + _mediaPlayer->seekTo(newTime); + _timelineSelector->setVisible(true); + return true; + } + + return false; + }; + _timelineTouchListener->onTouchMoved = [this](Touch* touch, Event* event) { + auto target = event->getCurrentTarget(); + const auto locationInNode = target->convertToNodeSpace(touch->getLocation()); + const auto& size = target->getContentSize(); + const auto rect = ax::Rect(0, 0, size.width, size.height); + + if (rect.containsPoint(locationInNode)) + { + auto percent = locationInNode.x / rect.size.x; + auto duration = _mediaPlayer->getDuration(); + auto newTime = percent * duration; + _mediaPlayer->seekTo(newTime); + } + }; + _timelineTouchListener->onTouchEnded = [this](Touch* touch, Event* event) { _timelineSelector->setVisible(false); }; + getEventDispatcher()->addEventListenerWithSceneGraphPriority(_timelineTouchListener, _timelineTotal); +} + +void BasicMediaController::updateControlsGlobalZ(float globalZOrder) +{ + _controlPanel->setGlobalZOrder(globalZOrder); + _timelineTotal->setGlobalZOrder(globalZOrder); + _timelinePlayed->setGlobalZOrder(globalZOrder); + _timelineSelector->setGlobalZOrder(globalZOrder); +} + +void BasicMediaController::updateControls() +{ + if (_mediaPlayer) + { + const auto currentTime = _mediaPlayer->getCurrentTime(); + const auto duration = _mediaPlayer->getDuration(); + auto& totalSize = _timelineTotal->getContentSize(); + _timelinePlayed->setContentSize(Size(totalSize.width * (currentTime / duration), totalSize.height)); + } +} + +void BasicMediaController::updateControlsForContentSize(const Vec2& contentSize) +{ + _mediaOverlay->setContentSize(contentSize); + _controlPanel->setContentSize(contentSize); + + auto scale = Director::getInstance()->getGLView()->getScaleY(); + _primaryButtonPanel->setScale(1 / scale); + _timelineTotal->setContentSize(Size(contentSize.width - 40, TIMELINE_BAR_HEIGHT / scale)); + _timelineSelector->setContentSize(Size(TIMELINE_BAR_HEIGHT, TIMELINE_BAR_HEIGHT) * 1.5f / scale); + _fullScreenEnterButton->setScale(1 / scale); + _fullScreenExitButton->setScale(1 / scale); + + _fullScreenEnterButton->setPositionNormalized(Vec2()); + _fullScreenEnterButton->setPositionNormalized(Vec2(0.03f, 0.97f)); + _fullScreenExitButton->setPositionNormalized(Vec2()); + _fullScreenExitButton->setPositionNormalized(Vec2(0.03f, 0.97f)); +} + MediaPlayer::MediaPlayer() - : _fullScreenDirty(false) - , _fullScreenEnabled(false) - , _keepAspectRatioEnabled(false) - , _videoPlayerIndex(-1) - , _eventCallback(nullptr) - , _isPlaying(false) - , _isLooping(false) - , _isUserInputEnabled(true) - , _styleType(StyleType::DEFAULT) { auto pvd = new PrivateVideoDescriptor{}; _videoContext = pvd; @@ -294,6 +935,8 @@ MediaPlayer::~MediaPlayer() removeAllProtectedChildren(); + AX_SAFE_RELEASE_NULL(_mediaController); + if (pvd->_engine) _meFactory->destroyMediaEngine(pvd->_engine); @@ -301,9 +944,29 @@ MediaPlayer::~MediaPlayer() AX_SAFE_RELEASE(pvd->_vtexture); AX_SAFE_RELEASE(pvd->_vchromaTexture); + if (g_mediaControlsTexture && g_mediaControlsTexture->getReferenceCount() == 1) + { + g_mediaControlsTexture = nullptr; + } + delete pvd; } +bool MediaPlayer::init() +{ + if (!Widget::init()) + { + return false; + } + + if (_userInputEnabled) + { + setMediaController(BasicMediaController::create(this)); + } + + return true; +} + void MediaPlayer::setFileName(std::string_view fileName) { auto fullPath = FileUtils::getInstance()->fullPathForFilename(fileName); @@ -336,7 +999,15 @@ void MediaPlayer::setLooping(bool looping) void MediaPlayer::setUserInputEnabled(bool enableInput) { - _isUserInputEnabled = enableInput; + _userInputEnabled = enableInput; + if (_mediaController) + { + _mediaController->setEnabled(_userInputEnabled); + } + else if (_userInputEnabled) + { + setMediaController(BasicMediaController::create(this)); + } } void MediaPlayer::setStyle(StyleType style) @@ -372,7 +1043,58 @@ void MediaPlayer::draw(Renderer* renderer, const Mat4& transform, uint32_t flags void MediaPlayer::setContentSize(const Size& contentSize) { Widget::setContentSize(contentSize); - reinterpret_cast(_videoContext)->_originalViewSize = contentSize; + auto videoContext = reinterpret_cast(_videoContext); + videoContext->_originalViewSize = contentSize; + if (_mediaController) + { + _mediaController->setContentSize(contentSize); + } +} + +MediaPlayer::MediaState MediaPlayer::getState() const +{ + if (_videoURL.empty()) + return MediaState::CLOSED; + + auto engine = reinterpret_cast(_videoContext)->_engine; + if (engine) + { + switch (engine->getState()) + { + case MEMediaState::Closed: + return MediaState::CLOSED; + case MEMediaState::Preparing: + return MediaState::LOADING; + case MEMediaState::Playing: + return MediaState::PLAYING; + case MEMediaState::Paused: + return MediaState::PAUSED; + case MEMediaState::Stopped: + return MediaState::STOPPED; + case MEMediaState::Error: + return MediaState::ERROR; + } + } + + return MediaState::CLOSED; +} + +void MediaPlayer::setMediaController(MediaController* controller) +{ + if (_mediaController) + { + removeProtectedChild(_mediaController, true); + AX_SAFE_RELEASE(_mediaController); + } + _mediaController = controller; + if (_mediaController) + { + AX_SAFE_RETAIN(_mediaController); + _mediaController->setPositionNormalized(Vec2(0.5f, 0.5f)); + _mediaController->setAnchorPoint(Vec2::ANCHOR_MIDDLE); + _mediaController->setEnabled(_userInputEnabled); + addProtectedChild(_mediaController, 1); + } } void MediaPlayer::setFullScreenEnabled(bool enabled) @@ -381,9 +1103,13 @@ void MediaPlayer::setFullScreenEnabled(bool enabled) { _fullScreenEnabled = enabled; - auto pvd = reinterpret_cast(_videoContext); - Widget::setContentSize(enabled ? _director->getGLView()->getDesignResolutionSize() - : pvd->_originalViewSize); + auto pvd = reinterpret_cast(_videoContext); + const auto contentSize = enabled ? _director->getGLView()->getDesignResolutionSize() : pvd->_originalViewSize; + Widget::setContentSize(contentSize); + if (_mediaController) + { + _mediaController->setContentSize(contentSize); + } } } @@ -423,10 +1149,10 @@ void MediaPlayer::play() case MEMediaState::Closed: engine->setAutoPlay(true); engine->open(_videoURL); - break; default: engine->play(); } + updateMediaController(); } } } @@ -437,7 +1163,10 @@ void MediaPlayer::pause() { auto engine = reinterpret_cast(_videoContext)->_engine; if (engine) + { engine->pause(); + updateMediaController(); + } } } @@ -454,6 +1183,8 @@ void MediaPlayer::resume() case MEMediaState::Paused: engine->play(); } + + updateMediaController(); } } } @@ -464,7 +1195,10 @@ void MediaPlayer::stop() { auto engine = reinterpret_cast(_videoContext)->_engine; if (engine) + { engine->stop(); + updateMediaController(); + } } } @@ -474,8 +1208,39 @@ void MediaPlayer::seekTo(float sec) { auto engine = reinterpret_cast(_videoContext)->_engine; if (engine) + { engine->setCurrentTime(sec); + updateMediaController(); + } + } +} + +float MediaPlayer::getCurrentTime() +{ + if (!_videoURL.empty()) + { + auto engine = reinterpret_cast(_videoContext)->_engine; + if (engine) + { + return static_cast(engine->getCurrentTime()); + } + } + + return 0.f; +} + +float MediaPlayer::getDuration() +{ + if (!_videoURL.empty()) + { + auto engine = reinterpret_cast(_videoContext)->_engine; + if (engine) + { + return static_cast(engine->getDuration()); + } } + + return 0.f; } bool MediaPlayer::isPlaying() const @@ -490,7 +1255,7 @@ bool MediaPlayer::isLooping() const bool MediaPlayer::isUserInputEnabled() const { - return _isUserInputEnabled; + return _userInputEnabled; } void MediaPlayer::setVisible(bool visible) @@ -536,7 +1301,7 @@ void MediaPlayer::copySpecialProperties(Widget* widget) { _isPlaying = videoPlayer->_isPlaying; _isLooping = videoPlayer->_isLooping; - _isUserInputEnabled = videoPlayer->_isUserInputEnabled; + _userInputEnabled = videoPlayer->_userInputEnabled; _styleType = videoPlayer->_styleType; _fullScreenEnabled = videoPlayer->_fullScreenEnabled; _fullScreenDirty = videoPlayer->_fullScreenDirty; @@ -548,4 +1313,14 @@ void MediaPlayer::copySpecialProperties(Widget* widget) } } +void MediaPlayer::updateMediaController() +{ + if (!_userInputEnabled || !_mediaController) + { + return; + } + + _mediaController->updateControllerState(); +} + #endif diff --git a/core/ui/UIMediaPlayer.h b/core/ui/UIMediaPlayer.h index 58d5ca4017bb..01a9e9e24302 100644 --- a/core/ui/UIMediaPlayer.h +++ b/core/ui/UIMediaPlayer.h @@ -25,9 +25,14 @@ ****************************************************************************/ #pragma once -#include "ui/UIWidget.h" +#if defined(AX_ENABLE_MEDIA) + +# include "UIButton.h" +# include "ui/UIWidget.h" +# include "ui/UILayout.h" +# include "2d/Sprite.h" +# include -#if AX_TARGET_PLATFORM != AX_PLATFORM_LINUX || defined(AX_ENABLE_VLC_MEDIA) # if AX_VIDEOPLAYER_DEBUG_DRAW # include "2d/DrawNode.h" @@ -44,6 +49,86 @@ NS_AX_BEGIN namespace ui { +class MediaPlayer; + +class AX_GUI_DLL MediaController : public ax::ui::Widget +{ +public: + explicit MediaController(MediaPlayer* player) : _mediaPlayer(player) {} + ~MediaController() override = 0; + + virtual void updateControllerState() = 0; + +protected: + MediaPlayer* _mediaPlayer = nullptr; +}; +inline MediaController::~MediaController() = default; // Required since the destructor is pure virtual + +class MediaPlayerControl : public ax::ui::Button +{ +public: + static MediaPlayerControl* create(SpriteFrame* frame); + + MediaPlayerControl() = default; + ~MediaPlayerControl() override; + + virtual bool init(SpriteFrame* frame); + + void onSizeChanged() override; + Vec2 getVirtualRendererSize() const override; + Vec2 getNormalSize() const override; + + void onPressStateChangedToNormal() override; + void onPressStateChangedToPressed() override; + void onPressStateChangedToDisabled() override; + +protected: + Sprite* _overlay = nullptr; +}; + +class AX_GUI_DLL BasicMediaController : public MediaController +{ +public: + explicit BasicMediaController(MediaPlayer* player); + + static BasicMediaController* create(MediaPlayer* mediaPlayer); + + bool init() override; + void initRenderer() override; + + void onPressStateChangedToPressed() override; + void setContentSize(const Vec2& contentSize) override; + void update(float delta) override; + void onEnter() override; + void setGlobalZOrder(float globalZOrder) override; + + void updateControllerState() override; + + virtual void createControls(); + virtual void updateControlsGlobalZ(float globalZOrder); + virtual void updateControls(); + virtual void updateControlsForContentSize(const Vec2& contentSize); + +protected: + Widget* _controlPanel = nullptr; + + MediaPlayerControl* _fullScreenEnterButton = nullptr; + MediaPlayerControl* _fullScreenExitButton = nullptr; + MediaPlayerControl* _playButton = nullptr; + MediaPlayerControl* _stopButton = nullptr; + MediaPlayerControl* _pauseButton = nullptr; + + Sprite* _timelineSelector = nullptr; + Sprite* _timelineTotal = nullptr; + Sprite* _timelinePlayed = nullptr; + Layout* _mediaOverlay = nullptr; + Widget* _primaryButtonPanel = nullptr; + + EventListenerTouchOneByOne* _timelineTouchListener = nullptr; + float _playRate = 1.f; + std::chrono::steady_clock::time_point _lastTouch; +}; + /** * @class MediaPlayer * @brief Play a media file. @@ -67,6 +152,17 @@ class AX_GUI_DLL MediaPlayer : public ax::ui::Widget ERROR }; + enum class MediaState + { + CLOSED = 0, + LOADING, + PLAYING, + PAUSED, + STOPPED, + FINISHED, + ERROR + }; + /** * Styles of how the the video player is presented * For now only used on iOS to use either MPMovieControlStyleEmbedded (DEFAULT) or @@ -88,6 +184,8 @@ class AX_GUI_DLL MediaPlayer : public ax::ui::Widget */ CREATE_FUNC(MediaPlayer); + bool init() override; + /** * Sets a file path as a video source for MediaPlayer. */ @@ -148,12 +246,12 @@ class AX_GUI_DLL MediaPlayer : public ax::ui::Widget /** * Pauses playback. */ - virtual void pause() override; + void pause() override; /** * Resumes playback. */ - virtual void resume() override; + void resume() override; /** * Stops playback. @@ -167,6 +265,20 @@ class AX_GUI_DLL MediaPlayer : public ax::ui::Widget */ virtual void seekTo(float sec); + /** + * Gets the current media position. + * + * @return float The current position in seconds + */ + virtual float getCurrentTime(); + + /** + * Gets total video duration + * + * @return float The duration in seconds + */ + virtual float getDuration(); + /** * Checks whether the MediaPlayer is playing. * @@ -226,22 +338,31 @@ class AX_GUI_DLL MediaPlayer : public ax::ui::Widget * @brief A function which will be called when video is playing. * * @param event @see MediaPlayer::EventType. - */ virtual void onPlayEvent(int event); - virtual void setVisible(bool visible) override; - virtual void draw(Renderer* renderer, const Mat4& transform, uint32_t flags) override; - virtual void onEnter() override; - virtual void onExit() override; + void setVisible(bool visible) override; + void draw(Renderer* renderer, const Mat4& transform, uint32_t flags) override; + void onEnter() override; + void onExit() override; void setContentSize(const Size& contentSize) override; + /** + * @brief Get current state of the media + * + * @return MediaState + */ + MediaState getState() const; + + void setMediaController(MediaController* controller); + MediaPlayer(); - virtual ~MediaPlayer(); + ~MediaPlayer() override; protected: - virtual ax::ui::Widget* createCloneInstance() override; - virtual void copySpecialProperties(Widget* model) override; + ax::ui::Widget* createCloneInstance() override; + void copySpecialProperties(Widget* model) override; + virtual void updateMediaController(); # if AX_VIDEOPLAYER_DEBUG_DRAW DrawNode* _debugDrawNode; @@ -255,10 +376,10 @@ class AX_GUI_DLL MediaPlayer : public ax::ui::Widget bool _isPlaying = false; bool _isLooping = false; - bool _isUserInputEnabled = true; bool _fullScreenDirty = false; bool _fullScreenEnabled = false; bool _keepAspectRatioEnabled = false; + bool _userInputEnabled = false; StyleType _styleType = StyleType::DEFAULT; @@ -269,6 +390,8 @@ class AX_GUI_DLL MediaPlayer : public ax::ui::Widget ccVideoPlayerCallback _eventCallback = nullptr; void* _videoContext = nullptr; + + MediaController* _mediaController = nullptr; }; using VideoPlayer = MediaPlayer; } // namespace ui diff --git a/core/ui/axmol-ui.h b/core/ui/axmol-ui.h index 8ab5eb63a701..e66685ef8f20 100644 --- a/core/ui/axmol-ui.h +++ b/core/ui/axmol-ui.h @@ -47,7 +47,7 @@ THE SOFTWARE. #include "ui/UIHBox.h" #include "ui/UIVBox.h" #include "ui/UIRelativeBox.h" -#if !defined(_WIN32) || defined(AX_ENABLE_MFMEDIA) +#if defined(AX_ENABLE_MEDIA) # include "ui/UIMediaPlayer.h" #endif #if !defined(_WIN32) || defined(AX_ENABLE_MSEDGE_WEBVIEW2) diff --git a/tests/cpp-tests/CMakeLists.txt b/tests/cpp-tests/CMakeLists.txt index e58f07c14a5f..ddd23a554d58 100644 --- a/tests/cpp-tests/CMakeLists.txt +++ b/tests/cpp-tests/CMakeLists.txt @@ -376,7 +376,7 @@ list(APPEND GAME_SOURCE Source/ZipTest/ZipTests.cpp ) -if(ANDROID OR MACOSX OR IOS OR (WINDOWS AND AX_ENABLE_MFMEDIA) OR AX_ENABLE_VLC_MEDIA) +if(AX_ENABLE_MEDIA) list(APPEND GAME_HEADER Source/UITest/CocoStudioGUITest/UIVideoPlayerTest/UIVideoPlayerTest.h) list(APPEND GAME_SOURCE diff --git a/tests/cpp-tests/Source/UITest/CocoStudioGUITest/CocosGUIScene.cpp b/tests/cpp-tests/Source/UITest/CocoStudioGUITest/CocosGUIScene.cpp index ef2e627b7d21..5776f519a1f0 100644 --- a/tests/cpp-tests/Source/UITest/CocoStudioGUITest/CocosGUIScene.cpp +++ b/tests/cpp-tests/Source/UITest/CocoStudioGUITest/CocosGUIScene.cpp @@ -44,7 +44,7 @@ #include "UIFocusTest/UIFocusTest.h" #include "UITabControlTest/UITabControlTest.h" -#if AX_TARGET_PLATFORM != AX_PLATFORM_LINUX || defined(AX_ENABLE_VLC_MEDIA) +#if defined(AX_ENABLE_MEDIA) # include "UIVideoPlayerTest/UIVideoPlayerTest.h" #endif @@ -63,7 +63,7 @@ GUIDynamicCreateTests::GUIDynamicCreateTests() { -#if (AX_TARGET_PLATFORM != AX_PLATFORM_LINUX && AX_TARGET_PLATFORM != AX_PLATFORM_WASM) || defined(AX_ENABLE_VLC_MEDIA) +#if defined(AX_ENABLE_MEDIA) addTest("VideoPlayer Test", []() { return new VideoPlayerTests; }); #endif #if (AX_TARGET_PLATFORM == AX_PLATFORM_ANDROID || AX_TARGET_PLATFORM == AX_PLATFORM_IOS) && \