Add the synchronization between Ui and Video player 34/235934/34
authorWonsik Jung <sidein@samsung.com>
Thu, 11 Jun 2020 05:52:18 +0000 (14:52 +0900)
committerWonsik Jung <sidein@samsung.com>
Fri, 24 Jul 2020 00:54:43 +0000 (09:54 +0900)
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

automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-video-player.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-window.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-window.h
automated-tests/src/dali-toolkit/utc-Dali-VideoView.cpp
dali-toolkit/devel-api/controls/video-view/video-view-devel.cpp
dali-toolkit/devel-api/controls/video-view/video-view-devel.h
dali-toolkit/internal/controls/video-view/video-view-impl.cpp
dali-toolkit/internal/controls/video-view/video-view-impl.h
dali-toolkit/public-api/controls/video-view/video-view.cpp

index 957681e..4a5e76c 100755 (executable)
@@ -16,6 +16,7 @@
  */
 
 #include <dali/devel-api/adaptor-framework/video-player.h>
+#include <dali/devel-api/adaptor-framework/video-sync-mode.h>
 #include <dali/public-api/object/any.h>
 #include <dali/public-api/object/base-object.h>
 #include <toolkit-application.h>
@@ -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;
 
index 72cbe65..3c01e99 100644 (file)
@@ -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();
index 2ff4370..000923a 100644 (file)
@@ -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 );
index e15a99a..24651f6 100644 (file)
@@ -21,6 +21,7 @@
 #include <dali-toolkit/dali-toolkit.h>
 #include <dali-toolkit/public-api/controls/video-view/video-view.h>
 #include <dali-toolkit/devel-api/controls/video-view/video-view-devel.h>
+#include <dali/devel-api/adaptor-framework/video-sync-mode.h>
 
 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<unsigned int>(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<unsigned int>(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;
+}
index 317d34d..41c6a30 100755 (executable)
@@ -33,6 +33,16 @@ Any GetMediaPlayer( VideoView videoView )
   return Dali::Toolkit::GetImpl( videoView ).GetMediaPlayer();\r
 }\r
 \r
+VideoView New( VideoSyncMode syncMode )\r
+{\r
+  VideoView videoView = Internal::VideoView::New( syncMode );\r
+  return videoView;\r
+}\r
+\r
+void PlayAnimation( VideoView videoView, Animation animation )\r
+{\r
+  Dali::Toolkit::GetImpl( videoView ).PlayAnimation( animation );\r
+}\r
 \r
 } // namespace DevelVideoView\r
 \r
index b121506..78edb3b 100755 (executable)
  *\r
  */\r
 \r
+// EXTERNAL INCLUDES\r
+#include <dali/devel-api/adaptor-framework/video-sync-mode.h>\r
+\r
 // INTERNAL INCLUDES\r
+#include <dali/public-api/animation/animation.h>\r
 #include <dali-toolkit/public-api/controls/video-view/video-view.h>\r
 #include <dali/public-api/object/any.h>\r
 \r
@@ -31,7 +35,6 @@ namespace Toolkit
 namespace DevelVideoView\r
 {\r
 \r
-\r
 /**\r
  * @brief Returns the internal media player.\r
  * @param[in] videoView The current VideoView\r
@@ -39,6 +42,26 @@ namespace DevelVideoView
  */\r
 DALI_TOOLKIT_API Any GetMediaPlayer( VideoView videoView );\r
 \r
+/**\r
+ * @brief Creates an initialized VideoView with synchronization mode.\r
+ *\r
+ * The syncMode is for synchronization between UI(transparent hole) and underlay video.\r
+ *\r
+ * @param[in] syncMode The synchronization mode between the UI (transparent hole) and VideoPlayer\r
+ * @return A handle to a newly allocated Dali VideoView\r
+ */\r
+DALI_TOOLKIT_API VideoView New( VideoSyncMode syncMode );\r
+\r
+/**\r
+ * @brief Play the resize or move animation with synchronization between UI(transparent hole) and video player\r
+ *\r
+ * The resize and move animation's play() function is called.\r
+ * If the animation is played, UI and video player will work synchronization.\r
+ *\r
+ * @param[in] videoView The current VideoView\r
+ * @param[in] animation The animation for video view's resize or move.\r
+ */\r
+DALI_TOOLKIT_API void PlayAnimation( VideoView videoView, Animation animation );\r
 \r
 } // namespace DevelVideoView\r
 \r
index a0a696a..2e34f27 100644 (file)
@@ -23,6 +23,7 @@
 #include <dali/public-api/object/type-registry.h>
 #include <dali/public-api/object/type-registry-helper.h>
 #include <dali/devel-api/scripting/scripting.h>
+#include <dali/devel-api/adaptor-framework/window-devel.h>
 #include <dali/public-api/adaptor-framework/native-image-source.h>
 #include <dali/integration-api/debug.h>
 #include <dali/public-api/animation/constraint.h>
@@ -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
index 200ab10..f10c1c0 100755 (executable)
@@ -27,6 +27,7 @@
 #include <dali/public-api/rendering/texture.h>
 #include <dali/devel-api/adaptor-framework/video-player.h>
 #include <dali/integration-api/adaptor-framework/trigger-event-factory.h>
+#include <dali/devel-api/adaptor-framework/video-sync-mode.h>
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/public-api/controls/control-impl.h>
@@ -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
index e709a58..ef478ff 100644 (file)
@@ -20,6 +20,7 @@
 
 // EXTERNAL INCLUDES
 #include <dali/public-api/object/property-map.h>
+#include <dali/devel-api/adaptor-framework/video-sync-mode.h>
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/controls/video-view/video-view-impl.h>
@@ -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;