From 1729f0da8849880dd20db5c6f045636e591a5b98 Mon Sep 17 00:00:00 2001 From: Wonsik Jung Date: Thu, 11 Jun 2020 14:52:18 +0900 Subject: [PATCH] Add the synchronization between Ui and Video player This patch is to support the synchronization between video player and UI. To do that, video player's changing function as resize/move should be called before calling eglSwapBuffers. Change-Id: Icfe0e0c2fee9d65a9df10827ed91faf38b09e720 --- .../toolkit-video-player.cpp | 27 ++++ .../dali-toolkit-test-utils/toolkit-window.cpp | 10 ++ .../dali-toolkit-test-utils/toolkit-window.h | 2 + .../src/dali-toolkit/utc-Dali-VideoView.cpp | 153 ++++++++++++++++++++- .../controls/video-view/video-view-devel.cpp | 10 ++ .../controls/video-view/video-view-devel.h | 25 +++- .../controls/video-view/video-view-impl.cpp | 61 +++++++- .../internal/controls/video-view/video-view-impl.h | 53 ++++++- .../public-api/controls/video-view/video-view.cpp | 9 +- 9 files changed, 333 insertions(+), 17 deletions(-) diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-video-player.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-video-player.cpp index 957681e..4a5e76c 100755 --- a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-video-player.cpp +++ b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-video-player.cpp @@ -16,6 +16,7 @@ */ #include +#include #include #include #include @@ -98,6 +99,15 @@ public: return NULL; } + void StartSynchronization() + { + + } + + void FinishSynchronization() + { + + } public: @@ -157,6 +167,13 @@ VideoPlayer VideoPlayer::New() return VideoPlayer( player ); } +VideoPlayer VideoPlayer::New( Dali::Actor actor, Dali::VideoSyncMode syncMode ) +{ + Internal::Adaptor::VideoPlayer* player = new Internal::Adaptor::VideoPlayer(); + + return VideoPlayer( player ); +} + VideoPlayer::VideoPlayer( const VideoPlayer& player ) : BaseHandle( player ) { @@ -298,5 +315,15 @@ Any VideoPlayer::GetMediaPlayer() return Internal::Adaptor::GetImplementation( *this ).GetMediaPlayer(); } +void VideoPlayer::StartSynchronization() +{ + Internal::Adaptor::GetImplementation( *this ).StartSynchronization(); +} + +void VideoPlayer::FinishSynchronization() +{ + Internal::Adaptor::GetImplementation( *this ).FinishSynchronization(); +} + } // namespace Dali; diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-window.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-window.cpp index 72cbe65..3c01e99 100644 --- a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-window.cpp +++ b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-window.cpp @@ -198,6 +198,16 @@ Window DownCast( BaseHandle handle ) return Dali::Window( windowImpl ); } +void AddFrameRenderedCallback( Window window, std::unique_ptr< CallbackBase > callback, int32_t frameId ) +{ + CallbackBase::Execute( *callback, frameId ); +} + +void AddFramePresentedCallback( Window window, std::unique_ptr< CallbackBase > callback, int32_t frameId ) +{ + CallbackBase::Execute( *callback, frameId ); +} + EventProcessingFinishedSignalType& EventProcessingFinishedSignal( Window window ) { return GetImplementation( window ).GetScene().EventProcessingFinishedSignal(); diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-window.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-window.h index 2ff4370..000923a 100644 --- a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-window.h +++ b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-window.h @@ -91,6 +91,8 @@ typedef Signal< void ( Window, bool ) > VisibilityChangedSignalType; Dali::Window Get( Actor actor ); Dali::Window DownCast( BaseHandle handle ); +void AddFrameRenderedCallback( Window window, std::unique_ptr< CallbackBase > callback, int32_t frameId ); +void AddFramePresentedCallback( Window window, std::unique_ptr< CallbackBase > callback, int32_t frameId ); EventProcessingFinishedSignalType& EventProcessingFinishedSignal( Window window ); KeyEventGeneratedSignalType& KeyEventGeneratedSignal( Dali::Window window ); diff --git a/automated-tests/src/dali-toolkit/utc-Dali-VideoView.cpp b/automated-tests/src/dali-toolkit/utc-Dali-VideoView.cpp index e15a99a..24651f6 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-VideoView.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-VideoView.cpp @@ -21,6 +21,7 @@ #include #include #include +#include using namespace Dali; using namespace Dali::Toolkit; @@ -31,6 +32,7 @@ const char* const TEST_FILE( "test.mp4" ); const char* const VOLUME_LEFT( "volumeLeft" ); const char* const VOLUME_RIGHT( "volumeRight" ); const char* const RENDERING_TYPE( "renderingTarget" ); +const char* const DUMMY_STRING( "dummy string" ); const char* VERTEX_SHADER = DALI_COMPOSE_SHADER( attribute mediump vec2 aPosition;\n @@ -106,7 +108,8 @@ int UtcDaliVideoViewNew(void) Toolkit::VideoView view = Toolkit::VideoView::New(); DALI_TEST_CHECK( view ); - Toolkit::VideoView view2 = Toolkit::VideoView::New( "" ); + const std::string url( DUMMY_STRING ); + Toolkit::VideoView view2 = Toolkit::VideoView::New( url ); DALI_TEST_CHECK( view2 ); END_TEST; } @@ -546,7 +549,7 @@ int UtcDaliVideoViewCustomShader(void) ToolkitTestApplication application; tet_infoline( "VideoView with custom shader" ); - VideoView view = VideoView::New(); + VideoView view = VideoView::New( false ); DALI_TEST_CHECK( view ); ToolkitApplication::DECODED_IMAGES_SUPPORTED = true; @@ -597,3 +600,149 @@ int UtcDaliVideoViewCustomShader(void) END_TEST; } + +// Functor to test whether a Finish signal is emitted +struct AnimationFinishCheck +{ + AnimationFinishCheck(bool& signalReceived) + : mSignalReceived(signalReceived) + { + } + + void operator()(Animation& animation) + { + mSignalReceived = true; + } + + void Reset() + { + mSignalReceived = false; + } + + void CheckSignalReceived() + { + if (!mSignalReceived) + { + tet_printf("Expected Finish signal was not received\n"); + tet_result(TET_FAIL); + } + else + { + tet_result(TET_PASS); + } + } + + void CheckSignalNotReceived() + { + if (mSignalReceived) + { + tet_printf("Unexpected Finish signal was received\n"); + tet_result(TET_FAIL); + } + else + { + tet_result(TET_PASS); + } + } + + bool& mSignalReceived; // owned by individual tests +}; + +int UtcDaliVideoViewSyncAniamtionForCoverage(void) +{ + ToolkitTestApplication application; + + VideoView videoView = DevelVideoView::New( Dali::VideoSyncMode::ENABLED ); + DALI_TEST_CHECK( videoView ); + + // Build the animation + float durationSeconds(1.0f); + Animation animation = Animation::New(durationSeconds); + + // Start the animation + Vector3 targetPosition(10.0f, 10.0f, 10.0f); + animation.AnimateTo(Property(videoView, Actor::Property::POSITION), targetPosition, AlphaFunction::LINEAR); + DevelVideoView::PlayAnimation( videoView, animation ); + + bool signalReceived(false); + AnimationFinishCheck finishCheck(signalReceived); + animation.FinishedSignal().Connect(&application, finishCheck); + + application.SendNotification(); + application.Render(static_cast(durationSeconds*1000.0f) - 1u/*just less than the animation duration*/); + + // We didn't expect the animation to finish yet + application.SendNotification(); + finishCheck.CheckSignalNotReceived(); + + application.Render(2u/*just beyond the animation duration*/); + + // We did expect the animation to finish + application.SendNotification(); + finishCheck.CheckSignalReceived(); + DALI_TEST_EQUALS( targetPosition, videoView.GetCurrentProperty< Vector3 >( Actor::Property::POSITION ), TEST_LOCATION ); + + // Restart the animation, with a different duration + finishCheck.Reset(); + + END_TEST; +} + +int UtcDaliVideoViewASyncAniamtionForCoverage(void) +{ + ToolkitTestApplication application; + + VideoView videoView = DevelVideoView::New( Dali::VideoSyncMode::DISABLED ); + DALI_TEST_CHECK( videoView ); + + // Build the animation + float durationSeconds(1.0f); + Animation animation = Animation::New(durationSeconds); + + // Start the animation + Vector3 targetPosition(10.0f, 10.0f, 10.0f); + animation.AnimateTo(Property(videoView, Actor::Property::POSITION), targetPosition, AlphaFunction::LINEAR); + DevelVideoView::PlayAnimation( videoView, animation ); + + bool signalReceived(false); + AnimationFinishCheck finishCheck(signalReceived); + animation.FinishedSignal().Connect(&application, finishCheck); + + application.SendNotification(); + application.Render(static_cast(durationSeconds*1000.0f) - 1u/*just less than the animation duration*/); + + // We didn't expect the animation to finish yet + application.SendNotification(); + finishCheck.CheckSignalNotReceived(); + + application.Render(2u/*just beyond the animation duration*/); + + // We did expect the animation to finish + application.SendNotification(); + finishCheck.CheckSignalReceived(); + DALI_TEST_EQUALS( targetPosition, videoView.GetCurrentProperty< Vector3 >( Actor::Property::POSITION ), TEST_LOCATION ); + + // Restart the animation, with a different duration + finishCheck.Reset(); + + END_TEST; +} + +int UtcDaliVideoViewResizeWithSynchronization(void) +{ + ToolkitTestApplication application; + VideoView videoView = DevelVideoView::New( Dali::VideoSyncMode::ENABLED ); + DALI_TEST_CHECK( videoView ); + + application.GetScene().Add( videoView ); + + Vector3 vector(50.0f, 200.0f, 0.0f); + videoView.SetProperty( Actor::Property::SIZE, vector ); + + application.SendNotification(); + application.Render(); + + DALI_TEST_CHECK(vector == videoView.GetCurrentProperty< Vector3 >( Actor::Property::SIZE )); + + END_TEST; +} diff --git a/dali-toolkit/devel-api/controls/video-view/video-view-devel.cpp b/dali-toolkit/devel-api/controls/video-view/video-view-devel.cpp index 317d34d..41c6a30 100755 --- a/dali-toolkit/devel-api/controls/video-view/video-view-devel.cpp +++ b/dali-toolkit/devel-api/controls/video-view/video-view-devel.cpp @@ -33,6 +33,16 @@ Any GetMediaPlayer( VideoView videoView ) return Dali::Toolkit::GetImpl( videoView ).GetMediaPlayer(); } +VideoView New( VideoSyncMode syncMode ) +{ + VideoView videoView = Internal::VideoView::New( syncMode ); + return videoView; +} + +void PlayAnimation( VideoView videoView, Animation animation ) +{ + Dali::Toolkit::GetImpl( videoView ).PlayAnimation( animation ); +} } // namespace DevelVideoView diff --git a/dali-toolkit/devel-api/controls/video-view/video-view-devel.h b/dali-toolkit/devel-api/controls/video-view/video-view-devel.h index b121506..78edb3b 100755 --- a/dali-toolkit/devel-api/controls/video-view/video-view-devel.h +++ b/dali-toolkit/devel-api/controls/video-view/video-view-devel.h @@ -18,7 +18,11 @@ * */ +// EXTERNAL INCLUDES +#include + // INTERNAL INCLUDES +#include #include #include @@ -31,7 +35,6 @@ namespace Toolkit namespace DevelVideoView { - /** * @brief Returns the internal media player. * @param[in] videoView The current VideoView @@ -39,6 +42,26 @@ namespace DevelVideoView */ DALI_TOOLKIT_API Any GetMediaPlayer( VideoView videoView ); +/** + * @brief Creates an initialized VideoView with synchronization mode. + * + * The syncMode is for synchronization between UI(transparent hole) and underlay video. + * + * @param[in] syncMode The synchronization mode between the UI (transparent hole) and VideoPlayer + * @return A handle to a newly allocated Dali VideoView + */ +DALI_TOOLKIT_API VideoView New( VideoSyncMode syncMode ); + +/** + * @brief Play the resize or move animation with synchronization between UI(transparent hole) and video player + * + * The resize and move animation's play() function is called. + * If the animation is played, UI and video player will work synchronization. + * + * @param[in] videoView The current VideoView + * @param[in] animation The animation for video view's resize or move. + */ +DALI_TOOLKIT_API void PlayAnimation( VideoView videoView, Animation animation ); } // namespace DevelVideoView diff --git a/dali-toolkit/internal/controls/video-view/video-view-impl.cpp b/dali-toolkit/internal/controls/video-view/video-view-impl.cpp index a0a696a..2e34f27 100644 --- a/dali-toolkit/internal/controls/video-view/video-view-impl.cpp +++ b/dali-toolkit/internal/controls/video-view/video-view-impl.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -130,26 +131,27 @@ const char* FRAGMENT_SHADER_TEXTURE = DALI_COMPOSE_SHADER( } // anonymous namepsace -VideoView::VideoView() +VideoView::VideoView( Dali::VideoSyncMode syncMode ) : Control( ControlBehaviour( ACTOR_BEHAVIOUR_DEFAULT | DISABLE_STYLE_CHANGE_SIGNALS ) ), mCurrentVideoPlayPosition( 0 ), + mFrameID( 0 ), mIsPlay( false ), - mIsUnderlay( true ) + mIsUnderlay( true ), + mSyncMode( syncMode ) { - mVideoPlayer = Dali::VideoPlayer::New(); } VideoView::~VideoView() { } -Toolkit::VideoView VideoView::New() +Toolkit::VideoView VideoView::New( VideoSyncMode syncMode ) { - VideoView* impl = new VideoView(); + VideoView* impl = new VideoView( syncMode ); Toolkit::VideoView handle = Toolkit::VideoView( *impl ); + impl->mVideoPlayer = Dali::VideoPlayer::New( impl->Self(), syncMode ); impl->Initialize(); - return handle; } @@ -565,6 +567,16 @@ void VideoView::OnStageDisconnection() Control::OnStageDisconnection(); } +void VideoView::OnSizeSet( const Vector3& targetSize ) +{ + if( mIsUnderlay && mSyncMode == Dali::VideoSyncMode::ENABLED ) + { + SetFrameRenderCallback(); + mVideoPlayer.StartSynchronization(); + } + Control::OnSizeSet( targetSize ); +} + Vector3 VideoView::GetNaturalSize() { Vector3 size; @@ -728,7 +740,9 @@ void VideoView::SetNativeImageTarget() void VideoView::UpdateDisplayArea( Dali::PropertyNotification& source ) { - if( !mIsUnderlay ) + // If mSyncMode is enabled, Video player's size and poistion is updated in Video player's constraint. + // Because video view and player should be work syncronization. + if( !mIsUnderlay || mSyncMode == Dali::VideoSyncMode::ENABLED ) { return; } @@ -812,6 +826,22 @@ Any VideoView::GetMediaPlayer() return mVideoPlayer.GetMediaPlayer(); } +void VideoView::OnAnimationFinished( Animation& animation ) +{ + // send desync + SetFrameRenderCallback(); +} + +void VideoView::PlayAnimation( Dali::Animation animation ) +{ + if( mIsUnderlay && mSyncMode == Dali::VideoSyncMode::ENABLED ) + { + mVideoPlayer.StartSynchronization(); + animation.FinishedSignal().Connect( this, &VideoView::OnAnimationFinished ); + } + animation.Play(); +} + Dali::Shader VideoView::CreateShader() { std::string fragmentShader = "#extension GL_OES_EGL_image_external:require\n"; @@ -881,6 +911,23 @@ void VideoView::ApplyBackupProperties() } } +void VideoView::FrameRenderCallback( int frameID ) +{ + // send desync + if( frameID == mFrameID ) + { + mVideoPlayer.FinishSynchronization(); + mFrameID = 0; + } +} + +void VideoView::SetFrameRenderCallback() +{ + mFrameID++; + DevelWindow::AddFrameRenderedCallback( DevelWindow::Get( Self() ), + std::unique_ptr< CallbackBase >( MakeCallback( this, &VideoView::FrameRenderCallback ) ), mFrameID ); +} + } // namespace Internal } // namespace toolkit diff --git a/dali-toolkit/internal/controls/video-view/video-view-impl.h b/dali-toolkit/internal/controls/video-view/video-view-impl.h index 200ab10..f10c1c0 100755 --- a/dali-toolkit/internal/controls/video-view/video-view-impl.h +++ b/dali-toolkit/internal/controls/video-view/video-view-impl.h @@ -27,6 +27,7 @@ #include #include #include +#include // INTERNAL INCLUDES #include @@ -47,16 +48,16 @@ class VideoView: public Control { protected: - VideoView(); + VideoView( Dali::VideoSyncMode syncMode ); virtual ~VideoView(); public: /** - * @copydoc Toolkit::VideoView::New() + * @copydoc Toolkit::DevelVideoView::New() */ - static Toolkit::VideoView New(); + static Toolkit::VideoView New( VideoSyncMode syncMode ); /** * @brief Sets a video url to play. @@ -255,6 +256,17 @@ public: */ Any GetMediaPlayer(); + /** + * @brief Play the resize or move animation with synchronization between UI(transparent hole) and video player + * + * The resize and move animation's play() function is called. + * If the animation is played, UI and video player will work synchronization. + * + * @param[in] videoView The current VideoView + * @param[in] animation The animation for video view's resize or move. + */ + void PlayAnimation( Dali::Animation animation ); + private: // From Control /** @@ -273,6 +285,11 @@ private: // From Control virtual void OnStageDisconnection(); /** + * @copydoc Toolkit::Control::OnSizeSet() + */ + virtual void OnSizeSet( const Vector3& targetSize ); + + /** * @copydoc Toolkit::Control::GetNaturalSize */ virtual Vector3 GetNaturalSize(); @@ -330,6 +347,32 @@ private: */ void ApplyBackupProperties(); + /* + * @brief FrameRender's callback function + * + * This function means the resize/move animation is finished, + * so Ui and video player's synchronization can be finished. + * + */ + void FrameRenderCallback( int frameID ); + + /* + * @brief Set frameRender Callback function + * + * This function is added for listenr the resize/move animation is finished, + * + */ + void SetFrameRenderCallback(); + + + /* + * @brief resize/move animation finished callback function + * + * This function is called the resize/move animation is finished, + * + */ + void OnAnimationFinished( Dali::Animation& animation ); + private: Dali::VideoPlayer mVideoPlayer; @@ -348,8 +391,12 @@ private: Dali::Property::Map mPropertyBackup; int mCurrentVideoPlayPosition; + int mFrameID; + bool mIsPlay; bool mIsUnderlay; + + Dali::VideoSyncMode mSyncMode; }; } // namespace Internal diff --git a/dali-toolkit/public-api/controls/video-view/video-view.cpp b/dali-toolkit/public-api/controls/video-view/video-view.cpp index e709a58..ef478ff 100644 --- a/dali-toolkit/public-api/controls/video-view/video-view.cpp +++ b/dali-toolkit/public-api/controls/video-view/video-view.cpp @@ -20,6 +20,7 @@ // EXTERNAL INCLUDES #include +#include // INTERNAL INCLUDES #include @@ -55,26 +56,26 @@ VideoView::~VideoView() VideoView VideoView::New() { - return Internal::VideoView::New(); + return Internal::VideoView::New( Dali::VideoSyncMode::DISABLED ); } VideoView VideoView::New( const std::string& url ) { - VideoView videoView = Internal::VideoView::New(); + VideoView videoView = Internal::VideoView::New( Dali::VideoSyncMode::DISABLED ); Dali::Toolkit::GetImpl( videoView ).SetUrl( url ); return videoView; } VideoView VideoView::New( bool swCodec ) { - VideoView videoView = Internal::VideoView::New(); + VideoView videoView = Internal::VideoView::New( Dali::VideoSyncMode::DISABLED ); Dali::Toolkit::GetImpl( videoView ).SetSWCodec( swCodec ); return videoView; } VideoView VideoView::New( const std::string& url, bool swCodec ) { - VideoView videoView = Internal::VideoView::New(); + VideoView videoView = Internal::VideoView::New( Dali::VideoSyncMode::DISABLED ); Dali::Toolkit::GetImpl( videoView ).SetUrl( url ); Dali::Toolkit::GetImpl( videoView ).SetSWCodec( swCodec ); return videoView; -- 2.7.4