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