There is no need to call mOverlayRenderer's AddRenderer() in play().
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / video-view / video-view-impl.cpp
1 /*
2  * Copyright (c) 2020 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include "video-view-impl.h"
20
21 // EXTERNAL INCLUDES
22 #include <cstring>
23 #include <dali/public-api/object/type-registry.h>
24 #include <dali/public-api/object/type-registry-helper.h>
25 #include <dali/devel-api/scripting/scripting.h>
26 #include <dali/devel-api/adaptor-framework/window-devel.h>
27 #include <dali/public-api/adaptor-framework/native-image-source.h>
28 #include <dali/integration-api/debug.h>
29 #include <dali/public-api/animation/constraint.h>
30 #include <dali/devel-api/actors/actor-devel.h>
31
32 // INTERNAL INCLUDES
33 #include <dali-toolkit/public-api/controls/video-view/video-view.h>
34 #include <dali-toolkit/internal/visuals/visual-factory-cache.h>
35 #include <dali/integration-api/adaptor-framework/adaptor.h>
36
37 namespace Dali
38 {
39
40 namespace Toolkit
41 {
42
43 namespace Internal
44 {
45
46 namespace
47 {
48
49 BaseHandle Create()
50 {
51   return Toolkit::VideoView::New();
52 }
53
54 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::VideoView, Toolkit::Control, Create );
55
56 DALI_PROPERTY_REGISTRATION( Toolkit, VideoView, "video", MAP, VIDEO )
57 DALI_PROPERTY_REGISTRATION( Toolkit, VideoView, "looping", BOOLEAN, LOOPING )
58 DALI_PROPERTY_REGISTRATION( Toolkit, VideoView, "muted", BOOLEAN, MUTED )
59 DALI_PROPERTY_REGISTRATION( Toolkit, VideoView, "volume", MAP, VOLUME )
60 DALI_PROPERTY_REGISTRATION( Toolkit, VideoView, "underlay", BOOLEAN, UNDERLAY )
61 DALI_PROPERTY_REGISTRATION( Toolkit, VideoView, "playPosition", INTEGER, PLAY_POSITION )
62 DALI_PROPERTY_REGISTRATION( Toolkit, VideoView, "displayMode", INTEGER, DISPLAY_MODE )
63
64 DALI_SIGNAL_REGISTRATION( Toolkit, VideoView, "finished", FINISHED_SIGNAL )
65
66 DALI_ACTION_REGISTRATION( Toolkit, VideoView, "play", ACTION_VIDEOVIEW_PLAY )
67 DALI_ACTION_REGISTRATION( Toolkit, VideoView, "pause", ACTION_VIDEOVIEW_PAUSE )
68 DALI_ACTION_REGISTRATION( Toolkit, VideoView, "stop", ACTION_VIDEOVIEW_STOP )
69 DALI_ACTION_REGISTRATION( Toolkit, VideoView, "forward", ACTION_VIDEOVIEW_FORWARD )
70 DALI_ACTION_REGISTRATION( Toolkit, VideoView, "backward", ACTION_VIDEOVIEW_BACKWARD )
71
72 DALI_TYPE_REGISTRATION_END()
73
74 const char* const VOLUME_LEFT( "volumeLeft" );
75 const char* const VOLUME_RIGHT( "volumeRight" );
76
77 // 3.0 TC uses RENDERING_TARGET. It should be removed in next release
78 const char* const RENDERING_TARGET( "renderingTarget" );
79 const char* const WINDOW_SURFACE_TARGET( "windowSurfaceTarget" );
80 const char* const NATIVE_IMAGE_TARGET( "nativeImageTarget" );
81
82 const char* const CUSTOM_SHADER( "shader" );
83 const char* const CUSTOM_VERTEX_SHADER( "vertexShader" );
84 const char* const CUSTOM_FRAGMENT_SHADER( "fragmentShader" );
85 const char* const DEFAULT_SAMPLER_TYPE_NAME( "sampler2D" );
86 const char* const CUSTOM_SAMPLER_TYPE_NAME( "samplerExternalOES" );
87
88 const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
89   attribute mediump vec2 aPosition;\n
90   uniform highp   mat4 uMvpMatrix;\n
91   uniform highp   vec3 uSize;\n
92   \n
93   void main()\n
94   {\n
95     mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
96     vertexPosition.xyz *= uSize;\n
97     gl_Position = uMvpMatrix * vertexPosition;\n
98   }\n
99 );
100
101 const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
102   \n
103   void main()\n
104   {\n
105     gl_FragColor = vec4(0.0);\n
106   }\n
107 );
108
109 const char* VERTEX_SHADER_TEXTURE = DALI_COMPOSE_SHADER(
110   attribute mediump vec2 aPosition;\n
111   varying mediump vec2 vTexCoord;\n
112   uniform highp   mat4 uMvpMatrix;\n
113   uniform highp   vec3 uSize;\n
114   varying mediump vec2 sTexCoordRect;\n
115   void main()\n
116   {\n
117     gl_Position = uMvpMatrix * vec4(aPosition * uSize.xy, 0.0, 1.0);\n
118     vTexCoord = aPosition + vec2(0.5);\n
119   }\n
120 );
121
122 const char* FRAGMENT_SHADER_TEXTURE = DALI_COMPOSE_SHADER(
123   uniform lowp vec4 uColor;\n
124   varying mediump vec2 vTexCoord;\n
125   uniform samplerExternalOES sTexture;\n
126   void main()\n
127   {\n
128     gl_FragColor = texture2D( sTexture, vTexCoord ) * uColor;\n
129   }\n
130 );
131
132 } // anonymous namepsace
133
134 VideoView::VideoView( Dali::VideoSyncMode syncMode )
135 : Control( ControlBehaviour( ACTOR_BEHAVIOUR_DEFAULT | DISABLE_STYLE_CHANGE_SIGNALS ) ),
136   mCurrentVideoPlayPosition( 0 ),
137   mFrameID( 0 ),
138   mIsPlay( false ),
139   mIsUnderlay( true ),
140   mSyncMode( syncMode )
141 {
142 }
143
144 VideoView::~VideoView()
145 {
146 }
147
148 Toolkit::VideoView VideoView::New( VideoSyncMode syncMode )
149 {
150   VideoView* impl = new VideoView( syncMode );
151   Toolkit::VideoView handle = Toolkit::VideoView( *impl );
152
153   impl->mVideoPlayer = Dali::VideoPlayer::New( impl->Self(), syncMode );
154   impl->Initialize();
155   return handle;
156 }
157
158 void VideoView::OnInitialize()
159 {
160   mVideoPlayer.FinishedSignal().Connect( this, &VideoView::EmitSignalFinish );
161 }
162
163 void VideoView::SetUrl( const std::string& url )
164 {
165     mUrl = url;
166     mPropertyMap.Clear();
167
168   mVideoPlayer.SetUrl( mUrl );
169 }
170
171 void VideoView::SetPropertyMap( Property::Map map )
172 {
173   mPropertyMap = map;
174
175   Property::Value* target = map.Find( RENDERING_TARGET );
176   std::string targetType;
177
178   if( target && target->Get( targetType ) && targetType == WINDOW_SURFACE_TARGET )
179   {
180     mIsUnderlay = true;
181     SetWindowSurfaceTarget();
182   }
183   else if( target && target->Get( targetType ) && targetType == NATIVE_IMAGE_TARGET )
184   {
185     mIsUnderlay = false;
186     SetNativeImageTarget();
187   }
188
189   // Custom shader
190   Property::Value* shaderValue;
191   if( !map.Empty() )
192   {
193     shaderValue = map.Find( CUSTOM_SHADER );
194
195     if( shaderValue )
196     {
197       Property::Map* shaderMap = shaderValue->GetMap();
198       if( shaderMap )
199       {
200         mEffectPropertyMap = *shaderMap;
201       }
202     }
203   }
204
205   if( mTextureRenderer && !mEffectPropertyMap.Empty() )
206   {
207     Dali::Shader shader = CreateShader();
208     mTextureRenderer.SetShader( shader );
209   }
210
211   RelayoutRequest();
212 }
213
214 std::string VideoView::GetUrl()
215 {
216   return mUrl;
217 }
218
219 void VideoView::SetLooping( bool looping )
220 {
221   mVideoPlayer.SetLooping( looping );
222 }
223
224 bool VideoView::IsLooping()
225 {
226   return mVideoPlayer.IsLooping();
227 }
228
229 void VideoView::Play()
230 {
231   mVideoPlayer.Play();
232   mIsPlay = true;
233 }
234
235 void VideoView::Pause()
236 {
237   mVideoPlayer.Pause();
238   mIsPlay = false;
239 }
240
241 void VideoView::Stop()
242 {
243   mVideoPlayer.Stop();
244   mIsPlay = false;
245 }
246
247 void VideoView::Forward( int millisecond )
248 {
249   int curPos = mVideoPlayer.GetPlayPosition();
250
251   int nextPos = curPos + millisecond;
252
253   mVideoPlayer.SetPlayPosition( nextPos );
254 }
255
256 void VideoView::Backward( int millisecond )
257 {
258   int curPos = mVideoPlayer.GetPlayPosition();
259
260   int nextPos = curPos - millisecond;
261   nextPos = ( nextPos < 0 )? 0: nextPos;
262
263   mVideoPlayer.SetPlayPosition( nextPos );
264 }
265
266 void VideoView::SetMute( bool mute )
267 {
268   mVideoPlayer.SetMute( mute );
269 }
270
271 bool VideoView::IsMuted()
272 {
273   return mVideoPlayer.IsMuted();
274 }
275
276 void VideoView::SetVolume( float left, float right )
277 {
278   mVideoPlayer.SetVolume( left, right );
279 }
280
281 void VideoView::GetVolume( float& left, float& right )
282 {
283   mVideoPlayer.GetVolume( left, right );
284 }
285
286 Dali::Toolkit::VideoView::VideoViewSignalType& VideoView::FinishedSignal()
287 {
288   return mFinishedSignal;
289 }
290
291 void VideoView::EmitSignalFinish()
292 {
293   if ( !mFinishedSignal.Empty() )
294   {
295     Dali::Toolkit::VideoView handle( GetOwner() );
296     mFinishedSignal.Emit( handle );
297   }
298 }
299
300 bool VideoView::DoAction( BaseObject* object, const std::string& actionName, const Property::Map& attributes )
301 {
302   bool ret = false;
303
304   Dali::BaseHandle handle( object );
305   Toolkit::VideoView videoView = Toolkit::VideoView::DownCast( handle );
306
307   if( !videoView )
308   {
309     return ret;
310   }
311
312   VideoView& impl = GetImpl( videoView );
313
314   if( strcmp( actionName.c_str(), ACTION_VIDEOVIEW_PLAY ) == 0 )
315   {
316     impl.Play();
317     ret = true;
318   }
319   else if( strcmp( actionName.c_str(), ACTION_VIDEOVIEW_PAUSE ) == 0 )
320   {
321     impl.Pause();
322     ret = true;
323   }
324   else if( strcmp( actionName.c_str(), ACTION_VIDEOVIEW_STOP ) == 0 )
325   {
326     impl.Stop();
327     ret = true;
328   }
329   else if( strcmp( actionName.c_str(), ACTION_VIDEOVIEW_FORWARD ) == 0 )
330   {
331     int millisecond = 0;
332     if( attributes["videoForward"].Get( millisecond ) )
333     {
334       impl.Forward( millisecond );
335       ret = true;
336     }
337   }
338   else if( strcmp( actionName.c_str(), ACTION_VIDEOVIEW_BACKWARD ) == 0 )
339   {
340     int millisecond = 0;
341     if( attributes["videoBackward"].Get( millisecond ) )
342     {
343       impl.Backward( millisecond );
344       ret = true;
345     }
346   }
347
348   return ret;
349 }
350
351 bool VideoView::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
352 {
353   Dali::BaseHandle handle( object );
354
355   bool connected( true );
356   Toolkit::VideoView videoView = Toolkit::VideoView::DownCast( handle );
357
358   if( 0 == strcmp( signalName.c_str(), FINISHED_SIGNAL ) )
359   {
360     videoView.FinishedSignal().Connect( tracker, functor );
361   }
362   else
363   {
364     // signalName does not match any signal
365     connected = false;
366   }
367
368   return connected;
369 }
370
371 void VideoView::SetPropertyInternal( Property::Index index, const Property::Value& value )
372 {
373   switch( index )
374   {
375     case Toolkit::VideoView::Property::VIDEO:
376     {
377       std::string videoUrl;
378       Property::Map map;
379
380       if( value.Get( videoUrl ) )
381       {
382         SetUrl( videoUrl );
383       }
384       else if( value.Get( map ) )
385       {
386         SetPropertyMap( map );
387       }
388       break;
389     }
390     case Toolkit::VideoView::Property::LOOPING:
391     {
392       bool looping;
393       if( value.Get( looping ) )
394       {
395         SetLooping( looping );
396       }
397       break;
398     }
399     case Toolkit::VideoView::Property::MUTED:
400     {
401       bool mute;
402       if( value.Get( mute ) )
403       {
404         SetMute( mute );
405       }
406       break;
407     }
408     case Toolkit::VideoView::Property::VOLUME:
409     {
410       Property::Map map;
411       float left, right;
412       if( value.Get( map ) )
413       {
414         Property::Value* volumeLeft = map.Find( VOLUME_LEFT );
415         Property::Value* volumeRight = map.Find( VOLUME_RIGHT );
416         if( volumeLeft && volumeLeft->Get( left ) && volumeRight && volumeRight->Get( right ) )
417         {
418           SetVolume( left, right );
419         }
420       }
421       break;
422     }
423     case Toolkit::VideoView::Property::UNDERLAY:
424     {
425       bool underlay;
426       if( value.Get( underlay ) )
427       {
428         SetUnderlay( underlay );
429       }
430       break;
431     }
432     case Toolkit::VideoView::Property::PLAY_POSITION:
433     {
434       int pos;
435       if( value.Get( pos ) )
436       {
437         SetPlayPosition( pos );
438       }
439       break;
440     }
441     case Toolkit::VideoView::Property::DISPLAY_MODE:
442     {
443       int mode;
444       if( value.Get( mode ) )
445       {
446         SetDisplayMode( mode );
447       }
448       break;
449     }
450   }
451 }
452
453 void VideoView::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
454 {
455   Toolkit::VideoView videoView = Toolkit::VideoView::DownCast( Dali::BaseHandle( object ) );
456
457   if( videoView )
458   {
459     VideoView& impl = GetImpl( videoView );
460
461     impl.SetPropertyInternal( index, value );
462
463     if( index != Toolkit::VideoView::Property::UNDERLAY )
464     {
465       // Backup values.
466       // These values will be used when underlay mode is changed.
467       impl.mPropertyBackup[index] = value;
468     }
469   }
470 }
471
472 Property::Value VideoView::GetProperty( BaseObject* object, Property::Index propertyIndex )
473 {
474   Property::Value value;
475   Toolkit::VideoView videoView = Toolkit::VideoView::DownCast( Dali::BaseHandle( object ) );
476
477   if( videoView )
478   {
479     VideoView& impl = GetImpl( videoView );
480
481     switch( propertyIndex )
482     {
483       case Toolkit::VideoView::Property::VIDEO:
484       {
485         if( !impl.mUrl.empty() )
486         {
487           value = impl.mUrl;
488         }
489         else if( !impl.mPropertyMap.Empty() )
490         {
491           value = impl.mPropertyMap;
492         }
493         break;
494       }
495       case Toolkit::VideoView::Property::LOOPING:
496       {
497         value = impl.IsLooping();
498         break;
499       }
500       case Toolkit::VideoView::Property::MUTED:
501       {
502         value = impl.IsMuted();
503         break;
504       }
505       case Toolkit::VideoView::Property::VOLUME:
506       {
507         Property::Map map;
508         float left, right;
509
510         impl.GetVolume( left, right );
511         map.Insert( VOLUME_LEFT, left );
512         map.Insert( VOLUME_RIGHT, right );
513         value = map;
514         break;
515       }
516       case Toolkit::VideoView::Property::UNDERLAY:
517       {
518         value = impl.IsUnderlay();
519         break;
520       }
521       case Toolkit::VideoView::Property::PLAY_POSITION:
522       {
523         value = impl.GetPlayPosition();
524         break;
525       }
526       case Toolkit::VideoView::Property::DISPLAY_MODE:
527       {
528         value = impl.GetDisplayMode();
529         break;
530       }
531     }
532   }
533
534   return value;
535 }
536
537 void VideoView::SetDepthIndex( int depthIndex )
538 {
539   if( mTextureRenderer )
540   {
541     mTextureRenderer.SetProperty( Renderer::Property::DEPTH_INDEX, depthIndex );
542   }
543 }
544
545 void VideoView::OnSceneConnection( int depth )
546 {
547   Control::OnSceneConnection( depth );
548
549   if( mIsUnderlay )
550   {
551     SetWindowSurfaceTarget();
552   }
553 }
554
555 void VideoView::OnSceneDisconnection()
556 {
557   Control::OnSceneDisconnection();
558 }
559
560 void VideoView::OnSizeSet( const Vector3& targetSize )
561 {
562   if( mIsUnderlay && mSyncMode == Dali::VideoSyncMode::ENABLED )
563   {
564     SetFrameRenderCallback();
565     mVideoPlayer.StartSynchronization();
566   }
567   Control::OnSizeSet( targetSize );
568 }
569
570 Vector3 VideoView::GetNaturalSize()
571 {
572   Vector3 size;
573   size.x = mVideoSize.GetWidth();
574   size.y = mVideoSize.GetHeight();
575
576   if( size.x > 0 && size.y > 0 )
577   {
578     size.z = std::min( size.x, size.y );
579     return size;
580   }
581   else
582   {
583     return Control::GetNaturalSize();
584   }
585 }
586
587 float VideoView::GetHeightForWidth( float width )
588 {
589   if( mVideoSize.GetWidth() > 0 && mVideoSize.GetHeight() > 0 )
590   {
591     return GetHeightForWidthBase( width );
592   }
593   else
594   {
595     return Control::GetHeightForWidthBase( width );
596   }
597 }
598
599 float VideoView::GetWidthForHeight( float height )
600 {
601   if( mVideoSize.GetWidth() > 0 && mVideoSize.GetHeight() > 0 )
602   {
603     return GetWidthForHeightBase( height );
604   }
605   else
606   {
607     return Control::GetWidthForHeightBase( height );
608   }
609 }
610
611 void VideoView::SetWindowSurfaceTarget()
612 {
613   Actor self = Self();
614
615   if( !self.GetProperty< bool >( Actor::Property::CONNECTED_TO_SCENE ) )
616   {
617     // When the control is off the stage, it does not have Window.
618     return;
619   }
620
621   int curPos = mVideoPlayer.GetPlayPosition();
622
623   if( mIsPlay )
624   {
625     mVideoPlayer.Pause();
626   }
627
628   mPositionUpdateNotification = self.AddPropertyNotification( Actor::Property::WORLD_POSITION, StepCondition( 1.0f, 1.0f ) );
629   mSizeUpdateNotification = self.AddPropertyNotification( Actor::Property::SIZE, StepCondition( 1.0f, 1.0f ) );
630   mScaleUpdateNotification = self.AddPropertyNotification( Actor::Property::WORLD_SCALE, StepCondition( 0.1f, 1.0f ) );
631   mPositionUpdateNotification.NotifySignal().Connect( this, &VideoView::UpdateDisplayArea );
632   mSizeUpdateNotification.NotifySignal().Connect( this, &VideoView::UpdateDisplayArea );
633   mScaleUpdateNotification.NotifySignal().Connect( this, &VideoView::UpdateDisplayArea );
634
635   if( mTextureRenderer )
636   {
637     self.RemoveRenderer( mTextureRenderer );
638   }
639
640   // Note VideoPlayer::SetRenderingTarget resets all the options. (e.g. url, mute, looping)
641   mVideoPlayer.SetRenderingTarget( Dali::Adaptor::Get().GetNativeWindowHandle( self ) );
642
643   ApplyBackupProperties();
644
645   if( !mOverlayRenderer )
646   {
647     // For underlay rendering mode, video display area have to be transparent.
648     Geometry geometry = VisualFactoryCache::CreateQuadGeometry();
649     Shader shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
650     mOverlayRenderer = Renderer::New( geometry, shader );
651     mOverlayRenderer.SetProperty( Renderer::Property::BLEND_MODE, BlendMode::OFF );
652   }
653   Self().AddRenderer( mOverlayRenderer );
654
655   if( mIsPlay )
656   {
657     Play();
658   }
659
660   if( curPos > 0 )
661   {
662     mVideoPlayer.SetPlayPosition( curPos );
663   }
664 }
665
666 void VideoView::SetNativeImageTarget()
667 {
668   if( mVideoPlayer.IsVideoTextureSupported() == false )
669   {
670     DALI_LOG_ERROR( "Platform doesn't support decoded video frame images\n" );
671     mIsUnderlay = true;
672     return;
673   }
674
675   if( mIsPlay )
676   {
677     mVideoPlayer.Pause();
678   }
679
680   Actor self( Self() );
681
682   if( mOverlayRenderer )
683   {
684     self.RemoveRenderer( mOverlayRenderer );
685
686     mOverlayRenderer.Reset();
687   }
688
689   self.RemovePropertyNotification( mPositionUpdateNotification );
690   self.RemovePropertyNotification( mSizeUpdateNotification );
691   self.RemovePropertyNotification( mScaleUpdateNotification );
692
693   int curPos = mVideoPlayer.GetPlayPosition();
694
695   Any source;
696   Dali::NativeImageSourcePtr nativeImageSourcePtr = Dali::NativeImageSource::New( source );
697   mNativeTexture = Dali::Texture::New( *nativeImageSourcePtr );
698
699   if( !mTextureRenderer )
700   {
701     Dali::Geometry geometry = VisualFactoryCache::CreateQuadGeometry();
702     Dali::Shader shader = CreateShader();
703     Dali::TextureSet textureSet = Dali::TextureSet::New();
704     textureSet.SetTexture( 0u, mNativeTexture );
705
706     mTextureRenderer = Renderer::New( geometry, shader );
707     mTextureRenderer.SetTextures( textureSet );
708   }
709   else
710   {
711     Dali::TextureSet textureSet = mTextureRenderer.GetTextures();
712     textureSet.SetTexture( 0u, mNativeTexture );
713   }
714   Self().AddRenderer( mTextureRenderer );
715
716   // Note VideoPlayer::SetRenderingTarget resets all the options. (e.g. url, mute, looping)
717   mVideoPlayer.SetRenderingTarget( nativeImageSourcePtr );
718
719   ApplyBackupProperties();
720
721   if( mIsPlay )
722   {
723     Play();
724   }
725
726   if( curPos > 0 )
727   {
728     mVideoPlayer.SetPlayPosition( curPos );
729   }
730 }
731
732 void VideoView::UpdateDisplayArea( Dali::PropertyNotification& source )
733 {
734   // If mSyncMode is enabled, Video player's size and poistion is updated in Video player's constraint.
735   // Because video view and player should be work syncronization.
736   if( !mIsUnderlay || mSyncMode == Dali::VideoSyncMode::ENABLED )
737   {
738     return;
739   }
740
741   Actor self( Self() );
742
743   bool positionUsesAnchorPoint = self.GetProperty( Actor::Property::POSITION_USES_ANCHOR_POINT ).Get< bool >();
744   Vector3 actorSize = self.GetCurrentProperty< Vector3 >( Actor::Property::SIZE ) * self.GetCurrentProperty< Vector3 >( Actor::Property::SCALE );
745   Vector3 anchorPointOffSet = actorSize * ( positionUsesAnchorPoint ? self.GetCurrentProperty< Vector3 >( Actor::Property::ANCHOR_POINT ) : AnchorPoint::TOP_LEFT );
746
747   Vector2 screenPosition = self.GetProperty( Actor::Property::SCREEN_POSITION ).Get< Vector2 >();
748
749   mDisplayArea.x = screenPosition.x - anchorPointOffSet.x;
750   mDisplayArea.y = screenPosition.y - anchorPointOffSet.y;
751   mDisplayArea.width = actorSize.x;
752   mDisplayArea.height = actorSize.y;
753
754   mVideoPlayer.SetDisplayArea( mDisplayArea );
755 }
756
757 void VideoView::SetUnderlay( bool set )
758 {
759   if( set != mIsUnderlay )
760   {
761     mIsUnderlay = set;
762
763     if( mIsUnderlay )
764     {
765       SetWindowSurfaceTarget();
766     }
767     else
768     {
769       SetNativeImageTarget();
770     }
771
772     RelayoutRequest();
773   }
774 }
775
776 bool VideoView::IsUnderlay()
777 {
778   return mIsUnderlay;
779 }
780
781 void VideoView::SetSWCodec( bool on )
782 {
783   // If setting SW or HW type is failed , video-view shows video by default codec type.
784   // The default codec type is selected by platform.
785   if( on )
786   {
787     mVideoPlayer.SetCodecType( Dali::VideoPlayerPlugin::CodecType::SW );
788   }
789   else
790   {
791     mVideoPlayer.SetCodecType( Dali::VideoPlayerPlugin::CodecType::HW );
792   }
793 }
794
795 int VideoView::GetPlayPosition()
796 {
797   return mVideoPlayer.GetPlayPosition();
798 }
799
800 void VideoView::SetPlayPosition( int pos )
801 {
802   mVideoPlayer.SetPlayPosition( pos );
803 }
804
805 void VideoView::SetDisplayMode( int mode )
806 {
807   mVideoPlayer.SetDisplayMode( static_cast< Dali::VideoPlayerPlugin::DisplayMode::Type >( mode ) );
808 }
809
810 int VideoView::GetDisplayMode() const
811 {
812   return static_cast< int >( mVideoPlayer.GetDisplayMode() );
813 }
814
815 Any VideoView::GetMediaPlayer()
816 {
817   return mVideoPlayer.GetMediaPlayer();
818 }
819
820 void VideoView::OnAnimationFinished( Animation& animation )
821 {
822   // send desync
823   SetFrameRenderCallback();
824 }
825
826 void VideoView::PlayAnimation( Dali::Animation animation )
827 {
828   if( mIsUnderlay && mSyncMode == Dali::VideoSyncMode::ENABLED )
829   {
830     mVideoPlayer.StartSynchronization();
831     animation.FinishedSignal().Connect( this, &VideoView::OnAnimationFinished );
832   }
833   animation.Play();
834 }
835
836 Dali::Shader VideoView::CreateShader()
837 {
838   std::string fragmentShader = "#extension GL_OES_EGL_image_external:require\n";
839   std::string vertexShader;
840   std::string customFragmentShader;
841   bool checkShader = false;
842
843   if( !mEffectPropertyMap.Empty() )
844   {
845     Property::Value* vertexShaderValue = mEffectPropertyMap.Find( CUSTOM_VERTEX_SHADER );
846     if( vertexShaderValue )
847     {
848       checkShader = GetStringFromProperty( *vertexShaderValue, vertexShader );
849     }
850
851     if( !vertexShaderValue || !checkShader )
852     {
853       vertexShader = VERTEX_SHADER_TEXTURE;
854     }
855
856     Property::Value* fragmentShaderValue = mEffectPropertyMap.Find( CUSTOM_FRAGMENT_SHADER );
857     if( fragmentShaderValue )
858     {
859       checkShader = GetStringFromProperty( *fragmentShaderValue, customFragmentShader );
860
861       if( checkShader )
862       {
863         fragmentShader = customFragmentShader;
864       }
865     }
866
867     if( !fragmentShaderValue || !checkShader )
868     {
869       fragmentShader += FRAGMENT_SHADER_TEXTURE;
870     }
871   }
872   else
873   {
874     vertexShader = VERTEX_SHADER_TEXTURE;
875     fragmentShader += FRAGMENT_SHADER_TEXTURE;
876   }
877
878   return Dali::Shader::New( vertexShader, fragmentShader );
879 }
880
881 bool VideoView::GetStringFromProperty( const Dali::Property::Value& value, std::string& output )
882 {
883   bool extracted = false;
884   if( value.Get( output ) )
885   {
886     extracted = true;
887   }
888
889   return extracted;
890 }
891
892 void VideoView::ApplyBackupProperties()
893 {
894   Property::Map::SizeType pos = 0;
895   Property::Map::SizeType count = mPropertyBackup.Count();
896
897   for( ; pos < count; pos++ )
898   {
899     KeyValuePair property = mPropertyBackup.GetKeyValue( pos );
900
901     SetPropertyInternal( property.first.indexKey, property.second );
902   }
903 }
904
905 void VideoView::FrameRenderCallback( int frameID )
906 {
907   // send desync
908   if( frameID == mFrameID )
909   {
910     mVideoPlayer.FinishSynchronization();
911     mFrameID = 0;
912   }
913 }
914
915 void VideoView::SetFrameRenderCallback()
916 {
917   mFrameID++;
918   DevelWindow::AddFrameRenderedCallback( DevelWindow::Get( Self() ),
919                                          std::unique_ptr< CallbackBase >( MakeCallback( this, &VideoView::FrameRenderCallback ) ), mFrameID );
920 }
921
922 } // namespace Internal
923
924 } // namespace toolkit
925
926 } // namespace Dali