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