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