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