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