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