4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <gst/app/gstappsrc.h>
31 #include <gst/video/videooverlay.h>
33 #include <gst/wayland/wayland.h>
43 #include <mm_attrs_private.h>
46 #include "mm_player_priv.h"
47 #include "mm_player_ini.h"
48 #include "mm_player_attrs.h"
49 #include "mm_player_utils.h"
52 /*===========================================================================================
54 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
56 ========================================================================================== */
58 /*---------------------------------------------------------------------------
59 | GLOBAL CONSTANT DEFINITIONS: |
60 ---------------------------------------------------------------------------*/
62 /*---------------------------------------------------------------------------
63 | IMPORTED VARIABLE DECLARATIONS: |
64 ---------------------------------------------------------------------------*/
66 /*---------------------------------------------------------------------------
67 | IMPORTED FUNCTION DECLARATIONS: |
68 ---------------------------------------------------------------------------*/
70 /*---------------------------------------------------------------------------
72 ---------------------------------------------------------------------------*/
74 /*---------------------------------------------------------------------------
75 | LOCAL CONSTANT DEFINITIONS: |
76 ---------------------------------------------------------------------------*/
78 /*---------------------------------------------------------------------------
79 | LOCAL DATA TYPE DEFINITIONS: |
80 ---------------------------------------------------------------------------*/
82 /*---------------------------------------------------------------------------
83 | GLOBAL VARIABLE DEFINITIONS: |
84 ---------------------------------------------------------------------------*/
86 /*---------------------------------------------------------------------------
87 | LOCAL VARIABLE DEFINITIONS: |
88 ---------------------------------------------------------------------------*/
90 /*---------------------------------------------------------------------------
91 | LOCAL FUNCTION PROTOTYPES: |
92 ---------------------------------------------------------------------------*/
93 static gint __gst_transform_gsterror( mm_player_t* player, GstMessage * message, GError* error);
95 /*===========================================================================================
97 | FUNCTION DEFINITIONS |
99 ========================================================================================== */
101 __mmplayer_check_state(mm_player_t* player, enum PlayerCommandState command)
103 MMPlayerStateType current_state = MM_PLAYER_STATE_NUM;
104 MMPlayerStateType pending_state = MM_PLAYER_STATE_NUM;
105 // MMPlayerStateType target_state = MM_PLAYER_STATE_NUM;
106 // MMPlayerStateType prev_state = MM_PLAYER_STATE_NUM;
108 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
110 //debug_log("incomming command : %d \n", command );
112 current_state = MMPLAYER_CURRENT_STATE(player);
113 pending_state = MMPLAYER_PENDING_STATE(player);
114 // target_state = MMPLAYER_TARGET_STATE(player);
115 // prev_state = MMPLAYER_PREV_STATE(player);
117 MMPLAYER_PRINT_STATE(player);
121 case MMPLAYER_COMMAND_CREATE:
123 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
125 if ( current_state == MM_PLAYER_STATE_NULL ||
126 current_state == MM_PLAYER_STATE_READY ||
127 current_state == MM_PLAYER_STATE_PAUSED ||
128 current_state == MM_PLAYER_STATE_PLAYING )
133 case MMPLAYER_COMMAND_DESTROY:
135 /* destroy can called anytime */
137 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
141 case MMPLAYER_COMMAND_REALIZE:
143 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
145 if ( pending_state != MM_PLAYER_STATE_NONE )
151 /* need ready state to realize */
152 if ( current_state == MM_PLAYER_STATE_READY )
155 if ( current_state != MM_PLAYER_STATE_NULL )
161 case MMPLAYER_COMMAND_UNREALIZE:
163 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
165 if ( current_state == MM_PLAYER_STATE_NULL )
170 case MMPLAYER_COMMAND_START:
172 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
174 if ( pending_state == MM_PLAYER_STATE_NONE )
176 if ( current_state == MM_PLAYER_STATE_PLAYING )
178 else if ( current_state != MM_PLAYER_STATE_READY &&
179 current_state != MM_PLAYER_STATE_PAUSED )
182 else if ( pending_state == MM_PLAYER_STATE_PLAYING )
186 else if ( pending_state == MM_PLAYER_STATE_PAUSED )
188 debug_log("player is going to paused state, just change the pending state as playing");
197 case MMPLAYER_COMMAND_STOP:
199 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
201 if ( current_state == MM_PLAYER_STATE_READY )
204 /* need playing/paused state to stop */
205 if ( current_state != MM_PLAYER_STATE_PLAYING &&
206 current_state != MM_PLAYER_STATE_PAUSED )
211 case MMPLAYER_COMMAND_PAUSE:
213 if ( MMPLAYER_IS_LIVE_STREAMING( player ) )
216 if (player->doing_seek)
217 goto NOT_COMPLETED_SEEK;
219 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
221 if ( pending_state == MM_PLAYER_STATE_NONE )
223 if ( current_state == MM_PLAYER_STATE_PAUSED )
225 else if ( current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY ) // support loading state of broswer
228 else if ( pending_state == MM_PLAYER_STATE_PAUSED )
232 else if ( pending_state == MM_PLAYER_STATE_PLAYING )
234 if ( current_state == MM_PLAYER_STATE_PAUSED ) {
235 debug_log("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
243 case MMPLAYER_COMMAND_RESUME:
246 if (player->doing_seek)
247 goto NOT_COMPLETED_SEEK;
249 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
251 if ( pending_state == MM_PLAYER_STATE_NONE )
253 if ( current_state == MM_PLAYER_STATE_PLAYING )
255 else if ( current_state != MM_PLAYER_STATE_PAUSED )
258 else if ( pending_state == MM_PLAYER_STATE_PLAYING )
262 else if ( pending_state == MM_PLAYER_STATE_PAUSED )
264 debug_log("player is going to paused state, just change the pending state as playing");
276 player->cmd = command;
278 return MM_ERROR_NONE;
281 debug_warning("since player is in wrong state(%s). it's not able to apply the command(%d)",
282 MMPLAYER_STATE_GET_NAME(current_state), command);
283 return MM_ERROR_PLAYER_INVALID_STATE;
286 debug_warning("not completed seek");
287 return MM_ERROR_PLAYER_DOING_SEEK;
290 debug_warning("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
291 return MM_ERROR_PLAYER_NO_OP;
294 debug_warning("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
295 return MM_ERROR_PLAYER_NO_OP;
299 __mmplayer_gst_set_state (mm_player_t* player, GstElement * element, GstState state, gboolean async, gint timeout) // @
301 GstState element_state = GST_STATE_VOID_PENDING;
302 GstState element_pending_state = GST_STATE_VOID_PENDING;
303 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
307 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
308 return_val_if_fail ( element, MM_ERROR_INVALID_ARGUMENT );
310 debug_log("setting [%s] element state to : %s\n", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
313 ret = gst_element_set_state(element, state);
315 if ( ret == GST_STATE_CHANGE_FAILURE )
317 debug_error("failed to set [%s] state\n", GST_ELEMENT_NAME(element));
319 /* dump state of all element */
320 __mmplayer_dump_pipeline_state( player );
322 return MM_ERROR_PLAYER_INTERNAL;
325 /* return here so state transition to be done in async mode */
328 debug_log("async state transition. not waiting for state complete.\n");
329 return MM_ERROR_NONE;
332 /* wait for state transition */
333 ret = gst_element_get_state( element, &element_state, &element_pending_state, timeout * GST_SECOND );
335 if ( ret == GST_STATE_CHANGE_FAILURE || ( state != element_state ) )
337 debug_error("failed to change [%s] element state to [%s] within %d sec\n",
338 GST_ELEMENT_NAME(element),
339 gst_element_state_get_name(state), timeout );
341 debug_error(" [%s] state : %s pending : %s \n",
342 GST_ELEMENT_NAME(element),
343 gst_element_state_get_name(element_state),
344 gst_element_state_get_name(element_pending_state) );
346 /* dump state of all element */
347 __mmplayer_dump_pipeline_state( player );
349 return MM_ERROR_PLAYER_INTERNAL;
352 debug_log("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
356 return MM_ERROR_NONE;
359 void __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
361 GSource *source = NULL;
365 source = g_main_context_find_source_by_id (context, source_id);
369 debug_warning("context: %p, source id: %d, source: %p", context, source_id, source);
370 g_source_destroy(source);
377 __mmplayer_dump_pipeline_state( mm_player_t* player )
379 GstIterator*iter = NULL;
380 gboolean done = FALSE;
383 GstElement *element = NULL;
384 GstElementFactory *factory = NULL;
386 GstState state = GST_STATE_VOID_PENDING;
387 GstState pending = GST_STATE_VOID_PENDING;
388 GstClockTime time = 200*GST_MSECOND;
392 return_val_if_fail ( player &&
394 player->pipeline->mainbin,
397 iter = gst_bin_iterate_recurse(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst) );
402 switch ( gst_iterator_next (iter, &item) )
404 case GST_ITERATOR_OK:
405 element = g_value_get_object(&item);
406 gst_element_get_state(element,&state, &pending,time);
408 factory = gst_element_get_factory (element) ;
411 debug_error("%s:%s : From:%s To:%s refcount : %d\n", GST_OBJECT_NAME(factory) , GST_ELEMENT_NAME(element) ,
412 gst_element_state_get_name(state), gst_element_state_get_name(pending) , GST_OBJECT_REFCOUNT_VALUE(element));
414 g_value_reset (&item);
416 case GST_ITERATOR_RESYNC:
417 gst_iterator_resync (iter);
419 case GST_ITERATOR_ERROR:
422 case GST_ITERATOR_DONE:
429 element = GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
431 gst_element_get_state(element,&state, &pending,time);
433 factory = gst_element_get_factory (element) ;
437 debug_error("%s:%s : From:%s To:%s refcount : %d\n",
438 GST_OBJECT_NAME(factory),
439 GST_ELEMENT_NAME(element),
440 gst_element_state_get_name(state),
441 gst_element_state_get_name(pending),
442 GST_OBJECT_REFCOUNT_VALUE(element) );
445 g_value_unset(&item);
448 gst_iterator_free (iter);
456 __get_state_name ( int state )
460 case MM_PLAYER_STATE_NULL:
462 case MM_PLAYER_STATE_READY:
464 case MM_PLAYER_STATE_PAUSED:
466 case MM_PLAYER_STATE_PLAYING:
468 case MM_PLAYER_STATE_NONE:
476 __is_rtsp_streaming ( mm_player_t* player )
478 return_val_if_fail ( player, FALSE );
480 return ( player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_RTSP ) ? TRUE : FALSE;
484 __is_wfd_streaming ( mm_player_t* player )
486 return_val_if_fail ( player, FALSE );
488 return ( player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_WFD ) ? TRUE : FALSE;
492 __is_http_streaming ( mm_player_t* player )
494 return_val_if_fail ( player, FALSE );
496 return ( player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_HTTP ) ? TRUE : FALSE;
500 __is_streaming ( mm_player_t* player )
502 return_val_if_fail ( player, FALSE );
504 return ( __is_http_progressive_down( player ) || __is_rtsp_streaming ( player ) || __is_wfd_streaming ( player ) || __is_http_streaming ( player )
505 || __is_http_live_streaming ( player ) || __is_dash_streaming ( player ) || __is_smooth_streaming(player) ) ? TRUE : FALSE;
509 __is_live_streaming ( mm_player_t* player )
511 return_val_if_fail ( player, FALSE );
513 return ( __is_rtsp_streaming ( player ) && player->streaming_type == STREAMING_SERVICE_LIVE ) ? TRUE : FALSE;
517 __is_http_live_streaming( mm_player_t* player )
519 return_val_if_fail( player, FALSE );
521 return ( player->profile.uri_type == MM_PLAYER_URI_TYPE_HLS ) ? TRUE : FALSE;
525 __is_dash_streaming ( mm_player_t* player )
527 return_val_if_fail ( player, FALSE );
529 return ( player->profile.uri_type == MM_PLAYER_URI_TYPE_DASH ) ? TRUE : FALSE;
533 __is_smooth_streaming ( mm_player_t* player )
535 return_val_if_fail ( player, FALSE );
537 return ( player->profile.uri_type == MM_PLAYER_URI_TYPE_SS ) ? TRUE : FALSE;
542 __is_http_progressive_down(mm_player_t* player)
544 return_val_if_fail( player, FALSE );
546 return ((player->pd_mode) ? TRUE:FALSE);
548 /* if retval is FALSE, it will be dropped for perfomance. */
550 __mmplayer_check_useful_message(mm_player_t *player, GstMessage * message)
552 gboolean retval = FALSE;
554 if ( !(player->pipeline && player->pipeline->mainbin) )
556 debug_error("player pipeline handle is null");
560 switch (GST_MESSAGE_TYPE (message))
562 case GST_MESSAGE_TAG:
563 case GST_MESSAGE_EOS:
564 case GST_MESSAGE_ERROR:
565 case GST_MESSAGE_WARNING:
566 case GST_MESSAGE_CLOCK_LOST:
567 case GST_MESSAGE_NEW_CLOCK:
568 case GST_MESSAGE_ELEMENT:
569 case GST_MESSAGE_DURATION_CHANGED:
570 case GST_MESSAGE_ASYNC_START:
573 case GST_MESSAGE_ASYNC_DONE:
574 case GST_MESSAGE_STATE_CHANGED:
575 /* we only handle messages from pipeline */
576 if(( message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst ) && (!player->gapless.reconfigure))
581 case GST_MESSAGE_BUFFERING:
583 gint buffer_percent = 0;
585 gst_message_parse_buffering (message, &buffer_percent);
587 if ((MMPLAYER_IS_STREAMING(player)) &&
588 (player->streamer) &&
589 (player->streamer->is_buffering == TRUE) &&
590 (buffer_percent == MAX_BUFFER_PERCENT))
592 debug_log (">>> [%s] Buffering DONE is detected !!\n", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)));
593 player->streamer->is_buffering_done = TRUE;
608 __mmplayer_post_message(mm_player_t* player, enum MMMessageType msgtype, MMMessageParamType* param) // @
610 return_val_if_fail( player, FALSE );
612 if ( !player->msg_cb )
617 //debug_log("Message (type : %d) will be posted using msg-cb(%p). \n", msgtype, player->msg_cb);
619 player->msg_cb(msgtype, param, player->msg_cb_param);
625 __mmplayer_handle_gst_error ( mm_player_t* player, GstMessage * message, GError* error )
627 MMMessageParamType msg_param;
628 gchar *msg_src_element;
632 return_val_if_fail( player, FALSE );
633 return_val_if_fail( error, FALSE );
635 /* NOTE : do somthing necessary inside of __gst_handle_XXX_error. not here */
637 memset (&msg_param, 0, sizeof(MMMessageParamType));
639 if ( error->domain == GST_CORE_ERROR )
641 msg_param.code = __gst_handle_core_error( player, error->code );
643 else if ( error->domain == GST_LIBRARY_ERROR )
645 msg_param.code = __gst_handle_library_error( player, error->code );
647 else if ( error->domain == GST_RESOURCE_ERROR )
649 msg_param.code = __gst_handle_resource_error( player, error->code );
651 else if ( error->domain == GST_STREAM_ERROR )
653 msg_param.code = __gst_handle_stream_error( player, error, message );
657 debug_warning("This error domain is not defined.\n");
659 /* we treat system error as an internal error */
660 msg_param.code = MM_ERROR_PLAYER_INVALID_STREAM;
665 msg_src_element = GST_ELEMENT_NAME( GST_ELEMENT_CAST( message->src ) );
667 msg_param.data = (void *) error->message;
669 debug_error("-Msg src : [%s] Domain : [%s] Error : [%s] Code : [%d] is tranlated to error code : [0x%x]\n",
670 msg_src_element, g_quark_to_string (error->domain), error->message, error->code, msg_param.code);
674 if (msg_param.code == MM_ERROR_NONE)
677 /* post error to application */
678 if ( ! player->msg_posted )
680 MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param );
681 /* don't post more if one was sent already */
682 player->msg_posted = TRUE;
686 debug_log("skip error post because it's sent already.\n");
695 __gst_handle_core_error( mm_player_t* player, int code )
697 gint trans_err = MM_ERROR_NONE;
701 return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
705 case GST_CORE_ERROR_MISSING_PLUGIN:
706 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
707 case GST_CORE_ERROR_STATE_CHANGE:
708 case GST_CORE_ERROR_SEEK:
709 case GST_CORE_ERROR_NOT_IMPLEMENTED:
710 case GST_CORE_ERROR_FAILED:
711 case GST_CORE_ERROR_TOO_LAZY:
712 case GST_CORE_ERROR_PAD:
713 case GST_CORE_ERROR_THREAD:
714 case GST_CORE_ERROR_NEGOTIATION:
715 case GST_CORE_ERROR_EVENT:
716 case GST_CORE_ERROR_CAPS:
717 case GST_CORE_ERROR_TAG:
718 case GST_CORE_ERROR_CLOCK:
719 case GST_CORE_ERROR_DISABLED:
721 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
731 __gst_handle_library_error( mm_player_t* player, int code )
733 gint trans_err = MM_ERROR_NONE;
737 return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
741 case GST_LIBRARY_ERROR_FAILED:
742 case GST_LIBRARY_ERROR_TOO_LAZY:
743 case GST_LIBRARY_ERROR_INIT:
744 case GST_LIBRARY_ERROR_SHUTDOWN:
745 case GST_LIBRARY_ERROR_SETTINGS:
746 case GST_LIBRARY_ERROR_ENCODE:
748 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
759 __gst_handle_resource_error( mm_player_t* player, int code )
761 gint trans_err = MM_ERROR_NONE;
765 return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
769 case GST_RESOURCE_ERROR_NO_SPACE_LEFT:
770 trans_err = MM_ERROR_PLAYER_NO_FREE_SPACE;
772 case GST_RESOURCE_ERROR_NOT_FOUND:
773 case GST_RESOURCE_ERROR_OPEN_READ:
774 if ( MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING ( player )
775 || MMPLAYER_IS_RTSP_STREAMING(player))
777 trans_err = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
780 case GST_RESOURCE_ERROR_READ:
781 if ( MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING ( player )
782 || MMPLAYER_IS_RTSP_STREAMING(player))
784 trans_err = MM_ERROR_PLAYER_STREAMING_FAIL;
787 case GST_RESOURCE_ERROR_WRITE:
788 case GST_RESOURCE_ERROR_FAILED:
789 case GST_RESOURCE_ERROR_SEEK:
790 case GST_RESOURCE_ERROR_TOO_LAZY:
791 case GST_RESOURCE_ERROR_BUSY:
792 case GST_RESOURCE_ERROR_OPEN_WRITE:
793 case GST_RESOURCE_ERROR_OPEN_READ_WRITE:
794 case GST_RESOURCE_ERROR_CLOSE:
795 case GST_RESOURCE_ERROR_SYNC:
796 case GST_RESOURCE_ERROR_SETTINGS:
798 trans_err = MM_ERROR_PLAYER_INTERNAL;
809 __gst_handle_stream_error( mm_player_t* player, GError* error, GstMessage * message )
811 gint trans_err = MM_ERROR_NONE;
815 return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
816 return_val_if_fail( error, MM_ERROR_INVALID_ARGUMENT );
817 return_val_if_fail ( message, MM_ERROR_INVALID_ARGUMENT );
819 switch ( error->code )
821 case GST_STREAM_ERROR_FAILED:
822 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
823 case GST_STREAM_ERROR_DECODE:
824 case GST_STREAM_ERROR_WRONG_TYPE:
825 case GST_STREAM_ERROR_DECRYPT:
826 case GST_STREAM_ERROR_DECRYPT_NOKEY:
827 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
828 trans_err = __gst_transform_gsterror( player, message, error );
831 case GST_STREAM_ERROR_NOT_IMPLEMENTED:
832 case GST_STREAM_ERROR_TOO_LAZY:
833 case GST_STREAM_ERROR_ENCODE:
834 case GST_STREAM_ERROR_DEMUX:
835 case GST_STREAM_ERROR_MUX:
836 case GST_STREAM_ERROR_FORMAT:
838 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
847 /* NOTE : decide gstreamer state whether there is some playable track or not. */
849 __gst_transform_gsterror( mm_player_t* player, GstMessage * message, GError* error )
851 gchar *src_element_name = NULL;
852 GstElement *src_element = NULL;
853 GstElementFactory *factory = NULL;
854 const gchar* klass = NULL;
859 return_val_if_fail ( message, MM_ERROR_INVALID_ARGUMENT );
860 return_val_if_fail ( message->src, MM_ERROR_INVALID_ARGUMENT );
861 return_val_if_fail ( error, MM_ERROR_INVALID_ARGUMENT );
863 src_element = GST_ELEMENT_CAST(message->src);
867 src_element_name = GST_ELEMENT_NAME(src_element);
868 if ( !src_element_name )
871 factory = gst_element_get_factory(src_element);
875 klass = gst_element_factory_get_metadata (factory, GST_ELEMENT_METADATA_KLASS);
879 debug_log("error code=%d, msg=%s, src element=%s, class=%s\n",
880 error->code, error->message, src_element_name, klass);
884 if (player->selector) {
886 gint active_pad_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
887 debug_log ("current active pad index -%d", active_pad_index);
889 if (src_element_name) {
892 if (player->audio_decoders) {
893 GList *adec = player->audio_decoders;
894 for ( ;adec ; adec = g_list_next(adec)) {
895 gchar *name = adec->data;
897 debug_log("found audio decoder name = %s", name);
898 if (g_strrstr(name, src_element_name)) {
905 debug_log("active pad = %d, error src index = %d", active_pad_index, msg_src_pos);
908 if (active_pad_index != msg_src_pos) {
909 debug_log("skip error because error is posted from no activated track");
910 return MM_ERROR_NONE;
916 switch ( error->code )
918 case GST_STREAM_ERROR_DECODE:
920 /* Demuxer can't parse one track because it's corrupted.
921 * So, the decoder for it is not linked.
922 * But, it has one playable track.
924 if ( g_strrstr(klass, "Demux") )
926 if ( player->can_support_codec == FOUND_PLUGIN_VIDEO )
928 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
930 else if ( player->can_support_codec == FOUND_PLUGIN_AUDIO )
932 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
936 if ( player->pipeline->audiobin ) // PCM
938 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
942 goto CODEC_NOT_FOUND;
946 return MM_ERROR_PLAYER_INVALID_STREAM;
950 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
951 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
952 case GST_STREAM_ERROR_WRONG_TYPE:
953 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
955 case GST_STREAM_ERROR_FAILED:
957 /* Decoder Custom Message */
958 if ( strstr(error->message, "ongoing") )
960 if ( strncasecmp(klass, "audio", 5) )
962 if ( ( player->can_support_codec & FOUND_PLUGIN_VIDEO ) )
964 debug_log("Video can keep playing.\n");
965 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
969 goto CODEC_NOT_FOUND;
973 else if ( strncasecmp(klass, "video", 5) )
975 if ( ( player->can_support_codec & FOUND_PLUGIN_AUDIO ) )
977 debug_log("Audio can keep playing.\n");
978 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
982 goto CODEC_NOT_FOUND;
986 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
990 case GST_STREAM_ERROR_DECRYPT:
991 case GST_STREAM_ERROR_DECRYPT_NOKEY:
993 debug_error("decryption error, [%s] failed, reason : [%s]\n", src_element_name, error->message);
995 if ( strstr(error->message, "rights expired") )
997 return MM_ERROR_PLAYER_DRM_EXPIRED;
999 else if ( strstr(error->message, "no rights") )
1001 return MM_ERROR_PLAYER_DRM_NO_LICENSE;
1003 else if ( strstr(error->message, "has future rights") )
1005 return MM_ERROR_PLAYER_DRM_FUTURE_USE;
1007 else if ( strstr(error->message, "opl violation") )
1009 return MM_ERROR_PLAYER_DRM_OUTPUT_PROTECTION;
1011 return MM_ERROR_PLAYER_DRM_NOT_AUTHORIZED;
1021 return MM_ERROR_PLAYER_INVALID_STREAM;
1024 return MM_ERROR_PLAYER_INTERNAL;
1027 debug_log("not found any available codec. Player should be destroyed.\n");
1028 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
1032 __mmplayer_get_property_value_for_rotation(mm_player_t* player, int rotation_angle, int *value)
1034 int pro_value = 0; // in the case of expection, default will be returned.
1035 int dest_angle = rotation_angle;
1036 int rotation_type = -1;
1037 #define ROTATION_USING_SINK 0
1038 #define ROTATION_USING_CUSTOM 1
1039 #define ROTATION_USING_FLIP 2
1041 return_val_if_fail(player, FALSE);
1042 return_val_if_fail(value, FALSE);
1043 return_val_if_fail(rotation_angle >= 0, FALSE);
1045 if (rotation_angle >= 360)
1047 dest_angle = rotation_angle - 360;
1050 /* chech if supported or not */
1051 if ( dest_angle % 90 )
1053 debug_log("not supported rotation angle = %d", rotation_angle);
1058 * xvimagesink only (A)
1059 * custom_convert - no xv (e.g. memsink, evasimagesink (B)
1060 * videoflip - avsysmemsink (C)
1062 if (player->set_mode.video_zc)
1064 if (player->pipeline->videobin[MMPLAYER_V_CONV].gst) // B
1066 rotation_type = ROTATION_USING_CUSTOM;
1070 rotation_type = ROTATION_USING_SINK;
1075 int surface_type = 0;
1076 rotation_type = ROTATION_USING_FLIP;
1078 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1079 debug_log("check display surface type attribute: %d", surface_type);
1081 if ((surface_type == MM_DISPLAY_SURFACE_X) ||
1082 (surface_type == MM_DISPLAY_SURFACE_EVAS && !strcmp(player->ini.videosink_element_evas, "evaspixmapsink")))
1084 rotation_type = ROTATION_USING_SINK;
1088 rotation_type = ROTATION_USING_FLIP; //C
1091 debug_log("using %d type for rotation", rotation_type);
1094 /* get property value for setting */
1095 switch(rotation_type)
1097 case ROTATION_USING_SINK: // xvimagesink, pixmap
1104 pro_value = 3; // clockwise 90
1110 pro_value = 1; // counter-clockwise 90
1115 case ROTATION_USING_CUSTOM:
1117 gchar *ename = NULL;
1118 ename = GST_OBJECT_NAME(gst_element_get_factory(player->pipeline->videobin[MMPLAYER_V_CONV].gst));
1120 if (g_strrstr(ename, "fimcconvert"))
1127 pro_value = 90; // clockwise 90
1133 pro_value = 270; // counter-clockwise 90
1139 case ROTATION_USING_FLIP: // videoflip
1147 pro_value = 1; // clockwise 90
1153 pro_value = 3; // counter-clockwise 90
1160 debug_log("setting rotation property value : %d, used rotation type : %d", pro_value, rotation_type);
1168 _mmplayer_update_video_param(mm_player_t* player) // @
1170 MMHandleType attrs = 0;
1171 int surface_type = 0;
1172 int org_angle = 0; // current supported angle values are 0, 90, 180, 270
1174 int user_angle_type= 0;
1175 int rotation_value = 0;
1176 gchar *org_orient = NULL;
1180 /* check video sinkbin is created */
1181 return_val_if_fail ( player &&
1183 player->pipeline->videobin &&
1184 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
1185 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
1186 MM_ERROR_PLAYER_NOT_INITIALIZED );
1188 attrs = MMPLAYER_GET_ATTRS(player);
1191 debug_error("cannot get content attribute");
1192 return MM_ERROR_PLAYER_INTERNAL;
1195 /* update user roation */
1196 mm_attrs_get_int_by_name(attrs, "display_rotation", &user_angle_type);
1198 /* get angle with user type */
1199 switch(user_angle_type)
1201 case MM_DISPLAY_ROTATION_NONE:
1204 case MM_DISPLAY_ROTATION_90: // counter-clockwise 90
1207 case MM_DISPLAY_ROTATION_180:
1210 case MM_DISPLAY_ROTATION_270: // clockwise 90
1215 /* get original orientation */
1216 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1220 if (!strcmp (org_orient, "rotate-90"))
1222 else if (!strcmp (org_orient, "rotate-180"))
1224 else if (!strcmp (org_orient, "rotate-270"))
1227 debug_log ("original rotation is %s", org_orient);
1231 debug_log ("content_video_orientation get fail");
1234 debug_log("check user angle: %d, orientation: %d", user_angle, org_angle);
1236 /* check video stream callback is used */
1237 if(!player->set_mode.media_packet_video_stream && player->use_video_stream )
1239 if (player->set_mode.video_zc)
1241 gchar *ename = NULL;
1245 mm_attrs_get_int_by_name(attrs, "display_width", &width);
1246 mm_attrs_get_int_by_name(attrs, "display_height", &height);
1248 /* resize video frame with requested values for fimcconvert */
1249 ename = GST_OBJECT_NAME(gst_element_get_factory(player->pipeline->videobin[MMPLAYER_V_CONV].gst));
1251 if (ename && g_strrstr(ename, "fimcconvert"))
1254 g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "dst-width", width, NULL);
1257 g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "dst-height", height, NULL);
1259 /* NOTE: fimcconvert does not manage index of src buffer from upstream src-plugin, decoder gives frame information in output buffer with no ordering */
1260 g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "src-rand-idx", TRUE, NULL);
1262 /* get rotation value to set */
1263 __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
1265 g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "rotate", rotation_value, NULL);
1267 debug_log("updating fimcconvert - r[%d], w[%d], h[%d]", rotation_value, width, height);
1272 debug_log("using video stream callback with memsink. player handle : [%p]", player);
1274 /* get rotation value to set */
1275 __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
1277 g_object_set(player->pipeline->videobin[MMPLAYER_V_FLIP].gst, "method", rotation_value, NULL);
1280 return MM_ERROR_NONE;
1283 /* update display surface */
1284 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
1285 debug_log("check display surface type attribute: %d", surface_type);
1287 /* configuring display */
1288 switch ( surface_type )
1290 case MM_DISPLAY_SURFACE_X:
1292 /* ximagesink or xvimagesink */
1293 void *surface = NULL;
1294 int display_method = 0;
1303 int force_aspect_ratio = 0;
1304 gboolean visible = TRUE;
1308 void* wl_display = NULL;
1309 GstContext *context = NULL;
1310 int wl_window_x = 0;
1311 int wl_window_y = 0;
1312 int wl_window_width = 0;
1313 int wl_window_height = 0;
1315 mm_attrs_get_data_by_name(attrs, "wl_display", &wl_display);
1317 context = gst_wayland_display_handle_context_new(wl_display);
1319 gst_element_set_context(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), context);
1321 /*It should be set after setting window*/
1322 mm_attrs_get_int_by_name(attrs, "wl_window_render_x", &wl_window_x);
1323 mm_attrs_get_int_by_name(attrs, "wl_window_render_y", &wl_window_y);
1324 mm_attrs_get_int_by_name(attrs, "wl_window_render_width", &wl_window_width);
1325 mm_attrs_get_int_by_name(attrs, "wl_window_render_height", &wl_window_height);
1327 /* common case if using x surface */
1328 mm_attrs_get_data_by_name(attrs, "display_overlay", &surface);
1332 guintptr wl_surface = (guintptr)surface;
1333 debug_log("set video param : wayland surface %p", surface);
1334 gst_video_overlay_set_window_handle(
1335 GST_VIDEO_OVERLAY( player->pipeline->videobin[MMPLAYER_V_SINK].gst ),
1337 /* After setting window handle, set render rectangle */
1338 gst_video_overlay_set_render_rectangle(
1339 GST_VIDEO_OVERLAY( player->pipeline->videobin[MMPLAYER_V_SINK].gst ),
1340 wl_window_x,wl_window_y,wl_window_width,wl_window_height);
1343 xwin_id = *(int*)surface;
1344 debug_log("set video param : xid %p", *(int*)surface);
1347 gst_video_overlay_set_window_handle( GST_VIDEO_OVERLAY( player->pipeline->videobin[MMPLAYER_V_SINK].gst ), *(int*)surface );
1353 /* FIXIT : is it error case? */
1354 debug_warning("still we don't have xid on player attribute. create it's own surface.");
1357 /* if xvimagesink */
1358 if (!strcmp(player->ini.videosink_element_x,"xvimagesink"))
1360 mm_attrs_get_int_by_name(attrs, "display_force_aspect_ration", &force_aspect_ratio);
1361 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1362 mm_attrs_get_int_by_name(attrs, "display_src_crop_x", &src_crop_x);
1363 mm_attrs_get_int_by_name(attrs, "display_src_crop_y", &src_crop_y);
1364 mm_attrs_get_int_by_name(attrs, "display_src_crop_width", &src_crop_w);
1365 mm_attrs_get_int_by_name(attrs, "display_src_crop_height", &src_crop_h);
1366 mm_attrs_get_int_by_name(attrs, "display_roi_x", &roi_x);
1367 mm_attrs_get_int_by_name(attrs, "display_roi_y", &roi_y);
1368 mm_attrs_get_int_by_name(attrs, "display_roi_width", &roi_w);
1369 mm_attrs_get_int_by_name(attrs, "display_roi_height", &roi_h);
1370 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1371 #define DEFAULT_DISPLAY_MODE 2 // TV only, PRI_VIDEO_OFF_AND_SEC_VIDEO_FULL_SCREEN
1373 /* setting for cropping media source */
1374 if (src_crop_w && src_crop_h)
1376 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
1377 "src-crop-x", src_crop_x,
1378 "src-crop-y", src_crop_y,
1379 "src-crop-w", src_crop_w,
1380 "src-crop-h", src_crop_h,
1384 /* setting for ROI mode */
1385 if (display_method == 5) // 5 for ROI mode
1388 mm_attrs_get_int_by_name(attrs, "display_roi_mode", &roi_mode);
1389 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
1390 "dst-roi-mode", roi_mode,
1396 /* get rotation value to set,
1397 do not use org_angle because ROI mode in xvimagesink needs both a rotation value and an orientation value */
1398 __mmplayer_get_property_value_for_rotation(player, user_angle, &rotation_value);
1402 /* get rotation value to set */
1403 __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
1406 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
1407 "force-aspect-ratio", force_aspect_ratio,
1408 "orientation", org_angle/90, // setting for orientation of media, it is used for ROI/ZOOM feature in xvimagesink
1409 "rotate", rotation_value,
1410 "handle-events", TRUE,
1411 "display-geometry-method", display_method,
1412 "draw-borders", FALSE,
1413 "handle-expose", FALSE,
1415 "display-mode", DEFAULT_DISPLAY_MODE,
1418 debug_log("set video param : rotate %d, method %d visible %d", rotation_value, display_method, visible);
1419 debug_log("set video param : dst-roi-x: %d, dst-roi-y: %d, dst-roi-w: %d, dst-roi-h: %d", roi_x, roi_y, roi_w, roi_h );
1420 debug_log("set video param : force aspect ratio %d, display mode %d", force_aspect_ratio, DEFAULT_DISPLAY_MODE);
1424 case MM_DISPLAY_SURFACE_EVAS:
1426 void *object = NULL;
1428 gboolean visible = TRUE;
1429 int display_method = 0;
1431 /* common case if using evas surface */
1432 mm_attrs_get_data_by_name(attrs, "display_overlay", &object);
1433 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1434 mm_attrs_get_int_by_name(attrs, "display_evas_do_scaling", &scaling);
1435 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1437 /* if evasimagesink */
1438 if (!strcmp(player->ini.videosink_element_evas,"evasimagesink"))
1442 /* if it is evasimagesink, we are not supporting rotation */
1443 if (user_angle_type!=MM_DISPLAY_ROTATION_NONE)
1445 mm_attrs_set_int_by_name(attrs, "display_rotation", MM_DISPLAY_ROTATION_NONE);
1446 if (mmf_attrs_commit (attrs)) /* return -1 if error */
1447 debug_error("failed to commit\n");
1448 debug_warning("unsupported feature");
1449 return MM_ERROR_NOT_SUPPORT_API;
1451 __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
1452 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
1453 "evas-object", object,
1455 "display-geometry-method", display_method,
1456 "rotate", rotation_value,
1458 debug_log("set video param : method %d", display_method);
1459 debug_log("set video param : evas-object %x, visible %d", object, visible);
1460 debug_log("set video param : evas-object %x, rotate %d", object, rotation_value);
1464 debug_error("no evas object");
1465 return MM_ERROR_PLAYER_INTERNAL;
1469 /* if evasimagesink using converter */
1470 if (player->set_mode.video_zc && player->pipeline->videobin[MMPLAYER_V_CONV].gst)
1474 int no_scaling = !scaling;
1476 mm_attrs_get_int_by_name(attrs, "display_width", &width);
1477 mm_attrs_get_int_by_name(attrs, "display_height", &height);
1479 /* NOTE: fimcconvert does not manage index of src buffer from upstream src-plugin, decoder gives frame information in output buffer with no ordering */
1480 g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "src-rand-idx", TRUE, NULL);
1481 g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "dst-buffer-num", 5, NULL);
1485 /* no-scaling order to fimcconvert, original width, height size of media src will be passed to sink plugin */
1486 g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst,
1487 "dst-width", 0, /* setting 0, output video width will be media src's width */
1488 "dst-height", 0, /* setting 0, output video height will be media src's height */
1493 /* scaling order to fimcconvert */
1496 g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "dst-width", width, NULL);
1500 g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "dst-height", height, NULL);
1502 debug_log("set video param : video frame scaling down to width(%d) height(%d)", width, height);
1504 debug_log("set video param : display_evas_do_scaling %d", scaling);
1508 /* if evaspixmapsink */
1509 if (!strcmp(player->ini.videosink_element_evas,"evaspixmapsink"))
1513 __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
1514 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
1515 "evas-object", object,
1517 "display-geometry-method", display_method,
1518 "rotate", rotation_value,
1520 debug_log("set video param : method %d", display_method);
1521 debug_log("set video param : evas-object %x, visible %d", object, visible);
1522 debug_log("set video param : evas-object %x, rotate %d", object, rotation_value);
1526 debug_error("no evas object");
1527 return MM_ERROR_PLAYER_INTERNAL;
1530 int display_method = 0;
1535 int origin_size = !scaling;
1537 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1538 mm_attrs_get_int_by_name(attrs, "display_roi_x", &roi_x);
1539 mm_attrs_get_int_by_name(attrs, "display_roi_y", &roi_y);
1540 mm_attrs_get_int_by_name(attrs, "display_roi_width", &roi_w);
1541 mm_attrs_get_int_by_name(attrs, "display_roi_height", &roi_h);
1543 /* get rotation value to set */
1544 __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
1546 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
1547 "origin-size", origin_size,
1548 "rotate", rotation_value,
1553 "display-geometry-method", display_method,
1556 debug_log("set video param : method %d", display_method);
1557 debug_log("set video param : dst-roi-x: %d, dst-roi-y: %d, dst-roi-w: %d, dst-roi-h: %d",
1558 roi_x, roi_y, roi_w, roi_h );
1559 debug_log("set video param : display_evas_do_scaling %d (origin-size %d)", scaling, origin_size);
1563 case MM_DISPLAY_SURFACE_X_EXT: /* NOTE : this surface type is used for the videoTexture(canvasTexture) overlay */
1565 void *pixmap_id_cb = NULL;
1566 void *pixmap_id_cb_user_data = NULL;
1567 int display_method = 0;
1568 gboolean visible = TRUE;
1570 /* if xvimagesink */
1571 if (strcmp(player->ini.videosink_element_x,"xvimagesink"))
1573 debug_error("videosink is not xvimagesink");
1574 return MM_ERROR_PLAYER_INTERNAL;
1577 /* get information from attributes */
1578 mm_attrs_get_data_by_name(attrs, "display_overlay", &pixmap_id_cb);
1579 mm_attrs_get_data_by_name(attrs, "display_overlay_user_data", &pixmap_id_cb_user_data);
1580 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1581 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1585 debug_log("set video param : display_overlay(0x%x)", pixmap_id_cb);
1586 if (pixmap_id_cb_user_data)
1588 debug_log("set video param : display_overlay_user_data(0x%x)", pixmap_id_cb_user_data);
1593 debug_error("failed to set pixmap-id-callback");
1594 return MM_ERROR_PLAYER_INTERNAL;
1596 /* get rotation value to set */
1597 __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
1599 debug_log("set video param : rotate %d, method %d, visible %d", rotation_value, display_method, visible);
1601 /* set properties of videosink plugin */
1602 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
1603 "display-geometry-method", display_method,
1604 "draw-borders", FALSE,
1606 "rotate", rotation_value,
1607 "pixmap-id-callback", pixmap_id_cb,
1608 "pixmap-id-callback-userdata", pixmap_id_cb_user_data,
1612 case MM_DISPLAY_SURFACE_NULL:
1617 case MM_DISPLAY_SURFACE_REMOTE:
1626 return MM_ERROR_NONE;
1631 int _mmplayer_set_shm_stream_path(MMHandleType hplayer, const char *path)
1633 mm_player_t* player = (mm_player_t*) hplayer;
1638 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
1639 return_val_if_fail(path, MM_ERROR_INVALID_ARGUMENT);
1641 result = mm_attrs_set_string_by_name(player->attrs, "shm_stream_path", path)