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