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 #include <gst/interfaces/xoverlay.h>
38 #include <mm_attrs_private.h>
41 #include "mm_player_priv.h"
42 #include "mm_player_ini.h"
43 #include "mm_player_attrs.h"
44 #include "mm_player_capture.h"
46 /*===========================================================================================
48 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
50 ========================================================================================== */
52 /*---------------------------------------------------------------------------
53 | GLOBAL CONSTANT DEFINITIONS: |
54 ---------------------------------------------------------------------------*/
56 /*---------------------------------------------------------------------------
57 | IMPORTED VARIABLE DECLARATIONS: |
58 ---------------------------------------------------------------------------*/
60 /*---------------------------------------------------------------------------
61 | IMPORTED FUNCTION DECLARATIONS: |
62 ---------------------------------------------------------------------------*/
64 /*---------------------------------------------------------------------------
66 ---------------------------------------------------------------------------*/
67 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
68 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
70 #define MM_VOLUME_FACTOR_DEFAULT 1.0
71 #define MM_VOLUME_FACTOR_MIN 0
72 #define MM_VOLUME_FACTOR_MAX 1.0
74 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 700000 // 700 msec
76 #define MM_PLAYER_MPEG_VNAME "mpegversion"
77 #define MM_PLAYER_DIVX_VNAME "divxversion"
78 #define MM_PLAYER_WMV_VNAME "wmvversion"
79 #define MM_PLAYER_WMA_VNAME "wmaversion"
81 #define DEFAULT_PLAYBACK_RATE 1.0
83 #define GST_QUEUE_DEFAULT_TIME 2
84 #define GST_QUEUE_HLS_TIME 8
86 /* video capture callback*/
87 gulong ahs_appsrc_cb_probe_id = 0;
89 #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) )
90 #define MMPLAYER_PLAY_SUBTITLE(player) ((player)->play_subtitle)
92 #define LAZY_PAUSE_TIMEOUT_MSEC 700
94 /*---------------------------------------------------------------------------
95 | LOCAL CONSTANT DEFINITIONS: |
96 ---------------------------------------------------------------------------*/
98 /*---------------------------------------------------------------------------
99 | LOCAL DATA TYPE DEFINITIONS: |
100 ---------------------------------------------------------------------------*/
102 /*---------------------------------------------------------------------------
103 | GLOBAL VARIABLE DEFINITIONS: |
104 ---------------------------------------------------------------------------*/
106 /*---------------------------------------------------------------------------
107 | LOCAL VARIABLE DEFINITIONS: |
108 ---------------------------------------------------------------------------*/
110 /*---------------------------------------------------------------------------
111 | LOCAL FUNCTION PROTOTYPES: |
112 ---------------------------------------------------------------------------*/
113 static gboolean __mmplayer_set_state(mm_player_t* player, int state);
114 static int __mmplayer_get_state(mm_player_t* player);
115 static int __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps *caps, MMDisplaySurfaceType surface_type);
116 static int __mmplayer_gst_create_audio_pipeline(mm_player_t* player);
117 static int __mmplayer_gst_create_text_pipeline(mm_player_t* player);
118 static int __mmplayer_gst_create_subtitle_pipeline(mm_player_t* player);
119 static int __mmplayer_gst_create_pipeline(mm_player_t* player);
120 static int __mmplayer_gst_destroy_pipeline(mm_player_t* player);
121 static int __mmplayer_gst_element_link_bucket(GList* element_bucket);
123 static gboolean __mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data);
124 static void __mmplayer_gst_decode_callback(GstElement *decodebin, GstPad *pad, gboolean last, gpointer data);
126 static void __mmplayer_typefind_have_type( GstElement *tf, guint probability, GstCaps *caps, gpointer data);
127 static gboolean __mmplayer_try_to_plug(mm_player_t* player, GstPad *pad, const GstCaps *caps);
128 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
129 static gboolean __mmplayer_is_midi_type(gchar* str_caps);
130 static gboolean __mmplayer_is_amr_type (gchar *str_caps);
131 static gboolean __mmplayer_is_only_mp3_type (gchar *str_caps);
133 static gboolean __mmplayer_close_link(mm_player_t* player, GstPad *srcpad, GstElement *sinkelement, const char *padname, const GList *templlist);
134 static gboolean __mmplayer_feature_filter(GstPluginFeature *feature, gpointer data);
135 static void __mmplayer_add_new_pad(GstElement *element, GstPad *pad, gpointer data);
137 static void __mmplayer_gst_rtp_no_more_pads (GstElement *element, gpointer data);
138 static void __mmplayer_gst_rtp_dynamic_pad (GstElement *element, GstPad *pad, gpointer data);
139 static gboolean __mmplayer_update_stream_service_type( mm_player_t* player );
140 static gboolean __mmplayer_update_subtitle( GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
143 static void __mmplayer_init_factories(mm_player_t* player);
144 static void __mmplayer_release_factories(mm_player_t* player);
145 static void __mmplayer_release_misc(mm_player_t* player);
146 static gboolean __mmplayer_gstreamer_init(void);
148 static int __mmplayer_gst_set_state (mm_player_t* player, GstElement * pipeline, GstState state, gboolean async, gint timeout );
149 gboolean __mmplayer_post_message(mm_player_t* player, enum MMMessageType msgtype, MMMessageParamType* param);
150 static gboolean __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage *msg);
151 int __mmplayer_switch_audio_sink (mm_player_t* player);
152 static gboolean __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink);
153 static int __mmplayer_check_state(mm_player_t* player, enum PlayerCommandState command);
154 static gboolean __mmplayer_audio_stream_probe (GstPad *pad, GstBuffer *buffer, gpointer u_data);
156 static gboolean __mmplayer_dump_pipeline_state( mm_player_t* player );
157 static gboolean __mmplayer_check_subtitle( mm_player_t* player );
158 static gboolean __mmplayer_handle_gst_error ( mm_player_t* player, GstMessage * message, GError* error );
159 static gboolean __mmplayer_handle_streaming_error ( mm_player_t* player, GstMessage * message );
160 static void __mmplayer_post_delayed_eos( mm_player_t* player, int delay_in_ms );
161 static void __mmplayer_cancel_delayed_eos( mm_player_t* player );
162 static gboolean __mmplayer_eos_timer_cb(gpointer u_data);
163 static gboolean __mmplayer_link_decoder( mm_player_t* player,GstPad *srcpad);
164 static gboolean __mmplayer_link_sink( mm_player_t* player,GstPad *srcpad);
165 static int __mmplayer_post_missed_plugin(mm_player_t* player);
166 static int __mmplayer_check_not_supported_codec(mm_player_t* player, gchar* mime);
167 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player);
168 static void __mmplayer_add_sink( mm_player_t* player, GstElement* sink);
169 static void __mmplayer_del_sink( mm_player_t* player, GstElement* sink);
170 static void __mmplayer_release_signal_connection(mm_player_t* player);
171 static void __mmplayer_set_antishock( mm_player_t* player, gboolean disable_by_force);
172 static gpointer __mmplayer_repeat_thread(gpointer data);
173 int _mmplayer_get_track_count(MMHandleType hplayer, MMPlayerTrackType track_type, int *count);
175 static int __gst_realize(mm_player_t* player);
176 static int __gst_unrealize(mm_player_t* player);
177 static int __gst_start(mm_player_t* player);
178 static int __gst_stop(mm_player_t* player);
179 static int __gst_pause(mm_player_t* player, gboolean async);
180 static int __gst_resume(mm_player_t* player, gboolean async);
181 static gboolean __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
182 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
183 gint64 cur, GstSeekType stop_type, gint64 stop );
184 static int __gst_pending_seek ( mm_player_t* player );
186 static int __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called);
187 static int __gst_get_position(mm_player_t* player, int format, unsigned long *position);
188 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos);
189 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position);
190 static int __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param);
191 static void __gst_set_async_state_change(mm_player_t* player, gboolean async);
193 static gint __gst_handle_core_error( mm_player_t* player, int code );
194 static gint __gst_handle_library_error( mm_player_t* player, int code );
195 static gint __gst_handle_resource_error( mm_player_t* player, int code );
196 static gint __gst_handle_stream_error( mm_player_t* player, GError* error, GstMessage * message );
197 static gint __gst_transform_gsterror( mm_player_t* player, GstMessage * message, GError* error);
198 static gboolean __gst_send_event_to_sink( mm_player_t* player, GstEvent* event );
200 static int __mmplayer_set_pcm_extraction(mm_player_t* player);
201 static gboolean __mmplayer_can_extract_pcm( mm_player_t* player );
204 static void __mmplayer_do_sound_fadedown(mm_player_t* player, unsigned int time);
205 static void __mmplayer_undo_sound_fadedown(mm_player_t* player);
207 static void __mmplayer_add_new_caps(GstPad* pad, GParamSpec* unused, gpointer data);
208 static void __mmplayer_set_unlinked_mime_type(mm_player_t* player, GstCaps *caps);
211 const gchar * __get_state_name ( int state );
212 static gboolean __is_streaming( mm_player_t* player );
213 static gboolean __is_rtsp_streaming( mm_player_t* player );
214 static gboolean __is_live_streaming ( mm_player_t* player );
215 static gboolean __is_http_streaming( mm_player_t* player );
216 static gboolean __is_http_live_streaming( mm_player_t* player );
217 static gboolean __is_http_progressive_down(mm_player_t* player);
219 static gboolean __mmplayer_warm_up_video_codec( mm_player_t* player, GstElementFactory *factory);
220 static GstBusSyncReply __mmplayer_bus_sync_callback (GstBus * bus, GstMessage * message, gpointer data);
222 static int __mmplayer_realize_streaming_ext(mm_player_t* player);
223 static int __mmplayer_unrealize_streaming_ext(mm_player_t *player);
224 static int __mmplayer_start_streaming_ext(mm_player_t *player);
225 static int __mmplayer_destroy_streaming_ext(mm_player_t* player);
228 /*===========================================================================================
230 | FUNCTION DEFINITIONS |
232 ========================================================================================== */
234 /* implementing player FSM */
235 /* FIXIT : We need to handle state transition also at here since start api is no more sync */
237 __mmplayer_check_state(mm_player_t* player, enum PlayerCommandState command)
239 MMPlayerStateType current_state = MM_PLAYER_STATE_NUM;
240 MMPlayerStateType pending_state = MM_PLAYER_STATE_NUM;
241 MMPlayerStateType target_state = MM_PLAYER_STATE_NUM;
242 MMPlayerStateType prev_state = MM_PLAYER_STATE_NUM;
246 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
248 //debug_log("incomming command : %d \n", command );
250 current_state = MMPLAYER_CURRENT_STATE(player);
251 pending_state = MMPLAYER_PENDING_STATE(player);
252 target_state = MMPLAYER_TARGET_STATE(player);
253 prev_state = MMPLAYER_PREV_STATE(player);
255 MMPLAYER_PRINT_STATE(player);
259 case MMPLAYER_COMMAND_CREATE:
261 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
263 if ( current_state == MM_PLAYER_STATE_NULL ||
264 current_state == MM_PLAYER_STATE_READY ||
265 current_state == MM_PLAYER_STATE_PAUSED ||
266 current_state == MM_PLAYER_STATE_PLAYING )
271 case MMPLAYER_COMMAND_DESTROY:
273 /* destroy can called anytime */
275 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
279 case MMPLAYER_COMMAND_REALIZE:
281 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
283 if ( pending_state != MM_PLAYER_STATE_NONE )
289 /* need ready state to realize */
290 if ( current_state == MM_PLAYER_STATE_READY )
293 if ( current_state != MM_PLAYER_STATE_NULL )
299 case MMPLAYER_COMMAND_UNREALIZE:
301 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
303 if ( current_state == MM_PLAYER_STATE_NULL )
308 case MMPLAYER_COMMAND_START:
310 if (MMPLAYER_IS_HTTP_PD(player))
313 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
315 if ( pending_state == MM_PLAYER_STATE_NONE )
317 if ( current_state == MM_PLAYER_STATE_PLAYING )
319 else if ( current_state != MM_PLAYER_STATE_READY &&
320 current_state != MM_PLAYER_STATE_PAUSED )
323 else if ( pending_state == MM_PLAYER_STATE_PLAYING )
327 else if ( pending_state == MM_PLAYER_STATE_PAUSED )
329 debug_log("player is going to paused state, just change the pending state as playing");
338 case MMPLAYER_COMMAND_STOP:
340 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
342 if ( current_state == MM_PLAYER_STATE_READY )
345 /* need playing/paused state to stop */
346 if ( current_state != MM_PLAYER_STATE_PLAYING &&
347 current_state != MM_PLAYER_STATE_PAUSED )
352 case MMPLAYER_COMMAND_PAUSE:
354 if ( MMPLAYER_IS_LIVE_STREAMING( player ) )
357 if (player->doing_seek)
358 goto NOT_COMPLETED_SEEK;
360 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
362 if ( pending_state == MM_PLAYER_STATE_NONE )
364 if ( current_state == MM_PLAYER_STATE_PAUSED )
366 else if ( current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY ) // support loading state of broswer
369 else if ( pending_state == MM_PLAYER_STATE_PAUSED )
373 else if ( pending_state == MM_PLAYER_STATE_PLAYING )
375 if ( current_state == MM_PLAYER_STATE_PAUSED ) {
376 debug_log("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
384 case MMPLAYER_COMMAND_RESUME:
386 if ( MMPLAYER_IS_LIVE_STREAMING(player) )
389 if (player->doing_seek)
390 goto NOT_COMPLETED_SEEK;
392 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
394 if ( pending_state == MM_PLAYER_STATE_NONE )
396 if ( current_state == MM_PLAYER_STATE_PLAYING )
398 else if ( current_state != MM_PLAYER_STATE_PAUSED )
401 else if ( pending_state == MM_PLAYER_STATE_PLAYING )
405 else if ( pending_state == MM_PLAYER_STATE_PAUSED )
407 debug_log("player is going to paused state, just change the pending state as playing");
419 player->cmd = command;
422 return MM_ERROR_NONE;
425 debug_warning("since player is in wrong state(%s). it's not able to apply the command(%d)",
426 MMPLAYER_STATE_GET_NAME(current_state), command);
427 return MM_ERROR_PLAYER_INVALID_STATE;
430 debug_warning("not completed seek");
431 return MM_ERROR_PLAYER_DOING_SEEK;
434 debug_warning("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
435 return MM_ERROR_PLAYER_NO_OP;
438 debug_warning("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
439 return MM_ERROR_PLAYER_NO_OP;
443 __mmplayer_gst_set_state (mm_player_t* player, GstElement * element, GstState state, gboolean async, gint timeout) // @
445 GstState element_state = GST_STATE_VOID_PENDING;
446 GstState element_pending_state = GST_STATE_VOID_PENDING;
447 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
451 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
452 return_val_if_fail ( element, MM_ERROR_INVALID_ARGUMENT );
454 debug_log("setting [%s] element state to : %d\n", GST_ELEMENT_NAME(element), state);
457 ret = gst_element_set_state(element, state);
459 if ( ret == GST_STATE_CHANGE_FAILURE )
461 debug_error("failed to set [%s] state to [%d]\n", GST_ELEMENT_NAME(element), state);
462 return MM_ERROR_PLAYER_INTERNAL;
465 /* return here so state transition to be done in async mode */
468 debug_log("async state transition. not waiting for state complete.\n");
469 return MM_ERROR_NONE;
472 /* wait for state transition */
473 ret = gst_element_get_state( element, &element_state, &element_pending_state, timeout * GST_SECOND );
475 if ( ret == GST_STATE_CHANGE_FAILURE || ( state != element_state ) )
477 debug_error("failed to change [%s] element state to [%s] within %d sec\n",
478 GST_ELEMENT_NAME(element),
479 gst_element_state_get_name(state), timeout );
481 debug_error(" [%s] state : %s pending : %s \n",
482 GST_ELEMENT_NAME(element),
483 gst_element_state_get_name(element_state),
484 gst_element_state_get_name(element_pending_state) );
486 return MM_ERROR_PLAYER_INTERNAL;
489 debug_log("[%s] element state has changed to %s \n",
490 GST_ELEMENT_NAME(element),
491 gst_element_state_get_name(element_state));
495 return MM_ERROR_NONE;
499 __mmplayer_videostream_cb(GstElement *element, void *stream,
500 int width, int height, gpointer data) // @
502 mm_player_t* player = (mm_player_t*)data;
505 return_if_fail ( player );
509 if (player->video_stream_cb )
511 length = width * height * 4; // for rgb 32bit
512 player->video_stream_cb(stream, length, player->video_stream_cb_user_param, width, height);
519 _mmplayer_update_content_attrs(mm_player_t* player) // @
521 GstFormat fmt = GST_FORMAT_TIME;
523 GstStructure* p = NULL;
524 MMHandleType attrs = 0;
525 gint retry_count = 0;
526 gint retry_count_max = 10;
530 return_val_if_fail ( player, FALSE );
532 if ( ! player->need_update_content_attrs )
534 debug_log("content attributes are already updated");
538 /* get content attribute first */
539 attrs = MMPLAYER_GET_ATTRS(player);
542 debug_error("cannot get content attribute");
547 * NOTE : we need to wait for a while until is possible to get duration from pipeline
548 * as getting duration timing is depends on behavier of demuxers ( or etc ).
549 * we set timeout 100ms * 10 as initial value. fix it if needed.
551 if ( player->need_update_content_dur )
553 while ( retry_count < retry_count_max)
555 if ( FALSE == gst_element_query_duration( player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
558 /* retry if failed */
559 debug_warning("failed to get duraton. waiting 100ms and then retrying...");
565 if ( dur_nsec == 0 && ( !MMPLAYER_IS_LIVE_STREAMING( player ) ) )
567 /* retry if duration is zero in case of not live stream */
568 debug_warning("returned duration is zero. but it's not an live stream. retrying...");
577 player->duration = dur_nsec;
578 debug_log("duration : %lld msec", GST_TIME_AS_MSECONDS(dur_nsec));
580 /* try to get streaming service type */
581 __mmplayer_update_stream_service_type( player );
583 /* check duration is OK */
584 if ( dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING( player ) )
586 /* FIXIT : find another way to get duration here. */
587 debug_error("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
591 player->need_update_content_dur = FALSE;
595 mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(dur_nsec));
599 debug_log("not ready to get duration or already updated");
602 /* update rate, channels */
603 if ( player->pipeline->audiobin &&
604 player->pipeline->audiobin[MMPLAYER_A_SINK].gst )
606 GstCaps *caps_a = NULL;
608 gint samplerate = 0, channels = 0;
610 pad = gst_element_get_static_pad(
611 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink" );
615 caps_a = gst_pad_get_negotiated_caps( pad );
619 p = gst_caps_get_structure (caps_a, 0);
621 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
622 if ( ! samplerate ) // check if update already or not
624 gst_structure_get_int (p, "rate", &samplerate);
625 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
627 gst_structure_get_int (p, "channels", &channels);
628 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
630 debug_log("samplerate : %d channels : %d", samplerate, channels);
632 gst_caps_unref( caps_a );
637 debug_warning("not ready to get audio caps");
640 gst_object_unref( pad );
644 debug_warning("failed to get pad from audiosink");
648 /* update width, height, framerate */
649 if ( player->pipeline->videobin &&
650 player->pipeline->videobin[MMPLAYER_V_SINK].gst )
652 GstCaps *caps_v = NULL;
657 pad = gst_element_get_static_pad( player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink" );
660 caps_v = gst_pad_get_negotiated_caps( pad );
663 p = gst_caps_get_structure (caps_v, 0);
664 gst_structure_get_int (p, "width", &width);
665 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
667 gst_structure_get_int (p, "height", &height);
668 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
670 gst_structure_get_fraction (p, "framerate", &tmpNu, &tmpDe);
672 debug_log("width : %d height : %d", width, height );
674 gst_caps_unref( caps_v );
679 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
680 debug_log("fps : %d", tmpNu / tmpDe);
685 debug_warning("failed to get negitiated caps from videosink");
687 gst_object_unref( pad );
692 debug_warning("failed to get pad from videosink");
696 if (player->duration)
698 guint64 data_size = 0;
700 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO))
702 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
704 if (stat(path, &sb) == 0)
706 data_size = (guint64)sb.st_size;
709 else if (MMPLAYER_IS_HTTP_STREAMING(player))
711 data_size = player->http_content_size;
717 guint64 msec_dur = 0;
719 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
720 bitrate = data_size * 8 * 1000 / msec_dur;
721 debug_log("file size : %u, video bitrate = %llu", data_size, bitrate);
722 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
728 if ( mmf_attrs_commit ( attrs ) )
730 debug_error("failed to update attributes\n");
734 player->need_update_content_attrs = FALSE;
739 gboolean __mmplayer_update_stream_service_type( mm_player_t* player )
741 MMHandleType attrs = 0;
742 gint streaming_type = STREAMING_SERVICE_NONE;
746 return_val_if_fail ( player &&
748 player->pipeline->mainbin &&
749 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
752 /* streaming service type if streaming */
753 if ( ! MMPLAYER_IS_STREAMING(player) );
756 if (MMPLAYER_IS_RTSP_STREAMING(player))
758 /* get property from rtspsrc element */
759 g_object_get(G_OBJECT(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), "service_type", &streaming_type, NULL);
761 else if (MMPLAYER_IS_HTTP_STREAMING(player))
763 if ( player->duration <= 0)
764 streaming_type = STREAMING_SERVICE_LIVE;
766 streaming_type = STREAMING_SERVICE_VOD;
769 player->streaming_type = streaming_type;
771 if ( player->streaming_type == STREAMING_SERVICE_LIVE)
773 debug_log("It's live streaming. pause/resume/seek are not working.\n");
775 else if (player->streaming_type == STREAMING_SERVICE_LIVE)
777 debug_log("It's vod streaming. pause/resume/seek are working.\n");
781 debug_warning("fail to determine streaming type. pause/resume/seek may not working properly if stream is live stream\n");
784 /* get profile attribute */
785 attrs = MMPLAYER_GET_ATTRS(player);
788 debug_error("cannot get content attribute\n");
792 mm_attrs_set_int_by_name ( attrs, "streaming_type", streaming_type );
794 if ( mmf_attrs_commit ( attrs ) )
796 debug_warning("updating streaming service type failed. pause/resume/seek may not working properly if stream is live stream\n");
806 /* this function sets the player state and also report
807 * it to applicaton by calling callback function
810 __mmplayer_set_state(mm_player_t* player, int state) // @
812 MMMessageParamType msg = {0, };
813 int asm_result = MM_ERROR_NONE;
816 return_val_if_fail ( player, FALSE );
818 if ( MMPLAYER_CURRENT_STATE(player) == state )
820 debug_warning("already same state(%s)\n", MMPLAYER_STATE_GET_NAME(state));
821 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
825 /* post message to application */
826 if (MMPLAYER_TARGET_STATE(player) == state)
828 /* fill the message with state of player */
829 msg.state.previous = MMPLAYER_CURRENT_STATE(player);
830 msg.state.current = state;
832 /* state changed by asm callback */
833 if ( player->sm.by_asm_cb )
835 msg.union_type = MM_MSG_UNION_CODE;
836 msg.code = player->sm.event_src;
837 MMPLAYER_POST_MSG( player, MM_MESSAGE_STATE_INTERRUPTED, &msg );
839 /* state changed by usecase */
842 MMPLAYER_POST_MSG( player, MM_MESSAGE_STATE_CHANGED, &msg );
845 debug_log ("player reach the target state, then do something in each state(%s).\n",
846 MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
850 debug_log ("intermediate state, do nothing.\n");
851 MMPLAYER_PRINT_STATE(player);
856 /* update player states */
857 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
858 MMPLAYER_CURRENT_STATE(player) = state;
859 if ( MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player) )
860 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
863 MMPLAYER_PRINT_STATE(player);
865 switch ( MMPLAYER_TARGET_STATE(player) )
867 case MM_PLAYER_STATE_NULL:
868 case MM_PLAYER_STATE_READY:
870 if (player->cmd == MMPLAYER_COMMAND_STOP)
872 asm_result = _mmplayer_asm_set_state((MMHandleType)player, ASM_STATE_STOP);
873 if ( asm_result != MM_ERROR_NONE )
875 debug_error("failed to set asm state to stop\n");
882 case MM_PLAYER_STATE_PAUSED:
884 /* special care for local playback. normaly we can get some content attribute
885 * when the demuxer is changed to PAUSED. so we are trying it. it will be tried again
886 * when PLAYING state has signalled if failed.
887 * note that this is only happening pause command has come before the state of pipeline
888 * reach to the PLAYING.
890 if ( ! player->sent_bos ) // managed prepare sync case
892 player->need_update_content_dur = TRUE;
893 _mmplayer_update_content_attrs( player );
896 /* add audio callback probe if condition is satisfied */
897 if ( ! player->audio_cb_probe_id && player->is_sound_extraction )
898 __mmplayer_configure_audio_callback(player);
900 asm_result = _mmplayer_asm_set_state((MMHandleType)player, ASM_STATE_PAUSE);
903 debug_error("failed to set asm state to PAUSE\n");
909 case MM_PLAYER_STATE_PLAYING:
911 /* non-managed prepare case, should be updated */
912 if ( ! player->need_update_content_dur)
914 player->need_update_content_dur = TRUE;
915 _mmplayer_update_content_attrs ( player );
918 if ( player->cmd == MMPLAYER_COMMAND_START && !player->sent_bos )
920 __mmplayer_post_missed_plugin ( player );
922 /* update video resource status */
923 if ( ( player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO )
925 asm_result = _mmplayer_asm_set_state((MMHandleType)player, ASM_STATE_PLAYING);
928 MMMessageParamType msg = {0, };
930 debug_error("failed to go ahead because of video conflict\n");
932 msg.union_type = MM_MSG_UNION_CODE;
933 msg.code = MM_ERROR_POLICY_INTERRUPTED;
934 MMPLAYER_POST_MSG( player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
936 _mmplayer_unrealize((MMHandleType)player);
943 if ( player->resumed_by_rewind && player->playback_rate < 0.0 )
945 /* initialize because auto resume is done well. */
946 player->resumed_by_rewind = FALSE;
947 player->playback_rate = 1.0;
950 if ( !player->sent_bos )
952 /* check audio codec field is set or not
953 * we can get it from typefinder or codec's caps.
955 gchar *audio_codec = NULL;
956 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
958 /* The codec format can't be sent for audio only case like amr, mid etc.
959 * Because, parser don't make related TAG.
960 * So, if it's not set yet, fill it with found data.
964 if ( g_strrstr(player->type, "audio/midi"))
966 audio_codec = g_strdup("MIDI");
969 else if ( g_strrstr(player->type, "audio/x-amr"))
971 audio_codec = g_strdup("AMR");
973 else if ( g_strrstr(player->type, "audio/mpeg") && !g_strrstr(player->type, "mpegversion=(int)1"))
975 audio_codec = g_strdup("AAC");
979 audio_codec = g_strdup("unknown");
981 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
983 MMPLAYER_FREEIF(audio_codec);
984 mmf_attrs_commit(player->attrs);
985 debug_log("set audio codec type with caps\n");
988 MMTA_ACUM_ITEM_END("[KPI] start media player service", FALSE);
989 MMTA_ACUM_ITEM_END("[KPI] media player service create->playing", FALSE);
991 MMPLAYER_POST_MSG ( player, MM_MESSAGE_BEGIN_OF_STREAM, NULL );
992 player->sent_bos = TRUE;
997 case MM_PLAYER_STATE_NONE:
999 debug_warning("invalid target state, there is nothing to do.\n");
1010 __mmplayer_post_message(mm_player_t* player, enum MMMessageType msgtype, MMMessageParamType* param) // @
1012 return_val_if_fail( player, FALSE );
1016 if ( !player->msg_cb )
1018 debug_warning("no msg callback. can't post\n");
1022 //debug_log("Message (type : %d) will be posted using msg-cb(%p). \n", msgtype, player->msg_cb);
1024 player->msg_cb(msgtype, param, player->msg_cb_param);
1033 __mmplayer_get_state(mm_player_t* player) // @
1035 int state = MM_PLAYER_STATE_NONE;
1039 return_val_if_fail ( player, MM_PLAYER_STATE_NONE );
1041 state = MMPLAYER_CURRENT_STATE(player);
1043 debug_log("player state is %s.\n", MMPLAYER_STATE_GET_NAME(state));
1051 __gst_set_async_state_change(mm_player_t* player, gboolean async)
1054 return_if_fail( player && player->pipeline && player->pipeline->mainbin );
1056 /* need only when we are using decodebin */
1057 if ( ! PLAYER_INI()->use_decodebin )
1061 if ( player->pipeline->audiobin &&
1062 player->pipeline->audiobin[MMPLAYER_A_SINK].gst )
1064 debug_log("audiosink async : %d\n", async);
1065 g_object_set (G_OBJECT (player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "async", async, NULL);
1069 if ( player->pipeline->videobin &&
1070 player->pipeline->videobin[MMPLAYER_V_SINK].gst )
1072 debug_log("videosink async : %d\n", async);
1073 g_object_set (G_OBJECT (player->pipeline->videobin[MMPLAYER_V_SINK].gst), "async", async, NULL);
1076 /* decodebin if enabled */
1077 if ( PLAYER_INI()->use_decodebin )
1079 debug_log("decodebin async : %d\n", async);
1080 g_object_set (G_OBJECT (player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst), "async-handling", async, NULL);
1086 static gpointer __mmplayer_repeat_thread(gpointer data)
1088 mm_player_t* player = (mm_player_t*) data;
1089 gboolean ret_value = FALSE;
1090 MMHandleType attrs = 0;
1093 return_val_if_fail ( player, NULL );
1095 while ( ! player->repeat_thread_exit )
1097 debug_log("repeat thread started. waiting for signal.\n");
1098 g_cond_wait( player->repeat_thread_cond, player->repeat_thread_mutex );
1100 if ( player->repeat_thread_exit )
1102 debug_log("exiting repeat thread\n");
1106 if ( !player->cmd_lock )
1108 debug_log("can't get cmd lock\n");
1113 g_mutex_lock(player->cmd_lock);
1115 attrs = MMPLAYER_GET_ATTRS(player);
1117 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
1119 debug_error("can not get play count\n");
1123 if ( player->section_repeat )
1125 ret_value = _mmplayer_activate_section_repeat((MMHandleType)player, player->section_repeat_start, player->section_repeat_end);
1129 if ( player->playback_rate < 0.0 )
1131 player->resumed_by_rewind = TRUE;
1132 _mmplayer_set_mute((MMHandleType)player, 0);
1133 MMPLAYER_POST_MSG( player, MM_MESSAGE_RESUMED_BY_REW, NULL );
1136 ret_value = __gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
1137 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET,
1138 0, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
1141 player->sent_bos = FALSE;
1146 debug_error("failed to set position to zero for rewind\n");
1150 /* decrease play count */
1153 /* we successeded to rewind. update play count and then wait for next EOS */
1156 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
1158 /* commit attribute */
1159 if ( mmf_attrs_commit ( attrs ) )
1161 debug_error("failed to commit attribute\n");
1166 g_mutex_unlock(player->cmd_lock);
1173 __mmplayer_handle_buffering_message ( mm_player_t* player )
1175 MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
1176 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
1177 MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
1178 MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
1180 return_if_fail ( player );
1182 prev_state = MMPLAYER_PREV_STATE(player),
1183 current_state = MMPLAYER_CURRENT_STATE(player);
1184 target_state = MMPLAYER_TARGET_STATE(player);
1185 pending_state = MMPLAYER_PENDING_STATE(player);
1187 if ( MMPLAYER_IS_RTSP_STREAMING(player) )
1190 if ( !player->streamer->is_buffering )
1192 debug_log( "player state : prev %s, current %s, pending %s, target %s \n",
1193 MMPLAYER_STATE_GET_NAME(prev_state),
1194 MMPLAYER_STATE_GET_NAME(current_state),
1195 MMPLAYER_STATE_GET_NAME(pending_state),
1196 MMPLAYER_STATE_GET_NAME(target_state));
1198 /* NOTE : if buffering has done, player has to go to target state. */
1199 switch ( target_state )
1201 case MM_PLAYER_STATE_PAUSED :
1203 switch ( pending_state )
1205 case MM_PLAYER_STATE_PLAYING:
1207 __gst_pause ( player, TRUE );
1211 case MM_PLAYER_STATE_PAUSED:
1213 debug_log("player is already going to paused state, there is nothing to do.\n");
1217 case MM_PLAYER_STATE_NONE:
1218 case MM_PLAYER_STATE_NULL:
1219 case MM_PLAYER_STATE_READY:
1222 debug_warning("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state) );
1229 case MM_PLAYER_STATE_PLAYING :
1231 switch ( pending_state )
1233 case MM_PLAYER_STATE_NONE:
1235 if (current_state != MM_PLAYER_STATE_PLAYING)
1236 __gst_resume ( player, TRUE );
1240 case MM_PLAYER_STATE_PAUSED:
1242 /* NOTE: It should be worked as asynchronously.
1243 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
1245 __gst_resume ( player, TRUE );
1249 case MM_PLAYER_STATE_PLAYING:
1251 debug_log("player is already going to playing state, there is nothing to do.\n");
1255 case MM_PLAYER_STATE_NULL:
1256 case MM_PLAYER_STATE_READY:
1259 debug_warning("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state) );
1266 case MM_PLAYER_STATE_NULL :
1267 case MM_PLAYER_STATE_READY :
1268 case MM_PLAYER_STATE_NONE :
1271 debug_warning("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state) );
1278 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1279 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
1281 switch ( pending_state )
1283 case MM_PLAYER_STATE_NONE:
1285 if (current_state != MM_PLAYER_STATE_PAUSED)
1286 __gst_pause ( player, TRUE );
1290 case MM_PLAYER_STATE_PLAYING:
1292 __gst_pause ( player, TRUE );
1296 case MM_PLAYER_STATE_PAUSED:
1298 debug_log("player is already going to paused state, there is nothing to do.\n");
1302 case MM_PLAYER_STATE_NULL:
1303 case MM_PLAYER_STATE_READY:
1306 debug_warning("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state) );
1314 __mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data) // @
1316 mm_player_t* player = (mm_player_t*) data;
1317 gboolean ret = TRUE;
1318 static gboolean async_done = FALSE;
1320 return_val_if_fail ( player, FALSE );
1321 return_val_if_fail ( msg && GST_IS_MESSAGE(msg), FALSE );
1323 switch ( GST_MESSAGE_TYPE( msg ) )
1325 case GST_MESSAGE_UNKNOWN:
1326 debug_warning("unknown message received\n");
1329 case GST_MESSAGE_EOS:
1331 MMHandleType attrs = 0;
1334 debug_log("GST_MESSAGE_EOS received\n");
1336 /* NOTE : EOS event is comming multiple time. watch out it */
1337 /* check state. we only process EOS when pipeline state goes to PLAYING */
1338 if ( ! (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) )
1340 debug_warning("EOS received on non-playing state. ignoring it\n");
1344 if ( (player->audio_stream_cb) && (player->is_sound_extraction) )
1348 pad = gst_element_get_static_pad (player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
1350 debug_error("release audio callback\n");
1352 /* release audio callback */
1353 gst_pad_remove_buffer_probe (pad, player->audio_cb_probe_id);
1354 player->audio_cb_probe_id = 0;
1355 /* audio callback should be free because it can be called even though probe remove.*/
1356 player->audio_stream_cb = NULL;
1357 player->audio_stream_cb_user_param = NULL;
1361 /* rewind if repeat count is greater then zero */
1362 /* get play count */
1363 attrs = MMPLAYER_GET_ATTRS(player);
1367 gboolean smooth_repeat = FALSE;
1369 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1370 mm_attrs_get_int_by_name(attrs, "profile_smooth_repeat", &smooth_repeat);
1372 debug_log("remaining play count: %d, playback rate: %f\n", count, player->playback_rate);
1374 if ( count > 1 || count == -1 || player->playback_rate < 0.0 ) /* default value is 1 */
1376 if ( smooth_repeat )
1378 debug_log("smooth repeat enabled. seeking operation will be excuted in new thread\n");
1380 g_cond_signal( player->repeat_thread_cond );
1388 if ( player->section_repeat )
1390 ret_value = _mmplayer_activate_section_repeat((MMHandleType)player, player->section_repeat_start, player->section_repeat_end);
1395 if ( player->playback_rate < 0.0 )
1397 player->resumed_by_rewind = TRUE;
1398 _mmplayer_set_mute((MMHandleType)player, 0);
1399 MMPLAYER_POST_MSG( player, MM_MESSAGE_RESUMED_BY_REW, NULL );
1402 ret_value = __gst_set_position( player, MM_PLAYER_POS_FORMAT_TIME, 0, TRUE);
1405 player->sent_bos = FALSE;
1408 if ( MM_ERROR_NONE != ret_value )
1410 debug_error("failed to set position to zero for rewind\n");
1416 /* we successeded to rewind. update play count and then wait for next EOS */
1419 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
1421 if ( mmf_attrs_commit ( attrs ) )
1422 debug_error("failed to commit attrs\n");
1431 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-eos" );
1433 /* post eos message to application */
1434 __mmplayer_post_delayed_eos( player, PLAYER_INI()->eos_delay );
1436 /* reset last position */
1437 player->last_position = 0;
1441 case GST_MESSAGE_ERROR:
1443 GError *error = NULL;
1444 gchar* debug = NULL;
1445 gchar *msg_src_element = NULL;
1447 /* generating debug info before returning error */
1448 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-error" );
1450 /* get error code */
1451 gst_message_parse_error( msg, &error, &debug );
1453 msg_src_element = GST_ELEMENT_NAME( GST_ELEMENT_CAST( msg->src ) );
1454 if ( gst_structure_has_name ( msg->structure, "streaming_error" ) )
1456 /* Note : the streaming error from the streaming source is handled
1457 * using __mmplayer_handle_streaming_error.
1459 __mmplayer_handle_streaming_error ( player, msg );
1461 /* dump state of all element */
1462 __mmplayer_dump_pipeline_state( player );
1466 /* traslate gst error code to msl error code. then post it
1467 * to application if needed
1469 __mmplayer_handle_gst_error( player, msg, error );
1471 /* dump state of all element */
1472 __mmplayer_dump_pipeline_state( player );
1476 if (MMPLAYER_IS_HTTP_PD(player))
1478 _mmplayer_unrealize_pd_downloader ((MMHandleType)player);
1481 MMPLAYER_FREEIF( debug );
1482 g_error_free( error );
1486 case GST_MESSAGE_WARNING:
1489 GError* error = NULL;
1491 gst_message_parse_warning(msg, &error, &debug);
1493 debug_warning("warning : %s\n", error->message);
1494 debug_warning("debug : %s\n", debug);
1496 MMPLAYER_POST_MSG( player, MM_MESSAGE_WARNING, NULL );
1498 MMPLAYER_FREEIF( debug );
1499 g_error_free( error );
1503 case GST_MESSAGE_INFO: debug_log("GST_MESSAGE_STATE_DIRTY\n"); break;
1505 case GST_MESSAGE_TAG:
1507 debug_log("GST_MESSAGE_TAG\n");
1508 if ( ! __mmplayer_gst_extract_tag_from_msg( player, msg ) )
1510 debug_warning("failed to extract tags from gstmessage\n");
1515 case GST_MESSAGE_BUFFERING:
1517 MMMessageParamType msg_param = {0, };
1518 gboolean update_buffering_percent = TRUE;
1520 if ( !MMPLAYER_IS_STREAMING(player) || (player->profile.uri_type == MM_PLAYER_URI_TYPE_HLS) ) // pure hlsdemux case, don't consider buffering of msl currently
1523 __mm_player_streaming_buffering (player->streamer, msg);
1525 __mmplayer_handle_buffering_message ( player );
1527 update_buffering_percent = (player->pipeline_is_constructed || MMPLAYER_IS_RTSP_STREAMING(player) );
1528 if (update_buffering_percent)
1530 msg_param.connection.buffering = player->streamer->buffering_percent;
1531 MMPLAYER_POST_MSG ( player, MM_MESSAGE_BUFFERING, &msg_param );
1536 case GST_MESSAGE_STATE_CHANGED:
1538 MMPlayerGstElement *mainbin;
1539 const GValue *voldstate, *vnewstate, *vpending;
1540 GstState oldstate, newstate, pending;
1542 if ( ! ( player->pipeline && player->pipeline->mainbin ) )
1544 debug_error("player pipeline handle is null");
1549 mainbin = player->pipeline->mainbin;
1551 /* get state info from msg */
1552 voldstate = gst_structure_get_value (msg->structure, "old-state");
1553 vnewstate = gst_structure_get_value (msg->structure, "new-state");
1554 vpending = gst_structure_get_value (msg->structure, "pending-state");
1556 oldstate = (GstState)voldstate->data[0].v_int;
1557 newstate = (GstState)vnewstate->data[0].v_int;
1558 pending = (GstState)vpending->data[0].v_int;
1560 if (oldstate == newstate)
1563 debug_log("state changed [%s] : %s ---> %s final : %s\n",
1564 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1565 gst_element_state_get_name( (GstState)oldstate ),
1566 gst_element_state_get_name( (GstState)newstate ),
1567 gst_element_state_get_name( (GstState)pending ) );
1569 /* we only handle messages from pipeline */
1570 if( msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst )
1575 case GST_STATE_VOID_PENDING:
1578 case GST_STATE_NULL:
1581 case GST_STATE_READY:
1584 case GST_STATE_PAUSED:
1586 gboolean prepare_async = FALSE;
1588 player->need_update_content_dur = TRUE;
1590 if ( ! player->audio_cb_probe_id && player->is_sound_extraction )
1591 __mmplayer_configure_audio_callback(player);
1593 if ( ! player->sent_bos && oldstate == GST_STATE_READY) // managed prepare async case
1595 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1596 debug_log("checking prepare mode for async transition - %d", prepare_async);
1599 if ( MMPLAYER_IS_STREAMING(player) || prepare_async )
1601 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_PAUSED );
1603 if (player->streamer)
1604 __mm_player_streaming_set_content_bitrate(player->streamer, player->total_maximum_bitrate, player->total_bitrate);
1609 case GST_STATE_PLAYING:
1611 if (player->doing_seek && async_done)
1613 player->doing_seek = FALSE;
1615 MMPLAYER_POST_MSG ( player, MM_MESSAGE_SEEK_COMPLETED, NULL );
1618 if ( MMPLAYER_IS_STREAMING(player) ) // managed prepare async case when buffering is completed
1620 // pending state should be reset oyherwise, it's still playing even though it's resumed after bufferging.
1621 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_PLAYING);
1632 case GST_MESSAGE_STATE_DIRTY: debug_log("GST_MESSAGE_STATE_DIRTY\n"); break;
1633 case GST_MESSAGE_STEP_DONE: debug_log("GST_MESSAGE_STEP_DONE\n"); break;
1634 case GST_MESSAGE_CLOCK_PROVIDE: debug_log("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
1636 case GST_MESSAGE_CLOCK_LOST:
1638 GstClock *clock = NULL;
1639 gst_message_parse_clock_lost (msg, &clock);
1640 debug_log("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME (clock) : "NULL"));
1641 g_print ("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME (clock) : "NULL"));
1643 if (PLAYER_INI()->provide_clock)
1645 debug_log ("Provide clock is TRUE, do pause->resume\n");
1646 __gst_pause(player, FALSE);
1647 __gst_resume(player, FALSE);
1652 case GST_MESSAGE_NEW_CLOCK:
1654 GstClock *clock = NULL;
1655 gst_message_parse_new_clock (msg, &clock);
1656 debug_log("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME (clock) : "NULL"));
1660 case GST_MESSAGE_STRUCTURE_CHANGE: debug_log("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
1661 case GST_MESSAGE_STREAM_STATUS: debug_log("GST_MESSAGE_STREAM_STATUS\n"); break;
1662 case GST_MESSAGE_APPLICATION: debug_log("GST_MESSAGE_APPLICATION\n"); break;
1664 case GST_MESSAGE_ELEMENT:
1666 debug_log("GST_MESSAGE_ELEMENT\n");
1670 case GST_MESSAGE_SEGMENT_START: debug_log("GST_MESSAGE_SEGMENT_START\n"); break;
1671 case GST_MESSAGE_SEGMENT_DONE: debug_log("GST_MESSAGE_SEGMENT_DONE\n"); break;
1673 case GST_MESSAGE_DURATION:
1675 debug_log("GST_MESSAGE_DURATION\n");
1677 if (MMPLAYER_IS_STREAMING(player))
1682 gst_message_parse_duration (msg, &format, &bytes);
1683 if (format == GST_FORMAT_BYTES)
1685 debug_log("data total size of http content: %lld", bytes);
1686 player->http_content_size = bytes;
1690 player->need_update_content_attrs = TRUE;
1691 player->need_update_content_dur = TRUE;
1692 _mmplayer_update_content_attrs(player);
1696 case GST_MESSAGE_LATENCY: debug_log("GST_MESSAGE_LATENCY\n"); break;
1697 case GST_MESSAGE_ASYNC_START: debug_log("GST_MESSAGE_ASYNC_DONE : %s\n", gst_element_get_name(GST_MESSAGE_SRC(msg))); break;
1699 case GST_MESSAGE_ASYNC_DONE:
1701 debug_log("GST_MESSAGE_ASYNC_DONE : %s\n", gst_element_get_name(GST_MESSAGE_SRC(msg)));
1703 if (player->doing_seek)
1705 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED)
1707 player->doing_seek = FALSE;
1708 MMPLAYER_POST_MSG ( player, MM_MESSAGE_SEEK_COMPLETED, NULL );
1710 else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING)
1718 case GST_MESSAGE_REQUEST_STATE: debug_log("GST_MESSAGE_REQUEST_STATE\n"); break;
1719 case GST_MESSAGE_STEP_START: debug_log("GST_MESSAGE_STEP_START\n"); break;
1720 case GST_MESSAGE_QOS: debug_log("GST_MESSAGE_QOS\n"); break;
1721 case GST_MESSAGE_PROGRESS: debug_log("GST_MESSAGE_PROGRESS\n"); break;
1722 case GST_MESSAGE_ANY: debug_log("GST_MESSAGE_ANY\n"); break;
1725 debug_warning("unhandled message\n");
1729 /* FIXIT : this cause so many warnings/errors from glib/gstreamer. we should not call it since
1730 * gst_element_post_message api takes ownership of the message.
1732 //gst_message_unref( msg );
1738 __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg) // @
1741 /* macro for better code readability */
1742 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
1743 if (gst_tag_list_get_string(tag_list, gsttag, &string)) \
1745 if (string != NULL)\
1747 debug_log ( "update tag string : %s\n", string); \
1748 mm_attrs_set_string_by_name(attribute, playertag, string); \
1754 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
1755 value = gst_tag_list_get_value_index(tag_list, gsttag, index); \
1758 buffer = gst_value_get_buffer (value); \
1759 debug_log ( "update album cover data : %p, size : %d\n", GST_BUFFER_DATA(buffer), GST_BUFFER_SIZE(buffer)); \
1760 player->album_art = (gchar *)g_malloc(GST_BUFFER_SIZE(buffer)); \
1761 if (player->album_art); \
1763 memcpy(player->album_art, GST_BUFFER_DATA(buffer), GST_BUFFER_SIZE(buffer)); \
1764 mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, GST_BUFFER_SIZE(buffer)); \
1768 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
1769 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint))\
1773 if(gsttag==GST_TAG_BITRATE)\
1775 if (player->updated_bitrate_count == 0) \
1776 mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
1777 if (player->updated_bitrate_count<MM_PLAYER_STREAM_COUNT_MAX) \
1779 player->bitrate[player->updated_bitrate_count] = v_uint;\
1780 player->total_bitrate += player->bitrate[player->updated_maximum_bitrate_count]; \
1781 player->updated_bitrate_count++; \
1782 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate);\
1783 debug_log ( "update bitrate %d[bps] of stream #%d.\n", v_uint, player->updated_bitrate_count);\
1786 else if (gsttag==GST_TAG_MAXIMUM_BITRATE)\
1788 if (player->updated_maximum_bitrate_count<MM_PLAYER_STREAM_COUNT_MAX) \
1790 player->maximum_bitrate[player->updated_maximum_bitrate_count] = v_uint;\
1791 player->total_maximum_bitrate += player->maximum_bitrate[player->updated_maximum_bitrate_count]; \
1792 player->updated_maximum_bitrate_count++; \
1793 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate); \
1794 debug_log ( "update maximum bitrate %d[bps] of stream #%d\n", v_uint, player->updated_maximum_bitrate_count);\
1799 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
1805 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
1806 if (gst_tag_list_get_date(tag_list, gsttag, &date))\
1810 string = g_strdup_printf("%d", g_date_get_year(date));\
1811 mm_attrs_set_string_by_name(attribute, playertag, string);\
1812 debug_log ( "metainfo year : %s\n", string);\
1813 MMPLAYER_FREEIF(string);\
1818 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
1819 if(gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64))\
1823 /* FIXIT : don't know how to store date */\
1829 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
1830 if(gst_tag_list_get_double(tag_list, gsttag, &v_double))\
1834 /* FIXIT : don't know how to store date */\
1840 /* function start */
1841 GstTagList* tag_list = NULL;
1843 MMHandleType attrs = 0;
1845 char *string = NULL;
1849 GstBuffer *buffer = NULL;
1851 const GValue *value;
1853 /* currently not used. but those are needed for above macro */
1854 //guint64 v_uint64 = 0;
1855 //gdouble v_double = 0;
1857 return_val_if_fail( player && msg, FALSE );
1859 attrs = MMPLAYER_GET_ATTRS(player);
1861 return_val_if_fail( attrs, FALSE );
1863 /* get tag list from gst message */
1864 gst_message_parse_tag(msg, &tag_list);
1866 /* store tags to player attributes */
1867 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
1868 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
1869 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
1870 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
1871 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
1872 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
1873 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
1874 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
1875 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
1876 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
1877 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
1878 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
1879 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
1880 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
1881 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
1882 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
1883 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
1884 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
1885 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
1886 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
1887 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
1888 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
1889 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
1890 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
1891 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
1892 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
1893 /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
1894 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
1895 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
1896 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
1897 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
1898 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
1899 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
1900 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
1901 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
1902 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
1903 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
1904 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
1905 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
1906 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
1907 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
1908 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
1909 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
1910 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
1911 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
1913 if ( mmf_attrs_commit ( attrs ) )
1914 debug_error("failed to commit.\n");
1916 gst_tag_list_free(tag_list);
1922 __mmplayer_gst_rtp_no_more_pads (GstElement *element, gpointer data) // @
1924 mm_player_t* player = (mm_player_t*) data;
1928 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
1929 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
1930 * num_dynamic_pad. and this is no-more-pad situation which means mo more pad will be added.
1931 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
1933 * [1] audio and video will be dumped with filesink.
1934 * [2] autoplugging is done by just using pad caps.
1935 * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
1936 * and the video will be dumped via filesink.
1938 if ( player->num_dynamic_pad == 0 )
1940 debug_log("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
1942 if ( ! __mmplayer_gst_remove_fakesink( player,
1943 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]) );
1946 /* create dot before error-return. for debugging */
1947 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-no-more-pad" );
1949 /* NOTE : if rtspsrc goes to PLAYING before adding it's src pads, a/v sink elements will
1950 * not goes to PLAYING. they will just remain in PAUSED state. simply we are giving
1951 * PLAYING state again.
1953 __mmplayer_gst_set_state(player,
1954 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, TRUE, 5000 );
1956 player->no_more_pad = TRUE;
1962 __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink) // @
1964 GstElement* parent = NULL;
1966 return_val_if_fail(player && player->pipeline && fakesink, FALSE);
1969 g_mutex_lock( player->fsink_lock );
1971 if ( ! fakesink->gst )
1976 /* get parent of fakesink */
1977 parent = (GstElement*)gst_object_get_parent( (GstObject*)fakesink->gst );
1980 debug_log("fakesink already removed\n");
1984 gst_element_set_locked_state( fakesink->gst, TRUE );
1986 /* setting the state to NULL never returns async
1987 * so no need to wait for completion of state transiton
1989 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state (fakesink->gst, GST_STATE_NULL) )
1991 debug_error("fakesink state change failure!\n");
1993 /* FIXIT : should I return here? or try to proceed to next? */
1997 /* remove fakesink from it's parent */
1998 if ( ! gst_bin_remove( GST_BIN( parent ), fakesink->gst ) )
2000 debug_error("failed to remove fakesink\n");
2002 gst_object_unref( parent );
2007 gst_object_unref( parent );
2009 /* FIXIT : releasing fakesink takes too much time (around 700ms)
2010 * we need to figure out the reason why. just for now, fakesink will be released
2011 * in __mmplayer_gst_destroy_pipeline()
2013 // gst_object_unref ( fakesink->gst );
2014 // fakesink->gst = NULL;
2016 debug_log("state-holder removed\n");
2018 gst_element_set_locked_state( fakesink->gst, FALSE );
2020 g_mutex_unlock( player->fsink_lock );
2024 if ( fakesink->gst )
2026 gst_element_set_locked_state( fakesink->gst, FALSE );
2029 g_mutex_unlock( player->fsink_lock );
2035 __mmplayer_gst_rtp_dynamic_pad (GstElement *element, GstPad *pad, gpointer data) // @
2037 GstPad *sinkpad = NULL;
2038 GstCaps* caps = NULL;
2039 GstElement* new_element = NULL;
2041 mm_player_t* player = (mm_player_t*) data;
2045 return_if_fail( element && pad );
2046 return_if_fail( player &&
2048 player->pipeline->mainbin );
2051 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2052 * num_dynamic_pad will decreased after creating a sinkbin.
2054 player->num_dynamic_pad++;
2055 debug_log("stream count inc : %d\n", player->num_dynamic_pad);
2057 /* perform autoplugging if dump is disabled */
2058 if ( PLAYER_INI()->rtsp_do_typefinding )
2060 /* create typefind */
2061 new_element = gst_element_factory_make( "typefind", NULL );
2062 if ( ! new_element )
2064 debug_error("failed to create typefind\n");
2068 MMPLAYER_SIGNAL_CONNECT( player,
2069 G_OBJECT(new_element),
2071 G_CALLBACK(__mmplayer_typefind_have_type),
2074 /* FIXIT : try to remove it */
2075 player->have_dynamic_pad = FALSE;
2077 else /* NOTE : use pad's caps directely. if enabled. what I am assuming is there's no elemnt has dynamic pad */
2079 debug_log("using pad caps to autopluging instead of doing typefind\n");
2081 caps = gst_pad_get_caps( pad );
2083 MMPLAYER_CHECK_NULL( caps );
2085 /* clear previous result*/
2086 player->have_dynamic_pad = FALSE;
2088 if ( ! __mmplayer_try_to_plug( player, pad, caps ) )
2090 debug_error("failed to autoplug for caps : %s\n", gst_caps_to_string( caps ) );
2094 /* check if there's dynamic pad*/
2095 if( player->have_dynamic_pad )
2097 debug_error("using pad caps assums there's no dynamic pad !\n");
2098 debug_error("try with enalbing rtsp_do_typefinding\n");
2102 gst_caps_unref( caps );
2106 /* excute new_element if created*/
2109 debug_log("adding new element to pipeline\n");
2111 /* set state to READY before add to bin */
2112 MMPLAYER_ELEMENT_SET_STATE( new_element, GST_STATE_READY );
2114 /* add new element to the pipeline */
2115 if ( FALSE == gst_bin_add( GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element) )
2117 debug_error("failed to add autoplug element to bin\n");
2121 /* get pad from element */
2122 sinkpad = gst_element_get_static_pad ( GST_ELEMENT(new_element), "sink" );
2125 debug_error("failed to get sinkpad from autoplug element\n");
2130 if ( GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad) )
2132 debug_error("failed to link autoplug element\n");
2136 gst_object_unref (sinkpad);
2139 /* run. setting PLAYING here since streamming source is live source */
2140 MMPLAYER_ELEMENT_SET_STATE( new_element, GST_STATE_PLAYING );
2147 STATE_CHANGE_FAILED:
2149 /* FIXIT : take care if new_element has already added to pipeline */
2151 gst_object_unref(GST_OBJECT(new_element));
2154 gst_object_unref(GST_OBJECT(sinkpad));
2157 gst_object_unref(GST_OBJECT(caps));
2159 /* FIXIT : how to inform this error to MSL ????? */
2160 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2161 * then post an error to application
2167 __mmplayer_gst_decode_callback(GstElement *decodebin, GstPad *pad, gboolean last, gpointer data) // @
2169 mm_player_t* player = NULL;
2170 MMHandleType attrs = 0;
2171 GstElement* pipeline = NULL;
2172 GstCaps* caps = NULL;
2173 GstStructure* str = NULL;
2174 const gchar* name = NULL;
2175 GstPad* sinkpad = NULL;
2176 GstElement* sinkbin = NULL;
2179 player = (mm_player_t*) data;
2181 return_if_fail( decodebin && pad );
2182 return_if_fail(player && player->pipeline && player->pipeline->mainbin);
2184 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
2186 attrs = MMPLAYER_GET_ATTRS(player);
2189 debug_error("cannot get content attribute\n");
2193 /* get mimetype from caps */
2194 caps = gst_pad_get_caps( pad );
2197 debug_error("cannot get caps from pad.\n");
2201 str = gst_caps_get_structure( caps, 0 );
2204 debug_error("cannot get structure from capse.\n");
2208 name = gst_structure_get_name(str);
2211 debug_error("cannot get mimetype from structure.\n");
2215 debug_log("detected mimetype : %s\n", name);
2217 if (strstr(name, "audio"))
2219 if (player->pipeline->audiobin == NULL)
2221 __ta__("__mmplayer_gst_create_audio_pipeline",
2222 if (MM_ERROR_NONE != __mmplayer_gst_create_audio_pipeline(player))
2224 debug_error("failed to create audiobin. continuing without audio\n");
2229 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
2230 debug_log("creating audiosink bin success\n");
2234 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
2235 debug_log("re-using audiobin\n");
2238 /* FIXIT : track number shouldn't be hardcoded */
2239 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 1);
2241 player->audiosink_linked = 1;
2242 debug_msg("player->audsink_linked set to 1\n");
2245 else if (strstr(name, "video"))
2247 if (player->pipeline->videobin == NULL)
2249 /* NOTE : not make videobin because application dose not want to play it even though file has video stream.
2252 /* get video surface type */
2253 int surface_type = 0;
2254 mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &surface_type);
2255 debug_log("check display surface type attribute: %d", surface_type);
2256 if (surface_type == MM_DISPLAY_SURFACE_NULL)
2258 debug_log("not make videobin because it dose not want\n");
2262 __ta__("__mmplayer_gst_create_video_pipeline",
2263 if (MM_ERROR_NONE != __mmplayer_gst_create_video_pipeline(player, caps, surface_type) )
2265 debug_error("failed to create videobin. continuing without video\n");
2270 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
2271 debug_log("creating videosink bin success\n");
2275 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
2276 debug_log("re-using videobin\n");
2279 /* FIXIT : track number shouldn't be hardcoded */
2280 mm_attrs_set_int_by_name(attrs, "content_video_track_num", 1);
2282 player->videosink_linked = 1;
2283 debug_msg("player->videosink_linked set to 1\n");
2286 else if (strstr(name, "text"))
2288 if (player->pipeline->textbin == NULL)
2290 __ta__("__mmplayer_gst_create_text_pipeline",
2291 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player))
2293 debug_error("failed to create textbin. continuing without text\n");
2298 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
2299 debug_log("creating textink bin success\n");
2303 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
2304 debug_log("re-using textbin\n");
2307 /* FIXIT : track number shouldn't be hardcoded */
2308 mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1);
2310 player->textsink_linked = 1;
2311 debug_msg("player->textsink_linked set to 1\n");
2315 debug_warning("unknown type of elementary stream! ignoring it...\n");
2322 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state( sinkbin, GST_STATE_READY ) )
2324 debug_error("failed to set state(READY) to sinkbin\n");
2329 if ( FALSE == gst_bin_add( GST_BIN(pipeline), sinkbin ) )
2331 debug_error("failed to add sinkbin to pipeline\n");
2335 sinkpad = gst_element_get_static_pad( GST_ELEMENT(sinkbin), "sink" );
2339 debug_error("failed to get pad from sinkbin\n");
2344 if ( GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad) )
2346 debug_error("failed to get pad from sinkbin\n");
2351 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state( sinkbin, GST_STATE_PAUSED ) )
2353 debug_error("failed to set state(PLAYING) to sinkbin\n");
2357 gst_object_unref( sinkpad );
2361 /* update track number attributes */
2362 if ( mmf_attrs_commit ( attrs ) )
2363 debug_error("failed to commit attrs\n");
2365 debug_log("linking sink bin success\n");
2368 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
2369 * streaming task. if the task blocked, then buffer will not flow to the next element
2370 * ( autoplugging element ). so this is special hack for streaming. please try to remove it
2372 /* dec stream count. we can remove fakesink if it's zero */
2373 player->num_dynamic_pad--;
2375 debug_log("stream count dec : %d (num of dynamic pad)\n", player->num_dynamic_pad);
2377 if ( ( player->no_more_pad ) && ( player->num_dynamic_pad == 0 ) )
2379 __mmplayer_pipeline_complete( NULL, player );
2384 gst_caps_unref( caps );
2387 gst_object_unref(GST_OBJECT(sinkpad));
2393 _mmplayer_update_video_param(mm_player_t* player) // @
2395 MMHandleType attrs = 0;
2396 int surface_type = 0;
2400 /* check video sinkbin is created */
2401 return_val_if_fail ( player &&
2403 player->pipeline->videobin &&
2404 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
2405 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2406 MM_ERROR_PLAYER_NOT_INITIALIZED );
2408 attrs = MMPLAYER_GET_ATTRS(player);
2411 debug_error("cannot get content attribute");
2412 return MM_ERROR_PLAYER_INTERNAL;
2415 /* update display surface */
2416 mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &surface_type);
2417 debug_log("check display surface type attribute: %d", surface_type);
2419 /* check video stream callback is used */
2420 if( player->use_video_stream )
2422 int rotate, width, height, orientation;
2424 rotate = width = height = orientation = 0;
2426 debug_log("using video stream callback with memsink. player handle : [%p]", player);
2428 mm_attrs_get_int_by_name(attrs, "display_width", &width);
2429 mm_attrs_get_int_by_name(attrs, "display_height", &height);
2430 mm_attrs_get_int_by_name(attrs, "display_rotation", &rotate);
2431 mm_attrs_get_int_by_name(attrs, "display_orientation", &orientation);
2433 if (rotate < MM_DISPLAY_ROTATION_NONE || rotate > MM_DISPLAY_ROTATION_270)
2438 if(orientation == 1) rotate = 90;
2439 else if(orientation == 2) rotate = 180;
2440 else if(orientation == 3) rotate = 270;
2443 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "width", width, NULL);
2446 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "height", height, NULL);
2448 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotate,NULL);
2450 return MM_ERROR_NONE;
2453 /* configuring display */
2454 switch ( surface_type )
2456 case MM_DISPLAY_SURFACE_X:
2458 /* ximagesink or xvimagesink */
2462 int display_method = 0;
2467 int force_aspect_ratio = 0;
2469 gboolean visible = TRUE;
2471 /* common case if using x surface */
2472 mm_attrs_get_data_by_name(attrs, "display_overlay", &xid);
2475 debug_log("set video param : xid %d", *(int*)xid);
2476 gst_x_overlay_set_xwindow_id( GST_X_OVERLAY( player->pipeline->videobin[MMPLAYER_V_SINK].gst ), *(int*)xid );
2480 /* FIXIT : is it error case? */
2481 debug_warning("still we don't have xid on player attribute. create it's own surface.");
2484 /* if xvimagesink */
2485 if (!strcmp(PLAYER_INI()->videosink_element_x,"xvimagesink"))
2487 mm_attrs_get_int_by_name(attrs, "display_force_aspect_ration", &force_aspect_ratio);
2488 mm_attrs_get_int_by_name(attrs, "display_zoom", &zoom);
2489 mm_attrs_get_int_by_name(attrs, "display_rotation", °ree);
2490 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
2491 mm_attrs_get_int_by_name(attrs, "display_roi_x", &roi_x);
2492 mm_attrs_get_int_by_name(attrs, "display_roi_y", &roi_y);
2493 mm_attrs_get_int_by_name(attrs, "display_roi_width", &roi_w);
2494 mm_attrs_get_int_by_name(attrs, "display_roi_height", &roi_h);
2495 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
2497 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2498 "force-aspect-ratio", force_aspect_ratio,
2501 "handle-events", TRUE,
2502 "display-geometry-method", display_method,
2503 "draw-borders", FALSE,
2511 debug_log("set video param : zoom %d", zoom);
2512 debug_log("set video param : rotate %d", degree);
2513 debug_log("set video param : method %d", display_method);
2514 debug_log("set video param : dst-roi-x: %d, dst-roi-y: %d, dst-roi-w: %d, dst-roi-h: %d",
2515 roi_x, roi_y, roi_w, roi_h );
2516 debug_log("set video param : visible %d", visible);
2517 debug_log("set video param : force aspect ratio %d", force_aspect_ratio);
2521 case MM_DISPLAY_SURFACE_EVAS:
2523 void *object = NULL;
2525 gboolean visible = TRUE;
2527 /* common case if using evas surface */
2528 mm_attrs_get_data_by_name(attrs, "display_overlay", &object);
2529 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
2530 mm_attrs_get_int_by_name(attrs, "display_evas_do_scaling", &scaling);
2533 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2534 "evas-object", object,
2537 debug_log("set video param : evas-object %x", object);
2538 debug_log("set video param : visible %d", visible);
2542 debug_error("no evas object");
2543 return MM_ERROR_PLAYER_INTERNAL;
2546 /* if evaspixmapsink */
2547 if (!strcmp(PLAYER_INI()->videosink_element_evas,"evaspixmapsink"))
2549 int display_method = 0;
2554 int force_aspect_ratio = 0;
2555 int origin_size = !scaling;
2557 mm_attrs_get_int_by_name(attrs, "display_force_aspect_ration", &force_aspect_ratio);
2558 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
2559 mm_attrs_get_int_by_name(attrs, "display_roi_x", &roi_x);
2560 mm_attrs_get_int_by_name(attrs, "display_roi_y", &roi_y);
2561 mm_attrs_get_int_by_name(attrs, "display_roi_width", &roi_w);
2562 mm_attrs_get_int_by_name(attrs, "display_roi_height", &roi_h);
2564 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2565 "force-aspect-ratio", force_aspect_ratio,
2566 "origin-size", origin_size,
2571 "display-geometry-method", display_method,
2574 debug_log("set video param : method %d", display_method);
2575 debug_log("set video param : dst-roi-x: %d, dst-roi-y: %d, dst-roi-w: %d, dst-roi-h: %d",
2576 roi_x, roi_y, roi_w, roi_h );
2577 debug_log("set video param : force aspect ratio %d", force_aspect_ratio);
2578 debug_log("set video param : display_evas_do_scaling %d (origin-size %d)", scaling, origin_size);
2582 case MM_DISPLAY_SURFACE_X_EXT: /* NOTE : this surface type is for the video texture(canvas texture) */
2584 void *pixmap_id_cb = NULL;
2585 void *pixmap_id_cb_user_data = NULL;
2588 int display_method = 0;
2593 int force_aspect_ratio = 0;
2594 gboolean visible = TRUE;
2596 /* if xvimagesink */
2597 if (strcmp(PLAYER_INI()->videosink_element_x,"xvimagesink"))
2599 debug_error("videosink is not xvimagesink");
2600 return MM_ERROR_PLAYER_INTERNAL;
2603 /* get information from attributes */
2604 mm_attrs_get_data_by_name(attrs, "display_overlay", &pixmap_id_cb);
2605 mm_attrs_get_data_by_name(attrs, "display_overlay_user_data", &pixmap_id_cb_user_data);
2606 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
2610 debug_log("set video param : display_overlay(0x%x)", pixmap_id_cb);
2611 if (pixmap_id_cb_user_data)
2613 debug_log("set video param : display_overlay_user_data(0x%x)", pixmap_id_cb_user_data);
2618 debug_error("failed to set pixmap-id-callback");
2619 return MM_ERROR_PLAYER_INTERNAL;
2621 debug_log("set video param : method %d", display_method);
2622 debug_log("set video param : visible %d", visible);
2624 /* set properties of videosink plugin */
2625 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2626 "display-geometry-method", display_method,
2627 "draw-borders", FALSE,
2629 "pixmap-id-callback", pixmap_id_cb,
2630 "pixmap-id-callback-userdata", pixmap_id_cb_user_data,
2634 case MM_DISPLAY_SURFACE_NULL:
2643 return MM_ERROR_NONE;
2647 __mmplayer_gst_element_link_bucket(GList* element_bucket) // @
2649 GList* bucket = element_bucket;
2650 MMPlayerGstElement* element = NULL;
2651 MMPlayerGstElement* prv_element = NULL;
2652 gint successful_link_count = 0;
2656 return_val_if_fail(element_bucket, -1);
2658 prv_element = (MMPlayerGstElement*)bucket->data;
2659 bucket = bucket->next;
2661 for ( ; bucket; bucket = bucket->next )
2663 element = (MMPlayerGstElement*)bucket->data;
2665 if ( element && element->gst )
2667 if ( GST_ELEMENT_LINK(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst)) )
2669 debug_log("linking [%s] to [%s] success\n",
2670 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2671 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)) );
2672 successful_link_count ++;
2676 debug_log("linking [%s] to [%s] failed\n",
2677 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2678 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)) );
2683 prv_element = element;
2688 return successful_link_count;
2692 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket) // @
2694 GList* bucket = element_bucket;
2695 MMPlayerGstElement* element = NULL;
2696 int successful_add_count = 0;
2700 return_val_if_fail(element_bucket, 0);
2701 return_val_if_fail(bin, 0);
2703 for ( ; bucket; bucket = bucket->next )
2705 element = (MMPlayerGstElement*)bucket->data;
2707 if ( element && element->gst )
2709 if( !gst_bin_add(bin, GST_ELEMENT(element->gst)) )
2711 debug_log("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed\n",
2712 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2713 GST_ELEMENT_NAME(GST_ELEMENT(bin) ) );
2716 successful_add_count ++;
2722 return successful_add_count;
2728 * This function is to create audio pipeline for playing.
2730 * @param player [in] handle of player
2732 * @return This function returns zero on success.
2734 * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_pipeline
2736 #define MMPLAYER_CREATEONLY_ELEMENT(x_bin, x_id, x_factory, x_name) \
2737 x_bin[x_id].id = x_id;\
2738 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
2739 if ( ! x_bin[x_id].gst )\
2741 debug_critical("failed to create %s \n", x_factory);\
2745 /* macro for code readability. just for sinkbin-creation functions */
2746 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket) \
2749 x_bin[x_id].id = x_id;\
2750 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
2751 if ( ! x_bin[x_id].gst )\
2753 debug_critical("failed to create %s \n", x_factory);\
2756 if ( x_add_bucket )\
2757 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
2763 * - Local playback : audioconvert !volume ! capsfilter ! dnse ! audiosink
2764 * - Streaming : audioconvert !volume ! audiosink
2765 * - PCM extraction : audioconvert ! audioresample ! capsfilter ! fakesink
2768 __mmplayer_gst_create_audio_pipeline(mm_player_t* player)
2770 MMPlayerGstElement* first_element = NULL;
2771 MMPlayerGstElement* audiobin = NULL;
2772 MMHandleType attrs = 0;
2774 GstPad *ghostpad = NULL;
2775 GList* element_bucket = NULL;
2776 char *device_name = NULL;
2777 gboolean link_audio_sink_now = TRUE;
2782 return_val_if_fail( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
2785 audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
2786 audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
2789 debug_error("failed to allocate memory for audiobin\n");
2790 return MM_ERROR_PLAYER_NO_FREE_SPACE;
2793 attrs = MMPLAYER_GET_ATTRS(player);
2796 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
2797 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
2798 if ( !audiobin[MMPLAYER_A_BIN].gst )
2800 debug_critical("failed to create audiobin\n");
2805 player->pipeline->audiobin = audiobin;
2807 player->is_sound_extraction = __mmplayer_can_extract_pcm(player);
2809 /* Adding audiotp plugin for reverse trickplay feature */
2810 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TP, "audiotp", "audiotrickplay", TRUE);
2813 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audioconverter", TRUE);
2815 if ( ! player->is_sound_extraction )
2817 GstCaps* caps = NULL;
2819 /* for logical volume control */
2820 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE);
2821 g_object_set(G_OBJECT (audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2823 if (player->sound.mute)
2825 debug_log("mute enabled\n");
2826 g_object_set(G_OBJECT (audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2830 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE);
2832 caps = gst_caps_from_string( "audio/x-raw-int, "
2833 "endianness = (int) LITTLE_ENDIAN, "
2834 "signed = (boolean) true, "
2835 "width = (int) 16, "
2836 "depth = (int) 16" );
2838 g_object_set (GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL );
2840 gst_caps_unref( caps );
2842 /* audio filter. if enabled */
2843 if ( PLAYER_INI()->use_audio_filter_preset || PLAYER_INI()->use_audio_filter_custom )
2845 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, "soundalive", "audiofilter", TRUE);
2848 /* create audio sink */
2849 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, PLAYER_INI()->name_of_audiosink,
2850 "audiosink", link_audio_sink_now);
2853 if (MMPLAYER_IS_RTSP_STREAMING(player))
2854 g_object_set (G_OBJECT (audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL); /* sync off */
2856 g_object_set (G_OBJECT (audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE, NULL); /* sync on */
2859 g_object_set (G_OBJECT (audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2861 /* FIXIT : using system clock. isn't there another way? */
2862 g_object_set (G_OBJECT (audiobin[MMPLAYER_A_SINK].gst), "provide-clock", PLAYER_INI()->provide_clock, NULL);
2864 __mmplayer_add_sink( player, audiobin[MMPLAYER_A_SINK].gst );
2866 if(player->audio_buffer_cb)
2868 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "audio-handle", player->audio_buffer_cb_user_param, NULL);
2869 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "audio-callback", player->audio_buffer_cb, NULL);
2872 if ( g_strrstr(PLAYER_INI()->name_of_audiosink, "avsysaudiosink") )
2874 gint volume_type = 0;
2875 gint audio_route = 0;
2876 gint sound_priority = FALSE;
2877 gint is_spk_out_only = 0;
2880 * It should be set after player creation through attribute.
2881 * But, it can not be changed during playing.
2883 mm_attrs_get_int_by_name(attrs, "sound_volume_type", &volume_type);
2884 mm_attrs_get_int_by_name(attrs, "sound_route", &audio_route);
2885 mm_attrs_get_int_by_name(attrs, "sound_priority", &sound_priority);
2886 mm_attrs_get_int_by_name(attrs, "sound_spk_out_only", &is_spk_out_only);
2888 /* hook sound_type if emergency case */
2889 if ( player->sm.event == ASM_EVENT_EMERGENCY)
2891 debug_log ("This is emergency session, hook sound_type from [%d] to [%d]\n", volume_type, MM_SOUND_VOLUME_TYPE_EMERGENCY);
2892 volume_type = MM_SOUND_VOLUME_TYPE_EMERGENCY;
2895 g_object_set(audiobin[MMPLAYER_A_SINK].gst,
2896 "volumetype", volume_type,
2897 "audio-route", audio_route,
2898 "priority", sound_priority,
2899 "user-route", is_spk_out_only,
2902 debug_log("audiosink property status...volume type:%d, route:%d, priority=%d, user-route=%d\n",
2903 volume_type, audio_route, sound_priority, is_spk_out_only);
2906 /* Antishock can be enabled when player is resumed by soundCM.
2907 * But, it's not used in MMS, setting and etc.
2908 * Because, player start seems like late.
2910 __mmplayer_set_antishock( player , FALSE );
2912 else // pcm extraction only and no sound output
2914 int dst_samplerate = 0;
2915 int dst_channels = 0;
2917 char *caps_type = NULL;
2918 GstCaps* caps = NULL;
2921 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, "audioresample", "resampler", TRUE);
2923 /* get conf. values */
2924 mm_attrs_multiple_get(player->attrs,
2926 "pcm_extraction_samplerate", &dst_samplerate,
2927 "pcm_extraction_channels", &dst_channels,
2928 "pcm_extraction_depth", &dst_depth,
2931 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE);
2933 caps = gst_caps_new_simple ("audio/x-raw-int",
2934 "rate", G_TYPE_INT, dst_samplerate,
2935 "channels", G_TYPE_INT, dst_channels,
2936 "depth", G_TYPE_INT, dst_depth,
2939 caps_type = gst_caps_to_string(caps);
2940 debug_log("resampler new caps : %s\n", caps_type);
2942 g_object_set (GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL );
2945 gst_caps_unref( caps );
2946 MMPLAYER_FREEIF( caps_type );
2949 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "fakesink", TRUE);
2952 g_object_set (G_OBJECT (audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL);
2954 __mmplayer_add_sink( player, audiobin[MMPLAYER_A_SINK].gst );
2957 /* adding created elements to bin */
2958 debug_log("adding created elements to bin\n");
2959 if( !__mmplayer_gst_element_add_bucket_to_bin( GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket ))
2961 debug_error("failed to add elements\n");
2965 /* linking elements in the bucket by added order. */
2966 debug_log("Linking elements in the bucket by added order.\n");
2967 if ( __mmplayer_gst_element_link_bucket(element_bucket) == -1 )
2969 debug_error("failed to link elements\n");
2973 /* get first element's sinkpad for creating ghostpad */
2974 first_element = (MMPlayerGstElement *)element_bucket->data;
2976 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
2979 debug_error("failed to get pad from first element of audiobin\n");
2983 ghostpad = gst_ghost_pad_new("sink", pad);
2986 debug_error("failed to create ghostpad\n");
2990 if ( FALSE == gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad) )
2992 debug_error("failed to add ghostpad to audiobin\n");
2996 gst_object_unref(pad);
2998 if ( !player->bypass_sound_effect && (PLAYER_INI()->use_audio_filter_preset || PLAYER_INI()->use_audio_filter_custom) )
3000 if ( player->audio_filter_info.filter_type == MM_AUDIO_FILTER_TYPE_PRESET )
3002 if (!_mmplayer_sound_filter_preset_apply(player, player->audio_filter_info.preset))
3004 debug_msg("apply sound effect(preset:%d) setting success\n",player->audio_filter_info.preset);
3007 else if ( player->audio_filter_info.filter_type == MM_AUDIO_FILTER_TYPE_CUSTOM )
3009 if (!_mmplayer_sound_filter_custom_apply(player))
3011 debug_msg("apply sound effect(custom) setting success\n");
3016 /* done. free allocated variables */
3017 MMPLAYER_FREEIF( device_name );
3018 g_list_free(element_bucket);
3020 mm_attrs_set_int_by_name(attrs, "content_audio_found", TRUE);
3021 if ( mmf_attrs_commit ( attrs ) ) /* return -1 if error */
3022 debug_error("failed to commit attribute ""content_audio_found"".\n");
3026 return MM_ERROR_NONE;
3030 debug_log("ERROR : releasing audiobin\n");
3032 MMPLAYER_FREEIF( device_name );
3035 gst_object_unref(GST_OBJECT(pad));
3038 gst_object_unref(GST_OBJECT(ghostpad));
3040 g_list_free( element_bucket );
3043 /* release element which are not added to bin */
3044 for ( i = 1; i < MMPLAYER_A_NUM; i++ ) /* NOTE : skip bin */
3046 if ( audiobin[i].gst )
3048 GstObject* parent = NULL;
3049 parent = gst_element_get_parent( audiobin[i].gst );
3053 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3054 audiobin[i].gst = NULL;
3058 gst_object_unref(GST_OBJECT(parent));
3063 /* release audiobin with it's childs */
3064 if ( audiobin[MMPLAYER_A_BIN].gst )
3066 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3069 MMPLAYER_FREEIF( audiobin );
3071 player->pipeline->audiobin = NULL;
3073 return MM_ERROR_PLAYER_INTERNAL;
3077 __mmplayer_audio_stream_probe (GstPad *pad, GstBuffer *buffer, gpointer u_data)
3079 mm_player_t* player = (mm_player_t*) u_data;
3083 data = GST_BUFFER_DATA(buffer);
3084 size = GST_BUFFER_SIZE(buffer);
3086 if (player->audio_stream_cb && size && data)
3087 player->audio_stream_cb((void *)data, size, player->audio_stream_cb_user_param);
3093 * This function is to create video pipeline.
3095 * @param player [in] handle of player
3096 * caps [in] src caps of decoder
3097 * surface_type [in] surface type for video rendering
3099 * @return This function returns zero on success.
3101 * @see __mmplayer_gst_create_audio_pipeline, __mmplayer_gst_create_midi_pipeline
3105 * - x surface (arm/x86) : xvimagesink
3106 * - evas surface (arm) : ffmpegcolorspace ! evasimagesink
3107 * - evas surface (x86) : videoconvertor ! evasimagesink
3110 __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
3114 GList*element_bucket = NULL;
3115 MMPlayerGstElement* first_element = NULL;
3116 MMPlayerGstElement* videobin = NULL;
3117 gchar* vconv_factory = NULL;
3118 gchar *videosink_element = NULL;
3122 return_val_if_fail(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3125 videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
3127 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3129 player->pipeline->videobin = videobin;
3131 attrs = MMPLAYER_GET_ATTRS(player);
3134 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3135 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3136 if ( !videobin[MMPLAYER_V_BIN].gst )
3138 debug_critical("failed to create videobin");
3142 if( player->use_video_stream ) // video stream callack, so send raw video data to application
3144 GstStructure *str = NULL;
3148 debug_log("using memsink\n");
3150 /* first, create colorspace convert */
3151 if (strlen(PLAYER_INI()->name_of_video_converter) > 0)
3153 vconv_factory = PLAYER_INI()->name_of_video_converter;
3158 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_CONV, vconv_factory, "video converter", TRUE);
3161 /* then, create video scale to resize if needed */
3162 str = gst_caps_get_structure (caps, 0);
3166 debug_error("cannot get structure\n");
3170 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
3172 ret = gst_structure_get_fourcc (str, "format", &fourcc);
3175 debug_log("not fixed format at this point, and not consider this case\n")
3177 /* NOTE : if the width of I420 format is not multiple of 8, it should be resize before colorspace conversion.
3178 * so, video scale is required for this case only.
3180 if ( GST_MAKE_FOURCC ('I', '4', '2', '0') == fourcc )
3182 gint width = 0; //width of video
3183 gint height = 0; //height of video
3184 gint framerate_n = 0; //numerator of frame rate
3185 gint framerate_d = 0; //denominator of frame rate
3186 GstCaps* video_caps = NULL;
3187 const GValue *fps = NULL;
3190 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SCALE, "videoscale", "videoscale", TRUE);
3192 /*to limit width as multiple of 8 */
3193 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_CAPS, "capsfilter", "videocapsfilter", TRUE);
3195 /* get video stream caps parsed by demuxer */
3196 str = gst_caps_get_structure (player->v_stream_caps, 0);
3199 debug_error("cannot get structure\n");
3203 /* check the width if it's a multiple of 8 or not */
3204 ret = gst_structure_get_int (str, "width", &width);
3207 debug_error("cannot get width\n");
3210 width = GST_ROUND_UP_8(width);
3212 ret = gst_structure_get_int(str, "height", &height);
3215 debug_error("cannot get height\n");
3219 fps = gst_structure_get_value (str, "framerate");
3222 debug_error("cannot get fps\n");
3225 framerate_n = gst_value_get_fraction_numerator (fps);
3226 framerate_d = gst_value_get_fraction_denominator (fps);
3228 video_caps = gst_caps_new_simple( "video/x-raw-yuv",
3229 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('I', '4', '2', '0'),
3230 "width", G_TYPE_INT, width,
3231 "height", G_TYPE_INT, height,
3232 "framerate", GST_TYPE_FRACTION, framerate_n, framerate_d,
3235 g_object_set (GST_ELEMENT(videobin[MMPLAYER_V_CAPS].gst), "caps", video_caps, NULL );
3237 gst_caps_unref( video_caps );
3240 /* finally, create video sink. its oupput should be BGRX8888 for application like cario surface. */
3241 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, "avsysmemsink", "videosink", TRUE);
3243 MMPLAYER_SIGNAL_CONNECT( player,
3244 videobin[MMPLAYER_V_SINK].gst,
3246 G_CALLBACK(__mmplayer_videostream_cb),
3249 else // render video data using sink pugin like xvimagesink
3251 debug_log("using videosink");
3253 /*set video converter */
3254 if (strlen(PLAYER_INI()->name_of_video_converter) > 0)
3256 vconv_factory = PLAYER_INI()->name_of_video_converter;
3259 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_CONV, vconv_factory, "video converter", TRUE);
3260 debug_log("using video converter: %s", vconv_factory);
3264 /* videoscaler */ /* NOTE : ini parsing method seems to be more suitable rather than define method */
3265 #if !defined(__arm__)
3266 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SCALE, "videoscale", "videoscaler", TRUE);
3269 /* set video sink */
3270 switch (surface_type)
3272 case MM_DISPLAY_SURFACE_X:
3273 if (strlen(PLAYER_INI()->videosink_element_x) > 0)
3274 videosink_element = PLAYER_INI()->videosink_element_x;
3278 case MM_DISPLAY_SURFACE_EVAS:
3279 if (strlen(PLAYER_INI()->videosink_element_evas) > 0)
3280 videosink_element = PLAYER_INI()->videosink_element_evas;
3284 case MM_DISPLAY_SURFACE_X_EXT:
3286 void *pixmap_id_cb = NULL;
3287 mm_attrs_get_data_by_name(attrs, "display_overlay", &pixmap_id_cb);
3288 if (pixmap_id_cb) /* this is for the video textue(canvas texture) */
3290 videosink_element = PLAYER_INI()->videosink_element_x;
3291 debug_warning("video texture usage");
3295 debug_error("something wrong.. callback function for getting pixmap id is null");
3300 case MM_DISPLAY_SURFACE_NULL:
3301 if (strlen(PLAYER_INI()->videosink_element_fake) > 0)
3302 videosink_element = PLAYER_INI()->videosink_element_fake;
3307 debug_error("unidentified surface type");
3311 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_element, videosink_element, TRUE);
3312 debug_log("selected videosink name: %s", videosink_element);
3315 if ( _mmplayer_update_video_param(player) != MM_ERROR_NONE)
3319 g_object_set (G_OBJECT (videobin[MMPLAYER_V_SINK].gst), "qos", TRUE, NULL);
3321 /* store it as it's sink element */
3322 __mmplayer_add_sink( player, videobin[MMPLAYER_V_SINK].gst );
3324 /* adding created elements to bin */
3325 if( ! __mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket) )
3327 debug_error("failed to add elements\n");
3331 /* Linking elements in the bucket by added order */
3332 if ( __mmplayer_gst_element_link_bucket(element_bucket) == -1 )
3334 debug_error("failed to link elements\n");
3338 /* get first element's sinkpad for creating ghostpad */
3339 first_element = (MMPlayerGstElement *)element_bucket->data;
3340 if ( !first_element )
3342 debug_error("failed to get first element from bucket\n");
3346 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3349 debug_error("failed to get pad from first element\n");
3353 /* create ghostpad */
3354 if (FALSE == gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, gst_ghost_pad_new("sink", pad)))
3356 debug_error("failed to add ghostpad to videobin\n");
3359 gst_object_unref(pad);
3361 /* done. free allocated variables */
3362 g_list_free(element_bucket);
3364 mm_attrs_set_int_by_name(attrs, "content_video_found", TRUE);
3365 if ( mmf_attrs_commit ( attrs ) ) /* return -1 if error */
3366 debug_error("failed to commit attribute ""content_video_found"".\n");
3370 return MM_ERROR_NONE;
3373 debug_error("ERROR : releasing videobin\n");
3375 g_list_free( element_bucket );
3378 gst_object_unref(GST_OBJECT(pad));
3380 /* release videobin with it's childs */
3381 if ( videobin[MMPLAYER_V_BIN].gst )
3383 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3387 MMPLAYER_FREEIF( videobin );
3389 player->pipeline->videobin = NULL;
3391 return MM_ERROR_PLAYER_INTERNAL;
3394 static int __mmplayer_gst_create_text_pipeline(mm_player_t* player)
3396 MMPlayerGstElement* first_element = NULL;
3397 MMPlayerGstElement* textbin = NULL;
3398 GList* element_bucket = NULL;
3400 GstPad *ghostpad = NULL;
3405 return_val_if_fail( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
3408 textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
3411 debug_error("failed to allocate memory for textbin\n");
3412 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3416 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3417 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3418 if ( !textbin[MMPLAYER_T_BIN].gst )
3420 debug_critical("failed to create textbin\n");
3425 player->pipeline->textbin = textbin;
3428 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_SINK, "fakesink", "text_sink", TRUE);
3430 g_object_set (G_OBJECT (textbin[MMPLAYER_T_SINK].gst), "sync", TRUE, NULL);
3431 g_object_set (G_OBJECT (textbin[MMPLAYER_T_SINK].gst), "async", FALSE, NULL);
3432 g_object_set (G_OBJECT (textbin[MMPLAYER_T_SINK].gst), "signal-handoffs", TRUE, NULL);
3434 MMPLAYER_SIGNAL_CONNECT( player,
3435 G_OBJECT(textbin[MMPLAYER_T_SINK].gst),
3437 G_CALLBACK(__mmplayer_update_subtitle),
3440 __mmplayer_add_sink (player, GST_ELEMENT(textbin[MMPLAYER_T_SINK].gst));
3442 /* adding created elements to bin */
3443 debug_log("adding created elements to bin\n");
3444 if( !__mmplayer_gst_element_add_bucket_to_bin( GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket ))
3446 debug_error("failed to add elements\n");
3450 /* linking elements in the bucket by added order. */
3451 debug_log("Linking elements in the bucket by added order.\n");
3452 if ( __mmplayer_gst_element_link_bucket(element_bucket) == -1 )
3454 debug_error("failed to link elements\n");
3458 /* get first element's sinkpad for creating ghostpad */
3459 first_element = (MMPlayerGstElement *)element_bucket->data;
3461 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3464 debug_error("failed to get pad from first element of textbin\n");
3468 ghostpad = gst_ghost_pad_new("sink", pad);
3471 debug_error("failed to create ghostpad\n");
3475 if ( FALSE == gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad) )
3477 debug_error("failed to add ghostpad to textbin\n");
3481 gst_object_unref(pad);
3484 /* done. free allocated variables */
3485 g_list_free(element_bucket);
3489 return MM_ERROR_NONE;
3493 debug_log("ERROR : releasing textbin\n");
3496 gst_object_unref(GST_OBJECT(pad));
3499 gst_object_unref(GST_OBJECT(ghostpad));
3501 g_list_free( element_bucket );
3504 /* release element which are not added to bin */
3505 for ( i = 1; i < MMPLAYER_T_NUM; i++ ) /* NOTE : skip bin */
3507 if ( textbin[i].gst )
3509 GstObject* parent = NULL;
3510 parent = gst_element_get_parent( textbin[i].gst );
3514 gst_object_unref(GST_OBJECT(textbin[i].gst));
3515 textbin[i].gst = NULL;
3519 gst_object_unref(GST_OBJECT(parent));
3524 /* release textbin with it's childs */
3525 if ( textbin[MMPLAYER_T_BIN].gst )
3527 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3530 MMPLAYER_FREEIF( textbin );
3532 player->pipeline->textbin = NULL;
3534 return MM_ERROR_PLAYER_INTERNAL;
3539 __mmplayer_gst_create_subtitle_pipeline(mm_player_t* player)
3541 MMPlayerGstElement* subtitlebin = NULL;
3542 MMHandleType attrs = 0;
3543 gchar *subtitle_uri =NULL;
3544 GList*element_bucket = NULL;
3546 #define USE_MESSAGE_FOR_PLAYING_SUBTITLE
3547 #ifndef USE_MESSAGE_FOR_PLAYING_SUBTITLE
3549 gint width =0, height = 0;
3550 gboolean silent=FALSE;
3556 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3558 attrs = MMPLAYER_GET_ATTRS(player);
3561 debug_error("cannot get content attribute\n");
3562 return MM_ERROR_PLAYER_INTERNAL;
3565 mm_attrs_get_string_by_name ( attrs, "subtitle_uri", &subtitle_uri );
3566 if ( !subtitle_uri || strlen(subtitle_uri) < 1)
3568 debug_error("subtitle uri is not proper filepath.\n");
3569 return MM_ERROR_PLAYER_INVALID_URI;
3571 debug_log("subtitle file path is [%s].\n", subtitle_uri);
3575 subtitlebin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_SUB_NUM);
3578 debug_error("failed to allocate memory\n");
3579 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3583 subtitlebin[MMPLAYER_SUB_PIPE].id = MMPLAYER_SUB_PIPE;
3584 subtitlebin[MMPLAYER_SUB_PIPE].gst = gst_pipeline_new("subtitlebin");
3585 if ( !subtitlebin[MMPLAYER_SUB_PIPE].gst )
3587 debug_error("failed to create text pipeline\n");
3590 player->pipeline->subtitlebin = subtitlebin;
3592 /* create the text file source */
3593 MMPLAYER_CREATE_ELEMENT(subtitlebin, MMPLAYER_SUB_SRC, "filesrc", "subtitle_source", TRUE);
3594 g_object_set(G_OBJECT (subtitlebin[MMPLAYER_SUB_SRC].gst), "location", subtitle_uri, NULL);
3597 MMPLAYER_CREATE_ELEMENT(subtitlebin, MMPLAYER_SUB_QUEUE, "queue", NULL, TRUE);
3600 MMPLAYER_CREATE_ELEMENT(subtitlebin, MMPLAYER_SUB_SUBPARSE, "subparse", "subtitle_parser", TRUE);
3602 #ifndef USE_MESSAGE_FOR_PLAYING_SUBTITLE
3604 MMPLAYER_CREATE_ELEMENT(subtitlebin, MMPLAYER_SUB_TEXTRENDER, "textrender", "subtitle_render", TRUE);
3606 mm_attrs_get_int_by_name(attrs,"width", &width);
3607 mm_attrs_get_int_by_name(attrs,"height", &height);
3608 mm_attrs_get_int_by_name(attrs,"silent", &silent);
3609 g_object_set ( G_OBJECT (subtitlebin[MMPLAYER_SUB_TEXTRENDER].gst),"width", width, NULL);
3610 g_object_set ( G_OBJECT (subtitlebin[MMPLAYER_SUB_TEXTRENDER].gst),"height", height, NULL);
3611 g_object_set ( G_OBJECT (subtitlebin[MMPLAYER_SUB_TEXTRENDER].gst),"silent", silent, NULL);
3613 debug_log ( "subtitle winow size is [%dX%d].\n", width, height );
3614 debug_log ( "subtitle silent is [%d].\n", silent );
3617 MMPLAYER_CREATE_ELEMENT(subtitlebin, MMPLAYER_SUB_CONV1, "ffmpegcolorspace", "subtitle_converter1", TRUE);
3620 MMPLAYER_CREATE_ELEMENT(subtitlebin, MMPLAYER_SUB_FLIP, "videoflip", "subtitle_fliper", TRUE);
3623 MMPLAYER_CREATE_ELEMENT(subtitlebin, MMPLAYER_SUB_CONV2, "ffmpegcolorspace", "subtitle_converter2", TRUE);
3626 MMPLAYER_CREATE_ELEMENT(subtitlebin, MMPLAYER_SUB_SINK, "ximagesink", "subtitle_sink", TRUE);
3628 mm_attrs_get_data_by_name(attrs, "xid", &xid);
3631 debug_log("setting subtitle xid = %d\n", *(int*)xid);
3632 gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(subtitlebin[MMPLAYER_SUB_SINK].gst), *(int*)xid);
3636 /* FIXIT : is it error case? */
3637 debug_warning("still we don't have xid on player attribute. create it's own surface.\n");
3641 MMPLAYER_CREATE_ELEMENT(subtitlebin, MMPLAYER_SUB_SINK, "fakesink", "subtitle_sink", TRUE);
3643 g_object_set (G_OBJECT (subtitlebin[MMPLAYER_SUB_SINK].gst), "sync", TRUE, NULL);
3644 g_object_set (G_OBJECT (subtitlebin[MMPLAYER_SUB_SINK].gst), "async", FALSE, NULL);
3645 g_object_set (G_OBJECT (subtitlebin[MMPLAYER_SUB_SINK].gst), "signal-handoffs", TRUE, NULL);
3647 MMPLAYER_SIGNAL_CONNECT( player,
3648 G_OBJECT(subtitlebin[MMPLAYER_SUB_SINK].gst),
3650 G_CALLBACK(__mmplayer_update_subtitle),
3654 /* adding created elements to bin */
3655 if( ! __mmplayer_gst_element_add_bucket_to_bin(GST_BIN(subtitlebin[MMPLAYER_SUB_PIPE].gst), element_bucket) )
3657 debug_error("failed to add elements\n");
3661 /* Linking elements in the bucket by added order */
3662 if ( __mmplayer_gst_element_link_bucket(element_bucket) == -1 )
3664 debug_error("failed to link elements\n");
3668 /* done. free allocated variables */
3669 g_list_free(element_bucket);
3671 player->play_subtitle = TRUE;
3675 return MM_ERROR_NONE;
3679 debug_error("ERROR : releasing text pipeline\n");
3681 g_list_free( element_bucket );
3683 /* release subtitlebin with it's childs */
3684 if ( subtitlebin[MMPLAYER_SUB_PIPE].gst )
3686 gst_object_unref(GST_OBJECT(subtitlebin[MMPLAYER_SUB_PIPE].gst));
3689 MMPLAYER_FREEIF( subtitlebin );
3691 player->pipeline->subtitlebin = NULL;
3693 return MM_ERROR_PLAYER_INTERNAL;
3697 __mmplayer_update_subtitle( GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
3699 mm_player_t* player = (mm_player_t*) data;
3700 MMMessageParamType msg = {0, };
3701 GstClockTime duration = 0;
3702 guint8 *text = NULL;
3703 gboolean ret = TRUE;
3707 return_val_if_fail ( player, FALSE );
3708 return_val_if_fail ( buffer, FALSE );
3710 text = GST_BUFFER_DATA(buffer);
3711 duration = GST_BUFFER_DURATION(buffer);
3713 if ( player->is_subtitle_off )
3715 debug_log("subtitle is OFF.\n" );
3721 debug_log("There is no subtitle to be displayed.\n" );
3725 msg.data = (void *) text;
3726 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
3728 debug_warning("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data );
3730 MMPLAYER_POST_MSG( player, MM_MESSAGE_UPDATE_SUBTITLE, &msg );
3738 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
3740 GstEvent* event = NULL;
3741 gint64 current_pos = 0;
3742 gint64 adusted_pos = 0;
3743 gboolean ret = TRUE;
3747 /* check player and subtitlebin are created */
3748 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
3749 return_val_if_fail ( MMPLAYER_PLAY_SUBTITLE(player), MM_ERROR_PLAYER_NOT_INITIALIZED );
3753 debug_log("adjusted values is 0, no need to adjust subtitle position.\n");
3754 return MM_ERROR_NONE;
3759 case MM_PLAYER_POS_FORMAT_TIME:
3761 GstFormat fmt = GST_FORMAT_TIME;
3762 /* check current postion */
3763 ret = gst_element_query_position( GST_ELEMENT(player->pipeline->subtitlebin[MMPLAYER_SUB_PIPE].gst), &fmt, ¤t_pos );
3766 debug_warning("fail to query current postion.\n");
3767 return MM_ERROR_PLAYER_SEEK;
3771 adusted_pos = current_pos + ((gint64)position * G_GINT64_CONSTANT(1000000));
3772 if (adusted_pos < 0)
3773 adusted_pos = G_GINT64_CONSTANT(0);
3774 debug_log("adjust subtitle postion : %lu -> %lu [msec]\n", GST_TIME_AS_MSECONDS(current_pos), GST_TIME_AS_MSECONDS(adusted_pos));
3777 event = gst_event_new_seek (1.0, GST_FORMAT_TIME,
3778 ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ),
3779 GST_SEEK_TYPE_SET, adusted_pos,
3780 GST_SEEK_TYPE_SET, -1);
3784 case MM_PLAYER_POS_FORMAT_PERCENT:
3786 debug_warning("percent format is not supported yet.\n");
3787 return MM_ERROR_INVALID_ARGUMENT;
3793 debug_warning("invalid format.\n");
3794 return MM_ERROR_INVALID_ARGUMENT;
3798 /* keep ref to the event */
3799 gst_event_ref (event);
3801 debug_log("sending event[%s] to sink element [%s]\n",
3802 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(player->pipeline->subtitlebin[MMPLAYER_SUB_SINK].gst) );
3804 if ( ret = gst_element_send_event (player->pipeline->subtitlebin[MMPLAYER_SUB_SINK].gst, event) )
3806 debug_log("sending event[%s] to sink element [%s] success!\n",
3807 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(player->pipeline->subtitlebin[MMPLAYER_SUB_SINK].gst) );
3810 /* unref to the event */
3811 gst_event_unref (event);
3816 return MM_ERROR_NONE;
3821 __gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data) // @
3823 GstElement *appsrc = element;
3824 tBuffer *buf = (tBuffer *)user_data;
3825 GstBuffer *buffer = NULL;
3826 GstFlowReturn ret = GST_FLOW_OK;
3829 return_if_fail ( element );
3830 return_if_fail ( buf );
3832 buffer = gst_buffer_new ();
3834 if (buf->offset >= buf->len)
3836 debug_log("call eos appsrc\n");
3837 g_signal_emit_by_name (appsrc, "end-of-stream", &ret);
3841 if ( buf->len - buf->offset < size)
3843 len = buf->len - buf->offset + buf->offset;
3846 GST_BUFFER_DATA(buffer) = (guint8*)(buf->buf + buf->offset);
3847 GST_BUFFER_SIZE(buffer) = len;
3848 GST_BUFFER_OFFSET(buffer) = buf->offset;
3849 GST_BUFFER_OFFSET_END(buffer) = buf->offset + len;
3851 debug_log("feed buffer %p, offset %u-%u length %u\n", buffer, buf->offset, buf->len,len);
3852 g_signal_emit_by_name (appsrc, "push-buffer", buffer, &ret);
3858 __gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data) // @
3860 tBuffer *buf = (tBuffer *)user_data;
3862 return_val_if_fail ( buf, FALSE );
3864 buf->offset = (int)size;
3870 __gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data) // @
3872 mm_player_t *player = (mm_player_t*)user_data;
3874 return_if_fail ( player );
3876 debug_msg("app-src: feed data\n");
3878 if(player->need_data_cb)
3879 player->need_data_cb(size, player->buffer_cb_user_param);
3883 __gst_appsrc_seek_data(GstElement *element, guint64 offset, gpointer user_data) // @
3885 mm_player_t *player = (mm_player_t*)user_data;
3887 return_val_if_fail ( player, FALSE );
3889 debug_msg("app-src: seek data\n");
3891 if(player->seek_data_cb)
3892 player->seek_data_cb(offset, player->buffer_cb_user_param);
3899 __gst_appsrc_enough_data(GstElement *element, gpointer user_data) // @
3901 mm_player_t *player = (mm_player_t*)user_data;
3903 return_val_if_fail ( player, FALSE );
3905 debug_msg("app-src: enough data:%p\n", player->enough_data_cb);
3907 if(player->enough_data_cb)
3908 player->enough_data_cb(player->buffer_cb_user_param);
3914 _mmplayer_push_buffer(MMHandleType hplayer, unsigned char *buf, int size) // @
3916 mm_player_t* player = (mm_player_t*)hplayer;
3917 GstBuffer *buffer = NULL;
3918 GstFlowReturn gst_ret = GST_FLOW_OK;
3919 int ret = MM_ERROR_NONE;
3923 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
3925 /* check current state */
3926 // MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_START );
3929 /* NOTE : we should check and create pipeline again if not created as we destroy
3930 * whole pipeline when stopping in streamming playback
3932 if ( ! player->pipeline )
3934 if ( MM_ERROR_NONE != __gst_realize( player ) )
3936 debug_error("failed to realize before starting. only in streamming\n");
3937 return MM_ERROR_PLAYER_INTERNAL;
3941 debug_msg("app-src: pushing data\n");
3945 debug_error("buf is null\n");
3946 return MM_ERROR_NONE;
3949 buffer = gst_buffer_new ();
3953 debug_log("call eos appsrc\n");
3954 g_signal_emit_by_name (player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "end-of-stream", &gst_ret);
3955 return MM_ERROR_NONE;
3958 GST_BUFFER_DATA(buffer) = (guint8*)(buf);
3959 GST_BUFFER_SIZE(buffer) = size;
3961 debug_log("feed buffer %p, length %u\n", buf, size);
3962 g_signal_emit_by_name (player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "push-buffer", buffer, &gst_ret);
3969 static GstBusSyncReply
3970 __mmplayer_bus_sync_callback (GstBus * bus, GstMessage * message, gpointer data)
3972 mm_player_t *player = (mm_player_t *)data;
3973 GstElement *sender = (GstElement *) GST_MESSAGE_SRC (message);
3974 const gchar *name = gst_element_get_name (sender);
3976 switch (GST_MESSAGE_TYPE (message))
3978 case GST_MESSAGE_TAG:
3979 __mmplayer_gst_extract_tag_from_msg(player, message);
3983 return GST_BUS_PASS;
3985 gst_message_unref (message);
3987 return GST_BUS_DROP;
3991 * This function is to create audio or video pipeline for playing.
3993 * @param player [in] handle of player
3995 * @return This function returns zero on success.
4000 __mmplayer_gst_create_pipeline(mm_player_t* player) // @
4003 MMPlayerGstElement *mainbin = NULL;
4004 MMHandleType attrs = 0;
4005 GstElement* element = NULL;
4006 GList* element_bucket = NULL;
4007 gboolean need_state_holder = TRUE;
4012 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4014 /* get profile attribute */
4015 attrs = MMPLAYER_GET_ATTRS(player);
4018 debug_error("cannot get content attribute\n");
4022 /* create pipeline handles */
4023 if ( player->pipeline )
4025 debug_warning("pipeline should be released before create new one\n");
4029 player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0( sizeof(MMPlayerGstPipelineInfo) );
4030 if (player->pipeline == NULL)
4033 memset( player->pipeline, 0, sizeof(MMPlayerGstPipelineInfo) );
4036 /* create mainbin */
4037 mainbin = (MMPlayerGstElement*) g_malloc0( sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM );
4038 if (mainbin == NULL)
4041 memset( mainbin, 0, sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
4044 /* create pipeline */
4045 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4046 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4047 if ( ! mainbin[MMPLAYER_M_PIPE].gst )
4049 debug_error("failed to create pipeline\n");
4054 /* create source element */
4055 switch ( player->profile.uri_type )
4057 /* rtsp streamming */
4058 case MM_PLAYER_URI_TYPE_URL_RTSP:
4060 gint network_bandwidth;
4061 gchar *user_agent, *wap_profile;
4063 element = gst_element_factory_make(PLAYER_INI()->name_of_rtspsrc, "streaming_source");
4067 debug_critical("failed to create streaming source element\n");
4071 debug_log("using streamming source [%s].\n", PLAYER_INI()->name_of_rtspsrc);
4074 network_bandwidth = 0;
4075 user_agent = wap_profile = NULL;
4078 mm_attrs_get_string_by_name ( attrs, "streaming_user_agent", &user_agent );
4079 mm_attrs_get_string_by_name ( attrs,"streaming_wap_profile", &wap_profile );
4080 mm_attrs_get_int_by_name ( attrs, "streaming_network_bandwidth", &network_bandwidth );
4082 debug_log("setting streaming source ----------------\n");
4083 debug_log("user_agent : %s\n", user_agent);
4084 debug_log("wap_profile : %s\n", wap_profile);
4085 debug_log("network_bandwidth : %d\n", network_bandwidth);
4086 debug_log("buffering time : %d\n", PLAYER_INI()->rtsp_buffering_time);
4087 debug_log("rebuffering time : %d\n", PLAYER_INI()->rtsp_rebuffering_time);
4088 debug_log("-----------------------------------------\n");
4090 /* setting property to streaming source */
4091 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
4092 g_object_set(G_OBJECT(element), "bandwidth", network_bandwidth, NULL);
4093 g_object_set(G_OBJECT(element), "buffering_time", PLAYER_INI()->rtsp_buffering_time, NULL);
4094 g_object_set(G_OBJECT(element), "rebuffering_time", PLAYER_INI()->rtsp_rebuffering_time, NULL);
4096 g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL);
4098 g_object_set(G_OBJECT(element), "wap_profile", wap_profile, NULL);
4100 MMPLAYER_SIGNAL_CONNECT ( player, G_OBJECT(element), "pad-added",
4101 G_CALLBACK (__mmplayer_gst_rtp_dynamic_pad), player );
4102 MMPLAYER_SIGNAL_CONNECT ( player, G_OBJECT(element), "no-more-pads",
4103 G_CALLBACK (__mmplayer_gst_rtp_no_more_pads), player );
4105 player->no_more_pad = FALSE;
4106 player->num_dynamic_pad = 0;
4108 /* NOTE : we cannot determine it yet. this filed will be filled by
4109 * _mmplayer_update_content_attrs() after START.
4111 player->streaming_type = STREAMING_SERVICE_NONE;
4116 case MM_PLAYER_URI_TYPE_URL_HTTP:
4118 gchar *user_agent, *proxy, *cookies, **cookie_list;
4119 user_agent = proxy = cookies = NULL;
4121 gint mode = MM_PLAYER_PD_MODE_NONE;
4123 mm_attrs_get_int_by_name ( attrs, "pd_mode", &mode );
4125 player->pd_mode = mode;
4127 debug_log("http playback, PD mode : %d\n", player->pd_mode);
4129 if ( ! MMPLAYER_IS_HTTP_PD(player) )
4131 element = gst_element_factory_make(PLAYER_INI()->name_of_httpsrc, "http_streaming_source");
4134 debug_critical("failed to create http streaming source element[%s].\n", PLAYER_INI()->name_of_httpsrc);
4137 debug_log("using http streamming source [%s].\n", PLAYER_INI()->name_of_httpsrc);
4140 mm_attrs_get_string_by_name ( attrs, "streaming_cookie", &cookies );
4141 mm_attrs_get_string_by_name ( attrs, "streaming_user_agent", &user_agent );
4142 mm_attrs_get_string_by_name ( attrs, "streaming_proxy", &proxy );
4145 debug_log("setting http streaming source ----------------\n");
4146 debug_log("location : %s\n", player->profile.uri);
4147 debug_log("cookies : %s\n", cookies);
4148 debug_log("proxy : %s\n", proxy);
4149 debug_log("user_agent : %s\n", user_agent);
4150 debug_log("timeout : %d\n", PLAYER_INI()->http_timeout);
4151 debug_log("-----------------------------------------\n");
4153 /* setting property to streaming source */
4154 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
4155 g_object_set(G_OBJECT(element), "timeout", PLAYER_INI()->http_timeout, NULL);
4156 /* check if prosy is vailid or not */
4157 if ( util_check_valid_url ( proxy ) )
4158 g_object_set(G_OBJECT(element), "proxy", proxy, NULL);
4159 /* parsing cookies */
4160 if ( ( cookie_list = util_get_cookie_list ((const char*)cookies) ) )
4161 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
4163 g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL);
4165 else // progressive download
4167 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
4171 mm_attrs_get_string_by_name ( attrs, "pd_location", &path );
4173 MMPLAYER_FREEIF(player->pd_file_save_path);
4175 debug_log("PD Location : %s\n", path);
4179 player->pd_file_save_path = g_strdup(path);
4183 debug_error("can't find pd location so, it should be set \n");
4184 return MM_ERROR_PLAYER_FILE_NOT_FOUND;
4188 element = gst_element_factory_make("pdpushsrc", "PD pushsrc");
4191 debug_critical("failed to create PD push source element[%s].\n", "pdpushsrc");
4195 g_object_set(G_OBJECT(element), "location", player->pd_file_save_path, NULL);
4198 player->streaming_type = STREAMING_SERVICE_NONE;
4203 case MM_PLAYER_URI_TYPE_FILE:
4205 char* drmsrc = PLAYER_INI()->name_of_drmsrc;
4207 debug_log("using [%s] for 'file://' handler.\n", drmsrc);
4209 element = gst_element_factory_make(drmsrc, "source");
4212 debug_critical("failed to create %s\n", drmsrc);
4216 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
4217 //g_object_set(G_OBJECT(element), "use-mmap", TRUE, NULL);
4222 case MM_PLAYER_URI_TYPE_BUFF:
4224 guint64 stream_type = GST_APP_STREAM_TYPE_STREAM;
4226 debug_log("mem src is selected\n");
4228 element = gst_element_factory_make("appsrc", "buff-source");
4231 debug_critical("failed to create appsrc element\n");
4235 g_object_set( element, "stream-type", stream_type, NULL );
4236 //g_object_set( element, "size", player->mem_buf.len, NULL );
4237 //g_object_set( element, "blocksize", (guint64)20480, NULL );
4239 MMPLAYER_SIGNAL_CONNECT( player, element, "seek-data",
4240 G_CALLBACK(__gst_appsrc_seek_data), player);
4241 MMPLAYER_SIGNAL_CONNECT( player, element, "need-data",
4242 G_CALLBACK(__gst_appsrc_feed_data), player);
4243 MMPLAYER_SIGNAL_CONNECT( player, element, "enough-data",
4244 G_CALLBACK(__gst_appsrc_enough_data), player);
4249 case MM_PLAYER_URI_TYPE_MEM:
4251 guint64 stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
4253 debug_log("mem src is selected\n");
4255 element = gst_element_factory_make("appsrc", "mem-source");
4258 debug_critical("failed to create appsrc element\n");
4262 g_object_set( element, "stream-type", stream_type, NULL );
4263 g_object_set( element, "size", player->mem_buf.len, NULL );
4264 g_object_set( element, "blocksize", (guint64)20480, NULL );
4266 MMPLAYER_SIGNAL_CONNECT( player, element, "seek-data",
4267 G_CALLBACK(__gst_appsrc_seek_data_mem), &player->mem_buf );
4268 MMPLAYER_SIGNAL_CONNECT( player, element, "need-data",
4269 G_CALLBACK(__gst_appsrc_feed_data_mem), &player->mem_buf );
4272 case MM_PLAYER_URI_TYPE_URL:
4275 case MM_PLAYER_URI_TYPE_TEMP:
4278 case MM_PLAYER_URI_TYPE_NONE:
4283 /* check source element is OK */
4286 debug_critical("no source element was created.\n");
4290 /* take source element */
4291 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4292 mainbin[MMPLAYER_M_SRC].gst = element;
4293 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
4295 if (MMPLAYER_IS_STREAMING(player))
4297 player->streamer = __mm_player_streaming_create();
4298 __mm_player_streaming_initialize(player->streamer);
4301 if ( MMPLAYER_IS_HTTP_PD(player) )
4303 debug_log ("Picked queue2 element....\n");
4304 element = gst_element_factory_make("queue2", "hls_stream_buffer");
4307 debug_critical ( "failed to create http streaming buffer element\n" );
4312 mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_S_BUFFER;
4313 mainbin[MMPLAYER_M_S_BUFFER].gst = element;
4314 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_S_BUFFER]);
4316 __mm_player_streaming_set_buffer(player->streamer,
4319 PLAYER_INI()->http_max_size_bytes,
4321 PLAYER_INI()->http_buffering_limit,
4322 PLAYER_INI()->http_buffering_time,
4328 /* create autoplugging element if src element is not a streamming src */
4329 if ( player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_RTSP )
4333 if( PLAYER_INI()->use_decodebin )
4335 /* create decodebin */
4336 element = gst_element_factory_make("decodebin", "decodebin");
4338 g_object_set(G_OBJECT(element), "async-handling", TRUE, NULL);
4340 /* set signal handler */
4341 MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(element), "new-decoded-pad",
4342 G_CALLBACK(__mmplayer_gst_decode_callback), player);
4344 /* we don't need state holder, bcz decodebin is doing well by itself */
4345 need_state_holder = FALSE;
4349 element = gst_element_factory_make("typefind", "typefinder");
4350 MMPLAYER_SIGNAL_CONNECT( player, element, "have-type",
4351 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player );
4354 /* check autoplug element is OK */
4357 debug_critical("can not create autoplug element\n");
4361 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
4362 mainbin[MMPLAYER_M_AUTOPLUG].gst = element;
4364 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_AUTOPLUG]);
4368 /* add elements to pipeline */
4369 if( !__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket))
4371 debug_error("Failed to add elements to pipeline\n");
4376 /* linking elements in the bucket by added order. */
4377 if ( __mmplayer_gst_element_link_bucket(element_bucket) == -1 )
4379 debug_error("Failed to link some elements\n");
4384 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4385 if ( need_state_holder )
4388 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4389 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make ("fakesink", "state-holder");
4391 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4393 debug_error ("fakesink element could not be created\n");
4396 GST_OBJECT_FLAG_UNSET (mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_IS_SINK);
4398 /* take ownership of fakesink. we are reusing it */
4399 gst_object_ref( mainbin[MMPLAYER_M_SRC_FAKESINK].gst );
4402 if ( FALSE == gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst),
4403 mainbin[MMPLAYER_M_SRC_FAKESINK].gst) )
4405 debug_error("failed to add fakesink to bin\n");
4410 /* now we have completed mainbin. take it */
4411 player->pipeline->mainbin = mainbin;
4413 /* connect bus callback */
4414 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4417 debug_error ("cannot get bus from pipeline.\n");
4420 player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_callback, player);
4422 /* Note : check whether subtitle atrribute uri is set. If uri is set, then create the text pipeline */
4423 if ( __mmplayer_check_subtitle ( player ) )
4425 debug_log("try to create subtitle pipeline \n");
4427 if ( MM_ERROR_NONE != __mmplayer_gst_create_subtitle_pipeline(player) )
4428 debug_error("fail to create subtitle pipeline")
4430 debug_log("subtitle pipeline is created successfully\n");
4433 /* set sync handler to get tag synchronously */
4434 gst_bus_set_sync_handler(bus, __mmplayer_bus_sync_callback, player);
4438 gst_object_unref(GST_OBJECT(bus));
4439 g_list_free(element_bucket);
4443 return MM_ERROR_NONE;
4447 __mmplayer_gst_destroy_pipeline(player);
4448 g_list_free(element_bucket);
4450 /* release element which are not added to bin */
4451 for ( i = 1; i < MMPLAYER_M_NUM; i++ ) /* NOTE : skip pipeline */
4453 if ( mainbin[i].gst )
4455 GstObject* parent = NULL;
4456 parent = gst_element_get_parent( mainbin[i].gst );
4460 gst_object_unref(GST_OBJECT(mainbin[i].gst));
4461 mainbin[i].gst = NULL;
4465 gst_object_unref(GST_OBJECT(parent));
4470 /* release pipeline with it's childs */
4471 if ( mainbin[MMPLAYER_M_PIPE].gst )
4473 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4476 MMPLAYER_FREEIF( player->pipeline );
4477 MMPLAYER_FREEIF( mainbin );
4479 return MM_ERROR_PLAYER_INTERNAL;
4484 __mmplayer_gst_destroy_pipeline(mm_player_t* player) // @
4487 int ret = MM_ERROR_NONE;
4491 return_val_if_fail ( player, MM_ERROR_INVALID_HANDLE );
4493 /* cleanup stuffs */
4494 MMPLAYER_FREEIF(player->type);
4495 player->have_dynamic_pad = FALSE;
4496 player->no_more_pad = FALSE;
4497 player->num_dynamic_pad = 0;
4499 if (player->v_stream_caps)
4501 gst_caps_unref(player->v_stream_caps);
4502 player->v_stream_caps = NULL;
4505 if (ahs_appsrc_cb_probe_id )
4508 pad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "src" );
4510 gst_pad_remove_buffer_probe (pad, ahs_appsrc_cb_probe_id);
4511 gst_object_unref(pad);
4513 ahs_appsrc_cb_probe_id = 0;
4516 if ( player->sink_elements )
4517 g_list_free ( player->sink_elements );
4518 player->sink_elements = NULL;
4520 /* cleanup unlinked mime type */
4521 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4522 MMPLAYER_FREEIF(player->unlinked_video_mime);
4523 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4525 /* cleanup running stuffs */
4526 __mmplayer_cancel_delayed_eos( player );
4528 /* cleanup gst stuffs */
4529 if ( player->pipeline )
4531 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
4532 GstTagList* tag_list = player->pipeline->tag_list;
4534 /* first we need to disconnect all signal hander */
4535 __mmplayer_release_signal_connection( player );
4537 /* disconnecting bus watch */
4538 if ( player->bus_watcher )
4539 g_source_remove( player->bus_watcher );
4540 player->bus_watcher = 0;
4545 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4546 MMPlayerGstElement* videobin = player->pipeline->videobin;
4547 MMPlayerGstElement* textbin = player->pipeline->textbin;
4548 MMPlayerGstElement* subtitlebin = player->pipeline->subtitlebin;
4549 GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE (mainbin[MMPLAYER_M_PIPE].gst));
4550 gst_bus_set_sync_handler (bus, NULL, NULL);
4552 debug_log("pipeline status before set state to NULL\n");
4553 __mmplayer_dump_pipeline_state( player );
4555 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4556 ret = __mmplayer_gst_set_state ( player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout );
4557 if ( ret != MM_ERROR_NONE )
4559 debug_error("fail to change state to NULL\n");
4560 return MM_ERROR_PLAYER_INTERNAL;
4563 debug_log("pipeline status before unrefering pipeline\n");
4564 __mmplayer_dump_pipeline_state( player );
4566 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4569 if ( mainbin[MMPLAYER_M_SRC_FAKESINK].gst )
4570 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4572 /* free avsysaudiosink
4573 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4574 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4576 MMPLAYER_FREEIF( audiobin );
4577 MMPLAYER_FREEIF( videobin );
4578 MMPLAYER_FREEIF( textbin );
4579 MMPLAYER_FREEIF( subtitlebin);
4580 MMPLAYER_FREEIF( mainbin );
4584 gst_tag_list_free(tag_list);
4586 MMPLAYER_FREEIF( player->pipeline );
4589 player->pipeline_is_constructed = FALSE;
4596 static int __gst_realize(mm_player_t* player) // @
4599 int ret = MM_ERROR_NONE;
4603 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4605 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4607 __ta__("__mmplayer_gst_create_pipeline",
4608 ret = __mmplayer_gst_create_pipeline(player);
4611 debug_critical("failed to create pipeline\n");
4616 /* set pipeline state to READY */
4617 /* NOTE : state change to READY must be performed sync. */
4618 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4619 ret = __mmplayer_gst_set_state(player,
4620 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4622 if (MMPLAYER_PLAY_SUBTITLE(player))
4623 ret = __mmplayer_gst_set_state(player,
4624 player->pipeline->subtitlebin[MMPLAYER_SUB_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4626 if ( ret != MM_ERROR_NONE )
4628 /* return error if failed to set state */
4629 debug_error("failed to set state PAUSED (live : READY).\n");
4631 /* dump state of all element */
4632 __mmplayer_dump_pipeline_state( player );
4638 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_READY );
4641 /* create dot before error-return. for debugging */
4642 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-realize" );
4649 static int __gst_unrealize(mm_player_t* player) // @
4651 int ret = MM_ERROR_NONE;
4655 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4657 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4658 MMPLAYER_PRINT_STATE(player);
4660 /* release miscellaneous information */
4661 __mmplayer_release_misc( player );
4663 /* destroy pipeline */
4664 ret = __mmplayer_gst_destroy_pipeline( player );
4665 if ( ret != MM_ERROR_NONE )
4667 debug_error("failed to destory pipeline\n");
4671 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_NULL );
4678 static int __gst_pending_seek ( mm_player_t* player )
4680 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
4681 MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
4682 int ret = MM_ERROR_NONE;
4686 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
4688 if ( !player->pending_seek.is_pending )
4690 debug_log("pending seek is not reserved. nothing to do.\n" );
4694 /* check player state if player could pending seek or not. */
4695 current_state = MMPLAYER_CURRENT_STATE(player);
4696 pending_state = MMPLAYER_PENDING_STATE(player);
4698 if ( current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING )
4700 debug_warning("try to pending seek in %s state, try next time. \n",
4701 MMPLAYER_STATE_GET_NAME(current_state));
4705 debug_log("trying to play from (%lu) pending position\n", player->pending_seek.pos);
4707 ret = __gst_set_position ( player, player->pending_seek.format, player->pending_seek.pos, FALSE );
4709 if ( MM_ERROR_NONE != ret )
4710 debug_error("failed to seek pending postion. just keep staying current position.\n");
4712 player->pending_seek.is_pending = FALSE;
4719 static int __gst_start(mm_player_t* player) // @
4721 gboolean sound_extraction = 0;
4722 int ret = MM_ERROR_NONE;
4726 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
4728 /* get sound_extraction property */
4729 mm_attrs_get_int_by_name(player->attrs, "pcm_extraction", &sound_extraction);
4731 /* NOTE : if SetPosition was called before Start. do it now */
4732 /* streaming doesn't support it. so it should be always sync */
4733 /* !! create one more api to check if there is pending seek rather than checking variables */
4734 if ( (player->pending_seek.is_pending || sound_extraction) && !MMPLAYER_IS_STREAMING(player))
4736 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
4737 ret = __gst_pause(player, FALSE);
4738 if ( ret != MM_ERROR_NONE )
4740 debug_error("failed to set state to PAUSED for pending seek\n");
4744 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
4746 if ( sound_extraction )
4748 debug_log("setting pcm extraction\n");
4750 ret = __mmplayer_set_pcm_extraction(player);
4751 if ( MM_ERROR_NONE != ret )
4753 debug_warning("failed to set pcm extraction\n");
4759 if ( MM_ERROR_NONE != __gst_pending_seek(player) )
4761 debug_warning("failed to seek pending postion. starting from the begin of content.\n");
4766 debug_log("current state before doing transition");
4767 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
4768 MMPLAYER_PRINT_STATE(player);
4770 /* set pipeline state to PLAYING */
4771 ret = __mmplayer_gst_set_state(player,
4772 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player) );
4774 if (MMPLAYER_PLAY_SUBTITLE(player))
4775 ret = __mmplayer_gst_set_state(player,
4776 player->pipeline->subtitlebin[MMPLAYER_SUB_PIPE].gst, GST_STATE_PLAYING, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player) );
4778 if (ret == MM_ERROR_NONE)
4780 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
4784 debug_error("failed to set state to PLAYING");
4786 /* dump state of all element */
4787 __mmplayer_dump_pipeline_state( player );
4792 /* FIXIT : analyze so called "async problem" */
4794 __gst_set_async_state_change( player, FALSE );
4796 /* generating debug info before returning error */
4797 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-start" );
4804 static void __mmplayer_do_sound_fadedown(mm_player_t* player, unsigned int time)
4808 return_if_fail(player
4810 && player->pipeline->audiobin
4811 && player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
4813 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", 2, NULL);
4820 static void __mmplayer_undo_sound_fadedown(mm_player_t* player)
4824 return_if_fail(player
4826 && player->pipeline->audiobin
4827 && player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
4829 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", 0, NULL);
4834 static int __gst_stop(mm_player_t* player) // @
4836 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
4837 MMHandleType attrs = 0;
4838 gboolean fadewown = FALSE;
4839 gboolean rewind = FALSE;
4841 int ret = MM_ERROR_NONE;
4845 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4847 debug_log("current state before doing transition");
4848 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4849 MMPLAYER_PRINT_STATE(player);
4851 attrs = MMPLAYER_GET_ATTRS(player);
4854 debug_error("cannot get content attribute\n");
4855 return MM_ERROR_PLAYER_INTERNAL;
4858 mm_attrs_get_int_by_name(attrs,"sound_fadedown", &fadewown);
4860 /* enable fadedown */
4862 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
4864 /* Just set state to PAUESED and the rewind. it's usual player behavior. */
4865 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT ( player );
4866 if ( player->profile.uri_type == MM_PLAYER_URI_TYPE_BUFF || player->profile.uri_type == MM_PLAYER_URI_TYPE_HLS)
4868 ret = __mmplayer_gst_set_state(player,
4869 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout );
4873 ret = __mmplayer_gst_set_state( player,
4874 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout );
4876 if (MMPLAYER_PLAY_SUBTITLE(player))
4877 ret = __mmplayer_gst_set_state( player,
4878 player->pipeline->subtitlebin[MMPLAYER_SUB_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout );
4880 if ( !MMPLAYER_IS_STREAMING(player))
4884 /* disable fadeout */
4886 __mmplayer_undo_sound_fadedown(player);
4889 /* return if set_state has failed */
4890 if ( ret != MM_ERROR_NONE )
4892 debug_error("failed to set state.\n");
4894 /* dump state of all element. don't care it success or not */
4895 __mmplayer_dump_pipeline_state( player );
4903 if ( ! __gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
4904 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
4905 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE) )
4907 debug_warning("failed to rewind\n");
4908 ret = MM_ERROR_PLAYER_SEEK;
4913 player->sent_bos = FALSE;
4915 /* wait for seek to complete */
4916 change_ret = gst_element_get_state (player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
4917 if (MMPLAYER_PLAY_SUBTITLE(player))
4918 change_ret = gst_element_get_state (player->pipeline->subtitlebin[MMPLAYER_SUB_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
4920 if ( change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL )
4922 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_READY );
4926 debug_error("fail to stop player.\n");
4927 ret = MM_ERROR_PLAYER_INTERNAL;
4930 /* generate dot file if enabled */
4931 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-stop" );
4938 int __gst_pause(mm_player_t* player, gboolean async) // @
4940 int ret = MM_ERROR_NONE;
4944 return_val_if_fail(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4946 debug_log("current state before doing transition");
4947 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
4948 MMPLAYER_PRINT_STATE(player);
4950 /* set pipeline status to PAUSED */
4951 ret = __mmplayer_gst_set_state(player,
4952 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
4954 if (MMPLAYER_PLAY_SUBTITLE(player))
4955 ret = __mmplayer_gst_set_state(player,
4956 player->pipeline->subtitlebin[MMPLAYER_SUB_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
4958 if ( ret != MM_ERROR_NONE )
4960 debug_error("failed to set state to PAUSED\n");
4962 /* dump state of all element */
4963 __mmplayer_dump_pipeline_state( player );
4969 if ( async == FALSE )
4971 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_PAUSED );
4975 /* FIXIT : analyze so called "async problem" */
4977 __gst_set_async_state_change( player, TRUE);
4979 /* generate dot file before returning error */
4980 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-pause" );
4987 int __gst_resume(mm_player_t* player, gboolean async) // @
4989 int ret = MM_ERROR_NONE;
4994 return_val_if_fail(player && player->pipeline,
4995 MM_ERROR_PLAYER_NOT_INITIALIZED);
4997 debug_log("current state before doing transition");
4998 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
4999 MMPLAYER_PRINT_STATE(player);
5001 /* generate dot file before returning error */
5002 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-resume" );
5004 __mmplayer_set_antishock( player , FALSE );
5007 debug_log("do async state transition to PLAYING.\n");
5009 /* set pipeline state to PLAYING */
5010 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5011 ret = __mmplayer_gst_set_state(player,
5012 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout );
5014 if (MMPLAYER_PLAY_SUBTITLE(player))
5015 ret = __mmplayer_gst_set_state(player,
5016 player->pipeline->subtitlebin[MMPLAYER_SUB_PIPE].gst, GST_STATE_PLAYING, async, timeout );
5018 if (ret != MM_ERROR_NONE)
5020 debug_error("failed to set state to PLAYING\n");
5022 /* dump state of all element */
5023 __mmplayer_dump_pipeline_state( player );
5031 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_PLAYING );
5035 /* FIXIT : analyze so called "async problem" */
5037 __gst_set_async_state_change( player, FALSE );
5039 /* generate dot file before returning error */
5040 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-resume" );
5048 __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called) // @
5050 GstFormat fmt = GST_FORMAT_TIME;
5051 unsigned long dur_msec = 0;
5052 gint64 dur_nsec = 0;
5053 gint64 pos_nsec = 0;
5054 gboolean ret = TRUE;
5057 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
5058 return_val_if_fail ( !MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP );
5060 if ( MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
5061 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED )
5064 /* check duration */
5065 /* NOTE : duration cannot be zero except live streaming.
5066 * Since some element could have some timing problemn with quering duration, try again.
5068 if ( !player->duration )
5070 if ( !gst_element_query_duration( player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &fmt, &dur_nsec ))
5074 player->duration = dur_nsec;
5077 if ( player->duration )
5079 dur_msec = GST_TIME_AS_MSECONDS(player->duration);
5083 debug_error("could not get the duration. fail to seek.\n");
5087 debug_log("playback rate: %f\n", player->playback_rate);
5092 case MM_PLAYER_POS_FORMAT_TIME:
5094 /* check position is valid or not */
5095 if ( position > dur_msec )
5098 debug_log("seeking to (%lu) msec, duration is %d msec\n", position, dur_msec);
5100 if (player->doing_seek)
5102 debug_log("not completed seek");
5103 return MM_ERROR_PLAYER_DOING_SEEK;
5106 if ( !internal_called)
5107 player->doing_seek = TRUE;
5109 pos_nsec = position * G_GINT64_CONSTANT(1000000);
5110 ret = __gst_seek ( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
5111 GST_FORMAT_TIME, ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ),
5112 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE );
5115 debug_error("failed to set position. dur[%lu] pos[%lu] pos_msec[%llu]\n", dur_msec, position, pos_nsec);
5121 case MM_PLAYER_POS_FORMAT_PERCENT:
5123 if ( position < 0 && position > 100 )
5126 debug_log("seeking to (%lu)%% \n", position);
5128 if (player->doing_seek)
5130 debug_log("not completed seek");
5131 return MM_ERROR_PLAYER_DOING_SEEK;
5134 if ( !internal_called)
5135 player->doing_seek = TRUE;
5137 /* FIXIT : why don't we use 'GST_FORMAT_PERCENT' */
5138 pos_nsec = (gint64) ( ( position * player->duration ) / 100 );
5139 ret = __gst_seek ( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
5140 GST_FORMAT_TIME, ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ),
5141 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE );
5144 debug_error("failed to set position. dur[%lud] pos[%lud] pos_msec[%llud]\n", dur_msec, position, pos_nsec);
5155 /* NOTE : store last seeking point to overcome some bad operation
5156 * ( returning zero when getting current position ) of some elements
5158 player->last_position = pos_nsec;
5160 /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
5161 if ( player->playback_rate > 1.0 )
5162 _mmplayer_set_playspeed ( (MMHandleType)player, player->playback_rate );
5165 return MM_ERROR_NONE;
5168 player->pending_seek.is_pending = TRUE;
5169 player->pending_seek.format = format;
5170 player->pending_seek.pos = position;
5172 debug_warning("player current-state : %s, pending-state : %s, just preserve pending position(%lu).\n",
5173 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)), MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)), player->pending_seek.pos);
5175 return MM_ERROR_NONE;
5178 debug_error("invalid arguments, position : %ld dur : %ld format : %d \n", position, dur_msec, format);
5179 return MM_ERROR_INVALID_ARGUMENT;
5182 player->doing_seek = FALSE;
5183 return MM_ERROR_PLAYER_SEEK;
5186 #define TRICKPLAY_OFFSET GST_MSECOND
5189 __gst_get_position(mm_player_t* player, int format, unsigned long* position) // @
5191 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
5192 GstFormat fmt = GST_FORMAT_TIME;
5193 signed long long pos_msec = 0;
5194 gboolean ret = TRUE;
5196 return_val_if_fail( player && position && player->pipeline && player->pipeline->mainbin,
5197 MM_ERROR_PLAYER_NOT_INITIALIZED );
5199 current_state = MMPLAYER_CURRENT_STATE(player);
5201 /* NOTE : query position except paused state to overcome some bad operation
5202 * please refer to below comments in details
5204 if ( current_state != MM_PLAYER_STATE_PAUSED )
5206 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &fmt, &pos_msec);
5209 /* NOTE : get last point to overcome some bad operation of some elements
5210 * ( returning zero when getting current position in paused state
5211 * and when failed to get postion during seeking
5213 if ( ( current_state == MM_PLAYER_STATE_PAUSED )
5215 //|| ( player->last_position != 0 && pos_msec == 0 ) )
5217 debug_warning ("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS (pos_msec), ret, current_state);
5219 if(player->playback_rate < 0.0)
5220 pos_msec = player->last_position - TRICKPLAY_OFFSET;
5222 pos_msec = player->last_position;
5225 pos_msec = player->last_position;
5227 player->last_position = pos_msec;
5229 debug_warning("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_msec));
5234 player->last_position = pos_msec;
5238 case MM_PLAYER_POS_FORMAT_TIME:
5239 *position = GST_TIME_AS_MSECONDS(pos_msec);
5242 case MM_PLAYER_POS_FORMAT_PERCENT:
5247 dur = player->duration / GST_SECOND;
5250 debug_log ("duration is [%d], so returning position 0\n",dur);
5255 pos = pos_msec / GST_SECOND;
5256 *position = pos * 100 / dur;
5261 return MM_ERROR_PLAYER_INTERNAL;
5264 debug_log("current position : %lu\n", *position);
5267 return MM_ERROR_NONE;
5271 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
5273 GstElement *element = NULL;
5274 GstQuery *query = NULL;
5276 return_val_if_fail( player &&
5278 player->pipeline->mainbin,
5279 MM_ERROR_PLAYER_NOT_INITIALIZED );
5281 return_val_if_fail( start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT );
5283 if ( MMPLAYER_IS_HTTP_STREAMING ( player ))
5285 /* Note : In case of http streaming or HLS, the buffering queue [ queue2 ] could handle buffering query. */
5286 element = GST_ELEMENT ( player->pipeline->mainbin[MMPLAYER_M_S_BUFFER].gst );
5288 else if ( MMPLAYER_IS_RTSP_STREAMING ( player ) )
5290 debug_warning ( "it's not supported yet.\n" );
5291 return MM_ERROR_NONE;
5295 debug_warning ( "it's only used for streaming case.\n" );
5296 return MM_ERROR_NONE;
5304 case MM_PLAYER_POS_FORMAT_PERCENT :
5306 query = gst_query_new_buffering ( GST_FORMAT_PERCENT );
5307 if ( gst_element_query ( element, query ) )
5314 gst_query_parse_buffering_percent ( query, &busy, &percent);
5315 gst_query_parse_buffering_range ( query, &format, &start, &stop, NULL );
5317 debug_log ( "buffering start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT "\n", start, stop);
5320 *start_pos = 100 * start / GST_FORMAT_PERCENT_MAX;
5325 *stop_pos = 100 * stop / GST_FORMAT_PERCENT_MAX;
5329 gst_query_unref (query);
5333 case MM_PLAYER_POS_FORMAT_TIME :
5334 debug_warning ( "Time format is not supported yet.\n" );
5341 debug_log("current buffer position : %lu~%lu \n", *start_pos, *stop_pos );
5343 return MM_ERROR_NONE;
5347 __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param) // @
5353 debug_warning("set_message_callback is called with invalid player handle\n");
5354 return MM_ERROR_PLAYER_NOT_INITIALIZED;
5357 player->msg_cb = callback;
5358 player->msg_cb_param = user_param;
5360 debug_log("msg_cb : 0x%x msg_cb_param : 0x%x\n", (guint)callback, (guint)user_param);
5364 return MM_ERROR_NONE;
5367 static gboolean __mmfplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data) // @
5369 gboolean ret = FALSE;
5374 return_val_if_fail ( uri , FALSE);
5375 return_val_if_fail ( data , FALSE);
5376 return_val_if_fail ( ( strlen(uri) <= MM_MAX_URL_LEN ), FALSE );
5378 memset(data, 0, sizeof(MMPlayerParseProfile));
5380 if ((path = strstr(uri, "file://")))
5382 if (util_exist_file_path(path + 7)) {
5383 strncpy(data->uri, path, MM_MAX_URL_LEN-1);
5385 if ( util_is_sdp_file ( path ) )
5387 debug_log("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
5388 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
5392 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
5398 debug_warning("could access %s.\n", path);
5401 else if ((path = strstr(uri, "buff://")))
5403 data->uri_type = MM_PLAYER_URI_TYPE_BUFF;
5406 else if ((path = strstr(uri, "rtsp://")))
5409 strcpy(data->uri, uri);
5410 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
5414 else if ((path = strstr(uri, "http://")))
5417 strcpy(data->uri, uri);
5418 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
5423 else if ((path = strstr(uri, "https://")))
5426 strcpy(data->uri, uri);
5427 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
5432 else if ((path = strstr(uri, "rtspu://")))
5435 strcpy(data->uri, uri);
5436 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
5440 else if ((path = strstr(uri, "rtspr://")))
5442 strcpy(data->uri, path);
5443 char *separater =strstr(path, "*");
5447 char *urgent = separater + strlen("*");
5449 if ((urgent_len = strlen(urgent))) {
5450 data->uri[strlen(path) - urgent_len - strlen("*")] = '\0';
5451 strcpy(data->urgent, urgent);
5452 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
5457 else if ((path = strstr(uri, "mms://")))
5460 strcpy(data->uri, uri);
5461 data->uri_type = MM_PLAYER_URI_TYPE_URL_MMS;
5465 else if ((path = strstr(uri, "mem://")))
5469 char *buffer = NULL;
5470 char *seperator = strchr(path, ',');
5471 char ext[100] = {0,}, size[100] = {0,};
5474 if ((buffer = strstr(path, "ext="))) {
5475 buffer += strlen("ext=");
5477 if (strlen(buffer)) {
5478 strcpy(ext, buffer);
5480 if ((seperator = strchr(ext, ','))
5481 || (seperator = strchr(ext, ' '))
5482 || (seperator = strchr(ext, '\0'))) {
5483 seperator[0] = '\0';
5488 if ((buffer = strstr(path, "size="))) {
5489 buffer += strlen("size=");
5491 if (strlen(buffer) > 0) {
5492 strcpy(size, buffer);
5494 if ((seperator = strchr(size, ','))
5495 || (seperator = strchr(size, ' '))
5496 || (seperator = strchr(size, '\0'))) {
5497 seperator[0] = '\0';
5500 mem_size = atoi(size);
5505 debug_log("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
5506 if ( mem_size && param) {
5508 data->mem_size = mem_size;
5509 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
5516 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
5517 if (util_exist_file_path(uri))
5519 debug_warning("uri has no protocol-prefix. giving 'file://' by default.\n");
5520 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", uri);
5522 if ( util_is_sdp_file( (char*)uri ) )
5524 debug_log("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
5525 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
5529 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
5535 debug_error ("invalid uri, could not play..\n");
5536 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
5540 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE) {
5544 /* dump parse result */
5545 debug_log("profile parsing result ---\n");
5546 debug_log("incomming uri : %s\n", uri);
5547 debug_log("uri : %s\n", data->uri);
5548 debug_log("uri_type : %d\n", data->uri_type);
5549 debug_log("play_mode : %d\n", data->play_mode);
5550 debug_log("mem : 0x%x\n", (guint)data->mem);
5551 debug_log("mem_size : %d\n", data->mem_size);
5552 debug_log("urgent : %s\n", data->urgent);
5553 debug_log("--------------------------\n");
5560 gboolean _asm_postmsg(gpointer *data)
5562 mm_player_t* player = (mm_player_t*)data;
5563 MMMessageParamType msg = {0, };
5567 return_val_if_fail ( player, FALSE );
5569 msg.union_type = MM_MSG_UNION_CODE;
5570 msg.code = player->sm.event_src;
5572 MMPLAYER_POST_MSG( player, MM_MESSAGE_READY_TO_RESUME, &msg);
5576 gboolean _asm_lazy_pause(gpointer *data)
5578 mm_player_t* player = (mm_player_t*)data;
5579 int ret = MM_ERROR_NONE;
5583 return_val_if_fail ( player, FALSE );
5585 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING)
5587 debug_log ("Ready to proceed lazy pause\n");
5588 ret = _mmplayer_pause((MMHandleType)player);
5589 if(MM_ERROR_NONE != ret)
5591 debug_error("MMPlayer pause failed in ASM callback lazy pause\n");
5596 debug_log ("Invalid state to proceed lazy pause\n");
5600 if (player->pipeline && player->pipeline->audiobin)
5601 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", 0, NULL);
5603 player->sm.by_asm_cb = 0; //should be reset here
5610 __mmplayer_asm_callback(int handle, ASM_event_sources_t event_src, ASM_sound_commands_t command, unsigned int sound_status, void* cb_data)
5612 mm_player_t* player = (mm_player_t*) cb_data;
5613 ASM_cb_result_t cb_res = ASM_CB_RES_IGNORE;
5614 int result = MM_ERROR_NONE;
5615 gboolean lazy_pause = FALSE;
5619 return_val_if_fail ( player && player->pipeline, ASM_CB_RES_IGNORE );
5620 return_val_if_fail ( player->attrs, MM_ERROR_PLAYER_INTERNAL );
5622 if (player->is_sound_extraction)
5624 debug_log("sound extraction is working...so, asm command is ignored.\n");
5628 player->sm.by_asm_cb = 1; // it should be enabled for player state transition with called application command
5629 player->sm.event_src = event_src;
5631 if(event_src == ASM_EVENT_SOURCE_OTHER_PLAYER_APP)
5633 player->sm.event_src = ASM_EVENT_SOURCE_OTHER_APP;
5635 else if(event_src == ASM_EVENT_SOURCE_EARJACK_UNPLUG )
5637 int stop_by_asm = 0;
5639 mm_attrs_get_int_by_name(player->attrs, "sound_stop_when_unplugged", &stop_by_asm);
5643 else if (event_src == ASM_EVENT_SOURCE_RESOURCE_CONFLICT)
5645 /* can use video overlay simultaneously */
5646 /* video resource conflict */
5647 if(player->pipeline->videobin)
5649 if (PLAYER_INI()->multiple_codec_supported)
5651 debug_log("video conflict but, can support to use video overlay simultaneously");
5652 result = _mmplayer_pause((MMHandleType)player);
5653 cb_res = ASM_CB_RES_PAUSE;
5657 debug_log("video conflict, can't support for multiple codec instance");
5658 result = _mmplayer_unrealize((MMHandleType)player);
5659 cb_res = ASM_CB_RES_STOP;
5667 case ASM_COMMAND_PLAY:
5668 case ASM_COMMAND_STOP:
5669 debug_warning ("Got unexpected asm command (%d)", command);
5672 case ASM_COMMAND_PAUSE:
5674 debug_log("Got msg from asm to Pause");
5676 if(event_src == ASM_EVENT_SOURCE_CALL_START
5677 || event_src == ASM_EVENT_SOURCE_ALARM_START
5678 || event_src == ASM_EVENT_SOURCE_OTHER_APP)
5680 //hold 0.7 second to excute "fadedown mute" effect
5681 debug_log ("do fade down->pause->undo fade down");
5683 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
5685 result = _mmplayer_pause((MMHandleType)player);
5686 if (result != MM_ERROR_NONE)
5688 debug_warning("fail to set Pause state by asm");
5689 cb_res = ASM_CB_RES_IGNORE;
5692 __mmplayer_undo_sound_fadedown(player);
5694 else if(event_src == ASM_EVENT_SOURCE_OTHER_PLAYER_APP)
5696 lazy_pause = TRUE; // return as soon as possible, for fast start of other app
5698 if ( player->pipeline->audiobin && player->pipeline->audiobin[MMPLAYER_A_SINK].gst )
5699 g_object_set( player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "mute", 2, NULL);
5701 player->lazy_pause_event_id = g_timeout_add(LAZY_PAUSE_TIMEOUT_MSEC, (GSourceFunc)_asm_lazy_pause, (gpointer)player);
5702 debug_log ("set lazy pause timer (id=[%d], timeout=[%d ms])", player->lazy_pause_event_id, LAZY_PAUSE_TIMEOUT_MSEC);
5707 debug_log ("immediate pause");
5708 result = _mmplayer_pause((MMHandleType)player);
5710 cb_res = ASM_CB_RES_PAUSE;
5714 case ASM_COMMAND_RESUME:
5716 debug_log("Got msg from asm to Resume. So, application can resume. code (%d) \n", event_src);
5717 player->sm.by_asm_cb = 0;
5718 //ASM server is single thread daemon. So use g_idle_add() to post resume msg
5719 g_idle_add((GSourceFunc)_asm_postmsg, (gpointer)player);
5720 cb_res = ASM_CB_RES_IGNORE;
5729 player->sm.by_asm_cb = 0;
5737 _mmplayer_create_player(MMHandleType handle) // @
5739 mm_player_t* player = MM_PLAYER_CAST(handle);
5744 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
5746 MMTA_ACUM_ITEM_BEGIN("[KPI] media player service create->playing", FALSE);
5748 /* initialize player state */
5749 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
5750 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
5751 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
5752 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
5754 /* check current state */
5755 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL ( player, MMPLAYER_COMMAND_CREATE );
5757 /* construct attributes */
5758 player->attrs = _mmplayer_construct_attribute(handle);
5760 if ( !player->attrs )
5762 debug_critical("Failed to construct attributes\n");
5766 /* initialize gstreamer with configured parameter */
5767 if ( ! __mmplayer_gstreamer_init() )
5769 debug_critical("Initializing gstreamer failed\n");
5773 /* initialize factories if not using decodebin */
5774 if ( FALSE == PLAYER_INI()->use_decodebin )
5776 if( player->factories == NULL )
5777 __mmplayer_init_factories(player);
5780 /* create lock. note that g_tread_init() has already called in gst_init() */
5781 player->fsink_lock = g_mutex_new();
5782 if ( ! player->fsink_lock )
5784 debug_critical("Cannot create mutex for command lock\n");
5788 /* create repeat mutex */
5789 player->repeat_thread_mutex = g_mutex_new();
5790 if ( ! player->repeat_thread_mutex )
5792 debug_critical("Cannot create repeat mutex\n");
5796 /* create repeat cond */
5797 player->repeat_thread_cond = g_cond_new();
5798 if ( ! player->repeat_thread_cond )
5800 debug_critical("Cannot create repeat cond\n");
5804 /* create repeat thread */
5805 player->repeat_thread =
5806 g_thread_create (__mmplayer_repeat_thread, (gpointer)player, TRUE, NULL);
5807 if ( ! player->repeat_thread )
5812 if ( MM_ERROR_NONE != _mmplayer_initialize_video_capture(player))
5814 debug_error("failed to initialize video capture\n");
5818 /* register to asm */
5819 if ( MM_ERROR_NONE != _mmplayer_asm_register(&player->sm, (ASM_sound_cb_t)__mmplayer_asm_callback, (void*)player) )
5821 /* NOTE : we are dealing it as an error since we cannot expect it's behavior */
5822 debug_error("failed to register asm server\n");
5823 return MM_ERROR_POLICY_INTERNAL;
5826 if (MMPLAYER_IS_HTTP_PD(player))
5828 player->pd_downloader = NULL;
5829 player->pd_file_save_path = NULL;
5832 /* give default value of sound effect setting */
5833 player->bypass_sound_effect = TRUE;
5834 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
5835 player->playback_rate = DEFAULT_PLAYBACK_RATE;
5836 player->no_more_pad = TRUE;
5838 /* set player state to null */
5839 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = PLAYER_INI()->localplayback_state_change_timeout;
5840 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_NULL );
5843 return MM_ERROR_NONE;
5847 if ( player->fsink_lock )
5848 g_mutex_free( player->fsink_lock );
5849 player->fsink_lock = NULL;
5852 if ( player->repeat_thread_cond &&
5853 player->repeat_thread_mutex &&
5854 player->repeat_thread )
5856 player->repeat_thread_exit = TRUE;
5857 g_cond_signal( player->repeat_thread_cond );
5859 g_thread_join( player->repeat_thread );
5860 player->repeat_thread = NULL;
5862 g_mutex_free ( player->repeat_thread_mutex );
5863 player->repeat_thread_mutex = NULL;
5865 g_cond_free ( player->repeat_thread_cond );
5866 player->repeat_thread_cond = NULL;
5868 /* clear repeat thread mutex/cond if still alive
5869 * this can happen if only thread creating has failed
5871 if ( player->repeat_thread_mutex )
5872 g_mutex_free ( player->repeat_thread_mutex );
5874 if ( player->repeat_thread_cond )
5875 g_cond_free ( player->repeat_thread_cond );
5877 /* release attributes */
5878 _mmplayer_deconstruct_attribute(handle);
5880 return MM_ERROR_PLAYER_INTERNAL;
5884 __mmplayer_gstreamer_init(void) // @
5886 static gboolean initialized = FALSE;
5887 static const int max_argc = 50;
5889 gchar** argv = NULL;
5897 debug_log("gstreamer already initialized.\n");
5902 argc = malloc( sizeof(int) );
5903 argv = malloc( sizeof(gchar*) * max_argc );
5905 if ( !argc || !argv )
5908 memset( argv, 0, sizeof(gchar*) * max_argc );
5912 argv[0] = g_strdup( "mmplayer" );
5915 for ( i = 0; i < 5; i++ ) /* FIXIT : num of param is now fixed to 5. make it dynamic */
5917 if ( strlen( PLAYER_INI()->gst_param[i] ) > 0 )
5919 argv[*argc] = g_strdup( PLAYER_INI()->gst_param[i] );
5924 /* we would not do fork for scanning plugins */
5925 argv[*argc] = g_strdup("--gst-disable-registry-fork");
5928 /* check disable registry scan */
5929 if ( PLAYER_INI()->skip_rescan )
5931 argv[*argc] = g_strdup("--gst-disable-registry-update");
5935 /* check disable segtrap */
5936 if ( PLAYER_INI()->disable_segtrap )
5938 argv[*argc] = g_strdup("--gst-disable-segtrap");
5942 debug_log("initializing gstreamer with following parameter\n");
5943 debug_log("argc : %d\n", *argc);
5945 for ( i = 0; i < *argc; i++ )
5947 debug_log("argv[%d] : %s\n", i, argv[i]);
5951 /* initializing gstreamer */
5952 __ta__("gst_init time",
5954 if ( ! gst_init_check (argc, &argv, &err))
5956 debug_error("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
5967 for ( i = 0; i < *argc; i++ )
5969 MMPLAYER_FREEIF( argv[i] );
5972 MMPLAYER_FREEIF( argv );
5973 MMPLAYER_FREEIF( argc );
5984 MMPLAYER_FREEIF( argv );
5985 MMPLAYER_FREEIF( argc );
5991 __mmplayer_destroy_streaming_ext(mm_player_t* player)
5993 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
5995 if (player->pd_downloader)
5996 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
5998 if (MMPLAYER_IS_HTTP_PD(player))
5999 _mmplayer_destroy_pd_downloader((MMHandleType)player);
6001 if (MMPLAYER_IS_STREAMING(player))
6003 if (player->streamer)
6005 __mm_player_streaming_deinitialize (player->streamer);
6006 __mm_player_streaming_destroy(player->streamer);
6007 player->streamer = NULL;
6013 _mmplayer_destroy(MMHandleType handle) // @
6015 mm_player_t* player = MM_PLAYER_CAST(handle);
6019 /* check player handle */
6020 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6022 /* destroy can called at anytime */
6023 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL ( player, MMPLAYER_COMMAND_DESTROY );
6025 __mmplayer_destroy_streaming_ext(player);
6027 /* release repeat thread */
6028 if ( player->repeat_thread_cond &&
6029 player->repeat_thread_mutex &&
6030 player->repeat_thread )
6032 player->repeat_thread_exit = TRUE;
6033 g_cond_signal( player->repeat_thread_cond );
6035 debug_log("waitting for repeat thread exit\n");
6036 g_thread_join ( player->repeat_thread );
6037 g_mutex_free ( player->repeat_thread_mutex );
6038 g_cond_free ( player->repeat_thread_cond );
6039 debug_log("repeat thread released\n");
6042 if (MM_ERROR_NONE != _mmplayer_release_video_capture(player))
6044 debug_error("failed to release video capture\n");
6045 return MM_ERROR_PLAYER_INTERNAL;
6049 if ( MM_ERROR_NONE != _mmplayer_asm_deregister(&player->sm) )
6051 debug_error("failed to deregister asm server\n");
6052 return MM_ERROR_PLAYER_INTERNAL;
6055 /* release pipeline */
6056 if ( MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline( player ) )
6058 debug_error("failed to destory pipeline\n");
6059 return MM_ERROR_PLAYER_INTERNAL;
6062 /* release attributes */
6063 _mmplayer_deconstruct_attribute( handle );
6065 /* release factories */
6066 __mmplayer_release_factories( player );
6069 if ( player->fsink_lock )
6070 g_mutex_free( player->fsink_lock );
6072 if ( player->msg_cb_lock )
6073 g_mutex_free( player->msg_cb_lock );
6075 if (player->lazy_pause_event_id)
6077 g_source_remove (player->lazy_pause_event_id);
6078 player->lazy_pause_event_id = 0;
6083 return MM_ERROR_NONE;
6087 __mmplayer_realize_streaming_ext(mm_player_t* player)
6089 int ret = MM_ERROR_NONE;
6092 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6094 if (MMPLAYER_IS_HTTP_PD(player))
6096 gboolean bret = FALSE;
6098 player->pd_downloader = _mmplayer_create_pd_downloader();
6099 if ( !player->pd_downloader )
6101 debug_error ("Unable to create PD Downloader...");
6102 ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
6105 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
6109 debug_error ("Unable to create PD Downloader...");
6110 ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
6119 _mmplayer_realize(MMHandleType hplayer) // @
6121 mm_player_t* player = (mm_player_t*)hplayer;
6124 int application_pid = -1;
6125 gboolean update_registry = FALSE;
6126 MMHandleType attrs = 0;
6127 int ret = MM_ERROR_NONE;
6131 /* check player handle */
6132 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED )
6134 /* check current state */
6135 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_REALIZE );
6137 attrs = MMPLAYER_GET_ATTRS(player);
6140 debug_error("fail to get attributes.\n");
6141 return MM_ERROR_PLAYER_INTERNAL;
6144 mm_attrs_get_int_by_name(attrs, "sound_application_pid", &application_pid );
6145 player->sm.pid = application_pid;
6147 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
6148 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
6150 if (! __mmfplayer_parse_profile((const char*)uri, param, &player->profile) )
6152 debug_error("failed to parse profile\n");
6153 return MM_ERROR_PLAYER_INVALID_URI;
6156 /* FIXIT : we can use thouse in player->profile directly */
6157 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM)
6159 player->mem_buf.buf = (char *)player->profile.mem;
6160 player->mem_buf.len = player->profile.mem_size;
6161 player->mem_buf.offset = 0;
6164 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS)
6166 debug_warning("mms protocol is not supported format.\n");
6167 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
6170 if (MMPLAYER_IS_STREAMING(player))
6171 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = PLAYER_INI()->live_state_change_timeout;
6173 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = PLAYER_INI()->localplayback_state_change_timeout;
6175 player->videodec_linked = 0;
6176 player->videosink_linked = 0;
6177 player->audiodec_linked = 0;
6178 player->audiosink_linked = 0;
6179 player->textsink_linked = 0;
6181 /* set the subtitle ON default */
6182 player->is_subtitle_off = FALSE;
6184 /* we need to update content attrs only the content has changed */
6185 player->need_update_content_attrs = TRUE;
6186 player->need_update_content_dur = FALSE;
6188 /* registry should be updated for downloadable codec */
6189 mm_attrs_get_int_by_name(attrs, "profile_update_registry", &update_registry);
6191 if ( update_registry )
6193 debug_log("updating registry...\n");
6194 gst_update_registry();
6196 /* then we have to rebuild factories */
6197 __mmplayer_release_factories( player );
6198 __mmplayer_init_factories(player);
6201 /* realize pipeline */
6202 ret = __gst_realize( player );
6203 if ( ret != MM_ERROR_NONE )
6205 debug_error("fail to realize the player.\n");
6209 __mmplayer_realize_streaming_ext(player);
6218 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
6221 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6223 /* destroy can called at anytime */
6224 if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player))
6226 _mmplayer_unrealize_pd_downloader ((MMHandleType)player);
6227 player->pd_downloader = NULL;
6231 return MM_ERROR_NONE;
6235 _mmplayer_unrealize(MMHandleType hplayer) // @
6237 mm_player_t* player = (mm_player_t*)hplayer;
6238 int ret = MM_ERROR_NONE;
6242 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED )
6244 /* check current state */
6245 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_UNREALIZE );
6247 __mmplayer_unrealize_streaming_ext(player);
6249 /* unrealize pipeline */
6250 ret = __gst_unrealize( player );
6252 /* set player state if success */
6253 if ( MM_ERROR_NONE == ret )
6255 ret = _mmplayer_asm_set_state(hplayer, ASM_STATE_STOP);
6258 debug_error("failed to set asm state to STOP\n");
6269 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param) // @
6271 mm_player_t* player = (mm_player_t*)hplayer;
6273 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6275 return __gst_set_message_callback(player, callback, user_param);
6279 _mmplayer_get_state(MMHandleType hplayer, int* state) // @
6281 mm_player_t *player = (mm_player_t*)hplayer;
6283 return_val_if_fail(state, MM_ERROR_INVALID_ARGUMENT);
6285 *state = MMPLAYER_CURRENT_STATE(player);
6287 return MM_ERROR_NONE;
6292 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume) // @
6294 mm_player_t* player = (mm_player_t*) hplayer;
6295 GstElement* vol_element = NULL;
6300 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6302 debug_log("volume [L]=%f:[R]=%f\n",
6303 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
6305 /* invalid factor range or not */
6306 for ( i = 0; i < MM_VOLUME_CHANNEL_NUM; i++ )
6308 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
6309 debug_error("Invalid factor! (valid factor:0~1.0)\n");
6310 return MM_ERROR_INVALID_ARGUMENT;
6314 /* Save volume to handle. Currently the first array element will be saved. */
6315 player->sound.volume = volume.level[0];
6317 /* check pipeline handle */
6318 if ( ! player->pipeline || ! player->pipeline->audiobin )
6320 debug_log("audiobin is not created yet\n");
6321 debug_log("but, current stored volume will be set when it's created.\n");
6323 /* NOTE : stored volume will be used in create_audiobin
6324 * returning MM_ERROR_NONE here makes application to able to
6325 * set volume at anytime.
6327 return MM_ERROR_NONE;
6330 /* setting volume to volume element */
6331 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
6335 debug_log("volume is set [%f]\n", player->sound.volume);
6336 g_object_set(vol_element, "volume", player->sound.volume, NULL);
6341 return MM_ERROR_NONE;
6346 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
6348 mm_player_t* player = (mm_player_t*) hplayer;
6353 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6354 return_val_if_fail( volume, MM_ERROR_INVALID_ARGUMENT );
6356 /* returning stored volume */
6357 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
6358 volume->level[i] = player->sound.volume;
6362 return MM_ERROR_NONE;
6368 _mmplayer_set_mute(MMHandleType hplayer, int mute) // @
6370 mm_player_t* player = (mm_player_t*) hplayer;
6371 GstElement* vol_element = NULL;
6375 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6377 debug_log("mute : %d\n", mute);
6379 /* mute value shoud 0 or 1 */
6380 if ( mute != 0 && mute != 1 )
6382 debug_error("bad mute value\n");
6384 /* FIXIT : definitly, we need _BAD_PARAM error code */
6385 return MM_ERROR_INVALID_ARGUMENT;
6389 /* just hold mute value if pipeline is not ready */
6390 if ( !player->pipeline || !player->pipeline->audiobin )
6392 debug_log("pipeline is not ready. holding mute value\n");
6393 player->sound.mute = mute;
6394 return MM_ERROR_NONE;
6398 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
6400 /* NOTE : volume will only created when the bt is enabled */
6403 g_object_set(vol_element, "mute", mute, NULL);
6407 debug_log("volume elemnet is not created. using volume in audiosink\n");
6410 player->sound.mute = mute;
6414 return MM_ERROR_NONE;
6418 _mmplayer_get_mute(MMHandleType hplayer, int* pmute) // @
6420 mm_player_t* player = (mm_player_t*) hplayer;
6421 GstElement* vol_element = NULL;
6425 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6426 return_val_if_fail ( pmute, MM_ERROR_INVALID_ARGUMENT );
6428 /* just hold mute value if pipeline is not ready */
6429 if ( !player->pipeline || !player->pipeline->audiobin )
6431 debug_log("pipeline is not ready. returning stored value\n");
6432 *pmute = player->sound.mute;
6433 return MM_ERROR_NONE;
6437 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
6441 g_object_get(vol_element, "mute", pmute, NULL);
6442 debug_log("mute=%d\n\n", *pmute);
6446 *pmute = player->sound.mute;
6451 return MM_ERROR_NONE;
6455 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param) // @
6457 mm_player_t* player = (mm_player_t*) hplayer;
6461 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6462 return_val_if_fail ( callback, MM_ERROR_INVALID_ARGUMENT );
6464 player->video_stream_cb = callback;
6465 player->video_stream_cb_user_param = user_param;
6466 player->use_video_stream = TRUE;
6467 debug_log("Stream cb Handle value is %p : %p\n", player, player->video_stream_cb);
6471 return MM_ERROR_NONE;
6475 _mmplayer_set_audiostream_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param) // @
6477 mm_player_t* player = (mm_player_t*) hplayer;
6481 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6482 return_val_if_fail(callback, MM_ERROR_INVALID_ARGUMENT);
6484 player->audio_stream_cb = callback;
6485 player->audio_stream_cb_user_param = user_param;
6486 debug_log("Audio Stream cb Handle value is %p : %p\n", player, player->audio_stream_cb);
6490 return MM_ERROR_NONE;
6494 _mmplayer_set_audiobuffer_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param) // @
6496 mm_player_t* player = (mm_player_t*) hplayer;
6500 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6501 return_val_if_fail(callback, MM_ERROR_INVALID_ARGUMENT);
6503 player->audio_buffer_cb = callback;
6504 player->audio_buffer_cb_user_param = user_param;
6505 debug_log("Audio Stream cb Handle value is %p : %p\n", player, player->audio_buffer_cb);
6509 return MM_ERROR_NONE;
6513 _mmplayer_set_buffer_need_data_cb(MMHandleType hplayer, mm_player_buffer_need_data_callback callback, void *user_param) // @
6515 mm_player_t* player = (mm_player_t*) hplayer;
6519 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
6520 return_val_if_fail(callback, MM_ERROR_INVALID_ARGUMENT);
6522 player->need_data_cb = callback;
6523 player->buffer_cb_user_param = user_param;
6525 debug_log("buffer need dataHandle value is %p : %p\n", player, player->need_data_cb);
6529 return MM_ERROR_NONE;
6533 _mmplayer_set_buffer_enough_data_cb(MMHandleType hplayer, mm_player_buffer_enough_data_callback callback, void *user_param) // @
6535 mm_player_t* player = (mm_player_t*) hplayer;
6539 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
6540 return_val_if_fail(callback, MM_ERROR_INVALID_ARGUMENT);
6542 player->enough_data_cb = callback;
6543 player->buffer_cb_user_param = user_param;
6545 debug_log("buffer enough data cb Handle value is %p : %p\n", player, player->enough_data_cb);
6549 return MM_ERROR_NONE;
6553 _mmplayer_set_buffer_seek_data_cb(MMHandleType hplayer, mm_player_buffer_seek_data_callback callback, void *user_param) // @
6555 mm_player_t* player = (mm_player_t*) hplayer;
6559 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
6560 return_val_if_fail(callback, MM_ERROR_INVALID_ARGUMENT);
6562 player->seek_data_cb = callback;
6563 player->buffer_cb_user_param = user_param;
6565 debug_log("buffer seek data cb Handle value is %p : %p\n", player, player->seek_data_cb);
6569 return MM_ERROR_NONE;
6572 int __mmplayer_start_streaming_ext(mm_player_t *player)
6574 gint ret = MM_ERROR_NONE;
6577 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6579 if (MMPLAYER_IS_HTTP_PD(player))
6581 if ( !player->pd_downloader )
6583 ret = __mmplayer_realize_streaming_ext(player);
6585 if ( ret != MM_ERROR_NONE)
6587 debug_error ("failed to realize streaming ext\n");
6592 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI)
6594 ret = _mmplayer_start_pd_downloader ((MMHandleType)player);
6597 debug_error ("ERROR while starting PD...\n");
6598 return MM_ERROR_PLAYER_NOT_INITIALIZED;
6600 ret = MM_ERROR_NONE;
6609 _mmplayer_start(MMHandleType hplayer) // @
6611 mm_player_t* player = (mm_player_t*) hplayer;
6612 gint ret = MM_ERROR_NONE;
6616 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6618 /* check current state */
6619 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_START );
6621 ret = _mmplayer_asm_set_state(hplayer, ASM_STATE_PLAYING);
6622 if ( ret != MM_ERROR_NONE )
6624 debug_error("failed to set asm state to PLAYING\n");
6628 /* NOTE : we should check and create pipeline again if not created as we destroy
6629 * whole pipeline when stopping in streamming playback
6631 if ( ! player->pipeline )
6633 ret = __gst_realize( player );
6634 if ( MM_ERROR_NONE != ret )
6636 debug_error("failed to realize before starting. only in streamming\n");
6641 ret = __mmplayer_start_streaming_ext(player);
6642 if ( ret != MM_ERROR_NONE )
6644 debug_error("failed to start streaming ext \n");
6647 /* start pipeline */
6648 ret = __gst_start( player );
6649 if ( ret != MM_ERROR_NONE )
6651 debug_error("failed to start player.\n");
6659 /* NOTE: post "not supported codec message" to application
6660 * when one codec is not found during AUTOPLUGGING in MSL.
6661 * So, it's separated with error of __mmplayer_gst_callback().
6662 * And, if any codec is not found, don't send message here.
6663 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
6666 __mmplayer_post_missed_plugin(mm_player_t* player)
6668 MMMessageParamType msg_param;
6669 memset (&msg_param, 0, sizeof(MMMessageParamType));
6670 gboolean post_msg_direct = FALSE;
6674 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6676 debug_log("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
6677 player->not_supported_codec, player->can_support_codec);
6679 if( player->not_found_demuxer )
6681 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
6682 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
6684 MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param );
6685 MMPLAYER_FREEIF(msg_param.data);
6687 return MM_ERROR_NONE;
6690 if (player->not_supported_codec)
6692 if ( player->can_support_codec ) // There is one codec to play
6694 post_msg_direct = TRUE;
6698 if ( player->pipeline->audiobin ) // Some content has only PCM data in container.
6699 post_msg_direct = TRUE;
6702 if ( post_msg_direct )
6704 MMMessageParamType msg_param;
6705 memset (&msg_param, 0, sizeof(MMMessageParamType));
6707 if ( player->not_supported_codec == MISSING_PLUGIN_AUDIO )
6709 debug_warning("not found AUDIO codec, posting error code to application.\n");
6711 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
6712 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
6714 else if ( player->not_supported_codec == MISSING_PLUGIN_VIDEO )
6716 debug_warning("not found VIDEO codec, posting error code to application.\n");
6718 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
6719 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
6722 MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param );
6724 MMPLAYER_FREEIF(msg_param.data);
6726 return MM_ERROR_NONE;
6728 else // no any supported codec case
6730 debug_warning("not found any codec, posting error code to application.\n");
6732 if ( player->not_supported_codec == MISSING_PLUGIN_AUDIO )
6734 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
6735 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
6739 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
6740 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
6743 MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param );
6745 MMPLAYER_FREEIF(msg_param.data);
6751 return MM_ERROR_NONE;
6754 /* NOTE : it should be able to call 'stop' anytime*/
6756 _mmplayer_stop(MMHandleType hplayer) // @
6758 mm_player_t* player = (mm_player_t*)hplayer;
6759 int ret = MM_ERROR_NONE;
6763 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6765 /* check current state */
6766 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_STOP );
6768 /* NOTE : application should not wait for EOS after calling STOP */
6769 __mmplayer_cancel_delayed_eos( player );
6771 __mmplayer_unrealize_streaming_ext(player);
6774 ret = __gst_stop( player );
6776 if ( ret != MM_ERROR_NONE )
6778 debug_error("failed to stop player.\n");
6787 _mmplayer_pause(MMHandleType hplayer) // @
6789 mm_player_t* player = (mm_player_t*)hplayer;
6790 GstFormat fmt = GST_FORMAT_TIME;
6791 gint64 pos_msec = 0;
6792 gboolean async = FALSE;
6793 gint ret = MM_ERROR_NONE;
6797 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6799 /* check current state */
6800 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_PAUSE );
6802 switch (MMPLAYER_CURRENT_STATE(player))
6804 case MM_PLAYER_STATE_READY:
6806 /* check prepare async or not.
6807 * In the case of streaming playback, it's recommned to avoid blocking wait.
6809 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
6810 debug_log("prepare mode : %s", (async ? "async" : "sync"));
6812 if (__mmplayer_start_streaming_ext(player) != MM_ERROR_NONE)
6813 return MM_ERROR_PLAYER_INTERNAL;
6817 case MM_PLAYER_STATE_PLAYING:
6819 /* NOTE : store current point to overcome some bad operation
6820 * ( returning zero when getting current position in paused state) of some
6823 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &fmt, &pos_msec);
6825 debug_warning("getting current position failed in paused\n");
6827 player->last_position = pos_msec;
6832 /* pause pipeline */
6833 ret = __gst_pause( player, async );
6835 if ( ret != MM_ERROR_NONE )
6837 debug_error("failed to pause player.\n");
6846 _mmplayer_resume(MMHandleType hplayer)
6848 mm_player_t* player = (mm_player_t*)hplayer;
6849 int ret = MM_ERROR_NONE;
6853 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6855 ret = _mmplayer_asm_set_state(hplayer, ASM_STATE_PLAYING);
6858 debug_error("failed to set asm state to PLAYING\n");
6862 /* check current state */
6863 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_RESUME );
6865 /* resume pipeline */
6866 ret = __gst_resume( player, FALSE );
6868 if ( ret != MM_ERROR_NONE )
6870 debug_error("failed to resume player.\n");
6880 __mmplayer_set_play_count(mm_player_t* player, gint count)
6882 MMHandleType attrs = 0;
6886 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6888 attrs = MMPLAYER_GET_ATTRS(player);
6891 debug_error("fail to get attributes.\n");
6892 return MM_ERROR_PLAYER_INTERNAL;
6895 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
6896 if ( mmf_attrs_commit ( attrs ) ) /* return -1 if error */
6897 debug_error("failed to commit\n");
6901 return MM_ERROR_NONE;
6905 _mmplayer_activate_section_repeat(MMHandleType hplayer, unsigned long start, unsigned long end)
6907 mm_player_t* player = (mm_player_t*)hplayer;
6908 gint64 start_pos = 0;
6914 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6915 return_val_if_fail ( end <= GST_TIME_AS_MSECONDS(player->duration), MM_ERROR_INVALID_ARGUMENT );
6917 player->section_repeat = TRUE;
6918 player->section_repeat_start = start;
6919 player->section_repeat_end = end;
6921 start_pos = player->section_repeat_start * G_GINT64_CONSTANT(1000000);
6922 end_pos = player->section_repeat_end * G_GINT64_CONSTANT(1000000);
6924 __mmplayer_set_play_count( player, infinity );
6926 if ( (!__gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
6929 ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ),
6930 GST_SEEK_TYPE_SET, start_pos,
6931 GST_SEEK_TYPE_SET, end_pos)))
6933 debug_error("failed to activate section repeat\n");
6935 return MM_ERROR_PLAYER_SEEK;
6938 debug_log("succeeded to set section repeat from %d to %d\n",
6939 player->section_repeat_start, player->section_repeat_end);
6943 return MM_ERROR_NONE;
6947 __mmplayer_set_pcm_extraction(mm_player_t* player)
6949 guint64 start_nsec = 0;
6950 guint64 end_nsec = 0;
6951 guint64 dur_nsec = 0;
6952 guint64 dur_msec = 0;
6953 GstFormat fmt = GST_FORMAT_TIME;
6954 int required_start = 0;
6955 int required_end = 0;
6960 return_val_if_fail( player, FALSE );
6962 mm_attrs_multiple_get(player->attrs,
6964 "pcm_extraction_start_msec", &required_start,
6965 "pcm_extraction_end_msec", &required_end,
6968 debug_log("pcm extraction required position is from [%d] to [%d] (msec)\n", required_start, required_end);
6970 if (required_start == 0 && required_end == 0)
6972 debug_log("extracting entire stream");
6973 return MM_ERROR_NONE;
6975 else if (required_start < 0 || required_start > required_end || required_end < 0 )
6977 debug_log("invalid range for pcm extraction");
6978 return MM_ERROR_INVALID_ARGUMENT;
6982 ret = gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &fmt, &dur_nsec);
6985 debug_error("failed to get duration");
6986 return MM_ERROR_PLAYER_INTERNAL;
6988 dur_msec = GST_TIME_AS_MSECONDS(dur_nsec);
6990 if (dur_msec < required_end) // FIXME
6992 debug_log("invalid end pos for pcm extraction");
6993 return MM_ERROR_INVALID_ARGUMENT;
6996 start_nsec = required_start * G_GINT64_CONSTANT(1000000);
6997 end_nsec = required_end * G_GINT64_CONSTANT(1000000);
6999 if ( (!__gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
7002 ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ),
7003 GST_SEEK_TYPE_SET, start_nsec,
7004 GST_SEEK_TYPE_SET, end_nsec)))
7006 debug_error("failed to seek for pcm extraction\n");
7008 return MM_ERROR_PLAYER_SEEK;
7011 debug_log("succeeded to set up segment extraction from [%llu] to [%llu] (nsec)\n", start_nsec, end_nsec);
7015 return MM_ERROR_NONE;
7019 _mmplayer_deactivate_section_repeat(MMHandleType hplayer)
7021 mm_player_t* player = (mm_player_t*)hplayer;
7023 GstFormat fmt = GST_FORMAT_TIME;
7028 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7030 player->section_repeat = FALSE;
7032 __mmplayer_set_play_count( player, onetime );
7034 gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &fmt, &cur_pos);
7036 if ( (!__gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
7039 ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ),
7040 GST_SEEK_TYPE_SET, cur_pos,
7041 GST_SEEK_TYPE_SET, player->duration )))
7043 debug_error("failed to deactivate section repeat\n");
7045 return MM_ERROR_PLAYER_SEEK;
7050 return MM_ERROR_NONE;
7054 _mmplayer_set_playspeed(MMHandleType hplayer, gdouble rate)
7056 mm_player_t* player = (mm_player_t*)hplayer;
7057 signed long long pos_msec = 0;
7058 int ret = MM_ERROR_NONE;
7060 GstFormat format =GST_FORMAT_TIME;
7061 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7064 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
7065 return_val_if_fail ( !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API );
7067 /* The sound of video is not supported under 0.0 and over 2.0. */
7068 if(rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN)
7070 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
7073 _mmplayer_set_mute(hplayer, mute);
7075 if (player->playback_rate == rate)
7076 return MM_ERROR_NONE;
7078 /* If the position is reached at start potion during fast backward, EOS is posted.
7079 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
7081 player->playback_rate = rate;
7083 current_state = MMPLAYER_CURRENT_STATE(player);
7085 if ( current_state != MM_PLAYER_STATE_PAUSED )
7086 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &format, &pos_msec);
7088 debug_log ("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS (pos_msec), ret, current_state);
7090 if ( ( current_state == MM_PLAYER_STATE_PAUSED )
7092 //|| ( player->last_position != 0 && pos_msec == 0 ) )
7094 debug_warning("returning last point : %lld\n", player->last_position );
7095 pos_msec = player->last_position;
7098 if ((!gst_element_seek (player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
7101 ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ),
7102 //( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_KEY_UNIT),
7103 GST_SEEK_TYPE_SET, pos_msec,
7104 //GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE,
7105 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)))
7107 debug_error("failed to set speed playback\n");
7108 return MM_ERROR_PLAYER_SEEK;
7111 debug_log("succeeded to set speed playback as %fl\n", rate);
7115 return MM_ERROR_NONE;;
7119 _mmplayer_set_position(MMHandleType hplayer, int format, int position) // @
7121 mm_player_t* player = (mm_player_t*)hplayer;
7122 int ret = MM_ERROR_NONE;
7126 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7128 ret = __gst_set_position ( player, format, (unsigned long)position, FALSE );
7136 _mmplayer_get_position(MMHandleType hplayer, int format, unsigned long *position) // @
7138 mm_player_t* player = (mm_player_t*)hplayer;
7139 int ret = MM_ERROR_NONE;
7141 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7143 ret = __gst_get_position ( player, format, position );
7149 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos) // @
7151 mm_player_t* player = (mm_player_t*)hplayer;
7152 int ret = MM_ERROR_NONE;
7154 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7156 ret = __gst_get_buffer_position ( player, format, start_pos, stop_pos );
7162 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position) // @
7164 mm_player_t* player = (mm_player_t*)hplayer;
7165 int ret = MM_ERROR_NONE;
7169 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7171 ret = __gst_adjust_subtitle_position(player, format, position);
7179 __mmplayer_is_midi_type( gchar* str_caps)
7181 if ( ( g_strrstr(str_caps, "audio/midi") ) ||
7182 ( g_strrstr(str_caps, "application/x-gst_ff-mmf") ) ||
7183 ( g_strrstr(str_caps, "application/x-smaf") ) ||
7184 ( g_strrstr(str_caps, "audio/x-imelody") ) ||
7185 ( g_strrstr(str_caps, "audio/mobile-xmf") ) ||
7186 ( g_strrstr(str_caps, "audio/xmf") ) ||
7187 ( g_strrstr(str_caps, "audio/mxmf") ) )
7189 debug_log("midi\n");
7194 debug_log("not midi.\n");
7200 __mmplayer_is_amr_type (gchar *str_caps)
7202 if ((g_strrstr(str_caps, "AMR")) ||
7203 (g_strrstr(str_caps, "amr")))
7211 __mmplayer_is_only_mp3_type (gchar *str_caps)
7213 if (g_strrstr(str_caps, "application/x-id3") ||
7214 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
7222 __mmplayer_typefind_have_type( GstElement *tf, guint probability, // @
7223 GstCaps *caps, gpointer data)
7225 mm_player_t* player = (mm_player_t*)data;
7230 return_if_fail( player && tf && caps );
7232 /* store type string */
7233 MMPLAYER_FREEIF(player->type);
7234 player->type = gst_caps_to_string(caps);
7236 debug_log("meida type %s found, probability %d%% / %d\n", player->type, probability, gst_caps_get_size(caps));
7238 /* midi type should be stored because it will be used to set audio gain in avsysauiosink */
7239 if ( __mmplayer_is_midi_type(player->type))
7241 player->profile.play_mode = MM_PLAYER_MODE_MIDI;
7243 else if (__mmplayer_is_amr_type(player->type))
7245 player->bypass_sound_effect = FALSE;
7246 if ( (PLAYER_INI()->use_audio_filter_preset || PLAYER_INI()->use_audio_filter_custom) )
7248 if ( player->audio_filter_info.filter_type == MM_AUDIO_FILTER_TYPE_PRESET )
7250 if (!_mmplayer_sound_filter_preset_apply(player, player->audio_filter_info.preset))
7252 debug_msg("apply sound effect(preset:%d) setting success\n",player->audio_filter_info.preset);
7255 else if ( player->audio_filter_info.filter_type == MM_AUDIO_FILTER_TYPE_CUSTOM )
7257 if (!_mmplayer_sound_filter_custom_apply(player))
7259 debug_msg("apply sound effect(custom) setting success\n");
7264 else if ( g_strrstr(player->type, "application/x-hls"))
7266 /* If it can't know exact type when it parses uri because of redirection case,
7267 * it will be fixed by typefinder here.
7269 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
7272 pad = gst_element_get_static_pad(tf, "src");
7275 debug_error("fail to get typefind src pad.\n");
7281 if ( ! __mmplayer_try_to_plug( player, pad, caps ) )
7283 debug_error("failed to autoplug for type : %s\n", player->type);
7285 if ( ( PLAYER_INI()->async_start ) &&
7286 ( player->posted_msg == FALSE ) )
7288 __mmplayer_post_missed_plugin( player );
7294 /* finish autopluging if no dynamic pad waiting */
7295 if( ( ! player->have_dynamic_pad) && ( ! player->has_many_types) )
7297 if ( ! MMPLAYER_IS_RTSP_STREAMING( player ) )
7299 __mmplayer_pipeline_complete( NULL, (gpointer)player );
7304 gst_object_unref( GST_OBJECT(pad) );
7312 __mmplayer_warm_up_video_codec( mm_player_t* player, GstElementFactory *factory)
7314 GstElement *element;
7315 GstStateChangeReturn ret;
7316 gboolean usable = TRUE;
7318 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7319 return_val_if_fail ( factory, MM_ERROR_COMMON_INVALID_ARGUMENT );
7321 element = gst_element_factory_create (factory, NULL);
7323 ret = gst_element_set_state (element, GST_STATE_READY);
7325 if (ret != GST_STATE_CHANGE_SUCCESS)
7327 debug_error ("resource conflict so, %s unusable\n", GST_PLUGIN_FEATURE_NAME (factory));
7331 gst_element_set_state (element, GST_STATE_NULL);
7332 gst_object_unref (element);
7337 /* it will return first created element */
7339 __mmplayer_try_to_plug(mm_player_t* player, GstPad *pad, const GstCaps *caps) // @
7341 MMPlayerGstElement* mainbin = NULL;
7342 const char* mime = NULL;
7343 const GList* item = NULL;
7344 const gchar* klass = NULL;
7345 GstCaps* res = NULL;
7346 gboolean skip = FALSE;
7347 GstPad* queue_pad = NULL;
7348 GstElement* queue = NULL;
7349 GstElement *element = NULL;
7353 return_val_if_fail( player &&
7355 player->pipeline->mainbin,
7359 mainbin = player->pipeline->mainbin;
7361 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
7363 /* return if we got raw output */
7364 if(g_str_has_prefix(mime, "video/x-raw") || g_str_has_prefix(mime, "audio/x-raw") ||g_str_has_prefix(mime, "text/plain") )
7367 element = (GstElement*)gst_pad_get_parent(pad);
7370 /* NOTE : When no decoder has added during autoplugging. like a simple wave playback.
7371 * No queue will be added. I think it can caused breaking sound when playing raw audio
7372 * frames but there's no different. Decodebin also doesn't add with those wav fils.
7373 * Anyway, currentely raw-queue seems not necessary.
7377 /* NOTE : check if previously linked element is demuxer/depayloader/parse means no decoder
7378 * has linked. if so, we need to add queue for quality of output. note that
7379 * decodebin also has same problem.
7382 klass = gst_element_factory_get_klass( gst_element_get_factory(element) );
7384 /* add queue if needed */
7385 if( g_strrstr(klass, "Demux") ||
7386 g_strrstr(klass, "Depayloader") ||
7387 g_strrstr(klass, "Parse") )
7389 debug_log("adding raw queue\n");
7391 queue = gst_element_factory_make("queue", NULL);
7394 debug_warning("failed to create queue\n");
7399 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_READY) )
7401 debug_warning("failed to set state READY to queue\n");
7405 /* add to pipeline */
7406 if ( ! gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue) )
7408 debug_warning("failed to add queue\n");
7413 queue_pad = gst_element_get_static_pad(queue, "sink");
7415 if ( GST_PAD_LINK_OK != gst_pad_link(pad, queue_pad) )
7417 debug_warning("failed to link queue\n");
7420 gst_object_unref ( GST_OBJECT(queue_pad) );
7424 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_PAUSED) )
7426 debug_warning("failed to set state READY to queue\n");
7430 /* replace given pad to queue:src */
7431 pad = gst_element_get_static_pad(queue, "src");
7434 debug_warning("failed to get pad from queue\n");
7439 /* check if player can do start continually */
7440 MMPLAYER_CHECK_CMD_IF_EXIT(player);
7442 if(__mmplayer_link_sink(player,pad))
7443 __mmplayer_gst_decode_callback(element, pad, FALSE, player);
7445 gst_object_unref( GST_OBJECT(element));
7452 item = player->factories;
7453 for(; item != NULL ; item = item->next)
7456 GstElementFactory *factory = GST_ELEMENT_FACTORY(item->data);
7462 /* filtering exclude keyword */
7463 for ( idx = 0; PLAYER_INI()->exclude_element_keyword[idx][0] != '\0'; idx++ )
7465 if ( g_strrstr(GST_PLUGIN_FEATURE_NAME (factory),
7466 PLAYER_INI()->exclude_element_keyword[idx] ) )
7468 debug_warning("skipping [%s] by exculde keyword [%s]\n",
7469 GST_PLUGIN_FEATURE_NAME (factory),
7470 PLAYER_INI()->exclude_element_keyword[idx] );
7477 if ( skip ) continue;
7480 /* check factory class for filtering */
7481 klass = gst_element_factory_get_klass(GST_ELEMENT_FACTORY(factory));
7483 /* NOTE : msl don't need to use image plugins.
7484 * So, those plugins should be skipped for error handling.
7486 if ( g_strrstr(klass, "Codec/Decoder/Image") )
7488 debug_log("player doesn't need [%s] so, skipping it\n",
7489 GST_PLUGIN_FEATURE_NAME (factory) );
7495 /* check pad compatability */
7496 for(pads = gst_element_factory_get_static_pad_templates(factory);
7497 pads != NULL; pads=pads->next)
7499 GstStaticPadTemplate *temp1 = pads->data;
7500 GstCaps* static_caps = NULL;
7502 if( temp1->direction != GST_PAD_SINK ||
7503 temp1->presence != GST_PAD_ALWAYS)
7507 if ( GST_IS_CAPS( &temp1->static_caps.caps) )
7509 /* using existing caps */
7510 static_caps = gst_caps_ref( &temp1->static_caps.caps );
7515 static_caps = gst_caps_from_string ( temp1->static_caps.string );
7518 res = gst_caps_intersect(caps, static_caps);
7520 gst_caps_unref( static_caps );
7523 if( res && !gst_caps_is_empty(res) )
7525 GstElement *new_element;
7526 GList *elements = player->parsers;
7527 char *name_template = g_strdup(temp1->name_template);
7528 gchar *name_to_plug = GST_PLUGIN_FEATURE_NAME(factory);
7530 gst_caps_unref(res);
7532 debug_log("found %s to plug\n", name_to_plug);
7534 new_element = gst_element_factory_create(GST_ELEMENT_FACTORY(factory), NULL);
7535 if ( ! new_element )
7537 debug_error("failed to create element [%s]. continue with next.\n",
7538 GST_PLUGIN_FEATURE_NAME (factory));
7540 MMPLAYER_FREEIF(name_template);
7545 /* check and skip it if it was already used. Otherwise, it can be an infinite loop
7546 * because parser can accept its own output as input.
7548 if (g_strrstr(klass, "Parser"))
7550 gchar *selected = NULL;
7552 for ( ; elements; elements = g_list_next(elements))
7554 gchar *element_name = elements->data;
7556 if (g_strrstr(element_name, name_to_plug))
7558 debug_log("but, %s already linked, so skipping it\n", name_to_plug);
7565 selected = g_strdup(name_to_plug);
7567 player->parsers = g_list_append(player->parsers, selected);
7570 /* store specific handles for futher control */
7571 if(g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse"))
7573 /* FIXIT : first value will be overwritten if there's more
7574 * than 1 demuxer/parser
7576 debug_log("plugged element is demuxer. take it\n");
7577 mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7578 mainbin[MMPLAYER_M_DEMUX].gst = new_element;
7580 else if(g_strrstr(klass, "Decoder") && __mmplayer_link_decoder(player,pad))
7582 if(mainbin[MMPLAYER_M_DEC1].gst == NULL)
7584 debug_log("plugged element is decoder. take it[MMPLAYER_M_DEC1]\n");
7585 mainbin[MMPLAYER_M_DEC1].id = MMPLAYER_M_DEC1;
7586 mainbin[MMPLAYER_M_DEC1].gst = new_element;
7588 else if(mainbin[MMPLAYER_M_DEC2].gst == NULL)
7590 debug_log("plugged element is decoder. take it[MMPLAYER_M_DEC2]\n");
7591 mainbin[MMPLAYER_M_DEC2].id = MMPLAYER_M_DEC2;
7592 mainbin[MMPLAYER_M_DEC2].gst = new_element;
7595 /* NOTE : IF one codec is found, add it to supported_codec and remove from
7596 * missing plugin. Both of them are used to check what's supported codec
7597 * before returning result of play start. And, missing plugin should be
7598 * updated here for multi track files.
7600 if(g_str_has_prefix(mime, "video"))
7602 GstPad *src_pad = NULL;
7603 GstPadTemplate *pad_templ = NULL;
7604 GstCaps *caps = NULL;
7605 gchar *caps_type = NULL;
7607 debug_log("found VIDEO decoder\n");
7608 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7609 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7611 src_pad = gst_element_get_static_pad (new_element, "src");
7612 pad_templ = gst_pad_get_pad_template (src_pad);
7613 caps = GST_PAD_TEMPLATE_CAPS(pad_templ);
7615 caps_type = gst_caps_to_string(caps);
7617 if ( g_strrstr( caps_type, "ST12") )
7618 player->is_nv12_tiled = TRUE;
7621 MMPLAYER_FREEIF( caps_type );
7622 gst_object_unref (src_pad);
7624 else if (g_str_has_prefix(mime, "audio"))
7626 debug_log("found AUDIO decoder\n");
7627 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7628 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7631 if ( ! __mmplayer_close_link(player, pad, new_element,
7632 name_template,gst_element_factory_get_static_pad_templates(factory)) )
7634 if (player->keep_detecting_vcodec)
7637 /* Link is failed even though a supportable codec is found. */
7638 __mmplayer_check_not_supported_codec(player, (gchar *)mime);
7640 MMPLAYER_FREEIF(name_template);
7641 debug_error("failed to call _close_link\n");
7645 MMPLAYER_FREEIF(name_template);
7649 gst_caps_unref(res);
7655 /* There is no any found codec. */
7656 __mmplayer_check_not_supported_codec(player,(gchar *)mime);
7658 debug_error("failed to autoplug\n");
7669 gst_object_unref( queue );
7673 gst_object_unref( queue_pad );
7676 gst_object_unref ( element );
7683 int __mmplayer_check_not_supported_codec(mm_player_t* player, gchar* mime)
7687 return_val_if_fail(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7688 return_val_if_fail ( mime, MM_ERROR_INVALID_ARGUMENT );
7690 debug_log("mimetype to check: %s\n", mime );
7692 /* add missing plugin */
7693 /* NOTE : msl should check missing plugin for image mime type.
7694 * Some motion jpeg clips can have playable audio track.
7695 * So, msl have to play audio after displaying popup written video format not supported.
7697 if ( !( player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst ) )
7699 if ( !( player->can_support_codec | player->videodec_linked | player->audiodec_linked ) )
7701 debug_log("not found demuxer\n");
7702 player->not_found_demuxer = TRUE;
7703 player->unlinked_demuxer_mime = g_strdup_printf ( "%s", mime );
7709 if( ( g_str_has_prefix(mime, "video") ) ||( g_str_has_prefix(mime, "image") ) )
7711 debug_log("can support codec=%d, vdec_linked=%d, adec_linked=%d\n",
7712 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
7714 /* check that clip have multi tracks or not */
7715 if ( ( player->can_support_codec & FOUND_PLUGIN_VIDEO ) && ( player->videodec_linked ) )
7717 debug_log("video plugin is already linked\n");
7721 debug_warning("add VIDEO to missing plugin\n");
7722 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
7725 else if ( g_str_has_prefix(mime, "audio") )
7727 if ( ( player->can_support_codec & FOUND_PLUGIN_AUDIO ) && ( player->audiodec_linked ) )
7729 debug_log("audio plugin is already linked\n");
7733 debug_warning("add AUDIO to missing plugin\n");
7734 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
7741 return MM_ERROR_NONE;
7745 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data) // @
7747 mm_player_t* player = (mm_player_t*)data;
7751 return_if_fail( player );
7753 /* remove fakesink */
7754 if ( ! __mmplayer_gst_remove_fakesink( player,
7755 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]) )
7757 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
7758 * signaling mechanism ( pad-added, no-more-pad, new-decoded-pad ) from various
7759 * source element are not same. To overcome this situation, this function will called
7760 * several places and several times. Therefore, this is not an error case.
7764 debug_log("pipeline has completely constructed\n");
7766 player->pipeline_is_constructed = TRUE;
7768 if ( ( PLAYER_INI()->async_start ) &&
7769 ( player->posted_msg == FALSE ) )
7771 __mmplayer_post_missed_plugin( player );
7774 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-complate" );
7777 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player)
7781 return_val_if_fail ( player, FALSE );
7784 if ( MMPLAYER_IS_STREAMING(player) )
7787 /* This callback can be set to music player only. */
7788 if((player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO)
7790 debug_warning("audio callback is not supported for video");
7794 if (player->audio_stream_cb)
7799 pad = gst_element_get_static_pad (player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
7803 debug_error("failed to get sink pad from audiosink to probe data\n");
7807 player->audio_cb_probe_id = gst_pad_add_buffer_probe (pad,
7808 G_CALLBACK (__mmplayer_audio_stream_probe), player);
7810 gst_object_unref (pad);
7817 debug_error("There is no audio callback to configure.\n");
7827 __mmplayer_init_factories(mm_player_t* player) // @
7831 return_if_fail ( player );
7833 player->factories = gst_registry_feature_filter(gst_registry_get_default(),
7834 (GstPluginFeatureFilter)__mmplayer_feature_filter, FALSE, NULL);
7836 player->factories = g_list_sort(player->factories, (GCompareFunc)util_factory_rank_compare);
7842 __mmplayer_release_factories(mm_player_t* player) // @
7846 return_if_fail ( player );
7848 if (player->factories)
7850 gst_plugin_feature_list_free (player->factories);
7851 player->factories = NULL;
7858 __mmplayer_release_misc(mm_player_t* player)
7863 return_if_fail ( player );
7865 player->use_video_stream = FALSE;
7866 player->video_stream_cb = NULL;
7867 player->video_stream_cb_user_param = NULL;
7869 player->audio_stream_cb = NULL;
7870 player->audio_stream_cb_user_param = NULL;
7872 player->audio_buffer_cb = NULL;
7873 player->audio_buffer_cb_user_param = NULL;
7875 player->sent_bos = FALSE;
7876 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7878 player->doing_seek = FALSE;
7880 player->streamer = NULL;
7881 player->updated_bitrate_count = 0;
7882 player->total_bitrate = 0;
7883 player->updated_maximum_bitrate_count = 0;
7884 player->total_maximum_bitrate = 0;
7886 player->not_found_demuxer = 0;
7888 player->last_position = 0;
7889 player->duration = 0;
7890 player->http_content_size = 0;
7891 player->not_supported_codec = MISSING_PLUGIN_NONE;
7892 player->can_support_codec = FOUND_PLUGIN_NONE;
7893 player->need_update_content_dur = FALSE;
7894 player->pending_seek.is_pending = FALSE;
7895 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
7896 player->pending_seek.pos = 0;
7897 player->posted_msg == FALSE;
7898 player->has_many_types = FALSE;
7900 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++)
7902 player->bitrate[i] = 0;
7903 player->maximum_bitrate[i] = 0;
7906 /* clean found parsers */
7907 if (player->parsers)
7909 g_list_free(player->parsers);
7910 player->parsers = NULL;
7913 MMPLAYER_FREEIF(player->album_art);
7915 /* free memory related to sound effect */
7916 if(player->audio_filter_info.custom_ext_level_for_plugin)
7918 free(player->audio_filter_info.custom_ext_level_for_plugin);
7924 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name)
7926 GstElement *element = NULL;
7929 debug_log("creating %s to plug\n", name);
7931 element = gst_element_factory_make(name, NULL);
7934 debug_error("failed to create queue\n");
7938 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(element, GST_STATE_READY) )
7940 debug_error("failed to set state READY to %s\n", name);
7944 if ( ! gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), element))
7946 debug_error("failed to add %s\n", name);
7950 sinkpad = gst_element_get_static_pad(element, "sink");
7952 if ( GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad) )
7954 debug_error("failed to link %s\n", name);
7955 gst_object_unref (sinkpad);
7960 debug_log("linked %s to pipeline successfully\n", name);
7962 gst_object_unref (sinkpad);
7968 __mmplayer_close_link(mm_player_t* player, GstPad *srcpad, GstElement *sinkelement,
7969 const char *padname, const GList *templlist)
7972 gboolean has_dynamic_pads = FALSE;
7973 gboolean has_many_types = FALSE;
7974 const char *klass = NULL;
7975 GstStaticPadTemplate *padtemplate = NULL;
7976 GstElementFactory *factory = NULL;
7977 GstElement* queue = NULL;
7978 GstElement* parser = NULL;
7979 GstPad *pssrcpad = NULL;
7980 GstPad *qsrcpad = NULL, *qsinkpad = NULL;
7981 MMPlayerGstElement *mainbin = NULL;
7982 GstStructure* str = NULL;
7983 GstCaps* srccaps = NULL;
7984 GstState warmup = GST_STATE_READY;
7985 gboolean isvideo_decoder = FALSE;
7986 guint q_max_size_time = 0;
7990 return_val_if_fail ( player &&
7992 player->pipeline->mainbin,
7995 mainbin = player->pipeline->mainbin;
7997 debug_log("plugging pad %s:%s to newly create %s:%s\n",
7998 GST_ELEMENT_NAME( GST_PAD_PARENT ( srcpad ) ),
7999 GST_PAD_NAME( srcpad ),
8000 GST_ELEMENT_NAME( sinkelement ),
8003 factory = gst_element_get_factory(sinkelement);
8004 klass = gst_element_factory_get_klass(factory);
8006 /* check if player can do start continually */
8007 MMPLAYER_CHECK_CMD_IF_EXIT(player);
8009 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkelement, warmup) )
8011 if (isvideo_decoder)
8012 player->keep_detecting_vcodec = TRUE;
8014 debug_error("failed to set %d state to %s\n", warmup, GST_ELEMENT_NAME( sinkelement ));
8018 /* add to pipeline */
8019 if ( ! gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), sinkelement) )
8021 debug_error("failed to add %s to mainbin\n", GST_ELEMENT_NAME( sinkelement ));
8025 debug_log("element klass : %s\n", klass);
8027 /* added to support multi track files */
8028 /* only decoder case and any of the video/audio still need to link*/
8029 if(g_strrstr(klass, "Decoder") && __mmplayer_link_decoder(player,srcpad))
8033 name = g_strdup(GST_ELEMENT_NAME( GST_PAD_PARENT ( srcpad )));
8035 if (g_strrstr(name, "mpegtsdemux"))
8037 gchar *demux_caps = NULL;
8038 gchar *parser_name = NULL;
8039 GstCaps *dcaps = NULL;
8041 dcaps = gst_pad_get_caps(srcpad);
8042 demux_caps = gst_caps_to_string(dcaps);
8044 if (g_strrstr(demux_caps, "video/x-h264"))
8046 parser_name = g_strdup("h264parse");
8048 else if (g_strrstr(demux_caps, "video/mpeg"))
8050 parser_name = g_strdup("mpeg4videoparse");
8053 gst_caps_unref(dcaps);
8054 MMPLAYER_FREEIF( demux_caps );
8058 parser = __mmplayer_element_create_and_link(player, srcpad, parser_name);
8060 MMPLAYER_FREEIF(parser_name);
8064 debug_error("failed to create parser\n");
8068 /* update srcpad if parser is created */
8069 pssrcpad = gst_element_get_static_pad(parser, "src");
8074 MMPLAYER_FREEIF(name);
8076 queue = __mmplayer_element_create_and_link(player, srcpad, "queue"); // parser - queue or demuxer - queue
8079 debug_error("failed to create queue\n");
8083 /* update srcpad to link with decoder */
8084 qsrcpad = gst_element_get_static_pad(queue, "src");
8087 q_max_size_time = GST_QUEUE_DEFAULT_TIME;
8089 /* assigning queue handle for futher manipulation purpose */
8090 /* FIXIT : make it some kind of list so that msl can support more then two stream (text, data, etc...) */
8091 if(mainbin[MMPLAYER_M_Q1].gst == NULL)
8093 mainbin[MMPLAYER_M_Q1].id = MMPLAYER_M_Q1;
8094 mainbin[MMPLAYER_M_Q1].gst = queue;
8096 g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q1].gst), "max-size-time", q_max_size_time * GST_SECOND, NULL);
8098 else if(mainbin[MMPLAYER_M_Q2].gst == NULL)
8100 mainbin[MMPLAYER_M_Q2].id = MMPLAYER_M_Q2;
8101 mainbin[MMPLAYER_M_Q2].gst = queue;
8103 g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q2].gst), "max-size-time", q_max_size_time * GST_SECOND, NULL);
8107 debug_critical("Not supporting more then two elementary stream\n");
8111 pad = gst_element_get_static_pad(sinkelement, padname);
8115 debug_warning("failed to get pad(%s) from %s. retrying with [sink]\n",
8116 padname, GST_ELEMENT_NAME(sinkelement) );
8118 pad = gst_element_get_static_pad(sinkelement, "sink");
8121 debug_error("failed to get pad(sink) from %s. \n",
8122 GST_ELEMENT_NAME(sinkelement) );
8127 /* to check the video/audio type set the proper flag*/
8129 srccaps = gst_pad_get_caps( srcpad );
8133 str = gst_caps_get_structure( srccaps, 0 );
8137 name = gst_structure_get_name(str);
8142 /* link queue and decoder. so, it will be queue - decoder. */
8143 if ( GST_PAD_LINK_OK != gst_pad_link(srcpad, pad) )
8145 gst_object_unref(GST_OBJECT(pad));
8146 debug_error("failed to link (%s) to pad(%s)\n", GST_ELEMENT_NAME( sinkelement ), padname );
8148 /* reconstitute supportable codec */
8149 if (strstr(name, "video"))
8151 player->can_support_codec ^= FOUND_PLUGIN_VIDEO;
8153 else if (strstr(name, "audio"))
8155 player->can_support_codec ^= FOUND_PLUGIN_AUDIO;
8160 if (strstr(name, "video"))
8162 player->videodec_linked = 1;
8163 debug_msg("player->videodec_linked set to 1\n");
8166 else if (strstr(name, "audio"))
8168 player->audiodec_linked = 1;
8169 debug_msg("player->auddiodec_linked set to 1\n");
8172 gst_object_unref(GST_OBJECT(pad));
8173 gst_caps_unref(GST_CAPS(srccaps));
8177 if ( !MMPLAYER_IS_HTTP_PD(player) )
8179 if( (g_strrstr(klass, "Demux") && !g_strrstr(klass, "Metadata")) || (g_strrstr(klass, "Parser") ) )
8181 if (MMPLAYER_IS_HTTP_STREAMING(player))
8183 GstFormat fmt = GST_FORMAT_BYTES;
8184 gint64 dur_bytes = 0L;
8185 gchar *file_buffering_path = NULL;
8186 gboolean use_file_buffer = FALSE;
8188 if ( !mainbin[MMPLAYER_M_S_BUFFER].gst)
8190 debug_log("creating http streaming buffering queue\n");
8192 queue = gst_element_factory_make("queue2", "http_streaming_buffer");
8195 debug_critical ( "failed to create buffering queue element\n" );
8199 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_READY) )
8201 debug_error("failed to set state READY to buffering queue\n");
8205 if ( !gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue) )
8207 debug_error("failed to add buffering queue\n");
8211 qsinkpad = gst_element_get_static_pad(queue, "sink");
8212 qsrcpad = gst_element_get_static_pad(queue, "src");
8214 if ( GST_PAD_LINK_OK != gst_pad_link(srcpad, qsinkpad) )
8216 debug_error("failed to link buffering queue\n");
8222 mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_S_BUFFER;
8223 mainbin[MMPLAYER_M_S_BUFFER].gst = queue;
8225 if ( !MMPLAYER_IS_HTTP_LIVE_STREAMING(player))
8227 if ( !gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, &fmt, &dur_bytes))
8228 debug_error("fail to get duration.\n");
8232 use_file_buffer = MMPLAYER_USE_FILE_FOR_BUFFERING(player);
8233 file_buffering_path = g_strdup(PLAYER_INI()->http_file_buffer_path);
8237 __mm_player_streaming_set_buffer(player->streamer,
8240 PLAYER_INI()->http_max_size_bytes,
8242 PLAYER_INI()->http_buffering_limit,
8243 PLAYER_INI()->http_buffering_time,
8245 file_buffering_path,
8248 MMPLAYER_FREEIF(file_buffering_path);
8253 /* if it is not decoder or */
8254 /* in decoder case any of the video/audio still need to link*/
8255 if(!g_strrstr(klass, "Decoder"))
8258 pad = gst_element_get_static_pad(sinkelement, padname);
8261 debug_warning("failed to get pad(%s) from %s. retrying with [sink]\n",
8262 padname, GST_ELEMENT_NAME(sinkelement) );
8264 pad = gst_element_get_static_pad(sinkelement, "sink");
8268 debug_error("failed to get pad(sink) from %s. \n",
8269 GST_ELEMENT_NAME(sinkelement) );
8274 if ( GST_PAD_LINK_OK != gst_pad_link(srcpad, pad) )
8276 gst_object_unref(GST_OBJECT(pad));
8277 debug_error("failed to link (%s) to pad(%s)\n", GST_ELEMENT_NAME( sinkelement ), padname );
8281 gst_object_unref(GST_OBJECT(pad));
8284 for(;templlist != NULL; templlist = templlist->next)
8286 padtemplate = templlist->data;
8288 debug_log ("director = [%d], presence = [%d]\n", padtemplate->direction, padtemplate->presence);
8290 if( padtemplate->direction != GST_PAD_SRC ||
8291 padtemplate->presence == GST_PAD_REQUEST )
8294 switch(padtemplate->presence)
8296 case GST_PAD_ALWAYS:
8298 GstPad *srcpad = gst_element_get_static_pad(sinkelement, "src");
8299 GstCaps *caps = gst_pad_get_caps(srcpad);
8301 /* Check whether caps has many types */
8302 if ( gst_caps_get_size (caps) > 1 && g_strrstr(klass, "Parser")) {
8303 debug_log ("has_many_types for this caps [%s]\n", gst_caps_to_string(caps));
8304 has_many_types = TRUE;
8308 if ( ! __mmplayer_try_to_plug(player, srcpad, caps) )
8310 gst_object_unref(GST_OBJECT(srcpad));
8311 gst_caps_unref(GST_CAPS(caps));
8313 debug_error("failed to plug something after %s\n", GST_ELEMENT_NAME( sinkelement ));
8317 gst_caps_unref(GST_CAPS(caps));
8318 gst_object_unref(GST_OBJECT(srcpad));
8324 case GST_PAD_SOMETIMES:
8325 has_dynamic_pads = TRUE;
8333 /* check if player can do start continually */
8334 MMPLAYER_CHECK_CMD_IF_EXIT(player);
8336 if( has_dynamic_pads )
8338 player->have_dynamic_pad = TRUE;
8339 MMPLAYER_SIGNAL_CONNECT ( player, sinkelement, "pad-added",
8340 G_CALLBACK(__mmplayer_add_new_pad), player);
8342 /* for streaming, more then one typefind will used for each elementary stream
8343 * so this doesn't mean the whole pipeline completion
8345 if ( ! MMPLAYER_IS_RTSP_STREAMING( player ) )
8347 MMPLAYER_SIGNAL_CONNECT( player, sinkelement, "no-more-pads",
8348 G_CALLBACK(__mmplayer_pipeline_complete), player);
8356 player->has_many_types = has_many_types;
8358 pad = gst_element_get_static_pad(sinkelement, "src");
8359 MMPLAYER_SIGNAL_CONNECT (player, pad, "notify::caps", G_CALLBACK(__mmplayer_add_new_caps), player);
8360 gst_object_unref (GST_OBJECT(pad));
8364 /* check if player can do start continually */
8365 MMPLAYER_CHECK_CMD_IF_EXIT(player);
8367 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkelement, GST_STATE_PAUSED) )
8369 debug_error("failed to set state PAUSED to %s\n", GST_ELEMENT_NAME( sinkelement ));
8375 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state (queue, GST_STATE_PAUSED) )
8377 debug_error("failed to set state PAUSED to queue\n");
8383 gst_object_unref (GST_OBJECT(qsrcpad));
8389 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state (parser, GST_STATE_PAUSED) )
8391 debug_error("failed to set state PAUSED to queue\n");
8397 gst_object_unref (GST_OBJECT(pssrcpad));
8409 gst_object_unref(GST_OBJECT(qsrcpad));
8411 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
8412 * You need to explicitly set elements to the NULL state before
8413 * dropping the final reference, to allow them to clean up.
8415 gst_element_set_state(queue, GST_STATE_NULL);
8416 /* And, it still has a parent "player".
8417 * You need to let the parent manage the object instead of unreffing the object directly.
8420 gst_bin_remove (GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue);
8421 //gst_object_unref( queue );
8425 gst_caps_unref(GST_CAPS(srccaps));
8430 static gboolean __mmplayer_feature_filter(GstPluginFeature *feature, gpointer data) // @
8433 //const gchar *name;
8435 /* we only care about element factories */
8436 if (!GST_IS_ELEMENT_FACTORY(feature))
8439 /* only parsers, demuxers and decoders */
8440 klass = gst_element_factory_get_klass(GST_ELEMENT_FACTORY(feature));
8441 //name = gst_element_factory_get_longname(GST_ELEMENT_FACTORY(feature));
8443 if( g_strrstr(klass, "Demux") == NULL &&
8444 g_strrstr(klass, "Codec/Decoder") == NULL &&
8445 g_strrstr(klass, "Depayloader") == NULL &&
8446 g_strrstr(klass, "Parse") == NULL)
8454 static void __mmplayer_add_new_caps(GstPad* pad, GParamSpec* unused, gpointer data)
8456 mm_player_t* player = (mm_player_t*) data;
8457 GstCaps *caps = NULL;
8458 GstStructure *str = NULL;
8463 return_if_fail ( pad )
8464 return_if_fail ( unused )
8465 return_if_fail ( data )
8467 caps = gst_pad_get_caps(pad);
8471 str = gst_caps_get_structure(caps, 0);
8475 name = gst_structure_get_name(str);
8478 debug_log("name=%s\n", name);
8480 if ( ! __mmplayer_try_to_plug(player, pad, caps) )
8482 debug_error("failed to autoplug for type (%s)\n", name);
8483 gst_caps_unref(caps);
8487 gst_caps_unref(caps);
8489 __mmplayer_pipeline_complete( NULL, (gpointer)player );
8496 static void __mmplayer_set_unlinked_mime_type(mm_player_t* player, GstCaps *caps)
8500 const char *stream_type;
8501 gchar *version_field = NULL;
8505 return_if_fail ( player );
8506 return_if_fail ( caps );
8508 str = gst_caps_get_structure(caps, 0);
8512 stream_type = gst_structure_get_name(str);
8517 /* set unlinked mime type for downloadable codec */
8518 if (g_str_has_prefix(stream_type, "video/"))
8520 if (g_str_has_prefix(stream_type, "video/mpeg"))
8522 gst_structure_get_int (str, MM_PLAYER_MPEG_VNAME, &version);
8523 version_field = MM_PLAYER_MPEG_VNAME;
8525 else if (g_str_has_prefix(stream_type, "video/x-wmv"))
8527 gst_structure_get_int (str, MM_PLAYER_WMV_VNAME, &version);
8528 version_field = MM_PLAYER_WMV_VNAME;
8531 else if (g_str_has_prefix(stream_type, "video/x-divx"))
8533 gst_structure_get_int (str, MM_PLAYER_DIVX_VNAME, &version);
8534 version_field = MM_PLAYER_DIVX_VNAME;
8539 player->unlinked_video_mime = g_strdup_printf("%s, %s=%d", stream_type, version_field, version);
8543 player->unlinked_video_mime = g_strdup_printf("%s", stream_type);
8546 else if (g_str_has_prefix(stream_type, "audio/"))
8548 if (g_str_has_prefix(stream_type, "audio/mpeg")) // mp3 or aac
8550 gst_structure_get_int (str, MM_PLAYER_MPEG_VNAME, &version);
8551 version_field = MM_PLAYER_MPEG_VNAME;
8553 else if (g_str_has_prefix(stream_type, "audio/x-wma"))
8555 gst_structure_get_int (str, MM_PLAYER_WMA_VNAME, &version);
8556 version_field = MM_PLAYER_WMA_VNAME;
8561 player->unlinked_audio_mime = g_strdup_printf("%s, %s=%d", stream_type, version_field, version);
8565 player->unlinked_audio_mime = g_strdup_printf("%s", stream_type);
8572 static void __mmplayer_add_new_pad(GstElement *element, GstPad *pad, gpointer data)
8574 mm_player_t* player = (mm_player_t*) data;
8575 GstCaps *caps = NULL;
8576 GstStructure *str = NULL;
8580 return_if_fail ( player );
8581 return_if_fail ( pad );
8583 GST_OBJECT_LOCK (pad);
8584 if ((caps = GST_PAD_CAPS(pad)))
8586 GST_OBJECT_UNLOCK (pad);
8590 caps = gst_pad_get_caps(pad);
8591 if ( !caps ) return;
8594 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8596 str = gst_caps_get_structure(caps, 0);
8600 name = gst_structure_get_name(str);
8604 player->num_dynamic_pad++;
8605 debug_log("stream count inc : %d\n", player->num_dynamic_pad);
8607 /* Note : If the stream is the subtitle, we try not to play it. Just close the demuxer subtitle pad.
8608 * If want to play it, remove this code.
8610 if (g_strrstr(name, "application"))
8612 if (g_strrstr(name, "x-id3") || g_strrstr(name, "x-apetag"))
8614 /* If id3/ape tag comes, keep going */
8615 debug_log("application mime exception : id3/ape tag");
8619 /* Otherwise, we assume that this stream is subtile. */
8620 debug_log(" application mime type pad is closed.");
8624 else if (g_strrstr(name, "audio"))
8626 gint samplerate = 0, channels = 0;
8628 /* set stream information */
8629 /* if possible, set it here because the caps is not distrubed by resampler. */
8630 gst_structure_get_int (str, "rate", &samplerate);
8631 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
8633 gst_structure_get_int (str, "channels", &channels);
8634 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
8636 debug_log("audio samplerate : %d channels : %d", samplerate, channels);
8639 if ( mmf_attrs_commit ( player->attrs ) )
8641 debug_error("failed to update attributes");
8645 else if (g_strrstr(name, "video"))
8648 mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &stype);
8650 /* don't make video because of not required */
8651 if (stype == MM_DISPLAY_SURFACE_NULL)
8653 debug_log("no video because it's not required");
8657 player->v_stream_caps = gst_caps_copy(caps); //if needed, video caps is required when videobin is created
8660 if ( ! __mmplayer_try_to_plug(player, pad, caps) )
8662 debug_error("failed to autoplug for type (%s)", name);
8664 __mmplayer_set_unlinked_mime_type(player, caps);
8667 gst_caps_unref(caps);
8673 /* test API for tuning audio gain. this API should be
8674 * deprecated before the day of final release
8677 _mmplayer_set_volume_tune(MMHandleType hplayer, MMPlayerVolumeType volume)
8679 mm_player_t* player = (mm_player_t*) hplayer;
8680 gint error = MM_ERROR_NONE;
8682 gboolean isMidi = FALSE;
8687 return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
8688 return_val_if_fail( player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED )
8690 debug_log("clip type=%d(1-midi, 0-others), volume [L]=%d:[R]=%d\n",
8691 player->profile.play_mode, volume.level[0], volume.level[1]);
8693 isMidi = ( player->profile.play_mode == MM_PLAYER_MODE_MIDI ) ? TRUE : FALSE;
8700 /* is it proper volume level? */
8701 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; ++i)
8703 if (volume.level[i] < 0 || volume.level[i] > vol_max) {
8704 debug_log("Invalid Volume level!!!! \n");
8705 return MM_ERROR_INVALID_ARGUMENT;
8711 if ( player->pipeline->mainbin )
8713 GstElement *midi_element = player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst;
8715 if ( midi_element && ( strstr(GST_ELEMENT_NAME(midi_element), "midiparse")) )
8717 debug_log("setting volume (%d) level to midi plugin\n", volume.level[0]);
8719 g_object_set(midi_element, "volume", volume.level[0], NULL);
8725 if ( player->pipeline->audiobin )
8727 GstElement *sink_element = player->pipeline->audiobin[MMPLAYER_A_SINK].gst;
8729 /* Set to Avsysaudiosink element */
8733 gboolean mute = FALSE;
8734 vol_value = volume.level[0];
8736 g_object_set(G_OBJECT(sink_element), "tuningvolume", vol_value, NULL);
8738 mute = (vol_value == 0)? TRUE:FALSE;
8740 g_object_set(G_OBJECT(sink_element), "mute", mute, NULL);
8752 __mmplayer_dump_pipeline_state( mm_player_t* player )
8754 GstIterator*iter = NULL;
8755 gboolean done = FALSE;
8757 GstElement *item = NULL;
8758 GstElementFactory *factory = NULL;
8760 GstState state = GST_STATE_VOID_PENDING;
8761 GstState pending = GST_STATE_VOID_PENDING;
8762 GstClockTime time = 200*GST_MSECOND;
8766 return_val_if_fail ( player &&
8768 player->pipeline->mainbin,
8772 iter = gst_bin_iterate_recurse(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst) );
8777 switch ( gst_iterator_next (iter, (gpointer)&item) )
8779 case GST_ITERATOR_OK:
8780 gst_element_get_state(GST_ELEMENT (item),&state, &pending,time);
8782 factory = gst_element_get_factory (item) ;
8783 debug_log("%s:%s : From:%s To:%s refcount : %d\n", GST_OBJECT_NAME(factory) , GST_ELEMENT_NAME(item) ,
8784 gst_element_state_get_name(state), gst_element_state_get_name(pending) , GST_OBJECT_REFCOUNT_VALUE(item));
8787 gst_object_unref (item);
8789 case GST_ITERATOR_RESYNC:
8790 gst_iterator_resync (iter);
8792 case GST_ITERATOR_ERROR:
8795 case GST_ITERATOR_DONE:
8802 item = GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8804 gst_element_get_state(GST_ELEMENT (item),&state, &pending,time);
8806 factory = gst_element_get_factory (item) ;
8808 debug_log("%s:%s : From:%s To:%s refcount : %d\n",
8809 GST_OBJECT_NAME(factory),
8810 GST_ELEMENT_NAME(item),
8811 gst_element_state_get_name(state),
8812 gst_element_state_get_name(pending),
8813 GST_OBJECT_REFCOUNT_VALUE(item) );
8816 gst_iterator_free (iter);
8825 __mmplayer_check_subtitle( mm_player_t* player )
8827 MMHandleType attrs = 0;
8828 char *subtitle_uri = NULL;
8832 return_val_if_fail( player, FALSE );
8834 /* get subtitle attribute */
8835 attrs = MMPLAYER_GET_ATTRS(player);
8839 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8840 if ( !subtitle_uri || !strlen(subtitle_uri))
8843 debug_log ("subtite uri is %s[%d]\n", subtitle_uri, strlen(subtitle_uri));
8851 __mmplayer_can_extract_pcm( mm_player_t* player )
8853 MMHandleType attrs = 0;
8854 gboolean is_drm = FALSE;
8855 gboolean sound_extraction = FALSE;
8859 return_val_if_fail ( player, FALSE );
8861 attrs = MMPLAYER_GET_ATTRS(player);
8864 debug_error("fail to get attributes.");
8868 /* check file is drm or not */
8869 g_object_get(G_OBJECT(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), "is-drm", &is_drm, NULL);
8871 /* get sound_extraction property */
8872 mm_attrs_get_int_by_name(attrs, "pcm_extraction", &sound_extraction);
8874 if ( ! sound_extraction || is_drm )
8876 debug_log("pcm extraction param.. is drm = %d, extraction mode = %d", is_drm, sound_extraction);
8886 __mmplayer_handle_gst_error ( mm_player_t* player, GstMessage * message, GError* error )
8888 MMMessageParamType msg_param;
8889 gchar *msg_src_element;
8893 return_val_if_fail( player, FALSE );
8894 return_val_if_fail( error, FALSE );
8896 /* NOTE : do somthing necessary inside of __gst_handle_XXX_error. not here */
8898 memset (&msg_param, 0, sizeof(MMMessageParamType));
8900 if ( error->domain == GST_CORE_ERROR )
8902 msg_param.code = __gst_handle_core_error( player, error->code );
8904 else if ( error->domain == GST_LIBRARY_ERROR )
8906 msg_param.code = __gst_handle_library_error( player, error->code );
8908 else if ( error->domain == GST_RESOURCE_ERROR )
8910 msg_param.code = __gst_handle_resource_error( player, error->code );
8912 else if ( error->domain == GST_STREAM_ERROR )
8914 msg_param.code = __gst_handle_stream_error( player, error, message );
8918 debug_warning("This error domain is not defined.\n");
8920 /* we treat system error as an internal error */
8921 msg_param.code = MM_ERROR_PLAYER_INVALID_STREAM;
8926 msg_src_element = GST_ELEMENT_NAME( GST_ELEMENT_CAST( message->src ) );
8928 msg_param.data = (void *) error->message;
8930 debug_error("-Msg src : [%s] Domain : [%s] Error : [%s] Code : [%d] is tranlated to error code : [0x%x]\n",
8931 msg_src_element, g_quark_to_string (error->domain), error->message, error->code, msg_param.code);
8934 /* post error to application */
8935 if ( ! player->posted_msg )
8937 if (msg_param.code == MM_MESSAGE_DRM_NOT_AUTHORIZED)
8939 MMPLAYER_POST_MSG( player, MM_MESSAGE_DRM_NOT_AUTHORIZED, NULL );
8943 MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param );
8946 /* don't post more if one was sent already */
8947 player->posted_msg = TRUE;
8951 debug_log("skip error post because it's sent already.\n");
8960 __mmplayer_handle_streaming_error ( mm_player_t* player, GstMessage * message )
8963 MMMessageParamType msg_param;
8964 gchar *msg_src_element = NULL;
8965 GstStructure *s = NULL;
8967 gchar *error_string = NULL;
8971 return_val_if_fail ( player, FALSE );
8972 return_val_if_fail ( message, FALSE );
8974 s = malloc( sizeof(GstStructure) );
8975 memcpy ( s, gst_message_get_structure ( message ), sizeof(GstStructure));
8977 if ( !gst_structure_get_uint (s, "error_id", &error_id) )
8978 error_id = MMPLAYER_STREAMING_ERROR_NONE;
8982 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
8983 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
8985 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
8986 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
8988 case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
8989 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
8991 case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
8992 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
8994 case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
8995 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
8997 case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
8998 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
9000 case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
9001 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
9003 case MMPLAYER_STREAMING_ERROR_INVALID_URL:
9004 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
9006 case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
9007 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
9009 case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
9010 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
9012 case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
9013 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
9015 case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
9016 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
9018 case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
9019 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
9021 case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
9022 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
9024 case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
9025 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
9027 case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
9028 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
9030 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
9031 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
9033 case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
9034 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
9036 case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
9037 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
9039 case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
9040 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
9042 case MMPLAYER_STREAMING_ERROR_GONE:
9043 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
9045 case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
9046 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
9048 case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
9049 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
9051 case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
9052 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
9054 case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
9055 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
9057 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
9058 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
9060 case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
9061 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
9063 case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
9064 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
9066 case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
9067 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
9069 case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
9070 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
9072 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
9073 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
9075 case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
9076 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
9078 case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
9079 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
9081 case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
9082 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
9084 case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
9085 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
9087 case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
9088 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
9090 case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
9091 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
9093 case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
9094 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
9096 case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
9097 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
9099 case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
9100 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
9102 case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
9103 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
9105 case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
9106 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
9108 case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
9109 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
9111 case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
9112 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
9114 case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
9115 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
9118 return MM_ERROR_PLAYER_STREAMING_FAIL;
9121 error_string = g_strdup(gst_structure_get_string (s, "error_string"));
9123 msg_param.data = (void *) error_string;
9127 msg_src_element = GST_ELEMENT_NAME( GST_ELEMENT_CAST( message->src ) );
9129 debug_error("-Msg src : [%s] Code : [%x] Error : [%s] \n",
9130 msg_src_element, msg_param.code, (char*)msg_param.data );
9133 /* post error to application */
9134 if ( ! player->posted_msg )
9136 MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param );
9138 /* don't post more if one was sent already */
9139 player->posted_msg = TRUE;
9143 debug_log("skip error post because it's sent already.\n");
9153 __gst_handle_core_error( mm_player_t* player, int code )
9155 gint trans_err = MM_ERROR_NONE;
9159 return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9163 case GST_CORE_ERROR_STATE_CHANGE:
9164 case GST_CORE_ERROR_MISSING_PLUGIN:
9165 case GST_CORE_ERROR_SEEK:
9166 case GST_CORE_ERROR_NOT_IMPLEMENTED:
9167 case GST_CORE_ERROR_FAILED:
9168 case GST_CORE_ERROR_TOO_LAZY:
9169 case GST_CORE_ERROR_PAD:
9170 case GST_CORE_ERROR_THREAD:
9171 case GST_CORE_ERROR_NEGOTIATION:
9172 case GST_CORE_ERROR_EVENT:
9173 case GST_CORE_ERROR_CAPS:
9174 case GST_CORE_ERROR_TAG:
9175 case GST_CORE_ERROR_CLOCK:
9176 case GST_CORE_ERROR_DISABLED:
9178 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
9188 __gst_handle_library_error( mm_player_t* player, int code )
9190 gint trans_err = MM_ERROR_NONE;
9194 return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9198 case GST_LIBRARY_ERROR_FAILED:
9199 case GST_LIBRARY_ERROR_TOO_LAZY:
9200 case GST_LIBRARY_ERROR_INIT:
9201 case GST_LIBRARY_ERROR_SHUTDOWN:
9202 case GST_LIBRARY_ERROR_SETTINGS:
9203 case GST_LIBRARY_ERROR_ENCODE:
9205 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
9216 __gst_handle_resource_error( mm_player_t* player, int code )
9218 gint trans_err = MM_ERROR_NONE;
9222 return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9226 case GST_RESOURCE_ERROR_NO_SPACE_LEFT:
9227 trans_err = MM_ERROR_PLAYER_NO_FREE_SPACE;
9229 case GST_RESOURCE_ERROR_NOT_FOUND:
9230 case GST_RESOURCE_ERROR_OPEN_READ:
9231 if ( MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING ( player ) )
9233 trans_err = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
9236 case GST_RESOURCE_ERROR_READ:
9237 if ( MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING ( player ))
9239 trans_err = MM_ERROR_PLAYER_STREAMING_FAIL;
9242 case GST_RESOURCE_ERROR_SEEK:
9243 case GST_RESOURCE_ERROR_FAILED:
9244 case GST_RESOURCE_ERROR_TOO_LAZY:
9245 case GST_RESOURCE_ERROR_BUSY:
9246 case GST_RESOURCE_ERROR_OPEN_WRITE:
9247 case GST_RESOURCE_ERROR_OPEN_READ_WRITE:
9248 case GST_RESOURCE_ERROR_CLOSE:
9249 case GST_RESOURCE_ERROR_WRITE:
9250 case GST_RESOURCE_ERROR_SYNC:
9251 case GST_RESOURCE_ERROR_SETTINGS:
9253 trans_err = MM_ERROR_PLAYER_FILE_NOT_FOUND;
9264 __gst_handle_stream_error( mm_player_t* player, GError* error, GstMessage * message )
9266 gint trans_err = MM_ERROR_NONE;
9270 return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9271 return_val_if_fail( error, MM_ERROR_INVALID_ARGUMENT );
9272 return_val_if_fail ( message, MM_ERROR_INVALID_ARGUMENT );
9274 switch ( error->code )
9276 case GST_STREAM_ERROR_FAILED:
9277 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
9278 case GST_STREAM_ERROR_DECODE:
9279 case GST_STREAM_ERROR_WRONG_TYPE:
9280 case GST_STREAM_ERROR_DECRYPT:
9281 trans_err = __gst_transform_gsterror( player, message, error );
9284 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
9285 case GST_STREAM_ERROR_NOT_IMPLEMENTED:
9286 case GST_STREAM_ERROR_TOO_LAZY:
9287 case GST_STREAM_ERROR_ENCODE:
9288 case GST_STREAM_ERROR_DEMUX:
9289 case GST_STREAM_ERROR_MUX:
9290 case GST_STREAM_ERROR_FORMAT:
9291 case GST_STREAM_ERROR_DECRYPT_NOKEY:
9293 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
9303 /* NOTE : decide gstreamer state whether there is some playable track or not. */
9305 __gst_transform_gsterror( mm_player_t* player, GstMessage * message, GError* error )
9307 gchar *src_element_name = NULL;
9308 GstElement *src_element = NULL;
9309 GstElementFactory *factory = NULL;
9310 const gchar* klass = NULL;
9315 return_val_if_fail ( message, MM_ERROR_INVALID_ARGUMENT );
9316 return_val_if_fail ( message->src, MM_ERROR_INVALID_ARGUMENT );
9317 return_val_if_fail ( error, MM_ERROR_INVALID_ARGUMENT );
9319 src_element = GST_ELEMENT_CAST(message->src);
9321 goto INTERNAL_ERROR;
9323 src_element_name = GST_ELEMENT_NAME(src_element);
9324 if ( !src_element_name )
9325 goto INTERNAL_ERROR;
9327 factory = gst_element_get_factory(src_element);
9329 goto INTERNAL_ERROR;
9331 klass = gst_element_factory_get_klass(factory);
9333 goto INTERNAL_ERROR;
9335 debug_log("error code=%d, msg=%s, src element=%s, class=%s\n",
9336 error->code, error->message, src_element_name, klass);
9339 switch ( error->code )
9341 case GST_STREAM_ERROR_DECODE:
9343 /* NOTE : Delay is needed because gst callback is sometime sent
9344 * before completing autoplugging.
9345 * Timer is more better than usleep.
9346 * But, transformed msg value should be stored in player handle
9347 * for function to call by timer.
9349 if ( PLAYER_INI()->async_start )
9352 /* Demuxer can't parse one track because it's corrupted.
9353 * So, the decoder for it is not linked.
9354 * But, it has one playable track.
9356 if ( g_strrstr(klass, "Demux") )
9358 if ( player->can_support_codec == FOUND_PLUGIN_VIDEO )
9360 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9362 else if ( player->can_support_codec == FOUND_PLUGIN_AUDIO )
9364 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
9368 if ( player->pipeline->audiobin ) // PCM
9370 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
9374 goto CODEC_NOT_FOUND;
9378 return MM_ERROR_PLAYER_INVALID_STREAM;
9382 case GST_STREAM_ERROR_WRONG_TYPE:
9384 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
9388 case GST_STREAM_ERROR_FAILED:
9390 /* Decoder Custom Message */
9391 if ( strstr(error->message, "ongoing") )
9393 if ( strcasestr(klass, "audio") )
9395 if ( ( player->can_support_codec & FOUND_PLUGIN_VIDEO ) )
9397 debug_log("Video can keep playing.\n");
9398 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9402 goto CODEC_NOT_FOUND;
9406 else if ( strcasestr(klass, "video") )
9408 if ( ( player->can_support_codec & FOUND_PLUGIN_AUDIO ) )
9410 debug_log("Audio can keep playing.\n");
9411 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
9415 goto CODEC_NOT_FOUND;
9419 return MM_ERROR_PLAYER_INVALID_STREAM;
9423 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
9425 goto CODEC_NOT_FOUND;
9429 case GST_STREAM_ERROR_DECRYPT:
9431 debug_log("%s failed reason : %s\n", src_element_name, error->message);
9432 return MM_MESSAGE_DRM_NOT_AUTHORIZED;
9442 return MM_ERROR_PLAYER_INVALID_STREAM;
9445 return MM_ERROR_PLAYER_INTERNAL;
9448 debug_log("not found any available codec. Player should be destroyed.\n");
9449 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9453 __mmplayer_post_delayed_eos( mm_player_t* player, int delay_in_ms )
9457 return_if_fail( player );
9459 /* cancel if existing */
9460 __mmplayer_cancel_delayed_eos( player );
9463 /* post now if delay is zero */
9464 if ( delay_in_ms == 0 || player->is_sound_extraction)
9466 debug_log("eos delay is zero. posting EOS now\n");
9467 MMPLAYER_POST_MSG( player, MM_MESSAGE_END_OF_STREAM, NULL );
9469 if ( player->is_sound_extraction )
9470 __mmplayer_cancel_delayed_eos(player);
9475 /* init new timeout */
9476 /* NOTE : consider give high priority to this timer */
9478 debug_log("posting EOS message after [%d] msec\n", delay_in_ms);
9479 player->eos_timer = g_timeout_add( delay_in_ms,
9480 __mmplayer_eos_timer_cb, player );
9483 /* check timer is valid. if not, send EOS now */
9484 if ( player->eos_timer == 0 )
9486 debug_warning("creating timer for delayed EOS has failed. sending EOS now\n");
9487 MMPLAYER_POST_MSG( player, MM_MESSAGE_END_OF_STREAM, NULL );
9494 __mmplayer_cancel_delayed_eos( mm_player_t* player )
9498 return_if_fail( player );
9500 if ( player->eos_timer )
9502 g_source_remove( player->eos_timer );
9505 player->eos_timer = 0;
9513 __mmplayer_eos_timer_cb(gpointer u_data)
9515 mm_player_t* player = NULL;
9516 player = (mm_player_t*) u_data;
9520 return_val_if_fail( player, FALSE );
9523 MMPLAYER_POST_MSG( player, MM_MESSAGE_END_OF_STREAM, NULL );
9525 /* cleare timer id */
9526 player->eos_timer = 0;
9530 /* we are returning FALSE as we need only one posting */
9534 static void __mmplayer_set_antishock( mm_player_t* player, gboolean disable_by_force)
9536 gint antishock = FALSE;
9537 MMHandleType attrs = 0;
9541 return_if_fail ( player && player->pipeline );
9543 /* It should be passed for video only clip */
9544 if ( ! player->pipeline->audiobin )
9547 if ( ( g_strrstr(PLAYER_INI()->name_of_audiosink, "avsysaudiosink")) )
9549 attrs = MMPLAYER_GET_ATTRS(player);
9552 debug_error("fail to get attributes.\n");
9556 mm_attrs_get_int_by_name(attrs, "sound_fadeup", &antishock);
9558 debug_log("setting antishock as (%d)\n", antishock);
9560 if ( disable_by_force )
9562 debug_log("but, antishock is disabled by force when is seeked\n");
9567 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "fadeup", antishock, NULL);
9577 __mmplayer_link_decoder( mm_player_t* player, GstPad *srcpad)
9579 const gchar* name = NULL;
9580 GstStructure* str = NULL;
9581 GstCaps* srccaps = NULL;
9585 return_val_if_fail( player, FALSE );
9586 return_val_if_fail ( srcpad, FALSE );
9588 /* to check any of the decoder (video/audio) need to be linked to parser*/
9589 srccaps = gst_pad_get_caps( srcpad );
9593 str = gst_caps_get_structure( srccaps, 0 );
9597 name = gst_structure_get_name(str);
9601 if (strstr(name, "video"))
9603 if(player->videodec_linked)
9605 debug_msg("Video decoder already linked\n");
9609 if (strstr(name, "audio"))
9611 if(player->audiodec_linked)
9613 debug_msg("Audio decoder already linked\n");
9618 gst_caps_unref( srccaps );
9626 gst_caps_unref( srccaps );
9632 __mmplayer_link_sink( mm_player_t* player , GstPad *srcpad)
9634 const gchar* name = NULL;
9635 GstStructure* str = NULL;
9636 GstCaps* srccaps = NULL;
9640 return_val_if_fail ( player, FALSE );
9641 return_val_if_fail ( srcpad, FALSE );
9643 /* to check any of the decoder (video/audio) need to be linked to parser*/
9644 srccaps = gst_pad_get_caps( srcpad );
9648 str = gst_caps_get_structure( srccaps, 0 );
9652 name = gst_structure_get_name(str);
9656 if (strstr(name, "video"))
9658 if(player->videosink_linked)
9660 debug_msg("Video Sink already linked\n");
9664 if (strstr(name, "audio"))
9666 if(player->audiosink_linked)
9668 debug_msg("Audio Sink already linked\n");
9672 if (strstr(name, "text"))
9674 if(player->textsink_linked)
9676 debug_msg("Text Sink already linked\n");
9681 gst_caps_unref( srccaps );
9686 //return (!player->videosink_linked || !player->audiosink_linked);
9690 gst_caps_unref( srccaps );
9696 /* sending event to one of sinkelements */
9698 __gst_send_event_to_sink( mm_player_t* player, GstEvent* event )
9700 GList *sinks = NULL;
9701 gboolean res = FALSE;
9705 return_val_if_fail( player, FALSE );
9706 return_val_if_fail ( event, FALSE );
9708 sinks = player->sink_elements;
9711 GstElement *sink = GST_ELEMENT_CAST (sinks->data);
9713 if (GST_IS_ELEMENT(sink))
9715 /* keep ref to the event */
9716 gst_event_ref (event);
9718 if ( (res = gst_element_send_event (sink, event)) )
9720 debug_log("sending event[%s] to sink element [%s] success!\n",
9721 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink) );
9725 debug_log("sending event[%s] to sink element [%s] failed. try with next one.\n",
9726 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink) );
9729 sinks = g_list_next (sinks);
9732 /* Note : Textbin is not linked to the video or audio bin.
9733 * It needs to send the event to the text sink seperatelly.
9735 if ( MMPLAYER_PLAY_SUBTITLE(player) )
9737 GstElement *subtitle_sink = GST_ELEMENT_CAST (player->pipeline->subtitlebin[MMPLAYER_SUB_SINK].gst);
9739 if ( (res != gst_element_send_event (subtitle_sink, event)) )
9741 debug_error("sending event[%s] to subtitle sink element [%s] failed!\n",
9742 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(subtitle_sink) );
9746 debug_log("sending event[%s] to subtitle sink element [%s] success!\n",
9747 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(subtitle_sink) );
9751 gst_event_unref (event);
9759 __mmplayer_add_sink( mm_player_t* player, GstElement* sink )
9763 return_if_fail ( player );
9764 return_if_fail ( sink );
9766 player->sink_elements =
9767 g_list_append(player->sink_elements, sink);
9773 __mmplayer_del_sink( mm_player_t* player, GstElement* sink )
9777 return_if_fail ( player );
9778 return_if_fail ( sink );
9780 player->sink_elements =
9781 g_list_remove(player->sink_elements, sink);
9787 __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
9788 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
9789 gint64 cur, GstSeekType stop_type, gint64 stop )
9791 GstEvent* event = NULL;
9792 gboolean result = FALSE;
9796 return_val_if_fail( player, FALSE );
9798 event = gst_event_new_seek (rate, format, flags, cur_type,
9799 cur, stop_type, stop);
9801 result = __gst_send_event_to_sink( player, event );
9808 /* NOTE : be careful with calling this api. please refer to below glib comment
9809 * glib comment : Note that there is a bug in GObject that makes this function much
9810 * less useful than it might seem otherwise. Once gobject is disposed, the callback
9811 * will no longer be called, but, the signal handler is not currently disconnected.
9812 * If the instance is itself being freed at the same time than this doesn't matter,
9813 * since the signal will automatically be removed, but if instance persists,
9814 * then the signal handler will leak. You should not remove the signal yourself
9815 * because in a future versions of GObject, the handler will automatically be
9818 * It's possible to work around this problem in a way that will continue to work
9819 * with future versions of GObject by checking that the signal handler is still
9820 * connected before disconnected it:
9822 * if (g_signal_handler_is_connected (instance, id))
9823 * g_signal_handler_disconnect (instance, id);
9826 __mmplayer_release_signal_connection(mm_player_t* player)
9828 GList* sig_list = player->signals;
9829 MMPlayerSignalItem* item = NULL;
9833 return_if_fail( player );
9835 for ( ; sig_list; sig_list = sig_list->next )
9837 item = sig_list->data;
9839 if ( item && item->obj && GST_IS_ELEMENT(item->obj) )
9841 debug_log("checking signal connection : [%lud] from [%s]\n", item->sig, GST_OBJECT_NAME( item->obj ));
9843 if ( g_signal_handler_is_connected ( item->obj, item->sig ) )
9845 debug_log("signal disconnecting : [%lud] from [%s]\n", item->sig, GST_OBJECT_NAME( item->obj ));
9846 g_signal_handler_disconnect ( item->obj, item->sig );
9850 MMPLAYER_FREEIF( item );
9853 g_list_free ( player->signals );
9854 player->signals = NULL;
9862 /* Note : if silent is true, then subtitle would not be displayed. :*/
9863 int _mmplayer_set_subtitle_silent (MMHandleType hplayer, int silent)
9865 mm_player_t* player = (mm_player_t*) hplayer;
9869 /* check player handle */
9870 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9871 return_val_if_fail ( MMPLAYER_PLAY_SUBTITLE(player), MM_ERROR_PLAYER_NOT_INITIALIZED );
9873 player->is_subtitle_off = silent;
9875 debug_log("subtitle is %s.\n", player->is_subtitle_off ? "ON" : "OFF");
9879 return MM_ERROR_NONE;
9883 int _mmplayer_get_subtitle_silent (MMHandleType hplayer, int* silent)
9885 mm_player_t* player = (mm_player_t*) hplayer;
9889 /* check player handle */
9890 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9891 return_val_if_fail ( MMPLAYER_PLAY_SUBTITLE(player), MM_ERROR_PLAYER_NOT_INITIALIZED );
9893 *silent = player->is_subtitle_off;
9895 debug_log("subtitle is %s.\n", silent ? "ON" : "OFF");
9899 return MM_ERROR_NONE;
9902 int _mmplayer_get_track_count(MMHandleType hplayer, MMPlayerTrackType track_type, int *count)
9904 mm_player_t* player = (mm_player_t*) hplayer;
9905 MMHandleType attrs = 0;
9906 int ret = MM_ERROR_NONE;
9910 /* check player handle */
9911 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9912 return_val_if_fail(count, MM_ERROR_COMMON_INVALID_ARGUMENT);
9913 return_val_if_fail((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
9914 ||(MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING),
9915 MM_ERROR_PLAYER_INVALID_STATE);
9917 attrs = MMPLAYER_GET_ATTRS(player);
9920 debug_error("cannot get content attribute");
9921 return MM_ERROR_PLAYER_INTERNAL;
9926 case MM_PLAYER_TRACK_TYPE_AUDIO:
9927 ret = mm_attrs_get_int_by_name(attrs, "content_audio_track_num", count);
9929 case MM_PLAYER_TRACK_TYPE_VIDEO:
9930 ret = mm_attrs_get_int_by_name(attrs, "content_video_track_num", count);
9932 case MM_PLAYER_TRACK_TYPE_TEXT:
9933 ret = mm_attrs_get_int_by_name(attrs, "content_text_track_num", count);
9936 ret = MM_ERROR_COMMON_INVALID_ARGUMENT;
9940 debug_log ("%d track num is %d\n", track_type, *count);
9950 __get_state_name ( int state )
9954 case MM_PLAYER_STATE_NULL:
9956 case MM_PLAYER_STATE_READY:
9958 case MM_PLAYER_STATE_PAUSED:
9960 case MM_PLAYER_STATE_PLAYING:
9962 case MM_PLAYER_STATE_NONE:
9969 __is_rtsp_streaming ( mm_player_t* player )
9971 return_val_if_fail ( player, FALSE );
9973 return ( player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_RTSP ) ? TRUE : FALSE;
9977 __is_http_streaming ( mm_player_t* player )
9979 return_val_if_fail ( player, FALSE );
9981 return ( player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_HTTP ) ? TRUE : FALSE;
9985 __is_streaming ( mm_player_t* player )
9987 return_val_if_fail ( player, FALSE );
9989 return ( __is_rtsp_streaming ( player ) || __is_http_streaming ( player ) || __is_http_live_streaming ( player )) ? TRUE : FALSE;
9993 __is_live_streaming ( mm_player_t* player )
9995 return_val_if_fail ( player, FALSE );
9997 return ( __is_rtsp_streaming ( player ) && player->streaming_type == STREAMING_SERVICE_LIVE ) ? TRUE : FALSE;
10001 __is_http_live_streaming( mm_player_t* player )
10003 return_val_if_fail( player, FALSE );
10005 return ( player->profile.uri_type == MM_PLAYER_URI_TYPE_HLS ) ? TRUE : FALSE;
10009 __is_http_progressive_down(mm_player_t* player)
10011 return_val_if_fail( player, FALSE );
10013 return ((player->pd_mode) ? TRUE:FALSE);