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