d33e2347d5f3cbe916e7eb62aa1a165b4aef1dea
[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   mBackgroundColor( Dali::Stage::DEFAULT_BACKGROUND_COLOR ),
212   mTargetType( NativeImage )
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
283   if( target.GetType() == typeid( Dali::NativeImageSourcePtr ) )
284   {
285     if( mTargetType == TizenVideoPlayer::WindowSurface )
286     {
287       Stage::GetCurrent().SetBackgroundColor( mBackgroundColor );
288     }
289     mTargetType = TizenVideoPlayer::NativeImage;
290
291     Dali::NativeImageSourcePtr nativeImageSourcePtr = AnyCast< Dali::NativeImageSourcePtr >( target );
292
293     InitializeTextureStreamMode( nativeImageSourcePtr );
294   }
295   else if( target.GetType() == typeid( Ecore_Wl_Window* ) )
296   {
297     mTargetType = TizenVideoPlayer::WindowSurface;
298     mBackgroundColor = Stage::GetCurrent().GetBackgroundColor();
299     Stage::GetCurrent().SetBackgroundColor( Color::TRANSPARENT );
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, true, NULL, 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( mPlayerState == PLAYER_STATE_NONE )
516   {
517     error = player_create( &mPlayer );
518     LogPlayerError( error );
519   }
520
521   GetPlayerState( &mPlayerState );
522
523   if( mPlayerState == PLAYER_STATE_IDLE )
524   {
525     error = player_set_completed_cb( mPlayer, EmitPlaybackFinishedSignal, this );
526     LogPlayerError( error );
527
528     error = player_set_media_packet_video_frame_decoded_cb( mPlayer, MediaPacketVideoDecodedCb, this );
529     LogPlayerError( error );
530
531     error = player_set_sound_type( mPlayer, SOUND_TYPE_MEDIA );
532     LogPlayerError( error );
533
534     error = player_set_display_mode( mPlayer, PLAYER_DISPLAY_MODE_FULL_SCREEN );
535     LogPlayerError( error );
536
537     error = player_set_display( mPlayer, PLAYER_DISPLAY_TYPE_NONE, NULL );
538     LogPlayerError( error );
539
540     error = player_set_display_visible( mPlayer, true );
541     LogPlayerError( error );
542
543     mTimer = Dali::Timer::New( TIMER_INTERVAL );
544     mTimer.TickSignal().Connect( this, &TizenVideoPlayer::Update );
545   }
546 }
547
548 void TizenVideoPlayer::InitializeUnderlayMode( Ecore_Wl_Window* ecoreWlWindow )
549 {
550   int error;
551   if( mPlayerState == PLAYER_STATE_NONE )
552   {
553     error = player_create( &mPlayer );
554     LogPlayerError( error );
555   }
556
557   GetPlayerState( &mPlayerState );
558
559   if( mPlayerState == PLAYER_STATE_IDLE )
560   {
561     error = player_set_completed_cb( mPlayer, EmitPlaybackFinishedSignal, this );
562     LogPlayerError( error );
563
564     error = player_set_sound_type( mPlayer, SOUND_TYPE_MEDIA );
565     LogPlayerError( error );
566
567     error = player_set_display_mode( mPlayer, PLAYER_DISPLAY_MODE_FULL_SCREEN );
568     LogPlayerError( error );
569
570     int width, height;
571     ecore_wl_screen_size_get( &width, &height );
572     error = player_set_ecore_wl_display( mPlayer, PLAYER_DISPLAY_TYPE_OVERLAY, ecoreWlWindow, 0, 0, width, height );
573     LogPlayerError( error );
574
575     error = player_set_display_visible( mPlayer, true );
576     LogPlayerError( error );
577   }
578 }
579
580 bool TizenVideoPlayer::Update()
581 {
582   Dali::Mutex::ScopedLock lock( mPacketMutex );
583
584   int error;
585
586   if( mPacket != NULL )
587   {
588     error = media_packet_destroy( mPacket );
589     if( error != MEDIA_PACKET_ERROR_NONE )
590     {
591       DALI_LOG_ERROR( "Media packet destroy error: %d\n", error );
592     }
593     mPacket = NULL;
594   }
595
596   if( !mPacketVector.Empty() )
597   {
598     mPacket = static_cast< media_packet_h >( mPacketVector[0] );
599     mPacketVector.Remove( mPacketVector.Begin() );
600   }
601
602   if( mPacket == NULL )
603   {
604     return true;
605   }
606
607   error = media_packet_get_tbm_surface( mPacket, &mTbmSurface );
608   if( error != MEDIA_PACKET_ERROR_NONE )
609   {
610     media_packet_destroy( mPacket );
611     mPacket = NULL;
612     DALI_LOG_ERROR( " error: %d\n", error );
613     return true;
614   }
615
616   Any source( mTbmSurface );
617   mNativeImageSourcePtr->SetSource( source );
618   Dali::Stage::GetCurrent().KeepRendering( 0.0f );
619
620   return true;
621 }
622
623 void TizenVideoPlayer::DestroyPackets()
624 {
625   int error;
626   if( mPacket != NULL )
627   {
628     error = media_packet_destroy( mPacket );
629     DALI_LOG_ERROR( "Media packet destroy error: %d\n", error );
630     mPacket = NULL;
631   }
632
633   for(unsigned int i = 0; i < mPacketVector.Size(); ++i)
634   {
635     mPacket = static_cast< media_packet_h >( mPacketVector[i] );
636     error = media_packet_destroy( mPacket );
637     DALI_LOG_ERROR( "Media packet destroy error: %d\n", error );
638     mPacket = NULL;
639   }
640   mPacketVector.Clear();
641 }
642
643 void TizenVideoPlayer::PushPacket( media_packet_h packet )
644 {
645   Dali::Mutex::ScopedLock lock( mPacketMutex );
646   mPacketVector.PushBack( packet );
647 }
648
649 } // namespace Plugin
650 } // namespace Dali;