Added APIs for codec and seek in VideoView
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / video-view / video-view-impl.cpp
1 /*
2  * Copyright (c) 2017 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include "video-view-impl.h"
20
21 // EXTERNAL INCLUDES
22 #include <cstring>
23 #include <dali/public-api/object/type-registry.h>
24 #include <dali/public-api/object/type-registry-helper.h>
25 #include <dali/public-api/common/stage.h>
26 #include <dali/devel-api/scripting/scripting.h>
27 #include <dali/public-api/adaptor-framework/native-image-source.h>
28 #include <dali/integration-api/adaptors/adaptor.h>
29 #include <dali/integration-api/debug.h>
30 #include <dali/public-api/animation/constraint.h>
31 #include <dali/devel-api/actors/actor-devel.h>
32
33 // INTERNAL INCLUDES
34 #include <dali-toolkit/public-api/controls/video-view/video-view.h>
35 #include <dali-toolkit/public-api/visuals/visual-properties.h>
36 #include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
37 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
38 #include <dali-toolkit/internal/visuals/visual-base-impl.h>
39 #include <dali-toolkit/internal/visuals/visual-factory-impl.h>
40 #include <dali-toolkit/internal/visuals/visual-factory-cache.h>
41
42 namespace Dali
43 {
44
45 namespace Toolkit
46 {
47
48 namespace Internal
49 {
50
51 namespace
52 {
53
54 BaseHandle Create()
55 {
56   return Toolkit::VideoView::New();
57 }
58
59 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::VideoView, Toolkit::Control, Create );
60
61 DALI_PROPERTY_REGISTRATION( Toolkit, VideoView, "video", MAP, VIDEO )
62 DALI_PROPERTY_REGISTRATION( Toolkit, VideoView, "looping", BOOLEAN, LOOPING )
63 DALI_PROPERTY_REGISTRATION( Toolkit, VideoView, "muted", BOOLEAN, MUTED )
64 DALI_PROPERTY_REGISTRATION( Toolkit, VideoView, "volume", MAP, VOLUME )
65 DALI_PROPERTY_REGISTRATION( Toolkit, VideoView, "underlay", BOOLEAN, UNDERLAY )
66 DALI_PROPERTY_REGISTRATION( Toolkit, VideoView, "playPosition", INTEGER, PLAY_POSITION )
67
68 DALI_SIGNAL_REGISTRATION( Toolkit, VideoView, "finished", FINISHED_SIGNAL )
69
70 DALI_ACTION_REGISTRATION( Toolkit, VideoView, "play", ACTION_VIDEOVIEW_PLAY )
71 DALI_ACTION_REGISTRATION( Toolkit, VideoView, "pause", ACTION_VIDEOVIEW_PAUSE )
72 DALI_ACTION_REGISTRATION( Toolkit, VideoView, "stop", ACTION_VIDEOVIEW_STOP )
73 DALI_ACTION_REGISTRATION( Toolkit, VideoView, "forward", ACTION_VIDEOVIEW_FORWARD )
74 DALI_ACTION_REGISTRATION( Toolkit, VideoView, "backward", ACTION_VIDEOVIEW_BACKWARD )
75
76 DALI_TYPE_REGISTRATION_END()
77
78 const char* const VOLUME_LEFT( "volumeLeft" );
79 const char* const VOLUME_RIGHT( "volumeRight" );
80
81 // 3.0 TC uses RENDERING_TARGET. It should be removed in next release
82 const char* const RENDERING_TARGET( "renderingTarget" );
83 const char* const WINDOW_SURFACE_TARGET( "windowSurfaceTarget" );
84 const char* const NATIVE_IMAGE_TARGET( "nativeImageTarget" );
85
86 const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
87   attribute mediump vec2 aPosition;\n
88   uniform mediump mat4 uMvpMatrix;\n
89   uniform mediump vec3 uSize;\n
90   \n
91   void main()\n
92   {\n
93     mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
94     vertexPosition.xyz *= uSize;\n
95     gl_Position = uMvpMatrix * vertexPosition;\n
96   }\n
97 );
98
99 const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
100   uniform lowp vec4 uColor;\n
101   uniform lowp vec3 mixColor;\n
102   uniform lowp float opacity;\n
103   \n
104   void main()\n
105   {\n
106     gl_FragColor = vec4(mixColor, opacity)*uColor;\n
107   }\n
108 );
109
110 } // anonymous namepsace
111
112 VideoView::VideoView()
113 : Control( ControlBehaviour( ACTOR_BEHAVIOUR_DEFAULT | DISABLE_STYLE_CHANGE_SIGNALS ) ),
114   mCurrentVideoPlayPosition( 0 ),
115   mIsPlay( false ),
116   mIsUnderlay( true )
117 {
118   mVideoPlayer = Dali::VideoPlayer::New();
119 }
120
121 VideoView::~VideoView()
122 {
123 }
124
125 Toolkit::VideoView VideoView::New()
126 {
127   VideoView* impl = new VideoView();
128   Toolkit::VideoView handle = Toolkit::VideoView( *impl );
129
130   impl->Initialize();
131
132   return handle;
133 }
134
135 void VideoView::OnInitialize()
136 {
137   mVideoPlayer.FinishedSignal().Connect( this, &VideoView::EmitSignalFinish );
138   SetWindowSurfaceTarget();
139 }
140
141 void VideoView::SetUrl( const std::string& url )
142 {
143   if( mUrl != url || !mPropertyMap.Empty() )
144   {
145     mUrl = url;
146     mPropertyMap.Clear();
147   }
148
149   if( !mIsUnderlay )
150   {
151     Actor self( Self() );
152     Internal::InitializeVisual( self, mVisual, mNativeImage );
153   }
154
155   mVideoPlayer.SetUrl( mUrl );
156 }
157
158 void VideoView::SetPropertyMap( Property::Map map )
159 {
160   mPropertyMap = map;
161
162   Actor self( Self() );
163   Internal::InitializeVisual( self, mVisual, mPropertyMap );
164
165   Property::Value* widthValue = mPropertyMap.Find( "width" );
166   if( widthValue )
167   {
168     int width;
169     if( widthValue->Get( width ) )
170     {
171       mVideoSize = ImageDimensions( width, mVideoSize.GetHeight() );
172     }
173   }
174
175   Property::Value* heightValue = mPropertyMap.Find( "height" );
176   if( heightValue )
177   {
178     int height;
179     if( heightValue->Get( height ) )
180     {
181       mVideoSize = ImageDimensions( mVideoSize.GetWidth(), height );
182     }
183   }
184
185   Property::Value* target = map.Find( RENDERING_TARGET );
186   std::string targetType;
187
188   if( target && target->Get( targetType ) && targetType == WINDOW_SURFACE_TARGET )
189   {
190     mIsUnderlay = true;
191     SetWindowSurfaceTarget();
192   }
193   else if( target && target->Get( targetType ) && targetType == NATIVE_IMAGE_TARGET )
194   {
195     mIsUnderlay = false;
196     SetNativeImageTarget();
197   }
198
199   RelayoutRequest();
200 }
201
202 std::string VideoView::GetUrl()
203 {
204   return mUrl;
205 }
206
207 void VideoView::SetLooping(bool looping)
208 {
209   mVideoPlayer.SetLooping( looping );
210 }
211
212 bool VideoView::IsLooping()
213 {
214   return mVideoPlayer.IsLooping();
215 }
216
217 void VideoView::Play()
218 {
219   if( mIsUnderlay )
220   {
221     Self().AddRenderer( mRenderer );
222   }
223
224   mVideoPlayer.Play();
225   mIsPlay = true;
226 }
227
228 void VideoView::Pause()
229 {
230   mVideoPlayer.Pause();
231   mIsPlay = false;
232 }
233
234 void VideoView::Stop()
235 {
236   mVideoPlayer.Stop();
237   mIsPlay = false;
238 }
239
240 void VideoView::Forward( int millisecond )
241 {
242   int curPos = mVideoPlayer.GetPlayPosition();
243
244   int nextPos = curPos + millisecond;
245
246   mVideoPlayer.SetPlayPosition( nextPos );
247 }
248
249 void VideoView::Backward( int millisecond )
250 {
251   int curPos = mVideoPlayer.GetPlayPosition();
252
253   int nextPos = curPos - millisecond;
254   nextPos = ( nextPos < 0 )? 0: nextPos;
255
256   mVideoPlayer.SetPlayPosition( nextPos );
257 }
258
259 void VideoView::SetMute( bool mute )
260 {
261   mVideoPlayer.SetMute( mute );
262 }
263
264 bool VideoView::IsMuted()
265 {
266   return mVideoPlayer.IsMuted();
267 }
268
269 void VideoView::SetVolume( float left, float right )
270 {
271   mVideoPlayer.SetVolume( left, right );
272 }
273
274 void VideoView::GetVolume( float& left, float& right )
275 {
276   mVideoPlayer.GetVolume( left, right );
277 }
278
279 Dali::Toolkit::VideoView::VideoViewSignalType& VideoView::FinishedSignal()
280 {
281   return mFinishedSignal;
282 }
283
284 void VideoView::EmitSignalFinish()
285 {
286   if( mIsUnderlay )
287   {
288     Self().RemoveRenderer( mRenderer );
289   }
290
291   if ( !mFinishedSignal.Empty() )
292   {
293     Dali::Toolkit::VideoView handle( GetOwner() );
294     mFinishedSignal.Emit( handle );
295   }
296 }
297
298 bool VideoView::DoAction( BaseObject* object, const std::string& actionName, const Property::Map& attributes )
299 {
300   bool ret = false;
301
302   Dali::BaseHandle handle( object );
303   Toolkit::VideoView videoView = Toolkit::VideoView::DownCast( handle );
304
305   if( !videoView )
306   {
307     return ret;
308   }
309
310   VideoView& impl = GetImpl( videoView );
311
312   if( strcmp( actionName.c_str(), ACTION_VIDEOVIEW_PLAY ) == 0 )
313   {
314     impl.Play();
315     ret = true;
316   }
317   else if( strcmp( actionName.c_str(), ACTION_VIDEOVIEW_PAUSE ) == 0 )
318   {
319     impl.Pause();
320     ret = true;
321   }
322   else if( strcmp( actionName.c_str(), ACTION_VIDEOVIEW_STOP ) == 0 )
323   {
324     impl.Stop();
325     ret = true;
326   }
327   else if( strcmp( actionName.c_str(), ACTION_VIDEOVIEW_FORWARD ) == 0 )
328   {
329     int millisecond = 0;
330     if( attributes["videoForward"].Get( millisecond ) )
331     {
332       impl.Forward( millisecond );
333       ret = true;
334     }
335   }
336   else if( strcmp( actionName.c_str(), ACTION_VIDEOVIEW_BACKWARD ) == 0 )
337   {
338     int millisecond = 0;
339     if( attributes["videoBackward"].Get( millisecond ) )
340     {
341       impl.Backward( millisecond );
342       ret = true;
343     }
344   }
345
346   return ret;
347 }
348
349 bool VideoView::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
350 {
351   Dali::BaseHandle handle( object );
352
353   bool connected( true );
354   Toolkit::VideoView videoView = Toolkit::VideoView::DownCast( handle );
355
356   if( 0 == strcmp( signalName.c_str(), FINISHED_SIGNAL ) )
357   {
358     videoView.FinishedSignal().Connect( tracker, functor );
359   }
360   else
361   {
362     // signalName does not match any signal
363     connected = false;
364   }
365
366   return connected;
367 }
368
369 void VideoView::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
370 {
371   Toolkit::VideoView videoView = Toolkit::VideoView::DownCast( Dali::BaseHandle( object ) );
372
373   if( videoView )
374   {
375     VideoView& impl = GetImpl( videoView );
376
377     switch( index )
378     {
379       case Toolkit::VideoView::Property::VIDEO:
380       {
381         std::string videoUrl;
382         Property::Map map;
383
384         if( value.Get( videoUrl ) )
385         {
386           impl.SetUrl( videoUrl );
387         }
388         else if( value.Get( map ) )
389         {
390           Property::Value* shaderValue = map.Find( Toolkit::Visual::Property::SHADER, CUSTOM_SHADER );
391
392           if( map.Count() > 1u || !shaderValue )
393           {
394             impl.SetPropertyMap( map );
395           }
396           else if( impl.mVisual && map.Count() == 1u && shaderValue )
397           {
398             Property::Map shaderMap;
399             if( shaderValue->Get( shaderMap ) )
400             {
401               Internal::Visual::Base& visual = Toolkit::GetImplementation( impl.mVisual );
402               visual.SetCustomShader( shaderMap );
403               if( videoView.OnStage() )
404               {
405                 visual.SetOffStage( videoView );
406                 visual.SetOnStage( videoView );
407               }
408             }
409           }
410         }
411         break;
412       }
413       case Toolkit::VideoView::Property::LOOPING:
414       {
415         bool looping;
416         if( value.Get( looping ) )
417         {
418           impl.SetLooping( looping );
419         }
420         break;
421       }
422       case Toolkit::VideoView::Property::MUTED:
423       {
424         bool mute;
425         if( value.Get( mute ) )
426         {
427           impl.SetMute( mute );
428         }
429         break;
430       }
431       case Toolkit::VideoView::Property::VOLUME:
432       {
433         Property::Map map;
434         float left, right;
435         if( value.Get( map ) )
436         {
437           Property::Value* volumeLeft = map.Find( VOLUME_LEFT );
438           Property::Value* volumeRight = map.Find( VOLUME_RIGHT );
439           if( volumeLeft && volumeLeft->Get( left ) && volumeRight && volumeRight->Get( right ) )
440           {
441             impl.SetVolume( left, right );
442           }
443         }
444         break;
445       }
446       case Toolkit::VideoView::Property::UNDERLAY:
447       {
448         bool underlay;
449         if( value.Get( underlay ) )
450         {
451           impl.SetUnderlay( underlay );
452         }
453         break;
454       }
455       case Toolkit::VideoView::Property::PLAY_POSITION:
456       {
457         int pos;
458         if( value.Get( pos ) )
459         {
460           impl.SetPlayPosition( pos );
461         }
462         break;
463       }
464     }
465   }
466 }
467
468 Property::Value VideoView::GetProperty( BaseObject* object, Property::Index propertyIndex )
469 {
470   Property::Value value;
471   Toolkit::VideoView videoView = Toolkit::VideoView::DownCast( Dali::BaseHandle( object ) );
472
473   if( videoView )
474   {
475     VideoView& impl = GetImpl( videoView );
476
477     switch( propertyIndex )
478     {
479       case Toolkit::VideoView::Property::VIDEO:
480       {
481         if( !impl.mUrl.empty() )
482         {
483           value = impl.mUrl;
484         }
485         else if( !impl.mPropertyMap.Empty() )
486         {
487           value = impl.mPropertyMap;
488         }
489         break;
490       }
491       case Toolkit::VideoView::Property::LOOPING:
492       {
493         value = impl.IsLooping();
494         break;
495       }
496       case Toolkit::VideoView::Property::MUTED:
497       {
498         value = impl.IsMuted();
499         break;
500       }
501       case Toolkit::VideoView::Property::VOLUME:
502       {
503         Property::Map map;
504         float left, right;
505
506         impl.GetVolume( left, right );
507         map.Insert( VOLUME_LEFT, left );
508         map.Insert( VOLUME_RIGHT, right );
509         value = map;
510         break;
511       }
512       case Toolkit::VideoView::Property::UNDERLAY:
513       {
514         value = impl.IsUnderlay();
515         break;
516       }
517       case Toolkit::VideoView::Property::PLAY_POSITION:
518       {
519         value = impl.GetPlayPosition();
520         break;
521       }
522     }
523   }
524
525   return value;
526 }
527
528 void VideoView::SetDepthIndex( int depthIndex )
529 {
530   if( mVisual )
531   {
532     mVisual.SetDepthIndex( depthIndex );
533   }
534 }
535
536 void VideoView::OnStageConnection( int depth )
537 {
538   if( mVisual )
539   {
540     CustomActor self = Self();
541     Toolkit::GetImplementation(mVisual).SetOnStage( self );
542   }
543
544   Control::OnStageConnection( depth );
545 }
546
547 void VideoView::OnStageDisconnection()
548 {
549   if( mVisual )
550   {
551     CustomActor self = Self();
552     Toolkit::GetImplementation(mVisual).SetOffStage( self );
553   }
554
555   Control::OnStageDisconnection();
556 }
557
558 Vector3 VideoView::GetNaturalSize()
559 {
560   Vector3 size;
561   size.x = mVideoSize.GetWidth();
562   size.y = mVideoSize.GetHeight();
563
564   if( size.x > 0 && size.y > 0 )
565   {
566     size.z = std::min( size.x, size.y );
567     return size;
568   }
569   else
570   {
571     return Control::GetNaturalSize();
572   }
573 }
574
575 float VideoView::GetHeightForWidth( float width )
576 {
577   if( mVideoSize.GetWidth() > 0 && mVideoSize.GetHeight() > 0 )
578   {
579     return GetHeightForWidthBase( width );
580   }
581   else
582   {
583     return Control::GetHeightForWidthBase( width );
584   }
585 }
586
587 float VideoView::GetWidthForHeight( float height )
588 {
589   if( mVideoSize.GetWidth() > 0 && mVideoSize.GetHeight() > 0 )
590   {
591     return GetWidthForHeightBase( height );
592   }
593   else
594   {
595     return Control::GetWidthForHeightBase( height );
596   }
597 }
598
599 void VideoView::SetWindowSurfaceTarget()
600 {
601   Actor self = Self();
602   int curPos = mVideoPlayer.GetPlayPosition();
603
604   if( mVisual )
605   {
606     Toolkit::GetImplementation(mVisual).SetOffStage(self);
607     mVisual.Reset();
608   }
609
610   if( mIsPlay )
611   {
612     mVideoPlayer.Pause();
613   }
614
615   mPositionUpdateNotification = self.AddPropertyNotification( Actor::Property::WORLD_POSITION, StepCondition( 1.0f, 1.0f ) );
616   mSizeUpdateNotification = self.AddPropertyNotification( Actor::Property::SIZE, StepCondition( 1.0f, 1.0f ) );
617   mScaleUpdateNotification = self.AddPropertyNotification( Actor::Property::WORLD_SCALE, StepCondition( 0.1f, 1.0f ) );
618   mPositionUpdateNotification.NotifySignal().Connect( this, &VideoView::UpdateDisplayArea );
619   mSizeUpdateNotification.NotifySignal().Connect( this, &VideoView::UpdateDisplayArea );
620   mScaleUpdateNotification.NotifySignal().Connect( this, &VideoView::UpdateDisplayArea );
621
622   mVideoPlayer.SetRenderingTarget( Dali::Adaptor::Get().GetNativeWindowHandle() );
623   mVideoPlayer.SetUrl( mUrl );
624
625   if( !mRenderer )
626   {
627     // For underlay rendering mode, video display area have to be transparent.
628     Geometry geometry = VisualFactoryCache::CreateQuadGeometry();
629     Shader shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
630     mRenderer = Renderer::New( geometry, shader );
631
632     mRenderer.SetProperty( Renderer::Property::BLEND_MODE, BlendMode::ON );
633     mRenderer.SetProperty( Renderer::Property::BLEND_FACTOR_SRC_RGB, BlendFactor::ONE );
634     mRenderer.SetProperty( Renderer::Property::BLEND_FACTOR_DEST_RGB, BlendFactor::ZERO );
635     mRenderer.SetProperty( Renderer::Property::BLEND_FACTOR_SRC_ALPHA, BlendFactor::ONE );
636     mRenderer.SetProperty( Renderer::Property::BLEND_FACTOR_DEST_ALPHA, BlendFactor::ZERO );
637   }
638
639   if( mIsPlay )
640   {
641     Play();
642   }
643
644   if( curPos > 0 )
645   {
646     mVideoPlayer.SetPlayPosition( curPos );
647   }
648 }
649
650 void VideoView::SetNativeImageTarget()
651 {
652   if( mVideoPlayer.IsVideoTextureSupported() == false )
653   {
654     DALI_LOG_ERROR( "Platform doesn't support decoded video frame images\n" );
655     mIsUnderlay = true;
656     return;
657   }
658
659   if( mIsPlay )
660   {
661     mVideoPlayer.Pause();
662   }
663
664   Actor self( Self() );
665   self.RemoveRenderer( mRenderer );
666   Dali::Stage::GetCurrent().KeepRendering( 0.0f );
667
668   self.RemovePropertyNotification( mPositionUpdateNotification );
669   self.RemovePropertyNotification( mSizeUpdateNotification );
670   self.RemovePropertyNotification( mScaleUpdateNotification );
671
672   int curPos = mVideoPlayer.GetPlayPosition();
673
674   Any source;
675   Dali::NativeImageSourcePtr nativeImageSourcePtr = Dali::NativeImageSource::New( source );
676   mNativeImage = Dali::NativeImage::New( *nativeImageSourcePtr );
677
678   mVideoPlayer.SetRenderingTarget( nativeImageSourcePtr );
679   mVideoPlayer.SetUrl( mUrl );
680
681   Internal::InitializeVisual( self, mVisual, mNativeImage );
682   Self().RemoveRenderer( mRenderer );
683
684   if( mIsPlay )
685   {
686     Play();
687   }
688
689   if( curPos > 0 )
690   {
691     mVideoPlayer.SetPlayPosition( curPos );
692   }
693 }
694
695 void VideoView::UpdateDisplayArea( Dali::PropertyNotification& source )
696 {
697   if( !mIsUnderlay )
698   {
699     return;
700   }
701
702   Actor self( Self() );
703
704   bool positionUsesAnchorPoint = self.GetProperty( DevelActor::Property::POSITION_USES_ANCHOR_POINT ).Get< bool >();
705   Vector3 actorSize = self.GetCurrentSize() * self.GetCurrentScale();
706   Vector3 anchorPointOffSet = actorSize * ( positionUsesAnchorPoint ? self.GetCurrentAnchorPoint() : AnchorPoint::TOP_LEFT );
707
708   Vector2 screenPosition = self.GetProperty( DevelActor::Property::SCREEN_POSITION ).Get< Vector2 >();
709
710   mDisplayArea.x = screenPosition.x - anchorPointOffSet.x;
711   mDisplayArea.y = screenPosition.y - anchorPointOffSet.y;
712   mDisplayArea.width = actorSize.x;
713   mDisplayArea.height = actorSize.y;
714
715   mVideoPlayer.SetDisplayArea( mDisplayArea );
716 }
717
718 void VideoView::SetUnderlay( bool set )
719 {
720   if( set != mIsUnderlay )
721   {
722     mIsUnderlay = set;
723
724     if( mIsUnderlay )
725     {
726       SetWindowSurfaceTarget();
727     }
728     else
729     {
730       SetNativeImageTarget();
731     }
732
733     RelayoutRequest();
734   }
735 }
736
737 bool VideoView::IsUnderlay()
738 {
739   return mIsUnderlay;
740 }
741
742 void VideoView::SetSWCodec( bool on )
743 {
744   // If setting SW or HW type is failed , video-view shows video by default codec type.
745   // The default codec type is selected by platform.
746   if( on )
747   {
748     mVideoPlayer.SetCodecType( Dali::VideoPlayerPlugin::CodecType::SW );
749   }
750   else
751   {
752     mVideoPlayer.SetCodecType( Dali::VideoPlayerPlugin::CodecType::HW );
753   }
754 }
755
756 int VideoView::GetPlayPosition()
757 {
758   return mVideoPlayer.GetPlayPosition();
759 }
760
761 void VideoView::SetPlayPosition( int pos )
762 {
763   mVideoPlayer.SetPlayPosition( pos );
764 }
765
766 } // namespace Internal
767
768 } // namespace toolkit
769
770 } // namespace Dali