2022-02-24 17:57:08 +08:00
|
|
|
/****************************************************************************
|
|
|
|
Copyright (c) 2014-2016 Chukong Technologies Inc.
|
|
|
|
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
|
|
|
Copyright (c) 2022 Bytedance Inc.
|
|
|
|
|
2022-10-01 16:24:52 +08:00
|
|
|
https://axmolengine.github.io/
|
2022-02-24 17:57:08 +08:00
|
|
|
|
|
|
|
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.
|
|
|
|
****************************************************************************/
|
|
|
|
|
2023-04-02 01:51:36 +08:00
|
|
|
#include "ui/UIVideoPlayer.h"
|
2022-02-24 17:57:08 +08:00
|
|
|
|
2023-04-02 01:51:36 +08:00
|
|
|
// Now, common implementation based on redesigned MediaEngine is enable for windows and macOS
|
2023-06-01 12:48:40 +08:00
|
|
|
#if defined(_WIN32) || defined(__APPLE__)
|
2022-02-24 17:57:08 +08:00
|
|
|
# include <unordered_map>
|
|
|
|
# include <stdlib.h>
|
|
|
|
# include <string>
|
|
|
|
# include "base/CCDirector.h"
|
|
|
|
# include "base/CCEventListenerKeyboard.h"
|
|
|
|
# include "platform/CCFileUtils.h"
|
|
|
|
# include "ui/UIHelper.h"
|
2023-03-25 08:37:51 +08:00
|
|
|
# include "media/MediaEngine.h"
|
2022-02-24 17:57:08 +08:00
|
|
|
# include "ui/LayoutHelper.h"
|
2023-05-14 22:39:05 +08:00
|
|
|
# include "yasio/core/byte_buffer.hpp"
|
2022-02-24 17:57:08 +08:00
|
|
|
//-----------------------------------------------------------------------------------------------------------
|
|
|
|
|
2022-07-11 17:50:21 +08:00
|
|
|
USING_NS_AX;
|
2022-02-24 17:57:08 +08:00
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
# define PS_SET_UNIFORM(ps, name, value) \
|
|
|
|
do \
|
|
|
|
{ \
|
|
|
|
decltype(value) __v = value; \
|
|
|
|
auto __loc = (ps)->getUniformLocation(name); \
|
|
|
|
(ps)->setUniform(__loc, &__v, sizeof(__v)); \
|
|
|
|
} while (false)
|
|
|
|
|
2023-04-02 01:51:36 +08:00
|
|
|
# define PS_SET_UNIFORM_R(ps, name, value) \
|
|
|
|
do \
|
|
|
|
{ \
|
|
|
|
auto __loc = (ps)->getUniformLocation(name); \
|
|
|
|
(ps)->setUniform(__loc, &value, sizeof(value)); \
|
|
|
|
} while (false)
|
|
|
|
|
2022-08-08 18:02:17 +08:00
|
|
|
using namespace ax::ui;
|
2022-02-24 17:57:08 +08:00
|
|
|
|
|
|
|
namespace
|
|
|
|
{
|
|
|
|
struct PrivateVideoDescriptor
|
|
|
|
{
|
2023-04-02 01:51:36 +08:00
|
|
|
MediaEngine* _vplayer = nullptr;
|
|
|
|
Texture2D* _vtexture = nullptr;
|
|
|
|
Texture2D* _vchromaTexture = nullptr;
|
|
|
|
Sprite* _vrender = nullptr;
|
2022-02-24 17:57:08 +08:00
|
|
|
|
2023-04-02 01:51:36 +08:00
|
|
|
MEVideoPixelDesc _vpixelDesc;
|
2022-02-24 17:57:08 +08:00
|
|
|
|
|
|
|
Vec2 _originalViewSize;
|
|
|
|
|
2023-03-25 08:37:51 +08:00
|
|
|
bool _scaleDirty = false;
|
|
|
|
|
2022-02-24 17:57:08 +08:00
|
|
|
void closePlayer()
|
|
|
|
{
|
|
|
|
if (_vplayer)
|
|
|
|
_vplayer->Close();
|
|
|
|
}
|
|
|
|
|
|
|
|
void rescaleTo(VideoPlayer* videoView)
|
|
|
|
{
|
|
|
|
auto& videoSize = _vrender->getContentSize();
|
|
|
|
if (videoSize.x > 0 && videoSize.y > 0)
|
|
|
|
{ // rescale video to view node
|
|
|
|
auto& viewSize = videoView->getContentSize();
|
|
|
|
if (viewSize.x > 0 && viewSize.y > 0)
|
|
|
|
{
|
|
|
|
if (!videoView->isKeepAspectRatioEnabled())
|
|
|
|
{
|
|
|
|
_vrender->setScale(viewSize.x / videoSize.x, viewSize.y / videoSize.y);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-04-02 01:51:36 +08:00
|
|
|
const auto aspectRatio = (std::min)(viewSize.x / videoSize.x, viewSize.y / (videoSize.y));
|
2022-02-24 17:57:08 +08:00
|
|
|
|
2023-04-02 01:51:36 +08:00
|
|
|
_vrender->setScale(aspectRatio);
|
2022-02-24 17:57:08 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
LayoutHelper::centerNode(_vrender);
|
|
|
|
|
|
|
|
_vrender->setVisible(true);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
_vrender->setVisible(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
_scaleDirty = false;
|
|
|
|
}
|
2023-04-02 01:51:36 +08:00
|
|
|
|
|
|
|
static void updateColorTransform(backend::ProgramState* ps, bool bFullColorRange)
|
|
|
|
{
|
|
|
|
// clang-format off
|
|
|
|
// 1.16438356 ~= 255/219.0
|
|
|
|
const Mat4 colorTransform = bFullColorRange ? Mat4{ // 709Scaled
|
|
|
|
1.16438356f, 0.00000000f, 1.79265225f, 0.0f,
|
|
|
|
1.16438356f, -0.213237017f, - 0.533004045f, 0.0f,
|
|
|
|
1.16438356f, 2.11241937f, 0.00000000f, 0.0f,
|
|
|
|
0.0627451017f, 0.501960814f, 0.501960814f, 0.0f // YUVOffset8Bits: 16/255.0f, 128/255.0f, 128/255.0f
|
|
|
|
} : Mat4 { // 709Unscaled
|
|
|
|
1.000000f, 0.0000000f, 1.57472198f, 0.0f,
|
|
|
|
1.000000f, -0.187314089f, -0.46820747f, 0.0f,
|
|
|
|
1.000000f, 1.85561536f, 0.0000000f, 0.0f,
|
|
|
|
0.0627451f, 0.5019608f, 0.50196081f, 0.0f
|
|
|
|
};
|
|
|
|
|
|
|
|
// clang-format on
|
|
|
|
PS_SET_UNIFORM_R(ps, "colorTransform", colorTransform);
|
|
|
|
}
|
2022-02-24 17:57:08 +08:00
|
|
|
};
|
|
|
|
} // namespace
|
|
|
|
|
2023-03-25 08:37:51 +08:00
|
|
|
static std::unique_ptr<MediaEngineFactory> _meFactory = CreatePlatformMediaEngineFactory();
|
|
|
|
|
2022-02-24 17:57:08 +08:00
|
|
|
VideoPlayer::VideoPlayer()
|
|
|
|
: _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;
|
2022-07-16 10:43:05 +08:00
|
|
|
# if AX_VIDEOPLAYER_DEBUG_DRAW
|
2022-02-24 17:57:08 +08:00
|
|
|
_debugDrawNode = DrawNode::create();
|
|
|
|
addChild(_debugDrawNode);
|
|
|
|
# endif
|
|
|
|
|
|
|
|
// Initialize mediaPlayer backend
|
2023-03-25 08:37:51 +08:00
|
|
|
pvd->_vplayer = _meFactory->CreateMediaEngine();
|
|
|
|
if (pvd->_vplayer)
|
2022-02-24 17:57:08 +08:00
|
|
|
{
|
|
|
|
/// create video render sprite
|
|
|
|
pvd->_vrender = new Sprite();
|
2023-03-25 08:37:51 +08:00
|
|
|
pvd->_vrender->init();
|
|
|
|
pvd->_vrender->setAutoUpdatePS(false);
|
2022-02-24 17:57:08 +08:00
|
|
|
this->addProtectedChild(pvd->_vrender);
|
2023-03-25 08:37:51 +08:00
|
|
|
/// setup media event callback
|
|
|
|
pvd->_vplayer->SetMediaEventCallback([=](MEMediaEventType event) {
|
2022-02-24 17:57:08 +08:00
|
|
|
switch (event)
|
|
|
|
{
|
2023-03-25 08:37:51 +08:00
|
|
|
case MEMediaEventType::Playing:
|
2022-02-24 17:57:08 +08:00
|
|
|
if (!isPlaying())
|
|
|
|
onPlayEvent((int)EventType::PLAYING);
|
|
|
|
break;
|
|
|
|
|
2023-03-25 08:37:51 +08:00
|
|
|
case MEMediaEventType::Paused:
|
2022-02-24 17:57:08 +08:00
|
|
|
onPlayEvent((int)EventType::PAUSED);
|
|
|
|
break;
|
|
|
|
|
2023-03-25 08:37:51 +08:00
|
|
|
case MEMediaEventType::Stopped:
|
2022-02-24 17:57:08 +08:00
|
|
|
onPlayEvent((int)EventType::STOPPED);
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Raised by a media source when a presentation ends. This event signals that all streams in the
|
|
|
|
presentation are complete. The Media Session forwards this event to the application. */
|
|
|
|
// case MEEndOfPresentation:
|
|
|
|
// onPlayEvent((int)EventType::COMPLETED);
|
|
|
|
// break;
|
|
|
|
|
|
|
|
/* Raised by the Media Session when it has finished playing the last presentation in the playback queue.
|
|
|
|
* We send complete event at this case
|
|
|
|
*/
|
2023-03-25 08:37:51 +08:00
|
|
|
case MEMediaEventType::Completed:
|
2022-02-24 17:57:08 +08:00
|
|
|
onPlayEvent((int)EventType::COMPLETED);
|
|
|
|
break;
|
2023-03-25 08:37:51 +08:00
|
|
|
case MEMediaEventType::Error:
|
|
|
|
onPlayEvent((int)EventType::ERROR);
|
|
|
|
break;
|
2022-02-24 17:57:08 +08:00
|
|
|
}
|
2023-03-25 08:37:51 +08:00
|
|
|
});
|
2022-02-24 17:57:08 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-03-25 08:37:51 +08:00
|
|
|
ax::log("Create VideoPlayer backend failed");
|
2022-02-24 17:57:08 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VideoPlayer::~VideoPlayer()
|
|
|
|
{
|
2023-03-25 08:37:51 +08:00
|
|
|
auto pvd = reinterpret_cast<PrivateVideoDescriptor*>(_videoContext);
|
2022-02-24 17:57:08 +08:00
|
|
|
|
|
|
|
removeAllProtectedChildren();
|
|
|
|
|
|
|
|
if (pvd->_vplayer)
|
2023-03-25 08:37:51 +08:00
|
|
|
_meFactory->DestroyMediaEngine(pvd->_vplayer);
|
|
|
|
|
2023-04-02 01:51:36 +08:00
|
|
|
AX_SAFE_RELEASE(pvd->_vrender);
|
|
|
|
AX_SAFE_RELEASE(pvd->_vtexture);
|
|
|
|
AX_SAFE_RELEASE(pvd->_vchromaTexture);
|
2022-02-24 17:57:08 +08:00
|
|
|
|
|
|
|
delete pvd;
|
|
|
|
}
|
|
|
|
|
|
|
|
void VideoPlayer::setFileName(std::string_view fileName)
|
|
|
|
{
|
|
|
|
auto fullPath = FileUtils::getInstance()->fullPathForFilename(fileName);
|
2023-03-25 08:37:51 +08:00
|
|
|
fullPath.insert(fullPath.begin(), FILE_URL_SCHEME.begin(), FILE_URL_SCHEME.end());
|
2022-02-24 17:57:08 +08:00
|
|
|
if (fullPath != _videoURL)
|
|
|
|
{
|
|
|
|
reinterpret_cast<PrivateVideoDescriptor*>(_videoContext)->closePlayer();
|
|
|
|
_videoURL = std::move(fullPath);
|
|
|
|
}
|
|
|
|
_videoSource = VideoPlayer::Source::FILENAME;
|
|
|
|
}
|
|
|
|
|
|
|
|
void VideoPlayer::setURL(std::string_view videoUrl)
|
|
|
|
{
|
|
|
|
if (_videoURL != videoUrl)
|
|
|
|
{
|
|
|
|
reinterpret_cast<PrivateVideoDescriptor*>(_videoContext)->closePlayer();
|
|
|
|
_videoURL = videoUrl;
|
|
|
|
}
|
|
|
|
_videoSource = VideoPlayer::Source::URL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void VideoPlayer::setLooping(bool looping)
|
|
|
|
{
|
|
|
|
_isLooping = looping;
|
|
|
|
|
2023-03-25 08:37:51 +08:00
|
|
|
auto pvd = reinterpret_cast<PrivateVideoDescriptor*>(_videoContext);
|
2022-02-24 17:57:08 +08:00
|
|
|
if (pvd->_vplayer)
|
2023-03-25 08:37:51 +08:00
|
|
|
pvd->_vplayer->SetLoop(looping);
|
2022-02-24 17:57:08 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void VideoPlayer::setUserInputEnabled(bool enableInput)
|
|
|
|
{
|
|
|
|
_isUserInputEnabled = enableInput;
|
|
|
|
}
|
|
|
|
|
|
|
|
void VideoPlayer::setStyle(StyleType style)
|
|
|
|
{
|
|
|
|
_styleType = style;
|
|
|
|
}
|
|
|
|
|
|
|
|
void VideoPlayer::draw(Renderer* renderer, const Mat4& transform, uint32_t flags)
|
|
|
|
{
|
2022-08-08 18:02:17 +08:00
|
|
|
ax::ui::Widget::draw(renderer, transform, flags);
|
2022-02-24 17:57:08 +08:00
|
|
|
|
2023-03-25 08:37:51 +08:00
|
|
|
auto pvd = reinterpret_cast<PrivateVideoDescriptor*>(_videoContext);
|
2022-02-24 17:57:08 +08:00
|
|
|
auto vrender = pvd->_vrender;
|
2023-03-25 08:37:51 +08:00
|
|
|
auto vplayer = pvd->_vplayer;
|
|
|
|
if (!vrender || !vplayer)
|
2022-02-24 17:57:08 +08:00
|
|
|
return;
|
|
|
|
|
2023-04-02 01:51:36 +08:00
|
|
|
if (vrender->isVisible() && isPlaying())
|
|
|
|
{ // render 1 video sample if avaiable
|
2022-05-07 20:21:22 +08:00
|
|
|
|
2023-04-02 01:51:36 +08:00
|
|
|
vplayer->TransferVideoFrame([this, pvd](const ax::MEVideoFrame& frame){
|
|
|
|
auto pixelFormat = frame._vpd._PF;
|
|
|
|
auto bPixelDescChnaged = !frame._vpd.equals(pvd->_vpixelDesc);
|
|
|
|
if (bPixelDescChnaged)
|
|
|
|
{
|
|
|
|
pvd->_vpixelDesc = frame._vpd;
|
2022-02-24 17:57:08 +08:00
|
|
|
|
2023-04-02 01:51:36 +08:00
|
|
|
AX_SAFE_RELEASE(pvd->_vtexture);
|
|
|
|
pvd->_vtexture = new Texture2D(); // deault is Sampler Filter is: LINEAR
|
|
|
|
|
|
|
|
AX_SAFE_RELEASE_NULL(pvd->_vchromaTexture);
|
|
|
|
if (pixelFormat >= MEVideoPixelFormat::YUY2)
|
|
|
|
{ // use separated texture we can set differrent sample filter
|
|
|
|
pvd->_vchromaTexture = new Texture2D(); // Sampler Filter: NEAREST
|
|
|
|
pvd->_vchromaTexture->setAliasTexParameters();
|
|
|
|
}
|
|
|
|
|
|
|
|
auto programManager = ProgramManager::getInstance();
|
|
|
|
|
|
|
|
switch (pixelFormat)
|
|
|
|
{
|
|
|
|
case MEVideoPixelFormat::YUY2:
|
|
|
|
pvd->_vrender->setProgramState(backend::ProgramType::VIDEO_TEXTURE_YUY2);
|
|
|
|
break;
|
|
|
|
case MEVideoPixelFormat::NV12:
|
|
|
|
pvd->_vrender->setProgramState(backend::ProgramType::VIDEO_TEXTURE_NV12);
|
|
|
|
break;
|
|
|
|
case MEVideoPixelFormat::BGR32:
|
|
|
|
pvd->_vrender->setProgramState(backend::ProgramType::VIDEO_TEXTURE_BGR32);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
pvd->_vrender->setProgramState(backend::ProgramType::VIDEO_TEXTURE_RGB32);
|
|
|
|
}
|
|
|
|
}
|
2022-02-24 17:57:08 +08:00
|
|
|
|
2023-04-02 01:51:36 +08:00
|
|
|
auto& bufferDim = frame._vpd._dim;
|
2022-02-24 17:57:08 +08:00
|
|
|
|
2023-04-02 01:51:36 +08:00
|
|
|
switch (pixelFormat)
|
2022-02-24 17:57:08 +08:00
|
|
|
{
|
2023-04-02 01:51:36 +08:00
|
|
|
case MEVideoPixelFormat::YUY2:
|
|
|
|
{
|
|
|
|
pvd->_vtexture->updateWithData(frame._dataPointer, frame._dataLen, PixelFormat::LA8,
|
|
|
|
PixelFormat::LA8,
|
|
|
|
bufferDim.x, bufferDim.y, false, 0);
|
|
|
|
pvd->_vchromaTexture->updateWithData(frame._dataPointer, frame._dataLen, PixelFormat::RGBA8,
|
|
|
|
PixelFormat::RGBA8,
|
|
|
|
bufferDim.x >> 1, bufferDim.y, false, 0);
|
2022-05-07 20:21:22 +08:00
|
|
|
break;
|
2023-04-02 01:51:36 +08:00
|
|
|
}
|
|
|
|
case MEVideoPixelFormat::NV12:
|
|
|
|
{
|
|
|
|
pvd->_vtexture->updateWithData(frame._dataPointer, bufferDim.x * bufferDim.y, PixelFormat::A8,
|
|
|
|
PixelFormat::A8, bufferDim.x, bufferDim.y, false, 0);
|
|
|
|
pvd->_vchromaTexture->updateWithData(frame._cbcrDataPointer, (bufferDim.x * bufferDim.y) >> 1,
|
|
|
|
PixelFormat::RG8,
|
|
|
|
PixelFormat::RG8, bufferDim.x >> 1, bufferDim.y >> 1, false, 0);
|
2022-02-24 17:57:08 +08:00
|
|
|
break;
|
2023-04-02 01:51:36 +08:00
|
|
|
}
|
|
|
|
case MEVideoPixelFormat::RGB32:
|
|
|
|
case MEVideoPixelFormat::BGR32:
|
|
|
|
pvd->_vtexture->updateWithData(frame._dataPointer, frame._dataLen, PixelFormat::RGBA8,
|
|
|
|
PixelFormat::RGBA8, bufferDim.x, bufferDim.y, false, 0);
|
2022-02-24 17:57:08 +08:00
|
|
|
break;
|
2023-04-02 01:51:36 +08:00
|
|
|
default:;
|
2022-02-24 17:57:08 +08:00
|
|
|
}
|
2023-04-02 01:51:36 +08:00
|
|
|
if (bPixelDescChnaged)
|
|
|
|
{
|
|
|
|
pvd->_vrender->setTexture(pvd->_vtexture);
|
|
|
|
pvd->_vrender->setTextureRect(ax::Rect{Vec2::ZERO, Vec2{
|
|
|
|
frame._videoDim.x / AX_CONTENT_SCALE_FACTOR(),
|
|
|
|
frame._videoDim.y / AX_CONTENT_SCALE_FACTOR(),
|
|
|
|
}});
|
2022-02-24 17:57:08 +08:00
|
|
|
|
2023-04-02 01:51:36 +08:00
|
|
|
if (pixelFormat >= MEVideoPixelFormat::YUY2)
|
|
|
|
{
|
|
|
|
auto ps = pvd->_vrender->getProgramState();
|
|
|
|
PrivateVideoDescriptor::updateColorTransform(ps, frame._vpd._fullRange);
|
|
|
|
ps->setTexture(ps->getUniformLocation("u_tex1"), 1, pvd->_vchromaTexture->getBackendTexture());
|
|
|
|
}
|
2022-02-24 17:57:08 +08:00
|
|
|
|
2023-04-02 01:51:36 +08:00
|
|
|
pvd->_scaleDirty = true;
|
2022-02-24 17:57:08 +08:00
|
|
|
}
|
2023-04-02 01:51:36 +08:00
|
|
|
});
|
2022-02-24 17:57:08 +08:00
|
|
|
}
|
|
|
|
if (pvd->_scaleDirty || (flags & FLAGS_TRANSFORM_DIRTY))
|
|
|
|
pvd->rescaleTo(this);
|
|
|
|
|
2022-07-16 10:43:05 +08:00
|
|
|
# if AX_VIDEOPLAYER_DEBUG_DRAW
|
2022-02-24 17:57:08 +08:00
|
|
|
_debugDrawNode->clear();
|
|
|
|
auto size = getContentSize();
|
|
|
|
Point vertices[4] = {Point::ZERO, Point(size.width, 0), Point(size.width, size.height), Point(0, size.height)};
|
|
|
|
_debugDrawNode->drawPoly(vertices, 4, true, Color4F(1.0, 1.0, 1.0, 1.0));
|
|
|
|
# endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void VideoPlayer::setContentSize(const Size& contentSize)
|
|
|
|
{
|
|
|
|
Widget::setContentSize(contentSize);
|
|
|
|
reinterpret_cast<PrivateVideoDescriptor*>(_videoContext)->_originalViewSize = contentSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
void VideoPlayer::setFullScreenEnabled(bool enabled)
|
|
|
|
{
|
|
|
|
if (_fullScreenEnabled != enabled)
|
|
|
|
{
|
|
|
|
_fullScreenEnabled = enabled;
|
|
|
|
|
|
|
|
auto pvd = reinterpret_cast<PrivateVideoDescriptor*>(_videoContext);
|
2023-03-25 08:37:51 +08:00
|
|
|
Widget::setContentSize(enabled ? _director->getOpenGLView()->getDesignResolutionSize()
|
|
|
|
: pvd->_originalViewSize);
|
2022-02-24 17:57:08 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool VideoPlayer::isFullScreenEnabled() const
|
|
|
|
{
|
|
|
|
return _fullScreenEnabled;
|
|
|
|
}
|
|
|
|
|
|
|
|
void VideoPlayer::setKeepAspectRatioEnabled(bool enable)
|
|
|
|
{
|
|
|
|
if (_keepAspectRatioEnabled != enable)
|
|
|
|
{
|
|
|
|
_keepAspectRatioEnabled = enable;
|
|
|
|
reinterpret_cast<PrivateVideoDescriptor*>(_videoContext)->_scaleDirty = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-28 12:14:08 +08:00
|
|
|
void VideoPlayer::setPlayRate(float fRate)
|
|
|
|
{
|
|
|
|
if (!_videoURL.empty())
|
|
|
|
{
|
|
|
|
auto vplayer = reinterpret_cast<PrivateVideoDescriptor*>(_videoContext)->_vplayer;
|
|
|
|
if (vplayer)
|
|
|
|
vplayer->SetRate(fRate);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-24 17:57:08 +08:00
|
|
|
void VideoPlayer::play()
|
|
|
|
{
|
|
|
|
if (!_videoURL.empty())
|
|
|
|
{
|
|
|
|
auto vplayer = reinterpret_cast<PrivateVideoDescriptor*>(_videoContext)->_vplayer;
|
|
|
|
if (vplayer)
|
|
|
|
{
|
|
|
|
switch (vplayer->GetState())
|
|
|
|
{
|
2023-03-25 08:37:51 +08:00
|
|
|
case MEMediaState::Closed:
|
|
|
|
vplayer->SetAutoPlay(true);
|
|
|
|
vplayer->Open(_videoURL);
|
2022-02-24 17:57:08 +08:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
vplayer->Play();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void VideoPlayer::pause()
|
|
|
|
{
|
|
|
|
if (!_videoURL.empty())
|
|
|
|
{
|
|
|
|
auto vplayer = reinterpret_cast<PrivateVideoDescriptor*>(_videoContext)->_vplayer;
|
|
|
|
if (vplayer)
|
|
|
|
vplayer->Pause();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void VideoPlayer::resume()
|
|
|
|
{
|
|
|
|
if (!_videoURL.empty())
|
|
|
|
{
|
|
|
|
auto vplayer = reinterpret_cast<PrivateVideoDescriptor*>(_videoContext)->_vplayer;
|
2022-02-24 18:30:58 +08:00
|
|
|
if (vplayer)
|
|
|
|
{
|
|
|
|
switch (vplayer->GetState())
|
|
|
|
{
|
2023-03-25 08:37:51 +08:00
|
|
|
case MEMediaState::Stopped:
|
|
|
|
case MEMediaState::Paused:
|
2022-02-24 18:30:58 +08:00
|
|
|
vplayer->Play();
|
|
|
|
}
|
|
|
|
}
|
2022-02-24 17:57:08 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void VideoPlayer::stop()
|
|
|
|
{
|
|
|
|
if (!_videoURL.empty())
|
|
|
|
{
|
|
|
|
auto vplayer = reinterpret_cast<PrivateVideoDescriptor*>(_videoContext)->_vplayer;
|
|
|
|
if (vplayer)
|
|
|
|
vplayer->Stop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void VideoPlayer::seekTo(float sec)
|
|
|
|
{
|
|
|
|
if (!_videoURL.empty())
|
|
|
|
{
|
|
|
|
auto vplayer = reinterpret_cast<PrivateVideoDescriptor*>(_videoContext)->_vplayer;
|
|
|
|
if (vplayer)
|
2023-03-25 08:37:51 +08:00
|
|
|
vplayer->SetCurrentTime(sec);
|
2022-02-24 17:57:08 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool VideoPlayer::isPlaying() const
|
|
|
|
{
|
|
|
|
return _isPlaying;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool VideoPlayer::isLooping() const
|
|
|
|
{
|
|
|
|
return _isLooping;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool VideoPlayer::isUserInputEnabled() const
|
|
|
|
{
|
|
|
|
return _isUserInputEnabled;
|
|
|
|
}
|
|
|
|
|
|
|
|
void VideoPlayer::setVisible(bool visible)
|
|
|
|
{
|
2022-08-08 18:02:17 +08:00
|
|
|
ax::ui::Widget::setVisible(visible);
|
2022-02-24 17:57:08 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void VideoPlayer::onEnter()
|
|
|
|
{
|
|
|
|
Widget::onEnter();
|
|
|
|
}
|
|
|
|
|
|
|
|
void VideoPlayer::onExit()
|
|
|
|
{
|
2023-03-25 08:37:51 +08:00
|
|
|
_eventCallback = nullptr;
|
2022-02-24 17:57:08 +08:00
|
|
|
Widget::onExit();
|
|
|
|
}
|
|
|
|
|
|
|
|
void VideoPlayer::addEventListener(const VideoPlayer::ccVideoPlayerCallback& callback)
|
|
|
|
{
|
|
|
|
_eventCallback = callback;
|
|
|
|
}
|
|
|
|
|
|
|
|
void VideoPlayer::onPlayEvent(int event)
|
|
|
|
{
|
|
|
|
_isPlaying = (event == (int)VideoPlayer::EventType::PLAYING);
|
|
|
|
|
|
|
|
if (_eventCallback)
|
|
|
|
{
|
2023-03-25 08:37:51 +08:00
|
|
|
_director->getScheduler()->runOnAxmolThread(std::bind(_eventCallback, this, (VideoPlayer::EventType)event));
|
2022-02-24 17:57:08 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-08 18:02:17 +08:00
|
|
|
ax::ui::Widget* VideoPlayer::createCloneInstance()
|
2022-02-24 17:57:08 +08:00
|
|
|
{
|
|
|
|
return VideoPlayer::create();
|
|
|
|
}
|
|
|
|
|
|
|
|
void VideoPlayer::copySpecialProperties(Widget* widget)
|
|
|
|
{
|
|
|
|
VideoPlayer* videoPlayer = dynamic_cast<VideoPlayer*>(widget);
|
|
|
|
if (videoPlayer)
|
|
|
|
{
|
|
|
|
_isPlaying = videoPlayer->_isPlaying;
|
|
|
|
_isLooping = videoPlayer->_isLooping;
|
|
|
|
_isUserInputEnabled = videoPlayer->_isUserInputEnabled;
|
|
|
|
_styleType = videoPlayer->_styleType;
|
|
|
|
_fullScreenEnabled = videoPlayer->_fullScreenEnabled;
|
|
|
|
_fullScreenDirty = videoPlayer->_fullScreenDirty;
|
|
|
|
_videoURL = videoPlayer->_videoURL;
|
|
|
|
_keepAspectRatioEnabled = videoPlayer->_keepAspectRatioEnabled;
|
|
|
|
_videoSource = videoPlayer->_videoSource;
|
|
|
|
_videoPlayerIndex = videoPlayer->_videoPlayerIndex;
|
|
|
|
_eventCallback = videoPlayer->_eventCallback;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|