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>, YoungHwan An <younghwan_.an@samsung.com>
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
22 /*===========================================================================================
26 ========================================================================================== */
29 #include <gst/app/gstappsrc.h>
30 #ifndef GST_API_VERSION_1
31 #include <gst/interfaces/xoverlay.h>
33 #include <gst/video/videooverlay.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_capture.h"
51 /*===========================================================================================
53 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
55 ========================================================================================== */
57 /*---------------------------------------------------------------------------
58 | GLOBAL CONSTANT DEFINITIONS: |
59 ---------------------------------------------------------------------------*/
61 /*---------------------------------------------------------------------------
62 | IMPORTED VARIABLE DECLARATIONS: |
63 ---------------------------------------------------------------------------*/
65 /*---------------------------------------------------------------------------
66 | IMPORTED FUNCTION DECLARATIONS: |
67 ---------------------------------------------------------------------------*/
69 /*---------------------------------------------------------------------------
71 ---------------------------------------------------------------------------*/
72 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
73 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
75 #define MM_VOLUME_FACTOR_DEFAULT 1.0
76 #define MM_VOLUME_FACTOR_MIN 0
77 #define MM_VOLUME_FACTOR_MAX 1.0
79 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 700000 // 700 msec
81 #define MM_PLAYER_MPEG_VNAME "mpegversion"
82 #define MM_PLAYER_DIVX_VNAME "divxversion"
83 #define MM_PLAYER_WMV_VNAME "wmvversion"
84 #define MM_PLAYER_WMA_VNAME "wmaversion"
86 #define DEFAULT_PLAYBACK_RATE 1.0
88 #define GST_QUEUE_DEFAULT_TIME 8
89 #define GST_QUEUE_HLS_TIME 8
91 /* video capture callback*/
92 gulong ahs_appsrc_cb_probe_id = 0;
94 #define MMPLAYER_USE_FILE_FOR_BUFFERING(player) (((player)->profile.uri_type != MM_PLAYER_URI_TYPE_HLS) && (PLAYER_INI()->http_file_buffer_path) && (strlen(PLAYER_INI()->http_file_buffer_path) > 0) )
96 #define LAZY_PAUSE_TIMEOUT_MSEC 700
98 /*---------------------------------------------------------------------------
99 | LOCAL CONSTANT DEFINITIONS: |
100 ---------------------------------------------------------------------------*/
102 /*---------------------------------------------------------------------------
103 | LOCAL DATA TYPE DEFINITIONS: |
104 ---------------------------------------------------------------------------*/
106 /*---------------------------------------------------------------------------
107 | GLOBAL VARIABLE DEFINITIONS: |
108 ---------------------------------------------------------------------------*/
110 /*---------------------------------------------------------------------------
111 | LOCAL VARIABLE DEFINITIONS: |
112 ---------------------------------------------------------------------------*/
114 /*---------------------------------------------------------------------------
115 | LOCAL FUNCTION PROTOTYPES: |
116 ---------------------------------------------------------------------------*/
117 static gboolean __mmplayer_set_state(mm_player_t* player, int state);
118 static int __mmplayer_get_state(mm_player_t* player);
119 static int __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps *caps, MMDisplaySurfaceType surface_type);
120 static int __mmplayer_gst_create_audio_pipeline(mm_player_t* player);
121 static int __mmplayer_gst_create_text_pipeline(mm_player_t* player);
122 static int __mmplayer_gst_create_subtitle_src(mm_player_t* player);
123 static int __mmplayer_gst_create_pipeline(mm_player_t* player);
124 static int __mmplayer_gst_destroy_pipeline(mm_player_t* player);
125 static int __mmplayer_gst_element_link_bucket(GList* element_bucket);
127 static gboolean __mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data);
128 static void __mmplayer_gst_decode_callback(GstElement *decodebin, GstPad *pad, gboolean last, gpointer data);
130 static void __mmplayer_typefind_have_type( GstElement *tf, guint probability, GstCaps *caps, gpointer data);
131 static gboolean __mmplayer_try_to_plug(mm_player_t* player, GstPad *pad, const GstCaps *caps);
132 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
133 static gboolean __mmplayer_is_midi_type(gchar* str_caps);
134 static gboolean __mmplayer_is_amr_type (gchar *str_caps);
135 static gboolean __mmplayer_is_only_mp3_type (gchar *str_caps);
137 static gboolean __mmplayer_close_link(mm_player_t* player, GstPad *srcpad, GstElement *sinkelement, const char *padname, const GList *templlist);
138 static gboolean __mmplayer_feature_filter(GstPluginFeature *feature, gpointer data);
139 static void __mmplayer_add_new_pad(GstElement *element, GstPad *pad, gpointer data);
141 static void __mmplayer_gst_rtp_no_more_pads (GstElement *element, gpointer data);
142 static void __mmplayer_gst_rtp_dynamic_pad (GstElement *element, GstPad *pad, gpointer data);
143 static gboolean __mmplayer_get_stream_service_type( mm_player_t* player );
144 static gboolean __mmplayer_update_subtitle( GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
147 static void __mmplayer_init_factories(mm_player_t* player);
148 static void __mmplayer_release_factories(mm_player_t* player);
149 static void __mmplayer_release_misc(mm_player_t* player);
150 static gboolean __mmplayer_gstreamer_init(void);
152 static int __mmplayer_gst_set_state (mm_player_t* player, GstElement * pipeline, GstState state, gboolean async, gint timeout );
153 gboolean __mmplayer_post_message(mm_player_t* player, enum MMMessageType msgtype, MMMessageParamType* param);
154 static gboolean __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage *msg);
155 static gboolean __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg);
157 int __mmplayer_switch_audio_sink (mm_player_t* player);
158 static gboolean __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink);
159 static int __mmplayer_check_state(mm_player_t* player, enum PlayerCommandState command);
160 static gboolean __mmplayer_audio_stream_probe (GstPad *pad, GstBuffer *buffer, gpointer u_data);
162 static gboolean __mmplayer_dump_pipeline_state( mm_player_t* player );
163 static gboolean __mmplayer_check_subtitle( mm_player_t* player );
164 static gboolean __mmplayer_handle_gst_error ( mm_player_t* player, GstMessage * message, GError* error );
165 static gboolean __mmplayer_handle_streaming_error ( mm_player_t* player, GstMessage * message );
166 static void __mmplayer_post_delayed_eos( mm_player_t* player, int delay_in_ms );
167 static void __mmplayer_cancel_delayed_eos( mm_player_t* player );
168 static gboolean __mmplayer_eos_timer_cb(gpointer u_data);
169 static gboolean __mmplayer_link_decoder( mm_player_t* player,GstPad *srcpad);
170 static gboolean __mmplayer_link_sink( mm_player_t* player,GstPad *srcpad);
171 static int __mmplayer_handle_missed_plugin(mm_player_t* player);
172 static int __mmplayer_check_not_supported_codec(mm_player_t* player, gchar* mime);
173 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player);
174 static void __mmplayer_add_sink( mm_player_t* player, GstElement* sink);
175 static void __mmplayer_del_sink( mm_player_t* player, GstElement* sink);
176 static void __mmplayer_release_signal_connection(mm_player_t* player);
177 static void __mmplayer_set_antishock( mm_player_t* player, gboolean disable_by_force);
178 static gpointer __mmplayer_repeat_thread(gpointer data);
179 int _mmplayer_get_track_count(MMHandleType hplayer, MMPlayerTrackType track_type, int *count);
180 static gboolean _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag);
183 static int __gst_realize(mm_player_t* player);
184 static int __gst_unrealize(mm_player_t* player);
185 static int __gst_start(mm_player_t* player);
186 static int __gst_stop(mm_player_t* player);
187 static int __gst_pause(mm_player_t* player, gboolean async);
188 static int __gst_resume(mm_player_t* player, gboolean async);
189 static gboolean __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
190 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
191 gint64 cur, GstSeekType stop_type, gint64 stop );
192 static int __gst_pending_seek ( mm_player_t* player );
194 static int __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called);
195 static int __gst_get_position(mm_player_t* player, int format, unsigned long *position);
196 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos);
197 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position);
198 static int __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param);
199 static void __gst_set_async_state_change(mm_player_t* player, gboolean async);
201 static gint __gst_handle_core_error( mm_player_t* player, int code );
202 static gint __gst_handle_library_error( mm_player_t* player, int code );
203 static gint __gst_handle_resource_error( mm_player_t* player, int code );
204 static gint __gst_handle_stream_error( mm_player_t* player, GError* error, GstMessage * message );
205 static gint __gst_transform_gsterror( mm_player_t* player, GstMessage * message, GError* error);
206 static gboolean __gst_send_event_to_sink( mm_player_t* player, GstEvent* event );
208 static int __mmplayer_set_pcm_extraction(mm_player_t* player);
209 static gboolean __mmplayer_can_extract_pcm( mm_player_t* player );
212 static void __mmplayer_do_sound_fadedown(mm_player_t* player, unsigned int time);
213 static void __mmplayer_undo_sound_fadedown(mm_player_t* player);
215 static void __mmplayer_add_new_caps(GstPad* pad, GParamSpec* unused, gpointer data);
216 static void __mmplayer_set_unlinked_mime_type(mm_player_t* player, GstCaps *caps);
219 const gchar * __get_state_name ( int state );
220 static gboolean __is_streaming( mm_player_t* player );
221 static gboolean __is_rtsp_streaming( mm_player_t* player );
222 static gboolean __is_live_streaming ( mm_player_t* player );
223 static gboolean __is_http_streaming( mm_player_t* player );
224 static gboolean __is_http_live_streaming( mm_player_t* player );
225 static gboolean __is_http_progressive_down(mm_player_t* player);
227 static gboolean __mmplayer_warm_up_video_codec( mm_player_t* player, GstElementFactory *factory);
228 static GstBusSyncReply __mmplayer_bus_sync_callback (GstBus * bus, GstMessage * message, gpointer data);
230 static int __mmplayer_realize_streaming_ext(mm_player_t* player);
231 static int __mmplayer_unrealize_streaming_ext(mm_player_t *player);
232 static int __mmplayer_start_streaming_ext(mm_player_t *player);
233 static int __mmplayer_destroy_streaming_ext(mm_player_t* player);
236 /*===========================================================================================
238 | FUNCTION DEFINITIONS |
240 ========================================================================================== */
242 /* implementing player FSM */
243 /* FIXIT : We need to handle state transition also at here since start api is no more sync */
245 __mmplayer_check_state(mm_player_t* player, enum PlayerCommandState command)
247 MMPlayerStateType current_state = MM_PLAYER_STATE_NUM;
248 MMPlayerStateType pending_state = MM_PLAYER_STATE_NUM;
249 MMPlayerStateType target_state = MM_PLAYER_STATE_NUM;
250 MMPlayerStateType prev_state = MM_PLAYER_STATE_NUM;
254 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
256 //debug_log("incomming command : %d \n", command );
258 current_state = MMPLAYER_CURRENT_STATE(player);
259 pending_state = MMPLAYER_PENDING_STATE(player);
260 target_state = MMPLAYER_TARGET_STATE(player);
261 prev_state = MMPLAYER_PREV_STATE(player);
263 MMPLAYER_PRINT_STATE(player);
267 case MMPLAYER_COMMAND_CREATE:
269 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
271 if ( current_state == MM_PLAYER_STATE_NULL ||
272 current_state == MM_PLAYER_STATE_READY ||
273 current_state == MM_PLAYER_STATE_PAUSED ||
274 current_state == MM_PLAYER_STATE_PLAYING )
279 case MMPLAYER_COMMAND_DESTROY:
281 /* destroy can called anytime */
283 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
287 case MMPLAYER_COMMAND_REALIZE:
289 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
291 if ( pending_state != MM_PLAYER_STATE_NONE )
297 /* need ready state to realize */
298 if ( current_state == MM_PLAYER_STATE_READY )
301 if ( current_state != MM_PLAYER_STATE_NULL )
307 case MMPLAYER_COMMAND_UNREALIZE:
309 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
311 if ( current_state == MM_PLAYER_STATE_NULL )
316 case MMPLAYER_COMMAND_START:
318 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
320 if ( pending_state == MM_PLAYER_STATE_NONE )
322 if ( current_state == MM_PLAYER_STATE_PLAYING )
324 else if ( current_state != MM_PLAYER_STATE_READY &&
325 current_state != MM_PLAYER_STATE_PAUSED )
328 else if ( pending_state == MM_PLAYER_STATE_PLAYING )
332 else if ( pending_state == MM_PLAYER_STATE_PAUSED )
334 debug_log("player is going to paused state, just change the pending state as playing");
343 case MMPLAYER_COMMAND_STOP:
345 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
347 if ( current_state == MM_PLAYER_STATE_READY )
350 /* need playing/paused state to stop */
351 if ( current_state != MM_PLAYER_STATE_PLAYING &&
352 current_state != MM_PLAYER_STATE_PAUSED )
357 case MMPLAYER_COMMAND_PAUSE:
359 if ( MMPLAYER_IS_LIVE_STREAMING( player ) )
362 if (player->doing_seek)
363 goto NOT_COMPLETED_SEEK;
365 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
367 if ( pending_state == MM_PLAYER_STATE_NONE )
369 if ( current_state == MM_PLAYER_STATE_PAUSED )
371 else if ( current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY ) // support loading state of broswer
374 else if ( pending_state == MM_PLAYER_STATE_PAUSED )
378 else if ( pending_state == MM_PLAYER_STATE_PLAYING )
380 if ( current_state == MM_PLAYER_STATE_PAUSED ) {
381 debug_log("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
389 case MMPLAYER_COMMAND_RESUME:
391 if ( MMPLAYER_IS_LIVE_STREAMING(player) )
394 if (player->doing_seek)
395 goto NOT_COMPLETED_SEEK;
397 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
399 if ( pending_state == MM_PLAYER_STATE_NONE )
401 if ( current_state == MM_PLAYER_STATE_PLAYING )
403 else if ( current_state != MM_PLAYER_STATE_PAUSED )
406 else if ( pending_state == MM_PLAYER_STATE_PLAYING )
410 else if ( pending_state == MM_PLAYER_STATE_PAUSED )
412 debug_log("player is going to paused state, just change the pending state as playing");
424 player->cmd = command;
427 return MM_ERROR_NONE;
430 debug_warning("since player is in wrong state(%s). it's not able to apply the command(%d)",
431 MMPLAYER_STATE_GET_NAME(current_state), command);
432 return MM_ERROR_PLAYER_INVALID_STATE;
435 debug_warning("not completed seek");
436 return MM_ERROR_PLAYER_DOING_SEEK;
439 debug_warning("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
440 return MM_ERROR_PLAYER_NO_OP;
443 debug_warning("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
444 return MM_ERROR_PLAYER_NO_OP;
448 __mmplayer_gst_set_state (mm_player_t* player, GstElement * element, GstState state, gboolean async, gint timeout) // @
450 GstState element_state = GST_STATE_VOID_PENDING;
451 GstState element_pending_state = GST_STATE_VOID_PENDING;
452 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
456 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
457 return_val_if_fail ( element, MM_ERROR_INVALID_ARGUMENT );
459 debug_log("setting [%s] element state to : %d\n", GST_ELEMENT_NAME(element), state);
462 ret = gst_element_set_state(element, state);
464 if ( ret == GST_STATE_CHANGE_FAILURE )
466 debug_error("failed to set [%s] state to [%d]\n", GST_ELEMENT_NAME(element), state);
468 /* dump state of all element */
469 __mmplayer_dump_pipeline_state( player );
471 return MM_ERROR_PLAYER_INTERNAL;
474 /* return here so state transition to be done in async mode */
477 debug_log("async state transition. not waiting for state complete.\n");
478 return MM_ERROR_NONE;
481 /* wait for state transition */
482 ret = gst_element_get_state( element, &element_state, &element_pending_state, timeout * GST_SECOND );
484 if ( ret == GST_STATE_CHANGE_FAILURE || ( state != element_state ) )
486 debug_error("failed to change [%s] element state to [%s] within %d sec\n",
487 GST_ELEMENT_NAME(element),
488 gst_element_state_get_name(state), timeout );
490 debug_error(" [%s] state : %s pending : %s \n",
491 GST_ELEMENT_NAME(element),
492 gst_element_state_get_name(element_state),
493 gst_element_state_get_name(element_pending_state) );
495 /* dump state of all element */
496 __mmplayer_dump_pipeline_state( player );
498 return MM_ERROR_PLAYER_INTERNAL;
501 debug_log("[%s] element state has changed to %s \n",
502 GST_ELEMENT_NAME(element),
503 gst_element_state_get_name(element_state));
507 return MM_ERROR_NONE;
511 __mmplayer_videostream_cb(GstElement *element, void *stream,
512 int width, int height, gpointer data) // @
514 mm_player_t* player = (mm_player_t*)data;
517 return_if_fail ( player );
521 if (player->video_stream_cb )
523 length = width * height * 4; // for rgb 32bit
524 player->video_stream_cb(stream, length, player->video_stream_cb_user_param, width, height);
531 __mmplayer_videoframe_render_error_cb(GstElement *element, void *error_id, gpointer data)
533 mm_player_t* player = (mm_player_t*)data;
535 return_if_fail ( player );
539 if (player->video_frame_render_error_cb )
543 int surface_type = 0;
544 mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &surface_type);
545 switch (surface_type)
547 case MM_DISPLAY_SURFACE_X_EXT:
548 player->video_frame_render_error_cb((unsigned int*)error_id, player->video_frame_render_error_cb_user_param);
549 debug_log("display surface type(X_EXT) : render error callback(%p) is finished", player->video_frame_render_error_cb);
552 debug_error("video_frame_render_error_cb was set, but this surface type(%d) is not supported", surface_type);
558 debug_error("could not get surface type");
563 debug_warning("video_frame_render_error_cb was not set");
569 /* This function should be called after the pipeline goes PAUSED or higher
572 _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag) // @
574 static gboolean has_duration = FALSE;
575 static gboolean has_video_attrs = FALSE;
576 static gboolean has_audio_attrs = FALSE;
577 static gboolean has_bitrate = FALSE;
578 gboolean missing_only = FALSE;
579 gboolean all = FALSE;
581 #ifndef GST_API_VERSION_1
582 GstFormat fmt = GST_FORMAT_TIME;
585 GstStructure* p = NULL;
586 MMHandleType attrs = 0;
588 gint stream_service_type = STREAMING_SERVICE_NONE;
593 return_val_if_fail ( player, FALSE );
595 /* check player state here */
596 if ( MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
597 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING )
599 /* give warning now only */
600 debug_warning("be careful. content attributes may not available in this state ");
603 /* get content attribute first */
604 attrs = MMPLAYER_GET_ATTRS(player);
607 debug_error("cannot get content attribute");
611 /* get update flag */
613 if ( flag & ATTR_MISSING_ONLY )
616 debug_log("updating missed attr only");
619 if ( flag & ATTR_ALL )
622 has_duration = FALSE;
623 has_video_attrs = FALSE;
624 has_audio_attrs = FALSE;
627 debug_log("updating all attrs");
630 if ( missing_only && all )
632 debug_warning("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
633 missing_only = FALSE;
636 if ( (flag & ATTR_DURATION) || (!has_duration && missing_only) || all )
638 debug_log("try to update duration");
639 has_duration = FALSE;
641 #ifdef GST_API_VERSION_1
642 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec ))
644 player->duration = dur_nsec;
645 debug_log("duration : %lld msec", GST_TIME_AS_MSECONDS(dur_nsec));
648 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &fmt, &dur_nsec ))
650 player->duration = dur_nsec;
651 debug_log("duration : %lld msec", GST_TIME_AS_MSECONDS(dur_nsec));
655 /* try to get streaming service type */
656 stream_service_type = __mmplayer_get_stream_service_type( player );
657 mm_attrs_set_int_by_name ( attrs, "streaming_type", stream_service_type );
659 /* check duration is OK */
660 if ( dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING( player ) )
662 debug_error("not ready to get duration");
667 mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(dur_nsec));
669 debug_log("duration updated");
673 if ( (flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all )
675 /* update audio params
676 NOTE : We need original audio params and it can be only obtained from src pad of audio
677 decoder. Below code only valid when we are not using 'resampler' just before
680 debug_log("try to update audio attrs");
681 has_audio_attrs = FALSE;
683 if ( player->pipeline->audiobin &&
684 player->pipeline->audiobin[MMPLAYER_A_SINK].gst )
686 GstCaps *caps_a = NULL;
688 gint samplerate = 0, channels = 0;
690 pad = gst_element_get_static_pad(
691 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink" );
695 #ifdef GST_API_VERSION_1
696 caps_a = gst_pad_get_current_caps( pad );
698 caps_a = gst_pad_get_negotiated_caps( pad );
703 p = gst_caps_get_structure (caps_a, 0);
705 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
707 gst_structure_get_int (p, "rate", &samplerate);
708 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
710 gst_structure_get_int (p, "channels", &channels);
711 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
713 debug_log("samplerate : %d channels : %d", samplerate, channels);
715 gst_caps_unref( caps_a );
718 has_audio_attrs = TRUE;
722 debug_warning("not ready to get audio caps");
725 gst_object_unref( pad );
729 debug_warning("failed to get pad from audiosink");
734 if ( (flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all )
736 debug_log("try to update video attrs");
737 has_video_attrs = FALSE;
739 if ( player->pipeline->videobin &&
740 player->pipeline->videobin[MMPLAYER_V_SINK].gst )
742 GstCaps *caps_v = NULL;
747 pad = gst_element_get_static_pad( player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink" );
750 #ifdef GST_API_VERSION_1
751 caps_v = gst_pad_get_current_caps( pad );
753 caps_v = gst_pad_get_negotiated_caps( pad );
757 p = gst_caps_get_structure (caps_v, 0);
758 gst_structure_get_int (p, "width", &width);
759 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
761 gst_structure_get_int (p, "height", &height);
762 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
764 gst_structure_get_fraction (p, "framerate", &tmpNu, &tmpDe);
766 debug_log("width : %d height : %d", width, height );
768 gst_caps_unref( caps_v );
773 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
774 debug_log("fps : %d", tmpNu / tmpDe);
777 has_video_attrs = TRUE;
781 debug_log("no negitiated caps from videosink");
783 gst_object_unref( pad );
788 debug_log("no videosink sink pad");
794 if ( (flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all )
796 debug_log("try to update bitrate");
799 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
800 if (player->duration)
802 guint64 data_size = 0;
804 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO))
806 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
808 if (stat(path, &sb) == 0)
810 data_size = (guint64)sb.st_size;
813 else if (MMPLAYER_IS_HTTP_STREAMING(player))
815 data_size = player->http_content_size;
821 guint64 msec_dur = 0;
823 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
824 bitrate = data_size * 8 * 1000 / msec_dur;
825 debug_log("file size : %u, video bitrate = %llu", data_size, bitrate);
826 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
834 if ( mmf_attrs_commit ( attrs ) )
836 debug_error("failed to update attributes\n");
844 gint __mmplayer_get_stream_service_type( mm_player_t* player )
846 gint streaming_type = STREAMING_SERVICE_NONE;
850 return_val_if_fail ( player &&
852 player->pipeline->mainbin &&
853 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
856 /* streaming service type if streaming */
857 if ( ! MMPLAYER_IS_STREAMING(player) )
859 debug_log("not a streamming");
860 return STREAMING_SERVICE_NONE;
863 if (MMPLAYER_IS_RTSP_STREAMING(player))
865 /* get property from rtspsrc element */
866 g_object_get(G_OBJECT(player->pipeline->mainbin[MMPLAYER_M_SRC].gst),
867 "service_type", &streaming_type, NULL);
869 else if (MMPLAYER_IS_HTTP_STREAMING(player))
871 streaming_type = player->duration == 0 ?
872 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
875 switch ( streaming_type )
877 case STREAMING_SERVICE_LIVE:
878 debug_log("it's live streaming");
880 case STREAMING_SERVICE_VOD:
881 debug_log("it's vod streaming");
883 case STREAMING_SERVICE_NONE:
884 debug_error("should not get here");
887 debug_error("should not get here");
890 player->streaming_type = streaming_type;
893 return streaming_type;
897 /* this function sets the player state and also report
898 * it to applicaton by calling callback function
901 __mmplayer_set_state(mm_player_t* player, int state) // @
903 MMMessageParamType msg = {0, };
904 int asm_result = MM_ERROR_NONE;
905 gboolean post_bos = FALSE;
906 gboolean interrupted_by_asm = FALSE;
909 return_val_if_fail ( player, FALSE );
911 if ( MMPLAYER_CURRENT_STATE(player) == state )
913 debug_warning("already same state(%s)\n", MMPLAYER_STATE_GET_NAME(state));
914 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
918 /* update player states */
919 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
920 MMPLAYER_CURRENT_STATE(player) = state;
922 /* FIXIT : it's better to do like below code
923 if ( MMPLAYER_CURRENT_STATE(player) == MMPLAYER_TARGET_STATE(player) )
924 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
925 and add more code to handling PENDING_STATE.
927 if ( MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player) )
928 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
931 MMPLAYER_PRINT_STATE(player);
933 /* do some FSM stuffs before posting new state to application */
934 interrupted_by_asm = player->sm.by_asm_cb;
936 switch ( MMPLAYER_CURRENT_STATE(player) )
938 case MM_PLAYER_STATE_NULL:
939 case MM_PLAYER_STATE_READY:
941 if (player->cmd == MMPLAYER_COMMAND_STOP)
943 asm_result = _mmplayer_asm_set_state((MMHandleType)player, ASM_STATE_STOP);
944 if ( asm_result != MM_ERROR_NONE )
946 debug_error("failed to set asm state to stop\n");
953 case MM_PLAYER_STATE_PAUSED:
955 if ( ! player->sent_bos )
957 /* it's first time to update all content attrs. */
958 _mmplayer_update_content_attrs( player, ATTR_ALL );
961 /* add audio callback probe if condition is satisfied */
962 if ( ! player->audio_cb_probe_id && player->is_sound_extraction )
964 __mmplayer_configure_audio_callback(player);
967 asm_result = _mmplayer_asm_set_state((MMHandleType)player, ASM_STATE_PAUSE);
970 debug_error("failed to set asm state to PAUSE\n");
976 case MM_PLAYER_STATE_PLAYING:
978 /* try to get content metadata */
979 if ( ! player->sent_bos )
981 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
982 * c-api since c-api doesn't use _start() anymore. It may not work propery with
983 * legacy mmfw-player api */
984 _mmplayer_update_content_attrs( player, ATTR_MISSING_ONLY);
987 if ( player->cmd == MMPLAYER_COMMAND_START && !player->sent_bos )
989 __mmplayer_handle_missed_plugin ( player );
991 /* update video resource status */
992 if ( ( player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO )
994 asm_result = _mmplayer_asm_set_state((MMHandleType)player, ASM_STATE_PLAYING);
997 MMMessageParamType msg = {0, };
999 debug_error("failed to go ahead because of video conflict\n");
1001 msg.union_type = MM_MSG_UNION_CODE;
1002 msg.code = MM_ERROR_POLICY_INTERRUPTED;
1003 MMPLAYER_POST_MSG( player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
1005 _mmplayer_unrealize((MMHandleType)player);
1012 if ( player->resumed_by_rewind && player->playback_rate < 0.0 )
1014 /* initialize because auto resume is done well. */
1015 player->resumed_by_rewind = FALSE;
1016 player->playback_rate = 1.0;
1019 if ( !player->sent_bos )
1021 /* check audio codec field is set or not
1022 * we can get it from typefinder or codec's caps.
1024 gchar *audio_codec = NULL;
1025 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
1027 /* The codec format can't be sent for audio only case like amr, mid etc.
1028 * Because, parser don't make related TAG.
1029 * So, if it's not set yet, fill it with found data.
1031 if ( ! audio_codec )
1033 if ( g_strrstr(player->type, "audio/midi"))
1035 audio_codec = g_strdup("MIDI");
1038 else if ( g_strrstr(player->type, "audio/x-amr"))
1040 audio_codec = g_strdup("AMR");
1042 else if ( g_strrstr(player->type, "audio/mpeg") && !g_strrstr(player->type, "mpegversion=(int)1"))
1044 audio_codec = g_strdup("AAC");
1048 audio_codec = g_strdup("unknown");
1050 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
1052 MMPLAYER_FREEIF(audio_codec);
1053 mmf_attrs_commit(player->attrs);
1054 debug_log("set audio codec type with caps\n");
1062 case MM_PLAYER_STATE_NONE:
1064 debug_warning("invalid target state, there is nothing to do.\n");
1069 /* post message to application */
1070 if (MMPLAYER_TARGET_STATE(player) == state)
1072 /* fill the message with state of player */
1073 msg.state.previous = MMPLAYER_PREV_STATE(player);
1074 msg.state.current = MMPLAYER_CURRENT_STATE(player);
1076 /* state changed by asm callback */
1077 if ( interrupted_by_asm )
1079 msg.union_type = MM_MSG_UNION_CODE;
1080 msg.code = player->sm.event_src;
1081 MMPLAYER_POST_MSG( player, MM_MESSAGE_STATE_INTERRUPTED, &msg );
1083 /* state changed by usecase */
1086 MMPLAYER_POST_MSG( player, MM_MESSAGE_STATE_CHANGED, &msg );
1089 debug_log ("player reach the target state, then do something in each state(%s).\n",
1090 MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
1094 debug_log ("intermediate state, do nothing.\n");
1095 MMPLAYER_PRINT_STATE(player);
1101 MMTA_ACUM_ITEM_END("[KPI] start media player service", FALSE);
1102 MMTA_ACUM_ITEM_END("[KPI] media player service create->playing", FALSE);
1104 MMPLAYER_POST_MSG ( player, MM_MESSAGE_BEGIN_OF_STREAM, NULL );
1105 player->sent_bos = TRUE;
1114 __mmplayer_post_message(mm_player_t* player, enum MMMessageType msgtype, MMMessageParamType* param) // @
1116 return_val_if_fail( player, FALSE );
1120 if ( !player->msg_cb )
1122 debug_warning("no msg callback. can't post msg now\n");
1126 //debug_log("Message (type : %d) will be posted using msg-cb(%p). \n", msgtype, player->msg_cb);
1128 player->msg_cb(msgtype, param, player->msg_cb_param);
1137 __mmplayer_get_state(mm_player_t* player) // @
1139 int state = MM_PLAYER_STATE_NONE;
1143 return_val_if_fail ( player, MM_PLAYER_STATE_NONE );
1145 state = MMPLAYER_CURRENT_STATE(player);
1147 debug_log("player state is %s.\n", MMPLAYER_STATE_GET_NAME(state));
1155 __gst_set_async_state_change(mm_player_t* player, gboolean async)
1158 return_if_fail( player && player->pipeline && player->pipeline->mainbin );
1160 /* need only when we are using decodebin */
1161 if ( ! PLAYER_INI()->use_decodebin )
1165 if ( player->pipeline->audiobin &&
1166 player->pipeline->audiobin[MMPLAYER_A_SINK].gst )
1168 debug_log("audiosink async : %d\n", async);
1169 g_object_set (G_OBJECT (player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "async", async, NULL);
1173 if ( player->pipeline->videobin &&
1174 player->pipeline->videobin[MMPLAYER_V_SINK].gst )
1176 debug_log("videosink async : %d\n", async);
1177 g_object_set (G_OBJECT (player->pipeline->videobin[MMPLAYER_V_SINK].gst), "async", async, NULL);
1180 /* decodebin if enabled */
1181 if ( PLAYER_INI()->use_decodebin )
1183 debug_log("decodebin async : %d\n", async);
1184 g_object_set (G_OBJECT (player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst), "async-handling", async, NULL);
1190 static gpointer __mmplayer_repeat_thread(gpointer data)
1192 mm_player_t* player = (mm_player_t*) data;
1193 gboolean ret_value = FALSE;
1194 MMHandleType attrs = 0;
1197 return_val_if_fail ( player, NULL );
1199 while ( ! player->repeat_thread_exit )
1201 debug_log("repeat thread started. waiting for signal.\n");
1202 g_cond_wait( player->repeat_thread_cond, player->repeat_thread_mutex );
1204 if ( player->repeat_thread_exit )
1206 debug_log("exiting repeat thread\n");
1210 if ( !player->cmd_lock )
1212 debug_log("can't get cmd lock\n");
1217 g_mutex_lock(player->cmd_lock);
1219 attrs = MMPLAYER_GET_ATTRS(player);
1221 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
1223 debug_error("can not get play count\n");
1227 if ( player->section_repeat )
1229 ret_value = _mmplayer_activate_section_repeat((MMHandleType)player, player->section_repeat_start, player->section_repeat_end);
1233 if ( player->playback_rate < 0.0 )
1235 player->resumed_by_rewind = TRUE;
1236 _mmplayer_set_mute((MMHandleType)player, 0);
1237 MMPLAYER_POST_MSG( player, MM_MESSAGE_RESUMED_BY_REW, NULL );
1240 ret_value = __gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
1241 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET,
1242 0, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
1245 player->sent_bos = FALSE;
1250 debug_error("failed to set position to zero for rewind\n");
1254 /* decrease play count */
1257 /* we successeded to rewind. update play count and then wait for next EOS */
1260 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
1262 /* commit attribute */
1263 if ( mmf_attrs_commit ( attrs ) )
1265 debug_error("failed to commit attribute\n");
1270 g_mutex_unlock(player->cmd_lock);
1277 __mmplayer_handle_buffering_message ( mm_player_t* player )
1279 MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
1280 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
1281 MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
1282 MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
1284 return_if_fail ( player );
1286 prev_state = MMPLAYER_PREV_STATE(player),
1287 current_state = MMPLAYER_CURRENT_STATE(player);
1288 target_state = MMPLAYER_TARGET_STATE(player);
1289 pending_state = MMPLAYER_PENDING_STATE(player);
1291 if ( MMPLAYER_IS_RTSP_STREAMING(player) )
1294 if ( !player->streamer->is_buffering )
1296 debug_log( "player state : prev %s, current %s, pending %s, target %s \n",
1297 MMPLAYER_STATE_GET_NAME(prev_state),
1298 MMPLAYER_STATE_GET_NAME(current_state),
1299 MMPLAYER_STATE_GET_NAME(pending_state),
1300 MMPLAYER_STATE_GET_NAME(target_state));
1302 /* NOTE : if buffering has done, player has to go to target state. */
1303 switch ( target_state )
1305 case MM_PLAYER_STATE_PAUSED :
1307 switch ( pending_state )
1309 case MM_PLAYER_STATE_PLAYING:
1311 __gst_pause ( player, TRUE );
1315 case MM_PLAYER_STATE_PAUSED:
1317 debug_log("player is already going to paused state, there is nothing to do.\n");
1321 case MM_PLAYER_STATE_NONE:
1322 case MM_PLAYER_STATE_NULL:
1323 case MM_PLAYER_STATE_READY:
1326 debug_warning("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state) );
1333 case MM_PLAYER_STATE_PLAYING :
1335 switch ( pending_state )
1337 case MM_PLAYER_STATE_NONE:
1339 if (current_state != MM_PLAYER_STATE_PLAYING)
1340 __gst_resume ( player, TRUE );
1344 case MM_PLAYER_STATE_PAUSED:
1346 /* NOTE: It should be worked as asynchronously.
1347 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
1349 __gst_resume ( player, TRUE );
1353 case MM_PLAYER_STATE_PLAYING:
1355 debug_log("player is already going to playing state, there is nothing to do.\n");
1359 case MM_PLAYER_STATE_NULL:
1360 case MM_PLAYER_STATE_READY:
1363 debug_warning("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state) );
1370 case MM_PLAYER_STATE_NULL :
1371 case MM_PLAYER_STATE_READY :
1372 case MM_PLAYER_STATE_NONE :
1375 debug_warning("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state) );
1382 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1383 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
1385 switch ( pending_state )
1387 case MM_PLAYER_STATE_NONE:
1389 if (current_state != MM_PLAYER_STATE_PAUSED)
1390 __gst_pause ( player, TRUE );
1394 case MM_PLAYER_STATE_PLAYING:
1396 __gst_pause ( player, TRUE );
1400 case MM_PLAYER_STATE_PAUSED:
1402 debug_log("player is already going to paused state, there is nothing to do.\n");
1406 case MM_PLAYER_STATE_NULL:
1407 case MM_PLAYER_STATE_READY:
1410 debug_warning("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state) );
1418 __mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data) // @
1420 mm_player_t* player = (mm_player_t*) data;
1421 gboolean ret = TRUE;
1422 static gboolean async_done = FALSE;
1424 return_val_if_fail ( player, FALSE );
1425 return_val_if_fail ( msg && GST_IS_MESSAGE(msg), FALSE );
1427 #ifdef GST_API_VERSION_1
1428 const GstStructure *structure;
1429 structure = gst_message_get_structure (msg);
1432 switch ( GST_MESSAGE_TYPE( msg ) )
1434 case GST_MESSAGE_UNKNOWN:
1435 debug_warning("unknown message received\n");
1438 case GST_MESSAGE_EOS:
1440 MMHandleType attrs = 0;
1443 debug_log("GST_MESSAGE_EOS received\n");
1445 /* NOTE : EOS event is comming multiple time. watch out it */
1446 /* check state. we only process EOS when pipeline state goes to PLAYING */
1447 if ( ! (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) )
1449 debug_warning("EOS received on non-playing state. ignoring it\n");
1453 if ( (player->audio_stream_cb) && (player->is_sound_extraction) )
1457 pad = gst_element_get_static_pad (player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
1459 debug_error("release audio callback\n");
1461 /* release audio callback */
1462 #ifdef GST_API_VERSION_1
1463 gst_pad_remove_probe (pad, player->audio_cb_probe_id);
1465 gst_pad_remove_buffer_probe (pad, player->audio_cb_probe_id);
1467 player->audio_cb_probe_id = 0;
1468 /* audio callback should be free because it can be called even though probe remove.*/
1469 player->audio_stream_cb = NULL;
1470 player->audio_stream_cb_user_param = NULL;
1474 /* rewind if repeat count is greater then zero */
1475 /* get play count */
1476 attrs = MMPLAYER_GET_ATTRS(player);
1480 gboolean smooth_repeat = FALSE;
1482 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1483 mm_attrs_get_int_by_name(attrs, "profile_smooth_repeat", &smooth_repeat);
1485 debug_log("remaining play count: %d, playback rate: %f\n", count, player->playback_rate);
1487 if ( count > 1 || count == -1 || player->playback_rate < 0.0 ) /* default value is 1 */
1489 if ( smooth_repeat )
1491 debug_log("smooth repeat enabled. seeking operation will be excuted in new thread\n");
1493 g_cond_signal( player->repeat_thread_cond );
1501 if ( player->section_repeat )
1503 ret_value = _mmplayer_activate_section_repeat((MMHandleType)player, player->section_repeat_start, player->section_repeat_end);
1508 if ( player->playback_rate < 0.0 )
1510 player->resumed_by_rewind = TRUE;
1511 _mmplayer_set_mute((MMHandleType)player, 0);
1512 MMPLAYER_POST_MSG( player, MM_MESSAGE_RESUMED_BY_REW, NULL );
1515 ret_value = __gst_set_position( player, MM_PLAYER_POS_FORMAT_TIME, 0, TRUE);
1518 player->sent_bos = FALSE;
1521 if ( MM_ERROR_NONE != ret_value )
1523 debug_error("failed to set position to zero for rewind\n");
1529 /* we successeded to rewind. update play count and then wait for next EOS */
1532 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
1534 if ( mmf_attrs_commit ( attrs ) )
1535 debug_error("failed to commit attrs\n");
1544 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-eos" );
1546 /* post eos message to application */
1547 __mmplayer_post_delayed_eos( player, PLAYER_INI()->eos_delay );
1549 /* reset last position */
1550 player->last_position = 0;
1554 case GST_MESSAGE_ERROR:
1556 GError *error = NULL;
1557 gchar* debug = NULL;
1558 gchar *msg_src_element = NULL;
1560 /* generating debug info before returning error */
1561 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-error" );
1563 /* get error code */
1564 gst_message_parse_error( msg, &error, &debug );
1566 msg_src_element = GST_ELEMENT_NAME( GST_ELEMENT_CAST( msg->src ) );
1567 #ifdef GST_API_VERSION_1
1568 if ( gst_structure_has_name ( structure, "streaming_error" ) )
1570 /* Note : the streaming error from the streaming source is handled
1571 * using __mmplayer_handle_streaming_error.
1573 __mmplayer_handle_streaming_error ( player, msg );
1575 /* dump state of all element */
1576 __mmplayer_dump_pipeline_state( player );
1580 /* traslate gst error code to msl error code. then post it
1581 * to application if needed
1583 __mmplayer_handle_gst_error( player, msg, error );
1585 /* dump state of all element */
1586 __mmplayer_dump_pipeline_state( player );
1590 if ( gst_structure_has_name ( msg->structure, "streaming_error" ) )
1592 /* Note : the streaming error from the streaming source is handled
1593 * using __mmplayer_handle_streaming_error.
1595 __mmplayer_handle_streaming_error ( player, msg );
1597 /* dump state of all element */
1598 __mmplayer_dump_pipeline_state( player );
1602 /* traslate gst error code to msl error code. then post it
1603 * to application if needed
1605 __mmplayer_handle_gst_error( player, msg, error );
1607 /* dump state of all element */
1608 __mmplayer_dump_pipeline_state( player );
1615 if (MMPLAYER_IS_HTTP_PD(player))
1617 _mmplayer_unrealize_pd_downloader ((MMHandleType)player);
1620 MMPLAYER_FREEIF( debug );
1621 g_error_free( error );
1625 case GST_MESSAGE_WARNING:
1628 GError* error = NULL;
1630 gst_message_parse_warning(msg, &error, &debug);
1632 debug_warning("warning : %s\n", error->message);
1633 debug_warning("debug : %s\n", debug);
1635 MMPLAYER_POST_MSG( player, MM_MESSAGE_WARNING, NULL );
1637 MMPLAYER_FREEIF( debug );
1638 g_error_free( error );
1642 case GST_MESSAGE_INFO: debug_log("GST_MESSAGE_STATE_DIRTY\n"); break;
1644 case GST_MESSAGE_TAG:
1646 debug_log("GST_MESSAGE_TAG\n");
1647 if ( ! __mmplayer_gst_extract_tag_from_msg( player, msg ) )
1649 debug_warning("failed to extract tags from gstmessage\n");
1654 case GST_MESSAGE_BUFFERING:
1656 MMMessageParamType msg_param = {0, };
1657 gboolean update_buffering_percent = TRUE;
1659 if ( !MMPLAYER_IS_STREAMING(player) || (player->profile.uri_type == MM_PLAYER_URI_TYPE_HLS) ) // pure hlsdemux case, don't consider buffering of msl currently
1662 __mm_player_streaming_buffering (player->streamer, msg);
1664 __mmplayer_handle_buffering_message ( player );
1666 update_buffering_percent = (player->pipeline_is_constructed || MMPLAYER_IS_RTSP_STREAMING(player) );
1667 if (update_buffering_percent)
1669 msg_param.connection.buffering = player->streamer->buffering_percent;
1670 MMPLAYER_POST_MSG ( player, MM_MESSAGE_BUFFERING, &msg_param );
1675 case GST_MESSAGE_STATE_CHANGED:
1677 MMPlayerGstElement *mainbin;
1678 const GValue *voldstate, *vnewstate, *vpending;
1679 GstState oldstate, newstate, pending;
1681 if ( ! ( player->pipeline && player->pipeline->mainbin ) )
1683 debug_error("player pipeline handle is null");
1687 mainbin = player->pipeline->mainbin;
1689 /* we only handle messages from pipeline */
1690 if( msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst )
1693 /* get state info from msg */
1694 #ifdef GST_API_VERSION_1
1695 voldstate = gst_structure_get_value (structure, "old-state");
1696 vnewstate = gst_structure_get_value (structure, "new-state");
1697 vpending = gst_structure_get_value (structure, "pending-state");
1699 voldstate = gst_structure_get_value (msg->structure, "old-state");
1700 vnewstate = gst_structure_get_value (msg->structure, "new-state");
1701 vpending = gst_structure_get_value (msg->structure, "pending-state");
1704 oldstate = (GstState)voldstate->data[0].v_int;
1705 newstate = (GstState)vnewstate->data[0].v_int;
1706 pending = (GstState)vpending->data[0].v_int;
1708 debug_log("state changed [%s] : %s ---> %s final : %s\n",
1709 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1710 gst_element_state_get_name( (GstState)oldstate ),
1711 gst_element_state_get_name( (GstState)newstate ),
1712 gst_element_state_get_name( (GstState)pending ) );
1714 if (oldstate == newstate)
1716 debug_warning("pipeline reports state transition to old state");
1722 case GST_STATE_VOID_PENDING:
1725 case GST_STATE_NULL:
1728 case GST_STATE_READY:
1731 case GST_STATE_PAUSED:
1733 gboolean prepare_async = FALSE;
1735 if ( ! player->audio_cb_probe_id && player->is_sound_extraction )
1736 __mmplayer_configure_audio_callback(player);
1738 if ( ! player->sent_bos && oldstate == GST_STATE_READY) // managed prepare async case
1740 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1741 debug_log("checking prepare mode for async transition - %d", prepare_async);
1744 if ( MMPLAYER_IS_STREAMING(player) || prepare_async )
1746 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_PAUSED );
1748 if (player->streamer)
1750 __mm_player_streaming_set_content_bitrate(player->streamer,
1751 player->total_maximum_bitrate, player->total_bitrate);
1757 case GST_STATE_PLAYING:
1759 if (player->doing_seek && async_done)
1761 player->doing_seek = FALSE;
1763 MMPLAYER_POST_MSG ( player, MM_MESSAGE_SEEK_COMPLETED, NULL );
1766 if ( MMPLAYER_IS_STREAMING(player) ) // managed prepare async case when buffering is completed
1768 // pending state should be reset oyherwise, it's still playing even though it's resumed after bufferging.
1769 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_PLAYING);
1780 case GST_MESSAGE_STATE_DIRTY: debug_log("GST_MESSAGE_STATE_DIRTY\n"); break;
1781 case GST_MESSAGE_STEP_DONE: debug_log("GST_MESSAGE_STEP_DONE\n"); break;
1782 case GST_MESSAGE_CLOCK_PROVIDE: debug_log("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
1784 case GST_MESSAGE_CLOCK_LOST:
1786 GstClock *clock = NULL;
1787 gst_message_parse_clock_lost (msg, &clock);
1788 debug_log("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME (clock) : "NULL"));
1789 g_print ("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME (clock) : "NULL"));
1791 if (PLAYER_INI()->provide_clock)
1793 debug_log ("Provide clock is TRUE, do pause->resume\n");
1794 __gst_pause(player, FALSE);
1795 __gst_resume(player, FALSE);
1800 case GST_MESSAGE_NEW_CLOCK:
1802 GstClock *clock = NULL;
1803 gst_message_parse_new_clock (msg, &clock);
1804 debug_log("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME (clock) : "NULL"));
1808 case GST_MESSAGE_STRUCTURE_CHANGE: debug_log("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
1809 case GST_MESSAGE_STREAM_STATUS: debug_log("GST_MESSAGE_STREAM_STATUS\n"); break;
1810 case GST_MESSAGE_APPLICATION: debug_log("GST_MESSAGE_APPLICATION\n"); break;
1812 case GST_MESSAGE_ELEMENT:
1814 debug_log("GST_MESSAGE_ELEMENT\n");
1818 case GST_MESSAGE_SEGMENT_START: debug_log("GST_MESSAGE_SEGMENT_START\n"); break;
1819 case GST_MESSAGE_SEGMENT_DONE: debug_log("GST_MESSAGE_SEGMENT_DONE\n"); break;
1821 case GST_MESSAGE_DURATION:
1823 debug_log("GST_MESSAGE_DURATION\n");
1824 ret = __mmplayer_gst_handle_duration(player, msg);
1827 debug_warning("failed to update duration");
1834 case GST_MESSAGE_LATENCY: debug_log("GST_MESSAGE_LATENCY\n"); break;
1835 case GST_MESSAGE_ASYNC_START: debug_log("GST_MESSAGE_ASYNC_DONE : %s\n", gst_element_get_name(GST_MESSAGE_SRC(msg))); break;
1837 case GST_MESSAGE_ASYNC_DONE:
1839 debug_log("GST_MESSAGE_ASYNC_DONE : %s\n", gst_element_get_name(GST_MESSAGE_SRC(msg)));
1841 if (player->doing_seek)
1843 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED)
1845 player->doing_seek = FALSE;
1846 MMPLAYER_POST_MSG ( player, MM_MESSAGE_SEEK_COMPLETED, NULL );
1848 else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING)
1856 case GST_MESSAGE_REQUEST_STATE: debug_log("GST_MESSAGE_REQUEST_STATE\n"); break;
1857 case GST_MESSAGE_STEP_START: debug_log("GST_MESSAGE_STEP_START\n"); break;
1858 case GST_MESSAGE_QOS: debug_log("GST_MESSAGE_QOS\n"); break;
1859 case GST_MESSAGE_PROGRESS: debug_log("GST_MESSAGE_PROGRESS\n"); break;
1860 case GST_MESSAGE_ANY: debug_log("GST_MESSAGE_ANY\n"); break;
1863 debug_warning("unhandled message\n");
1867 /* FIXIT : this cause so many warnings/errors from glib/gstreamer. we should not call it since
1868 * gst_element_post_message api takes ownership of the message.
1870 //gst_message_unref( msg );
1876 __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg)
1883 return_val_if_fail(player, FALSE);
1884 return_val_if_fail(msg, FALSE);
1886 gst_message_parse_duration (msg, &format, &bytes);
1888 if (MMPLAYER_IS_HTTP_STREAMING(player) && format == GST_FORMAT_BYTES )
1890 debug_log("data total size of http content: %lld", bytes);
1891 player->http_content_size = bytes;
1893 else if (format == GST_FORMAT_TIME)
1895 /* handling audio clip which has vbr. means duration is keep changing */
1896 _mmplayer_update_content_attrs (player, ATTR_DURATION );
1900 debug_warning("duration is neither BYTES or TIME");
1911 __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg) // @
1914 /* macro for better code readability */
1915 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
1916 if (gst_tag_list_get_string(tag_list, gsttag, &string)) \
1918 if (string != NULL)\
1920 debug_log ( "update tag string : %s\n", string); \
1921 mm_attrs_set_string_by_name(attribute, playertag, string); \
1927 #ifdef GST_API_VERSION_1
1928 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
1929 value = gst_tag_list_get_value_index(tag_list, gsttag, index); \
1933 gst_buffer_map (buffer, &info, GST_MAP_WRITE); \
1934 buffer = gst_value_get_buffer (value); \
1935 debug_log ( "update album cover data : %p, size : %d\n", info.data, gst_buffer_get_size(buffer)); \
1936 player->album_art = (gchar *)g_malloc(gst_buffer_get_size(buffer)); \
1937 if (player->album_art); \
1939 memcpy(player->album_art, info.data, gst_buffer_get_size(buffer)); \
1940 mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, gst_buffer_get_size(buffer)); \
1942 gst_buffer_unmap (buffer, &info); \
1945 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
1946 value = gst_tag_list_get_value_index(tag_list, gsttag, index); \
1949 buffer = gst_value_get_buffer (value); \
1950 debug_log ( "update album cover data : %p, size : %d\n", GST_BUFFER_DATA(buffer), GST_BUFFER_SIZE(buffer)); \
1951 player->album_art = (gchar *)g_malloc(GST_BUFFER_SIZE(buffer)); \
1952 if (player->album_art); \
1954 memcpy(player->album_art, GST_BUFFER_DATA(buffer), GST_BUFFER_SIZE(buffer)); \
1955 mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, GST_BUFFER_SIZE(buffer)); \
1960 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
1961 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint))\
1965 if(gsttag==GST_TAG_BITRATE)\
1967 if (player->updated_bitrate_count == 0) \
1968 mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
1969 if (player->updated_bitrate_count<MM_PLAYER_STREAM_COUNT_MAX) \
1971 player->bitrate[player->updated_bitrate_count] = v_uint;\
1972 player->total_bitrate += player->bitrate[player->updated_maximum_bitrate_count]; \
1973 player->updated_bitrate_count++; \
1974 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate);\
1975 debug_log ( "update bitrate %d[bps] of stream #%d.\n", v_uint, player->updated_bitrate_count);\
1978 else if (gsttag==GST_TAG_MAXIMUM_BITRATE)\
1980 if (player->updated_maximum_bitrate_count<MM_PLAYER_STREAM_COUNT_MAX) \
1982 player->maximum_bitrate[player->updated_maximum_bitrate_count] = v_uint;\
1983 player->total_maximum_bitrate += player->maximum_bitrate[player->updated_maximum_bitrate_count]; \
1984 player->updated_maximum_bitrate_count++; \
1985 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate); \
1986 debug_log ( "update maximum bitrate %d[bps] of stream #%d\n", v_uint, player->updated_maximum_bitrate_count);\
1991 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
1997 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
1998 if (gst_tag_list_get_date(tag_list, gsttag, &date))\
2002 string = g_strdup_printf("%d", g_date_get_year(date));\
2003 mm_attrs_set_string_by_name(attribute, playertag, string);\
2004 debug_log ( "metainfo year : %s\n", string);\
2005 MMPLAYER_FREEIF(string);\
2010 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
2011 if(gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64))\
2015 /* FIXIT : don't know how to store date */\
2021 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
2022 if(gst_tag_list_get_double(tag_list, gsttag, &v_double))\
2026 /* FIXIT : don't know how to store date */\
2032 /* function start */
2033 GstTagList* tag_list = NULL;
2035 MMHandleType attrs = 0;
2037 char *string = NULL;
2041 GstBuffer *buffer = NULL;
2043 const GValue *value;
2045 /* currently not used. but those are needed for above macro */
2046 //guint64 v_uint64 = 0;
2047 //gdouble v_double = 0;
2049 return_val_if_fail( player && msg, FALSE );
2051 attrs = MMPLAYER_GET_ATTRS(player);
2053 return_val_if_fail( attrs, FALSE );
2055 /* get tag list from gst message */
2056 gst_message_parse_tag(msg, &tag_list);
2058 /* store tags to player attributes */
2059 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
2060 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
2061 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
2062 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
2063 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
2064 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
2065 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
2066 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
2067 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
2068 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
2069 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
2070 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
2071 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
2072 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
2073 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
2074 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
2075 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
2076 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
2077 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
2078 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
2079 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
2080 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
2081 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
2082 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
2083 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
2084 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
2085 /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
2086 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
2087 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
2088 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
2089 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
2090 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
2091 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
2092 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
2093 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
2094 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
2095 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
2096 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
2097 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
2098 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
2099 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
2100 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
2101 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
2102 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
2103 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
2105 if ( mmf_attrs_commit ( attrs ) )
2106 debug_error("failed to commit.\n");
2108 gst_tag_list_free(tag_list);
2114 __mmplayer_gst_rtp_no_more_pads (GstElement *element, gpointer data) // @
2116 mm_player_t* player = (mm_player_t*) data;
2120 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2121 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2122 * num_dynamic_pad. and this is no-more-pad situation which means mo more pad will be added.
2123 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2125 * [1] audio and video will be dumped with filesink.
2126 * [2] autoplugging is done by just using pad caps.
2127 * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2128 * and the video will be dumped via filesink.
2130 if ( player->num_dynamic_pad == 0 )
2132 debug_log("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
2134 if ( ! __mmplayer_gst_remove_fakesink( player,
2135 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]) )
2137 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
2138 * signaling mechanism ( pad-added, no-more-pad, new-decoded-pad ) from various
2139 * source element are not same. To overcome this situation, this function will called
2140 * several places and several times. Therefore, this is not an error case.
2146 /* create dot before error-return. for debugging */
2147 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-no-more-pad" );
2149 /* NOTE : if rtspsrc goes to PLAYING before adding it's src pads, a/v sink elements will
2150 * not goes to PLAYING. they will just remain in PAUSED state. simply we are giving
2151 * PLAYING state again.
2153 __mmplayer_gst_set_state(player,
2154 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, TRUE, 5000 );
2156 player->no_more_pad = TRUE;
2162 __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink) // @
2164 GstElement* parent = NULL;
2166 return_val_if_fail(player && player->pipeline && fakesink, FALSE);
2169 g_mutex_lock( player->fsink_lock );
2171 if ( ! fakesink->gst )
2176 /* get parent of fakesink */
2177 parent = (GstElement*)gst_object_get_parent( (GstObject*)fakesink->gst );
2180 debug_log("fakesink already removed\n");
2184 gst_element_set_locked_state( fakesink->gst, TRUE );
2186 /* setting the state to NULL never returns async
2187 * so no need to wait for completion of state transiton
2189 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state (fakesink->gst, GST_STATE_NULL) )
2191 debug_error("fakesink state change failure!\n");
2193 /* FIXIT : should I return here? or try to proceed to next? */
2197 /* remove fakesink from it's parent */
2198 if ( ! gst_bin_remove( GST_BIN( parent ), fakesink->gst ) )
2200 debug_error("failed to remove fakesink\n");
2202 gst_object_unref( parent );
2207 gst_object_unref( parent );
2209 debug_log("state-holder removed\n");
2211 gst_element_set_locked_state( fakesink->gst, FALSE );
2213 g_mutex_unlock( player->fsink_lock );
2217 if ( fakesink->gst )
2219 gst_element_set_locked_state( fakesink->gst, FALSE );
2222 g_mutex_unlock( player->fsink_lock );
2228 __mmplayer_gst_rtp_dynamic_pad (GstElement *element, GstPad *pad, gpointer data) // @
2230 GstPad *sinkpad = NULL;
2231 GstCaps* caps = NULL;
2232 GstElement* new_element = NULL;
2234 mm_player_t* player = (mm_player_t*) data;
2238 return_if_fail( element && pad );
2239 return_if_fail( player &&
2241 player->pipeline->mainbin );
2244 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2245 * num_dynamic_pad will decreased after creating a sinkbin.
2247 player->num_dynamic_pad++;
2248 debug_log("stream count inc : %d\n", player->num_dynamic_pad);
2250 /* perform autoplugging if dump is disabled */
2251 if ( PLAYER_INI()->rtsp_do_typefinding )
2253 /* create typefind */
2254 new_element = gst_element_factory_make( "typefind", NULL );
2255 if ( ! new_element )
2257 debug_error("failed to create typefind\n");
2261 MMPLAYER_SIGNAL_CONNECT( player,
2262 G_OBJECT(new_element),
2264 G_CALLBACK(__mmplayer_typefind_have_type),
2267 /* FIXIT : try to remove it */
2268 player->have_dynamic_pad = FALSE;
2270 else /* NOTE : use pad's caps directely. if enabled. what I am assuming is there's no elemnt has dynamic pad */
2272 debug_log("using pad caps to autopluging instead of doing typefind\n");
2273 #ifdef GST_API_VERSION_1
2274 caps = gst_pad_get_current_caps( pad );
2276 caps = gst_pad_get_caps( pad );
2279 MMPLAYER_CHECK_NULL( caps );
2281 /* clear previous result*/
2282 player->have_dynamic_pad = FALSE;
2284 if ( ! __mmplayer_try_to_plug( player, pad, caps ) )
2286 debug_error("failed to autoplug for caps : %s\n", gst_caps_to_string( caps ) );
2290 /* check if there's dynamic pad*/
2291 if( player->have_dynamic_pad )
2293 debug_error("using pad caps assums there's no dynamic pad !\n");
2294 debug_error("try with enalbing rtsp_do_typefinding\n");
2298 gst_caps_unref( caps );
2302 /* excute new_element if created*/
2305 debug_log("adding new element to pipeline\n");
2307 /* set state to READY before add to bin */
2308 MMPLAYER_ELEMENT_SET_STATE( new_element, GST_STATE_READY );
2310 /* add new element to the pipeline */
2311 if ( FALSE == gst_bin_add( GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element) )
2313 debug_error("failed to add autoplug element to bin\n");
2317 /* get pad from element */
2318 sinkpad = gst_element_get_static_pad ( GST_ELEMENT(new_element), "sink" );
2321 debug_error("failed to get sinkpad from autoplug element\n");
2326 if ( GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad) )
2328 debug_error("failed to link autoplug element\n");
2332 gst_object_unref (sinkpad);
2335 /* run. setting PLAYING here since streamming source is live source */
2336 MMPLAYER_ELEMENT_SET_STATE( new_element, GST_STATE_PLAYING );
2343 STATE_CHANGE_FAILED:
2345 /* FIXIT : take care if new_element has already added to pipeline */
2347 gst_object_unref(GST_OBJECT(new_element));
2350 gst_object_unref(GST_OBJECT(sinkpad));
2353 gst_object_unref(GST_OBJECT(caps));
2355 /* FIXIT : how to inform this error to MSL ????? */
2356 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2357 * then post an error to application
2363 __mmplayer_gst_decode_callback(GstElement *decodebin, GstPad *pad, gboolean last, gpointer data) // @
2365 mm_player_t* player = NULL;
2366 MMHandleType attrs = 0;
2367 GstElement* pipeline = NULL;
2368 GstCaps* caps = NULL;
2369 GstStructure* str = NULL;
2370 const gchar* name = NULL;
2371 GstPad* sinkpad = NULL;
2372 GstElement* sinkbin = NULL;
2375 player = (mm_player_t*) data;
2377 return_if_fail( decodebin && pad );
2378 return_if_fail(player && player->pipeline && player->pipeline->mainbin);
2380 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
2382 attrs = MMPLAYER_GET_ATTRS(player);
2385 debug_error("cannot get content attribute\n");
2389 /* get mimetype from caps */
2390 #ifdef GST_API_VERSION_1
2391 caps = gst_pad_get_current_caps( pad );
2393 caps = gst_pad_get_caps( pad );
2397 debug_error("cannot get caps from pad.\n");
2401 str = gst_caps_get_structure( caps, 0 );
2404 debug_error("cannot get structure from capse.\n");
2408 name = gst_structure_get_name(str);
2411 debug_error("cannot get mimetype from structure.\n");
2415 debug_log("detected mimetype : %s\n", name);
2417 if (strstr(name, "audio"))
2419 if (player->pipeline->audiobin == NULL)
2421 __ta__("__mmplayer_gst_create_audio_pipeline",
2422 if (MM_ERROR_NONE != __mmplayer_gst_create_audio_pipeline(player))
2424 debug_error("failed to create audiobin. continuing without audio\n");
2429 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
2430 debug_log("creating audiosink bin success\n");
2434 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
2435 debug_log("re-using audiobin\n");
2438 /* FIXIT : track number shouldn't be hardcoded */
2439 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 1);
2440 player->audiosink_linked = 1;
2442 sinkpad = gst_element_get_static_pad( GST_ELEMENT(sinkbin), "sink" );
2445 debug_error("failed to get pad from sinkbin\n");
2449 else if (strstr(name, "video"))
2451 if (player->pipeline->videobin == NULL)
2453 /* NOTE : not make videobin because application dose not want to play it even though file has video stream. */
2454 /* get video surface type */
2455 int surface_type = 0;
2456 mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &surface_type);
2458 if (surface_type == MM_DISPLAY_SURFACE_NULL)
2460 debug_log("not make videobin because it dose not want\n");
2464 __ta__("__mmplayer_gst_create_video_pipeline",
2465 if (MM_ERROR_NONE != __mmplayer_gst_create_video_pipeline(player, caps, surface_type) )
2467 debug_error("failed to create videobin. continuing without video\n");
2472 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
2473 debug_log("creating videosink bin success\n");
2477 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
2478 debug_log("re-using videobin\n");
2481 /* FIXIT : track number shouldn't be hardcoded */
2482 mm_attrs_set_int_by_name(attrs, "content_video_track_num", 1);
2483 player->videosink_linked = 1;
2485 sinkpad = gst_element_get_static_pad( GST_ELEMENT(sinkbin), "sink" );
2488 debug_error("failed to get pad from sinkbin\n");
2492 else if (strstr(name, "text"))
2494 if (player->pipeline->textbin == NULL)
2496 __ta__("__mmplayer_gst_create_text_pipeline",
2497 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player))
2499 debug_error("failed to create textbin. continuing without text\n");
2504 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
2505 debug_log("creating textink bin success\n");
2509 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
2510 debug_log("re-using textbin\n");
2513 /* FIXIT : track number shouldn't be hardcoded */
2514 mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1);
2516 player->textsink_linked = 1;
2517 debug_msg("player->textsink_linked set to 1\n");
2519 sinkpad = gst_element_get_static_pad( GST_ELEMENT(sinkbin), "text_sink" );
2522 debug_error("failed to get pad from sinkbin\n");
2528 debug_warning("unknown type of elementary stream! ignoring it...\n");
2535 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state( sinkbin, GST_STATE_READY ) )
2537 debug_error("failed to set state(READY) to sinkbin\n");
2542 if ( FALSE == gst_bin_add( GST_BIN(pipeline), sinkbin ) )
2544 debug_error("failed to add sinkbin to pipeline\n");
2549 if ( GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad) )
2551 debug_error("failed to get pad from sinkbin\n");
2556 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state( sinkbin, GST_STATE_PAUSED ) )
2558 debug_error("failed to set state(PLAYING) to sinkbin\n");
2562 gst_object_unref( sinkpad );
2566 debug_log("linking sink bin success\n");
2568 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
2569 * streaming task. if the task blocked, then buffer will not flow to the next element
2570 * ( autoplugging element ). so this is special hack for streaming. please try to remove it
2572 /* dec stream count. we can remove fakesink if it's zero */
2573 player->num_dynamic_pad--;
2575 debug_log("stream count dec : %d (num of dynamic pad)\n", player->num_dynamic_pad);
2577 if ( ( player->no_more_pad ) && ( player->num_dynamic_pad == 0 ) )
2579 __mmplayer_pipeline_complete( NULL, player );
2584 gst_caps_unref( caps );
2587 gst_object_unref(GST_OBJECT(sinkpad));
2589 /* flusing out new attributes */
2590 if ( mmf_attrs_commit ( attrs ) )
2592 debug_error("failed to comit attributes\n");
2599 __mmplayer_get_property_value_for_rotation(mm_player_t* player, int rotation_angle, int *value)
2601 int pro_value = 0; // in the case of expection, default will be returned.
2602 int dest_angle = rotation_angle;
2603 int rotation_using_type = -1;
2604 #define ROTATION_USING_X 0
2605 #define ROTATION_USING_FIMC 1
2606 #define ROTATION_USING_FLIP 2
2608 return_val_if_fail(player, FALSE);
2609 return_val_if_fail(value, FALSE);
2610 return_val_if_fail(rotation_angle >= 0, FALSE);
2612 if (rotation_angle >= 360)
2614 dest_angle = rotation_angle - 360;
2617 /* chech if supported or not */
2618 if ( dest_angle % 90 )
2620 debug_log("not supported rotation angle = %d", rotation_angle);
2624 if (player->use_video_stream)
2626 if (player->is_nv12_tiled)
2628 rotation_using_type = ROTATION_USING_FIMC;
2632 rotation_using_type = ROTATION_USING_FLIP;
2637 int surface_type = 0;
2638 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
2639 debug_log("check display surface type for rotation: %d", surface_type);
2641 switch (surface_type)
2643 case MM_DISPLAY_SURFACE_X:
2644 rotation_using_type = ROTATION_USING_X;
2646 case MM_DISPLAY_SURFACE_EVAS:
2647 if (player->is_nv12_tiled && !strcmp(PLAYER_INI()->videosink_element_evas,"evasimagesink"))
2649 rotation_using_type = ROTATION_USING_FIMC;
2651 else if (!player->is_nv12_tiled)
2653 rotation_using_type = ROTATION_USING_FLIP;
2657 debug_error("it should not be here..");
2662 rotation_using_type = ROTATION_USING_FLIP;
2667 debug_log("using %d type for rotation", rotation_using_type);
2669 /* get property value for setting */
2670 switch(rotation_using_type)
2672 case ROTATION_USING_X: // xvimagesink
2679 pro_value = 3; // clockwise 90
2685 pro_value = 1; // counter-clockwise 90
2690 case ROTATION_USING_FIMC: // fimcconvert
2697 pro_value = 90; // clockwise 90
2703 pro_value = 270; // counter-clockwise 90
2708 case ROTATION_USING_FLIP: // videoflip
2716 pro_value = 1; // clockwise 90
2722 pro_value = 3; // counter-clockwise 90
2729 debug_log("setting rotation property value : %d", pro_value);
2737 _mmplayer_update_video_param(mm_player_t* player) // @
2739 MMHandleType attrs = 0;
2740 int surface_type = 0;
2741 int org_angle = 0; // current supported angle values are 0, 90, 180, 270
2743 int user_angle_type= 0;
2744 int rotation_value = 0;
2748 /* check video sinkbin is created */
2749 return_val_if_fail ( player &&
2751 player->pipeline->videobin &&
2752 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
2753 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2754 MM_ERROR_PLAYER_NOT_INITIALIZED );
2756 attrs = MMPLAYER_GET_ATTRS(player);
2759 debug_error("cannot get content attribute");
2760 return MM_ERROR_PLAYER_INTERNAL;
2763 /* update user roation */
2764 mm_attrs_get_int_by_name(attrs, "display_rotation", &user_angle_type);
2766 /* get angle with user type */
2767 switch(user_angle_type)
2769 case MM_DISPLAY_ROTATION_NONE:
2772 case MM_DISPLAY_ROTATION_90: // counter-clockwise 90
2775 case MM_DISPLAY_ROTATION_180:
2778 case MM_DISPLAY_ROTATION_270: // clockwise 90
2783 /* get original orientation */
2784 if (player->v_stream_caps)
2786 GstStructure *str = NULL;
2788 str = gst_caps_get_structure (player->v_stream_caps, 0);
2789 if ( !gst_structure_get_int (str, "orientation", &org_angle))
2791 debug_log ("missing 'orientation' field in video caps");
2795 debug_log("origianl video orientation = %d", org_angle);
2799 debug_log("check user angle: %d, org angle: %d", user_angle, org_angle);
2801 /* get rotation value to set */
2802 __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
2804 /* check video stream callback is used */
2805 if( player->use_video_stream )
2807 if (player->is_nv12_tiled)
2809 gchar *ename = NULL;
2813 mm_attrs_get_int_by_name(attrs, "display_width", &width);
2814 mm_attrs_get_int_by_name(attrs, "display_height", &height);
2816 /* resize video frame with requested values for fimcconvert */
2817 #ifdef GST_API_VERSION_1
2818 ename = GST_OBJECT (gst_element_get_factory(player->pipeline->videobin[MMPLAYER_V_CONV].gst));
2820 ename = GST_PLUGIN_FEATURE_NAME(gst_element_get_factory(player->pipeline->videobin[MMPLAYER_V_CONV].gst));
2823 if (g_strrstr(ename, "fimcconvert"))
2826 g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "dst-width", width, NULL);
2829 g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "dst-height", height, NULL);
2831 g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "rotate", rotation_value, NULL);
2832 debug_log("updating fimcconvert - r[%d], w[%d], h[%d]", rotation_value, width, height);
2836 debug_error("no available video converter");
2837 return MM_ERROR_PLAYER_INTERNAL;
2842 debug_log("using video stream callback with memsink. player handle : [%p]", player);
2844 g_object_set(player->pipeline->videobin[MMPLAYER_V_FLIP].gst, "method", rotation_value, NULL);
2847 return MM_ERROR_NONE;
2850 /* update display surface */
2851 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
2852 debug_log("check display surface type attribute: %d", surface_type);
2854 /* configuring display */
2855 switch ( surface_type )
2857 case MM_DISPLAY_SURFACE_X:
2859 /* ximagesink or xvimagesink */
2862 int display_method = 0;
2867 int force_aspect_ratio = 0;
2868 gboolean visible = TRUE;
2870 /* common case if using x surface */
2871 mm_attrs_get_data_by_name(attrs, "display_overlay", &xid);
2874 #define GST_VAAPI_DISPLAY_TYPE_X11 1
2875 if (!strncmp(PLAYER_INI()->videosink_element_x,"vaapisink", strlen("vaapisink"))){
2876 debug_log("set video param: vaapisink display %d", GST_VAAPI_DISPLAY_TYPE_X11);
2877 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2878 "display", GST_VAAPI_DISPLAY_TYPE_X11,
2882 debug_log("set video param : xid %d", *(int*)xid);
2883 #ifdef GST_API_VERSION_1
2884 gst_video_overlay_set_window_handle( GST_VIDEO_OVERLAY( player->pipeline->videobin[MMPLAYER_V_SINK].gst ), *(int*)xid );
2886 gst_x_overlay_set_xwindow_id( GST_X_OVERLAY( player->pipeline->videobin[MMPLAYER_V_SINK].gst ), *(int*)xid );
2891 /* FIXIT : is it error case? */
2892 debug_warning("still we don't have xid on player attribute. create it's own surface.");
2895 /* if xvimagesink */
2896 if (!strcmp(PLAYER_INI()->videosink_element_x,"xvimagesink"))
2898 mm_attrs_get_int_by_name(attrs, "display_force_aspect_ration", &force_aspect_ratio);
2899 mm_attrs_get_int_by_name(attrs, "display_zoom", &zoom);
2900 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
2901 mm_attrs_get_int_by_name(attrs, "display_roi_x", &roi_x);
2902 mm_attrs_get_int_by_name(attrs, "display_roi_y", &roi_y);
2903 mm_attrs_get_int_by_name(attrs, "display_roi_width", &roi_w);
2904 mm_attrs_get_int_by_name(attrs, "display_roi_height", &roi_h);
2905 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
2907 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2908 "force-aspect-ratio", force_aspect_ratio,
2910 "rotate", rotation_value,
2911 "handle-events", TRUE,
2912 "display-geometry-method", display_method,
2913 "draw-borders", FALSE,
2921 debug_log("set video param : zoom %d", zoom);
2922 debug_log("set video param : rotate %d", rotation_value);
2923 debug_log("set video param : method %d", display_method);
2924 debug_log("set video param : dst-roi-x: %d, dst-roi-y: %d, dst-roi-w: %d, dst-roi-h: %d",
2925 roi_x, roi_y, roi_w, roi_h );
2926 debug_log("set video param : visible %d", visible);
2927 debug_log("set video param : force aspect ratio %d", force_aspect_ratio);
2931 if (!strncmp(PLAYER_INI()->videosink_element_x, "vaapisink", strlen("vaapisink")))
2933 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2934 "rotation", rotation_value,
2936 debug_log("set video param: vaapisink rotation %d", rotation_value);
2940 case MM_DISPLAY_SURFACE_EVAS:
2942 void *object = NULL;
2944 gboolean visible = TRUE;
2946 /* common case if using evas surface */
2947 mm_attrs_get_data_by_name(attrs, "display_overlay", &object);
2948 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
2949 mm_attrs_get_int_by_name(attrs, "display_evas_do_scaling", &scaling);
2952 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2953 "evas-object", object,
2956 debug_log("set video param : evas-object %x", object);
2957 debug_log("set video param : visible %d", visible);
2961 debug_error("no evas object");
2962 return MM_ERROR_PLAYER_INTERNAL;
2965 /* if evasimagesink */
2966 if (!strcmp(PLAYER_INI()->videosink_element_evas,"evasimagesink") && player->is_nv12_tiled)
2970 int no_scaling = !scaling;
2972 mm_attrs_get_int_by_name(attrs, "display_width", &width);
2973 mm_attrs_get_int_by_name(attrs, "display_height", &height);
2975 /* NOTE: fimcconvert does not manage index of src buffer from upstream src-plugin, decoder gives frame information in output buffer with no ordering */
2976 g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "dst-buffer-num", 5, NULL);
2980 /* no-scaling order to fimcconvert, original width, height size of media src will be passed to sink plugin */
2981 g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst,
2982 "dst-width", 0, /* setting 0, output video width will be media src's width */
2983 "dst-height", 0, /* setting 0, output video height will be media src's height */
2988 /* scaling order to fimcconvert */
2991 g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "dst-width", width, NULL);
2995 g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "dst-height", height, NULL);
2997 debug_log("set video param : video frame scaling down to width(%d) height(%d)", width, height);
2999 debug_log("set video param : display_evas_do_scaling %d", scaling);
3002 /* if evaspixmapsink */
3003 if (!strcmp(PLAYER_INI()->videosink_element_evas,"evaspixmapsink"))
3005 int display_method = 0;
3010 int origin_size = !scaling;
3012 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
3013 mm_attrs_get_int_by_name(attrs, "display_roi_x", &roi_x);
3014 mm_attrs_get_int_by_name(attrs, "display_roi_y", &roi_y);
3015 mm_attrs_get_int_by_name(attrs, "display_roi_width", &roi_w);
3016 mm_attrs_get_int_by_name(attrs, "display_roi_height", &roi_h);
3018 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3019 "origin-size", origin_size,
3024 "display-geometry-method", display_method,
3027 debug_log("set video param : method %d", display_method);
3028 debug_log("set video param : dst-roi-x: %d, dst-roi-y: %d, dst-roi-w: %d, dst-roi-h: %d",
3029 roi_x, roi_y, roi_w, roi_h );
3030 debug_log("set video param : display_evas_do_scaling %d (origin-size %d)", scaling, origin_size);
3032 g_object_set(player->pipeline->videobin[MMPLAYER_V_FLIP].gst, "method", rotation_value, NULL);
3035 case MM_DISPLAY_SURFACE_X_EXT: /* NOTE : this surface type is used for the videoTexture(canvasTexture) overlay */
3037 void *pixmap_id_cb = NULL;
3038 void *pixmap_id_cb_user_data = NULL;
3039 int display_method = 0;
3040 gboolean visible = TRUE;
3042 /* if xvimagesink */
3043 if (strcmp(PLAYER_INI()->videosink_element_x,"xvimagesink"))
3045 debug_error("videosink is not xvimagesink");
3046 return MM_ERROR_PLAYER_INTERNAL;
3049 /* get information from attributes */
3050 mm_attrs_get_data_by_name(attrs, "display_overlay", &pixmap_id_cb);
3051 mm_attrs_get_data_by_name(attrs, "display_overlay_user_data", &pixmap_id_cb_user_data);
3052 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
3056 debug_log("set video param : display_overlay(0x%x)", pixmap_id_cb);
3057 if (pixmap_id_cb_user_data)
3059 debug_log("set video param : display_overlay_user_data(0x%x)", pixmap_id_cb_user_data);
3064 debug_error("failed to set pixmap-id-callback");
3065 return MM_ERROR_PLAYER_INTERNAL;
3067 debug_log("set video param : method %d", display_method);
3068 debug_log("set video param : visible %d", visible);
3070 /* set properties of videosink plugin */
3071 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3072 "display-geometry-method", display_method,
3073 "draw-borders", FALSE,
3075 "rotate", rotation_value,
3076 "pixmap-id-callback", pixmap_id_cb,
3077 "pixmap-id-callback-userdata", pixmap_id_cb_user_data,
3081 case MM_DISPLAY_SURFACE_NULL:
3090 return MM_ERROR_NONE;
3094 __mmplayer_gst_element_link_bucket(GList* element_bucket) // @
3096 GList* bucket = element_bucket;
3097 MMPlayerGstElement* element = NULL;
3098 MMPlayerGstElement* prv_element = NULL;
3099 gint successful_link_count = 0;
3103 return_val_if_fail(element_bucket, -1);
3105 prv_element = (MMPlayerGstElement*)bucket->data;
3106 bucket = bucket->next;
3108 for ( ; bucket; bucket = bucket->next )
3110 element = (MMPlayerGstElement*)bucket->data;
3112 if ( element && element->gst )
3114 if ( GST_ELEMENT_LINK(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst)) )
3116 debug_log("linking [%s] to [%s] success\n",
3117 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
3118 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)) );
3119 successful_link_count ++;
3123 debug_log("linking [%s] to [%s] failed\n",
3124 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
3125 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)) );
3130 prv_element = element;
3135 return successful_link_count;
3139 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket) // @
3141 GList* bucket = element_bucket;
3142 MMPlayerGstElement* element = NULL;
3143 int successful_add_count = 0;
3147 return_val_if_fail(element_bucket, 0);
3148 return_val_if_fail(bin, 0);
3150 for ( ; bucket; bucket = bucket->next )
3152 element = (MMPlayerGstElement*)bucket->data;
3154 if ( element && element->gst )
3156 if( !gst_bin_add(bin, GST_ELEMENT(element->gst)) )
3158 debug_log("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed\n",
3159 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
3160 GST_ELEMENT_NAME(GST_ELEMENT(bin) ) );
3163 successful_add_count ++;
3169 return successful_add_count;
3175 * This function is to create audio pipeline for playing.
3177 * @param player [in] handle of player
3179 * @return This function returns zero on success.
3181 * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_pipeline
3183 #define MMPLAYER_CREATEONLY_ELEMENT(x_bin, x_id, x_factory, x_name) \
3184 x_bin[x_id].id = x_id;\
3185 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
3186 if ( ! x_bin[x_id].gst )\
3188 debug_critical("failed to create %s \n", x_factory);\
3192 #define MMPLAYER_CREATE_ELEMENT_ADD_BIN(x_bin, x_id, x_factory, x_name, y_bin) \
3193 x_bin[x_id].id = x_id;\
3194 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
3195 if ( ! x_bin[x_id].gst )\
3197 debug_critical("failed to create %s \n", x_factory);\
3200 if( !gst_bin_add(GST_BIN(y_bin), GST_ELEMENT(x_bin[x_id].gst)))\
3202 debug_log("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed\n",\
3203 GST_ELEMENT_NAME(GST_ELEMENT(x_bin[x_id].gst)),\
3204 GST_ELEMENT_NAME(GST_ELEMENT(y_bin) ) );\
3208 /* macro for code readability. just for sinkbin-creation functions */
3209 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket) \
3212 x_bin[x_id].id = x_id;\
3213 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
3214 if ( ! x_bin[x_id].gst )\
3216 debug_critical("failed to create %s \n", x_factory);\
3219 if ( x_add_bucket )\
3220 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
3226 * - Local playback : audioconvert !volume ! capsfilter ! audioeq ! audiosink
3227 * - Streaming : audioconvert !volume ! audiosink
3228 * - PCM extraction : audioconvert ! audioresample ! capsfilter ! fakesink
3231 __mmplayer_gst_create_audio_pipeline(mm_player_t* player)
3233 MMPlayerGstElement* first_element = NULL;
3234 MMPlayerGstElement* audiobin = NULL;
3235 MMHandleType attrs = 0;
3237 GstPad *ghostpad = NULL;
3238 GList* element_bucket = NULL;
3239 char *device_name = NULL;
3240 gboolean link_audio_sink_now = TRUE;
3245 return_val_if_fail( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
3248 audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
3251 debug_error("failed to allocate memory for audiobin\n");
3252 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3255 attrs = MMPLAYER_GET_ATTRS(player);
3258 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
3259 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
3260 if ( !audiobin[MMPLAYER_A_BIN].gst )
3262 debug_critical("failed to create audiobin\n");
3267 player->pipeline->audiobin = audiobin;
3269 player->is_sound_extraction = __mmplayer_can_extract_pcm(player);
3271 /* Adding audiotp plugin for reverse trickplay feature */
3272 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TP, "audiotp", "audiotrickplay", TRUE);
3275 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audioconverter", TRUE);
3277 if ( ! player->is_sound_extraction )
3279 GstCaps* caps = NULL;
3282 /* for logical volume control */
3283 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE);
3284 g_object_set(G_OBJECT (audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
3286 if (player->sound.mute)
3288 debug_log("mute enabled\n");
3289 g_object_set(G_OBJECT (audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
3293 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE);
3295 caps = gst_caps_from_string( "audio/x-raw-int, "
3296 "endianness = (int) LITTLE_ENDIAN, "
3297 "signed = (boolean) true, "
3298 "width = (int) 16, "
3299 "depth = (int) 16" );
3300 g_object_set (GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL );
3302 gst_caps_unref( caps );
3304 /* chech if multi-chennels */
3305 if (player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)
3307 GstPad *srcpad = NULL;
3308 GstCaps *caps = NULL;
3310 if ((srcpad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "src")))
3312 #ifdef GST_API_VERSION_1
3313 if ((caps = gst_pad_get_current_caps(srcpad)))
3315 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
3316 GstStructure *str = gst_caps_get_structure(caps, 0);
3318 gst_structure_get_int (str, "channels", &channels);
3319 gst_caps_unref(caps);
3322 if ((caps = gst_pad_get_caps(srcpad)))
3324 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
3325 GstStructure *str = gst_caps_get_structure(caps, 0);
3327 gst_structure_get_int (str, "channels", &channels);
3328 gst_caps_unref(caps);
3331 gst_object_unref(srcpad);
3335 /* audio effect element. if audio effect is enabled */
3336 if ( channels <= 2 && (PLAYER_INI()->use_audio_effect_preset || PLAYER_INI()->use_audio_effect_custom) )
3338 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, PLAYER_INI()->name_of_audio_effect, "audiofilter", TRUE);
3341 /* create audio sink */
3342 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, PLAYER_INI()->name_of_audiosink,
3343 "audiosink", link_audio_sink_now);
3346 if (MMPLAYER_IS_RTSP_STREAMING(player))
3347 g_object_set (G_OBJECT (audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL); /* sync off */
3349 g_object_set (G_OBJECT (audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE, NULL); /* sync on */
3352 g_object_set (G_OBJECT (audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
3354 /* FIXIT : using system clock. isn't there another way? */
3355 g_object_set (G_OBJECT (audiobin[MMPLAYER_A_SINK].gst), "provide-clock", PLAYER_INI()->provide_clock, NULL);
3357 __mmplayer_add_sink( player, audiobin[MMPLAYER_A_SINK].gst );
3359 if(player->audio_buffer_cb)
3361 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "audio-handle", player->audio_buffer_cb_user_param, NULL);
3362 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "audio-callback", player->audio_buffer_cb, NULL);
3365 if ( g_strrstr(PLAYER_INI()->name_of_audiosink, "avsysaudiosink") )
3367 gint volume_type = 0;
3368 gint audio_route = 0;
3369 gint sound_priority = FALSE;
3370 gint is_spk_out_only = 0;
3371 gint latency_mode = 0;
3374 * It should be set after player creation through attribute.
3375 * But, it can not be changed during playing.
3377 mm_attrs_get_int_by_name(attrs, "sound_volume_type", &volume_type);
3378 mm_attrs_get_int_by_name(attrs, "sound_route", &audio_route);
3379 mm_attrs_get_int_by_name(attrs, "sound_priority", &sound_priority);
3380 mm_attrs_get_int_by_name(attrs, "sound_spk_out_only", &is_spk_out_only);
3381 mm_attrs_get_int_by_name(attrs, "audio_latency_mode", &latency_mode);
3383 /* hook sound_type if emergency case */
3384 if ( player->sm.event == ASM_EVENT_EMERGENCY)
3386 debug_log ("This is emergency session, hook sound_type from [%d] to [%d]\n", volume_type, MM_SOUND_VOLUME_TYPE_EMERGENCY);
3387 volume_type = MM_SOUND_VOLUME_TYPE_EMERGENCY;
3390 g_object_set(audiobin[MMPLAYER_A_SINK].gst,
3391 "volumetype", volume_type,
3392 "audio-route", audio_route,
3393 "priority", sound_priority,
3394 "user-route", is_spk_out_only,
3395 "latency", latency_mode,
3398 debug_log("audiosink property status...volume type:%d, route:%d, priority=%d, user-route=%d, latency=%d\n",
3399 volume_type, audio_route, sound_priority, is_spk_out_only, latency_mode);
3402 /* Antishock can be enabled when player is resumed by soundCM.
3403 * But, it's not used in MMS, setting and etc.
3404 * Because, player start seems like late.
3406 __mmplayer_set_antishock( player , FALSE );
3408 else // pcm extraction only and no sound output
3410 int dst_samplerate = 0;
3411 int dst_channels = 0;
3413 char *caps_type = NULL;
3414 GstCaps* caps = NULL;
3417 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, "audioresample", "resampler", TRUE);
3419 /* get conf. values */
3420 mm_attrs_multiple_get(player->attrs,
3422 "pcm_extraction_samplerate", &dst_samplerate,
3423 "pcm_extraction_channels", &dst_channels,
3424 "pcm_extraction_depth", &dst_depth,
3427 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE);
3429 caps = gst_caps_new_simple ("audio/x-raw-int",
3430 "rate", G_TYPE_INT, dst_samplerate,
3431 "channels", G_TYPE_INT, dst_channels,
3432 "depth", G_TYPE_INT, dst_depth,
3435 caps_type = gst_caps_to_string(caps);
3436 debug_log("resampler new caps : %s\n", caps_type);
3438 g_object_set (GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL );
3441 gst_caps_unref( caps );
3442 MMPLAYER_FREEIF( caps_type );
3445 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "fakesink", TRUE);
3448 g_object_set (G_OBJECT (audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL);
3450 __mmplayer_add_sink( player, audiobin[MMPLAYER_A_SINK].gst );
3453 /* adding created elements to bin */
3454 debug_log("adding created elements to bin\n");
3455 if( !__mmplayer_gst_element_add_bucket_to_bin( GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket ))
3457 debug_error("failed to add elements\n");
3461 /* linking elements in the bucket by added order. */
3462 debug_log("Linking elements in the bucket by added order.\n");
3463 if ( __mmplayer_gst_element_link_bucket(element_bucket) == -1 )
3465 debug_error("failed to link elements\n");
3469 /* get first element's sinkpad for creating ghostpad */
3470 first_element = (MMPlayerGstElement *)element_bucket->data;
3472 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3475 debug_error("failed to get pad from first element of audiobin\n");
3479 ghostpad = gst_ghost_pad_new("sink", pad);
3482 debug_error("failed to create ghostpad\n");
3486 if ( FALSE == gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad) )
3488 debug_error("failed to add ghostpad to audiobin\n");
3492 gst_object_unref(pad);
3494 if ( !player->bypass_audio_effect && (PLAYER_INI()->use_audio_effect_preset || PLAYER_INI()->use_audio_effect_custom) )
3496 if ( player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_PRESET )
3498 if (!_mmplayer_audio_effect_preset_apply(player, player->audio_effect_info.preset))
3500 debug_msg("apply audio effect(preset:%d) setting success\n",player->audio_effect_info.preset);
3503 else if ( player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM )
3505 if (!_mmplayer_audio_effect_custom_apply(player))
3507 debug_msg("apply audio effect(custom) setting success\n");
3512 /* done. free allocated variables */
3513 MMPLAYER_FREEIF( device_name );
3514 g_list_free(element_bucket);
3516 mm_attrs_set_int_by_name(attrs, "content_audio_found", TRUE);
3520 return MM_ERROR_NONE;
3524 debug_log("ERROR : releasing audiobin\n");
3526 MMPLAYER_FREEIF( device_name );
3529 gst_object_unref(GST_OBJECT(pad));
3532 gst_object_unref(GST_OBJECT(ghostpad));
3534 g_list_free( element_bucket );
3537 /* release element which are not added to bin */
3538 for ( i = 1; i < MMPLAYER_A_NUM; i++ ) /* NOTE : skip bin */
3540 if ( audiobin[i].gst )
3542 GstObject* parent = NULL;
3543 parent = gst_element_get_parent( audiobin[i].gst );
3547 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3548 audiobin[i].gst = NULL;
3552 gst_object_unref(GST_OBJECT(parent));
3557 /* release audiobin with it's childs */
3558 if ( audiobin[MMPLAYER_A_BIN].gst )
3560 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3563 MMPLAYER_FREEIF( audiobin );
3565 player->pipeline->audiobin = NULL;
3567 return MM_ERROR_PLAYER_INTERNAL;
3571 __mmplayer_audio_stream_probe (GstPad *pad, GstBuffer *buffer, gpointer u_data)
3573 mm_player_t* player = (mm_player_t*) u_data;
3577 #ifdef GST_API_VERSION_1
3579 gst_buffer_map (buffer, &info, GST_MAP_WRITE);
3581 size = gst_buffer_get_size(buffer);
3583 if (player->audio_stream_cb && size && data)
3584 player->audio_stream_cb((void *)data, size, player->audio_stream_cb_user_param);
3586 gst_buffer_unmap (buffer, &info);
3588 data = GST_BUFFER_DATA(buffer);
3589 size = GST_BUFFER_SIZE(buffer);
3591 if (player->audio_stream_cb && size && data)
3592 player->audio_stream_cb((void *)data, size, player->audio_stream_cb_user_param);
3599 * This function is to create video pipeline.
3601 * @param player [in] handle of player
3602 * caps [in] src caps of decoder
3603 * surface_type [in] surface type for video rendering
3605 * @return This function returns zero on success.
3607 * @see __mmplayer_gst_create_audio_pipeline, __mmplayer_gst_create_midi_pipeline
3611 * - x surface (arm/x86) : videoflip ! xvimagesink
3612 * - evas surface (arm) : fimcconvert ! evasimagesink
3613 * - evas surface (x86) : videoconvertor ! videoflip ! evasimagesink
3616 __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
3620 GList*element_bucket = NULL;
3621 MMPlayerGstElement* first_element = NULL;
3622 MMPlayerGstElement* videobin = NULL;
3623 gchar* vconv_factory = NULL;
3624 gchar *videosink_element = NULL;
3628 return_val_if_fail(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3631 videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
3634 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3637 player->pipeline->videobin = videobin;
3639 attrs = MMPLAYER_GET_ATTRS(player);
3642 debug_error("cannot get content attribute");
3643 return MM_ERROR_PLAYER_INTERNAL;
3647 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3648 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3649 if ( !videobin[MMPLAYER_V_BIN].gst )
3651 debug_critical("failed to create videobin");
3655 if( player->use_video_stream ) // video stream callback, so send raw video data to application
3657 GstStructure *str = NULL;
3660 debug_log("using memsink\n");
3662 /* first, create colorspace convert */
3663 if (player->is_nv12_tiled)
3665 vconv_factory = "fimcconvert";
3667 else // get video converter from player ini file
3669 if (strlen(PLAYER_INI()->name_of_video_converter) > 0)
3671 vconv_factory = PLAYER_INI()->name_of_video_converter;
3677 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_CONV, vconv_factory, "video converter", TRUE);
3680 if ( !player->is_nv12_tiled)
3682 gint width = 0; //width of video
3683 gint height = 0; //height of video
3684 GstCaps* video_caps = NULL;
3686 /* rotator, scaler and capsfilter */
3687 if (strncmp(PLAYER_INI()->videosink_element_x, "vaapisink", strlen("vaapisink"))){
3688 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE);
3689 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SCALE, "videoscale", "video scaler", TRUE);
3690 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_CAPS, "capsfilter", "videocapsfilter", TRUE);
3693 /* get video stream caps parsed by demuxer */
3694 str = gst_caps_get_structure (player->v_stream_caps, 0);
3697 debug_error("cannot get structure");
3701 mm_attrs_get_int_by_name(attrs, "display_width", &width);
3702 mm_attrs_get_int_by_name(attrs, "display_height", &height);
3703 if (!width || !height) {
3704 /* we set width/height of original media's size to capsfilter for scaling video */
3705 ret = gst_structure_get_int (str, "width", &width);
3708 debug_error("cannot get width");
3712 ret = gst_structure_get_int(str, "height", &height);
3715 debug_error("cannot get height");
3720 video_caps = gst_caps_new_simple( "video/x-raw-rgb",
3721 "width", G_TYPE_INT, width,
3722 "height", G_TYPE_INT, height,
3725 g_object_set (GST_ELEMENT(videobin[MMPLAYER_V_CAPS].gst), "caps", video_caps, NULL );
3727 gst_caps_unref( video_caps );
3730 /* finally, create video sink. output will be BGRA8888. */
3731 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, "avsysmemsink", "videosink", TRUE);
3733 MMPLAYER_SIGNAL_CONNECT( player,
3734 videobin[MMPLAYER_V_SINK].gst,
3736 G_CALLBACK(__mmplayer_videostream_cb),
3739 else // render video data using sink plugin like xvimagesink
3741 debug_log("using videosink");
3743 /* set video converter */
3744 if (strlen(PLAYER_INI()->name_of_video_converter) > 0)
3746 vconv_factory = PLAYER_INI()->name_of_video_converter;
3748 if ( (player->is_nv12_tiled && (surface_type == MM_DISPLAY_SURFACE_EVAS) &&
3749 !strcmp(PLAYER_INI()->videosink_element_evas, "evasimagesink") ) )
3751 vconv_factory = "fimcconvert";
3753 else if (player->is_nv12_tiled)
3755 vconv_factory = NULL;
3760 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_CONV, vconv_factory, "video converter", TRUE);
3761 debug_log("using video converter: %s", vconv_factory);
3765 if (strncmp(PLAYER_INI()->videosink_element_x,"vaapisink", strlen("vaapisink"))){
3766 /* set video rotator */
3767 if ( !player->is_nv12_tiled )
3768 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE);
3771 #if !defined(__arm__)
3772 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SCALE, "videoscale", "videoscaler", TRUE);
3776 /* set video sink */
3777 switch (surface_type)
3779 case MM_DISPLAY_SURFACE_X:
3780 if (strlen(PLAYER_INI()->videosink_element_x) > 0)
3781 videosink_element = PLAYER_INI()->videosink_element_x;
3785 case MM_DISPLAY_SURFACE_EVAS:
3786 if (strlen(PLAYER_INI()->videosink_element_evas) > 0)
3787 videosink_element = PLAYER_INI()->videosink_element_evas;
3791 case MM_DISPLAY_SURFACE_X_EXT:
3793 void *pixmap_id_cb = NULL;
3794 mm_attrs_get_data_by_name(attrs, "display_overlay", &pixmap_id_cb);
3795 if (pixmap_id_cb) /* this is used for the videoTextue(canvasTexture) overlay */
3797 videosink_element = PLAYER_INI()->videosink_element_x;
3801 debug_error("something wrong.. callback function for getting pixmap id is null");
3806 case MM_DISPLAY_SURFACE_NULL:
3807 if (strlen(PLAYER_INI()->videosink_element_fake) > 0)
3808 videosink_element = PLAYER_INI()->videosink_element_fake;
3813 debug_error("unidentified surface type");
3817 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_element, videosink_element, TRUE);
3818 debug_log("selected videosink name: %s", videosink_element);
3820 /* connect signal handlers for sink plug-in */
3821 switch (surface_type) {
3822 case MM_DISPLAY_SURFACE_X_EXT:
3823 MMPLAYER_SIGNAL_CONNECT( player,
3824 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3825 "frame-render-error",
3826 G_CALLBACK(__mmplayer_videoframe_render_error_cb),
3828 debug_log("videoTexture usage, connect a signal handler for pixmap rendering error");
3835 if ( _mmplayer_update_video_param(player) != MM_ERROR_NONE)
3839 g_object_set (G_OBJECT (videobin[MMPLAYER_V_SINK].gst), "qos", TRUE, NULL);
3841 /* store it as it's sink element */
3842 __mmplayer_add_sink( player, videobin[MMPLAYER_V_SINK].gst );
3844 /* adding created elements to bin */
3845 if( ! __mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket) )
3847 debug_error("failed to add elements\n");
3851 /* Linking elements in the bucket by added order */
3852 if ( __mmplayer_gst_element_link_bucket(element_bucket) == -1 )
3854 debug_error("failed to link elements\n");
3858 /* get first element's sinkpad for creating ghostpad */
3859 first_element = (MMPlayerGstElement *)element_bucket->data;
3860 if ( !first_element )
3862 debug_error("failed to get first element from bucket\n");
3866 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3869 debug_error("failed to get pad from first element\n");
3873 /* create ghostpad */
3874 if (FALSE == gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, gst_ghost_pad_new("sink", pad)))
3876 debug_error("failed to add ghostpad to videobin\n");
3879 gst_object_unref(pad);
3881 /* done. free allocated variables */
3882 g_list_free(element_bucket);
3884 mm_attrs_set_int_by_name(attrs, "content_video_found", TRUE);
3888 return MM_ERROR_NONE;
3891 debug_error("ERROR : releasing videobin\n");
3893 g_list_free( element_bucket );
3896 gst_object_unref(GST_OBJECT(pad));
3898 /* release videobin with it's childs */
3899 if ( videobin[MMPLAYER_V_BIN].gst )
3901 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3905 MMPLAYER_FREEIF( videobin );
3907 player->pipeline->videobin = NULL;
3909 return MM_ERROR_PLAYER_INTERNAL;
3912 static int __mmplayer_gst_create_text_pipeline(mm_player_t* player)
3914 MMPlayerGstElement* first_element = NULL;
3915 MMPlayerGstElement* textbin = NULL;
3916 GList* element_bucket = NULL;
3918 GstPad *ghostpad = NULL;
3923 return_val_if_fail( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
3926 textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
3929 debug_error("failed to allocate memory for textbin\n");
3930 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3934 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3935 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3936 if ( !textbin[MMPLAYER_T_BIN].gst )
3938 debug_critical("failed to create textbin\n");
3943 player->pipeline->textbin = textbin;
3946 if (player->use_textoverlay)
3948 debug_log ("use textoverlay for displaying \n");
3950 MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_TEXT_QUEUE, "queue", "text_t_queue", textbin[MMPLAYER_T_BIN].gst);
3952 MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_VIDEO_QUEUE, "queue", "text_v_queue", textbin[MMPLAYER_T_BIN].gst);
3954 MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_VIDEO_CONVERTER, "fimcconvert", "text_v_converter", textbin[MMPLAYER_T_BIN].gst);
3956 MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_OVERLAY, "textoverlay", "text_overlay", textbin[MMPLAYER_T_BIN].gst);
3958 if (!gst_element_link_pads (textbin[MMPLAYER_T_VIDEO_QUEUE].gst, "src", textbin[MMPLAYER_T_VIDEO_CONVERTER].gst, "sink"))
3960 debug_error("failed to link queue and converter\n");
3964 if (!gst_element_link_pads (textbin[MMPLAYER_T_VIDEO_CONVERTER].gst, "src", textbin[MMPLAYER_T_OVERLAY].gst, "video_sink"))
3966 debug_error("failed to link queue and textoverlay\n");
3970 if (!gst_element_link_pads (textbin[MMPLAYER_T_TEXT_QUEUE].gst, "src", textbin[MMPLAYER_T_OVERLAY].gst, "text_sink"))
3972 debug_error("failed to link queue and textoverlay\n");
3979 debug_log ("use subtitle message for displaying \n");
3981 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_TEXT_QUEUE, "queue", "text_queue", TRUE);
3983 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_SINK, "fakesink", "text_sink", TRUE);
3985 g_object_set (G_OBJECT (textbin[MMPLAYER_T_SINK].gst), "sync", TRUE, NULL);
3986 g_object_set (G_OBJECT (textbin[MMPLAYER_T_SINK].gst), "async", FALSE, NULL);
3987 g_object_set (G_OBJECT (textbin[MMPLAYER_T_SINK].gst), "signal-handoffs", TRUE, NULL);
3989 MMPLAYER_SIGNAL_CONNECT( player,
3990 G_OBJECT(textbin[MMPLAYER_T_SINK].gst),
3992 G_CALLBACK(__mmplayer_update_subtitle),
3995 if (!player->play_subtitle)
3997 debug_log ("add textbin sink as sink element of whole pipeline.\n");
3998 __mmplayer_add_sink (player, GST_ELEMENT(textbin[MMPLAYER_T_SINK].gst));
4001 /* adding created elements to bin */
4002 debug_log("adding created elements to bin\n");
4003 if( !__mmplayer_gst_element_add_bucket_to_bin( GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket ))
4005 debug_error("failed to add elements\n");
4009 /* linking elements in the bucket by added order. */
4010 debug_log("Linking elements in the bucket by added order.\n");
4011 if ( __mmplayer_gst_element_link_bucket(element_bucket) == -1 )
4013 debug_error("failed to link elements\n");
4017 /* done. free allocated variables */
4018 g_list_free(element_bucket);
4021 if (textbin[MMPLAYER_T_TEXT_QUEUE].gst)
4023 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_TEXT_QUEUE].gst), "sink");
4026 debug_error("failed to get text pad of textbin\n");
4030 ghostpad = gst_ghost_pad_new("text_sink", pad);
4033 debug_error("failed to create ghostpad of textbin\n");
4037 if ( FALSE == gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad) )
4039 debug_error("failed to add ghostpad to textbin\n");
4044 if (textbin[MMPLAYER_T_VIDEO_QUEUE].gst)
4046 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_VIDEO_QUEUE].gst), "sink");
4049 debug_error("failed to get video pad of textbin\n");
4053 ghostpad = gst_ghost_pad_new("video_sink", pad);
4056 debug_error("failed to create ghostpad of textbin\n");
4060 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad))
4062 debug_error("failed to add ghostpad to textbin\n");
4067 if (textbin[MMPLAYER_T_OVERLAY].gst)
4069 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_OVERLAY].gst), "src");
4072 debug_error("failed to get src pad of textbin\n");
4076 ghostpad = gst_ghost_pad_new("src", pad);
4079 debug_error("failed to create ghostpad of textbin\n");
4083 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad))
4085 debug_error("failed to add ghostpad to textbin\n");
4090 gst_object_unref(pad);
4094 return MM_ERROR_NONE;
4098 debug_log("ERROR : releasing textbin\n");
4101 gst_object_unref(GST_OBJECT(pad));
4104 gst_object_unref(GST_OBJECT(ghostpad));
4106 g_list_free( element_bucket );
4109 /* release element which are not added to bin */
4110 for ( i = 1; i < MMPLAYER_T_NUM; i++ ) /* NOTE : skip bin */
4112 if ( textbin[i].gst )
4114 GstObject* parent = NULL;
4115 parent = gst_element_get_parent( textbin[i].gst );
4119 gst_object_unref(GST_OBJECT(textbin[i].gst));
4120 textbin[i].gst = NULL;
4124 gst_object_unref(GST_OBJECT(parent));
4129 /* release textbin with it's childs */
4130 if ( textbin[MMPLAYER_T_BIN].gst )
4132 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
4135 MMPLAYER_FREEIF( textbin );
4137 player->pipeline->textbin = NULL;
4139 return MM_ERROR_PLAYER_INTERNAL;
4144 __mmplayer_gst_create_subtitle_src(mm_player_t* player)
4146 MMPlayerGstElement* mainbin = NULL;
4147 MMHandleType attrs = 0;
4148 GstElement * pipeline = NULL;
4149 GstElement *subsrc = NULL;
4150 GstElement *subparse = NULL;
4151 GstPad *sinkpad = NULL;
4152 gchar *subtitle_uri =NULL;
4153 gchar *charset = NULL;
4158 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4160 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4161 mainbin = player->pipeline->mainbin;
4163 attrs = MMPLAYER_GET_ATTRS(player);
4166 debug_error("cannot get content attribute\n");
4167 return MM_ERROR_PLAYER_INTERNAL;
4170 mm_attrs_get_string_by_name ( attrs, "subtitle_uri", &subtitle_uri );
4171 if ( !subtitle_uri || strlen(subtitle_uri) < 1)
4173 debug_error("subtitle uri is not proper filepath.\n");
4174 return MM_ERROR_PLAYER_INVALID_URI;
4176 debug_log("subtitle file path is [%s].\n", subtitle_uri);
4179 /* create the subtitle source */
4180 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
4183 debug_error ( "failed to create filesrc element\n" );
4186 g_object_set(G_OBJECT (subsrc), "location", subtitle_uri, NULL);
4188 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
4189 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
4191 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc))
4193 debug_warning("failed to add queue\n");
4198 subparse = gst_element_factory_make("subparse", "subtitle_parser");
4201 debug_error ( "failed to create subparse element\n" );
4205 charset = util_get_charset(subtitle_uri);
4208 debug_log ("detected charset is %s\n", charset );
4209 g_object_set (G_OBJECT (subparse), "subtitle-encoding", charset, NULL);
4212 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
4213 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
4215 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse))
4217 debug_warning("failed to add subparse\n");
4221 if (!gst_element_link_pads (subsrc, "src", subparse, "sink"))
4223 debug_warning("failed to link subsrc and subparse\n");
4227 player->play_subtitle = TRUE;
4228 debug_log ("play subtitle using subtitle file\n");
4230 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player))
4232 debug_error("failed to create textbin. continuing without text\n");
4236 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(player->pipeline->textbin[MMPLAYER_T_BIN].gst)))
4238 debug_warning("failed to add textbin\n");
4242 if (!gst_element_link_pads (subparse, "src", player->pipeline->textbin[MMPLAYER_T_BIN].gst, "text_sink"))
4244 debug_warning("failed to link subparse and textbin\n");
4250 return MM_ERROR_NONE;
4254 return MM_ERROR_PLAYER_INTERNAL;
4257 #ifdef GST_API_VERSION_1
4259 __mmplayer_update_subtitle( GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4261 mm_player_t* player = (mm_player_t*) data;
4262 MMMessageParamType msg = {0, };
4263 GstClockTime duration = 0;
4264 guint8 *text = NULL;
4265 gboolean ret = TRUE;
4270 return_val_if_fail ( player, FALSE );
4271 return_val_if_fail ( buffer, FALSE );
4273 gst_buffer_map (buffer, &info, GST_MAP_WRITE);
4275 gst_buffer_unmap (buffer, &info);
4277 duration = GST_BUFFER_DURATION(buffer);
4279 if ( player->is_subtitle_off )
4281 debug_log("subtitle is OFF.\n" );
4287 debug_log("There is no subtitle to be displayed.\n" );
4291 msg.data = (void *) text;
4292 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4294 debug_warning("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data );
4296 MMPLAYER_POST_MSG( player, MM_MESSAGE_UPDATE_SUBTITLE, &msg );
4304 __mmplayer_update_subtitle( GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4306 mm_player_t* player = (mm_player_t*) data;
4307 MMMessageParamType msg = {0, };
4308 GstClockTime duration = 0;
4309 guint8 *text = NULL;
4310 gboolean ret = TRUE;
4314 return_val_if_fail ( player, FALSE );
4315 return_val_if_fail ( buffer, FALSE );
4317 text = GST_BUFFER_DATA(buffer);
4318 duration = GST_BUFFER_DURATION(buffer);
4320 if ( player->is_subtitle_off )
4322 debug_log("subtitle is OFF.\n" );
4328 debug_log("There is no subtitle to be displayed.\n" );
4332 msg.data = (void *) text;
4333 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4335 debug_warning("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data );
4337 MMPLAYER_POST_MSG( player, MM_MESSAGE_UPDATE_SUBTITLE, &msg );
4345 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
4347 GstEvent* event = NULL;
4348 gint64 current_pos = 0;
4349 gint64 adusted_pos = 0;
4350 gboolean ret = TRUE;
4354 /* check player and subtitlebin are created */
4355 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
4356 return_val_if_fail ( player->play_subtitle, MM_ERROR_NOT_SUPPORT_API );
4360 debug_log ("nothing to do\n");
4361 return MM_ERROR_NONE;
4366 case MM_PLAYER_POS_FORMAT_TIME:
4368 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, ¤t_pos ))
4370 debug_error("failed to get position");
4371 return MM_ERROR_PLAYER_INTERNAL;
4374 adusted_pos = (gint64)current_pos + ((gint64)position * G_GINT64_CONSTANT(1000000));
4375 if (adusted_pos < 0)
4376 adusted_pos = G_GUINT64_CONSTANT(0);
4377 debug_log("adjust subtitle postion : %lu -> %lu [msec]\n", GST_TIME_AS_MSECONDS(current_pos), GST_TIME_AS_MSECONDS(adusted_pos));
4379 event = gst_event_new_seek (1.0, GST_FORMAT_TIME,
4380 ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ),
4381 GST_SEEK_TYPE_SET, adusted_pos,
4382 GST_SEEK_TYPE_SET, -1);
4388 debug_warning("invalid format.\n");
4389 return MM_ERROR_INVALID_ARGUMENT;
4393 /* keep ref to the event */
4394 gst_event_ref (event);
4396 debug_log("sending event[%s] to subparse element [%s]\n",
4397 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SUBPARSE].gst) );
4399 if (gst_element_send_event (player->pipeline->mainbin[MMPLAYER_M_SUBPARSE].gst, event))
4401 debug_log("sending event[%s] to subparse element [%s] success!\n",
4402 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SUBPARSE].gst) );
4405 /* unref to the event */
4406 gst_event_unref (event);
4410 return MM_ERROR_NONE;
4413 #ifdef GST_API_VERSION_1
4415 __gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data) // @
4417 GstElement *appsrc = element;
4418 tBuffer *buf = (tBuffer *)user_data;
4419 GstBuffer *buffer = NULL;
4420 GstFlowReturn ret = GST_FLOW_OK;
4423 return_if_fail ( element );
4424 return_if_fail ( buf );
4426 //buffer = gst_buffer_new ();
4428 if (buf->offset >= buf->len)
4430 debug_log("call eos appsrc\n");
4431 g_signal_emit_by_name (appsrc, "end-of-stream", &ret);
4435 if ( buf->len - buf->offset < size)
4437 len = buf->len - buf->offset + buf->offset;
4440 buffer = gst_buffer_new();
4443 info.data = (guint8*)(buf->buf + buf->offset);
4444 gst_buffer_set_size(buffer, len);
4446 //GST_BUFFER_DATA(buffer) = (guint8*)(buf->buf + buf->offset);
4447 //GST_BUFFER_SIZE(buffer) = len;
4448 GST_BUFFER_OFFSET(buffer) = buf->offset;
4449 GST_BUFFER_OFFSET_END(buffer) = buf->offset + len;
4450 gst_buffer_map (buffer, &info, GST_MAP_WRITE);
4452 debug_log("feed buffer %p, offset %u-%u length %u\n", buffer, buf->offset, buf->len,len);
4453 g_signal_emit_by_name (appsrc, "push-buffer", buffer, &ret);
4459 __gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data) // @
4461 GstElement *appsrc = element;
4462 tBuffer *buf = (tBuffer *)user_data;
4463 GstBuffer *buffer = NULL;
4464 GstFlowReturn ret = GST_FLOW_OK;
4467 return_if_fail ( element );
4468 return_if_fail ( buf );
4470 buffer = gst_buffer_new ();
4472 if (buf->offset >= buf->len)
4474 debug_log("call eos appsrc\n");
4475 g_signal_emit_by_name (appsrc, "end-of-stream", &ret);
4479 if ( buf->len - buf->offset < size)
4481 len = buf->len - buf->offset + buf->offset;
4484 GST_BUFFER_DATA(buffer) = (guint8*)(buf->buf + buf->offset);
4485 GST_BUFFER_SIZE(buffer) = len;
4486 GST_BUFFER_OFFSET(buffer) = buf->offset;
4487 GST_BUFFER_OFFSET_END(buffer) = buf->offset + len;
4489 debug_log("feed buffer %p, offset %u-%u length %u\n", buffer, buf->offset, buf->len,len);
4490 g_signal_emit_by_name (appsrc, "push-buffer", buffer, &ret);
4497 __gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data) // @
4499 tBuffer *buf = (tBuffer *)user_data;
4501 return_val_if_fail ( buf, FALSE );
4503 buf->offset = (int)size;
4509 __gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data) // @
4511 mm_player_t *player = (mm_player_t*)user_data;
4513 return_if_fail ( player );
4515 debug_msg("app-src: feed data\n");
4517 if(player->need_data_cb)
4518 player->need_data_cb(size, player->buffer_cb_user_param);
4522 __gst_appsrc_seek_data(GstElement *element, guint64 offset, gpointer user_data) // @
4524 mm_player_t *player = (mm_player_t*)user_data;
4526 return_val_if_fail ( player, FALSE );
4528 debug_msg("app-src: seek data\n");
4530 if(player->seek_data_cb)
4531 player->seek_data_cb(offset, player->buffer_cb_user_param);
4538 __gst_appsrc_enough_data(GstElement *element, gpointer user_data) // @
4540 mm_player_t *player = (mm_player_t*)user_data;
4542 return_val_if_fail ( player, FALSE );
4544 debug_msg("app-src: enough data:%p\n", player->enough_data_cb);
4546 if(player->enough_data_cb)
4547 player->enough_data_cb(player->buffer_cb_user_param);
4552 #ifdef GST_API_VERSION_1
4554 _mmplayer_push_buffer(MMHandleType hplayer, unsigned char *buf, int size) // @
4556 mm_player_t* player = (mm_player_t*)hplayer;
4557 GstBuffer *buffer = NULL;
4559 GstFlowReturn gst_ret = GST_FLOW_OK;
4560 int ret = MM_ERROR_NONE;
4564 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
4566 /* check current state */
4567 // MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_START );
4570 /* NOTE : we should check and create pipeline again if not created as we destroy
4571 * whole pipeline when stopping in streamming playback
4573 if ( ! player->pipeline )
4575 if ( MM_ERROR_NONE != __gst_realize( player ) )
4577 debug_error("failed to realize before starting. only in streamming\n");
4578 return MM_ERROR_PLAYER_INTERNAL;
4582 debug_msg("app-src: pushing data\n");
4586 debug_error("buf is null\n");
4587 return MM_ERROR_NONE;
4590 buffer = gst_buffer_new ();
4594 debug_log("call eos appsrc\n");
4595 g_signal_emit_by_name (player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "end-of-stream", &gst_ret);
4596 return MM_ERROR_NONE;
4599 info.data = (guint8*)(buf);
4600 gst_buffer_set_size(buffer, size);
4601 gst_buffer_map (buffer, &info, GST_MAP_WRITE);
4603 debug_log("feed buffer %p, length %u\n", buf, size);
4604 g_signal_emit_by_name (player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "push-buffer", buffer, &gst_ret);
4612 _mmplayer_push_buffer(MMHandleType hplayer, unsigned char *buf, int size) // @
4614 mm_player_t* player = (mm_player_t*)hplayer;
4615 GstBuffer *buffer = NULL;
4616 GstFlowReturn gst_ret = GST_FLOW_OK;
4617 int ret = MM_ERROR_NONE;
4621 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
4623 /* check current state */
4624 // MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_START );
4627 /* NOTE : we should check and create pipeline again if not created as we destroy
4628 * whole pipeline when stopping in streamming playback
4630 if ( ! player->pipeline )
4632 if ( MM_ERROR_NONE != __gst_realize( player ) )
4634 debug_error("failed to realize before starting. only in streamming\n");
4635 return MM_ERROR_PLAYER_INTERNAL;
4639 debug_msg("app-src: pushing data\n");
4643 debug_error("buf is null\n");
4644 return MM_ERROR_NONE;
4647 buffer = gst_buffer_new ();
4651 debug_log("call eos appsrc\n");
4652 g_signal_emit_by_name (player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "end-of-stream", &gst_ret);
4653 return MM_ERROR_NONE;
4656 GST_BUFFER_DATA(buffer) = (guint8*)(buf);
4657 GST_BUFFER_SIZE(buffer) = size;
4659 debug_log("feed buffer %p, length %u\n", buf, size);
4660 g_signal_emit_by_name (player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "push-buffer", buffer, &gst_ret);
4668 static GstBusSyncReply
4669 __mmplayer_bus_sync_callback (GstBus * bus, GstMessage * message, gpointer data)
4671 mm_player_t *player = (mm_player_t *)data;
4673 switch (GST_MESSAGE_TYPE (message))
4675 case GST_MESSAGE_TAG:
4676 __mmplayer_gst_extract_tag_from_msg(player, message);
4678 case GST_MESSAGE_DURATION:
4679 __mmplayer_gst_handle_duration(player, message);
4683 return GST_BUS_PASS;
4685 gst_message_unref (message);
4687 return GST_BUS_DROP;
4691 * This function is to create audio or video pipeline for playing.
4693 * @param player [in] handle of player
4695 * @return This function returns zero on success.
4700 __mmplayer_gst_create_pipeline(mm_player_t* player) // @
4703 MMPlayerGstElement *mainbin = NULL;
4704 MMHandleType attrs = 0;
4705 GstElement* element = NULL;
4706 GList* element_bucket = NULL;
4707 gboolean need_state_holder = TRUE;
4712 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4714 /* get profile attribute */
4715 attrs = MMPLAYER_GET_ATTRS(player);
4718 debug_error("cannot get content attribute\n");
4722 /* create pipeline handles */
4723 if ( player->pipeline )
4725 debug_warning("pipeline should be released before create new one\n");
4729 player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0( sizeof(MMPlayerGstPipelineInfo) );
4730 if (player->pipeline == NULL)
4733 memset( player->pipeline, 0, sizeof(MMPlayerGstPipelineInfo) );
4736 /* create mainbin */
4737 mainbin = (MMPlayerGstElement*) g_malloc0( sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM );
4738 if (mainbin == NULL)
4741 memset( mainbin, 0, sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
4744 /* create pipeline */
4745 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4746 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4747 if ( ! mainbin[MMPLAYER_M_PIPE].gst )
4749 debug_error("failed to create pipeline\n");
4754 /* create source element */
4755 switch ( player->profile.uri_type )
4757 /* rtsp streamming */
4758 case MM_PLAYER_URI_TYPE_URL_RTSP:
4760 gint network_bandwidth;
4761 gchar *user_agent, *wap_profile;
4763 element = gst_element_factory_make(PLAYER_INI()->name_of_rtspsrc, "streaming_source");
4767 debug_critical("failed to create streaming source element\n");
4771 debug_log("using streamming source [%s].\n", PLAYER_INI()->name_of_rtspsrc);
4774 network_bandwidth = 0;
4775 user_agent = wap_profile = NULL;
4778 mm_attrs_get_string_by_name ( attrs, "streaming_user_agent", &user_agent );
4779 mm_attrs_get_string_by_name ( attrs,"streaming_wap_profile", &wap_profile );
4780 mm_attrs_get_int_by_name ( attrs, "streaming_network_bandwidth", &network_bandwidth );
4782 debug_log("setting streaming source ----------------\n");
4783 debug_log("user_agent : %s\n", user_agent);
4784 debug_log("wap_profile : %s\n", wap_profile);
4785 debug_log("network_bandwidth : %d\n", network_bandwidth);
4786 debug_log("buffering time : %d\n", PLAYER_INI()->rtsp_buffering_time);
4787 debug_log("rebuffering time : %d\n", PLAYER_INI()->rtsp_rebuffering_time);
4788 debug_log("-----------------------------------------\n");
4790 /* setting property to streaming source */
4791 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
4792 g_object_set(G_OBJECT(element), "bandwidth", network_bandwidth, NULL);
4793 g_object_set(G_OBJECT(element), "buffering_time", PLAYER_INI()->rtsp_buffering_time, NULL);
4794 g_object_set(G_OBJECT(element), "rebuffering_time", PLAYER_INI()->rtsp_rebuffering_time, NULL);
4796 g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL);
4798 g_object_set(G_OBJECT(element), "wap_profile", wap_profile, NULL);
4800 MMPLAYER_SIGNAL_CONNECT ( player, G_OBJECT(element), "pad-added",
4801 G_CALLBACK (__mmplayer_gst_rtp_dynamic_pad), player );
4802 MMPLAYER_SIGNAL_CONNECT ( player, G_OBJECT(element), "no-more-pads",
4803 G_CALLBACK (__mmplayer_gst_rtp_no_more_pads), player );
4805 player->no_more_pad = FALSE;
4806 player->num_dynamic_pad = 0;
4808 /* NOTE : we cannot determine it yet. this filed will be filled by
4809 * _mmplayer_update_content_attrs() after START.
4811 player->streaming_type = STREAMING_SERVICE_NONE;
4816 case MM_PLAYER_URI_TYPE_URL_HTTP:
4818 gchar *user_agent, *proxy, *cookies, **cookie_list;
4819 user_agent = proxy = cookies = NULL;
4821 gint mode = MM_PLAYER_PD_MODE_NONE;
4823 mm_attrs_get_int_by_name ( attrs, "pd_mode", &mode );
4825 player->pd_mode = mode;
4827 debug_log("http playback, PD mode : %d\n", player->pd_mode);
4829 if ( ! MMPLAYER_IS_HTTP_PD(player) )
4831 element = gst_element_factory_make(PLAYER_INI()->name_of_httpsrc, "http_streaming_source");
4834 debug_critical("failed to create http streaming source element[%s].\n", PLAYER_INI()->name_of_httpsrc);
4837 debug_log("using http streamming source [%s].\n", PLAYER_INI()->name_of_httpsrc);
4840 mm_attrs_get_string_by_name ( attrs, "streaming_cookie", &cookies );
4841 mm_attrs_get_string_by_name ( attrs, "streaming_user_agent", &user_agent );
4842 mm_attrs_get_string_by_name ( attrs, "streaming_proxy", &proxy );
4845 debug_log("setting http streaming source ----------------\n");
4846 debug_log("location : %s\n", player->profile.uri);
4847 debug_log("cookies : %s\n", cookies);
4848 debug_log("proxy : %s\n", proxy);
4849 debug_log("user_agent : %s\n", user_agent);
4850 debug_log("timeout : %d\n", PLAYER_INI()->http_timeout);
4851 debug_log("-----------------------------------------\n");
4853 /* setting property to streaming source */
4854 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
4855 g_object_set(G_OBJECT(element), "timeout", PLAYER_INI()->http_timeout, NULL);
4856 /* check if prosy is vailid or not */
4857 if ( util_check_valid_url ( proxy ) )
4858 g_object_set(G_OBJECT(element), "proxy", proxy, NULL);
4859 /* parsing cookies */
4860 if ( ( cookie_list = util_get_cookie_list ((const char*)cookies) ) )
4861 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
4863 g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL);
4865 else // progressive download
4867 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
4871 mm_attrs_get_string_by_name ( attrs, "pd_location", &path );
4873 MMPLAYER_FREEIF(player->pd_file_save_path);
4875 debug_log("PD Location : %s\n", path);
4879 player->pd_file_save_path = g_strdup(path);
4883 debug_error("can't find pd location so, it should be set \n");
4884 return MM_ERROR_PLAYER_FILE_NOT_FOUND;
4888 element = gst_element_factory_make("pdpushsrc", "PD pushsrc");
4891 debug_critical("failed to create PD push source element[%s].\n", "pdpushsrc");
4895 g_object_set(G_OBJECT(element), "location", player->pd_file_save_path, NULL);
4898 player->streaming_type = STREAMING_SERVICE_NONE;
4903 case MM_PLAYER_URI_TYPE_FILE:
4905 char* drmsrc = PLAYER_INI()->name_of_drmsrc;
4907 debug_log("using [%s] for 'file://' handler.\n", drmsrc);
4909 element = gst_element_factory_make(drmsrc, "source");
4912 debug_critical("failed to create %s\n", drmsrc);
4916 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
4917 //g_object_set(G_OBJECT(element), "use-mmap", TRUE, NULL);
4922 case MM_PLAYER_URI_TYPE_BUFF:
4924 guint64 stream_type = GST_APP_STREAM_TYPE_STREAM;
4926 debug_log("mem src is selected\n");
4928 element = gst_element_factory_make("appsrc", "buff-source");
4931 debug_critical("failed to create appsrc element\n");
4935 g_object_set( element, "stream-type", stream_type, NULL );
4936 //g_object_set( element, "size", player->mem_buf.len, NULL );
4937 //g_object_set( element, "blocksize", (guint64)20480, NULL );
4939 MMPLAYER_SIGNAL_CONNECT( player, element, "seek-data",
4940 G_CALLBACK(__gst_appsrc_seek_data), player);
4941 MMPLAYER_SIGNAL_CONNECT( player, element, "need-data",
4942 G_CALLBACK(__gst_appsrc_feed_data), player);
4943 MMPLAYER_SIGNAL_CONNECT( player, element, "enough-data",
4944 G_CALLBACK(__gst_appsrc_enough_data), player);
4949 case MM_PLAYER_URI_TYPE_MEM:
4951 guint64 stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
4953 debug_log("mem src is selected\n");
4955 element = gst_element_factory_make("appsrc", "mem-source");
4958 debug_critical("failed to create appsrc element\n");
4962 g_object_set( element, "stream-type", stream_type, NULL );
4963 g_object_set( element, "size", player->mem_buf.len, NULL );
4964 g_object_set( element, "blocksize", (guint64)20480, NULL );
4966 MMPLAYER_SIGNAL_CONNECT( player, element, "seek-data",
4967 G_CALLBACK(__gst_appsrc_seek_data_mem), &player->mem_buf );
4968 MMPLAYER_SIGNAL_CONNECT( player, element, "need-data",
4969 G_CALLBACK(__gst_appsrc_feed_data_mem), &player->mem_buf );
4972 case MM_PLAYER_URI_TYPE_URL:
4975 case MM_PLAYER_URI_TYPE_TEMP:
4978 case MM_PLAYER_URI_TYPE_NONE:
4983 /* check source element is OK */
4986 debug_critical("no source element was created.\n");
4990 /* take source element */
4991 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4992 mainbin[MMPLAYER_M_SRC].gst = element;
4993 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
4995 if (MMPLAYER_IS_STREAMING(player))
4997 player->streamer = __mm_player_streaming_create();
4998 __mm_player_streaming_initialize(player->streamer);
5001 if ( MMPLAYER_IS_HTTP_PD(player) )
5003 debug_log ("Picked queue2 element....\n");
5004 element = gst_element_factory_make("queue2", "hls_stream_buffer");
5007 debug_critical ( "failed to create http streaming buffer element\n" );
5012 mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_S_BUFFER;
5013 mainbin[MMPLAYER_M_S_BUFFER].gst = element;
5014 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_S_BUFFER]);
5016 __mm_player_streaming_set_buffer(player->streamer,
5019 PLAYER_INI()->http_max_size_bytes,
5021 PLAYER_INI()->http_buffering_limit,
5022 PLAYER_INI()->http_buffering_time,
5028 /* create autoplugging element if src element is not a streamming src */
5029 if ( player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_RTSP )
5033 if( PLAYER_INI()->use_decodebin )
5035 /* create decodebin */
5036 element = gst_element_factory_make("decodebin", "decodebin");
5038 g_object_set(G_OBJECT(element), "async-handling", TRUE, NULL);
5040 /* set signal handler */
5041 MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(element), "new-decoded-pad",
5042 G_CALLBACK(__mmplayer_gst_decode_callback), player);
5044 /* we don't need state holder, bcz decodebin is doing well by itself */
5045 need_state_holder = FALSE;
5049 element = gst_element_factory_make("typefind", "typefinder");
5050 MMPLAYER_SIGNAL_CONNECT( player, element, "have-type",
5051 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player );
5054 /* check autoplug element is OK */
5057 debug_critical("can not create autoplug element\n");
5061 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
5062 mainbin[MMPLAYER_M_AUTOPLUG].gst = element;
5064 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_AUTOPLUG]);
5068 /* add elements to pipeline */
5069 if( !__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket))
5071 debug_error("Failed to add elements to pipeline\n");
5076 /* linking elements in the bucket by added order. */
5077 if ( __mmplayer_gst_element_link_bucket(element_bucket) == -1 )
5079 debug_error("Failed to link some elements\n");
5084 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
5085 if ( need_state_holder )
5088 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
5089 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make ("fakesink", "state-holder");
5091 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
5093 debug_error ("fakesink element could not be created\n");
5096 #ifdef GST_API_VERSION_1
5097 GST_OBJECT_FLAG_UNSET (mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
5099 GST_OBJECT_FLAG_UNSET (mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_IS_SINK);
5102 /* take ownership of fakesink. we are reusing it */
5103 gst_object_ref( mainbin[MMPLAYER_M_SRC_FAKESINK].gst );
5106 if ( FALSE == gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst),
5107 mainbin[MMPLAYER_M_SRC_FAKESINK].gst) )
5109 debug_error("failed to add fakesink to bin\n");
5114 /* now we have completed mainbin. take it */
5115 player->pipeline->mainbin = mainbin;
5117 /* connect bus callback */
5118 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
5121 debug_error ("cannot get bus from pipeline.\n");
5124 player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_callback, player);
5126 /* Note : check whether subtitle atrribute uri is set. If uri is set, then tyr to play subtitle file */
5127 if ( __mmplayer_check_subtitle ( player ) )
5129 if ( MM_ERROR_NONE != __mmplayer_gst_create_subtitle_src(player) )
5130 debug_error("fail to create subtitle src\n")
5133 /* set sync handler to get tag synchronously */
5134 #ifdef GST_API_VERSION_1
5135 gst_bus_set_sync_handler(bus, __mmplayer_bus_sync_callback, player, NULL);
5137 gst_bus_set_sync_handler(bus, __mmplayer_bus_sync_callback, player);
5140 gst_object_unref(GST_OBJECT(bus));
5141 g_list_free(element_bucket);
5145 return MM_ERROR_NONE;
5149 __mmplayer_gst_destroy_pipeline(player);
5150 g_list_free(element_bucket);
5152 /* release element which are not added to bin */
5153 for ( i = 1; i < MMPLAYER_M_NUM; i++ ) /* NOTE : skip pipeline */
5155 if ( mainbin[i].gst )
5157 GstObject* parent = NULL;
5158 parent = gst_element_get_parent( mainbin[i].gst );
5162 gst_object_unref(GST_OBJECT(mainbin[i].gst));
5163 mainbin[i].gst = NULL;
5167 gst_object_unref(GST_OBJECT(parent));
5172 /* release pipeline with it's childs */
5173 if ( mainbin[MMPLAYER_M_PIPE].gst )
5175 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
5178 MMPLAYER_FREEIF( player->pipeline );
5179 MMPLAYER_FREEIF( mainbin );
5181 return MM_ERROR_PLAYER_INTERNAL;
5186 __mmplayer_gst_destroy_pipeline(mm_player_t* player) // @
5189 int ret = MM_ERROR_NONE;
5193 return_val_if_fail ( player, MM_ERROR_INVALID_HANDLE );
5195 /* cleanup stuffs */
5196 MMPLAYER_FREEIF(player->type);
5197 player->have_dynamic_pad = FALSE;
5198 player->no_more_pad = FALSE;
5199 player->num_dynamic_pad = 0;
5201 if (player->v_stream_caps)
5203 gst_caps_unref(player->v_stream_caps);
5204 player->v_stream_caps = NULL;
5207 if (ahs_appsrc_cb_probe_id )
5210 pad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "src" );
5212 #ifdef GST_API_VERSION_1
5213 gst_pad_remove_probe (pad, ahs_appsrc_cb_probe_id);
5215 gst_pad_remove_buffer_probe (pad, ahs_appsrc_cb_probe_id);
5217 gst_object_unref(pad);
5219 ahs_appsrc_cb_probe_id = 0;
5222 if ( player->sink_elements )
5223 g_list_free ( player->sink_elements );
5224 player->sink_elements = NULL;
5226 /* cleanup unlinked mime type */
5227 MMPLAYER_FREEIF(player->unlinked_audio_mime);
5228 MMPLAYER_FREEIF(player->unlinked_video_mime);
5229 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
5231 /* cleanup running stuffs */
5232 __mmplayer_cancel_delayed_eos( player );
5234 /* cleanup gst stuffs */
5235 if ( player->pipeline )
5237 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
5238 GstTagList* tag_list = player->pipeline->tag_list;
5240 /* first we need to disconnect all signal hander */
5241 __mmplayer_release_signal_connection( player );
5243 /* disconnecting bus watch */
5244 if ( player->bus_watcher )
5245 g_source_remove( player->bus_watcher );
5246 player->bus_watcher = 0;
5250 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
5251 MMPlayerGstElement* videobin = player->pipeline->videobin;
5252 MMPlayerGstElement* textbin = player->pipeline->textbin;
5253 GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE (mainbin[MMPLAYER_M_PIPE].gst));
5255 #ifdef GST_API_VERSION_1
5256 gst_bus_set_sync_handler (bus, NULL, NULL, NULL);
5258 gst_bus_set_sync_handler (bus, NULL, NULL);
5260 gst_object_unref(bus);
5262 debug_log("pipeline status before set state to NULL\n");
5263 __mmplayer_dump_pipeline_state( player );
5265 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5266 ret = __mmplayer_gst_set_state ( player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout );
5267 if ( ret != MM_ERROR_NONE )
5269 debug_error("fail to change state to NULL\n");
5270 return MM_ERROR_PLAYER_INTERNAL;
5273 debug_log("pipeline status before unrefering pipeline\n");
5274 __mmplayer_dump_pipeline_state( player );
5276 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
5279 if ( mainbin[MMPLAYER_M_SRC_FAKESINK].gst )
5280 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
5282 /* free avsysaudiosink
5283 avsysaudiosink should be unref when destory pipeline just after start play with BT.
5284 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
5286 MMPLAYER_FREEIF( audiobin );
5287 MMPLAYER_FREEIF( videobin );
5288 MMPLAYER_FREEIF( textbin );
5289 MMPLAYER_FREEIF( mainbin );
5293 gst_tag_list_free(tag_list);
5295 MMPLAYER_FREEIF( player->pipeline );
5298 player->pipeline_is_constructed = FALSE;
5305 static int __gst_realize(mm_player_t* player) // @
5308 int ret = MM_ERROR_NONE;
5312 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5314 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
5316 __ta__("__mmplayer_gst_create_pipeline",
5317 ret = __mmplayer_gst_create_pipeline(player);
5320 debug_critical("failed to create pipeline\n");
5325 /* set pipeline state to READY */
5326 /* NOTE : state change to READY must be performed sync. */
5327 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5328 ret = __mmplayer_gst_set_state(player,
5329 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
5331 if ( ret != MM_ERROR_NONE )
5333 /* return error if failed to set state */
5334 debug_error("failed to set READY state");
5339 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_READY );
5342 /* create dot before error-return. for debugging */
5343 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-realize" );
5350 static int __gst_unrealize(mm_player_t* player) // @
5352 int ret = MM_ERROR_NONE;
5356 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5358 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
5359 MMPLAYER_PRINT_STATE(player);
5361 /* release miscellaneous information */
5362 __mmplayer_release_misc( player );
5364 /* destroy pipeline */
5365 ret = __mmplayer_gst_destroy_pipeline( player );
5366 if ( ret != MM_ERROR_NONE )
5368 debug_error("failed to destory pipeline\n");
5372 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_NULL );
5379 static int __gst_pending_seek ( mm_player_t* player )
5381 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
5382 MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
5383 int ret = MM_ERROR_NONE;
5387 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
5389 if ( !player->pending_seek.is_pending )
5391 debug_log("pending seek is not reserved. nothing to do.\n" );
5395 /* check player state if player could pending seek or not. */
5396 current_state = MMPLAYER_CURRENT_STATE(player);
5397 pending_state = MMPLAYER_PENDING_STATE(player);
5399 if ( current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING )
5401 debug_warning("try to pending seek in %s state, try next time. \n",
5402 MMPLAYER_STATE_GET_NAME(current_state));
5406 debug_log("trying to play from (%lu) pending position\n", player->pending_seek.pos);
5408 ret = __gst_set_position ( player, player->pending_seek.format, player->pending_seek.pos, FALSE );
5410 if ( MM_ERROR_NONE != ret )
5411 debug_error("failed to seek pending postion. just keep staying current position.\n");
5413 player->pending_seek.is_pending = FALSE;
5420 static int __gst_start(mm_player_t* player) // @
5422 gboolean sound_extraction = 0;
5423 int ret = MM_ERROR_NONE;
5427 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
5429 /* get sound_extraction property */
5430 mm_attrs_get_int_by_name(player->attrs, "pcm_extraction", &sound_extraction);
5432 /* NOTE : if SetPosition was called before Start. do it now */
5433 /* streaming doesn't support it. so it should be always sync */
5434 /* !! create one more api to check if there is pending seek rather than checking variables */
5435 if ( (player->pending_seek.is_pending || sound_extraction) && !MMPLAYER_IS_STREAMING(player))
5437 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
5438 ret = __gst_pause(player, FALSE);
5439 if ( ret != MM_ERROR_NONE )
5441 debug_error("failed to set state to PAUSED for pending seek\n");
5445 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
5447 if ( sound_extraction )
5449 debug_log("setting pcm extraction\n");
5451 ret = __mmplayer_set_pcm_extraction(player);
5452 if ( MM_ERROR_NONE != ret )
5454 debug_warning("failed to set pcm extraction\n");
5460 if ( MM_ERROR_NONE != __gst_pending_seek(player) )
5462 debug_warning("failed to seek pending postion. starting from the begin of content.\n");
5467 debug_log("current state before doing transition");
5468 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
5469 MMPLAYER_PRINT_STATE(player);
5471 /* set pipeline state to PLAYING */
5472 ret = __mmplayer_gst_set_state(player,
5473 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player) );
5474 if (ret == MM_ERROR_NONE)
5476 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
5480 debug_error("failed to set state to PLAYING");
5484 /* generating debug info before returning error */
5485 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-start" );
5492 static void __mmplayer_do_sound_fadedown(mm_player_t* player, unsigned int time)
5496 return_if_fail(player
5498 && player->pipeline->audiobin
5499 && player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
5501 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", 2, NULL);
5508 static void __mmplayer_undo_sound_fadedown(mm_player_t* player)
5512 return_if_fail(player
5514 && player->pipeline->audiobin
5515 && player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
5517 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", 0, NULL);
5522 static int __gst_stop(mm_player_t* player) // @
5524 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
5525 MMHandleType attrs = 0;
5526 gboolean fadewown = FALSE;
5527 gboolean rewind = FALSE;
5529 int ret = MM_ERROR_NONE;
5533 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5535 debug_log("current state before doing transition");
5536 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
5537 MMPLAYER_PRINT_STATE(player);
5539 attrs = MMPLAYER_GET_ATTRS(player);
5542 debug_error("cannot get content attribute\n");
5543 return MM_ERROR_PLAYER_INTERNAL;
5546 mm_attrs_get_int_by_name(attrs,"sound_fadedown", &fadewown);
5548 /* enable fadedown */
5550 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
5552 /* Just set state to PAUESED and the rewind. it's usual player behavior. */
5553 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT ( player );
5554 if ( player->profile.uri_type == MM_PLAYER_URI_TYPE_BUFF || player->profile.uri_type == MM_PLAYER_URI_TYPE_HLS)
5556 ret = __mmplayer_gst_set_state(player,
5557 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout );
5561 ret = __mmplayer_gst_set_state( player,
5562 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout );
5564 if ( !MMPLAYER_IS_STREAMING(player))
5568 /* disable fadeout */
5570 __mmplayer_undo_sound_fadedown(player);
5573 /* return if set_state has failed */
5574 if ( ret != MM_ERROR_NONE )
5576 debug_error("failed to set state.\n");
5583 if ( ! __gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
5584 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
5585 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE) )
5587 debug_warning("failed to rewind\n");
5588 ret = MM_ERROR_PLAYER_SEEK;
5593 player->sent_bos = FALSE;
5595 /* wait for seek to complete */
5596 change_ret = gst_element_get_state (player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
5597 if ( change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL )
5599 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_READY );
5603 debug_error("fail to stop player.\n");
5604 ret = MM_ERROR_PLAYER_INTERNAL;
5605 __mmplayer_dump_pipeline_state(player);
5608 /* generate dot file if enabled */
5609 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-stop" );
5616 int __gst_pause(mm_player_t* player, gboolean async) // @
5618 int ret = MM_ERROR_NONE;
5622 return_val_if_fail(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5624 debug_log("current state before doing transition");
5625 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
5626 MMPLAYER_PRINT_STATE(player);
5628 /* set pipeline status to PAUSED */
5629 ret = __mmplayer_gst_set_state(player,
5630 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5632 if ( FALSE == async && ret != MM_ERROR_NONE )
5634 GstMessage *msg = NULL;
5635 GTimer *timer = NULL;
5636 gdouble MAX_TIMEOUT_SEC = 3;
5638 debug_error("failed to set state to PAUSED");
5640 timer = g_timer_new();
5641 g_timer_start(timer);
5643 GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
5644 /* check if gst error posted or not */
5647 msg = gst_bus_timed_pop(bus, GST_SECOND /2);
5650 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR)
5652 GError *error = NULL;
5654 debug_error("paring error posted from bus");
5655 /* parse error code */
5656 gst_message_parse_error(msg, &error, NULL);
5658 if (error->domain == GST_STREAM_ERROR)
5660 ret = __gst_handle_stream_error( player, error, msg );
5662 else if (error->domain == GST_RESOURCE_ERROR)
5664 ret = __gst_handle_resource_error( player, error->code );
5666 else if (error->domain == GST_LIBRARY_ERROR)
5668 ret = __gst_handle_library_error( player, error->code );
5670 else if (error->domain == GST_CORE_ERROR)
5672 ret = __gst_handle_core_error( player, error->code );
5674 player->msg_posted = TRUE;
5676 gst_message_unref(msg);
5678 } while (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC);
5681 gst_object_unref(bus);
5682 g_timer_stop (timer);
5683 g_timer_destroy (timer);
5689 if ( async == FALSE )
5691 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_PAUSED );
5695 /* FIXIT : analyze so called "async problem" */
5697 __gst_set_async_state_change( player, TRUE);
5699 /* generate dot file before returning error */
5700 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-pause" );
5707 int __gst_resume(mm_player_t* player, gboolean async) // @
5709 int ret = MM_ERROR_NONE;
5715 return_val_if_fail(player && player->pipeline,
5716 MM_ERROR_PLAYER_NOT_INITIALIZED);
5718 debug_log("current state before doing transition");
5719 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
5720 MMPLAYER_PRINT_STATE(player);
5722 /* generate dot file before returning error */
5723 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-resume" );
5725 __mmplayer_set_antishock( player , FALSE );
5728 debug_log("do async state transition to PLAYING.\n");
5730 /* clean bus sync handler because it's not needed any more */
5731 bus = gst_pipeline_get_bus (GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
5732 #ifdef GST_API_VERSION_1
5733 gst_bus_set_sync_handler (bus, NULL, NULL, NULL);
5735 gst_bus_set_sync_handler (bus, NULL, NULL);
5737 gst_object_unref(bus);
5739 /* set pipeline state to PLAYING */
5740 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5742 ret = __mmplayer_gst_set_state(player,
5743 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout );
5744 if (ret != MM_ERROR_NONE)
5746 debug_error("failed to set state to PLAYING\n");
5754 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_PLAYING );
5758 /* FIXIT : analyze so called "async problem" */
5760 __gst_set_async_state_change( player, FALSE );
5762 /* generate dot file before returning error */
5763 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-resume" );
5771 __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called) // @
5773 #ifndef GST_API_VERSION_1
5774 GstFormat fmt = GST_FORMAT_TIME;
5776 unsigned long dur_msec = 0;
5777 gint64 dur_nsec = 0;
5778 gint64 pos_nsec = 0;
5779 gboolean ret = TRUE;
5782 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
5783 return_val_if_fail ( !MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP );
5785 if ( MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
5786 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED )
5789 /* check duration */
5790 /* NOTE : duration cannot be zero except live streaming.
5791 * Since some element could have some timing problemn with quering duration, try again.
5793 if ( !player->duration )
5795 #ifdef GST_API_VERSION_1
5796 if ( !gst_element_query_duration( player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec ))
5801 if ( !gst_element_query_duration( player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &fmt, &dur_nsec ))
5806 player->duration = dur_nsec;
5809 if ( player->duration )
5811 dur_msec = GST_TIME_AS_MSECONDS(player->duration);
5815 debug_error("could not get the duration. fail to seek.\n");
5819 debug_log("playback rate: %f\n", player->playback_rate);
5824 case MM_PLAYER_POS_FORMAT_TIME:
5826 /* check position is valid or not */
5827 if ( position > dur_msec )
5830 debug_log("seeking to (%lu) msec, duration is %d msec\n", position, dur_msec);
5832 if (player->doing_seek)
5834 debug_log("not completed seek");
5835 return MM_ERROR_PLAYER_DOING_SEEK;
5838 if ( !internal_called)
5839 player->doing_seek = TRUE;
5841 pos_nsec = position * G_GINT64_CONSTANT(1000000);
5842 ret = __gst_seek ( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
5843 GST_FORMAT_TIME, ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ),
5844 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE );
5847 debug_error("failed to set position. dur[%lu] pos[%lu] pos_msec[%llu]\n", dur_msec, position, pos_nsec);
5853 case MM_PLAYER_POS_FORMAT_PERCENT:
5855 debug_log("seeking to (%lu)%% \n", position);
5857 if (player->doing_seek)
5859 debug_log("not completed seek");
5860 return MM_ERROR_PLAYER_DOING_SEEK;
5863 if ( !internal_called)
5864 player->doing_seek = TRUE;
5866 /* FIXIT : why don't we use 'GST_FORMAT_PERCENT' */
5867 pos_nsec = (gint64) ( ( position * player->duration ) / 100 );
5868 ret = __gst_seek ( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
5869 GST_FORMAT_TIME, ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ),
5870 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE );
5873 debug_error("failed to set position. dur[%lud] pos[%lud] pos_msec[%llud]\n", dur_msec, position, pos_nsec);
5884 /* NOTE : store last seeking point to overcome some bad operation
5885 * ( returning zero when getting current position ) of some elements
5887 player->last_position = pos_nsec;
5889 /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
5890 if ( player->playback_rate > 1.0 )
5891 _mmplayer_set_playspeed ( (MMHandleType)player, player->playback_rate );
5894 return MM_ERROR_NONE;
5897 player->pending_seek.is_pending = TRUE;
5898 player->pending_seek.format = format;
5899 player->pending_seek.pos = position;
5901 debug_warning("player current-state : %s, pending-state : %s, just preserve pending position(%lu).\n",
5902 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)), MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)), player->pending_seek.pos);
5904 return MM_ERROR_NONE;
5907 debug_error("invalid arguments, position : %ld dur : %ld format : %d \n", position, dur_msec, format);
5908 return MM_ERROR_INVALID_ARGUMENT;
5911 player->doing_seek = FALSE;
5912 return MM_ERROR_PLAYER_SEEK;
5915 #define TRICKPLAY_OFFSET GST_MSECOND
5918 __gst_get_position(mm_player_t* player, int format, unsigned long* position) // @
5920 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
5921 #ifndef GST_API_VERSION_1
5922 GstFormat fmt = GST_FORMAT_TIME;
5924 signed long long pos_msec = 0;
5925 gboolean ret = TRUE;
5927 return_val_if_fail( player && position && player->pipeline && player->pipeline->mainbin,
5928 MM_ERROR_PLAYER_NOT_INITIALIZED );
5930 current_state = MMPLAYER_CURRENT_STATE(player);
5932 /* NOTE : query position except paused state to overcome some bad operation
5933 * please refer to below comments in details
5935 if ( current_state != MM_PLAYER_STATE_PAUSED )
5937 #ifdef GST_API_VERSION_1
5938 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
5940 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &fmt, &pos_msec);
5944 /* NOTE : get last point to overcome some bad operation of some elements
5945 * ( returning zero when getting current position in paused state
5946 * and when failed to get postion during seeking
5948 if ( ( current_state == MM_PLAYER_STATE_PAUSED )
5950 //|| ( player->last_position != 0 && pos_msec == 0 ) )
5952 debug_warning ("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS (pos_msec), ret, current_state);
5954 if(player->playback_rate < 0.0)
5955 pos_msec = player->last_position - TRICKPLAY_OFFSET;
5957 pos_msec = player->last_position;
5960 pos_msec = player->last_position;
5962 player->last_position = pos_msec;
5964 debug_warning("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_msec));
5969 player->last_position = pos_msec;
5973 case MM_PLAYER_POS_FORMAT_TIME:
5974 *position = GST_TIME_AS_MSECONDS(pos_msec);
5977 case MM_PLAYER_POS_FORMAT_PERCENT:
5982 dur = player->duration / GST_SECOND;
5985 debug_log ("duration is [%d], so returning position 0\n",dur);
5990 pos = pos_msec / GST_SECOND;
5991 *position = pos * 100 / dur;
5996 return MM_ERROR_PLAYER_INTERNAL;
5999 debug_log("current position : %lu\n", *position);
6002 return MM_ERROR_NONE;
6006 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
6008 GstElement *element = NULL;
6009 GstQuery *query = NULL;
6011 return_val_if_fail( player &&
6013 player->pipeline->mainbin,
6014 MM_ERROR_PLAYER_NOT_INITIALIZED );
6016 return_val_if_fail( start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT );
6018 if ( MMPLAYER_IS_HTTP_STREAMING ( player ))
6020 /* Note : In case of http streaming or HLS, the buffering queue [ queue2 ] could handle buffering query. */
6021 element = GST_ELEMENT ( player->pipeline->mainbin[MMPLAYER_M_S_BUFFER].gst );
6023 else if ( MMPLAYER_IS_RTSP_STREAMING ( player ) )
6025 debug_warning ( "it's not supported yet.\n" );
6026 return MM_ERROR_NONE;
6030 debug_warning ( "it's only used for streaming case.\n" );
6031 return MM_ERROR_NONE;
6039 case MM_PLAYER_POS_FORMAT_PERCENT :
6041 query = gst_query_new_buffering ( GST_FORMAT_PERCENT );
6042 if ( gst_element_query ( element, query ) )
6049 gst_query_parse_buffering_percent ( query, &busy, &percent);
6050 gst_query_parse_buffering_range ( query, &format, &start, &stop, NULL );
6052 debug_log ( "buffering start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT "\n", start, stop);
6055 *start_pos = 100 * start / GST_FORMAT_PERCENT_MAX;
6060 *stop_pos = 100 * stop / GST_FORMAT_PERCENT_MAX;
6064 gst_query_unref (query);
6068 case MM_PLAYER_POS_FORMAT_TIME :
6069 debug_warning ( "Time format is not supported yet.\n" );
6076 debug_log("current buffer position : %lu~%lu \n", *start_pos, *stop_pos );
6078 return MM_ERROR_NONE;
6082 __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param) // @
6088 debug_warning("set_message_callback is called with invalid player handle\n");
6089 return MM_ERROR_PLAYER_NOT_INITIALIZED;
6092 player->msg_cb = callback;
6093 player->msg_cb_param = user_param;
6095 debug_log("msg_cb : 0x%x msg_cb_param : 0x%x\n", (guint)callback, (guint)user_param);
6099 return MM_ERROR_NONE;
6102 static gboolean __mmfplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data) // @
6104 gboolean ret = FALSE;
6109 return_val_if_fail ( uri , FALSE);
6110 return_val_if_fail ( data , FALSE);
6111 return_val_if_fail ( ( strlen(uri) <= MM_MAX_URL_LEN ), FALSE );
6113 memset(data, 0, sizeof(MMPlayerParseProfile));
6115 if ((path = strstr(uri, "file://")))
6117 if (util_exist_file_path(path + 7)) {
6118 strncpy(data->uri, path, MM_MAX_URL_LEN-1);
6120 if ( util_is_sdp_file ( path ) )
6122 debug_log("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
6123 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
6127 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
6133 debug_warning("could access %s.\n", path);
6136 else if ((path = strstr(uri, "buff://")))
6138 data->uri_type = MM_PLAYER_URI_TYPE_BUFF;
6141 else if ((path = strstr(uri, "rtsp://")))
6144 strcpy(data->uri, uri);
6145 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
6149 else if ((path = strstr(uri, "http://")))
6152 strcpy(data->uri, uri);
6153 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
6158 else if ((path = strstr(uri, "https://")))
6161 strcpy(data->uri, uri);
6162 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
6167 else if ((path = strstr(uri, "rtspu://")))
6170 strcpy(data->uri, uri);
6171 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
6175 else if ((path = strstr(uri, "rtspr://")))
6177 strcpy(data->uri, path);
6178 char *separater =strstr(path, "*");
6182 char *urgent = separater + strlen("*");
6184 if ((urgent_len = strlen(urgent))) {
6185 data->uri[strlen(path) - urgent_len - strlen("*")] = '\0';
6186 strcpy(data->urgent, urgent);
6187 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
6192 else if ((path = strstr(uri, "mms://")))
6195 strcpy(data->uri, uri);
6196 data->uri_type = MM_PLAYER_URI_TYPE_URL_MMS;
6200 else if ((path = strstr(uri, "mem://")))
6204 char *buffer = NULL;
6205 char *seperator = strchr(path, ',');
6206 char ext[100] = {0,}, size[100] = {0,};
6209 if ((buffer = strstr(path, "ext="))) {
6210 buffer += strlen("ext=");
6212 if (strlen(buffer)) {
6213 strcpy(ext, buffer);
6215 if ((seperator = strchr(ext, ','))
6216 || (seperator = strchr(ext, ' '))
6217 || (seperator = strchr(ext, '\0'))) {
6218 seperator[0] = '\0';
6223 if ((buffer = strstr(path, "size="))) {
6224 buffer += strlen("size=");
6226 if (strlen(buffer) > 0) {
6227 strcpy(size, buffer);
6229 if ((seperator = strchr(size, ','))
6230 || (seperator = strchr(size, ' '))
6231 || (seperator = strchr(size, '\0'))) {
6232 seperator[0] = '\0';
6235 mem_size = atoi(size);
6240 debug_log("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
6241 if ( mem_size && param) {
6243 data->mem_size = mem_size;
6244 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
6251 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
6252 if (util_exist_file_path(uri))
6254 debug_warning("uri has no protocol-prefix. giving 'file://' by default.\n");
6255 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", uri);
6257 if ( util_is_sdp_file( (char*)uri ) )
6259 debug_log("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
6260 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
6264 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
6270 debug_error ("invalid uri, could not play..\n");
6271 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
6275 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE) {
6279 /* dump parse result */
6280 debug_log("profile parsing result ---\n");
6281 debug_warning("incomming uri : %s\n", uri);
6282 debug_log("uri : %s\n", data->uri);
6283 debug_log("uri_type : %d\n", data->uri_type);
6284 debug_log("play_mode : %d\n", data->play_mode);
6285 debug_log("mem : 0x%x\n", (guint)data->mem);
6286 debug_log("mem_size : %d\n", data->mem_size);
6287 debug_log("urgent : %s\n", data->urgent);
6288 debug_log("--------------------------\n");
6295 gboolean _asm_postmsg(gpointer *data)
6297 mm_player_t* player = (mm_player_t*)data;
6298 MMMessageParamType msg = {0, };
6302 return_val_if_fail ( player, FALSE );
6304 msg.union_type = MM_MSG_UNION_CODE;
6305 msg.code = player->sm.event_src;
6307 MMPLAYER_POST_MSG( player, MM_MESSAGE_READY_TO_RESUME, &msg);
6312 gboolean _asm_lazy_pause(gpointer *data)
6314 mm_player_t* player = (mm_player_t*)data;
6315 int ret = MM_ERROR_NONE;
6319 return_val_if_fail ( player, FALSE );
6321 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING)
6323 debug_log ("Ready to proceed lazy pause\n");
6324 ret = _mmplayer_pause((MMHandleType)player);
6325 if(MM_ERROR_NONE != ret)
6327 debug_error("MMPlayer pause failed in ASM callback lazy pause\n");
6332 debug_log ("Invalid state to proceed lazy pause\n");
6336 if (player->pipeline && player->pipeline->audiobin)
6337 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", 0, NULL);
6339 player->sm.by_asm_cb = 0; //should be reset here
6347 __mmplayer_asm_callback(int handle, ASM_event_sources_t event_src, ASM_sound_commands_t command, unsigned int sound_status, void* cb_data)
6349 mm_player_t* player = (mm_player_t*) cb_data;
6350 ASM_cb_result_t cb_res = ASM_CB_RES_IGNORE;
6351 int result = MM_ERROR_NONE;
6352 gboolean lazy_pause = FALSE;
6356 return_val_if_fail ( player && player->pipeline, ASM_CB_RES_IGNORE );
6357 return_val_if_fail ( player->attrs, MM_ERROR_PLAYER_INTERNAL );
6359 if (player->is_sound_extraction)
6361 debug_log("sound extraction is working...so, asm command is ignored.\n");
6365 player->sm.by_asm_cb = 1; // it should be enabled for player state transition with called application command
6366 player->sm.event_src = event_src;
6368 if(event_src == ASM_EVENT_SOURCE_EARJACK_UNPLUG )
6370 int stop_by_asm = 0;
6372 mm_attrs_get_int_by_name(player->attrs, "sound_stop_when_unplugged", &stop_by_asm);
6376 else if (event_src == ASM_EVENT_SOURCE_RESOURCE_CONFLICT)
6378 /* can use video overlay simultaneously */
6379 /* video resource conflict */
6380 if(player->pipeline->videobin)
6382 if (PLAYER_INI()->multiple_codec_supported)
6384 debug_log("video conflict but, can support to use video overlay simultaneously");
6385 result = _mmplayer_pause((MMHandleType)player);
6386 cb_res = ASM_CB_RES_PAUSE;
6390 debug_log("video conflict, can't support for multiple codec instance");
6391 result = _mmplayer_unrealize((MMHandleType)player);
6392 cb_res = ASM_CB_RES_STOP;
6400 case ASM_COMMAND_PLAY:
6401 debug_warning ("Got unexpected asm command (%d)", command);
6404 case ASM_COMMAND_STOP: // notification case
6406 debug_warning("Got msg from asm to stop");
6408 result = _mmplayer_stop((MMHandleType)player);
6409 if (result != MM_ERROR_NONE)
6411 debug_warning("fail to set stop state by asm");
6412 cb_res = ASM_CB_RES_IGNORE;
6416 cb_res = ASM_CB_RES_STOP;
6418 player->sm.by_asm_cb = 0; // reset because no message any more from asm
6422 case ASM_COMMAND_PAUSE:
6424 debug_warning("Got msg from asm to Pause");
6426 if(event_src == ASM_EVENT_SOURCE_CALL_START
6427 || event_src == ASM_EVENT_SOURCE_ALARM_START
6428 || event_src == ASM_EVENT_SOURCE_MEDIA)
6430 //hold 0.7 second to excute "fadedown mute" effect
6431 debug_warning ("do fade down->pause->undo fade down");
6433 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
6435 result = _mmplayer_pause((MMHandleType)player);
6436 if (result != MM_ERROR_NONE)
6438 debug_warning("fail to set Pause state by asm");
6439 cb_res = ASM_CB_RES_IGNORE;
6442 __mmplayer_undo_sound_fadedown(player);
6444 else if(event_src == ASM_EVENT_SOURCE_OTHER_PLAYER_APP)
6446 lazy_pause = TRUE; // return as soon as possible, for fast start of other app
6448 if ( player->pipeline->audiobin && player->pipeline->audiobin[MMPLAYER_A_SINK].gst )
6449 g_object_set( player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "mute", 2, NULL);
6451 player->lazy_pause_event_id = g_timeout_add(LAZY_PAUSE_TIMEOUT_MSEC, (GSourceFunc)_asm_lazy_pause, (gpointer)player);
6452 debug_warning ("set lazy pause timer (id=[%d], timeout=[%d ms])", player->lazy_pause_event_id, LAZY_PAUSE_TIMEOUT_MSEC);
6457 debug_log ("immediate pause");
6458 result = _mmplayer_pause((MMHandleType)player);
6460 cb_res = ASM_CB_RES_PAUSE;
6464 case ASM_COMMAND_RESUME:
6466 debug_warning("Got msg from asm to Resume. So, application can resume. code (%d) \n", event_src);
6467 player->sm.by_asm_cb = 0;
6468 //ASM server is single thread daemon. So use g_idle_add() to post resume msg
6469 g_idle_add((GSourceFunc)_asm_postmsg, (gpointer)player);
6470 cb_res = ASM_CB_RES_IGNORE;
6479 player->sm.by_asm_cb = 0;
6487 _mmplayer_create_player(MMHandleType handle) // @
6489 mm_player_t* player = MM_PLAYER_CAST(handle);
6493 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6495 MMTA_ACUM_ITEM_BEGIN("[KPI] media player service create->playing", FALSE);
6497 /* initialize player state */
6498 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
6499 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
6500 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
6501 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
6503 /* check current state */
6504 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL ( player, MMPLAYER_COMMAND_CREATE );
6506 /* construct attributes */
6507 player->attrs = _mmplayer_construct_attribute(handle);
6509 if ( !player->attrs )
6511 debug_critical("Failed to construct attributes\n");
6515 /* initialize gstreamer with configured parameter */
6516 if ( ! __mmplayer_gstreamer_init() )
6518 debug_critical("Initializing gstreamer failed\n");
6522 /* initialize factories if not using decodebin */
6523 if ( FALSE == PLAYER_INI()->use_decodebin )
6525 if( player->factories == NULL )
6526 __mmplayer_init_factories(player);
6529 /* create lock. note that g_tread_init() has already called in gst_init() */
6530 player->fsink_lock = g_mutex_new();
6531 if ( ! player->fsink_lock )
6533 debug_critical("Cannot create mutex for command lock\n");
6537 /* create repeat mutex */
6538 player->repeat_thread_mutex = g_mutex_new();
6539 if ( ! player->repeat_thread_mutex )
6541 debug_critical("Cannot create repeat mutex\n");
6545 /* create repeat cond */
6546 player->repeat_thread_cond = g_cond_new();
6547 if ( ! player->repeat_thread_cond )
6549 debug_critical("Cannot create repeat cond\n");
6553 /* create repeat thread */
6554 player->repeat_thread =
6555 g_thread_create (__mmplayer_repeat_thread, (gpointer)player, TRUE, NULL);
6556 if ( ! player->repeat_thread )
6561 if ( MM_ERROR_NONE != _mmplayer_initialize_video_capture(player))
6563 debug_error("failed to initialize video capture\n");
6567 /* register to asm */
6568 if ( MM_ERROR_NONE != _mmplayer_asm_register(&player->sm, (ASM_sound_cb_t)__mmplayer_asm_callback, (void*)player) )
6570 /* NOTE : we are dealing it as an error since we cannot expect it's behavior */
6571 debug_error("failed to register asm server\n");
6572 return MM_ERROR_POLICY_INTERNAL;
6575 if (MMPLAYER_IS_HTTP_PD(player))
6577 player->pd_downloader = NULL;
6578 player->pd_file_save_path = NULL;
6581 /* give default value of audio effect setting */
6582 player->bypass_audio_effect = TRUE;
6583 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
6584 player->playback_rate = DEFAULT_PLAYBACK_RATE;
6586 player->play_subtitle = FALSE;
6587 player->use_textoverlay = FALSE;
6589 /* set player state to null */
6590 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = PLAYER_INI()->localplayback_state_change_timeout;
6591 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_NULL );
6595 return MM_ERROR_NONE;
6599 if ( player->fsink_lock )
6600 g_mutex_free( player->fsink_lock );
6601 player->fsink_lock = NULL;
6604 if ( player->repeat_thread_cond &&
6605 player->repeat_thread_mutex &&
6606 player->repeat_thread )
6608 player->repeat_thread_exit = TRUE;
6609 g_cond_signal( player->repeat_thread_cond );
6611 g_thread_join( player->repeat_thread );
6612 player->repeat_thread = NULL;
6614 g_mutex_free ( player->repeat_thread_mutex );
6615 player->repeat_thread_mutex = NULL;
6617 g_cond_free ( player->repeat_thread_cond );
6618 player->repeat_thread_cond = NULL;
6620 /* clear repeat thread mutex/cond if still alive
6621 * this can happen if only thread creating has failed
6623 if ( player->repeat_thread_mutex )
6624 g_mutex_free ( player->repeat_thread_mutex );
6626 if ( player->repeat_thread_cond )
6627 g_cond_free ( player->repeat_thread_cond );
6629 /* release attributes */
6630 _mmplayer_deconstruct_attribute(handle);
6632 return MM_ERROR_PLAYER_INTERNAL;
6636 __mmplayer_gstreamer_init(void) // @
6638 static gboolean initialized = FALSE;
6639 static const int max_argc = 50;
6641 gchar** argv = NULL;
6649 debug_log("gstreamer already initialized.\n");
6654 argc = malloc( sizeof(int) );
6655 argv = malloc( sizeof(gchar*) * max_argc );
6657 if ( !argc || !argv )
6660 memset( argv, 0, sizeof(gchar*) * max_argc );
6664 argv[0] = g_strdup( "mmplayer" );
6667 for ( i = 0; i < 5; i++ ) /* FIXIT : num of param is now fixed to 5. make it dynamic */
6669 if ( strlen( PLAYER_INI()->gst_param[i] ) > 0 )
6671 argv[*argc] = g_strdup( PLAYER_INI()->gst_param[i] );
6676 /* we would not do fork for scanning plugins */
6677 argv[*argc] = g_strdup("--gst-disable-registry-fork");
6680 /* check disable registry scan */
6681 if ( PLAYER_INI()->skip_rescan )
6683 argv[*argc] = g_strdup("--gst-disable-registry-update");
6687 /* check disable segtrap */
6688 if ( PLAYER_INI()->disable_segtrap )
6690 argv[*argc] = g_strdup("--gst-disable-segtrap");
6694 debug_log("initializing gstreamer with following parameter\n");
6695 debug_log("argc : %d\n", *argc);
6697 for ( i = 0; i < *argc; i++ )
6699 debug_log("argv[%d] : %s\n", i, argv[i]);
6703 /* initializing gstreamer */
6704 __ta__("gst_init time",
6706 if ( ! gst_init_check (argc, &argv, &err))
6708 debug_error("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
6719 for ( i = 0; i < *argc; i++ )
6721 MMPLAYER_FREEIF( argv[i] );
6724 MMPLAYER_FREEIF( argv );
6725 MMPLAYER_FREEIF( argc );
6736 MMPLAYER_FREEIF( argv );
6737 MMPLAYER_FREEIF( argc );
6743 __mmplayer_destroy_streaming_ext(mm_player_t* player)
6745 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6747 if (player->pd_downloader)
6748 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
6750 if (MMPLAYER_IS_HTTP_PD(player))
6751 _mmplayer_destroy_pd_downloader((MMHandleType)player);
6753 if (MMPLAYER_IS_STREAMING(player))
6755 if (player->streamer)
6757 __mm_player_streaming_deinitialize (player->streamer);
6758 __mm_player_streaming_destroy(player->streamer);
6759 player->streamer = NULL;
6762 return MM_ERROR_NONE;
6766 _mmplayer_destroy(MMHandleType handle) // @
6768 mm_player_t* player = MM_PLAYER_CAST(handle);
6772 /* check player handle */
6773 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6775 /* destroy can called at anytime */
6776 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL ( player, MMPLAYER_COMMAND_DESTROY );
6778 __mmplayer_destroy_streaming_ext(player);
6780 /* release repeat thread */
6781 if ( player->repeat_thread_cond &&
6782 player->repeat_thread_mutex &&
6783 player->repeat_thread )
6785 player->repeat_thread_exit = TRUE;
6786 g_cond_signal( player->repeat_thread_cond );
6788 debug_log("waitting for repeat thread exit\n");
6789 g_thread_join ( player->repeat_thread );
6790 g_mutex_free ( player->repeat_thread_mutex );
6791 g_cond_free ( player->repeat_thread_cond );
6792 debug_log("repeat thread released\n");
6795 if (MM_ERROR_NONE != _mmplayer_release_video_capture(player))
6797 debug_error("failed to release video capture\n");
6798 return MM_ERROR_PLAYER_INTERNAL;
6802 if ( MM_ERROR_NONE != _mmplayer_asm_unregister(&player->sm) )
6804 debug_error("failed to deregister asm server\n");
6805 return MM_ERROR_PLAYER_INTERNAL;
6808 /* release pipeline */
6809 if ( MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline( player ) )
6811 debug_error("failed to destory pipeline\n");
6812 return MM_ERROR_PLAYER_INTERNAL;
6815 /* release attributes */
6816 _mmplayer_deconstruct_attribute( handle );
6818 /* release factories */
6819 __mmplayer_release_factories( player );
6822 if ( player->fsink_lock )
6823 g_mutex_free( player->fsink_lock );
6825 if ( player->msg_cb_lock )
6826 g_mutex_free( player->msg_cb_lock );
6828 if (player->lazy_pause_event_id)
6830 g_source_remove (player->lazy_pause_event_id);
6831 player->lazy_pause_event_id = 0;
6836 return MM_ERROR_NONE;
6840 __mmplayer_realize_streaming_ext(mm_player_t* player)
6842 int ret = MM_ERROR_NONE;
6845 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6847 if (MMPLAYER_IS_HTTP_PD(player))
6849 gboolean bret = FALSE;
6851 player->pd_downloader = _mmplayer_create_pd_downloader();
6852 if ( !player->pd_downloader )
6854 debug_error ("Unable to create PD Downloader...");
6855 ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
6858 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
6862 debug_error ("Unable to create PD Downloader...");
6863 ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
6872 _mmplayer_realize(MMHandleType hplayer) // @
6874 mm_player_t* player = (mm_player_t*)hplayer;
6877 int application_pid = -1;
6878 gboolean update_registry = FALSE;
6879 MMHandleType attrs = 0;
6880 int ret = MM_ERROR_NONE;
6884 /* check player handle */
6885 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED )
6887 /* check current state */
6888 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_REALIZE );
6890 attrs = MMPLAYER_GET_ATTRS(player);
6893 debug_error("fail to get attributes.\n");
6894 return MM_ERROR_PLAYER_INTERNAL;
6897 mm_attrs_get_int_by_name(attrs, "sound_application_pid", &application_pid );
6898 player->sm.pid = application_pid;
6900 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
6901 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
6903 if (! __mmfplayer_parse_profile((const char*)uri, param, &player->profile) )
6905 debug_error("failed to parse profile\n");
6906 return MM_ERROR_PLAYER_INVALID_URI;
6909 /* FIXIT : we can use thouse in player->profile directly */
6910 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM)
6912 player->mem_buf.buf = (char *)player->profile.mem;
6913 player->mem_buf.len = player->profile.mem_size;
6914 player->mem_buf.offset = 0;
6917 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS)
6919 debug_warning("mms protocol is not supported format.\n");
6920 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
6923 if (MMPLAYER_IS_STREAMING(player))
6924 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = PLAYER_INI()->live_state_change_timeout;
6926 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = PLAYER_INI()->localplayback_state_change_timeout;
6928 player->videodec_linked = 0;
6929 player->videosink_linked = 0;
6930 player->audiodec_linked = 0;
6931 player->audiosink_linked = 0;
6932 player->textsink_linked = 0;
6934 /* set the subtitle ON default */
6935 player->is_subtitle_off = FALSE;
6937 /* registry should be updated for downloadable codec */
6938 mm_attrs_get_int_by_name(attrs, "profile_update_registry", &update_registry);
6940 if ( update_registry )
6942 debug_log("updating registry...\n");
6943 gst_update_registry();
6945 /* then we have to rebuild factories */
6946 __mmplayer_release_factories( player );
6947 __mmplayer_init_factories(player);
6950 /* realize pipeline */
6951 ret = __gst_realize( player );
6952 if ( ret != MM_ERROR_NONE )
6954 debug_error("fail to realize the player.\n");
6958 ret = __mmplayer_realize_streaming_ext(player);
6967 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
6970 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6972 /* destroy can called at anytime */
6973 if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player))
6975 _mmplayer_unrealize_pd_downloader ((MMHandleType)player);
6976 player->pd_downloader = NULL;
6980 return MM_ERROR_NONE;
6984 _mmplayer_unrealize(MMHandleType hplayer) // @
6986 mm_player_t* player = (mm_player_t*)hplayer;
6987 int ret = MM_ERROR_NONE;
6991 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED )
6993 /* check current state */
6994 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_UNREALIZE );
6996 __mmplayer_unrealize_streaming_ext(player);
6998 /* unrealize pipeline */
6999 ret = __gst_unrealize( player );
7001 /* set player state if success */
7002 if ( MM_ERROR_NONE == ret )
7004 if (player->sm.state != ASM_STATE_STOP) {
7005 ret = _mmplayer_asm_set_state(hplayer, ASM_STATE_STOP);
7008 debug_error("failed to set asm state to STOP\n");
7020 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param) // @
7022 mm_player_t* player = (mm_player_t*)hplayer;
7024 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7026 return __gst_set_message_callback(player, callback, user_param);
7030 _mmplayer_get_state(MMHandleType hplayer, int* state) // @
7032 mm_player_t *player = (mm_player_t*)hplayer;
7034 return_val_if_fail(state, MM_ERROR_INVALID_ARGUMENT);
7036 *state = MMPLAYER_CURRENT_STATE(player);
7038 return MM_ERROR_NONE;
7043 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume) // @
7045 mm_player_t* player = (mm_player_t*) hplayer;
7046 GstElement* vol_element = NULL;
7051 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7053 debug_log("volume [L]=%f:[R]=%f\n",
7054 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
7056 /* invalid factor range or not */
7057 for ( i = 0; i < MM_VOLUME_CHANNEL_NUM; i++ )
7059 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
7060 debug_error("Invalid factor! (valid factor:0~1.0)\n");
7061 return MM_ERROR_INVALID_ARGUMENT;
7065 /* Save volume to handle. Currently the first array element will be saved. */
7066 player->sound.volume = volume.level[0];
7068 /* check pipeline handle */
7069 if ( ! player->pipeline || ! player->pipeline->audiobin )
7071 debug_log("audiobin is not created yet\n");
7072 debug_log("but, current stored volume will be set when it's created.\n");
7074 /* NOTE : stored volume will be used in create_audiobin
7075 * returning MM_ERROR_NONE here makes application to able to
7076 * set volume at anytime.
7078 return MM_ERROR_NONE;
7081 /* setting volume to volume element */
7082 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
7086 debug_log("volume is set [%f]\n", player->sound.volume);
7087 g_object_set(vol_element, "volume", player->sound.volume, NULL);
7092 return MM_ERROR_NONE;
7097 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
7099 mm_player_t* player = (mm_player_t*) hplayer;
7104 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7105 return_val_if_fail( volume, MM_ERROR_INVALID_ARGUMENT );
7107 /* returning stored volume */
7108 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
7109 volume->level[i] = player->sound.volume;
7113 return MM_ERROR_NONE;
7119 _mmplayer_set_mute(MMHandleType hplayer, int mute) // @
7121 mm_player_t* player = (mm_player_t*) hplayer;
7122 GstElement* vol_element = NULL;
7126 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7128 debug_log("mute : %d\n", mute);
7130 /* mute value shoud 0 or 1 */
7131 if ( mute != 0 && mute != 1 )
7133 debug_error("bad mute value\n");
7135 /* FIXIT : definitly, we need _BAD_PARAM error code */
7136 return MM_ERROR_INVALID_ARGUMENT;
7140 /* just hold mute value if pipeline is not ready */
7141 if ( !player->pipeline || !player->pipeline->audiobin )
7143 debug_log("pipeline is not ready. holding mute value\n");
7144 player->sound.mute = mute;
7145 return MM_ERROR_NONE;
7149 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
7151 /* NOTE : volume will only created when the bt is enabled */
7154 g_object_set(vol_element, "mute", mute, NULL);
7158 debug_log("volume elemnet is not created. using volume in audiosink\n");
7161 player->sound.mute = mute;
7165 return MM_ERROR_NONE;
7169 _mmplayer_get_mute(MMHandleType hplayer, int* pmute) // @
7171 mm_player_t* player = (mm_player_t*) hplayer;
7172 GstElement* vol_element = NULL;
7176 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7177 return_val_if_fail ( pmute, MM_ERROR_INVALID_ARGUMENT );
7179 /* just hold mute value if pipeline is not ready */
7180 if ( !player->pipeline || !player->pipeline->audiobin )
7182 debug_log("pipeline is not ready. returning stored value\n");
7183 *pmute = player->sound.mute;
7184 return MM_ERROR_NONE;
7188 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
7192 g_object_get(vol_element, "mute", pmute, NULL);
7193 debug_log("mute=%d\n\n", *pmute);
7197 *pmute = player->sound.mute;
7202 return MM_ERROR_NONE;
7206 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param) // @
7208 mm_player_t* player = (mm_player_t*) hplayer;
7212 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7213 return_val_if_fail ( callback, MM_ERROR_INVALID_ARGUMENT );
7215 player->video_stream_cb = callback;
7216 player->video_stream_cb_user_param = user_param;
7217 player->use_video_stream = TRUE;
7218 debug_log("Stream cb Handle value is %p : %p\n", player, player->video_stream_cb);
7222 return MM_ERROR_NONE;
7226 _mmplayer_set_audiostream_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param) // @
7228 mm_player_t* player = (mm_player_t*) hplayer;
7232 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7233 return_val_if_fail(callback, MM_ERROR_INVALID_ARGUMENT);
7235 player->audio_stream_cb = callback;
7236 player->audio_stream_cb_user_param = user_param;
7237 debug_log("Audio Stream cb Handle value is %p : %p\n", player, player->audio_stream_cb);
7241 return MM_ERROR_NONE;
7245 _mmplayer_set_audiobuffer_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param) // @
7247 mm_player_t* player = (mm_player_t*) hplayer;
7251 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7252 return_val_if_fail(callback, MM_ERROR_INVALID_ARGUMENT);
7254 player->audio_buffer_cb = callback;
7255 player->audio_buffer_cb_user_param = user_param;
7256 debug_log("Audio Stream cb Handle value is %p : %p\n", player, player->audio_buffer_cb);
7260 return MM_ERROR_NONE;
7264 _mmplayer_set_buffer_need_data_cb(MMHandleType hplayer, mm_player_buffer_need_data_callback callback, void *user_param) // @
7266 mm_player_t* player = (mm_player_t*) hplayer;
7270 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
7271 return_val_if_fail(callback, MM_ERROR_INVALID_ARGUMENT);
7273 player->need_data_cb = callback;
7274 player->buffer_cb_user_param = user_param;
7276 debug_log("buffer need dataHandle value is %p : %p\n", player, player->need_data_cb);
7280 return MM_ERROR_NONE;
7284 _mmplayer_set_buffer_enough_data_cb(MMHandleType hplayer, mm_player_buffer_enough_data_callback callback, void *user_param) // @
7286 mm_player_t* player = (mm_player_t*) hplayer;
7290 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
7291 return_val_if_fail(callback, MM_ERROR_INVALID_ARGUMENT);
7293 player->enough_data_cb = callback;
7294 player->buffer_cb_user_param = user_param;
7296 debug_log("buffer enough data cb Handle value is %p : %p\n", player, player->enough_data_cb);
7300 return MM_ERROR_NONE;
7304 _mmplayer_set_buffer_seek_data_cb(MMHandleType hplayer, mm_player_buffer_seek_data_callback callback, void *user_param) // @
7306 mm_player_t* player = (mm_player_t*) hplayer;
7310 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
7311 return_val_if_fail(callback, MM_ERROR_INVALID_ARGUMENT);
7313 player->seek_data_cb = callback;
7314 player->buffer_cb_user_param = user_param;
7316 debug_log("buffer seek data cb Handle value is %p : %p\n", player, player->seek_data_cb);
7320 return MM_ERROR_NONE;
7324 _mmplayer_set_videoframe_render_error_cb(MMHandleType hplayer, mm_player_video_frame_render_error_callback callback, void *user_param) // @
7326 mm_player_t* player = (mm_player_t*) hplayer;
7330 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7331 return_val_if_fail ( callback, MM_ERROR_INVALID_ARGUMENT );
7333 player->video_frame_render_error_cb = callback;
7334 player->video_frame_render_error_cb_user_param = user_param;
7336 debug_log("Video frame render error cb Handle value is %p : %p\n", player, player->video_frame_render_error_cb);
7340 return MM_ERROR_NONE;
7344 __mmplayer_start_streaming_ext(mm_player_t *player)
7346 gint ret = MM_ERROR_NONE;
7349 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7351 if (MMPLAYER_IS_HTTP_PD(player))
7353 if ( !player->pd_downloader )
7355 ret = __mmplayer_realize_streaming_ext(player);
7357 if ( ret != MM_ERROR_NONE)
7359 debug_error ("failed to realize streaming ext\n");
7364 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI)
7366 ret = _mmplayer_start_pd_downloader ((MMHandleType)player);
7369 debug_error ("ERROR while starting PD...\n");
7370 return MM_ERROR_PLAYER_NOT_INITIALIZED;
7372 ret = MM_ERROR_NONE;
7381 _mmplayer_start(MMHandleType hplayer) // @
7383 mm_player_t* player = (mm_player_t*) hplayer;
7384 gint ret = MM_ERROR_NONE;
7388 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7390 /* check current state */
7391 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_START );
7393 ret = _mmplayer_asm_set_state(hplayer, ASM_STATE_PLAYING);
7394 if ( ret != MM_ERROR_NONE )
7396 debug_error("failed to set asm state to PLAYING\n");
7400 /* NOTE : we should check and create pipeline again if not created as we destroy
7401 * whole pipeline when stopping in streamming playback
7403 if ( ! player->pipeline )
7405 ret = __gst_realize( player );
7406 if ( MM_ERROR_NONE != ret )
7408 debug_error("failed to realize before starting. only in streamming\n");
7413 ret = __mmplayer_start_streaming_ext(player);
7414 if ( ret != MM_ERROR_NONE )
7416 debug_error("failed to start streaming ext \n");
7419 /* start pipeline */
7420 ret = __gst_start( player );
7421 if ( ret != MM_ERROR_NONE )
7423 debug_error("failed to start player.\n");
7431 /* NOTE: post "not supported codec message" to application
7432 * when one codec is not found during AUTOPLUGGING in MSL.
7433 * So, it's separated with error of __mmplayer_gst_callback().
7434 * And, if any codec is not found, don't send message here.
7435 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
7438 __mmplayer_handle_missed_plugin(mm_player_t* player)
7440 MMMessageParamType msg_param;
7441 memset (&msg_param, 0, sizeof(MMMessageParamType));
7442 gboolean post_msg_direct = FALSE;
7446 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7448 debug_log("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
7449 player->not_supported_codec, player->can_support_codec);
7451 if( player->not_found_demuxer )
7453 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
7454 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
7456 MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param );
7457 MMPLAYER_FREEIF(msg_param.data);
7459 return MM_ERROR_NONE;
7462 if (player->not_supported_codec)
7464 if ( player->can_support_codec ) // There is one codec to play
7466 post_msg_direct = TRUE;
7470 if ( player->pipeline->audiobin ) // Some content has only PCM data in container.
7471 post_msg_direct = TRUE;
7474 if ( post_msg_direct )
7476 MMMessageParamType msg_param;
7477 memset (&msg_param, 0, sizeof(MMMessageParamType));
7479 if ( player->not_supported_codec == MISSING_PLUGIN_AUDIO )
7481 debug_warning("not found AUDIO codec, posting error code to application.\n");
7483 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
7484 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
7486 else if ( player->not_supported_codec == MISSING_PLUGIN_VIDEO )
7488 debug_warning("not found VIDEO codec, posting error code to application.\n");
7490 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
7491 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
7494 MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param );
7496 MMPLAYER_FREEIF(msg_param.data);
7498 return MM_ERROR_NONE;
7500 else // no any supported codec case
7502 debug_warning("not found any codec, posting error code to application.\n");
7504 if ( player->not_supported_codec == MISSING_PLUGIN_AUDIO )
7506 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
7507 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
7511 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
7512 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
7515 MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param );
7517 MMPLAYER_FREEIF(msg_param.data);
7523 return MM_ERROR_NONE;
7526 /* NOTE : it should be able to call 'stop' anytime*/
7528 _mmplayer_stop(MMHandleType hplayer) // @
7530 mm_player_t* player = (mm_player_t*)hplayer;
7531 int ret = MM_ERROR_NONE;
7535 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7537 /* check current state */
7538 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_STOP );
7540 /* NOTE : application should not wait for EOS after calling STOP */
7541 __mmplayer_cancel_delayed_eos( player );
7543 __mmplayer_unrealize_streaming_ext(player);
7546 ret = __gst_stop( player );
7548 if ( ret != MM_ERROR_NONE )
7550 debug_error("failed to stop player.\n");
7559 _mmplayer_pause(MMHandleType hplayer) // @
7561 mm_player_t* player = (mm_player_t*)hplayer;
7562 #ifndef GST_API_VERSION_1
7563 GstFormat fmt = GST_FORMAT_TIME;
7565 gint64 pos_msec = 0;
7566 gboolean async = FALSE;
7567 gint ret = MM_ERROR_NONE;
7571 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7573 /* check current state */
7574 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_PAUSE );
7576 switch (MMPLAYER_CURRENT_STATE(player))
7578 case MM_PLAYER_STATE_READY:
7580 /* check prepare async or not.
7581 * In the case of streaming playback, it's recommned to avoid blocking wait.
7583 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
7584 debug_log("prepare mode : %s", (async ? "async" : "sync"));
7588 case MM_PLAYER_STATE_PLAYING:
7590 /* NOTE : store current point to overcome some bad operation
7591 * ( returning zero when getting current position in paused state) of some
7594 #ifdef GST_API_VERSION_1
7595 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
7597 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &fmt, &pos_msec);
7600 debug_warning("getting current position failed in paused\n");
7602 player->last_position = pos_msec;
7607 /* pause pipeline */
7608 ret = __gst_pause( player, async );
7610 if ( ret != MM_ERROR_NONE )
7612 debug_error("failed to pause player. ret : 0x%x\n", ret);
7621 _mmplayer_resume(MMHandleType hplayer)
7623 mm_player_t* player = (mm_player_t*)hplayer;
7624 int ret = MM_ERROR_NONE;
7625 gboolean async = FALSE;
7629 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7631 ret = _mmplayer_asm_set_state(hplayer, ASM_STATE_PLAYING);
7634 debug_error("failed to set asm state to PLAYING\n");
7638 /* check current state */
7639 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_RESUME );
7641 /* resume pipeline */
7642 ret = __gst_resume( player, FALSE );
7644 if ( ret != MM_ERROR_NONE )
7646 debug_error("failed to resume player.\n");
7656 __mmplayer_set_play_count(mm_player_t* player, gint count)
7658 MMHandleType attrs = 0;
7662 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7664 attrs = MMPLAYER_GET_ATTRS(player);
7667 debug_error("fail to get attributes.\n");
7668 return MM_ERROR_PLAYER_INTERNAL;
7671 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
7672 if ( mmf_attrs_commit ( attrs ) ) /* return -1 if error */
7673 debug_error("failed to commit\n");
7677 return MM_ERROR_NONE;
7681 _mmplayer_activate_section_repeat(MMHandleType hplayer, unsigned long start, unsigned long end)
7683 mm_player_t* player = (mm_player_t*)hplayer;
7684 gint64 start_pos = 0;
7690 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7691 return_val_if_fail ( end <= GST_TIME_AS_MSECONDS(player->duration), MM_ERROR_INVALID_ARGUMENT );
7693 player->section_repeat = TRUE;
7694 player->section_repeat_start = start;
7695 player->section_repeat_end = end;
7697 start_pos = player->section_repeat_start * G_GINT64_CONSTANT(1000000);
7698 end_pos = player->section_repeat_end * G_GINT64_CONSTANT(1000000);
7700 __mmplayer_set_play_count( player, infinity );
7702 if ( (!__gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
7703 player->playback_rate,
7705 ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ),
7706 GST_SEEK_TYPE_SET, start_pos,
7707 GST_SEEK_TYPE_SET, end_pos)))
7709 debug_error("failed to activate section repeat\n");
7711 return MM_ERROR_PLAYER_SEEK;
7714 debug_log("succeeded to set section repeat from %d to %d\n",
7715 player->section_repeat_start, player->section_repeat_end);
7719 return MM_ERROR_NONE;
7723 __mmplayer_set_pcm_extraction(mm_player_t* player)
7725 guint64 start_nsec = 0;
7726 guint64 end_nsec = 0;
7727 guint64 dur_nsec = 0;
7728 guint64 dur_msec = 0;
7729 #ifndef GST_API_VERSION_1
7730 GstFormat fmt = GST_FORMAT_TIME;
7732 int required_start = 0;
7733 int required_end = 0;
7738 return_val_if_fail( player, FALSE );
7740 mm_attrs_multiple_get(player->attrs,
7742 "pcm_extraction_start_msec", &required_start,
7743 "pcm_extraction_end_msec", &required_end,
7746 debug_log("pcm extraction required position is from [%d] to [%d] (msec)\n", required_start, required_end);
7748 if (required_start == 0 && required_end == 0)
7750 debug_log("extracting entire stream");
7751 return MM_ERROR_NONE;
7753 else if (required_start < 0 || required_start > required_end || required_end < 0 )
7755 debug_log("invalid range for pcm extraction");
7756 return MM_ERROR_INVALID_ARGUMENT;
7760 #ifdef GST_API_VERSION_1
7761 ret = gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec);
7763 ret = gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &fmt, &dur_nsec);
7767 debug_error("failed to get duration");
7768 return MM_ERROR_PLAYER_INTERNAL;
7770 dur_msec = GST_TIME_AS_MSECONDS(dur_nsec);
7772 if (dur_msec < required_end) // FIXME
7774 debug_log("invalid end pos for pcm extraction");
7775 return MM_ERROR_INVALID_ARGUMENT;
7778 start_nsec = required_start * G_GINT64_CONSTANT(1000000);
7779 end_nsec = required_end * G_GINT64_CONSTANT(1000000);
7781 if ( (!__gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
7784 ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ),
7785 GST_SEEK_TYPE_SET, start_nsec,
7786 GST_SEEK_TYPE_SET, end_nsec)))
7788 debug_error("failed to seek for pcm extraction\n");
7790 return MM_ERROR_PLAYER_SEEK;
7793 debug_log("succeeded to set up segment extraction from [%llu] to [%llu] (nsec)\n", start_nsec, end_nsec);
7797 return MM_ERROR_NONE;
7801 _mmplayer_deactivate_section_repeat(MMHandleType hplayer)
7803 mm_player_t* player = (mm_player_t*)hplayer;
7805 #ifndef GST_API_VERSION_1
7806 GstFormat fmt = GST_FORMAT_TIME;
7812 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7814 player->section_repeat = FALSE;
7816 __mmplayer_set_play_count( player, onetime );
7817 #ifdef GST_API_VERSION_1
7818 gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_pos);
7820 gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &fmt, &cur_pos);
7823 if ( (!__gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
7826 ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ),
7827 GST_SEEK_TYPE_SET, cur_pos,
7828 GST_SEEK_TYPE_SET, player->duration )))
7830 debug_error("failed to deactivate section repeat\n");
7832 return MM_ERROR_PLAYER_SEEK;
7837 return MM_ERROR_NONE;
7841 _mmplayer_set_playspeed(MMHandleType hplayer, gdouble rate)
7843 mm_player_t* player = (mm_player_t*)hplayer;
7844 signed long long pos_msec = 0;
7845 int ret = MM_ERROR_NONE;
7847 #ifndef GST_API_VERSION_1
7848 GstFormat format =GST_FORMAT_TIME;
7850 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7853 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
7854 return_val_if_fail ( !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API );
7856 /* The sound of video is not supported under 0.0 and over 2.0. */
7857 if(rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN)
7859 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
7862 _mmplayer_set_mute(hplayer, mute);
7864 if (player->playback_rate == rate)
7865 return MM_ERROR_NONE;
7867 /* If the position is reached at start potion during fast backward, EOS is posted.
7868 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
7870 player->playback_rate = rate;
7872 current_state = MMPLAYER_CURRENT_STATE(player);
7873 #ifdef GST_API_VERSION_1
7874 if ( current_state != MM_PLAYER_STATE_PAUSED )
7875 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
7877 if ( current_state != MM_PLAYER_STATE_PAUSED )
7878 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &format, &pos_msec);
7881 debug_log ("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS (pos_msec), ret, current_state);
7883 if ( ( current_state == MM_PLAYER_STATE_PAUSED )
7885 //|| ( player->last_position != 0 && pos_msec == 0 ) )
7887 debug_warning("returning last point : %lld\n", player->last_position );
7888 pos_msec = player->last_position;
7891 if ((!gst_element_seek (player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
7894 ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ),
7895 //( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_KEY_UNIT),
7896 GST_SEEK_TYPE_SET, pos_msec,
7897 //GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE,
7898 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)))
7900 debug_error("failed to set speed playback\n");
7901 return MM_ERROR_PLAYER_SEEK;
7904 debug_log("succeeded to set speed playback as %fl\n", rate);
7908 return MM_ERROR_NONE;;
7912 _mmplayer_set_position(MMHandleType hplayer, int format, int position) // @
7914 mm_player_t* player = (mm_player_t*)hplayer;
7915 int ret = MM_ERROR_NONE;
7919 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7921 ret = __gst_set_position ( player, format, (unsigned long)position, FALSE );
7929 _mmplayer_get_position(MMHandleType hplayer, int format, unsigned long *position) // @
7931 mm_player_t* player = (mm_player_t*)hplayer;
7932 int ret = MM_ERROR_NONE;
7934 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7936 ret = __gst_get_position ( player, format, position );
7942 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos) // @
7944 mm_player_t* player = (mm_player_t*)hplayer;
7945 int ret = MM_ERROR_NONE;
7947 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7949 ret = __gst_get_buffer_position ( player, format, start_pos, stop_pos );
7955 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position) // @
7957 mm_player_t* player = (mm_player_t*)hplayer;
7958 int ret = MM_ERROR_NONE;
7962 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7964 ret = __gst_adjust_subtitle_position(player, format, position);
7972 __mmplayer_is_midi_type( gchar* str_caps)
7974 if ( ( g_strrstr(str_caps, "audio/midi") ) ||
7975 ( g_strrstr(str_caps, "application/x-gst_ff-mmf") ) ||
7976 ( g_strrstr(str_caps, "application/x-smaf") ) ||
7977 ( g_strrstr(str_caps, "audio/x-imelody") ) ||
7978 ( g_strrstr(str_caps, "audio/mobile-xmf") ) ||
7979 ( g_strrstr(str_caps, "audio/xmf") ) ||
7980 ( g_strrstr(str_caps, "audio/mxmf") ) )
7982 debug_log("midi\n");
7991 __mmplayer_is_amr_type (gchar *str_caps)
7993 if ((g_strrstr(str_caps, "AMR")) ||
7994 (g_strrstr(str_caps, "amr")))
8002 __mmplayer_is_only_mp3_type (gchar *str_caps)
8004 if (g_strrstr(str_caps, "application/x-id3") ||
8005 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
8013 __mmplayer_typefind_have_type( GstElement *tf, guint probability, // @
8014 GstCaps *caps, gpointer data)
8016 mm_player_t* player = (mm_player_t*)data;
8021 return_if_fail( player && tf && caps );
8023 /* store type string */
8024 MMPLAYER_FREEIF(player->type);
8025 player->type = gst_caps_to_string(caps);
8027 debug_log("meida type %s found, probability %d%% / %d\n", player->type, probability, gst_caps_get_size(caps));
8029 /* midi type should be stored because it will be used to set audio gain in avsysaudiosink */
8030 if ( __mmplayer_is_midi_type(player->type))
8032 player->profile.play_mode = MM_PLAYER_MODE_MIDI;
8034 else if (__mmplayer_is_amr_type(player->type))
8036 player->bypass_audio_effect = FALSE;
8037 if ( (PLAYER_INI()->use_audio_effect_preset || PLAYER_INI()->use_audio_effect_custom) )
8039 if ( player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_PRESET )
8041 if (!_mmplayer_audio_effect_preset_apply(player, player->audio_effect_info.preset))
8043 debug_msg("apply audio effect(preset:%d) setting success\n",player->audio_effect_info.preset);
8046 else if ( player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM )
8048 if (!_mmplayer_audio_effect_custom_apply(player))
8050 debug_msg("apply audio effect(custom) setting success\n");
8055 else if ( g_strrstr(player->type, "application/x-hls"))
8057 /* If it can't know exact type when it parses uri because of redirection case,
8058 * it will be fixed by typefinder here.
8060 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
8063 pad = gst_element_get_static_pad(tf, "src");
8066 debug_error("fail to get typefind src pad.\n");
8071 if ( ! __mmplayer_try_to_plug( player, pad, caps ) )
8073 gboolean async = FALSE;
8075 debug_error("failed to autoplug %s\n", player->type);
8076 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
8078 if ( async && player->msg_posted == FALSE )
8080 __mmplayer_handle_missed_plugin( player );
8086 /* finish autopluging if no dynamic pad waiting */
8087 if( ( ! player->have_dynamic_pad) && ( ! player->has_many_types) )
8089 if ( ! MMPLAYER_IS_RTSP_STREAMING( player ) )
8091 __mmplayer_pipeline_complete( NULL, (gpointer)player );
8096 gst_object_unref( GST_OBJECT(pad) );
8104 __mmplayer_warm_up_video_codec( mm_player_t* player, GstElementFactory *factory)
8106 GstElement *element;
8107 GstStateChangeReturn ret;
8108 gboolean usable = TRUE;
8110 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
8111 return_val_if_fail ( factory, MM_ERROR_COMMON_INVALID_ARGUMENT );
8113 element = gst_element_factory_create (factory, NULL);
8115 ret = gst_element_set_state (element, GST_STATE_READY);
8117 if (ret != GST_STATE_CHANGE_SUCCESS)
8119 #ifdef GST_API_VERSION_1
8120 debug_error ("resource conflict so, %s unusable\n", gst_object_get_name (GST_OBJECT (factory)));
8122 debug_error ("resource conflict so, %s unusable\n", GST_PLUGIN_FEATURE_NAME (factory));
8127 gst_element_set_state (element, GST_STATE_NULL);
8128 gst_object_unref (element);
8133 /* it will return first created element */
8135 __mmplayer_try_to_plug(mm_player_t* player, GstPad *pad, const GstCaps *caps) // @
8137 MMPlayerGstElement* mainbin = NULL;
8138 const char* mime = NULL;
8139 const GList* item = NULL;
8140 const gchar* klass = NULL;
8141 GstCaps* res = NULL;
8142 gboolean skip = FALSE;
8143 GstPad* queue_pad = NULL;
8144 GstElement* queue = NULL;
8145 GstElement *element = NULL;
8149 return_val_if_fail( player && player->pipeline && player->pipeline->mainbin, FALSE );
8151 mainbin = player->pipeline->mainbin;
8153 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
8155 /* return if we got raw output */
8156 if(g_str_has_prefix(mime, "video/x-raw") || g_str_has_prefix(mime, "audio/x-raw")
8157 || g_str_has_prefix(mime, "video/x-surface")
8158 || g_str_has_prefix(mime, "text/plain") ||g_str_has_prefix(mime, "text/x-pango-markup"))
8161 element = (GstElement*)gst_pad_get_parent(pad);
8162 /* NOTE : When no decoder has added during autoplugging. like a simple wave playback.
8163 * No queue will be added. I think it can caused breaking sound when playing raw audio
8164 * frames but there's no different. Decodebin also doesn't add with those wav fils.
8165 * Anyway, currentely raw-queue seems not necessary.
8168 /* NOTE : check if previously linked element is demuxer/depayloader/parse means no decoder
8169 * has linked. if so, we need to add queue for quality of output. note that
8170 * decodebin also has same problem.
8172 klass = gst_element_factory_get_klass( gst_element_get_factory(element) );
8174 /* add queue if needed */
8175 if( (g_strrstr(klass, "Demux") || g_strrstr(klass, "Depayloader")
8176 || g_strrstr(klass, "Parse")) && !g_str_has_prefix(mime, "text"))
8178 debug_log("adding raw queue\n");
8180 queue = gst_element_factory_make("queue", NULL);
8183 debug_warning("failed to create queue\n");
8188 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_READY) )
8190 debug_warning("failed to set state READY to queue\n");
8194 /* add to pipeline */
8195 if ( ! gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue) )
8197 debug_warning("failed to add queue\n");
8202 queue_pad = gst_element_get_static_pad(queue, "sink");
8204 if ( GST_PAD_LINK_OK != gst_pad_link(pad, queue_pad) )
8206 debug_warning("failed to link queue\n");
8209 gst_object_unref ( GST_OBJECT(queue_pad) );
8213 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_PAUSED) )
8215 debug_warning("failed to set state READY to queue\n");
8219 /* replace given pad to queue:src */
8220 pad = gst_element_get_static_pad(queue, "src");
8223 debug_warning("failed to get pad from queue\n");
8228 /* check if player can do start continually */
8229 MMPLAYER_CHECK_CMD_IF_EXIT(player);
8231 if(__mmplayer_link_sink(player,pad))
8232 __mmplayer_gst_decode_callback(element, pad, FALSE, player);
8234 gst_object_unref( GST_OBJECT(element));
8240 item = player->factories;
8241 for(; item != NULL ; item = item->next)
8243 GstElementFactory *factory = GST_ELEMENT_FACTORY(item->data);
8249 /* filtering exclude keyword */
8250 #ifdef GST_API_VERSION_1
8251 for ( idx = 0; PLAYER_INI()->exclude_element_keyword[idx][0] != '\0'; idx++ )
8253 if ( g_strrstr(gst_object_get_name (GST_OBJECT (factory)),
8254 PLAYER_INI()->exclude_element_keyword[idx]) )
8256 debug_warning("skipping [%s] by exculde keyword [%s]\n",
8257 gst_object_get_name (GST_OBJECT (factory)),
8258 PLAYER_INI()->exclude_element_keyword[idx] );
8265 for ( idx = 0; PLAYER_INI()->exclude_element_keyword[idx][0] != '\0'; idx++ )
8267 if ( g_strrstr(GST_PLUGIN_FEATURE_NAME (factory),
8268 PLAYER_INI()->exclude_element_keyword[idx] ) )
8270 debug_warning("skipping [%s] by exculde keyword [%s]\n",
8271 GST_PLUGIN_FEATURE_NAME (factory),
8272 PLAYER_INI()->exclude_element_keyword[idx] );
8280 if ( skip ) continue;
8282 /* check factory class for filtering */
8283 klass = gst_element_factory_get_klass(GST_ELEMENT_FACTORY(factory));
8285 /* NOTE : msl don't need to use image plugins.
8286 * So, those plugins should be skipped for error handling.
8288 if ( g_strrstr(klass, "Codec/Decoder/Image") )
8290 #ifdef GST_API_VERSION_1
8291 debug_log("skipping [%s] by not required\n",
8292 gst_object_get_name (GST_OBJECT (factory)) );
8294 debug_log("skipping [%s] by not required\n",
8295 GST_PLUGIN_FEATURE_NAME (factory) );
8300 /* check pad compatability */
8301 for(pads = gst_element_factory_get_static_pad_templates(factory);
8302 pads != NULL; pads=pads->next)
8304 GstStaticPadTemplate *temp1 = pads->data;
8305 GstCaps* static_caps = NULL;
8307 if( temp1->direction != GST_PAD_SINK ||
8308 temp1->presence != GST_PAD_ALWAYS)
8312 if ( GST_IS_CAPS( &temp1->static_caps.caps) )
8314 /* using existing caps */
8315 static_caps = gst_caps_ref( &temp1->static_caps.caps );
8320 static_caps = gst_caps_from_string ( temp1->static_caps.string );
8323 res = gst_caps_intersect(caps, static_caps);
8325 gst_caps_unref( static_caps );
8328 if( res && !gst_caps_is_empty(res) )
8330 #ifdef GST_API_VERSION_1
8331 GstElement *new_element;
8332 GList *elements = player->parsers;
8333 char *name_template = g_strdup(temp1->name_template);
8334 gchar *name_to_plug = gst_object_get_name (GST_OBJECT (factory));
8336 gst_caps_unref(res);
8338 debug_log("found %s to plug\n", name_to_plug);
8340 new_element = gst_element_factory_create(GST_ELEMENT_FACTORY(factory), NULL);
8341 if ( ! new_element )
8343 debug_error("failed to create element [%s]. continue with next.\n",
8344 gst_object_get_name (GST_OBJECT (factory)));
8346 MMPLAYER_FREEIF(name_template);
8351 GstElement *new_element;
8352 GList *elements = player->parsers;
8353 char *name_template = g_strdup(temp1->name_template);
8354 gchar *name_to_plug = GST_PLUGIN_FEATURE_NAME(factory);
8356 gst_caps_unref(res);
8358 debug_log("found %s to plug\n", name_to_plug);
8360 new_element = gst_element_factory_create(GST_ELEMENT_FACTORY(factory), NULL);
8361 if ( ! new_element )
8363 debug_error("failed to create element [%s]. continue with next.\n",
8364 GST_PLUGIN_FEATURE_NAME (factory));
8366 MMPLAYER_FREEIF(name_template);
8372 /* check and skip it if it was already used. Otherwise, it can be an infinite loop
8373 * because parser can accept its own output as input.
8375 if (g_strrstr(klass, "Parser"))
8377 gchar *selected = NULL;
8379 for ( ; elements; elements = g_list_next(elements))
8381 gchar *element_name = elements->data;
8383 if (g_strrstr(element_name, name_to_plug))
8385 debug_log("but, %s already linked, so skipping it\n", name_to_plug);
8392 selected = g_strdup(name_to_plug);
8394 player->parsers = g_list_append(player->parsers, selected);
8397 /* store specific handles for futher control */
8398 if(g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse"))
8400 /* FIXIT : first value will be overwritten if there's more
8401 * than 1 demuxer/parser
8403 debug_log("plugged element is demuxer. take it\n");
8404 mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
8405 mainbin[MMPLAYER_M_DEMUX].gst = new_element;
8407 else if(g_strrstr(klass, "Decoder") && __mmplayer_link_decoder(player,pad))
8409 if(mainbin[MMPLAYER_M_DEC1].gst == NULL)
8411 debug_log("plugged element is decoder. take it[MMPLAYER_M_DEC1]\n");
8412 mainbin[MMPLAYER_M_DEC1].id = MMPLAYER_M_DEC1;
8413 mainbin[MMPLAYER_M_DEC1].gst = new_element;
8415 else if(mainbin[MMPLAYER_M_DEC2].gst == NULL)
8417 debug_log("plugged element is decoder. take it[MMPLAYER_M_DEC2]\n");
8418 mainbin[MMPLAYER_M_DEC2].id = MMPLAYER_M_DEC2;
8419 mainbin[MMPLAYER_M_DEC2].gst = new_element;
8421 /* NOTE : IF one codec is found, add it to supported_codec and remove from
8422 * missing plugin. Both of them are used to check what's supported codec
8423 * before returning result of play start. And, missing plugin should be
8424 * updated here for multi track files.
8426 if(g_str_has_prefix(mime, "video"))
8428 GstPad *src_pad = NULL;
8429 GstPadTemplate *pad_templ = NULL;
8430 GstCaps *caps = NULL;
8431 gchar *caps_type = NULL;
8433 debug_log("found VIDEO decoder\n");
8434 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
8435 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
8437 src_pad = gst_element_get_static_pad (new_element, "src");
8438 pad_templ = gst_pad_get_pad_template (src_pad);
8439 caps = GST_PAD_TEMPLATE_CAPS(pad_templ);
8441 caps_type = gst_caps_to_string(caps);
8443 if ( g_strrstr( caps_type, "ST12") )
8444 player->is_nv12_tiled = TRUE;
8447 MMPLAYER_FREEIF( caps_type );
8448 gst_object_unref (src_pad);
8450 else if (g_str_has_prefix(mime, "audio"))
8452 debug_log("found AUDIO decoder\n");
8453 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
8454 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
8457 if ( ! __mmplayer_close_link(player, pad, new_element,
8458 name_template,gst_element_factory_get_static_pad_templates(factory)) )
8460 if (player->keep_detecting_vcodec)
8463 /* Link is failed even though a supportable codec is found. */
8464 __mmplayer_check_not_supported_codec(player, (gchar *)mime);
8466 MMPLAYER_FREEIF(name_template);
8467 debug_error("failed to call _close_link\n");
8471 MMPLAYER_FREEIF(name_template);
8475 gst_caps_unref(res);
8481 /* There is no available codec. */
8482 __mmplayer_check_not_supported_codec(player,(gchar *)mime);
8491 gst_object_unref( queue );
8495 gst_object_unref( queue_pad );
8498 gst_object_unref ( element );
8505 int __mmplayer_check_not_supported_codec(mm_player_t* player, gchar* mime)
8509 return_val_if_fail(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
8510 return_val_if_fail ( mime, MM_ERROR_INVALID_ARGUMENT );
8512 debug_log("mimetype to check: %s\n", mime );
8514 /* add missing plugin */
8515 /* NOTE : msl should check missing plugin for image mime type.
8516 * Some motion jpeg clips can have playable audio track.
8517 * So, msl have to play audio after displaying popup written video format not supported.
8519 if ( !( player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst ) )
8521 if ( !( player->can_support_codec | player->videodec_linked | player->audiodec_linked ) )
8523 debug_log("not found demuxer\n");
8524 player->not_found_demuxer = TRUE;
8525 player->unlinked_demuxer_mime = g_strdup_printf ( "%s", mime );
8531 if( ( g_str_has_prefix(mime, "video") ) ||( g_str_has_prefix(mime, "image") ) )
8533 debug_log("can support codec=%d, vdec_linked=%d, adec_linked=%d\n",
8534 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
8536 /* check that clip have multi tracks or not */
8537 if ( ( player->can_support_codec & FOUND_PLUGIN_VIDEO ) && ( player->videodec_linked ) )
8539 debug_log("video plugin is already linked\n");
8543 debug_warning("add VIDEO to missing plugin\n");
8544 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
8547 else if ( g_str_has_prefix(mime, "audio") )
8549 if ( ( player->can_support_codec & FOUND_PLUGIN_AUDIO ) && ( player->audiodec_linked ) )
8551 debug_log("audio plugin is already linked\n");
8555 debug_warning("add AUDIO to missing plugin\n");
8556 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
8563 return MM_ERROR_NONE;
8567 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data) // @
8569 mm_player_t* player = (mm_player_t*)data;
8573 return_if_fail( player );
8575 /* remove fakesink */
8576 if ( ! __mmplayer_gst_remove_fakesink( player,
8577 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]) )
8579 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
8580 * signaling mechanism ( pad-added, no-more-pad, new-decoded-pad ) from various
8581 * source element are not same. To overcome this situation, this function will called
8582 * several places and several times. Therefore, this is not an error case.
8586 debug_log("pipeline has completely constructed\n");
8588 player->pipeline_is_constructed = TRUE;
8590 if ( ( PLAYER_INI()->async_start ) &&
8591 ( player->msg_posted == FALSE ) &&
8592 ( player->cmd >= MMPLAYER_COMMAND_START ))
8594 __mmplayer_handle_missed_plugin( player );
8597 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-complete" );
8600 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player)
8604 return_val_if_fail ( player, FALSE );
8607 if ( MMPLAYER_IS_STREAMING(player) )
8610 /* This callback can be set to music player only. */
8611 if((player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO)
8613 debug_warning("audio callback is not supported for video");
8617 if (player->audio_stream_cb)
8622 #ifdef GST_API_VERSION_1
8623 pad = gst_element_get_static_pad (player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
8625 pad = gst_element_get_pad (player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
8630 debug_error("failed to get sink pad from audiosink to probe data\n");
8634 #ifdef GST_API_VERSION_1
8635 player->audio_cb_probe_id = gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER,
8636 __mmplayer_audio_stream_probe, player, NULL);
8638 player->audio_cb_probe_id = gst_pad_add_buffer_probe (pad,
8639 G_CALLBACK (__mmplayer_audio_stream_probe), player);
8642 gst_object_unref (pad);
8649 debug_error("There is no audio callback to configure.\n");
8659 __mmplayer_init_factories(mm_player_t* player) // @
8663 return_if_fail ( player );
8665 #ifdef GST_API_VERSION_1
8666 player->factories = gst_registry_feature_filter(gst_registry_get(),
8667 (GstPluginFeatureFilter)__mmplayer_feature_filter, FALSE, NULL);
8669 player->factories = gst_registry_feature_filter(gst_registry_get_default(),
8670 (GstPluginFeatureFilter)__mmplayer_feature_filter, FALSE, NULL);
8673 player->factories = g_list_sort(player->factories, (GCompareFunc)util_factory_rank_compare);
8679 __mmplayer_release_factories(mm_player_t* player) // @
8683 return_if_fail ( player );
8685 if (player->factories)
8687 gst_plugin_feature_list_free (player->factories);
8688 player->factories = NULL;
8695 __mmplayer_release_misc(mm_player_t* player)
8700 return_if_fail ( player );
8702 player->use_video_stream = FALSE;
8703 player->video_stream_cb = NULL;
8704 player->video_stream_cb_user_param = NULL;
8706 player->audio_stream_cb = NULL;
8707 player->audio_stream_cb_user_param = NULL;
8709 player->audio_buffer_cb = NULL;
8710 player->audio_buffer_cb_user_param = NULL;
8712 player->sent_bos = FALSE;
8713 player->playback_rate = DEFAULT_PLAYBACK_RATE;
8715 player->doing_seek = FALSE;
8717 player->streamer = NULL;
8718 player->updated_bitrate_count = 0;
8719 player->total_bitrate = 0;
8720 player->updated_maximum_bitrate_count = 0;
8721 player->total_maximum_bitrate = 0;
8723 player->not_found_demuxer = 0;
8725 player->last_position = 0;
8726 player->duration = 0;
8727 player->http_content_size = 0;
8728 player->not_supported_codec = MISSING_PLUGIN_NONE;
8729 player->can_support_codec = FOUND_PLUGIN_NONE;
8730 player->pending_seek.is_pending = FALSE;
8731 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
8732 player->pending_seek.pos = 0;
8733 player->msg_posted = FALSE;
8734 player->has_many_types = FALSE;
8736 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++)
8738 player->bitrate[i] = 0;
8739 player->maximum_bitrate[i] = 0;
8742 /* clean found parsers */
8743 if (player->parsers)
8745 g_list_free(player->parsers);
8746 player->parsers = NULL;
8749 MMPLAYER_FREEIF(player->album_art);
8751 /* free memory related to audio effect */
8752 if(player->audio_effect_info.custom_ext_level_for_plugin)
8754 free(player->audio_effect_info.custom_ext_level_for_plugin);
8760 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name)
8762 GstElement *element = NULL;
8765 debug_log("creating %s to plug\n", name);
8767 element = gst_element_factory_make(name, NULL);
8770 debug_error("failed to create queue\n");
8774 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(element, GST_STATE_READY) )
8776 debug_error("failed to set state READY to %s\n", name);
8780 if ( ! gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), element))
8782 debug_error("failed to add %s\n", name);
8786 sinkpad = gst_element_get_static_pad(element, "sink");
8788 if ( GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad) )
8790 debug_error("failed to link %s\n", name);
8791 gst_object_unref (sinkpad);
8796 debug_log("linked %s to pipeline successfully\n", name);
8798 gst_object_unref (sinkpad);
8804 __mmplayer_close_link(mm_player_t* player, GstPad *srcpad, GstElement *sinkelement,
8805 const char *padname, const GList *templlist)
8808 gboolean has_dynamic_pads = FALSE;
8809 gboolean has_many_types = FALSE;
8810 const char *klass = NULL;
8811 GstStaticPadTemplate *padtemplate = NULL;
8812 GstElementFactory *factory = NULL;
8813 GstElement* queue = NULL;
8814 GstElement* parser = NULL;
8815 GstPad *pssrcpad = NULL;
8816 GstPad *qsrcpad = NULL, *qsinkpad = NULL;
8817 MMPlayerGstElement *mainbin = NULL;
8818 GstStructure* str = NULL;
8819 GstCaps* srccaps = NULL;
8820 GstState warmup = GST_STATE_READY;
8821 gboolean isvideo_decoder = FALSE;
8822 guint q_max_size_time = 0;
8826 return_val_if_fail ( player &&
8828 player->pipeline->mainbin,
8831 mainbin = player->pipeline->mainbin;
8833 debug_log("plugging pad %s:%s to newly create %s:%s\n",
8834 GST_ELEMENT_NAME( GST_PAD_PARENT ( srcpad ) ),
8835 GST_PAD_NAME( srcpad ),
8836 GST_ELEMENT_NAME( sinkelement ),
8839 factory = gst_element_get_factory(sinkelement);
8840 klass = gst_element_factory_get_klass(factory);
8842 /* check if player can do start continually */
8843 MMPLAYER_CHECK_CMD_IF_EXIT(player);
8845 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkelement, warmup) )
8847 if (isvideo_decoder)
8848 player->keep_detecting_vcodec = TRUE;
8850 debug_error("failed to set %d state to %s\n", warmup, GST_ELEMENT_NAME( sinkelement ));
8854 /* add to pipeline */
8855 if ( ! gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), sinkelement) )
8857 debug_error("failed to add %s to mainbin\n", GST_ELEMENT_NAME( sinkelement ));
8861 debug_log("element klass : %s\n", klass);
8863 /* added to support multi track files */
8864 /* only decoder case and any of the video/audio still need to link*/
8865 if(g_strrstr(klass, "Decoder") && __mmplayer_link_decoder(player,srcpad))
8869 name = g_strdup(GST_ELEMENT_NAME( GST_PAD_PARENT ( srcpad )));
8871 if (g_strrstr(name, "mpegtsdemux"))
8873 gchar *demux_caps = NULL;
8874 gchar *parser_name = NULL;
8875 GstCaps *dcaps = NULL;
8877 #ifdef GST_API_VERSION_1
8878 dcaps = gst_pad_get_current_caps(srcpad);
8880 dcaps = gst_pad_get_caps(srcpad);
8882 demux_caps = gst_caps_to_string(dcaps);
8884 if (g_strrstr(demux_caps, "video/x-h264"))
8886 parser_name = g_strdup("h264parse");
8888 else if (g_strrstr(demux_caps, "video/mpeg"))
8890 parser_name = g_strdup("mpeg4videoparse");
8893 gst_caps_unref(dcaps);
8894 MMPLAYER_FREEIF( demux_caps );
8898 parser = __mmplayer_element_create_and_link(player, srcpad, parser_name);
8900 MMPLAYER_FREEIF(parser_name);
8904 debug_error("failed to create parser\n");
8908 /* update srcpad if parser is created */
8909 pssrcpad = gst_element_get_static_pad(parser, "src");
8914 MMPLAYER_FREEIF(name);
8916 queue = __mmplayer_element_create_and_link(player, srcpad, "queue"); // parser - queue or demuxer - queue
8919 debug_error("failed to create queue\n");
8923 /* update srcpad to link with decoder */
8924 qsrcpad = gst_element_get_static_pad(queue, "src");
8927 q_max_size_time = GST_QUEUE_DEFAULT_TIME;
8929 /* assigning queue handle for futher manipulation purpose */
8930 /* FIXIT : make it some kind of list so that msl can support more then two stream (text, data, etc...) */
8931 if(mainbin[MMPLAYER_M_Q1].gst == NULL)
8933 mainbin[MMPLAYER_M_Q1].id = MMPLAYER_M_Q1;
8934 mainbin[MMPLAYER_M_Q1].gst = queue;
8936 g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q1].gst), "max-size-time", q_max_size_time * GST_SECOND, NULL);
8938 else if(mainbin[MMPLAYER_M_Q2].gst == NULL)
8940 mainbin[MMPLAYER_M_Q2].id = MMPLAYER_M_Q2;
8941 mainbin[MMPLAYER_M_Q2].gst = queue;
8943 g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q2].gst), "max-size-time", q_max_size_time * GST_SECOND, NULL);
8947 debug_critical("Not supporting more then two elementary stream\n");
8951 pad = gst_element_get_static_pad(sinkelement, padname);
8955 debug_warning("failed to get pad(%s) from %s. retrying with [sink]\n",
8956 padname, GST_ELEMENT_NAME(sinkelement) );
8958 pad = gst_element_get_static_pad(sinkelement, "sink");
8961 debug_error("failed to get pad(sink) from %s. \n",
8962 GST_ELEMENT_NAME(sinkelement) );
8967 /* to check the video/audio type set the proper flag*/
8969 #ifdef GST_API_VERSION_1
8970 srccaps = gst_pad_get_current_caps( srcpad );
8972 srccaps = gst_pad_get_caps( srcpad );
8977 str = gst_caps_get_structure( srccaps, 0 );
8981 name = gst_structure_get_name(str);
8986 /* link queue and decoder. so, it will be queue - decoder. */
8987 if ( GST_PAD_LINK_OK != gst_pad_link(srcpad, pad) )
8989 gst_object_unref(GST_OBJECT(pad));
8990 debug_error("failed to link (%s) to pad(%s)\n", GST_ELEMENT_NAME( sinkelement ), padname );
8992 /* reconstitute supportable codec */
8993 if (strstr(name, "video"))
8995 player->can_support_codec ^= FOUND_PLUGIN_VIDEO;
8997 else if (strstr(name, "audio"))
8999 player->can_support_codec ^= FOUND_PLUGIN_AUDIO;
9004 if (strstr(name, "video"))
9006 player->videodec_linked = 1;
9007 debug_msg("player->videodec_linked set to 1\n");
9010 else if (strstr(name, "audio"))
9012 player->audiodec_linked = 1;
9013 debug_msg("player->auddiodec_linked set to 1\n");
9016 gst_object_unref(GST_OBJECT(pad));
9017 gst_caps_unref(GST_CAPS(srccaps));
9021 if ( !MMPLAYER_IS_HTTP_PD(player) )
9023 if( (g_strrstr(klass, "Demux") && !g_strrstr(klass, "Metadata")) || (g_strrstr(klass, "Parser") ) )
9025 if (MMPLAYER_IS_HTTP_STREAMING(player))
9027 #ifndef GST_API_VERSION_1
9028 GstFormat fmt = GST_FORMAT_BYTES;
9030 gint64 dur_bytes = 0L;
9031 gchar *file_buffering_path = NULL;
9032 gboolean use_file_buffer = FALSE;
9034 if ( !mainbin[MMPLAYER_M_S_BUFFER].gst)
9036 debug_log("creating http streaming buffering queue\n");
9038 queue = gst_element_factory_make("queue2", "http_streaming_buffer");
9041 debug_critical ( "failed to create buffering queue element\n" );
9045 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_READY) )
9047 debug_error("failed to set state READY to buffering queue\n");
9051 if ( !gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue) )
9053 debug_error("failed to add buffering queue\n");
9057 qsinkpad = gst_element_get_static_pad(queue, "sink");
9058 qsrcpad = gst_element_get_static_pad(queue, "src");
9060 if ( GST_PAD_LINK_OK != gst_pad_link(srcpad, qsinkpad) )
9062 debug_error("failed to link buffering queue\n");
9068 mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_S_BUFFER;
9069 mainbin[MMPLAYER_M_S_BUFFER].gst = queue;
9071 if ( !MMPLAYER_IS_HTTP_LIVE_STREAMING(player))
9073 #ifdef GST_API_VERSION_1
9074 if ( !gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
9075 debug_error("fail to get duration.\n");
9077 if ( !gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, &fmt, &dur_bytes))
9078 debug_error("fail to get duration.\n");
9083 use_file_buffer = MMPLAYER_USE_FILE_FOR_BUFFERING(player);
9084 file_buffering_path = g_strdup(PLAYER_INI()->http_file_buffer_path);
9088 __mm_player_streaming_set_buffer(player->streamer,
9091 PLAYER_INI()->http_max_size_bytes,
9093 PLAYER_INI()->http_buffering_limit,
9094 PLAYER_INI()->http_buffering_time,
9096 file_buffering_path,
9099 MMPLAYER_FREEIF(file_buffering_path);
9104 /* if it is not decoder or */
9105 /* in decoder case any of the video/audio still need to link*/
9106 if(!g_strrstr(klass, "Decoder"))
9109 pad = gst_element_get_static_pad(sinkelement, padname);
9112 debug_warning("failed to get pad(%s) from %s. retrying with [sink]\n",
9113 padname, GST_ELEMENT_NAME(sinkelement) );
9115 pad = gst_element_get_static_pad(sinkelement, "sink");
9119 debug_error("failed to get pad(sink) from %s. \n",
9120 GST_ELEMENT_NAME(sinkelement) );
9125 if ( GST_PAD_LINK_OK != gst_pad_link(srcpad, pad) )
9127 gst_object_unref(GST_OBJECT(pad));
9128 debug_error("failed to link (%s) to pad(%s)\n", GST_ELEMENT_NAME( sinkelement ), padname );
9132 gst_object_unref(GST_OBJECT(pad));
9135 for(;templlist != NULL; templlist = templlist->next)
9137 padtemplate = templlist->data;
9139 debug_log ("director = [%d], presence = [%d]\n", padtemplate->direction, padtemplate->presence);
9141 if( padtemplate->direction != GST_PAD_SRC ||
9142 padtemplate->presence == GST_PAD_REQUEST )
9145 switch(padtemplate->presence)
9147 case GST_PAD_ALWAYS:
9149 GstPad *srcpad = gst_element_get_static_pad(sinkelement, "src");
9150 #ifdef GST_API_VERSION_1
9151 GstCaps *caps = gst_pad_get_current_caps(srcpad);
9153 GstCaps *caps = gst_pad_get_caps(srcpad);
9156 /* Check whether caps has many types */
9157 if ( gst_caps_get_size (caps) > 1 && g_strrstr(klass, "Parser")) {
9158 debug_log ("has_many_types for this caps [%s]\n", gst_caps_to_string(caps));
9159 has_many_types = TRUE;
9163 if ( ! __mmplayer_try_to_plug(player, srcpad, caps) )
9165 gst_object_unref(GST_OBJECT(srcpad));
9166 gst_caps_unref(GST_CAPS(caps));
9168 debug_error("failed to plug something after %s\n", GST_ELEMENT_NAME( sinkelement ));
9172 gst_caps_unref(GST_CAPS(caps));
9173 gst_object_unref(GST_OBJECT(srcpad));
9179 case GST_PAD_SOMETIMES:
9180 has_dynamic_pads = TRUE;
9188 /* check if player can do start continually */
9189 MMPLAYER_CHECK_CMD_IF_EXIT(player);
9191 if( has_dynamic_pads )
9193 player->have_dynamic_pad = TRUE;
9194 MMPLAYER_SIGNAL_CONNECT ( player, sinkelement, "pad-added",
9195 G_CALLBACK(__mmplayer_add_new_pad), player);
9197 /* for streaming, more then one typefind will used for each elementary stream
9198 * so this doesn't mean the whole pipeline completion
9200 if ( ! MMPLAYER_IS_RTSP_STREAMING( player ) )
9202 MMPLAYER_SIGNAL_CONNECT( player, sinkelement, "no-more-pads",
9203 G_CALLBACK(__mmplayer_pipeline_complete), player);
9211 player->has_many_types = has_many_types;
9213 pad = gst_element_get_static_pad(sinkelement, "src");
9214 MMPLAYER_SIGNAL_CONNECT (player, pad, "notify::caps", G_CALLBACK(__mmplayer_add_new_caps), player);
9215 gst_object_unref (GST_OBJECT(pad));
9219 /* check if player can do start continually */
9220 MMPLAYER_CHECK_CMD_IF_EXIT(player);
9222 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkelement, GST_STATE_PAUSED) )
9224 debug_error("failed to set state PAUSED to %s\n", GST_ELEMENT_NAME( sinkelement ));
9230 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state (queue, GST_STATE_PAUSED) )
9232 debug_error("failed to set state PAUSED to queue\n");
9238 gst_object_unref (GST_OBJECT(qsrcpad));
9244 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state (parser, GST_STATE_PAUSED) )
9246 debug_error("failed to set state PAUSED to queue\n");
9252 gst_object_unref (GST_OBJECT(pssrcpad));
9264 gst_object_unref(GST_OBJECT(qsrcpad));
9266 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
9267 * You need to explicitly set elements to the NULL state before
9268 * dropping the final reference, to allow them to clean up.
9270 gst_element_set_state(queue, GST_STATE_NULL);
9271 /* And, it still has a parent "player".
9272 * You need to let the parent manage the object instead of unreffing the object directly.
9275 gst_bin_remove (GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue);
9276 //gst_object_unref( queue );
9280 gst_caps_unref(GST_CAPS(srccaps));
9285 static gboolean __mmplayer_feature_filter(GstPluginFeature *feature, gpointer data) // @
9288 //const gchar *name;
9290 /* we only care about element factories */
9291 if (!GST_IS_ELEMENT_FACTORY(feature))
9294 /* only parsers, demuxers and decoders */
9295 klass = gst_element_factory_get_klass(GST_ELEMENT_FACTORY(feature));
9296 //name = gst_element_factory_get_longname(GST_ELEMENT_FACTORY(feature));
9298 if( g_strrstr(klass, "Demux") == NULL &&
9299 g_strrstr(klass, "Codec/Decoder") == NULL &&
9300 g_strrstr(klass, "Depayloader") == NULL &&
9301 g_strrstr(klass, "Parse") == NULL)
9309 static void __mmplayer_add_new_caps(GstPad* pad, GParamSpec* unused, gpointer data)
9311 mm_player_t* player = (mm_player_t*) data;
9312 GstCaps *caps = NULL;
9313 GstStructure *str = NULL;
9318 return_if_fail ( pad )
9319 return_if_fail ( unused )
9320 return_if_fail ( data )
9322 #ifdef GST_API_VERSION_1
9323 caps = gst_pad_get_current_caps(pad);
9325 caps = gst_pad_get_caps(pad);
9330 str = gst_caps_get_structure(caps, 0);
9334 name = gst_structure_get_name(str);
9337 debug_log("name=%s\n", name);
9339 if ( ! __mmplayer_try_to_plug(player, pad, caps) )
9341 debug_error("failed to autoplug for type (%s)\n", name);
9342 gst_caps_unref(caps);
9346 gst_caps_unref(caps);
9348 __mmplayer_pipeline_complete( NULL, (gpointer)player );
9355 static void __mmplayer_set_unlinked_mime_type(mm_player_t* player, GstCaps *caps)
9359 const char *stream_type;
9360 gchar *version_field = NULL;
9364 return_if_fail ( player );
9365 return_if_fail ( caps );
9367 str = gst_caps_get_structure(caps, 0);
9371 stream_type = gst_structure_get_name(str);
9376 /* set unlinked mime type for downloadable codec */
9377 if (g_str_has_prefix(stream_type, "video/"))
9379 if (g_str_has_prefix(stream_type, "video/mpeg"))
9381 gst_structure_get_int (str, MM_PLAYER_MPEG_VNAME, &version);
9382 version_field = MM_PLAYER_MPEG_VNAME;
9384 else if (g_str_has_prefix(stream_type, "video/x-wmv"))
9386 gst_structure_get_int (str, MM_PLAYER_WMV_VNAME, &version);
9387 version_field = MM_PLAYER_WMV_VNAME;
9390 else if (g_str_has_prefix(stream_type, "video/x-divx"))
9392 gst_structure_get_int (str, MM_PLAYER_DIVX_VNAME, &version);
9393 version_field = MM_PLAYER_DIVX_VNAME;
9398 player->unlinked_video_mime = g_strdup_printf("%s, %s=%d", stream_type, version_field, version);
9402 player->unlinked_video_mime = g_strdup_printf("%s", stream_type);
9405 else if (g_str_has_prefix(stream_type, "audio/"))
9407 if (g_str_has_prefix(stream_type, "audio/mpeg")) // mp3 or aac
9409 gst_structure_get_int (str, MM_PLAYER_MPEG_VNAME, &version);
9410 version_field = MM_PLAYER_MPEG_VNAME;
9412 else if (g_str_has_prefix(stream_type, "audio/x-wma"))
9414 gst_structure_get_int (str, MM_PLAYER_WMA_VNAME, &version);
9415 version_field = MM_PLAYER_WMA_VNAME;
9420 player->unlinked_audio_mime = g_strdup_printf("%s, %s=%d", stream_type, version_field, version);
9424 player->unlinked_audio_mime = g_strdup_printf("%s", stream_type);
9431 static void __mmplayer_add_new_pad(GstElement *element, GstPad *pad, gpointer data)
9433 mm_player_t* player = (mm_player_t*) data;
9434 GstCaps *caps = NULL;
9435 GstStructure *str = NULL;
9439 return_if_fail ( player );
9440 return_if_fail ( pad );
9442 GST_OBJECT_LOCK (pad);
9443 #ifdef GST_API_VERSION_1
9444 if ((caps = gst_pad_get_current_caps (pad)))
9447 if ((caps = GST_PAD_CAPS(pad)))
9450 GST_OBJECT_UNLOCK (pad);
9454 #ifdef GST_API_VERSION_1
9455 caps = gst_pad_get_current_caps(pad);
9457 caps = gst_pad_get_caps(pad);
9459 if ( !caps ) return;
9462 //MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9464 str = gst_caps_get_structure(caps, 0);
9468 name = gst_structure_get_name(str);
9472 player->num_dynamic_pad++;
9473 debug_log("stream count inc : %d\n", player->num_dynamic_pad);
9475 /* Note : If the stream is the subtitle, we try not to play it. Just close the demuxer subtitle pad.
9476 * If want to play it, remove this code.
9478 if (g_strrstr(name, "application"))
9480 if (g_strrstr(name, "x-id3") || g_strrstr(name, "x-apetag"))
9482 /* If id3/ape tag comes, keep going */
9483 debug_log("application mime exception : id3/ape tag");
9487 /* Otherwise, we assume that this stream is subtile. */
9488 debug_log(" application mime type pad is closed.");
9492 else if (g_strrstr(name, "audio"))
9494 gint samplerate = 0, channels = 0;
9496 /* set stream information */
9497 /* if possible, set it here because the caps is not distrubed by resampler. */
9498 gst_structure_get_int (str, "rate", &samplerate);
9499 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
9501 gst_structure_get_int (str, "channels", &channels);
9502 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
9504 debug_log("audio samplerate : %d channels : %d", samplerate, channels);
9506 else if (g_strrstr(name, "video"))
9509 mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &stype);
9511 /* don't make video because of not required */
9512 if (stype == MM_DISPLAY_SURFACE_NULL)
9514 debug_log("no video because it's not required");
9518 player->v_stream_caps = gst_caps_copy(caps); //if needed, video caps is required when videobin is created
9521 if ( ! __mmplayer_try_to_plug(player, pad, caps) )
9523 debug_error("failed to autoplug for type (%s)", name);
9525 __mmplayer_set_unlinked_mime_type(player, caps);
9528 gst_caps_unref(caps);
9534 /* test API for tuning audio gain. this API should be
9535 * deprecated before the day of final release
9538 _mmplayer_set_volume_tune(MMHandleType hplayer, MMPlayerVolumeType volume)
9540 mm_player_t* player = (mm_player_t*) hplayer;
9541 gint error = MM_ERROR_NONE;
9543 gboolean isMidi = FALSE;
9548 return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9549 return_val_if_fail( player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED )
9551 debug_log("clip type=%d(1-midi, 0-others), volume [L]=%d:[R]=%d\n",
9552 player->profile.play_mode, volume.level[0], volume.level[1]);
9554 isMidi = ( player->profile.play_mode == MM_PLAYER_MODE_MIDI ) ? TRUE : FALSE;
9561 /* is it proper volume level? */
9562 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; ++i)
9564 if (volume.level[i] < 0 || volume.level[i] > vol_max) {
9565 debug_log("Invalid Volume level!!!! \n");
9566 return MM_ERROR_INVALID_ARGUMENT;
9572 if ( player->pipeline->mainbin )
9574 GstElement *midi_element = player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst;
9576 if ( midi_element && ( strstr(GST_ELEMENT_NAME(midi_element), "midiparse")) )
9578 debug_log("setting volume (%d) level to midi plugin\n", volume.level[0]);
9580 g_object_set(midi_element, "volume", volume.level[0], NULL);
9586 if ( player->pipeline->audiobin )
9588 GstElement *sink_element = player->pipeline->audiobin[MMPLAYER_A_SINK].gst;
9590 /* Set to Avsysaudiosink element */
9594 gboolean mute = FALSE;
9595 vol_value = volume.level[0];
9597 g_object_set(G_OBJECT(sink_element), "tuningvolume", vol_value, NULL);
9599 mute = (vol_value == 0)? TRUE:FALSE;
9601 g_object_set(G_OBJECT(sink_element), "mute", mute, NULL);
9613 __mmplayer_dump_pipeline_state( mm_player_t* player )
9615 GstIterator*iter = NULL;
9616 gboolean done = FALSE;
9618 GstElement *item = NULL;
9619 GstElementFactory *factory = NULL;
9621 GstState state = GST_STATE_VOID_PENDING;
9622 GstState pending = GST_STATE_VOID_PENDING;
9623 GstClockTime time = 200*GST_MSECOND;
9627 return_val_if_fail ( player &&
9629 player->pipeline->mainbin,
9632 iter = gst_bin_iterate_recurse(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst) );
9637 switch ( gst_iterator_next (iter, (gpointer)&item) )
9639 case GST_ITERATOR_OK:
9640 gst_element_get_state(GST_ELEMENT (item),&state, &pending,time);
9642 factory = gst_element_get_factory (item) ;
9645 debug_error("%s:%s : From:%s To:%s refcount : %d\n", GST_OBJECT_NAME(factory) , GST_ELEMENT_NAME(item) ,
9646 gst_element_state_get_name(state), gst_element_state_get_name(pending) , GST_OBJECT_REFCOUNT_VALUE(item));
9648 gst_object_unref (item);
9650 case GST_ITERATOR_RESYNC:
9651 gst_iterator_resync (iter);
9653 case GST_ITERATOR_ERROR:
9656 case GST_ITERATOR_DONE:
9663 item = GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
9665 gst_element_get_state(GST_ELEMENT (item),&state, &pending,time);
9667 factory = gst_element_get_factory (item) ;
9671 debug_error("%s:%s : From:%s To:%s refcount : %d\n",
9672 GST_OBJECT_NAME(factory),
9673 GST_ELEMENT_NAME(item),
9674 gst_element_state_get_name(state),
9675 gst_element_state_get_name(pending),
9676 GST_OBJECT_REFCOUNT_VALUE(item) );
9680 gst_iterator_free (iter);
9689 __mmplayer_check_subtitle( mm_player_t* player )
9691 MMHandleType attrs = 0;
9692 char *subtitle_uri = NULL;
9696 return_val_if_fail( player, FALSE );
9698 /* get subtitle attribute */
9699 attrs = MMPLAYER_GET_ATTRS(player);
9703 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
9704 if ( !subtitle_uri || !strlen(subtitle_uri))
9707 debug_log ("subtite uri is %s[%d]\n", subtitle_uri, strlen(subtitle_uri));
9715 __mmplayer_can_extract_pcm( mm_player_t* player )
9717 MMHandleType attrs = 0;
9718 gboolean is_drm = FALSE;
9719 gboolean sound_extraction = FALSE;
9721 return_val_if_fail ( player, FALSE );
9723 attrs = MMPLAYER_GET_ATTRS(player);
9726 debug_error("fail to get attributes.");
9730 /* check file is drm or not */
9731 g_object_get(G_OBJECT(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), "is-drm", &is_drm, NULL);
9733 /* get sound_extraction property */
9734 mm_attrs_get_int_by_name(attrs, "pcm_extraction", &sound_extraction);
9736 if ( ! sound_extraction || is_drm )
9738 debug_log("checking pcm extraction mode : %d, drm : %d", sound_extraction, is_drm);
9746 __mmplayer_handle_gst_error ( mm_player_t* player, GstMessage * message, GError* error )
9748 MMMessageParamType msg_param;
9749 gchar *msg_src_element;
9753 return_val_if_fail( player, FALSE );
9754 return_val_if_fail( error, FALSE );
9756 /* NOTE : do somthing necessary inside of __gst_handle_XXX_error. not here */
9758 memset (&msg_param, 0, sizeof(MMMessageParamType));
9760 if ( error->domain == GST_CORE_ERROR )
9762 msg_param.code = __gst_handle_core_error( player, error->code );
9764 else if ( error->domain == GST_LIBRARY_ERROR )
9766 msg_param.code = __gst_handle_library_error( player, error->code );
9768 else if ( error->domain == GST_RESOURCE_ERROR )
9770 msg_param.code = __gst_handle_resource_error( player, error->code );
9772 else if ( error->domain == GST_STREAM_ERROR )
9774 msg_param.code = __gst_handle_stream_error( player, error, message );
9778 debug_warning("This error domain is not defined.\n");
9780 /* we treat system error as an internal error */
9781 msg_param.code = MM_ERROR_PLAYER_INVALID_STREAM;
9786 msg_src_element = GST_ELEMENT_NAME( GST_ELEMENT_CAST( message->src ) );
9788 msg_param.data = (void *) error->message;
9790 debug_error("-Msg src : [%s] Domain : [%s] Error : [%s] Code : [%d] is tranlated to error code : [0x%x]\n",
9791 msg_src_element, g_quark_to_string (error->domain), error->message, error->code, msg_param.code);
9794 /* post error to application */
9795 if ( ! player->msg_posted )
9797 MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param );
9798 /* don't post more if one was sent already */
9799 player->msg_posted = TRUE;
9803 debug_log("skip error post because it's sent already.\n");
9812 __mmplayer_handle_streaming_error ( mm_player_t* player, GstMessage * message )
9815 MMMessageParamType msg_param;
9816 gchar *msg_src_element = NULL;
9817 GstStructure *s = NULL;
9819 gchar *error_string = NULL;
9823 return_val_if_fail ( player, FALSE );
9824 return_val_if_fail ( message, FALSE );
9826 s = malloc( sizeof(GstStructure) );
9827 memcpy ( s, gst_message_get_structure ( message ), sizeof(GstStructure));
9829 if ( !gst_structure_get_uint (s, "error_id", &error_id) )
9830 error_id = MMPLAYER_STREAMING_ERROR_NONE;
9834 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
9835 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
9837 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
9838 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
9840 case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
9841 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
9843 case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
9844 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
9846 case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
9847 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
9849 case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
9850 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
9852 case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
9853 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
9855 case MMPLAYER_STREAMING_ERROR_INVALID_URL:
9856 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
9858 case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
9859 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
9861 case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
9862 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
9864 case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
9865 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
9867 case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
9868 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
9870 case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
9871 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
9873 case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
9874 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
9876 case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
9877 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
9879 case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
9880 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
9882 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
9883 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
9885 case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
9886 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
9888 case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
9889 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
9891 case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
9892 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
9894 case MMPLAYER_STREAMING_ERROR_GONE:
9895 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
9897 case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
9898 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
9900 case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
9901 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
9903 case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
9904 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
9906 case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
9907 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
9909 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
9910 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
9912 case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
9913 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
9915 case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
9916 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
9918 case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
9919 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
9921 case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
9922 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
9924 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
9925 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
9927 case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
9928 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
9930 case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
9931 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
9933 case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
9934 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
9936 case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
9937 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
9939 case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
9940 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
9942 case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
9943 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
9945 case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
9946 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
9948 case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
9949 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
9951 case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
9952 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
9954 case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
9955 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
9957 case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
9958 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
9960 case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
9961 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
9963 case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
9964 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
9966 case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
9967 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
9970 return MM_ERROR_PLAYER_STREAMING_FAIL;
9973 error_string = g_strdup(gst_structure_get_string (s, "error_string"));
9975 msg_param.data = (void *) error_string;
9979 msg_src_element = GST_ELEMENT_NAME( GST_ELEMENT_CAST( message->src ) );
9981 debug_error("-Msg src : [%s] Code : [%x] Error : [%s] \n",
9982 msg_src_element, msg_param.code, (char*)msg_param.data );
9985 /* post error to application */
9986 if ( ! player->msg_posted )
9988 MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param );
9990 /* don't post more if one was sent already */
9991 player->msg_posted = TRUE;
9995 debug_log("skip error post because it's sent already.\n");
10005 __gst_handle_core_error( mm_player_t* player, int code )
10007 gint trans_err = MM_ERROR_NONE;
10011 return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
10015 case GST_CORE_ERROR_STATE_CHANGE:
10016 case GST_CORE_ERROR_MISSING_PLUGIN:
10017 case GST_CORE_ERROR_SEEK:
10018 case GST_CORE_ERROR_NOT_IMPLEMENTED:
10019 case GST_CORE_ERROR_FAILED:
10020 case GST_CORE_ERROR_TOO_LAZY:
10021 case GST_CORE_ERROR_PAD:
10022 case GST_CORE_ERROR_THREAD:
10023 case GST_CORE_ERROR_NEGOTIATION:
10024 case GST_CORE_ERROR_EVENT:
10025 case GST_CORE_ERROR_CAPS:
10026 case GST_CORE_ERROR_TAG:
10027 case GST_CORE_ERROR_CLOCK:
10028 case GST_CORE_ERROR_DISABLED:
10030 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
10040 __gst_handle_library_error( mm_player_t* player, int code )
10042 gint trans_err = MM_ERROR_NONE;
10046 return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
10050 case GST_LIBRARY_ERROR_FAILED:
10051 case GST_LIBRARY_ERROR_TOO_LAZY:
10052 case GST_LIBRARY_ERROR_INIT:
10053 case GST_LIBRARY_ERROR_SHUTDOWN:
10054 case GST_LIBRARY_ERROR_SETTINGS:
10055 case GST_LIBRARY_ERROR_ENCODE:
10057 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
10068 __gst_handle_resource_error( mm_player_t* player, int code )
10070 gint trans_err = MM_ERROR_NONE;
10074 return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
10078 case GST_RESOURCE_ERROR_NO_SPACE_LEFT:
10079 trans_err = MM_ERROR_PLAYER_NO_FREE_SPACE;
10081 case GST_RESOURCE_ERROR_NOT_FOUND:
10082 case GST_RESOURCE_ERROR_OPEN_READ:
10083 if ( MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING ( player )
10084 || MMPLAYER_IS_RTSP_STREAMING(player))
10086 trans_err = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
10089 case GST_RESOURCE_ERROR_READ:
10090 if ( MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING ( player )
10091 || MMPLAYER_IS_RTSP_STREAMING(player))
10093 trans_err = MM_ERROR_PLAYER_STREAMING_FAIL;
10096 case GST_RESOURCE_ERROR_WRITE:
10097 case GST_RESOURCE_ERROR_FAILED:
10098 trans_err = MM_ERROR_PLAYER_INTERNAL;
10101 case GST_RESOURCE_ERROR_SEEK:
10102 case GST_RESOURCE_ERROR_TOO_LAZY:
10103 case GST_RESOURCE_ERROR_BUSY:
10104 case GST_RESOURCE_ERROR_OPEN_WRITE:
10105 case GST_RESOURCE_ERROR_OPEN_READ_WRITE:
10106 case GST_RESOURCE_ERROR_CLOSE:
10107 case GST_RESOURCE_ERROR_SYNC:
10108 case GST_RESOURCE_ERROR_SETTINGS:
10110 trans_err = MM_ERROR_PLAYER_FILE_NOT_FOUND;
10121 __gst_handle_stream_error( mm_player_t* player, GError* error, GstMessage * message )
10123 gint trans_err = MM_ERROR_NONE;
10127 return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
10128 return_val_if_fail( error, MM_ERROR_INVALID_ARGUMENT );
10129 return_val_if_fail ( message, MM_ERROR_INVALID_ARGUMENT );
10131 switch ( error->code )
10133 case GST_STREAM_ERROR_FAILED:
10134 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
10135 case GST_STREAM_ERROR_DECODE:
10136 case GST_STREAM_ERROR_WRONG_TYPE:
10137 case GST_STREAM_ERROR_DECRYPT:
10138 case GST_STREAM_ERROR_DECRYPT_NOKEY:
10139 trans_err = __gst_transform_gsterror( player, message, error );
10142 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
10143 case GST_STREAM_ERROR_NOT_IMPLEMENTED:
10144 case GST_STREAM_ERROR_TOO_LAZY:
10145 case GST_STREAM_ERROR_ENCODE:
10146 case GST_STREAM_ERROR_DEMUX:
10147 case GST_STREAM_ERROR_MUX:
10148 case GST_STREAM_ERROR_FORMAT:
10150 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
10159 /* NOTE : decide gstreamer state whether there is some playable track or not. */
10161 __gst_transform_gsterror( mm_player_t* player, GstMessage * message, GError* error )
10163 gchar *src_element_name = NULL;
10164 GstElement *src_element = NULL;
10165 GstElementFactory *factory = NULL;
10166 const gchar* klass = NULL;
10171 return_val_if_fail ( message, MM_ERROR_INVALID_ARGUMENT );
10172 return_val_if_fail ( message->src, MM_ERROR_INVALID_ARGUMENT );
10173 return_val_if_fail ( error, MM_ERROR_INVALID_ARGUMENT );
10175 src_element = GST_ELEMENT_CAST(message->src);
10176 if ( !src_element )
10177 goto INTERNAL_ERROR;
10179 src_element_name = GST_ELEMENT_NAME(src_element);
10180 if ( !src_element_name )
10181 goto INTERNAL_ERROR;
10183 factory = gst_element_get_factory(src_element);
10185 goto INTERNAL_ERROR;
10187 klass = gst_element_factory_get_klass(factory);
10189 goto INTERNAL_ERROR;
10191 debug_log("error code=%d, msg=%s, src element=%s, class=%s\n",
10192 error->code, error->message, src_element_name, klass);
10194 switch ( error->code )
10196 case GST_STREAM_ERROR_DECODE:
10198 /* Demuxer can't parse one track because it's corrupted.
10199 * So, the decoder for it is not linked.
10200 * But, it has one playable track.
10202 if ( g_strrstr(klass, "Demux") )
10204 if ( player->can_support_codec == FOUND_PLUGIN_VIDEO )
10206 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
10208 else if ( player->can_support_codec == FOUND_PLUGIN_AUDIO )
10210 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
10214 if ( player->pipeline->audiobin ) // PCM
10216 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
10220 goto CODEC_NOT_FOUND;
10224 return MM_ERROR_PLAYER_INVALID_STREAM;
10228 case GST_STREAM_ERROR_WRONG_TYPE:
10230 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
10234 case GST_STREAM_ERROR_FAILED:
10236 /* Decoder Custom Message */
10237 if ( strstr(error->message, "ongoing") )
10239 if ( strncasecmp(klass, "audio", 5) )
10241 if ( ( player->can_support_codec & FOUND_PLUGIN_VIDEO ) )
10243 debug_log("Video can keep playing.\n");
10244 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
10248 goto CODEC_NOT_FOUND;
10252 else if ( strncasecmp(klass, "video", 5) )
10254 if ( ( player->can_support_codec & FOUND_PLUGIN_AUDIO ) )
10256 debug_log("Audio can keep playing.\n");
10257 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
10261 goto CODEC_NOT_FOUND;
10265 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
10269 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
10270 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
10273 case GST_STREAM_ERROR_DECRYPT:
10274 case GST_STREAM_ERROR_DECRYPT_NOKEY:
10276 debug_error("decryption error, [%s] failed, reason : [%s]\n", src_element_name, error->message);
10278 if ( strstr(error->message, "rights expired") )
10280 return MM_ERROR_PLAYER_DRM_EXPIRED;
10282 else if ( strstr(error->message, "no rights") )
10284 return MM_ERROR_PLAYER_DRM_NO_LICENSE;
10286 else if ( strstr(error->message, "has future rights") )
10288 return MM_ERROR_PLAYER_DRM_FUTURE_USE;
10290 else if ( strstr(error->message, "opl violation") )
10292 return MM_ERROR_PLAYER_DRM_OUTPUT_PROTECTION;
10294 return MM_ERROR_PLAYER_DRM_NOT_AUTHORIZED;
10304 return MM_ERROR_PLAYER_INVALID_STREAM;
10307 return MM_ERROR_PLAYER_INTERNAL;
10310 debug_log("not found any available codec. Player should be destroyed.\n");
10311 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
10315 __mmplayer_post_delayed_eos( mm_player_t* player, int delay_in_ms )
10319 return_if_fail( player );
10321 /* cancel if existing */
10322 __mmplayer_cancel_delayed_eos( player );
10325 /* post now if delay is zero */
10326 if ( delay_in_ms == 0 || player->is_sound_extraction)
10328 debug_log("eos delay is zero. posting EOS now\n");
10329 MMPLAYER_POST_MSG( player, MM_MESSAGE_END_OF_STREAM, NULL );
10331 if ( player->is_sound_extraction )
10332 __mmplayer_cancel_delayed_eos(player);
10337 /* init new timeout */
10338 /* NOTE : consider give high priority to this timer */
10340 debug_log("posting EOS message after [%d] msec\n", delay_in_ms);
10341 player->eos_timer = g_timeout_add( delay_in_ms,
10342 __mmplayer_eos_timer_cb, player );
10345 /* check timer is valid. if not, send EOS now */
10346 if ( player->eos_timer == 0 )
10348 debug_warning("creating timer for delayed EOS has failed. sending EOS now\n");
10349 MMPLAYER_POST_MSG( player, MM_MESSAGE_END_OF_STREAM, NULL );
10356 __mmplayer_cancel_delayed_eos( mm_player_t* player )
10360 return_if_fail( player );
10362 if ( player->eos_timer )
10364 g_source_remove( player->eos_timer );
10367 player->eos_timer = 0;
10375 __mmplayer_eos_timer_cb(gpointer u_data)
10377 mm_player_t* player = NULL;
10378 player = (mm_player_t*) u_data;
10382 return_val_if_fail( player, FALSE );
10385 MMPLAYER_POST_MSG( player, MM_MESSAGE_END_OF_STREAM, NULL );
10387 /* cleare timer id */
10388 player->eos_timer = 0;
10392 /* we are returning FALSE as we need only one posting */
10396 static void __mmplayer_set_antishock( mm_player_t* player, gboolean disable_by_force)
10398 gint antishock = FALSE;
10399 MMHandleType attrs = 0;
10403 return_if_fail ( player && player->pipeline );
10405 /* It should be passed for video only clip */
10406 if ( ! player->pipeline->audiobin )
10409 if ( ( g_strrstr(PLAYER_INI()->name_of_audiosink, "avsysaudiosink")) )
10411 attrs = MMPLAYER_GET_ATTRS(player);
10414 debug_error("fail to get attributes.\n");
10418 mm_attrs_get_int_by_name(attrs, "sound_fadeup", &antishock);
10420 debug_log("setting antishock as (%d)\n", antishock);
10422 if ( disable_by_force )
10424 debug_log("but, antishock is disabled by force when is seeked\n");
10429 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "fadeup", antishock, NULL);
10439 __mmplayer_link_decoder( mm_player_t* player, GstPad *srcpad)
10441 const gchar* name = NULL;
10442 GstStructure* str = NULL;
10443 GstCaps* srccaps = NULL;
10447 return_val_if_fail( player, FALSE );
10448 return_val_if_fail ( srcpad, FALSE );
10450 /* to check any of the decoder (video/audio) need to be linked to parser*/
10451 #ifdef GST_API_VERSION_1
10452 srccaps = gst_pad_get_current_caps( srcpad );
10454 srccaps = gst_pad_get_caps( srcpad );
10459 str = gst_caps_get_structure( srccaps, 0 );
10463 name = gst_structure_get_name(str);
10467 if (strstr(name, "video"))
10469 if(player->videodec_linked)
10471 debug_msg("Video decoder already linked\n");
10475 if (strstr(name, "audio"))
10477 if(player->audiodec_linked)
10479 debug_msg("Audio decoder already linked\n");
10484 gst_caps_unref( srccaps );
10492 gst_caps_unref( srccaps );
10498 __mmplayer_link_sink( mm_player_t* player , GstPad *srcpad)
10500 const gchar* name = NULL;
10501 GstStructure* str = NULL;
10502 GstCaps* srccaps = NULL;
10506 return_val_if_fail ( player, FALSE );
10507 return_val_if_fail ( srcpad, FALSE );
10509 /* to check any of the decoder (video/audio) need to be linked to parser*/
10510 #ifdef GST_API_VERSION_1
10511 srccaps = gst_pad_get_current_caps( srcpad );
10513 srccaps = gst_pad_get_caps( srcpad );
10518 str = gst_caps_get_structure( srccaps, 0 );
10522 name = gst_structure_get_name(str);
10526 if (strstr(name, "video"))
10528 if(player->videosink_linked)
10530 debug_msg("Video Sink already linked\n");
10534 if (strstr(name, "audio"))
10536 if(player->audiosink_linked)
10538 debug_msg("Audio Sink already linked\n");
10542 if (strstr(name, "text"))
10544 if(player->textsink_linked)
10546 debug_msg("Text Sink already linked\n");
10551 gst_caps_unref( srccaps );
10556 //return (!player->videosink_linked || !player->audiosink_linked);
10560 gst_caps_unref( srccaps );
10566 /* sending event to one of sinkelements */
10568 __gst_send_event_to_sink( mm_player_t* player, GstEvent* event )
10570 GstEvent * event2 = NULL;
10571 GList *sinks = NULL;
10572 gboolean res = FALSE;
10576 return_val_if_fail( player, FALSE );
10577 return_val_if_fail ( event, FALSE );
10579 if ( player->play_subtitle && !player->use_textoverlay)
10580 event2 = gst_event_copy((const GstEvent *)event);
10582 sinks = player->sink_elements;
10585 GstElement *sink = GST_ELEMENT_CAST (sinks->data);
10587 if (GST_IS_ELEMENT(sink))
10589 /* keep ref to the event */
10590 gst_event_ref (event);
10592 if ( (res = gst_element_send_event (sink, event)) )
10594 debug_log("sending event[%s] to sink element [%s] success!\n",
10595 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink) );
10599 debug_log("sending event[%s] to sink element [%s] failed. try with next one.\n",
10600 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink) );
10603 sinks = g_list_next (sinks);
10606 /* Note : Textbin is not linked to the video or audio bin.
10607 * It needs to send the event to the text sink seperatelly.
10609 if ( player->play_subtitle && !player->use_textoverlay)
10611 GstElement *text_sink = GST_ELEMENT_CAST (player->pipeline->textbin[MMPLAYER_T_SINK].gst);
10613 if (GST_IS_ELEMENT(text_sink))
10615 /* keep ref to the event */
10616 gst_event_ref (event2);
10618 if ( (res != gst_element_send_event (text_sink, event2)) )
10620 debug_error("sending event[%s] to subtitle sink element [%s] failed!\n",
10621 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink) );
10625 debug_log("sending event[%s] to subtitle sink element [%s] success!\n",
10626 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink) );
10629 gst_event_unref (event2);
10633 gst_event_unref (event);
10641 __mmplayer_add_sink( mm_player_t* player, GstElement* sink )
10645 return_if_fail ( player );
10646 return_if_fail ( sink );
10648 player->sink_elements =
10649 g_list_append(player->sink_elements, sink);
10655 __mmplayer_del_sink( mm_player_t* player, GstElement* sink )
10659 return_if_fail ( player );
10660 return_if_fail ( sink );
10662 player->sink_elements =
10663 g_list_remove(player->sink_elements, sink);
10669 __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
10670 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
10671 gint64 cur, GstSeekType stop_type, gint64 stop )
10673 GstEvent* event = NULL;
10674 gboolean result = FALSE;
10678 return_val_if_fail( player, FALSE );
10680 event = gst_event_new_seek (rate, format, flags, cur_type,
10681 cur, stop_type, stop);
10683 result = __gst_send_event_to_sink( player, event );
10690 /* NOTE : be careful with calling this api. please refer to below glib comment
10691 * glib comment : Note that there is a bug in GObject that makes this function much
10692 * less useful than it might seem otherwise. Once gobject is disposed, the callback
10693 * will no longer be called, but, the signal handler is not currently disconnected.
10694 * If the instance is itself being freed at the same time than this doesn't matter,
10695 * since the signal will automatically be removed, but if instance persists,
10696 * then the signal handler will leak. You should not remove the signal yourself
10697 * because in a future versions of GObject, the handler will automatically be
10700 * It's possible to work around this problem in a way that will continue to work
10701 * with future versions of GObject by checking that the signal handler is still
10702 * connected before disconnected it:
10704 * if (g_signal_handler_is_connected (instance, id))
10705 * g_signal_handler_disconnect (instance, id);
10708 __mmplayer_release_signal_connection(mm_player_t* player)
10710 GList* sig_list = player->signals;
10711 MMPlayerSignalItem* item = NULL;
10715 return_if_fail( player );
10717 for ( ; sig_list; sig_list = sig_list->next )
10719 item = sig_list->data;
10721 if ( item && item->obj && GST_IS_ELEMENT(item->obj) )
10723 debug_log("checking signal connection : [%lud] from [%s]\n", item->sig, GST_OBJECT_NAME( item->obj ));
10725 if ( g_signal_handler_is_connected ( item->obj, item->sig ) )
10727 debug_log("signal disconnecting : [%lud] from [%s]\n", item->sig, GST_OBJECT_NAME( item->obj ));
10728 g_signal_handler_disconnect ( item->obj, item->sig );
10732 MMPLAYER_FREEIF( item );
10735 g_list_free ( player->signals );
10736 player->signals = NULL;
10744 /* Note : if silent is true, then subtitle would not be displayed. :*/
10745 int _mmplayer_set_subtitle_silent (MMHandleType hplayer, int silent)
10747 mm_player_t* player = (mm_player_t*) hplayer;
10751 /* check player handle */
10752 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED );
10754 player->is_subtitle_off = silent;
10756 debug_log("subtitle is %s.\n", player->is_subtitle_off ? "ON" : "OFF");
10760 return MM_ERROR_NONE;
10764 int _mmplayer_get_subtitle_silent (MMHandleType hplayer, int* silent)
10766 mm_player_t* player = (mm_player_t*) hplayer;
10770 /* check player handle */
10771 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED );
10773 *silent = player->is_subtitle_off;
10775 debug_log("subtitle is %s.\n", silent ? "ON" : "OFF");
10779 return MM_ERROR_NONE;
10782 int _mmplayer_get_track_count(MMHandleType hplayer, MMPlayerTrackType track_type, int *count)
10784 mm_player_t* player = (mm_player_t*) hplayer;
10785 MMHandleType attrs = 0;
10786 int ret = MM_ERROR_NONE;
10790 /* check player handle */
10791 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10792 return_val_if_fail(count, MM_ERROR_COMMON_INVALID_ARGUMENT);
10793 return_val_if_fail((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
10794 ||(MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING),
10795 MM_ERROR_PLAYER_INVALID_STATE);
10797 attrs = MMPLAYER_GET_ATTRS(player);
10800 debug_error("cannot get content attribute");
10801 return MM_ERROR_PLAYER_INTERNAL;
10804 switch (track_type)
10806 case MM_PLAYER_TRACK_TYPE_AUDIO:
10807 ret = mm_attrs_get_int_by_name(attrs, "content_audio_track_num", count);
10809 case MM_PLAYER_TRACK_TYPE_VIDEO:
10810 ret = mm_attrs_get_int_by_name(attrs, "content_video_track_num", count);
10812 case MM_PLAYER_TRACK_TYPE_TEXT:
10813 ret = mm_attrs_get_int_by_name(attrs, "content_text_track_num", count);
10816 ret = MM_ERROR_COMMON_INVALID_ARGUMENT;
10820 debug_log ("%d track num is %d\n", track_type, *count);
10829 __get_state_name ( int state )
10833 case MM_PLAYER_STATE_NULL:
10835 case MM_PLAYER_STATE_READY:
10837 case MM_PLAYER_STATE_PAUSED:
10839 case MM_PLAYER_STATE_PLAYING:
10841 case MM_PLAYER_STATE_NONE:
10849 __is_rtsp_streaming ( mm_player_t* player )
10851 return_val_if_fail ( player, FALSE );
10853 return ( player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_RTSP ) ? TRUE : FALSE;
10857 __is_http_streaming ( mm_player_t* player )
10859 return_val_if_fail ( player, FALSE );
10861 return ( player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_HTTP ) ? TRUE : FALSE;
10865 __is_streaming ( mm_player_t* player )
10867 return_val_if_fail ( player, FALSE );
10869 return ( __is_rtsp_streaming ( player ) || __is_http_streaming ( player ) || __is_http_live_streaming ( player )) ? TRUE : FALSE;
10873 __is_live_streaming ( mm_player_t* player )
10875 return_val_if_fail ( player, FALSE );
10877 return ( __is_rtsp_streaming ( player ) && player->streaming_type == STREAMING_SERVICE_LIVE ) ? TRUE : FALSE;
10881 __is_http_live_streaming( mm_player_t* player )
10883 return_val_if_fail( player, FALSE );
10885 return ( player->profile.uri_type == MM_PLAYER_URI_TYPE_HLS ) ? TRUE : FALSE;
10889 __is_http_progressive_down(mm_player_t* player)
10891 return_val_if_fail( player, FALSE );
10893 return ((player->pd_mode) ? TRUE:FALSE);