2 * Copyright (c) 2021 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include "video-view-impl.h"
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>
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>
50 return Toolkit::VideoView::New();
53 DALI_TYPE_REGISTRATION_BEGIN(Toolkit::VideoView, Toolkit::Control, Create);
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)
63 DALI_SIGNAL_REGISTRATION(Toolkit, VideoView, "finished", FINISHED_SIGNAL)
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)
71 DALI_TYPE_REGISTRATION_END()
73 const char* const VOLUME_LEFT("volumeLeft");
74 const char* const VOLUME_RIGHT("volumeRight");
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");
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");
87 const char* const IS_VIDEO_VIEW_PROPERTY_NAME = "isVideoView";
91 VideoView::VideoView(Dali::VideoSyncMode syncMode)
92 : Control(ControlBehaviour(ACTOR_BEHAVIOUR_DEFAULT | DISABLE_STYLE_CHANGE_SIGNALS)),
93 mCurrentVideoPlayPosition(0),
102 VideoView::~VideoView()
106 Toolkit::VideoView VideoView::New(VideoSyncMode syncMode)
108 VideoView* impl = new VideoView(syncMode);
109 Toolkit::VideoView handle = Toolkit::VideoView(*impl);
111 impl->mVideoPlayer = Dali::VideoPlayer::New(impl->Self(), syncMode);
116 void VideoView::OnInitialize()
119 mVideoPlayer.FinishedSignal().Connect(this, &VideoView::EmitSignalFinish);
121 DevelControl::SetAccessibilityConstructor(self, [](Dali::Actor actor) {
122 return std::unique_ptr<Dali::Accessibility::Accessible>(
123 new DevelControl::ControlAccessible(actor, Dali::Accessibility::Role::VIDEO));
126 //Enable highightability
127 Self().SetProperty(Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE, true);
129 //update self property
130 self.RegisterProperty(IS_VIDEO_VIEW_PROPERTY_NAME, true, Property::READ_WRITE);
133 void VideoView::SetUrl(const std::string& url)
136 mPropertyMap.Clear();
138 mVideoPlayer.SetUrl(mUrl);
141 void VideoView::SetPropertyMap(Property::Map map)
145 Property::Value* target = map.Find(RENDERING_TARGET);
146 std::string targetType;
148 if(target && target->Get(targetType) && targetType == WINDOW_SURFACE_TARGET)
151 SetWindowSurfaceTarget();
153 else if(target && target->Get(targetType) && targetType == NATIVE_IMAGE_TARGET)
156 SetNativeImageTarget();
160 Property::Value* shaderValue;
163 shaderValue = map.Find(CUSTOM_SHADER);
167 Property::Map* shaderMap = shaderValue->GetMap();
170 mEffectPropertyMap = *shaderMap;
175 if(mTextureRenderer && !mEffectPropertyMap.Empty())
177 Dali::Shader shader = CreateShader();
178 mTextureRenderer.SetShader(shader);
184 std::string VideoView::GetUrl()
189 void VideoView::SetLooping(bool looping)
191 mVideoPlayer.SetLooping(looping);
194 bool VideoView::IsLooping()
196 return mVideoPlayer.IsLooping();
199 void VideoView::Play()
205 void VideoView::Pause()
207 mVideoPlayer.Pause();
211 void VideoView::Stop()
217 void VideoView::Forward(int millisecond)
219 int curPos = mVideoPlayer.GetPlayPosition();
221 int nextPos = curPos + millisecond;
223 mVideoPlayer.SetPlayPosition(nextPos);
226 void VideoView::Backward(int millisecond)
228 int curPos = mVideoPlayer.GetPlayPosition();
230 int nextPos = curPos - millisecond;
231 nextPos = (nextPos < 0) ? 0 : nextPos;
233 mVideoPlayer.SetPlayPosition(nextPos);
236 void VideoView::SetMute(bool mute)
238 mVideoPlayer.SetMute(mute);
241 bool VideoView::IsMuted()
243 return mVideoPlayer.IsMuted();
246 void VideoView::SetVolume(float left, float right)
248 mVideoPlayer.SetVolume(left, right);
251 void VideoView::GetVolume(float& left, float& right)
253 mVideoPlayer.GetVolume(left, right);
256 Dali::Toolkit::VideoView::VideoViewSignalType& VideoView::FinishedSignal()
258 return mFinishedSignal;
261 void VideoView::EmitSignalFinish()
263 if(!mFinishedSignal.Empty())
265 Dali::Toolkit::VideoView handle(GetOwner());
266 mFinishedSignal.Emit(handle);
270 bool VideoView::DoAction(BaseObject* object, const std::string& actionName, const Property::Map& attributes)
274 Dali::BaseHandle handle(object);
275 Toolkit::VideoView videoView = Toolkit::VideoView::DownCast(handle);
282 VideoView& impl = GetImpl(videoView);
284 if(strcmp(actionName.c_str(), ACTION_VIDEOVIEW_PLAY) == 0)
289 else if(strcmp(actionName.c_str(), ACTION_VIDEOVIEW_PAUSE) == 0)
294 else if(strcmp(actionName.c_str(), ACTION_VIDEOVIEW_STOP) == 0)
299 else if(strcmp(actionName.c_str(), ACTION_VIDEOVIEW_FORWARD) == 0)
302 if(attributes["videoForward"].Get(millisecond))
304 impl.Forward(millisecond);
308 else if(strcmp(actionName.c_str(), ACTION_VIDEOVIEW_BACKWARD) == 0)
311 if(attributes["videoBackward"].Get(millisecond))
313 impl.Backward(millisecond);
321 bool VideoView::DoConnectSignal(BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor)
323 Dali::BaseHandle handle(object);
325 bool connected(true);
326 Toolkit::VideoView videoView = Toolkit::VideoView::DownCast(handle);
328 if(0 == strcmp(signalName.c_str(), FINISHED_SIGNAL))
330 videoView.FinishedSignal().Connect(tracker, functor);
334 // signalName does not match any signal
341 void VideoView::SetPropertyInternal(Property::Index index, const Property::Value& value)
345 case Toolkit::VideoView::Property::VIDEO:
347 std::string videoUrl;
350 if(value.Get(videoUrl))
354 else if(value.Get(map))
360 case Toolkit::VideoView::Property::LOOPING:
363 if(value.Get(looping))
369 case Toolkit::VideoView::Property::MUTED:
378 case Toolkit::VideoView::Property::VOLUME:
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))
388 SetVolume(left, right);
393 case Toolkit::VideoView::Property::UNDERLAY:
396 if(value.Get(underlay))
398 SetUnderlay(underlay);
402 case Toolkit::VideoView::Property::PLAY_POSITION:
407 SetPlayPosition(pos);
411 case Toolkit::VideoView::Property::DISPLAY_MODE:
416 SetDisplayMode(mode);
423 void VideoView::SetProperty(BaseObject* object, Property::Index index, const Property::Value& value)
425 Toolkit::VideoView videoView = Toolkit::VideoView::DownCast(Dali::BaseHandle(object));
429 VideoView& impl = GetImpl(videoView);
431 impl.SetPropertyInternal(index, value);
433 if(index != Toolkit::VideoView::Property::UNDERLAY)
436 // These values will be used when underlay mode is changed.
437 impl.mPropertyBackup[index] = value;
442 Property::Value VideoView::GetProperty(BaseObject* object, Property::Index propertyIndex)
444 Property::Value value;
445 Toolkit::VideoView videoView = Toolkit::VideoView::DownCast(Dali::BaseHandle(object));
449 VideoView& impl = GetImpl(videoView);
451 switch(propertyIndex)
453 case Toolkit::VideoView::Property::VIDEO:
455 if(!impl.mUrl.empty())
459 else if(!impl.mPropertyMap.Empty())
461 value = impl.mPropertyMap;
465 case Toolkit::VideoView::Property::LOOPING:
467 value = impl.IsLooping();
470 case Toolkit::VideoView::Property::MUTED:
472 value = impl.IsMuted();
475 case Toolkit::VideoView::Property::VOLUME:
480 impl.GetVolume(left, right);
481 map.Insert(VOLUME_LEFT, left);
482 map.Insert(VOLUME_RIGHT, right);
486 case Toolkit::VideoView::Property::UNDERLAY:
488 value = impl.IsUnderlay();
491 case Toolkit::VideoView::Property::PLAY_POSITION:
493 value = impl.GetPlayPosition();
496 case Toolkit::VideoView::Property::DISPLAY_MODE:
498 value = impl.GetDisplayMode();
507 void VideoView::SetDepthIndex(int depthIndex)
511 mTextureRenderer.SetProperty(Renderer::Property::DEPTH_INDEX, depthIndex);
515 void VideoView::OnSceneConnection(int depth)
520 mSiblingOrder = self.GetProperty<int>(Dali::DevelActor::Property::SIBLING_ORDER);
521 DevelActor::ChildOrderChangedSignal(self.GetParent()).Connect(this, &VideoView::OnChildOrderChanged);
522 SetWindowSurfaceTarget();
525 Control::OnSceneConnection(depth);
528 void VideoView::OnSceneDisconnection()
530 Control::OnSceneDisconnection();
533 void VideoView::OnSizeSet(const Vector3& targetSize)
535 if(mIsUnderlay && mSyncMode == Dali::VideoSyncMode::ENABLED)
537 SetFrameRenderCallback();
538 mVideoPlayer.StartSynchronization();
540 Control::OnSizeSet(targetSize);
543 void VideoView::OnChildOrderChanged(Actor actor)
546 int currentSiblingOrder = self.GetProperty<int>(Dali::DevelActor::Property::SIBLING_ORDER);
547 if(currentSiblingOrder != mSiblingOrder)
549 Actor parent = self.GetParent();
554 int numChildren = static_cast<int>(parent.GetChildCount());
555 for(int i = 0; i < numChildren; i++)
557 child = parent.GetChildAt(i);
558 if(!IsVideoView(child))
568 if(i < currentSiblingOrder)
572 else if(i > currentSiblingOrder)
581 Toolkit::VideoView lowerView = Toolkit::VideoView::DownCast(lower);
582 mVideoPlayer.RaiseAbove(GetImpl(lowerView).GetVideoPlayer());
587 Toolkit::VideoView upperView = Toolkit::VideoView::DownCast(upper);
588 mVideoPlayer.LowerBelow(GetImpl(upperView).GetVideoPlayer());
590 mSiblingOrder = currentSiblingOrder;
594 Vector3 VideoView::GetNaturalSize()
597 size.x = mVideoSize.GetWidth();
598 size.y = mVideoSize.GetHeight();
600 if(size.x > 0 && size.y > 0)
602 size.z = std::min(size.x, size.y);
607 return Control::GetNaturalSize();
611 void VideoView::SetWindowSurfaceTarget()
615 if(!self.GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE))
617 // When the control is off the stage, it does not have Window.
621 Dali::Window window = DevelWindow::Get(self);
622 window.ResizeSignal().Connect(this, &VideoView::OnWindowResized);
624 int curPos = mVideoPlayer.GetPlayPosition();
628 mVideoPlayer.Pause();
631 mPositionUpdateNotification = self.AddPropertyNotification(Actor::Property::WORLD_POSITION, StepCondition(1.0f, 1.0f));
632 mSizeUpdateNotification = self.AddPropertyNotification(Actor::Property::SIZE, StepCondition(1.0f, 1.0f));
633 mScaleUpdateNotification = self.AddPropertyNotification(Actor::Property::WORLD_SCALE, StepCondition(0.1f, 1.0f));
634 mPositionUpdateNotification.NotifySignal().Connect(this, &VideoView::UpdateDisplayArea);
635 mSizeUpdateNotification.NotifySignal().Connect(this, &VideoView::UpdateDisplayArea);
636 mScaleUpdateNotification.NotifySignal().Connect(this, &VideoView::UpdateDisplayArea);
640 self.RemoveRenderer(mTextureRenderer);
643 // Note VideoPlayer::SetRenderingTarget resets all the options. (e.g. url, mute, looping)
644 mVideoPlayer.SetRenderingTarget(Dali::Adaptor::Get().GetNativeWindowHandle(self));
646 ApplyBackupProperties();
648 if(!mOverlayRenderer)
650 // For underlay rendering mode, video display area have to be transparent.
651 Geometry geometry = VisualFactoryCache::CreateQuadGeometry();
652 Shader shader = Shader::New(SHADER_VIDEO_VIEW_VERT, SHADER_VIDEO_VIEW_FRAG);
653 mOverlayRenderer = Renderer::New(geometry, shader);
654 mOverlayRenderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::OFF);
656 Self().AddRenderer(mOverlayRenderer);
665 mVideoPlayer.SetPlayPosition(curPos);
669 void VideoView::SetNativeImageTarget()
671 if(mVideoPlayer.IsVideoTextureSupported() == false)
673 DALI_LOG_ERROR("Platform doesn't support decoded video frame images\n");
680 mVideoPlayer.Pause();
687 self.RemoveRenderer(mOverlayRenderer);
689 mOverlayRenderer.Reset();
692 self.RemovePropertyNotification(mPositionUpdateNotification);
693 self.RemovePropertyNotification(mSizeUpdateNotification);
694 self.RemovePropertyNotification(mScaleUpdateNotification);
696 int curPos = mVideoPlayer.GetPlayPosition();
699 Dali::NativeImageSourcePtr nativeImageSourcePtr = Dali::NativeImageSource::New(source);
700 mNativeTexture = Dali::Texture::New(*nativeImageSourcePtr);
702 if(!mTextureRenderer)
704 Dali::Geometry geometry = VisualFactoryCache::CreateQuadGeometry();
705 Dali::Shader shader = CreateShader();
706 Dali::TextureSet textureSet = Dali::TextureSet::New();
707 textureSet.SetTexture(0u, mNativeTexture);
709 mTextureRenderer = Renderer::New(geometry, shader);
710 mTextureRenderer.SetTextures(textureSet);
714 Dali::TextureSet textureSet = mTextureRenderer.GetTextures();
715 textureSet.SetTexture(0u, mNativeTexture);
717 Self().AddRenderer(mTextureRenderer);
719 // Note VideoPlayer::SetRenderingTarget resets all the options. (e.g. url, mute, looping)
720 mVideoPlayer.SetRenderingTarget(nativeImageSourcePtr);
722 ApplyBackupProperties();
731 mVideoPlayer.SetPlayPosition(curPos);
735 void VideoView::UpdateDisplayArea(Dali::PropertyNotification& source)
737 // If mSyncMode is enabled, Video player's size and poistion is updated in Video player's constraint.
738 // Because video view and player should be work syncronization.
739 if(!mIsUnderlay || mSyncMode == Dali::VideoSyncMode::ENABLED)
746 bool positionUsesAnchorPoint = self.GetProperty(Actor::Property::POSITION_USES_ANCHOR_POINT).Get<bool>();
747 Vector3 actorSize = self.GetCurrentProperty<Vector3>(Actor::Property::SIZE) * self.GetCurrentProperty<Vector3>(Actor::Property::SCALE);
748 Vector3 anchorPointOffSet = actorSize * (positionUsesAnchorPoint ? self.GetCurrentProperty<Vector3>(Actor::Property::ANCHOR_POINT) : AnchorPoint::TOP_LEFT);
750 Vector2 screenPosition = self.GetProperty(Actor::Property::SCREEN_POSITION).Get<Vector2>();
752 mDisplayArea.x = screenPosition.x - anchorPointOffSet.x;
753 mDisplayArea.y = screenPosition.y - anchorPointOffSet.y;
754 mDisplayArea.width = actorSize.x;
755 mDisplayArea.height = actorSize.y;
757 mVideoPlayer.SetDisplayArea(mDisplayArea);
760 void VideoView::SetUnderlay(bool set)
762 if(set != mIsUnderlay)
768 SetWindowSurfaceTarget();
772 SetNativeImageTarget();
779 bool VideoView::IsUnderlay()
784 void VideoView::SetSWCodec(bool on)
786 // If setting SW or HW type is failed , video-view shows video by default codec type.
787 // The default codec type is selected by platform.
790 mVideoPlayer.SetCodecType(Dali::VideoPlayerPlugin::CodecType::SW);
794 mVideoPlayer.SetCodecType(Dali::VideoPlayerPlugin::CodecType::HW);
798 int VideoView::GetPlayPosition()
800 return mVideoPlayer.GetPlayPosition();
803 void VideoView::SetPlayPosition(int pos)
805 mVideoPlayer.SetPlayPosition(pos);
808 void VideoView::SetDisplayMode(int mode)
810 mVideoPlayer.SetDisplayMode(static_cast<Dali::VideoPlayerPlugin::DisplayMode::Type>(mode));
813 int VideoView::GetDisplayMode() const
815 return static_cast<int>(mVideoPlayer.GetDisplayMode());
818 Any VideoView::GetMediaPlayer()
820 return mVideoPlayer.GetMediaPlayer();
823 void VideoView::OnAnimationFinished(Animation& animation)
826 SetFrameRenderCallback();
829 void VideoView::OnWindowResized(Dali::Window winHandle, Dali::Window::WindowSize size)
831 Dali::VideoPlayerPlugin::DisplayRotation videoAngle = mVideoPlayer.GetDisplayRotation();
832 int windowAngle = (DevelWindow::GetPhysicalOrientation(winHandle) / 90);
834 if(windowAngle != videoAngle)
836 mVideoPlayer.SetDisplayRotation(static_cast<Dali::VideoPlayerPlugin::DisplayRotation>(windowAngle));
840 void VideoView::PlayAnimation(Dali::Animation animation)
842 if(mIsUnderlay && mSyncMode == Dali::VideoSyncMode::ENABLED)
844 mVideoPlayer.StartSynchronization();
845 animation.FinishedSignal().Connect(this, &VideoView::OnAnimationFinished);
850 Dali::Shader VideoView::CreateShader()
852 std::string fragmentShader;
853 std::string vertexShader;
854 std::string customFragmentShader;
855 bool checkShader = false;
857 if(!mEffectPropertyMap.Empty())
859 Property::Value* vertexShaderValue = mEffectPropertyMap.Find(CUSTOM_VERTEX_SHADER);
860 if(vertexShaderValue)
862 checkShader = GetStringFromProperty(*vertexShaderValue, vertexShader);
865 if(!vertexShaderValue || !checkShader)
867 vertexShader = SHADER_VIDEO_VIEW_TEXTURE_VERT.data();
870 Property::Value* fragmentShaderValue = mEffectPropertyMap.Find(CUSTOM_FRAGMENT_SHADER);
871 if(fragmentShaderValue)
873 checkShader = GetStringFromProperty(*fragmentShaderValue, customFragmentShader);
877 fragmentShader = customFragmentShader;
881 if(!fragmentShaderValue || !checkShader)
883 fragmentShader = SHADER_VIDEO_VIEW_TEXTURE_FRAG.data();
884 DevelTexture::ApplyNativeFragmentShader(mNativeTexture, fragmentShader);
889 vertexShader = SHADER_VIDEO_VIEW_TEXTURE_VERT.data();
890 fragmentShader = SHADER_VIDEO_VIEW_TEXTURE_FRAG.data();
891 DevelTexture::ApplyNativeFragmentShader(mNativeTexture, fragmentShader);
894 return Dali::Shader::New(vertexShader, fragmentShader);
897 bool VideoView::GetStringFromProperty(const Dali::Property::Value& value, std::string& output)
899 bool extracted = false;
900 if(value.Get(output))
908 void VideoView::ApplyBackupProperties()
910 Property::Map::SizeType pos = 0;
911 Property::Map::SizeType count = mPropertyBackup.Count();
913 for(; pos < count; pos++)
915 KeyValuePair property = mPropertyBackup.GetKeyValue(pos);
917 SetPropertyInternal(property.first.indexKey, property.second);
921 void VideoView::FrameRenderCallback(int frameID)
924 if(frameID == mFrameID)
926 mVideoPlayer.FinishSynchronization();
931 void VideoView::SetFrameRenderCallback()
934 DevelWindow::AddFrameRenderedCallback(DevelWindow::Get(Self()),
935 std::unique_ptr<CallbackBase>(MakeCallback(this, &VideoView::FrameRenderCallback)),
939 bool VideoView::IsVideoView(Actor actor) const
941 // Check whether the actor is a VideoView
942 bool isVideoView = false;
946 Property::Index propertyIsVideoView = actor.GetPropertyIndex(IS_VIDEO_VIEW_PROPERTY_NAME);
947 if(propertyIsVideoView != Property::INVALID_INDEX)
949 isVideoView = actor.GetProperty<bool>(propertyIsVideoView);
956 VideoPlayer VideoView::GetVideoPlayer()
961 } // namespace Internal
963 } // namespace Toolkit