Modified parameters of play position API in video plugin
[platform/core/uifw/dali-adaptor.git] / plugins / video-player / tizen-video-player.cpp
1 /*
2  * Copyright (c) 2016 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 <tizen-video-player.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/public-api/common/stage.h>
23 #include <dali/devel-api/threading/mutex.h>
24 #include <dali/integration-api/debug.h>
25
26 // INTERNAL INCLUDES
27
28 // The plugin factories
29 extern "C" DALI_EXPORT_API Dali::VideoPlayerPlugin* CreateVideoPlayerPlugin( void )
30 {
31   return new Dali::Plugin::TizenVideoPlayer;
32 }
33
34 extern "C" DALI_EXPORT_API void DestroyVideoPlayerPlugin( Dali::VideoPlayerPlugin* plugin )
35 {
36   if( plugin != NULL )
37   {
38     delete plugin;
39   }
40 }
41
42 namespace Dali
43 {
44
45 namespace Plugin
46 {
47
48 namespace
49 {
50
51 const int TIMER_INTERVAL( 20 );
52
53 static void MediaPacketVideoDecodedCb( media_packet_h packet, void* user_data )
54 {
55   TizenVideoPlayer* player = static_cast< TizenVideoPlayer* >( user_data );
56
57   if( player == NULL )
58   {
59     DALI_LOG_ERROR( "Decoded callback got Null pointer as user_data.\n" );
60     return;
61   }
62
63   player->PushPacket( packet );
64 }
65
66 static void EmitPlaybackFinishedSignal( void* user_data )
67 {
68   TizenVideoPlayer* player = static_cast< TizenVideoPlayer* >( user_data );
69   DALI_LOG_ERROR( "EmitPlaybackFinishedSignal.\n" );
70
71   if( player == NULL )
72   {
73     DALI_LOG_ERROR( "Decoded callback got Null pointer as user_data.\n" );
74     return;
75   }
76
77   DALI_LOG_ERROR( "EmitPlaybackFinishedSignal.\n" );
78
79   if( !player->mFinishedSignal.Empty() )
80   {
81     DALI_LOG_ERROR( "EmitPlaybackFinishedSignal.3\n" );
82     player->mFinishedSignal.Emit();
83   }
84
85   player->Stop();
86 }
87
88 // ToDo: VD player_set_play_position() doesn't work when callback pointer is NULL.
89 // We should check whether this callback is needed in platform.
90 static void PlayerSeekCompletedCb( void* data )
91 {
92 }
93
94 void LogPlayerError( int error )
95 {
96   if( error != PLAYER_ERROR_NONE )
97   {
98     switch( error )
99     {
100       case PLAYER_ERROR_OUT_OF_MEMORY:
101       {
102         DALI_LOG_ERROR( "Player error: Out of memory\n" );
103         return;
104       }
105       case PLAYER_ERROR_INVALID_PARAMETER:
106       {
107         DALI_LOG_ERROR( "Player error: Invalid parameter\n" );
108         return;
109       }
110       case PLAYER_ERROR_NO_SUCH_FILE:
111       {
112         DALI_LOG_ERROR( "Player error: No such file\n" );
113         return;
114       }
115       case PLAYER_ERROR_INVALID_OPERATION:
116       {
117         DALI_LOG_ERROR( "Player error: Invalid operation\n" );
118         return;
119       }
120       case PLAYER_ERROR_FILE_NO_SPACE_ON_DEVICE:
121       {
122         DALI_LOG_ERROR( "Player error: No space on device\n" );
123         return;
124       }
125       case PLAYER_ERROR_FEATURE_NOT_SUPPORTED_ON_DEVICE:
126       {
127         DALI_LOG_ERROR( "Player error: Not supported feature on device\n" );
128         return;
129       }
130       case PLAYER_ERROR_SEEK_FAILED:
131       {
132         DALI_LOG_ERROR( "Player error: Seek failed\n" );
133         return;
134       }
135       case PLAYER_ERROR_INVALID_STATE:
136       {
137         DALI_LOG_ERROR( "Player error: Invalid state\n" );
138         return;
139       }
140       case PLAYER_ERROR_NOT_SUPPORTED_FILE:
141       {
142         DALI_LOG_ERROR( "Player error: Not supported file\n" );
143         return;
144       }
145       case PLAYER_ERROR_INVALID_URI:
146       {
147         DALI_LOG_ERROR( "Player error: Invalid uri\n" );
148         return;
149       }
150       case PLAYER_ERROR_SOUND_POLICY:
151       {
152         DALI_LOG_ERROR( "Player error: Sound policy\n" );
153         return;
154       }
155       case PLAYER_ERROR_CONNECTION_FAILED:
156       {
157         DALI_LOG_ERROR( "Player error: Connection failed\n" );
158         return;
159       }
160       case PLAYER_ERROR_VIDEO_CAPTURE_FAILED:
161       {
162         DALI_LOG_ERROR( "Player error: Video capture failed\n" );
163         return;
164       }
165       case PLAYER_ERROR_DRM_EXPIRED:
166       {
167         DALI_LOG_ERROR( "Player error: DRM expired\n" );
168         return;
169       }
170       case PLAYER_ERROR_DRM_NO_LICENSE:
171       {
172         DALI_LOG_ERROR( "Player error: No license\n" );
173         return;
174       }
175       case PLAYER_ERROR_DRM_FUTURE_USE:
176       {
177         DALI_LOG_ERROR( "Player error: License for future use\n" );
178         return;
179       }
180       case PLAYER_ERROR_DRM_NOT_PERMITTED:
181       {
182         DALI_LOG_ERROR( "Player error: Format not permitted\n" );
183         return;
184       }
185       case PLAYER_ERROR_RESOURCE_LIMIT:
186       {
187         DALI_LOG_ERROR( "Player error: Resource limit\n" );
188         return;
189       }
190       case PLAYER_ERROR_PERMISSION_DENIED:
191       {
192         DALI_LOG_ERROR( "Player error: Permission denied\n" );
193         return;
194       }
195       case PLAYER_ERROR_SERVICE_DISCONNECTED:
196       {
197         DALI_LOG_ERROR( "Player error: Service disconnected\n" );
198         return;
199       }
200       case PLAYER_ERROR_BUFFER_SPACE:
201       {
202         DALI_LOG_ERROR( "Player error: Buffer space\n" );
203         return;
204       }
205     }
206   }
207 }
208
209 } // unnamed namespace
210
211 TizenVideoPlayer::TizenVideoPlayer()
212 : mPlayer( NULL ),
213   mPlayerState( PLAYER_STATE_NONE ),
214   mTbmSurface( NULL ),
215   mPacket( NULL ),
216   mTargetType( NativeImage ),
217   mAlphaBitChanged( false )
218 {
219 }
220
221 TizenVideoPlayer::~TizenVideoPlayer()
222 {
223 }
224
225 void TizenVideoPlayer::GetPlayerState( player_state_e* state )
226 {
227   if( mPlayer != NULL && player_get_state( mPlayer, state ) != PLAYER_ERROR_NONE )
228   {
229     DALI_LOG_ERROR( "player_get_state error: Invalid parameter\n" );
230     *state = PLAYER_STATE_NONE;
231   }
232 }
233
234 void TizenVideoPlayer::SetUrl( const std::string& url )
235 {
236   if( mUrl != url )
237   {
238     mUrl = url;
239
240     GetPlayerState( &mPlayerState );
241
242     if( mPlayerState != PLAYER_STATE_NONE && mPlayerState != PLAYER_STATE_IDLE )
243     {
244       Stop();
245       int error = player_unprepare( mPlayer );
246       LogPlayerError( error );
247     }
248
249     if( mPlayerState == PLAYER_STATE_IDLE )
250     {
251       int error = player_set_uri( mPlayer, mUrl.c_str() );
252       LogPlayerError( error );
253
254       error = player_prepare( mPlayer );
255       LogPlayerError( error );
256     }
257   }
258 }
259
260 std::string TizenVideoPlayer::GetUrl()
261 {
262   return mUrl;
263 }
264
265 void TizenVideoPlayer::SetRenderingTarget( Any target )
266 {
267   int error;
268   if( mPlayerState != PLAYER_STATE_NONE )
269   {
270     GetPlayerState( &mPlayerState );
271
272     if( mPlayerState != PLAYER_STATE_IDLE )
273     {
274       Stop();
275       error = player_unprepare( mPlayer );
276       LogPlayerError( error );
277     }
278
279     error = player_destroy( mPlayer );
280     LogPlayerError( error );
281     mPlayerState = PLAYER_STATE_NONE;
282     mPlayer = NULL;
283     mUrl = "";
284   }
285
286   mNativeImageSourcePtr = NULL;
287   mEcoreWlWindow = NULL;
288
289   if( target.GetType() == typeid( Dali::NativeImageSourcePtr ) )
290   {
291     mTargetType = TizenVideoPlayer::NativeImage;
292
293     Dali::NativeImageSourcePtr nativeImageSourcePtr = AnyCast< Dali::NativeImageSourcePtr >( target );
294
295     InitializeTextureStreamMode( nativeImageSourcePtr );
296   }
297   else if( target.GetType() == typeid( Ecore_Wl_Window* ) )
298   {
299     mTargetType = TizenVideoPlayer::WindowSurface;
300
301     Ecore_Wl_Window* nativeWindow = Dali::AnyCast< Ecore_Wl_Window* >( target );
302     InitializeUnderlayMode( nativeWindow );
303   }
304   else
305   {
306     DALI_LOG_ERROR( "Video rendering target is unknown\n" );
307   }
308 }
309
310 void TizenVideoPlayer::SetLooping( bool looping )
311 {
312   GetPlayerState( &mPlayerState );
313
314   if( mPlayerState != PLAYER_STATE_NONE )
315   {
316     int error = player_set_looping( mPlayer, looping );
317     LogPlayerError( error );
318   }
319 }
320
321 bool TizenVideoPlayer::IsLooping()
322 {
323   GetPlayerState( &mPlayerState );
324
325   bool looping = false;
326   if( mPlayerState != PLAYER_STATE_NONE )
327   {
328     int error = player_is_looping( mPlayer, &looping );
329     LogPlayerError( error );
330   }
331
332   return looping;
333 }
334
335 void TizenVideoPlayer::Play()
336 {
337   GetPlayerState( &mPlayerState );
338
339   if( mPlayerState == PLAYER_STATE_READY || mPlayerState == PLAYER_STATE_PAUSED )
340   {
341     if( mNativeImageSourcePtr != NULL && mTimer )
342     {
343       mTimer.Start();
344     }
345
346     int error = player_start( mPlayer );
347     LogPlayerError( error );
348   }
349 }
350
351 void TizenVideoPlayer::Pause()
352 {
353   GetPlayerState( &mPlayerState );
354
355   if( mPlayerState == PLAYER_STATE_PLAYING )
356   {
357     int error = player_pause( mPlayer );
358     LogPlayerError( error );
359
360     if( mNativeImageSourcePtr != NULL && mTimer )
361     {
362       mTimer.Stop();
363       DestroyPackets();
364     }
365   }
366 }
367
368 void TizenVideoPlayer::Stop()
369 {
370   GetPlayerState( &mPlayerState );
371
372   if( mPlayerState == PLAYER_STATE_PLAYING || mPlayerState == PLAYER_STATE_PAUSED )
373   {
374     int error = player_stop( mPlayer );
375     LogPlayerError( error );
376   }
377
378   if( mNativeImageSourcePtr != NULL && mTimer )
379   {
380     mTimer.Stop();
381     DestroyPackets();
382   }
383 }
384
385 void TizenVideoPlayer::SetMute( bool muted )
386 {
387   GetPlayerState( &mPlayerState );
388
389   if( mPlayerState == PLAYER_STATE_IDLE ||
390       mPlayerState == PLAYER_STATE_READY ||
391       mPlayerState == PLAYER_STATE_PLAYING ||
392       mPlayerState == PLAYER_STATE_PAUSED
393     )
394   {
395     int error = player_set_mute( mPlayer, muted );
396     LogPlayerError( error );
397   }
398 }
399
400 bool TizenVideoPlayer::IsMuted()
401 {
402   GetPlayerState( &mPlayerState );
403   bool muted = false;
404
405    if( mPlayerState == PLAYER_STATE_IDLE ||
406       mPlayerState == PLAYER_STATE_READY ||
407       mPlayerState == PLAYER_STATE_PLAYING ||
408       mPlayerState == PLAYER_STATE_PAUSED
409     )
410   {
411     int error = player_is_muted( mPlayer, &muted );
412     LogPlayerError( error );
413   }
414
415   return muted;
416 }
417
418 void TizenVideoPlayer::SetVolume( float left, float right )
419 {
420   GetPlayerState( &mPlayerState );
421
422   int error = player_set_volume( mPlayer, left, right );
423   LogPlayerError( error );
424 }
425
426 void TizenVideoPlayer::GetVolume( float& left, float& right )
427 {
428   GetPlayerState( &mPlayerState );
429
430   int error = player_get_volume( mPlayer, &left, &right );
431   LogPlayerError( error );
432 }
433
434 void TizenVideoPlayer::SetPlayPosition( int millisecond )
435 {
436   int error;
437
438   GetPlayerState( &mPlayerState );
439
440   if( mPlayerState == PLAYER_STATE_READY ||
441       mPlayerState == PLAYER_STATE_PLAYING ||
442       mPlayerState == PLAYER_STATE_PAUSED
443   )
444   {
445     error = player_set_play_position( mPlayer, millisecond, false, PlayerSeekCompletedCb, NULL );
446     LogPlayerError( error );
447   }
448 }
449
450 int TizenVideoPlayer::GetPlayPosition()
451 {
452   int error;
453   int millisecond = 0;
454
455   GetPlayerState( &mPlayerState );
456
457   if( mPlayerState == PLAYER_STATE_IDLE ||
458       mPlayerState == PLAYER_STATE_READY ||
459       mPlayerState == PLAYER_STATE_PLAYING ||
460       mPlayerState == PLAYER_STATE_PAUSED
461   )
462   {
463     error = player_get_play_position( mPlayer, &millisecond );
464     LogPlayerError( error );
465   }
466
467   return millisecond;
468 }
469
470 void TizenVideoPlayer::SetDisplayRotation( Dali::VideoPlayerPlugin::DisplayRotation rotation )
471 {
472   if( mNativeImageSourcePtr != NULL )
473   {
474     DALI_LOG_ERROR( "SetDisplayRotation is only for window rendering target.\n" );
475     return;
476   }
477
478   int error;
479   if( mPlayerState != PLAYER_STATE_NONE )
480   {
481     error = player_set_display_rotation( mPlayer, static_cast< player_display_rotation_e >( rotation ) );
482     LogPlayerError( error );
483   }
484 }
485
486 Dali::VideoPlayerPlugin::DisplayRotation TizenVideoPlayer::GetDisplayRotation()
487 {
488   if( mNativeImageSourcePtr != NULL )
489   {
490     DALI_LOG_ERROR( "GetDisplayRotation is only for window rendering target.\n" );
491     return Dali::VideoPlayerPlugin::ROTATION_NONE;
492   }
493
494   int error;
495   player_display_rotation_e rotation = PLAYER_DISPLAY_ROTATION_NONE;
496   if( mPlayerState != PLAYER_STATE_NONE )
497   {
498     error = player_get_display_rotation( mPlayer, &rotation );
499     LogPlayerError( error );
500   }
501   return static_cast< Dali::VideoPlayerPlugin::DisplayRotation >( rotation );
502 }
503
504 Dali::VideoPlayerPlugin::VideoPlayerSignalType& TizenVideoPlayer::FinishedSignal()
505 {
506   return mFinishedSignal;
507 }
508
509 void TizenVideoPlayer::InitializeTextureStreamMode( Dali::NativeImageSourcePtr nativeImageSourcePtr )
510 {
511   int error;
512
513   mNativeImageSourcePtr = nativeImageSourcePtr;
514
515   if( mAlphaBitChanged )
516   {
517     ecore_wl_window_alpha_set( mEcoreWlWindow, false );
518     mAlphaBitChanged = false;
519   }
520
521   if( mPlayerState == PLAYER_STATE_NONE )
522   {
523     error = player_create( &mPlayer );
524     LogPlayerError( error );
525   }
526
527   GetPlayerState( &mPlayerState );
528
529   if( mPlayerState == PLAYER_STATE_IDLE )
530   {
531     error = player_set_completed_cb( mPlayer, EmitPlaybackFinishedSignal, this );
532     LogPlayerError( error );
533
534     error = player_set_media_packet_video_frame_decoded_cb( mPlayer, MediaPacketVideoDecodedCb, this );
535     LogPlayerError( error );
536
537     error = player_set_sound_type( mPlayer, SOUND_TYPE_MEDIA );
538     LogPlayerError( error );
539
540     error = player_set_display_mode( mPlayer, PLAYER_DISPLAY_MODE_FULL_SCREEN );
541     LogPlayerError( error );
542
543     error = player_set_display( mPlayer, PLAYER_DISPLAY_TYPE_NONE, NULL );
544     LogPlayerError( error );
545
546     error = player_set_display_visible( mPlayer, true );
547     LogPlayerError( error );
548
549     mTimer = Dali::Timer::New( TIMER_INTERVAL );
550     mTimer.TickSignal().Connect( this, &TizenVideoPlayer::Update );
551   }
552 }
553
554 void TizenVideoPlayer::InitializeUnderlayMode( Ecore_Wl_Window* ecoreWlWindow )
555 {
556   int error;
557   if( mPlayerState == PLAYER_STATE_NONE )
558   {
559     error = player_create( &mPlayer );
560     LogPlayerError( error );
561   }
562
563   GetPlayerState( &mPlayerState );
564   mEcoreWlWindow = ecoreWlWindow;
565
566   if( mPlayerState == PLAYER_STATE_IDLE )
567   {
568     error = player_set_completed_cb( mPlayer, EmitPlaybackFinishedSignal, this );
569     LogPlayerError( error );
570
571     error = player_set_sound_type( mPlayer, SOUND_TYPE_MEDIA );
572     LogPlayerError( error );
573
574     error = player_set_display_mode( mPlayer, PLAYER_DISPLAY_MODE_DST_ROI );
575     LogPlayerError( error );
576
577     error = player_set_display_roi_area( mPlayer, 0, 0, 1, 1 );
578
579     int width, height;
580     mAlphaBitChanged = ( ecore_wl_window_alpha_get( mEcoreWlWindow ) )? false: true;
581     ecore_wl_screen_size_get( &width, &height );
582
583     if( mAlphaBitChanged )
584     {
585       ecore_wl_window_alpha_set( mEcoreWlWindow, true );
586     }
587     error = player_set_ecore_wl_display( mPlayer, PLAYER_DISPLAY_TYPE_OVERLAY, mEcoreWlWindow, 0, 0, width, height );
588     LogPlayerError( error );
589
590     error = player_set_display_visible( mPlayer, true );
591     LogPlayerError( error );
592   }
593 }
594
595 bool TizenVideoPlayer::Update()
596 {
597   Dali::Mutex::ScopedLock lock( mPacketMutex );
598
599   int error;
600
601   if( mPacket != NULL )
602   {
603     error = media_packet_destroy( mPacket );
604     if( error != MEDIA_PACKET_ERROR_NONE )
605     {
606       DALI_LOG_ERROR( "Media packet destroy error: %d\n", error );
607     }
608     mPacket = NULL;
609   }
610
611   if( !mPacketVector.Empty() )
612   {
613     mPacket = static_cast< media_packet_h >( mPacketVector[0] );
614     mPacketVector.Remove( mPacketVector.Begin() );
615   }
616
617   if( mPacket == NULL )
618   {
619     return true;
620   }
621
622   error = media_packet_get_tbm_surface( mPacket, &mTbmSurface );
623   if( error != MEDIA_PACKET_ERROR_NONE )
624   {
625     media_packet_destroy( mPacket );
626     mPacket = NULL;
627     DALI_LOG_ERROR( " error: %d\n", error );
628     return true;
629   }
630
631   Any source( mTbmSurface );
632   mNativeImageSourcePtr->SetSource( source );
633   Dali::Stage::GetCurrent().KeepRendering( 0.0f );
634
635   return true;
636 }
637
638 void TizenVideoPlayer::DestroyPackets()
639 {
640   int error;
641   if( mPacket != NULL )
642   {
643     error = media_packet_destroy( mPacket );
644     DALI_LOG_ERROR( "Media packet destroy error: %d\n", error );
645     mPacket = NULL;
646   }
647
648   for(unsigned int i = 0; i < mPacketVector.Size(); ++i)
649   {
650     mPacket = static_cast< media_packet_h >( mPacketVector[i] );
651     error = media_packet_destroy( mPacket );
652     DALI_LOG_ERROR( "Media packet destroy error: %d\n", error );
653     mPacket = NULL;
654   }
655   mPacketVector.Clear();
656 }
657
658 void TizenVideoPlayer::PushPacket( media_packet_h packet )
659 {
660   Dali::Mutex::ScopedLock lock( mPacketMutex );
661   mPacketVector.PushBack( packet );
662 }
663
664 void TizenVideoPlayer::SetDisplayArea( DisplayArea area )
665 {
666   GetPlayerState( &mPlayerState );
667
668   if( mNativeImageSourcePtr != NULL )
669   {
670     DALI_LOG_ERROR( "SetDisplayArea is only for window surface target.\n" );
671     return;
672   }
673
674   if( mPlayerState == PLAYER_STATE_IDLE ||
675       mPlayerState == PLAYER_STATE_READY ||
676       mPlayerState == PLAYER_STATE_PLAYING ||
677       mPlayerState == PLAYER_STATE_PAUSED
678
679   )
680   {
681     int error = player_set_display_roi_area( mPlayer, area.x, area.y, area.width, area.height );
682     LogPlayerError( error );
683   }
684 }
685
686 void TizenVideoPlayer::Forward( int millisecond )
687 {
688   int error;
689
690   GetPlayerState( &mPlayerState );
691
692   if( mPlayerState == PLAYER_STATE_READY ||
693       mPlayerState == PLAYER_STATE_PLAYING ||
694       mPlayerState == PLAYER_STATE_PAUSED
695   )
696   {
697     int currentPosition = 0;
698     int nextPosition = 0;
699
700     error = player_get_play_position( mPlayer, &currentPosition );
701     LogPlayerError( error );
702
703     nextPosition = currentPosition + millisecond;
704
705     error = player_set_play_position( mPlayer, nextPosition, false, PlayerSeekCompletedCb, NULL );
706     LogPlayerError( error );
707   }
708 }
709
710 void TizenVideoPlayer::Backward( int millisecond )
711 {
712   int error;
713
714   GetPlayerState( &mPlayerState );
715
716   if( mPlayerState == PLAYER_STATE_READY ||
717       mPlayerState == PLAYER_STATE_PLAYING ||
718       mPlayerState == PLAYER_STATE_PAUSED
719   )
720   {
721     int currentPosition = 0;
722     int nextPosition = 0;
723
724     error = player_get_play_position( mPlayer, &currentPosition );
725     LogPlayerError( error );
726
727     nextPosition = currentPosition - millisecond;
728     nextPosition = ( nextPosition < 0 )? 0 : nextPosition;
729
730     error = player_set_play_position( mPlayer, nextPosition, false, PlayerSeekCompletedCb, NULL );
731     LogPlayerError( error );
732   }
733 }
734
735 } // namespace Plugin
736 } // namespace Dali;