e11736ee72ae36b2108ab600dccc201e778df782
[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 : mUrl(),
213   mPlayer( NULL ),
214   mPlayerState( PLAYER_STATE_NONE ),
215   mTbmSurface( NULL ),
216   mPacket( NULL ),
217   mNativeImageSourcePtr( NULL ),
218   mTimer( NULL ),
219   mBackgroundColor( Vector4( 1.0f, 1.0f, 1.0f, 0.0f ) ),
220   mTargetType( NativeImage ),
221   mPacketMutex(),
222   mPacketVector(),
223   mEcoreWlWindow( NULL ),
224   mAlphaBitChanged( false )
225 {
226 }
227
228 TizenVideoPlayer::~TizenVideoPlayer()
229 {
230 }
231
232 void TizenVideoPlayer::GetPlayerState( player_state_e* state )
233 {
234   if( mPlayer != NULL && player_get_state( mPlayer, state ) != PLAYER_ERROR_NONE )
235   {
236     DALI_LOG_ERROR( "player_get_state error: Invalid parameter\n" );
237     *state = PLAYER_STATE_NONE;
238   }
239 }
240
241 void TizenVideoPlayer::SetUrl( const std::string& url )
242 {
243   if( mUrl != url )
244   {
245     mUrl = url;
246
247     GetPlayerState( &mPlayerState );
248
249     if( mPlayerState != PLAYER_STATE_NONE && mPlayerState != PLAYER_STATE_IDLE )
250     {
251       Stop();
252       int error = player_unprepare( mPlayer );
253       LogPlayerError( error );
254     }
255
256     if( mPlayerState == PLAYER_STATE_IDLE )
257     {
258       int error = player_set_uri( mPlayer, mUrl.c_str() );
259       LogPlayerError( error );
260
261       error = player_prepare( mPlayer );
262       LogPlayerError( error );
263     }
264   }
265 }
266
267 std::string TizenVideoPlayer::GetUrl()
268 {
269   return mUrl;
270 }
271
272 void TizenVideoPlayer::SetRenderingTarget( Any target )
273 {
274   int error;
275   if( mPlayerState != PLAYER_STATE_NONE )
276   {
277     GetPlayerState( &mPlayerState );
278
279     if( mPlayerState != PLAYER_STATE_IDLE )
280     {
281       Stop();
282       error = player_unprepare( mPlayer );
283       LogPlayerError( error );
284     }
285
286     error = player_destroy( mPlayer );
287     LogPlayerError( error );
288     mPlayerState = PLAYER_STATE_NONE;
289     mPlayer = NULL;
290     mUrl = "";
291   }
292
293   mNativeImageSourcePtr = NULL;
294   mEcoreWlWindow = NULL;
295
296   if( target.GetType() == typeid( Dali::NativeImageSourcePtr ) )
297   {
298     mTargetType = TizenVideoPlayer::NativeImage;
299
300     Dali::NativeImageSourcePtr nativeImageSourcePtr = AnyCast< Dali::NativeImageSourcePtr >( target );
301
302     InitializeTextureStreamMode( nativeImageSourcePtr );
303   }
304   else if( target.GetType() == typeid( Ecore_Wl_Window* ) )
305   {
306     mTargetType = TizenVideoPlayer::WindowSurface;
307
308     Ecore_Wl_Window* nativeWindow = Dali::AnyCast< Ecore_Wl_Window* >( target );
309     InitializeUnderlayMode( nativeWindow );
310   }
311   else
312   {
313     DALI_LOG_ERROR( "Video rendering target is unknown\n" );
314   }
315 }
316
317 void TizenVideoPlayer::SetLooping( bool looping )
318 {
319   GetPlayerState( &mPlayerState );
320
321   if( mPlayerState != PLAYER_STATE_NONE )
322   {
323     int error = player_set_looping( mPlayer, looping );
324     LogPlayerError( error );
325   }
326 }
327
328 bool TizenVideoPlayer::IsLooping()
329 {
330   GetPlayerState( &mPlayerState );
331
332   bool looping = false;
333   if( mPlayerState != PLAYER_STATE_NONE )
334   {
335     int error = player_is_looping( mPlayer, &looping );
336     LogPlayerError( error );
337   }
338
339   return looping;
340 }
341
342 void TizenVideoPlayer::Play()
343 {
344   GetPlayerState( &mPlayerState );
345
346   if( mPlayerState == PLAYER_STATE_READY || mPlayerState == PLAYER_STATE_PAUSED )
347   {
348     if( mNativeImageSourcePtr != NULL && mTimer )
349     {
350       mTimer.Start();
351     }
352
353     int error = player_start( mPlayer );
354     LogPlayerError( error );
355   }
356 }
357
358 void TizenVideoPlayer::Pause()
359 {
360   GetPlayerState( &mPlayerState );
361
362   if( mPlayerState == PLAYER_STATE_PLAYING )
363   {
364     int error = player_pause( mPlayer );
365     LogPlayerError( error );
366
367     if( mNativeImageSourcePtr != NULL && mTimer )
368     {
369       mTimer.Stop();
370       DestroyPackets();
371     }
372   }
373 }
374
375 void TizenVideoPlayer::Stop()
376 {
377   GetPlayerState( &mPlayerState );
378
379   if( mPlayerState == PLAYER_STATE_PLAYING || mPlayerState == PLAYER_STATE_PAUSED )
380   {
381     int error = player_stop( mPlayer );
382     LogPlayerError( error );
383   }
384
385   if( mNativeImageSourcePtr != NULL && mTimer )
386   {
387     mTimer.Stop();
388     DestroyPackets();
389   }
390 }
391
392 void TizenVideoPlayer::SetMute( bool muted )
393 {
394   GetPlayerState( &mPlayerState );
395
396   if( mPlayerState == PLAYER_STATE_IDLE ||
397       mPlayerState == PLAYER_STATE_READY ||
398       mPlayerState == PLAYER_STATE_PLAYING ||
399       mPlayerState == PLAYER_STATE_PAUSED
400     )
401   {
402     int error = player_set_mute( mPlayer, muted );
403     LogPlayerError( error );
404   }
405 }
406
407 bool TizenVideoPlayer::IsMuted()
408 {
409   GetPlayerState( &mPlayerState );
410   bool muted = false;
411
412    if( mPlayerState == PLAYER_STATE_IDLE ||
413       mPlayerState == PLAYER_STATE_READY ||
414       mPlayerState == PLAYER_STATE_PLAYING ||
415       mPlayerState == PLAYER_STATE_PAUSED
416     )
417   {
418     int error = player_is_muted( mPlayer, &muted );
419     LogPlayerError( error );
420   }
421
422   return muted;
423 }
424
425 void TizenVideoPlayer::SetVolume( float left, float right )
426 {
427   GetPlayerState( &mPlayerState );
428
429   int error = player_set_volume( mPlayer, left, right );
430   LogPlayerError( error );
431 }
432
433 void TizenVideoPlayer::GetVolume( float& left, float& right )
434 {
435   GetPlayerState( &mPlayerState );
436
437   int error = player_get_volume( mPlayer, &left, &right );
438   LogPlayerError( error );
439 }
440
441 void TizenVideoPlayer::SetPlayPosition( int millisecond )
442 {
443   int error;
444
445   GetPlayerState( &mPlayerState );
446
447   if( mPlayerState == PLAYER_STATE_READY ||
448       mPlayerState == PLAYER_STATE_PLAYING ||
449       mPlayerState == PLAYER_STATE_PAUSED
450   )
451   {
452     error = player_set_play_position( mPlayer, millisecond, false, PlayerSeekCompletedCb, NULL );
453     LogPlayerError( error );
454   }
455 }
456
457 int TizenVideoPlayer::GetPlayPosition()
458 {
459   int error;
460   int millisecond = 0;
461
462   GetPlayerState( &mPlayerState );
463
464   if( mPlayerState == PLAYER_STATE_IDLE ||
465       mPlayerState == PLAYER_STATE_READY ||
466       mPlayerState == PLAYER_STATE_PLAYING ||
467       mPlayerState == PLAYER_STATE_PAUSED
468   )
469   {
470     error = player_get_play_position( mPlayer, &millisecond );
471     LogPlayerError( error );
472   }
473
474   return millisecond;
475 }
476
477 void TizenVideoPlayer::SetDisplayRotation( Dali::VideoPlayerPlugin::DisplayRotation rotation )
478 {
479   if( mNativeImageSourcePtr != NULL )
480   {
481     DALI_LOG_ERROR( "SetDisplayRotation is only for window rendering target.\n" );
482     return;
483   }
484
485   int error;
486   if( mPlayerState != PLAYER_STATE_NONE )
487   {
488     error = player_set_display_rotation( mPlayer, static_cast< player_display_rotation_e >( rotation ) );
489     LogPlayerError( error );
490   }
491 }
492
493 Dali::VideoPlayerPlugin::DisplayRotation TizenVideoPlayer::GetDisplayRotation()
494 {
495   if( mNativeImageSourcePtr != NULL )
496   {
497     DALI_LOG_ERROR( "GetDisplayRotation is only for window rendering target.\n" );
498     return Dali::VideoPlayerPlugin::ROTATION_NONE;
499   }
500
501   int error;
502   player_display_rotation_e rotation = PLAYER_DISPLAY_ROTATION_NONE;
503   if( mPlayerState != PLAYER_STATE_NONE )
504   {
505     error = player_get_display_rotation( mPlayer, &rotation );
506     LogPlayerError( error );
507   }
508   return static_cast< Dali::VideoPlayerPlugin::DisplayRotation >( rotation );
509 }
510
511 Dali::VideoPlayerPlugin::VideoPlayerSignalType& TizenVideoPlayer::FinishedSignal()
512 {
513   return mFinishedSignal;
514 }
515
516 void TizenVideoPlayer::InitializeTextureStreamMode( Dali::NativeImageSourcePtr nativeImageSourcePtr )
517 {
518   int error;
519
520   mNativeImageSourcePtr = nativeImageSourcePtr;
521
522   if( mAlphaBitChanged )
523   {
524     ecore_wl_window_alpha_set( mEcoreWlWindow, false );
525     mAlphaBitChanged = false;
526   }
527
528   if( mPlayerState == PLAYER_STATE_NONE )
529   {
530     error = player_create( &mPlayer );
531     LogPlayerError( error );
532   }
533
534   GetPlayerState( &mPlayerState );
535
536   if( mPlayerState == PLAYER_STATE_IDLE )
537   {
538     error = player_set_completed_cb( mPlayer, EmitPlaybackFinishedSignal, this );
539     LogPlayerError( error );
540
541     error = player_set_media_packet_video_frame_decoded_cb( mPlayer, MediaPacketVideoDecodedCb, this );
542     LogPlayerError( error );
543
544     error = player_set_sound_type( mPlayer, SOUND_TYPE_MEDIA );
545     LogPlayerError( error );
546
547     error = player_set_display_mode( mPlayer, PLAYER_DISPLAY_MODE_FULL_SCREEN );
548     LogPlayerError( error );
549
550     error = player_set_display( mPlayer, PLAYER_DISPLAY_TYPE_NONE, NULL );
551     LogPlayerError( error );
552
553     error = player_set_display_visible( mPlayer, true );
554     LogPlayerError( error );
555
556     mTimer = Dali::Timer::New( TIMER_INTERVAL );
557     mTimer.TickSignal().Connect( this, &TizenVideoPlayer::Update );
558   }
559 }
560
561 void TizenVideoPlayer::InitializeUnderlayMode( Ecore_Wl_Window* ecoreWlWindow )
562 {
563   int error;
564   if( mPlayerState == PLAYER_STATE_NONE )
565   {
566     error = player_create( &mPlayer );
567     LogPlayerError( error );
568   }
569
570   GetPlayerState( &mPlayerState );
571   mEcoreWlWindow = ecoreWlWindow;
572
573   if( mPlayerState == PLAYER_STATE_IDLE )
574   {
575     error = player_set_completed_cb( mPlayer, EmitPlaybackFinishedSignal, this );
576     LogPlayerError( error );
577
578     error = player_set_sound_type( mPlayer, SOUND_TYPE_MEDIA );
579     LogPlayerError( error );
580
581     error = player_set_display_mode( mPlayer, PLAYER_DISPLAY_MODE_DST_ROI );
582     LogPlayerError( error );
583
584     error = player_set_display_roi_area( mPlayer, 0, 0, 1, 1 );
585
586     int width, height;
587     mAlphaBitChanged = ( ecore_wl_window_alpha_get( mEcoreWlWindow ) )? false: true;
588     ecore_wl_screen_size_get( &width, &height );
589
590     if( mAlphaBitChanged )
591     {
592       ecore_wl_window_alpha_set( mEcoreWlWindow, true );
593     }
594     error = player_set_ecore_wl_display( mPlayer, PLAYER_DISPLAY_TYPE_OVERLAY, mEcoreWlWindow, 0, 0, width, height );
595     LogPlayerError( error );
596
597     error = player_set_display_visible( mPlayer, true );
598     LogPlayerError( error );
599   }
600 }
601
602 bool TizenVideoPlayer::Update()
603 {
604   Dali::Mutex::ScopedLock lock( mPacketMutex );
605
606   int error;
607
608   if( mPacket != NULL )
609   {
610     error = media_packet_destroy( mPacket );
611     if( error != MEDIA_PACKET_ERROR_NONE )
612     {
613       DALI_LOG_ERROR( "Media packet destroy error: %d\n", error );
614     }
615     mPacket = NULL;
616   }
617
618   if( !mPacketVector.Empty() )
619   {
620     mPacket = static_cast< media_packet_h >( mPacketVector[0] );
621     mPacketVector.Remove( mPacketVector.Begin() );
622   }
623
624   if( mPacket == NULL )
625   {
626     return true;
627   }
628
629   error = media_packet_get_tbm_surface( mPacket, &mTbmSurface );
630   if( error != MEDIA_PACKET_ERROR_NONE )
631   {
632     media_packet_destroy( mPacket );
633     mPacket = NULL;
634     DALI_LOG_ERROR( " error: %d\n", error );
635     return true;
636   }
637
638   Any source( mTbmSurface );
639   mNativeImageSourcePtr->SetSource( source );
640   Dali::Stage::GetCurrent().KeepRendering( 0.0f );
641
642   return true;
643 }
644
645 void TizenVideoPlayer::DestroyPackets()
646 {
647   int error;
648   if( mPacket != NULL )
649   {
650     error = media_packet_destroy( mPacket );
651     DALI_LOG_ERROR( "Media packet destroy error: %d\n", error );
652     mPacket = NULL;
653   }
654
655   for(unsigned int i = 0; i < mPacketVector.Size(); ++i)
656   {
657     mPacket = static_cast< media_packet_h >( mPacketVector[i] );
658     error = media_packet_destroy( mPacket );
659     DALI_LOG_ERROR( "Media packet destroy error: %d\n", error );
660     mPacket = NULL;
661   }
662   mPacketVector.Clear();
663 }
664
665 void TizenVideoPlayer::PushPacket( media_packet_h packet )
666 {
667   Dali::Mutex::ScopedLock lock( mPacketMutex );
668   mPacketVector.PushBack( packet );
669 }
670
671 void TizenVideoPlayer::SetDisplayArea( DisplayArea area )
672 {
673   GetPlayerState( &mPlayerState );
674
675   if( mNativeImageSourcePtr != NULL )
676   {
677     DALI_LOG_ERROR( "SetDisplayArea is only for window surface target.\n" );
678     return;
679   }
680
681   if( mPlayerState == PLAYER_STATE_IDLE ||
682       mPlayerState == PLAYER_STATE_READY ||
683       mPlayerState == PLAYER_STATE_PLAYING ||
684       mPlayerState == PLAYER_STATE_PAUSED
685
686   )
687   {
688     int error = player_set_display_roi_area( mPlayer, area.x, area.y, area.width, area.height );
689     LogPlayerError( error );
690   }
691 }
692
693 void TizenVideoPlayer::Forward( int millisecond )
694 {
695   int error;
696
697   GetPlayerState( &mPlayerState );
698
699   if( mPlayerState == PLAYER_STATE_READY ||
700       mPlayerState == PLAYER_STATE_PLAYING ||
701       mPlayerState == PLAYER_STATE_PAUSED
702   )
703   {
704     int currentPosition = 0;
705     int nextPosition = 0;
706
707     error = player_get_play_position( mPlayer, &currentPosition );
708     LogPlayerError( error );
709
710     nextPosition = currentPosition + millisecond;
711
712     error = player_set_play_position( mPlayer, nextPosition, false, PlayerSeekCompletedCb, NULL );
713     LogPlayerError( error );
714   }
715 }
716
717 void TizenVideoPlayer::Backward( int millisecond )
718 {
719   int error;
720
721   GetPlayerState( &mPlayerState );
722
723   if( mPlayerState == PLAYER_STATE_READY ||
724       mPlayerState == PLAYER_STATE_PLAYING ||
725       mPlayerState == PLAYER_STATE_PAUSED
726   )
727   {
728     int currentPosition = 0;
729     int nextPosition = 0;
730
731     error = player_get_play_position( mPlayer, &currentPosition );
732     LogPlayerError( error );
733
734     nextPosition = currentPosition - millisecond;
735     nextPosition = ( nextPosition < 0 )? 0 : nextPosition;
736
737     error = player_set_play_position( mPlayer, nextPosition, false, PlayerSeekCompletedCb, NULL );
738     LogPlayerError( error );
739   }
740 }
741
742 } // namespace Plugin
743 } // namespace Dali;