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) )
91 #define LAZY_PAUSE_TIMEOUT_MSEC 700
93 /*---------------------------------------------------------------------------
94 | LOCAL CONSTANT DEFINITIONS: |
95 ---------------------------------------------------------------------------*/
97 /*---------------------------------------------------------------------------
98 | LOCAL DATA TYPE DEFINITIONS: |
99 ---------------------------------------------------------------------------*/
101 /*---------------------------------------------------------------------------
102 | GLOBAL VARIABLE DEFINITIONS: |
103 ---------------------------------------------------------------------------*/
105 /*---------------------------------------------------------------------------
106 | LOCAL VARIABLE DEFINITIONS: |
107 ---------------------------------------------------------------------------*/
109 /*---------------------------------------------------------------------------
110 | LOCAL FUNCTION PROTOTYPES: |
111 ---------------------------------------------------------------------------*/
112 static gboolean __mmplayer_set_state(mm_player_t* player, int state);
113 static int __mmplayer_get_state(mm_player_t* player);
114 static int __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps *caps, MMDisplaySurfaceType surface_type);
115 static int __mmplayer_gst_create_audio_pipeline(mm_player_t* player);
116 static int __mmplayer_gst_create_text_pipeline(mm_player_t* player);
117 static int __mmplayer_gst_create_subtitle_src(mm_player_t* player);
118 static int __mmplayer_gst_create_pipeline(mm_player_t* player);
119 static int __mmplayer_gst_destroy_pipeline(mm_player_t* player);
120 static int __mmplayer_gst_element_link_bucket(GList* element_bucket);
122 static gboolean __mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data);
123 static void __mmplayer_gst_decode_callback(GstElement *decodebin, GstPad *pad, gboolean last, gpointer data);
125 static void __mmplayer_typefind_have_type( GstElement *tf, guint probability, GstCaps *caps, gpointer data);
126 static gboolean __mmplayer_try_to_plug(mm_player_t* player, GstPad *pad, const GstCaps *caps);
127 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
128 static gboolean __mmplayer_is_midi_type(gchar* str_caps);
129 static gboolean __mmplayer_is_amr_type (gchar *str_caps);
130 static gboolean __mmplayer_is_only_mp3_type (gchar *str_caps);
132 static gboolean __mmplayer_close_link(mm_player_t* player, GstPad *srcpad, GstElement *sinkelement, const char *padname, const GList *templlist);
133 static gboolean __mmplayer_feature_filter(GstPluginFeature *feature, gpointer data);
134 static void __mmplayer_add_new_pad(GstElement *element, GstPad *pad, gpointer data);
136 static void __mmplayer_gst_rtp_no_more_pads (GstElement *element, gpointer data);
137 static void __mmplayer_gst_rtp_dynamic_pad (GstElement *element, GstPad *pad, gpointer data);
138 static gboolean __mmplayer_update_stream_service_type( mm_player_t* player );
139 static gboolean __mmplayer_update_subtitle( GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
142 static void __mmplayer_init_factories(mm_player_t* player);
143 static void __mmplayer_release_factories(mm_player_t* player);
144 static void __mmplayer_release_misc(mm_player_t* player);
145 static gboolean __mmplayer_gstreamer_init(void);
147 static int __mmplayer_gst_set_state (mm_player_t* player, GstElement * pipeline, GstState state, gboolean async, gint timeout );
148 gboolean __mmplayer_post_message(mm_player_t* player, enum MMMessageType msgtype, MMMessageParamType* param);
149 static gboolean __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage *msg);
150 int __mmplayer_switch_audio_sink (mm_player_t* player);
151 static gboolean __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink);
152 static int __mmplayer_check_state(mm_player_t* player, enum PlayerCommandState command);
153 static gboolean __mmplayer_audio_stream_probe (GstPad *pad, GstBuffer *buffer, gpointer u_data);
155 static gboolean __mmplayer_dump_pipeline_state( mm_player_t* player );
156 static gboolean __mmplayer_check_subtitle( mm_player_t* player );
157 static gboolean __mmplayer_handle_gst_error ( mm_player_t* player, GstMessage * message, GError* error );
158 static gboolean __mmplayer_handle_streaming_error ( mm_player_t* player, GstMessage * message );
159 static void __mmplayer_post_delayed_eos( mm_player_t* player, int delay_in_ms );
160 static void __mmplayer_cancel_delayed_eos( mm_player_t* player );
161 static gboolean __mmplayer_eos_timer_cb(gpointer u_data);
162 static gboolean __mmplayer_link_decoder( mm_player_t* player,GstPad *srcpad);
163 static gboolean __mmplayer_link_sink( mm_player_t* player,GstPad *srcpad);
164 static int __mmplayer_post_missed_plugin(mm_player_t* player);
165 static int __mmplayer_check_not_supported_codec(mm_player_t* player, gchar* mime);
166 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player);
167 static void __mmplayer_add_sink( mm_player_t* player, GstElement* sink);
168 static void __mmplayer_del_sink( mm_player_t* player, GstElement* sink);
169 static void __mmplayer_release_signal_connection(mm_player_t* player);
170 static void __mmplayer_set_antishock( mm_player_t* player, gboolean disable_by_force);
171 static gpointer __mmplayer_repeat_thread(gpointer data);
172 int _mmplayer_get_track_count(MMHandleType hplayer, MMPlayerTrackType track_type, int *count);
174 static int __gst_realize(mm_player_t* player);
175 static int __gst_unrealize(mm_player_t* player);
176 static int __gst_start(mm_player_t* player);
177 static int __gst_stop(mm_player_t* player);
178 static int __gst_pause(mm_player_t* player, gboolean async);
179 static int __gst_resume(mm_player_t* player, gboolean async);
180 static gboolean __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
181 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
182 gint64 cur, GstSeekType stop_type, gint64 stop );
183 static int __gst_pending_seek ( mm_player_t* player );
185 static int __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called);
186 static int __gst_get_position(mm_player_t* player, int format, unsigned long *position);
187 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos);
188 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position);
189 static int __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param);
190 static void __gst_set_async_state_change(mm_player_t* player, gboolean async);
192 static gint __gst_handle_core_error( mm_player_t* player, int code );
193 static gint __gst_handle_library_error( mm_player_t* player, int code );
194 static gint __gst_handle_resource_error( mm_player_t* player, int code );
195 static gint __gst_handle_stream_error( mm_player_t* player, GError* error, GstMessage * message );
196 static gint __gst_transform_gsterror( mm_player_t* player, GstMessage * message, GError* error);
197 static gboolean __gst_send_event_to_sink( mm_player_t* player, GstEvent* event );
199 static int __mmplayer_set_pcm_extraction(mm_player_t* player);
200 static gboolean __mmplayer_can_extract_pcm( mm_player_t* player );
203 static void __mmplayer_do_sound_fadedown(mm_player_t* player, unsigned int time);
204 static void __mmplayer_undo_sound_fadedown(mm_player_t* player);
206 static void __mmplayer_add_new_caps(GstPad* pad, GParamSpec* unused, gpointer data);
207 static void __mmplayer_set_unlinked_mime_type(mm_player_t* player, GstCaps *caps);
210 const gchar * __get_state_name ( int state );
211 static gboolean __is_streaming( mm_player_t* player );
212 static gboolean __is_rtsp_streaming( mm_player_t* player );
213 static gboolean __is_live_streaming ( mm_player_t* player );
214 static gboolean __is_http_streaming( mm_player_t* player );
215 static gboolean __is_http_live_streaming( mm_player_t* player );
216 static gboolean __is_http_progressive_down(mm_player_t* player);
218 static gboolean __mmplayer_warm_up_video_codec( mm_player_t* player, GstElementFactory *factory);
219 static GstBusSyncReply __mmplayer_bus_sync_callback (GstBus * bus, GstMessage * message, gpointer data);
221 static int __mmplayer_realize_streaming_ext(mm_player_t* player);
222 static int __mmplayer_unrealize_streaming_ext(mm_player_t *player);
223 static int __mmplayer_start_streaming_ext(mm_player_t *player);
224 static int __mmplayer_destroy_streaming_ext(mm_player_t* player);
227 /*===========================================================================================
229 | FUNCTION DEFINITIONS |
231 ========================================================================================== */
233 /* implementing player FSM */
234 /* FIXIT : We need to handle state transition also at here since start api is no more sync */
236 __mmplayer_check_state(mm_player_t* player, enum PlayerCommandState command)
238 MMPlayerStateType current_state = MM_PLAYER_STATE_NUM;
239 MMPlayerStateType pending_state = MM_PLAYER_STATE_NUM;
240 MMPlayerStateType target_state = MM_PLAYER_STATE_NUM;
241 MMPlayerStateType prev_state = MM_PLAYER_STATE_NUM;
245 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
247 //debug_log("incomming command : %d \n", command );
249 current_state = MMPLAYER_CURRENT_STATE(player);
250 pending_state = MMPLAYER_PENDING_STATE(player);
251 target_state = MMPLAYER_TARGET_STATE(player);
252 prev_state = MMPLAYER_PREV_STATE(player);
254 MMPLAYER_PRINT_STATE(player);
258 case MMPLAYER_COMMAND_CREATE:
260 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
262 if ( current_state == MM_PLAYER_STATE_NULL ||
263 current_state == MM_PLAYER_STATE_READY ||
264 current_state == MM_PLAYER_STATE_PAUSED ||
265 current_state == MM_PLAYER_STATE_PLAYING )
270 case MMPLAYER_COMMAND_DESTROY:
272 /* destroy can called anytime */
274 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
278 case MMPLAYER_COMMAND_REALIZE:
280 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
282 if ( pending_state != MM_PLAYER_STATE_NONE )
288 /* need ready state to realize */
289 if ( current_state == MM_PLAYER_STATE_READY )
292 if ( current_state != MM_PLAYER_STATE_NULL )
298 case MMPLAYER_COMMAND_UNREALIZE:
300 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
302 if ( current_state == MM_PLAYER_STATE_NULL )
307 case MMPLAYER_COMMAND_START:
309 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
311 if ( pending_state == MM_PLAYER_STATE_NONE )
313 if ( current_state == MM_PLAYER_STATE_PLAYING )
315 else if ( current_state != MM_PLAYER_STATE_READY &&
316 current_state != MM_PLAYER_STATE_PAUSED )
319 else if ( pending_state == MM_PLAYER_STATE_PLAYING )
323 else if ( pending_state == MM_PLAYER_STATE_PAUSED )
325 debug_log("player is going to paused state, just change the pending state as playing");
334 case MMPLAYER_COMMAND_STOP:
336 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
338 if ( current_state == MM_PLAYER_STATE_READY )
341 /* need playing/paused state to stop */
342 if ( current_state != MM_PLAYER_STATE_PLAYING &&
343 current_state != MM_PLAYER_STATE_PAUSED )
348 case MMPLAYER_COMMAND_PAUSE:
350 if ( MMPLAYER_IS_LIVE_STREAMING( player ) )
353 if (player->doing_seek)
354 goto NOT_COMPLETED_SEEK;
356 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
358 if ( pending_state == MM_PLAYER_STATE_NONE )
360 if ( current_state == MM_PLAYER_STATE_PAUSED )
362 else if ( current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY ) // support loading state of broswer
365 else if ( pending_state == MM_PLAYER_STATE_PAUSED )
369 else if ( pending_state == MM_PLAYER_STATE_PLAYING )
371 if ( current_state == MM_PLAYER_STATE_PAUSED ) {
372 debug_log("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
380 case MMPLAYER_COMMAND_RESUME:
382 if ( MMPLAYER_IS_LIVE_STREAMING(player) )
385 if (player->doing_seek)
386 goto NOT_COMPLETED_SEEK;
388 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
390 if ( pending_state == MM_PLAYER_STATE_NONE )
392 if ( current_state == MM_PLAYER_STATE_PLAYING )
394 else if ( current_state != MM_PLAYER_STATE_PAUSED )
397 else if ( pending_state == MM_PLAYER_STATE_PLAYING )
401 else if ( pending_state == MM_PLAYER_STATE_PAUSED )
403 debug_log("player is going to paused state, just change the pending state as playing");
415 player->cmd = command;
418 return MM_ERROR_NONE;
421 debug_warning("since player is in wrong state(%s). it's not able to apply the command(%d)",
422 MMPLAYER_STATE_GET_NAME(current_state), command);
423 return MM_ERROR_PLAYER_INVALID_STATE;
426 debug_warning("not completed seek");
427 return MM_ERROR_PLAYER_DOING_SEEK;
430 debug_warning("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
431 return MM_ERROR_PLAYER_NO_OP;
434 debug_warning("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
435 return MM_ERROR_PLAYER_NO_OP;
439 __mmplayer_gst_set_state (mm_player_t* player, GstElement * element, GstState state, gboolean async, gint timeout) // @
441 GstState element_state = GST_STATE_VOID_PENDING;
442 GstState element_pending_state = GST_STATE_VOID_PENDING;
443 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
447 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
448 return_val_if_fail ( element, MM_ERROR_INVALID_ARGUMENT );
450 debug_log("setting [%s] element state to : %d\n", GST_ELEMENT_NAME(element), state);
453 ret = gst_element_set_state(element, state);
455 if ( ret == GST_STATE_CHANGE_FAILURE )
457 debug_error("failed to set [%s] state to [%d]\n", GST_ELEMENT_NAME(element), state);
458 return MM_ERROR_PLAYER_INTERNAL;
461 /* return here so state transition to be done in async mode */
464 debug_log("async state transition. not waiting for state complete.\n");
465 return MM_ERROR_NONE;
468 /* wait for state transition */
469 ret = gst_element_get_state( element, &element_state, &element_pending_state, timeout * GST_SECOND );
471 if ( ret == GST_STATE_CHANGE_FAILURE || ( state != element_state ) )
473 debug_error("failed to change [%s] element state to [%s] within %d sec\n",
474 GST_ELEMENT_NAME(element),
475 gst_element_state_get_name(state), timeout );
477 debug_error(" [%s] state : %s pending : %s \n",
478 GST_ELEMENT_NAME(element),
479 gst_element_state_get_name(element_state),
480 gst_element_state_get_name(element_pending_state) );
482 return MM_ERROR_PLAYER_INTERNAL;
485 debug_log("[%s] element state has changed to %s \n",
486 GST_ELEMENT_NAME(element),
487 gst_element_state_get_name(element_state));
491 return MM_ERROR_NONE;
495 __mmplayer_videostream_cb(GstElement *element, void *stream,
496 int width, int height, gpointer data) // @
498 mm_player_t* player = (mm_player_t*)data;
501 return_if_fail ( player );
505 if (player->video_stream_cb )
507 length = width * height * 4; // for rgb 32bit
508 player->video_stream_cb(stream, length, player->video_stream_cb_user_param, width, height);
515 _mmplayer_update_content_attrs(mm_player_t* player) // @
517 GstFormat fmt = GST_FORMAT_TIME;
519 GstStructure* p = NULL;
520 MMHandleType attrs = 0;
521 gint retry_count = 0;
522 gint retry_count_max = 10;
526 return_val_if_fail ( player, FALSE );
528 if ( ! player->need_update_content_attrs )
530 debug_log("content attributes are already updated");
534 /* get content attribute first */
535 attrs = MMPLAYER_GET_ATTRS(player);
538 debug_error("cannot get content attribute");
543 * NOTE : we need to wait for a while until is possible to get duration from pipeline
544 * as getting duration timing is depends on behavier of demuxers ( or etc ).
545 * we set timeout 100ms * 10 as initial value. fix it if needed.
547 if ( player->need_update_content_dur )
549 while ( retry_count < retry_count_max)
551 if ( FALSE == gst_element_query_duration( player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
554 /* retry if failed */
555 debug_warning("failed to get duraton. waiting 100ms and then retrying...");
561 if ( dur_nsec == 0 && ( !MMPLAYER_IS_LIVE_STREAMING( player ) ) )
563 /* retry if duration is zero in case of not live stream */
564 debug_warning("returned duration is zero. but it's not an live stream. retrying...");
573 player->duration = dur_nsec;
574 debug_log("duration : %lld msec", GST_TIME_AS_MSECONDS(dur_nsec));
576 /* try to get streaming service type */
577 __mmplayer_update_stream_service_type( player );
579 /* check duration is OK */
580 if ( dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING( player ) )
582 /* FIXIT : find another way to get duration here. */
583 debug_error("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
587 player->need_update_content_dur = FALSE;
591 mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(dur_nsec));
595 debug_log("not ready to get duration or already updated");
598 /* update rate, channels */
599 if ( player->pipeline->audiobin &&
600 player->pipeline->audiobin[MMPLAYER_A_SINK].gst )
602 GstCaps *caps_a = NULL;
604 gint samplerate = 0, channels = 0;
606 pad = gst_element_get_static_pad(
607 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink" );
611 caps_a = gst_pad_get_negotiated_caps( pad );
615 p = gst_caps_get_structure (caps_a, 0);
617 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
618 if ( ! samplerate ) // check if update already or not
620 gst_structure_get_int (p, "rate", &samplerate);
621 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
623 gst_structure_get_int (p, "channels", &channels);
624 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
626 debug_log("samplerate : %d channels : %d", samplerate, channels);
628 gst_caps_unref( caps_a );
633 debug_warning("not ready to get audio caps");
636 gst_object_unref( pad );
640 debug_warning("failed to get pad from audiosink");
644 /* update width, height, framerate */
645 if ( player->pipeline->videobin &&
646 player->pipeline->videobin[MMPLAYER_V_SINK].gst )
648 GstCaps *caps_v = NULL;
653 pad = gst_element_get_static_pad( player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink" );
656 caps_v = gst_pad_get_negotiated_caps( pad );
659 p = gst_caps_get_structure (caps_v, 0);
660 gst_structure_get_int (p, "width", &width);
661 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
663 gst_structure_get_int (p, "height", &height);
664 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
666 gst_structure_get_fraction (p, "framerate", &tmpNu, &tmpDe);
668 debug_log("width : %d height : %d", width, height );
670 gst_caps_unref( caps_v );
675 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
676 debug_log("fps : %d", tmpNu / tmpDe);
681 debug_warning("failed to get negitiated caps from videosink");
683 gst_object_unref( pad );
688 debug_warning("failed to get pad from videosink");
692 if (player->duration)
694 guint64 data_size = 0;
696 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO))
698 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
700 if (stat(path, &sb) == 0)
702 data_size = (guint64)sb.st_size;
705 else if (MMPLAYER_IS_HTTP_STREAMING(player))
707 data_size = player->http_content_size;
713 guint64 msec_dur = 0;
715 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
716 bitrate = data_size * 8 * 1000 / msec_dur;
717 debug_log("file size : %u, video bitrate = %llu", data_size, bitrate);
718 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
724 if ( mmf_attrs_commit ( attrs ) )
726 debug_error("failed to update attributes\n");
730 player->need_update_content_attrs = FALSE;
735 gboolean __mmplayer_update_stream_service_type( mm_player_t* player )
737 MMHandleType attrs = 0;
738 gint streaming_type = STREAMING_SERVICE_NONE;
742 return_val_if_fail ( player &&
744 player->pipeline->mainbin &&
745 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
748 /* streaming service type if streaming */
749 if ( ! MMPLAYER_IS_STREAMING(player) );
752 if (MMPLAYER_IS_RTSP_STREAMING(player))
754 /* get property from rtspsrc element */
755 g_object_get(G_OBJECT(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), "service_type", &streaming_type, NULL);
757 else if (MMPLAYER_IS_HTTP_STREAMING(player))
759 if ( player->duration == 0)
760 streaming_type = STREAMING_SERVICE_LIVE;
762 streaming_type = STREAMING_SERVICE_VOD;
765 player->streaming_type = streaming_type;
767 if ( player->streaming_type == STREAMING_SERVICE_LIVE)
769 debug_log("It's live streaming. pause/resume/seek are not working.\n");
771 else if (player->streaming_type == STREAMING_SERVICE_LIVE)
773 debug_log("It's vod streaming. pause/resume/seek are working.\n");
777 debug_warning("fail to determine streaming type. pause/resume/seek may not working properly if stream is live stream\n");
780 /* get profile attribute */
781 attrs = MMPLAYER_GET_ATTRS(player);
784 debug_error("cannot get content attribute\n");
788 mm_attrs_set_int_by_name ( attrs, "streaming_type", streaming_type );
790 if ( mmf_attrs_commit ( attrs ) )
792 debug_warning("updating streaming service type failed. pause/resume/seek may not working properly if stream is live stream\n");
802 /* this function sets the player state and also report
803 * it to applicaton by calling callback function
806 __mmplayer_set_state(mm_player_t* player, int state) // @
808 MMMessageParamType msg = {0, };
809 int asm_result = MM_ERROR_NONE;
812 return_val_if_fail ( player, FALSE );
814 if ( MMPLAYER_CURRENT_STATE(player) == state )
816 debug_warning("already same state(%s)\n", MMPLAYER_STATE_GET_NAME(state));
817 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
821 /* post message to application */
822 if (MMPLAYER_TARGET_STATE(player) == state)
824 /* fill the message with state of player */
825 msg.state.previous = MMPLAYER_CURRENT_STATE(player);
826 msg.state.current = state;
828 /* state changed by asm callback */
829 if ( player->sm.by_asm_cb )
831 msg.union_type = MM_MSG_UNION_CODE;
832 msg.code = player->sm.event_src;
833 MMPLAYER_POST_MSG( player, MM_MESSAGE_STATE_INTERRUPTED, &msg );
835 /* state changed by usecase */
838 MMPLAYER_POST_MSG( player, MM_MESSAGE_STATE_CHANGED, &msg );
841 debug_log ("player reach the target state, then do something in each state(%s).\n",
842 MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
846 debug_log ("intermediate state, do nothing.\n");
847 MMPLAYER_PRINT_STATE(player);
852 /* update player states */
853 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
854 MMPLAYER_CURRENT_STATE(player) = state;
855 if ( MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player) )
856 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
859 MMPLAYER_PRINT_STATE(player);
861 switch ( MMPLAYER_TARGET_STATE(player) )
863 case MM_PLAYER_STATE_NULL:
864 case MM_PLAYER_STATE_READY:
866 if (player->cmd == MMPLAYER_COMMAND_STOP)
868 asm_result = _mmplayer_asm_set_state((MMHandleType)player, ASM_STATE_STOP);
869 if ( asm_result != MM_ERROR_NONE )
871 debug_error("failed to set asm state to stop\n");
878 case MM_PLAYER_STATE_PAUSED:
880 /* special care for local playback. normaly we can get some content attribute
881 * when the demuxer is changed to PAUSED. so we are trying it. it will be tried again
882 * when PLAYING state has signalled if failed.
883 * note that this is only happening pause command has come before the state of pipeline
884 * reach to the PLAYING.
886 if ( ! player->sent_bos )
888 player->need_update_content_attrs = TRUE;
889 player->need_update_content_dur = TRUE;
890 _mmplayer_update_content_attrs( player );
893 /* add audio callback probe if condition is satisfied */
894 if ( ! player->audio_cb_probe_id && player->is_sound_extraction )
895 __mmplayer_configure_audio_callback(player);
897 asm_result = _mmplayer_asm_set_state((MMHandleType)player, ASM_STATE_PAUSE);
900 debug_error("failed to set asm state to PAUSE\n");
906 case MM_PLAYER_STATE_PLAYING:
908 /* non-managed prepare case, should be updated */
909 if ( ! player->need_update_content_dur)
911 player->need_update_content_dur = TRUE;
912 _mmplayer_update_content_attrs ( player );
914 if (MMPLAYER_IS_STREAMING(player))
916 /* force setting value to TRUE for streaming */
917 player->need_update_content_attrs = TRUE;
918 _mmplayer_update_content_attrs ( player );
921 if ( player->cmd == MMPLAYER_COMMAND_START && !player->sent_bos )
923 __mmplayer_post_missed_plugin ( player );
925 /* update video resource status */
926 if ( ( player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO )
928 asm_result = _mmplayer_asm_set_state((MMHandleType)player, ASM_STATE_PLAYING);
931 MMMessageParamType msg = {0, };
933 debug_error("failed to go ahead because of video conflict\n");
935 msg.union_type = MM_MSG_UNION_CODE;
936 msg.code = MM_ERROR_POLICY_INTERRUPTED;
937 MMPLAYER_POST_MSG( player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
939 _mmplayer_unrealize((MMHandleType)player);
946 if ( player->resumed_by_rewind && player->playback_rate < 0.0 )
948 /* initialize because auto resume is done well. */
949 player->resumed_by_rewind = FALSE;
950 player->playback_rate = 1.0;
953 if ( !player->sent_bos )
955 /* check audio codec field is set or not
956 * we can get it from typefinder or codec's caps.
958 gchar *audio_codec = NULL;
959 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
961 /* The codec format can't be sent for audio only case like amr, mid etc.
962 * Because, parser don't make related TAG.
963 * So, if it's not set yet, fill it with found data.
967 if ( g_strrstr(player->type, "audio/midi"))
969 audio_codec = g_strdup("MIDI");
972 else if ( g_strrstr(player->type, "audio/x-amr"))
974 audio_codec = g_strdup("AMR");
976 else if ( g_strrstr(player->type, "audio/mpeg") && !g_strrstr(player->type, "mpegversion=(int)1"))
978 audio_codec = g_strdup("AAC");
982 audio_codec = g_strdup("unknown");
984 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
986 MMPLAYER_FREEIF(audio_codec);
987 mmf_attrs_commit(player->attrs);
988 debug_log("set audio codec type with caps\n");
991 MMTA_ACUM_ITEM_END("[KPI] start media player service", FALSE);
992 MMTA_ACUM_ITEM_END("[KPI] media player service create->playing", FALSE);
994 MMPLAYER_POST_MSG ( player, MM_MESSAGE_BEGIN_OF_STREAM, NULL );
995 player->sent_bos = TRUE;
1000 case MM_PLAYER_STATE_NONE:
1002 debug_warning("invalid target state, there is nothing to do.\n");
1013 __mmplayer_post_message(mm_player_t* player, enum MMMessageType msgtype, MMMessageParamType* param) // @
1015 return_val_if_fail( player, FALSE );
1019 if ( !player->msg_cb )
1021 debug_warning("no msg callback. can't post\n");
1025 //debug_log("Message (type : %d) will be posted using msg-cb(%p). \n", msgtype, player->msg_cb);
1027 player->msg_cb(msgtype, param, player->msg_cb_param);
1036 __mmplayer_get_state(mm_player_t* player) // @
1038 int state = MM_PLAYER_STATE_NONE;
1042 return_val_if_fail ( player, MM_PLAYER_STATE_NONE );
1044 state = MMPLAYER_CURRENT_STATE(player);
1046 debug_log("player state is %s.\n", MMPLAYER_STATE_GET_NAME(state));
1054 __gst_set_async_state_change(mm_player_t* player, gboolean async)
1057 return_if_fail( player && player->pipeline && player->pipeline->mainbin );
1059 /* need only when we are using decodebin */
1060 if ( ! PLAYER_INI()->use_decodebin )
1064 if ( player->pipeline->audiobin &&
1065 player->pipeline->audiobin[MMPLAYER_A_SINK].gst )
1067 debug_log("audiosink async : %d\n", async);
1068 g_object_set (G_OBJECT (player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "async", async, NULL);
1072 if ( player->pipeline->videobin &&
1073 player->pipeline->videobin[MMPLAYER_V_SINK].gst )
1075 debug_log("videosink async : %d\n", async);
1076 g_object_set (G_OBJECT (player->pipeline->videobin[MMPLAYER_V_SINK].gst), "async", async, NULL);
1079 /* decodebin if enabled */
1080 if ( PLAYER_INI()->use_decodebin )
1082 debug_log("decodebin async : %d\n", async);
1083 g_object_set (G_OBJECT (player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst), "async-handling", async, NULL);
1089 static gpointer __mmplayer_repeat_thread(gpointer data)
1091 mm_player_t* player = (mm_player_t*) data;
1092 gboolean ret_value = FALSE;
1093 MMHandleType attrs = 0;
1096 return_val_if_fail ( player, NULL );
1098 while ( ! player->repeat_thread_exit )
1100 debug_log("repeat thread started. waiting for signal.\n");
1101 g_cond_wait( player->repeat_thread_cond, player->repeat_thread_mutex );
1103 if ( player->repeat_thread_exit )
1105 debug_log("exiting repeat thread\n");
1109 if ( !player->cmd_lock )
1111 debug_log("can't get cmd lock\n");
1116 g_mutex_lock(player->cmd_lock);
1118 attrs = MMPLAYER_GET_ATTRS(player);
1120 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
1122 debug_error("can not get play count\n");
1126 if ( player->section_repeat )
1128 ret_value = _mmplayer_activate_section_repeat((MMHandleType)player, player->section_repeat_start, player->section_repeat_end);
1132 if ( player->playback_rate < 0.0 )
1134 player->resumed_by_rewind = TRUE;
1135 _mmplayer_set_mute((MMHandleType)player, 0);
1136 MMPLAYER_POST_MSG( player, MM_MESSAGE_RESUMED_BY_REW, NULL );
1139 ret_value = __gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
1140 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET,
1141 0, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
1144 player->sent_bos = FALSE;
1149 debug_error("failed to set position to zero for rewind\n");
1153 /* decrease play count */
1156 /* we successeded to rewind. update play count and then wait for next EOS */
1159 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
1161 /* commit attribute */
1162 if ( mmf_attrs_commit ( attrs ) )
1164 debug_error("failed to commit attribute\n");
1169 g_mutex_unlock(player->cmd_lock);
1176 __mmplayer_handle_buffering_message ( mm_player_t* player )
1178 MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
1179 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
1180 MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
1181 MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
1183 return_if_fail ( player );
1185 prev_state = MMPLAYER_PREV_STATE(player),
1186 current_state = MMPLAYER_CURRENT_STATE(player);
1187 target_state = MMPLAYER_TARGET_STATE(player);
1188 pending_state = MMPLAYER_PENDING_STATE(player);
1190 if ( MMPLAYER_IS_RTSP_STREAMING(player) )
1193 if ( !player->streamer->is_buffering )
1195 debug_log( "player state : prev %s, current %s, pending %s, target %s \n",
1196 MMPLAYER_STATE_GET_NAME(prev_state),
1197 MMPLAYER_STATE_GET_NAME(current_state),
1198 MMPLAYER_STATE_GET_NAME(pending_state),
1199 MMPLAYER_STATE_GET_NAME(target_state));
1201 /* NOTE : if buffering has done, player has to go to target state. */
1202 switch ( target_state )
1204 case MM_PLAYER_STATE_PAUSED :
1206 switch ( pending_state )
1208 case MM_PLAYER_STATE_PLAYING:
1210 __gst_pause ( player, TRUE );
1214 case MM_PLAYER_STATE_PAUSED:
1216 debug_log("player is already going to paused state, there is nothing to do.\n");
1220 case MM_PLAYER_STATE_NONE:
1221 case MM_PLAYER_STATE_NULL:
1222 case MM_PLAYER_STATE_READY:
1225 debug_warning("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state) );
1232 case MM_PLAYER_STATE_PLAYING :
1234 switch ( pending_state )
1236 case MM_PLAYER_STATE_NONE:
1238 if (current_state != MM_PLAYER_STATE_PLAYING)
1239 __gst_resume ( player, TRUE );
1243 case MM_PLAYER_STATE_PAUSED:
1245 /* NOTE: It should be worked as asynchronously.
1246 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
1248 __gst_resume ( player, TRUE );
1252 case MM_PLAYER_STATE_PLAYING:
1254 debug_log("player is already going to playing state, there is nothing to do.\n");
1258 case MM_PLAYER_STATE_NULL:
1259 case MM_PLAYER_STATE_READY:
1262 debug_warning("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state) );
1269 case MM_PLAYER_STATE_NULL :
1270 case MM_PLAYER_STATE_READY :
1271 case MM_PLAYER_STATE_NONE :
1274 debug_warning("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state) );
1281 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1282 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
1284 switch ( pending_state )
1286 case MM_PLAYER_STATE_NONE:
1288 if (current_state != MM_PLAYER_STATE_PAUSED)
1289 __gst_pause ( player, TRUE );
1293 case MM_PLAYER_STATE_PLAYING:
1295 __gst_pause ( player, TRUE );
1299 case MM_PLAYER_STATE_PAUSED:
1301 debug_log("player is already going to paused state, there is nothing to do.\n");
1305 case MM_PLAYER_STATE_NULL:
1306 case MM_PLAYER_STATE_READY:
1309 debug_warning("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state) );
1317 __mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data) // @
1319 mm_player_t* player = (mm_player_t*) data;
1320 gboolean ret = TRUE;
1321 static gboolean async_done = FALSE;
1323 return_val_if_fail ( player, FALSE );
1324 return_val_if_fail ( msg && GST_IS_MESSAGE(msg), FALSE );
1326 switch ( GST_MESSAGE_TYPE( msg ) )
1328 case GST_MESSAGE_UNKNOWN:
1329 debug_warning("unknown message received\n");
1332 case GST_MESSAGE_EOS:
1334 MMHandleType attrs = 0;
1337 debug_log("GST_MESSAGE_EOS received\n");
1339 /* NOTE : EOS event is comming multiple time. watch out it */
1340 /* check state. we only process EOS when pipeline state goes to PLAYING */
1341 if ( ! (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) )
1343 debug_warning("EOS received on non-playing state. ignoring it\n");
1347 if ( (player->audio_stream_cb) && (player->is_sound_extraction) )
1351 pad = gst_element_get_static_pad (player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
1353 debug_error("release audio callback\n");
1355 /* release audio callback */
1356 gst_pad_remove_buffer_probe (pad, player->audio_cb_probe_id);
1357 player->audio_cb_probe_id = 0;
1358 /* audio callback should be free because it can be called even though probe remove.*/
1359 player->audio_stream_cb = NULL;
1360 player->audio_stream_cb_user_param = NULL;
1364 /* rewind if repeat count is greater then zero */
1365 /* get play count */
1366 attrs = MMPLAYER_GET_ATTRS(player);
1370 gboolean smooth_repeat = FALSE;
1372 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1373 mm_attrs_get_int_by_name(attrs, "profile_smooth_repeat", &smooth_repeat);
1375 debug_log("remaining play count: %d, playback rate: %f\n", count, player->playback_rate);
1377 if ( count > 1 || count == -1 || player->playback_rate < 0.0 ) /* default value is 1 */
1379 if ( smooth_repeat )
1381 debug_log("smooth repeat enabled. seeking operation will be excuted in new thread\n");
1383 g_cond_signal( player->repeat_thread_cond );
1391 if ( player->section_repeat )
1393 ret_value = _mmplayer_activate_section_repeat((MMHandleType)player, player->section_repeat_start, player->section_repeat_end);
1398 if ( player->playback_rate < 0.0 )
1400 player->resumed_by_rewind = TRUE;
1401 _mmplayer_set_mute((MMHandleType)player, 0);
1402 MMPLAYER_POST_MSG( player, MM_MESSAGE_RESUMED_BY_REW, NULL );
1405 ret_value = __gst_set_position( player, MM_PLAYER_POS_FORMAT_TIME, 0, TRUE);
1408 player->sent_bos = FALSE;
1411 if ( MM_ERROR_NONE != ret_value )
1413 debug_error("failed to set position to zero for rewind\n");
1419 /* we successeded to rewind. update play count and then wait for next EOS */
1422 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
1424 if ( mmf_attrs_commit ( attrs ) )
1425 debug_error("failed to commit attrs\n");
1434 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-eos" );
1436 /* post eos message to application */
1437 __mmplayer_post_delayed_eos( player, PLAYER_INI()->eos_delay );
1439 /* reset last position */
1440 player->last_position = 0;
1444 case GST_MESSAGE_ERROR:
1446 GError *error = NULL;
1447 gchar* debug = NULL;
1448 gchar *msg_src_element = NULL;
1450 /* generating debug info before returning error */
1451 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-error" );
1453 /* get error code */
1454 gst_message_parse_error( msg, &error, &debug );
1456 msg_src_element = GST_ELEMENT_NAME( GST_ELEMENT_CAST( msg->src ) );
1457 if ( gst_structure_has_name ( msg->structure, "streaming_error" ) )
1459 /* Note : the streaming error from the streaming source is handled
1460 * using __mmplayer_handle_streaming_error.
1462 __mmplayer_handle_streaming_error ( player, msg );
1464 /* dump state of all element */
1465 __mmplayer_dump_pipeline_state( player );
1469 /* traslate gst error code to msl error code. then post it
1470 * to application if needed
1472 __mmplayer_handle_gst_error( player, msg, error );
1474 /* dump state of all element */
1475 __mmplayer_dump_pipeline_state( player );
1479 if (MMPLAYER_IS_HTTP_PD(player))
1481 _mmplayer_unrealize_pd_downloader ((MMHandleType)player);
1484 MMPLAYER_FREEIF( debug );
1485 g_error_free( error );
1489 case GST_MESSAGE_WARNING:
1492 GError* error = NULL;
1494 gst_message_parse_warning(msg, &error, &debug);
1496 debug_warning("warning : %s\n", error->message);
1497 debug_warning("debug : %s\n", debug);
1499 MMPLAYER_POST_MSG( player, MM_MESSAGE_WARNING, NULL );
1501 MMPLAYER_FREEIF( debug );
1502 g_error_free( error );
1506 case GST_MESSAGE_INFO: debug_log("GST_MESSAGE_STATE_DIRTY\n"); break;
1508 case GST_MESSAGE_TAG:
1510 debug_log("GST_MESSAGE_TAG\n");
1511 if ( ! __mmplayer_gst_extract_tag_from_msg( player, msg ) )
1513 debug_warning("failed to extract tags from gstmessage\n");
1518 case GST_MESSAGE_BUFFERING:
1520 MMMessageParamType msg_param = {0, };
1521 gboolean update_buffering_percent = TRUE;
1523 if ( !MMPLAYER_IS_STREAMING(player) || (player->profile.uri_type == MM_PLAYER_URI_TYPE_HLS) ) // pure hlsdemux case, don't consider buffering of msl currently
1526 __mm_player_streaming_buffering (player->streamer, msg);
1528 __mmplayer_handle_buffering_message ( player );
1530 update_buffering_percent = (player->pipeline_is_constructed || MMPLAYER_IS_RTSP_STREAMING(player) );
1531 if (update_buffering_percent)
1533 msg_param.connection.buffering = player->streamer->buffering_percent;
1534 MMPLAYER_POST_MSG ( player, MM_MESSAGE_BUFFERING, &msg_param );
1539 case GST_MESSAGE_STATE_CHANGED:
1541 MMPlayerGstElement *mainbin;
1542 const GValue *voldstate, *vnewstate, *vpending;
1543 GstState oldstate, newstate, pending;
1545 if ( ! ( player->pipeline && player->pipeline->mainbin ) )
1547 debug_error("player pipeline handle is null");
1552 mainbin = player->pipeline->mainbin;
1554 /* get state info from msg */
1555 voldstate = gst_structure_get_value (msg->structure, "old-state");
1556 vnewstate = gst_structure_get_value (msg->structure, "new-state");
1557 vpending = gst_structure_get_value (msg->structure, "pending-state");
1559 oldstate = (GstState)voldstate->data[0].v_int;
1560 newstate = (GstState)vnewstate->data[0].v_int;
1561 pending = (GstState)vpending->data[0].v_int;
1563 if (oldstate == newstate)
1566 debug_log("state changed [%s] : %s ---> %s final : %s\n",
1567 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1568 gst_element_state_get_name( (GstState)oldstate ),
1569 gst_element_state_get_name( (GstState)newstate ),
1570 gst_element_state_get_name( (GstState)pending ) );
1572 /* we only handle messages from pipeline */
1573 if( msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst )
1578 case GST_STATE_VOID_PENDING:
1581 case GST_STATE_NULL:
1584 case GST_STATE_READY:
1587 case GST_STATE_PAUSED:
1589 gboolean prepare_async = FALSE;
1591 player->need_update_content_dur = TRUE;
1593 if ( ! player->audio_cb_probe_id && player->is_sound_extraction )
1594 __mmplayer_configure_audio_callback(player);
1596 if ( ! player->sent_bos && oldstate == GST_STATE_READY) // managed prepare async case
1598 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1599 debug_log("checking prepare mode for async transition - %d", prepare_async);
1602 if ( MMPLAYER_IS_STREAMING(player) || prepare_async )
1604 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_PAUSED );
1606 if (player->streamer)
1607 __mm_player_streaming_set_content_bitrate(player->streamer, player->total_maximum_bitrate, player->total_bitrate);
1612 case GST_STATE_PLAYING:
1614 if (player->doing_seek && async_done)
1616 player->doing_seek = FALSE;
1618 MMPLAYER_POST_MSG ( player, MM_MESSAGE_SEEK_COMPLETED, NULL );
1621 if ( MMPLAYER_IS_STREAMING(player) ) // managed prepare async case when buffering is completed
1623 // pending state should be reset oyherwise, it's still playing even though it's resumed after bufferging.
1624 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_PLAYING);
1635 case GST_MESSAGE_STATE_DIRTY: debug_log("GST_MESSAGE_STATE_DIRTY\n"); break;
1636 case GST_MESSAGE_STEP_DONE: debug_log("GST_MESSAGE_STEP_DONE\n"); break;
1637 case GST_MESSAGE_CLOCK_PROVIDE: debug_log("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
1639 case GST_MESSAGE_CLOCK_LOST:
1641 GstClock *clock = NULL;
1642 gst_message_parse_clock_lost (msg, &clock);
1643 debug_log("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME (clock) : "NULL"));
1644 g_print ("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME (clock) : "NULL"));
1646 if (PLAYER_INI()->provide_clock)
1648 debug_log ("Provide clock is TRUE, do pause->resume\n");
1649 __gst_pause(player, FALSE);
1650 __gst_resume(player, FALSE);
1655 case GST_MESSAGE_NEW_CLOCK:
1657 GstClock *clock = NULL;
1658 gst_message_parse_new_clock (msg, &clock);
1659 debug_log("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME (clock) : "NULL"));
1663 case GST_MESSAGE_STRUCTURE_CHANGE: debug_log("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
1664 case GST_MESSAGE_STREAM_STATUS: debug_log("GST_MESSAGE_STREAM_STATUS\n"); break;
1665 case GST_MESSAGE_APPLICATION: debug_log("GST_MESSAGE_APPLICATION\n"); break;
1667 case GST_MESSAGE_ELEMENT:
1669 debug_log("GST_MESSAGE_ELEMENT\n");
1673 case GST_MESSAGE_SEGMENT_START: debug_log("GST_MESSAGE_SEGMENT_START\n"); break;
1674 case GST_MESSAGE_SEGMENT_DONE: debug_log("GST_MESSAGE_SEGMENT_DONE\n"); break;
1676 case GST_MESSAGE_DURATION:
1678 debug_log("GST_MESSAGE_DURATION\n");
1680 if (MMPLAYER_IS_STREAMING(player))
1685 gst_message_parse_duration (msg, &format, &bytes);
1686 if (format == GST_FORMAT_BYTES)
1688 debug_log("data total size of http content: %lld", bytes);
1689 player->http_content_size = bytes;
1693 player->need_update_content_attrs = TRUE;
1694 player->need_update_content_dur = TRUE;
1695 _mmplayer_update_content_attrs(player);
1699 case GST_MESSAGE_LATENCY: debug_log("GST_MESSAGE_LATENCY\n"); break;
1700 case GST_MESSAGE_ASYNC_START: debug_log("GST_MESSAGE_ASYNC_DONE : %s\n", gst_element_get_name(GST_MESSAGE_SRC(msg))); break;
1702 case GST_MESSAGE_ASYNC_DONE:
1704 debug_log("GST_MESSAGE_ASYNC_DONE : %s\n", gst_element_get_name(GST_MESSAGE_SRC(msg)));
1706 if (player->doing_seek)
1708 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED)
1710 player->doing_seek = FALSE;
1711 MMPLAYER_POST_MSG ( player, MM_MESSAGE_SEEK_COMPLETED, NULL );
1713 else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING)
1721 case GST_MESSAGE_REQUEST_STATE: debug_log("GST_MESSAGE_REQUEST_STATE\n"); break;
1722 case GST_MESSAGE_STEP_START: debug_log("GST_MESSAGE_STEP_START\n"); break;
1723 case GST_MESSAGE_QOS: debug_log("GST_MESSAGE_QOS\n"); break;
1724 case GST_MESSAGE_PROGRESS: debug_log("GST_MESSAGE_PROGRESS\n"); break;
1725 case GST_MESSAGE_ANY: debug_log("GST_MESSAGE_ANY\n"); break;
1728 debug_warning("unhandled message\n");
1732 /* FIXIT : this cause so many warnings/errors from glib/gstreamer. we should not call it since
1733 * gst_element_post_message api takes ownership of the message.
1735 //gst_message_unref( msg );
1741 __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg) // @
1744 /* macro for better code readability */
1745 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
1746 if (gst_tag_list_get_string(tag_list, gsttag, &string)) \
1748 if (string != NULL)\
1750 debug_log ( "update tag string : %s\n", string); \
1751 mm_attrs_set_string_by_name(attribute, playertag, string); \
1757 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
1758 value = gst_tag_list_get_value_index(tag_list, gsttag, index); \
1761 buffer = gst_value_get_buffer (value); \
1762 debug_log ( "update album cover data : %p, size : %d\n", GST_BUFFER_DATA(buffer), GST_BUFFER_SIZE(buffer)); \
1763 player->album_art = (gchar *)g_malloc(GST_BUFFER_SIZE(buffer)); \
1764 if (player->album_art); \
1766 memcpy(player->album_art, GST_BUFFER_DATA(buffer), GST_BUFFER_SIZE(buffer)); \
1767 mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, GST_BUFFER_SIZE(buffer)); \
1771 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
1772 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint))\
1776 if(gsttag==GST_TAG_BITRATE)\
1778 if (player->updated_bitrate_count == 0) \
1779 mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
1780 if (player->updated_bitrate_count<MM_PLAYER_STREAM_COUNT_MAX) \
1782 player->bitrate[player->updated_bitrate_count] = v_uint;\
1783 player->total_bitrate += player->bitrate[player->updated_maximum_bitrate_count]; \
1784 player->updated_bitrate_count++; \
1785 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate);\
1786 debug_log ( "update bitrate %d[bps] of stream #%d.\n", v_uint, player->updated_bitrate_count);\
1789 else if (gsttag==GST_TAG_MAXIMUM_BITRATE)\
1791 if (player->updated_maximum_bitrate_count<MM_PLAYER_STREAM_COUNT_MAX) \
1793 player->maximum_bitrate[player->updated_maximum_bitrate_count] = v_uint;\
1794 player->total_maximum_bitrate += player->maximum_bitrate[player->updated_maximum_bitrate_count]; \
1795 player->updated_maximum_bitrate_count++; \
1796 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate); \
1797 debug_log ( "update maximum bitrate %d[bps] of stream #%d\n", v_uint, player->updated_maximum_bitrate_count);\
1802 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
1808 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
1809 if (gst_tag_list_get_date(tag_list, gsttag, &date))\
1813 string = g_strdup_printf("%d", g_date_get_year(date));\
1814 mm_attrs_set_string_by_name(attribute, playertag, string);\
1815 debug_log ( "metainfo year : %s\n", string);\
1816 MMPLAYER_FREEIF(string);\
1821 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
1822 if(gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64))\
1826 /* FIXIT : don't know how to store date */\
1832 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
1833 if(gst_tag_list_get_double(tag_list, gsttag, &v_double))\
1837 /* FIXIT : don't know how to store date */\
1843 /* function start */
1844 GstTagList* tag_list = NULL;
1846 MMHandleType attrs = 0;
1848 char *string = NULL;
1852 GstBuffer *buffer = NULL;
1854 const GValue *value;
1856 /* currently not used. but those are needed for above macro */
1857 //guint64 v_uint64 = 0;
1858 //gdouble v_double = 0;
1860 return_val_if_fail( player && msg, FALSE );
1862 attrs = MMPLAYER_GET_ATTRS(player);
1864 return_val_if_fail( attrs, FALSE );
1866 /* get tag list from gst message */
1867 gst_message_parse_tag(msg, &tag_list);
1869 /* store tags to player attributes */
1870 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
1871 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
1872 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
1873 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
1874 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
1875 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
1876 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
1877 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
1878 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
1879 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
1880 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
1881 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
1882 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
1883 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
1884 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
1885 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
1886 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
1887 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
1888 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
1889 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
1890 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
1891 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
1892 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
1893 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
1894 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
1895 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
1896 /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
1897 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
1898 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
1899 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
1900 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
1901 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
1902 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
1903 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
1904 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
1905 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
1906 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
1907 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
1908 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
1909 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
1910 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
1911 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
1912 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
1913 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
1914 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
1916 if ( mmf_attrs_commit ( attrs ) )
1917 debug_error("failed to commit.\n");
1919 gst_tag_list_free(tag_list);
1925 __mmplayer_gst_rtp_no_more_pads (GstElement *element, gpointer data) // @
1927 mm_player_t* player = (mm_player_t*) data;
1931 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
1932 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
1933 * num_dynamic_pad. and this is no-more-pad situation which means mo more pad will be added.
1934 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
1936 * [1] audio and video will be dumped with filesink.
1937 * [2] autoplugging is done by just using pad caps.
1938 * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
1939 * and the video will be dumped via filesink.
1941 if ( player->num_dynamic_pad == 0 )
1943 debug_log("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
1945 if ( ! __mmplayer_gst_remove_fakesink( player,
1946 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]) )
1948 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
1949 * signaling mechanism ( pad-added, no-more-pad, new-decoded-pad ) from various
1950 * source element are not same. To overcome this situation, this function will called
1951 * several places and several times. Therefore, this is not an error case.
1957 /* create dot before error-return. for debugging */
1958 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-no-more-pad" );
1960 /* NOTE : if rtspsrc goes to PLAYING before adding it's src pads, a/v sink elements will
1961 * not goes to PLAYING. they will just remain in PAUSED state. simply we are giving
1962 * PLAYING state again.
1964 __mmplayer_gst_set_state(player,
1965 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, TRUE, 5000 );
1967 player->no_more_pad = TRUE;
1973 __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink) // @
1975 GstElement* parent = NULL;
1977 return_val_if_fail(player && player->pipeline && fakesink, FALSE);
1980 g_mutex_lock( player->fsink_lock );
1982 if ( ! fakesink->gst )
1987 /* get parent of fakesink */
1988 parent = (GstElement*)gst_object_get_parent( (GstObject*)fakesink->gst );
1991 debug_log("fakesink already removed\n");
1995 gst_element_set_locked_state( fakesink->gst, TRUE );
1997 /* setting the state to NULL never returns async
1998 * so no need to wait for completion of state transiton
2000 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state (fakesink->gst, GST_STATE_NULL) )
2002 debug_error("fakesink state change failure!\n");
2004 /* FIXIT : should I return here? or try to proceed to next? */
2008 /* remove fakesink from it's parent */
2009 if ( ! gst_bin_remove( GST_BIN( parent ), fakesink->gst ) )
2011 debug_error("failed to remove fakesink\n");
2013 gst_object_unref( parent );
2018 gst_object_unref( parent );
2020 /* FIXIT : releasing fakesink takes too much time (around 700ms)
2021 * we need to figure out the reason why. just for now, fakesink will be released
2022 * in __mmplayer_gst_destroy_pipeline()
2024 // gst_object_unref ( fakesink->gst );
2025 // fakesink->gst = NULL;
2027 debug_log("state-holder removed\n");
2029 gst_element_set_locked_state( fakesink->gst, FALSE );
2031 g_mutex_unlock( player->fsink_lock );
2035 if ( fakesink->gst )
2037 gst_element_set_locked_state( fakesink->gst, FALSE );
2040 g_mutex_unlock( player->fsink_lock );
2046 __mmplayer_gst_rtp_dynamic_pad (GstElement *element, GstPad *pad, gpointer data) // @
2048 GstPad *sinkpad = NULL;
2049 GstCaps* caps = NULL;
2050 GstElement* new_element = NULL;
2052 mm_player_t* player = (mm_player_t*) data;
2056 return_if_fail( element && pad );
2057 return_if_fail( player &&
2059 player->pipeline->mainbin );
2062 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2063 * num_dynamic_pad will decreased after creating a sinkbin.
2065 player->num_dynamic_pad++;
2066 debug_log("stream count inc : %d\n", player->num_dynamic_pad);
2068 /* perform autoplugging if dump is disabled */
2069 if ( PLAYER_INI()->rtsp_do_typefinding )
2071 /* create typefind */
2072 new_element = gst_element_factory_make( "typefind", NULL );
2073 if ( ! new_element )
2075 debug_error("failed to create typefind\n");
2079 MMPLAYER_SIGNAL_CONNECT( player,
2080 G_OBJECT(new_element),
2082 G_CALLBACK(__mmplayer_typefind_have_type),
2085 /* FIXIT : try to remove it */
2086 player->have_dynamic_pad = FALSE;
2088 else /* NOTE : use pad's caps directely. if enabled. what I am assuming is there's no elemnt has dynamic pad */
2090 debug_log("using pad caps to autopluging instead of doing typefind\n");
2092 caps = gst_pad_get_caps( pad );
2094 MMPLAYER_CHECK_NULL( caps );
2096 /* clear previous result*/
2097 player->have_dynamic_pad = FALSE;
2099 if ( ! __mmplayer_try_to_plug( player, pad, caps ) )
2101 debug_error("failed to autoplug for caps : %s\n", gst_caps_to_string( caps ) );
2105 /* check if there's dynamic pad*/
2106 if( player->have_dynamic_pad )
2108 debug_error("using pad caps assums there's no dynamic pad !\n");
2109 debug_error("try with enalbing rtsp_do_typefinding\n");
2113 gst_caps_unref( caps );
2117 /* excute new_element if created*/
2120 debug_log("adding new element to pipeline\n");
2122 /* set state to READY before add to bin */
2123 MMPLAYER_ELEMENT_SET_STATE( new_element, GST_STATE_READY );
2125 /* add new element to the pipeline */
2126 if ( FALSE == gst_bin_add( GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element) )
2128 debug_error("failed to add autoplug element to bin\n");
2132 /* get pad from element */
2133 sinkpad = gst_element_get_static_pad ( GST_ELEMENT(new_element), "sink" );
2136 debug_error("failed to get sinkpad from autoplug element\n");
2141 if ( GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad) )
2143 debug_error("failed to link autoplug element\n");
2147 gst_object_unref (sinkpad);
2150 /* run. setting PLAYING here since streamming source is live source */
2151 MMPLAYER_ELEMENT_SET_STATE( new_element, GST_STATE_PLAYING );
2158 STATE_CHANGE_FAILED:
2160 /* FIXIT : take care if new_element has already added to pipeline */
2162 gst_object_unref(GST_OBJECT(new_element));
2165 gst_object_unref(GST_OBJECT(sinkpad));
2168 gst_object_unref(GST_OBJECT(caps));
2170 /* FIXIT : how to inform this error to MSL ????? */
2171 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2172 * then post an error to application
2178 __mmplayer_gst_decode_callback(GstElement *decodebin, GstPad *pad, gboolean last, gpointer data) // @
2180 mm_player_t* player = NULL;
2181 MMHandleType attrs = 0;
2182 GstElement* pipeline = NULL;
2183 GstCaps* caps = NULL;
2184 GstStructure* str = NULL;
2185 const gchar* name = NULL;
2186 GstPad* sinkpad = NULL;
2187 GstElement* sinkbin = NULL;
2190 player = (mm_player_t*) data;
2192 return_if_fail( decodebin && pad );
2193 return_if_fail(player && player->pipeline && player->pipeline->mainbin);
2195 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
2197 attrs = MMPLAYER_GET_ATTRS(player);
2200 debug_error("cannot get content attribute\n");
2204 /* get mimetype from caps */
2205 caps = gst_pad_get_caps( pad );
2208 debug_error("cannot get caps from pad.\n");
2212 str = gst_caps_get_structure( caps, 0 );
2215 debug_error("cannot get structure from capse.\n");
2219 name = gst_structure_get_name(str);
2222 debug_error("cannot get mimetype from structure.\n");
2226 debug_log("detected mimetype : %s\n", name);
2228 if (strstr(name, "audio"))
2230 if (player->pipeline->audiobin == NULL)
2232 __ta__("__mmplayer_gst_create_audio_pipeline",
2233 if (MM_ERROR_NONE != __mmplayer_gst_create_audio_pipeline(player))
2235 debug_error("failed to create audiobin. continuing without audio\n");
2240 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
2241 debug_log("creating audiosink bin success\n");
2245 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
2246 debug_log("re-using audiobin\n");
2249 /* FIXIT : track number shouldn't be hardcoded */
2250 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 1);
2252 player->audiosink_linked = 1;
2253 debug_msg("player->audsink_linked set to 1\n");
2255 sinkpad = gst_element_get_static_pad( GST_ELEMENT(sinkbin), "sink" );
2258 debug_error("failed to get pad from sinkbin\n");
2262 else if (strstr(name, "video"))
2264 if (player->pipeline->videobin == NULL)
2266 /* NOTE : not make videobin because application dose not want to play it even though file has video stream.
2269 /* get video surface type */
2270 int surface_type = 0;
2271 mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &surface_type);
2273 if (surface_type == MM_DISPLAY_SURFACE_NULL)
2275 debug_log("not make videobin because it dose not want\n");
2279 __ta__("__mmplayer_gst_create_video_pipeline",
2280 if (MM_ERROR_NONE != __mmplayer_gst_create_video_pipeline(player, caps, surface_type) )
2282 debug_error("failed to create videobin. continuing without video\n");
2287 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
2288 debug_log("creating videosink bin success\n");
2292 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
2293 debug_log("re-using videobin\n");
2296 /* FIXIT : track number shouldn't be hardcoded */
2297 mm_attrs_set_int_by_name(attrs, "content_video_track_num", 1);
2299 player->videosink_linked = 1;
2300 debug_msg("player->videosink_linked set to 1\n");
2302 sinkpad = gst_element_get_static_pad( GST_ELEMENT(sinkbin), "sink" );
2305 debug_error("failed to get pad from sinkbin\n");
2309 else if (strstr(name, "text"))
2311 if (player->pipeline->textbin == NULL)
2313 __ta__("__mmplayer_gst_create_text_pipeline",
2314 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player))
2316 debug_error("failed to create textbin. continuing without text\n");
2321 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
2322 debug_log("creating textink bin success\n");
2326 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
2327 debug_log("re-using textbin\n");
2330 /* FIXIT : track number shouldn't be hardcoded */
2331 mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1);
2333 player->textsink_linked = 1;
2334 debug_msg("player->textsink_linked set to 1\n");
2336 sinkpad = gst_element_get_static_pad( GST_ELEMENT(sinkbin), "text_sink" );
2339 debug_error("failed to get pad from sinkbin\n");
2345 debug_warning("unknown type of elementary stream! ignoring it...\n");
2352 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state( sinkbin, GST_STATE_READY ) )
2354 debug_error("failed to set state(READY) to sinkbin\n");
2359 if ( FALSE == gst_bin_add( GST_BIN(pipeline), sinkbin ) )
2361 debug_error("failed to add sinkbin to pipeline\n");
2366 if ( GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad) )
2368 debug_error("failed to get pad from sinkbin\n");
2373 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state( sinkbin, GST_STATE_PAUSED ) )
2375 debug_error("failed to set state(PLAYING) to sinkbin\n");
2379 gst_object_unref( sinkpad );
2383 /* update track number attributes */
2384 if ( mmf_attrs_commit ( attrs ) )
2385 debug_error("failed to commit attrs\n");
2387 debug_log("linking sink bin success\n");
2389 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
2390 * streaming task. if the task blocked, then buffer will not flow to the next element
2391 * ( autoplugging element ). so this is special hack for streaming. please try to remove it
2393 /* dec stream count. we can remove fakesink if it's zero */
2394 player->num_dynamic_pad--;
2396 debug_log("stream count dec : %d (num of dynamic pad)\n", player->num_dynamic_pad);
2398 if ( ( player->no_more_pad ) && ( player->num_dynamic_pad == 0 ) )
2400 __mmplayer_pipeline_complete( NULL, player );
2405 gst_caps_unref( caps );
2408 gst_object_unref(GST_OBJECT(sinkpad));
2414 __mmplayer_get_property_value_for_rotation(mm_player_t* player, int rotation_angle, int *value)
2416 int pro_value = 0; // in the case of expection, default will be returned.
2417 int dest_angle = rotation_angle;
2418 char *element_name = NULL;
2419 int rotation_using_type = -1;
2420 #define ROTATION_USING_X 0
2421 #define ROTATION_USING_FLIP 1
2423 return_val_if_fail(player, FALSE);
2424 return_val_if_fail(value, FALSE);
2425 return_val_if_fail(rotation_angle >= 0, FALSE);
2427 if (rotation_angle >= 360)
2429 dest_angle = rotation_angle - 360;
2432 /* chech if supported or not */
2433 if ( dest_angle % 90 )
2435 debug_log("not supported rotation angle = %d", rotation_angle);
2439 if (player->use_video_stream)
2441 rotation_using_type = ROTATION_USING_FLIP;
2445 int surface_type = 0;
2446 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
2447 debug_log("check display surface type for rotation: %d", surface_type);
2449 switch (surface_type)
2451 case MM_DISPLAY_SURFACE_X:
2452 rotation_using_type = ROTATION_USING_X;
2454 case MM_DISPLAY_SURFACE_EVAS:
2456 rotation_using_type = ROTATION_USING_FLIP;
2461 debug_log("using %d type for rotation", rotation_using_type);
2463 /* get property value for setting */
2464 switch(rotation_using_type)
2466 case ROTATION_USING_X: // xvimagesink
2473 pro_value = 3; // clockwise 90
2479 pro_value = 1; // counter-clockwise 90
2484 case ROTATION_USING_FLIP: // videoflip
2492 pro_value = 1; // clockwise 90
2498 pro_value = 3; // counter-clockwise 90
2505 debug_log("setting rotation property value : %d", pro_value);
2513 _mmplayer_update_video_param(mm_player_t* player) // @
2515 MMHandleType attrs = 0;
2516 int surface_type = 0;
2517 int org_angle = 0; // current supported angle values are 0, 90, 180, 270
2519 int user_angle_type= 0;
2520 int rotation_value = 0;
2524 /* check video sinkbin is created */
2525 return_val_if_fail ( player &&
2527 player->pipeline->videobin &&
2528 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
2529 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2530 MM_ERROR_PLAYER_NOT_INITIALIZED );
2532 attrs = MMPLAYER_GET_ATTRS(player);
2535 debug_error("cannot get content attribute");
2536 return MM_ERROR_PLAYER_INTERNAL;
2539 /* update user roation */
2540 mm_attrs_get_int_by_name(attrs, "display_rotation", &user_angle_type);
2542 /* get angle with user type */
2543 switch(user_angle_type)
2545 case MM_DISPLAY_ROTATION_NONE:
2548 case MM_DISPLAY_ROTATION_90: // counter-clockwise 90
2551 case MM_DISPLAY_ROTATION_180:
2554 case MM_DISPLAY_ROTATION_270: // clockwise 90
2559 /* get original orientation */
2560 if (player->v_stream_caps)
2562 GstStructure *str = NULL;
2564 str = gst_caps_get_structure (player->v_stream_caps, 0);
2565 if ( !gst_structure_get_int (str, "orientation", &org_angle))
2567 debug_log ("missing 'orientation' field in video caps");
2571 debug_log("origianl video orientation = %d", org_angle);
2575 debug_log("check user angle: %d, org angle: %d", user_angle, org_angle);
2577 /* check video stream callback is used */
2578 if( player->use_video_stream )
2580 debug_log("using video stream callback with memsink. player handle : [%p]", player);
2582 /* get rotation value to set */
2583 __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
2585 g_object_set(player->pipeline->videobin[MMPLAYER_V_FLIP].gst, "method", rotation_value, NULL);
2587 return MM_ERROR_NONE;
2590 /* update display surface */
2591 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
2592 debug_log("check display surface type attribute: %d", surface_type);
2594 /* configuring display */
2595 switch ( surface_type )
2597 case MM_DISPLAY_SURFACE_X:
2599 /* ximagesink or xvimagesink */
2602 int display_method = 0;
2607 int force_aspect_ratio = 0;
2608 gboolean visible = TRUE;
2610 /* common case if using x surface */
2611 mm_attrs_get_data_by_name(attrs, "display_overlay", &xid);
2614 debug_log("set video param : xid %d", *(int*)xid);
2615 gst_x_overlay_set_xwindow_id( GST_X_OVERLAY( player->pipeline->videobin[MMPLAYER_V_SINK].gst ), *(int*)xid );
2619 /* FIXIT : is it error case? */
2620 debug_warning("still we don't have xid on player attribute. create it's own surface.");
2623 /* if xvimagesink */
2624 if (!strcmp(PLAYER_INI()->videosink_element_x,"xvimagesink"))
2626 mm_attrs_get_int_by_name(attrs, "display_force_aspect_ration", &force_aspect_ratio);
2627 mm_attrs_get_int_by_name(attrs, "display_zoom", &zoom);
2628 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
2629 mm_attrs_get_int_by_name(attrs, "display_roi_x", &roi_x);
2630 mm_attrs_get_int_by_name(attrs, "display_roi_y", &roi_y);
2631 mm_attrs_get_int_by_name(attrs, "display_roi_width", &roi_w);
2632 mm_attrs_get_int_by_name(attrs, "display_roi_height", &roi_h);
2633 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
2635 /* get rotation value to set */
2636 __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
2638 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2639 "force-aspect-ratio", force_aspect_ratio,
2641 "rotate", rotation_value,
2642 "handle-events", TRUE,
2643 "display-geometry-method", display_method,
2644 "draw-borders", FALSE,
2652 debug_log("set video param : zoom %d", zoom);
2653 debug_log("set video param : rotate %d", rotation_value);
2654 debug_log("set video param : method %d", display_method);
2655 debug_log("set video param : dst-roi-x: %d, dst-roi-y: %d, dst-roi-w: %d, dst-roi-h: %d",
2656 roi_x, roi_y, roi_w, roi_h );
2657 debug_log("set video param : visible %d", visible);
2658 debug_log("set video param : force aspect ratio %d", force_aspect_ratio);
2662 case MM_DISPLAY_SURFACE_EVAS:
2664 void *object = NULL;
2666 gboolean visible = TRUE;
2668 /* common case if using evas surface */
2669 mm_attrs_get_data_by_name(attrs, "display_overlay", &object);
2670 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
2671 mm_attrs_get_int_by_name(attrs, "display_evas_do_scaling", &scaling);
2674 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2675 "evas-object", object,
2678 debug_log("set video param : evas-object %x", object);
2679 debug_log("set video param : visible %d", visible);
2683 debug_error("no evas object");
2684 return MM_ERROR_PLAYER_INTERNAL;
2687 /* if evaspixmapsink */
2688 if (!strcmp(PLAYER_INI()->videosink_element_evas,"evaspixmapsink"))
2690 int display_method = 0;
2695 int force_aspect_ratio = 0;
2696 int origin_size = !scaling;
2698 mm_attrs_get_int_by_name(attrs, "display_force_aspect_ration", &force_aspect_ratio);
2699 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
2700 mm_attrs_get_int_by_name(attrs, "display_roi_x", &roi_x);
2701 mm_attrs_get_int_by_name(attrs, "display_roi_y", &roi_y);
2702 mm_attrs_get_int_by_name(attrs, "display_roi_width", &roi_w);
2703 mm_attrs_get_int_by_name(attrs, "display_roi_height", &roi_h);
2705 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2706 "force-aspect-ratio", force_aspect_ratio,
2707 "origin-size", origin_size,
2712 "display-geometry-method", display_method,
2715 debug_log("set video param : method %d", display_method);
2716 debug_log("set video param : dst-roi-x: %d, dst-roi-y: %d, dst-roi-w: %d, dst-roi-h: %d",
2717 roi_x, roi_y, roi_w, roi_h );
2718 debug_log("set video param : force aspect ratio %d", force_aspect_ratio);
2719 debug_log("set video param : display_evas_do_scaling %d (origin-size %d)", scaling, origin_size);
2723 case MM_DISPLAY_SURFACE_X_EXT: /* NOTE : this surface type is for the video texture(canvas texture) */
2725 void *pixmap_id_cb = NULL;
2726 void *pixmap_id_cb_user_data = NULL;
2727 int display_method = 0;
2728 gboolean visible = TRUE;
2730 /* if xvimagesink */
2731 if (strcmp(PLAYER_INI()->videosink_element_x,"xvimagesink"))
2733 debug_error("videosink is not xvimagesink");
2734 return MM_ERROR_PLAYER_INTERNAL;
2737 /* get information from attributes */
2738 mm_attrs_get_data_by_name(attrs, "display_overlay", &pixmap_id_cb);
2739 mm_attrs_get_data_by_name(attrs, "display_overlay_user_data", &pixmap_id_cb_user_data);
2740 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
2744 debug_log("set video param : display_overlay(0x%x)", pixmap_id_cb);
2745 if (pixmap_id_cb_user_data)
2747 debug_log("set video param : display_overlay_user_data(0x%x)", pixmap_id_cb_user_data);
2752 debug_error("failed to set pixmap-id-callback");
2753 return MM_ERROR_PLAYER_INTERNAL;
2755 debug_log("set video param : method %d", display_method);
2756 debug_log("set video param : visible %d", visible);
2758 /* set properties of videosink plugin */
2759 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2760 "display-geometry-method", display_method,
2761 "draw-borders", FALSE,
2763 "pixmap-id-callback", pixmap_id_cb,
2764 "pixmap-id-callback-userdata", pixmap_id_cb_user_data,
2768 case MM_DISPLAY_SURFACE_NULL:
2777 return MM_ERROR_NONE;
2781 __mmplayer_gst_element_link_bucket(GList* element_bucket) // @
2783 GList* bucket = element_bucket;
2784 MMPlayerGstElement* element = NULL;
2785 MMPlayerGstElement* prv_element = NULL;
2786 gint successful_link_count = 0;
2790 return_val_if_fail(element_bucket, -1);
2792 prv_element = (MMPlayerGstElement*)bucket->data;
2793 bucket = bucket->next;
2795 for ( ; bucket; bucket = bucket->next )
2797 element = (MMPlayerGstElement*)bucket->data;
2799 if ( element && element->gst )
2801 if ( GST_ELEMENT_LINK(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst)) )
2803 debug_log("linking [%s] to [%s] success\n",
2804 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2805 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)) );
2806 successful_link_count ++;
2810 debug_log("linking [%s] to [%s] failed\n",
2811 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2812 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)) );
2817 prv_element = element;
2822 return successful_link_count;
2826 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket) // @
2828 GList* bucket = element_bucket;
2829 MMPlayerGstElement* element = NULL;
2830 int successful_add_count = 0;
2834 return_val_if_fail(element_bucket, 0);
2835 return_val_if_fail(bin, 0);
2837 for ( ; bucket; bucket = bucket->next )
2839 element = (MMPlayerGstElement*)bucket->data;
2841 if ( element && element->gst )
2843 if( !gst_bin_add(bin, GST_ELEMENT(element->gst)) )
2845 debug_log("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed\n",
2846 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2847 GST_ELEMENT_NAME(GST_ELEMENT(bin) ) );
2850 successful_add_count ++;
2856 return successful_add_count;
2862 * This function is to create audio pipeline for playing.
2864 * @param player [in] handle of player
2866 * @return This function returns zero on success.
2868 * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_pipeline
2870 #define MMPLAYER_CREATEONLY_ELEMENT(x_bin, x_id, x_factory, x_name) \
2871 x_bin[x_id].id = x_id;\
2872 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
2873 if ( ! x_bin[x_id].gst )\
2875 debug_critical("failed to create %s \n", x_factory);\
2879 #define MMPLAYER_CREATE_ELEMENT_ADD_BIN(x_bin, x_id, x_factory, x_name, y_bin) \
2880 x_bin[x_id].id = x_id;\
2881 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
2882 if ( ! x_bin[x_id].gst )\
2884 debug_critical("failed to create %s \n", x_factory);\
2887 if( !gst_bin_add(GST_BIN(y_bin), GST_ELEMENT(x_bin[x_id].gst)))\
2889 debug_log("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed\n",\
2890 GST_ELEMENT_NAME(GST_ELEMENT(x_bin[x_id].gst)),\
2891 GST_ELEMENT_NAME(GST_ELEMENT(y_bin) ) );\
2895 /* macro for code readability. just for sinkbin-creation functions */
2896 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket) \
2899 x_bin[x_id].id = x_id;\
2900 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
2901 if ( ! x_bin[x_id].gst )\
2903 debug_critical("failed to create %s \n", x_factory);\
2906 if ( x_add_bucket )\
2907 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
2913 * - Local playback : audioconvert !volume ! capsfilter ! audioeq ! audiosink
2914 * - Streaming : audioconvert !volume ! audiosink
2915 * - PCM extraction : audioconvert ! audioresample ! capsfilter ! fakesink
2918 __mmplayer_gst_create_audio_pipeline(mm_player_t* player)
2920 MMPlayerGstElement* first_element = NULL;
2921 MMPlayerGstElement* audiobin = NULL;
2922 MMHandleType attrs = 0;
2924 GstPad *ghostpad = NULL;
2925 GList* element_bucket = NULL;
2926 char *device_name = NULL;
2927 gboolean link_audio_sink_now = TRUE;
2932 return_val_if_fail( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
2935 audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
2939 debug_error("failed to allocate memory for audiobin\n");
2940 return MM_ERROR_PLAYER_NO_FREE_SPACE;
2943 attrs = MMPLAYER_GET_ATTRS(player);
2946 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
2947 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
2948 if ( !audiobin[MMPLAYER_A_BIN].gst )
2950 debug_critical("failed to create audiobin\n");
2955 player->pipeline->audiobin = audiobin;
2957 player->is_sound_extraction = __mmplayer_can_extract_pcm(player);
2959 /* Adding audiotp plugin for reverse trickplay feature */
2960 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TP, "audiotp", "audiotrickplay", TRUE);
2963 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audioconverter", TRUE);
2965 if ( ! player->is_sound_extraction )
2967 GstCaps* caps = NULL;
2970 /* for logical volume control */
2971 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE);
2972 g_object_set(G_OBJECT (audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2974 if (player->sound.mute)
2976 debug_log("mute enabled\n");
2977 g_object_set(G_OBJECT (audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2981 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE);
2983 caps = gst_caps_from_string( "audio/x-raw-int, "
2984 "endianness = (int) LITTLE_ENDIAN, "
2985 "signed = (boolean) true, "
2986 "width = (int) 16, "
2987 "depth = (int) 16" );
2988 g_object_set (GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL );
2990 gst_caps_unref( caps );
2992 /* chech if multi-chennels */
2993 if (player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)
2995 GstPad *srcpad = NULL;
2996 GstCaps *caps = NULL;
2998 if (srcpad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "src"))
3000 if (caps = gst_pad_get_caps(srcpad))
3002 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
3003 GstStructure *str = gst_caps_get_structure(caps, 0);
3005 gst_structure_get_int (str, "channels", &channels);
3006 gst_caps_unref(caps);
3008 gst_object_unref(srcpad);
3012 /* audio effect element. if audio effect is enabled */
3013 if ( channels <= 2 && (PLAYER_INI()->use_audio_effect_preset || PLAYER_INI()->use_audio_effect_custom) )
3015 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, PLAYER_INI()->name_of_audio_effect, "audiofilter", TRUE);
3018 /* create audio sink */
3019 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, PLAYER_INI()->name_of_audiosink,
3020 "audiosink", link_audio_sink_now);
3023 if (MMPLAYER_IS_RTSP_STREAMING(player))
3024 g_object_set (G_OBJECT (audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL); /* sync off */
3026 g_object_set (G_OBJECT (audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE, NULL); /* sync on */
3029 g_object_set (G_OBJECT (audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
3031 /* FIXIT : using system clock. isn't there another way? */
3032 g_object_set (G_OBJECT (audiobin[MMPLAYER_A_SINK].gst), "provide-clock", PLAYER_INI()->provide_clock, NULL);
3034 __mmplayer_add_sink( player, audiobin[MMPLAYER_A_SINK].gst );
3036 if(player->audio_buffer_cb)
3038 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "audio-handle", player->audio_buffer_cb_user_param, NULL);
3039 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "audio-callback", player->audio_buffer_cb, NULL);
3042 if ( g_strrstr(PLAYER_INI()->name_of_audiosink, "avsysaudiosink") )
3044 gint volume_type = 0;
3045 gint audio_route = 0;
3046 gint sound_priority = FALSE;
3047 gint is_spk_out_only = 0;
3048 gint latency_mode = 0;
3051 * It should be set after player creation through attribute.
3052 * But, it can not be changed during playing.
3054 mm_attrs_get_int_by_name(attrs, "sound_volume_type", &volume_type);
3055 mm_attrs_get_int_by_name(attrs, "sound_route", &audio_route);
3056 mm_attrs_get_int_by_name(attrs, "sound_priority", &sound_priority);
3057 mm_attrs_get_int_by_name(attrs, "sound_spk_out_only", &is_spk_out_only);
3058 mm_attrs_get_int_by_name(attrs, "audio_latency_mode", &latency_mode);
3060 /* hook sound_type if emergency case */
3061 if ( player->sm.event == ASM_EVENT_EMERGENCY)
3063 debug_log ("This is emergency session, hook sound_type from [%d] to [%d]\n", volume_type, MM_SOUND_VOLUME_TYPE_EMERGENCY);
3064 volume_type = MM_SOUND_VOLUME_TYPE_EMERGENCY;
3067 g_object_set(audiobin[MMPLAYER_A_SINK].gst,
3068 "volumetype", volume_type,
3069 "audio-route", audio_route,
3070 "priority", sound_priority,
3071 "user-route", is_spk_out_only,
3072 "latency", latency_mode,
3075 debug_log("audiosink property status...volume type:%d, route:%d, priority=%d, user-route=%d, latency=%d\n",
3076 volume_type, audio_route, sound_priority, is_spk_out_only, latency_mode);
3079 /* Antishock can be enabled when player is resumed by soundCM.
3080 * But, it's not used in MMS, setting and etc.
3081 * Because, player start seems like late.
3083 __mmplayer_set_antishock( player , FALSE );
3085 else // pcm extraction only and no sound output
3087 int dst_samplerate = 0;
3088 int dst_channels = 0;
3090 char *caps_type = NULL;
3091 GstCaps* caps = NULL;
3094 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, "audioresample", "resampler", TRUE);
3096 /* get conf. values */
3097 mm_attrs_multiple_get(player->attrs,
3099 "pcm_extraction_samplerate", &dst_samplerate,
3100 "pcm_extraction_channels", &dst_channels,
3101 "pcm_extraction_depth", &dst_depth,
3104 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE);
3106 caps = gst_caps_new_simple ("audio/x-raw-int",
3107 "rate", G_TYPE_INT, dst_samplerate,
3108 "channels", G_TYPE_INT, dst_channels,
3109 "depth", G_TYPE_INT, dst_depth,
3112 caps_type = gst_caps_to_string(caps);
3113 debug_log("resampler new caps : %s\n", caps_type);
3115 g_object_set (GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL );
3118 gst_caps_unref( caps );
3119 MMPLAYER_FREEIF( caps_type );
3122 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "fakesink", TRUE);
3125 g_object_set (G_OBJECT (audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL);
3127 __mmplayer_add_sink( player, audiobin[MMPLAYER_A_SINK].gst );
3130 /* adding created elements to bin */
3131 debug_log("adding created elements to bin\n");
3132 if( !__mmplayer_gst_element_add_bucket_to_bin( GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket ))
3134 debug_error("failed to add elements\n");
3138 /* linking elements in the bucket by added order. */
3139 debug_log("Linking elements in the bucket by added order.\n");
3140 if ( __mmplayer_gst_element_link_bucket(element_bucket) == -1 )
3142 debug_error("failed to link elements\n");
3146 /* get first element's sinkpad for creating ghostpad */
3147 first_element = (MMPlayerGstElement *)element_bucket->data;
3149 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3152 debug_error("failed to get pad from first element of audiobin\n");
3156 ghostpad = gst_ghost_pad_new("sink", pad);
3159 debug_error("failed to create ghostpad\n");
3163 if ( FALSE == gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad) )
3165 debug_error("failed to add ghostpad to audiobin\n");
3169 gst_object_unref(pad);
3171 if ( !player->bypass_audio_effect && (PLAYER_INI()->use_audio_effect_preset || PLAYER_INI()->use_audio_effect_custom) )
3173 if ( player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_PRESET )
3175 if (!_mmplayer_audio_effect_preset_apply(player, player->audio_effect_info.preset))
3177 debug_msg("apply audio effect(preset:%d) setting success\n",player->audio_effect_info.preset);
3180 else if ( player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM )
3182 if (!_mmplayer_audio_effect_custom_apply(player))
3184 debug_msg("apply audio effect(custom) setting success\n");
3189 /* done. free allocated variables */
3190 MMPLAYER_FREEIF( device_name );
3191 g_list_free(element_bucket);
3193 mm_attrs_set_int_by_name(attrs, "content_audio_found", TRUE);
3194 if ( mmf_attrs_commit ( attrs ) ) /* return -1 if error */
3195 debug_error("failed to commit attribute ""content_audio_found"".\n");
3199 return MM_ERROR_NONE;
3203 debug_log("ERROR : releasing audiobin\n");
3205 MMPLAYER_FREEIF( device_name );
3208 gst_object_unref(GST_OBJECT(pad));
3211 gst_object_unref(GST_OBJECT(ghostpad));
3213 g_list_free( element_bucket );
3216 /* release element which are not added to bin */
3217 for ( i = 1; i < MMPLAYER_A_NUM; i++ ) /* NOTE : skip bin */
3219 if ( audiobin[i].gst )
3221 GstObject* parent = NULL;
3222 parent = gst_element_get_parent( audiobin[i].gst );
3226 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3227 audiobin[i].gst = NULL;
3231 gst_object_unref(GST_OBJECT(parent));
3236 /* release audiobin with it's childs */
3237 if ( audiobin[MMPLAYER_A_BIN].gst )
3239 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3242 MMPLAYER_FREEIF( audiobin );
3244 player->pipeline->audiobin = NULL;
3246 return MM_ERROR_PLAYER_INTERNAL;
3250 __mmplayer_audio_stream_probe (GstPad *pad, GstBuffer *buffer, gpointer u_data)
3252 mm_player_t* player = (mm_player_t*) u_data;
3256 data = GST_BUFFER_DATA(buffer);
3257 size = GST_BUFFER_SIZE(buffer);
3259 if (player->audio_stream_cb && size && data)
3260 player->audio_stream_cb((void *)data, size, player->audio_stream_cb_user_param);
3266 * This function is to create video pipeline.
3268 * @param player [in] handle of player
3269 * caps [in] src caps of decoder
3270 * surface_type [in] surface type for video rendering
3272 * @return This function returns zero on success.
3274 * @see __mmplayer_gst_create_audio_pipeline, __mmplayer_gst_create_midi_pipeline
3278 * - x surface (arm/x86) : videoflip ! xvimagesink
3279 * - evas surface (arm) : ffmpegcolorspace ! videoflip ! evasimagesink
3280 * - evas surface (x86) : videoconvertor ! videoflip ! evasimagesink
3283 __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
3287 GList*element_bucket = NULL;
3288 MMPlayerGstElement* first_element = NULL;
3289 MMPlayerGstElement* videobin = NULL;
3290 gchar* vconv_factory = NULL;
3291 gchar *videosink_element = NULL;
3295 return_val_if_fail(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3298 videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
3301 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3304 player->pipeline->videobin = videobin;
3306 attrs = MMPLAYER_GET_ATTRS(player);
3309 debug_error("cannot get content attribute");
3310 return MM_ERROR_PLAYER_INTERNAL;
3314 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3315 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3316 if ( !videobin[MMPLAYER_V_BIN].gst )
3318 debug_critical("failed to create videobin");
3322 if( player->use_video_stream ) // video stream callback, so send raw video data to application
3324 GstStructure *str = NULL;
3327 gint width = 0; //width of video
3328 gint height = 0; //height of video
3329 GstCaps* video_caps = NULL;
3331 debug_log("using memsink\n");
3333 /* first, create colorspace convert */
3334 if (strlen(PLAYER_INI()->name_of_video_converter) > 0)
3336 vconv_factory = PLAYER_INI()->name_of_video_converter;
3341 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_CONV, vconv_factory, "video converter", TRUE);
3344 /* rotator, scaler and capsfilter */
3345 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE);
3346 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SCALE, "videoscale", "video scaler", TRUE);
3347 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_CAPS, "capsfilter", "videocapsfilter", TRUE);
3349 /* get video stream caps parsed by demuxer */
3350 str = gst_caps_get_structure (player->v_stream_caps, 0);
3353 debug_error("cannot get structure");
3357 mm_attrs_get_int_by_name(attrs, "display_width", &width);
3358 mm_attrs_get_int_by_name(attrs, "display_height", &height);
3359 if (!width || !height)
3361 /* we set width/height of original media's size to capsfilter for scaling video */
3362 ret = gst_structure_get_int (str, "width", &width);
3365 debug_error("cannot get width");
3369 ret = gst_structure_get_int(str, "height", &height);
3372 debug_error("cannot get height");
3377 video_caps = gst_caps_new_simple( "video/x-raw-rgb",
3378 "width", G_TYPE_INT, width,
3379 "height", G_TYPE_INT, height,
3382 g_object_set (GST_ELEMENT(videobin[MMPLAYER_V_CAPS].gst), "caps", video_caps, NULL );
3384 gst_caps_unref( video_caps );
3386 /* finally, create video sink. output will be BGRA8888. */
3387 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, "avsysmemsink", "videosink", TRUE);
3389 MMPLAYER_SIGNAL_CONNECT( player,
3390 videobin[MMPLAYER_V_SINK].gst,
3392 G_CALLBACK(__mmplayer_videostream_cb),
3395 else // render video data using sink plugin like xvimagesink
3397 debug_log("using videosink");
3399 /* set video converter */
3400 if (strlen(PLAYER_INI()->name_of_video_converter) > 0)
3402 vconv_factory = PLAYER_INI()->name_of_video_converter;
3405 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_CONV, vconv_factory, "video converter", TRUE);
3406 debug_log("using video converter: %s", vconv_factory);
3410 /* set video rotator */
3411 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE);
3414 #if !defined(__arm__)
3415 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SCALE, "videoscale", "videoscaler", TRUE);
3418 /* set video sink */
3419 switch (surface_type)
3421 case MM_DISPLAY_SURFACE_X:
3422 if (strlen(PLAYER_INI()->videosink_element_x) > 0)
3423 videosink_element = PLAYER_INI()->videosink_element_x;
3427 case MM_DISPLAY_SURFACE_EVAS:
3428 if (strlen(PLAYER_INI()->videosink_element_evas) > 0)
3429 videosink_element = PLAYER_INI()->videosink_element_evas;
3433 case MM_DISPLAY_SURFACE_X_EXT:
3435 void *pixmap_id_cb = NULL;
3436 mm_attrs_get_data_by_name(attrs, "display_overlay", &pixmap_id_cb);
3437 if (pixmap_id_cb) /* this is for the video textue(canvas texture) */
3439 videosink_element = PLAYER_INI()->videosink_element_x;
3440 debug_warning("video texture usage");
3444 debug_error("something wrong.. callback function for getting pixmap id is null");
3449 case MM_DISPLAY_SURFACE_NULL:
3450 if (strlen(PLAYER_INI()->videosink_element_fake) > 0)
3451 videosink_element = PLAYER_INI()->videosink_element_fake;
3456 debug_error("unidentified surface type");
3460 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_element, videosink_element, TRUE);
3461 debug_log("selected videosink name: %s", videosink_element);
3464 if ( _mmplayer_update_video_param(player) != MM_ERROR_NONE)
3468 g_object_set (G_OBJECT (videobin[MMPLAYER_V_SINK].gst), "qos", TRUE, NULL);
3470 /* store it as it's sink element */
3471 __mmplayer_add_sink( player, videobin[MMPLAYER_V_SINK].gst );
3473 /* adding created elements to bin */
3474 if( ! __mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket) )
3476 debug_error("failed to add elements\n");
3480 /* Linking elements in the bucket by added order */
3481 if ( __mmplayer_gst_element_link_bucket(element_bucket) == -1 )
3483 debug_error("failed to link elements\n");
3487 /* get first element's sinkpad for creating ghostpad */
3488 first_element = (MMPlayerGstElement *)element_bucket->data;
3489 if ( !first_element )
3491 debug_error("failed to get first element from bucket\n");
3495 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3498 debug_error("failed to get pad from first element\n");
3502 /* create ghostpad */
3503 if (FALSE == gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, gst_ghost_pad_new("sink", pad)))
3505 debug_error("failed to add ghostpad to videobin\n");
3508 gst_object_unref(pad);
3510 /* done. free allocated variables */
3511 g_list_free(element_bucket);
3513 mm_attrs_set_int_by_name(attrs, "content_video_found", TRUE);
3514 if ( mmf_attrs_commit ( attrs ) ) /* return -1 if error */
3515 debug_error("failed to commit attribute ""content_video_found"".\n");
3519 return MM_ERROR_NONE;
3522 debug_error("ERROR : releasing videobin\n");
3524 g_list_free( element_bucket );
3527 gst_object_unref(GST_OBJECT(pad));
3529 /* release videobin with it's childs */
3530 if ( videobin[MMPLAYER_V_BIN].gst )
3532 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3536 MMPLAYER_FREEIF( videobin );
3538 player->pipeline->videobin = NULL;
3540 return MM_ERROR_PLAYER_INTERNAL;
3543 static int __mmplayer_gst_create_text_pipeline(mm_player_t* player)
3545 MMPlayerGstElement* first_element = NULL;
3546 MMPlayerGstElement* textbin = NULL;
3547 GList* element_bucket = NULL;
3549 GstPad *ghostpad = NULL;
3554 return_val_if_fail( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
3557 textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
3560 debug_error("failed to allocate memory for textbin\n");
3561 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3565 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3566 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3567 if ( !textbin[MMPLAYER_T_BIN].gst )
3569 debug_critical("failed to create textbin\n");
3574 player->pipeline->textbin = textbin;
3577 if (player->use_textoverlay)
3579 debug_log ("use textoverlay for displaying \n");
3581 MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_TEXT_QUEUE, "queue", "text_t_queue", textbin[MMPLAYER_T_BIN].gst);
3583 MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_VIDEO_QUEUE, "queue", "text_v_queue", textbin[MMPLAYER_T_BIN].gst);
3585 MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_VIDEO_CONVERTER, "fimcconvert", "text_v_converter", textbin[MMPLAYER_T_BIN].gst);
3587 MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_OVERLAY, "textoverlay", "text_overlay", textbin[MMPLAYER_T_BIN].gst);
3589 if (!gst_element_link_pads (textbin[MMPLAYER_T_VIDEO_QUEUE].gst, "src", textbin[MMPLAYER_T_VIDEO_CONVERTER].gst, "sink"))
3591 debug_error("failed to link queue and converter\n");
3595 if (!gst_element_link_pads (textbin[MMPLAYER_T_VIDEO_CONVERTER].gst, "src", textbin[MMPLAYER_T_OVERLAY].gst, "video_sink"))
3597 debug_error("failed to link queue and textoverlay\n");
3601 if (!gst_element_link_pads (textbin[MMPLAYER_T_TEXT_QUEUE].gst, "src", textbin[MMPLAYER_T_OVERLAY].gst, "text_sink"))
3603 debug_error("failed to link queue and textoverlay\n");
3610 debug_log ("use subtitle message for displaying \n");
3612 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_TEXT_QUEUE, "queue", "text_queue", TRUE);
3614 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_SINK, "fakesink", "text_sink", TRUE);
3616 g_object_set (G_OBJECT (textbin[MMPLAYER_T_SINK].gst), "sync", TRUE, NULL);
3617 g_object_set (G_OBJECT (textbin[MMPLAYER_T_SINK].gst), "async", FALSE, NULL);
3618 g_object_set (G_OBJECT (textbin[MMPLAYER_T_SINK].gst), "signal-handoffs", TRUE, NULL);
3620 MMPLAYER_SIGNAL_CONNECT( player,
3621 G_OBJECT(textbin[MMPLAYER_T_SINK].gst),
3623 G_CALLBACK(__mmplayer_update_subtitle),
3626 if (!player->play_subtitle)
3628 debug_log ("add textbin sink as sink element of whole pipeline.\n");
3629 __mmplayer_add_sink (player, GST_ELEMENT(textbin[MMPLAYER_T_SINK].gst));
3632 /* adding created elements to bin */
3633 debug_log("adding created elements to bin\n");
3634 if( !__mmplayer_gst_element_add_bucket_to_bin( GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket ))
3636 debug_error("failed to add elements\n");
3640 /* linking elements in the bucket by added order. */
3641 debug_log("Linking elements in the bucket by added order.\n");
3642 if ( __mmplayer_gst_element_link_bucket(element_bucket) == -1 )
3644 debug_error("failed to link elements\n");
3648 /* done. free allocated variables */
3649 g_list_free(element_bucket);
3652 if (textbin[MMPLAYER_T_TEXT_QUEUE].gst)
3654 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_TEXT_QUEUE].gst), "sink");
3657 debug_error("failed to get text pad of textbin\n");
3661 ghostpad = gst_ghost_pad_new("text_sink", pad);
3664 debug_error("failed to create ghostpad of textbin\n");
3668 if ( FALSE == gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad) )
3670 debug_error("failed to add ghostpad to textbin\n");
3675 if (textbin[MMPLAYER_T_VIDEO_QUEUE].gst)
3677 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_VIDEO_QUEUE].gst), "sink");
3680 debug_error("failed to get video pad of textbin\n");
3684 ghostpad = gst_ghost_pad_new("video_sink", pad);
3687 debug_error("failed to create ghostpad of textbin\n");
3691 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad))
3693 debug_error("failed to add ghostpad to textbin\n");
3698 if (textbin[MMPLAYER_T_OVERLAY].gst)
3700 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_OVERLAY].gst), "src");
3703 debug_error("failed to get src pad of textbin\n");
3707 ghostpad = gst_ghost_pad_new("src", pad);
3710 debug_error("failed to create ghostpad of textbin\n");
3714 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad))
3716 debug_error("failed to add ghostpad to textbin\n");
3721 gst_object_unref(pad);
3725 return MM_ERROR_NONE;
3729 debug_log("ERROR : releasing textbin\n");
3732 gst_object_unref(GST_OBJECT(pad));
3735 gst_object_unref(GST_OBJECT(ghostpad));
3737 g_list_free( element_bucket );
3740 /* release element which are not added to bin */
3741 for ( i = 1; i < MMPLAYER_T_NUM; i++ ) /* NOTE : skip bin */
3743 if ( textbin[i].gst )
3745 GstObject* parent = NULL;
3746 parent = gst_element_get_parent( textbin[i].gst );
3750 gst_object_unref(GST_OBJECT(textbin[i].gst));
3751 textbin[i].gst = NULL;
3755 gst_object_unref(GST_OBJECT(parent));
3760 /* release textbin with it's childs */
3761 if ( textbin[MMPLAYER_T_BIN].gst )
3763 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3766 MMPLAYER_FREEIF( textbin );
3768 player->pipeline->textbin = NULL;
3770 return MM_ERROR_PLAYER_INTERNAL;
3775 __mmplayer_gst_create_subtitle_src(mm_player_t* player)
3777 MMPlayerGstElement* mainbin = NULL;
3778 MMHandleType attrs = 0;
3779 GstElement * pipeline = NULL;
3780 GstElement *subsrc = NULL;
3781 GstElement *subparse = NULL;
3782 GstPad *sinkpad = NULL;
3783 gchar *subtitle_uri =NULL;
3784 gchar *charset = NULL;
3789 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3791 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
3792 mainbin = player->pipeline->mainbin;
3794 attrs = MMPLAYER_GET_ATTRS(player);
3797 debug_error("cannot get content attribute\n");
3798 return MM_ERROR_PLAYER_INTERNAL;
3801 mm_attrs_get_string_by_name ( attrs, "subtitle_uri", &subtitle_uri );
3802 if ( !subtitle_uri || strlen(subtitle_uri) < 1)
3804 debug_error("subtitle uri is not proper filepath.\n");
3805 return MM_ERROR_PLAYER_INVALID_URI;
3807 debug_log("subtitle file path is [%s].\n", subtitle_uri);
3810 /* create the subtitle source */
3811 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3814 debug_error ( "failed to create filesrc element\n" );
3817 g_object_set(G_OBJECT (subsrc), "location", subtitle_uri, NULL);
3819 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3820 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3822 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc))
3824 debug_warning("failed to add queue\n");
3829 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3832 debug_error ( "failed to create subparse element\n" );
3836 charset = util_get_charset(subtitle_uri);
3839 debug_log ("detected charset is %s\n", charset );
3840 g_object_set (G_OBJECT (subparse), "subtitle-encoding", charset, NULL);
3843 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3844 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3846 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse))
3848 debug_warning("failed to add subparse\n");
3852 if (!gst_element_link_pads (subsrc, "src", subparse, "sink"))
3854 debug_warning("failed to link subsrc and subparse\n");
3858 player->play_subtitle = TRUE;
3859 debug_log ("play subtitle using subtitle file\n");
3861 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player))
3863 debug_error("failed to create textbin. continuing without text\n");
3867 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(player->pipeline->textbin[MMPLAYER_T_BIN].gst)))
3869 debug_warning("failed to add textbin\n");
3873 if (!gst_element_link_pads (subparse, "src", player->pipeline->textbin[MMPLAYER_T_BIN].gst, "text_sink"))
3875 debug_warning("failed to link subparse and textbin\n");
3881 return MM_ERROR_NONE;
3885 return MM_ERROR_PLAYER_INTERNAL;
3889 __mmplayer_update_subtitle( GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
3891 mm_player_t* player = (mm_player_t*) data;
3892 MMMessageParamType msg = {0, };
3893 GstClockTime duration = 0;
3894 guint8 *text = NULL;
3895 gboolean ret = TRUE;
3899 return_val_if_fail ( player, FALSE );
3900 return_val_if_fail ( buffer, FALSE );
3902 text = GST_BUFFER_DATA(buffer);
3903 duration = GST_BUFFER_DURATION(buffer);
3905 if ( player->is_subtitle_off )
3907 debug_log("subtitle is OFF.\n" );
3913 debug_log("There is no subtitle to be displayed.\n" );
3917 msg.data = (void *) text;
3918 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
3920 debug_warning("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data );
3922 MMPLAYER_POST_MSG( player, MM_MESSAGE_UPDATE_SUBTITLE, &msg );
3929 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
3931 GstEvent* event = NULL;
3932 gint64 current_pos = 0;
3933 gint64 adusted_pos = 0;
3934 gboolean ret = TRUE;
3938 /* check player and subtitlebin are created */
3939 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
3940 return_val_if_fail ( player->play_subtitle, MM_ERROR_NOT_SUPPORT_API );
3944 debug_log ("nothing to do\n");
3945 return MM_ERROR_NONE;
3950 case MM_PLAYER_POS_FORMAT_TIME:
3952 /* check current postion */
3953 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, ¤t_pos ))
3955 debug_error("failed to get position");
3956 return MM_ERROR_PLAYER_INTERNAL;
3959 adusted_pos = (gint64)current_pos + ((gint64)position * G_GINT64_CONSTANT(1000000));
3960 if (adusted_pos < 0)
3961 adusted_pos = G_GUINT64_CONSTANT(0);
3962 debug_log("adjust subtitle postion : %lu -> %lu [msec]\n", GST_TIME_AS_MSECONDS(current_pos), GST_TIME_AS_MSECONDS(adusted_pos));
3964 event = gst_event_new_seek (1.0, GST_FORMAT_TIME,
3965 ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ),
3966 GST_SEEK_TYPE_SET, adusted_pos,
3967 GST_SEEK_TYPE_SET, -1);
3973 debug_warning("invalid format.\n");
3974 return MM_ERROR_INVALID_ARGUMENT;
3978 /* keep ref to the event */
3979 gst_event_ref (event);
3981 debug_log("sending event[%s] to subparse element [%s]\n",
3982 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SUBPARSE].gst) );
3984 if (gst_element_send_event (player->pipeline->mainbin[MMPLAYER_M_SUBPARSE].gst, event))
3986 debug_log("sending event[%s] to subparse element [%s] success!\n",
3987 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SUBPARSE].gst) );
3990 /* unref to the event */
3991 gst_event_unref (event);
3995 return MM_ERROR_NONE;
3999 __gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data) // @
4001 GstElement *appsrc = element;
4002 tBuffer *buf = (tBuffer *)user_data;
4003 GstBuffer *buffer = NULL;
4004 GstFlowReturn ret = GST_FLOW_OK;
4007 return_if_fail ( element );
4008 return_if_fail ( buf );
4010 buffer = gst_buffer_new ();
4012 if (buf->offset >= buf->len)
4014 debug_log("call eos appsrc\n");
4015 g_signal_emit_by_name (appsrc, "end-of-stream", &ret);
4019 if ( buf->len - buf->offset < size)
4021 len = buf->len - buf->offset + buf->offset;
4024 GST_BUFFER_DATA(buffer) = (guint8*)(buf->buf + buf->offset);
4025 GST_BUFFER_SIZE(buffer) = len;
4026 GST_BUFFER_OFFSET(buffer) = buf->offset;
4027 GST_BUFFER_OFFSET_END(buffer) = buf->offset + len;
4029 debug_log("feed buffer %p, offset %u-%u length %u\n", buffer, buf->offset, buf->len,len);
4030 g_signal_emit_by_name (appsrc, "push-buffer", buffer, &ret);
4036 __gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data) // @
4038 tBuffer *buf = (tBuffer *)user_data;
4040 return_val_if_fail ( buf, FALSE );
4042 buf->offset = (int)size;
4048 __gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data) // @
4050 mm_player_t *player = (mm_player_t*)user_data;
4052 return_if_fail ( player );
4054 debug_msg("app-src: feed data\n");
4056 if(player->need_data_cb)
4057 player->need_data_cb(size, player->buffer_cb_user_param);
4061 __gst_appsrc_seek_data(GstElement *element, guint64 offset, gpointer user_data) // @
4063 mm_player_t *player = (mm_player_t*)user_data;
4065 return_val_if_fail ( player, FALSE );
4067 debug_msg("app-src: seek data\n");
4069 if(player->seek_data_cb)
4070 player->seek_data_cb(offset, player->buffer_cb_user_param);
4077 __gst_appsrc_enough_data(GstElement *element, gpointer user_data) // @
4079 mm_player_t *player = (mm_player_t*)user_data;
4081 return_val_if_fail ( player, FALSE );
4083 debug_msg("app-src: enough data:%p\n", player->enough_data_cb);
4085 if(player->enough_data_cb)
4086 player->enough_data_cb(player->buffer_cb_user_param);
4092 _mmplayer_push_buffer(MMHandleType hplayer, unsigned char *buf, int size) // @
4094 mm_player_t* player = (mm_player_t*)hplayer;
4095 GstBuffer *buffer = NULL;
4096 GstFlowReturn gst_ret = GST_FLOW_OK;
4097 int ret = MM_ERROR_NONE;
4101 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
4103 /* check current state */
4104 // MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_START );
4107 /* NOTE : we should check and create pipeline again if not created as we destroy
4108 * whole pipeline when stopping in streamming playback
4110 if ( ! player->pipeline )
4112 if ( MM_ERROR_NONE != __gst_realize( player ) )
4114 debug_error("failed to realize before starting. only in streamming\n");
4115 return MM_ERROR_PLAYER_INTERNAL;
4119 debug_msg("app-src: pushing data\n");
4123 debug_error("buf is null\n");
4124 return MM_ERROR_NONE;
4127 buffer = gst_buffer_new ();
4131 debug_log("call eos appsrc\n");
4132 g_signal_emit_by_name (player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "end-of-stream", &gst_ret);
4133 return MM_ERROR_NONE;
4136 GST_BUFFER_DATA(buffer) = (guint8*)(buf);
4137 GST_BUFFER_SIZE(buffer) = size;
4139 debug_log("feed buffer %p, length %u\n", buf, size);
4140 g_signal_emit_by_name (player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "push-buffer", buffer, &gst_ret);
4147 static GstBusSyncReply
4148 __mmplayer_bus_sync_callback (GstBus * bus, GstMessage * message, gpointer data)
4150 mm_player_t *player = (mm_player_t *)data;
4152 switch (GST_MESSAGE_TYPE (message))
4154 case GST_MESSAGE_TAG:
4155 __mmplayer_gst_extract_tag_from_msg(player, message);
4159 return GST_BUS_PASS;
4161 gst_message_unref (message);
4163 return GST_BUS_DROP;
4167 * This function is to create audio or video pipeline for playing.
4169 * @param player [in] handle of player
4171 * @return This function returns zero on success.
4176 __mmplayer_gst_create_pipeline(mm_player_t* player) // @
4179 MMPlayerGstElement *mainbin = NULL;
4180 MMHandleType attrs = 0;
4181 GstElement* element = NULL;
4182 GList* element_bucket = NULL;
4183 gboolean need_state_holder = TRUE;
4188 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4190 /* get profile attribute */
4191 attrs = MMPLAYER_GET_ATTRS(player);
4194 debug_error("cannot get content attribute\n");
4198 /* create pipeline handles */
4199 if ( player->pipeline )
4201 debug_warning("pipeline should be released before create new one\n");
4205 player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0( sizeof(MMPlayerGstPipelineInfo) );
4206 if (player->pipeline == NULL)
4209 memset( player->pipeline, 0, sizeof(MMPlayerGstPipelineInfo) );
4212 /* create mainbin */
4213 mainbin = (MMPlayerGstElement*) g_malloc0( sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM );
4214 if (mainbin == NULL)
4217 memset( mainbin, 0, sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
4220 /* create pipeline */
4221 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4222 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4223 if ( ! mainbin[MMPLAYER_M_PIPE].gst )
4225 debug_error("failed to create pipeline\n");
4230 /* create source element */
4231 switch ( player->profile.uri_type )
4233 /* rtsp streamming */
4234 case MM_PLAYER_URI_TYPE_URL_RTSP:
4236 gint network_bandwidth;
4237 gchar *user_agent, *wap_profile;
4239 element = gst_element_factory_make(PLAYER_INI()->name_of_rtspsrc, "streaming_source");
4243 debug_critical("failed to create streaming source element\n");
4247 debug_log("using streamming source [%s].\n", PLAYER_INI()->name_of_rtspsrc);
4250 network_bandwidth = 0;
4251 user_agent = wap_profile = NULL;
4254 mm_attrs_get_string_by_name ( attrs, "streaming_user_agent", &user_agent );
4255 mm_attrs_get_string_by_name ( attrs,"streaming_wap_profile", &wap_profile );
4256 mm_attrs_get_int_by_name ( attrs, "streaming_network_bandwidth", &network_bandwidth );
4258 debug_log("setting streaming source ----------------\n");
4259 debug_log("user_agent : %s\n", user_agent);
4260 debug_log("wap_profile : %s\n", wap_profile);
4261 debug_log("network_bandwidth : %d\n", network_bandwidth);
4262 debug_log("buffering time : %d\n", PLAYER_INI()->rtsp_buffering_time);
4263 debug_log("rebuffering time : %d\n", PLAYER_INI()->rtsp_rebuffering_time);
4264 debug_log("-----------------------------------------\n");
4266 /* setting property to streaming source */
4267 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
4268 g_object_set(G_OBJECT(element), "bandwidth", network_bandwidth, NULL);
4269 g_object_set(G_OBJECT(element), "buffering_time", PLAYER_INI()->rtsp_buffering_time, NULL);
4270 g_object_set(G_OBJECT(element), "rebuffering_time", PLAYER_INI()->rtsp_rebuffering_time, NULL);
4272 g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL);
4274 g_object_set(G_OBJECT(element), "wap_profile", wap_profile, NULL);
4276 MMPLAYER_SIGNAL_CONNECT ( player, G_OBJECT(element), "pad-added",
4277 G_CALLBACK (__mmplayer_gst_rtp_dynamic_pad), player );
4278 MMPLAYER_SIGNAL_CONNECT ( player, G_OBJECT(element), "no-more-pads",
4279 G_CALLBACK (__mmplayer_gst_rtp_no_more_pads), player );
4281 player->no_more_pad = FALSE;
4282 player->num_dynamic_pad = 0;
4284 /* NOTE : we cannot determine it yet. this filed will be filled by
4285 * _mmplayer_update_content_attrs() after START.
4287 player->streaming_type = STREAMING_SERVICE_NONE;
4292 case MM_PLAYER_URI_TYPE_URL_HTTP:
4294 gchar *user_agent, *proxy, *cookies, **cookie_list;
4295 user_agent = proxy = cookies = NULL;
4297 gint mode = MM_PLAYER_PD_MODE_NONE;
4299 mm_attrs_get_int_by_name ( attrs, "pd_mode", &mode );
4301 player->pd_mode = mode;
4303 debug_log("http playback, PD mode : %d\n", player->pd_mode);
4305 if ( ! MMPLAYER_IS_HTTP_PD(player) )
4307 element = gst_element_factory_make(PLAYER_INI()->name_of_httpsrc, "http_streaming_source");
4310 debug_critical("failed to create http streaming source element[%s].\n", PLAYER_INI()->name_of_httpsrc);
4313 debug_log("using http streamming source [%s].\n", PLAYER_INI()->name_of_httpsrc);
4316 mm_attrs_get_string_by_name ( attrs, "streaming_cookie", &cookies );
4317 mm_attrs_get_string_by_name ( attrs, "streaming_user_agent", &user_agent );
4318 mm_attrs_get_string_by_name ( attrs, "streaming_proxy", &proxy );
4321 debug_log("setting http streaming source ----------------\n");
4322 debug_log("location : %s\n", player->profile.uri);
4323 debug_log("cookies : %s\n", cookies);
4324 debug_log("proxy : %s\n", proxy);
4325 debug_log("user_agent : %s\n", user_agent);
4326 debug_log("timeout : %d\n", PLAYER_INI()->http_timeout);
4327 debug_log("-----------------------------------------\n");
4329 /* setting property to streaming source */
4330 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
4331 g_object_set(G_OBJECT(element), "timeout", PLAYER_INI()->http_timeout, NULL);
4332 /* check if prosy is vailid or not */
4333 if ( util_check_valid_url ( proxy ) )
4334 g_object_set(G_OBJECT(element), "proxy", proxy, NULL);
4335 /* parsing cookies */
4336 if ( ( cookie_list = util_get_cookie_list ((const char*)cookies) ) )
4337 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
4339 g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL);
4341 else // progressive download
4343 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
4347 mm_attrs_get_string_by_name ( attrs, "pd_location", &path );
4349 MMPLAYER_FREEIF(player->pd_file_save_path);
4351 debug_log("PD Location : %s\n", path);
4355 player->pd_file_save_path = g_strdup(path);
4359 debug_error("can't find pd location so, it should be set \n");
4360 return MM_ERROR_PLAYER_FILE_NOT_FOUND;
4364 element = gst_element_factory_make("pdpushsrc", "PD pushsrc");
4367 debug_critical("failed to create PD push source element[%s].\n", "pdpushsrc");
4371 g_object_set(G_OBJECT(element), "location", player->pd_file_save_path, NULL);
4374 player->streaming_type = STREAMING_SERVICE_NONE;
4379 case MM_PLAYER_URI_TYPE_FILE:
4381 char* drmsrc = PLAYER_INI()->name_of_drmsrc;
4383 debug_log("using [%s] for 'file://' handler.\n", drmsrc);
4385 element = gst_element_factory_make(drmsrc, "source");
4388 debug_critical("failed to create %s\n", drmsrc);
4392 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
4393 //g_object_set(G_OBJECT(element), "use-mmap", TRUE, NULL);
4398 case MM_PLAYER_URI_TYPE_BUFF:
4400 guint64 stream_type = GST_APP_STREAM_TYPE_STREAM;
4402 debug_log("mem src is selected\n");
4404 element = gst_element_factory_make("appsrc", "buff-source");
4407 debug_critical("failed to create appsrc element\n");
4411 g_object_set( element, "stream-type", stream_type, NULL );
4412 //g_object_set( element, "size", player->mem_buf.len, NULL );
4413 //g_object_set( element, "blocksize", (guint64)20480, NULL );
4415 MMPLAYER_SIGNAL_CONNECT( player, element, "seek-data",
4416 G_CALLBACK(__gst_appsrc_seek_data), player);
4417 MMPLAYER_SIGNAL_CONNECT( player, element, "need-data",
4418 G_CALLBACK(__gst_appsrc_feed_data), player);
4419 MMPLAYER_SIGNAL_CONNECT( player, element, "enough-data",
4420 G_CALLBACK(__gst_appsrc_enough_data), player);
4425 case MM_PLAYER_URI_TYPE_MEM:
4427 guint64 stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
4429 debug_log("mem src is selected\n");
4431 element = gst_element_factory_make("appsrc", "mem-source");
4434 debug_critical("failed to create appsrc element\n");
4438 g_object_set( element, "stream-type", stream_type, NULL );
4439 g_object_set( element, "size", player->mem_buf.len, NULL );
4440 g_object_set( element, "blocksize", (guint64)20480, NULL );
4442 MMPLAYER_SIGNAL_CONNECT( player, element, "seek-data",
4443 G_CALLBACK(__gst_appsrc_seek_data_mem), &player->mem_buf );
4444 MMPLAYER_SIGNAL_CONNECT( player, element, "need-data",
4445 G_CALLBACK(__gst_appsrc_feed_data_mem), &player->mem_buf );
4448 case MM_PLAYER_URI_TYPE_URL:
4451 case MM_PLAYER_URI_TYPE_TEMP:
4454 case MM_PLAYER_URI_TYPE_NONE:
4459 /* check source element is OK */
4462 debug_critical("no source element was created.\n");
4466 /* take source element */
4467 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4468 mainbin[MMPLAYER_M_SRC].gst = element;
4469 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
4471 if (MMPLAYER_IS_STREAMING(player))
4473 player->streamer = __mm_player_streaming_create();
4474 __mm_player_streaming_initialize(player->streamer);
4477 if ( MMPLAYER_IS_HTTP_PD(player) )
4479 debug_log ("Picked queue2 element....\n");
4480 element = gst_element_factory_make("queue2", "hls_stream_buffer");
4483 debug_critical ( "failed to create http streaming buffer element\n" );
4488 mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_S_BUFFER;
4489 mainbin[MMPLAYER_M_S_BUFFER].gst = element;
4490 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_S_BUFFER]);
4492 __mm_player_streaming_set_buffer(player->streamer,
4495 PLAYER_INI()->http_max_size_bytes,
4497 PLAYER_INI()->http_buffering_limit,
4498 PLAYER_INI()->http_buffering_time,
4504 /* create autoplugging element if src element is not a streamming src */
4505 if ( player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_RTSP )
4509 if( PLAYER_INI()->use_decodebin )
4511 /* create decodebin */
4512 element = gst_element_factory_make("decodebin", "decodebin");
4514 g_object_set(G_OBJECT(element), "async-handling", TRUE, NULL);
4516 /* set signal handler */
4517 MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(element), "new-decoded-pad",
4518 G_CALLBACK(__mmplayer_gst_decode_callback), player);
4520 /* we don't need state holder, bcz decodebin is doing well by itself */
4521 need_state_holder = FALSE;
4525 element = gst_element_factory_make("typefind", "typefinder");
4526 MMPLAYER_SIGNAL_CONNECT( player, element, "have-type",
4527 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player );
4530 /* check autoplug element is OK */
4533 debug_critical("can not create autoplug element\n");
4537 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
4538 mainbin[MMPLAYER_M_AUTOPLUG].gst = element;
4540 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_AUTOPLUG]);
4544 /* add elements to pipeline */
4545 if( !__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket))
4547 debug_error("Failed to add elements to pipeline\n");
4552 /* linking elements in the bucket by added order. */
4553 if ( __mmplayer_gst_element_link_bucket(element_bucket) == -1 )
4555 debug_error("Failed to link some elements\n");
4560 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4561 if ( need_state_holder )
4564 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4565 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make ("fakesink", "state-holder");
4567 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4569 debug_error ("fakesink element could not be created\n");
4572 GST_OBJECT_FLAG_UNSET (mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_IS_SINK);
4574 /* take ownership of fakesink. we are reusing it */
4575 gst_object_ref( mainbin[MMPLAYER_M_SRC_FAKESINK].gst );
4578 if ( FALSE == gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst),
4579 mainbin[MMPLAYER_M_SRC_FAKESINK].gst) )
4581 debug_error("failed to add fakesink to bin\n");
4586 /* now we have completed mainbin. take it */
4587 player->pipeline->mainbin = mainbin;
4589 /* connect bus callback */
4590 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4593 debug_error ("cannot get bus from pipeline.\n");
4596 player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_callback, player);
4598 /* Note : check whether subtitle atrribute uri is set. If uri is set, then tyr to play subtitle file */
4599 if ( __mmplayer_check_subtitle ( player ) )
4601 if ( MM_ERROR_NONE != __mmplayer_gst_create_subtitle_src(player) )
4602 debug_error("fail to create subtitle src\n")
4605 /* set sync handler to get tag synchronously */
4606 gst_bus_set_sync_handler(bus, __mmplayer_bus_sync_callback, player);
4609 gst_object_unref(GST_OBJECT(bus));
4610 g_list_free(element_bucket);
4614 return MM_ERROR_NONE;
4618 __mmplayer_gst_destroy_pipeline(player);
4619 g_list_free(element_bucket);
4621 /* release element which are not added to bin */
4622 for ( i = 1; i < MMPLAYER_M_NUM; i++ ) /* NOTE : skip pipeline */
4624 if ( mainbin[i].gst )
4626 GstObject* parent = NULL;
4627 parent = gst_element_get_parent( mainbin[i].gst );
4631 gst_object_unref(GST_OBJECT(mainbin[i].gst));
4632 mainbin[i].gst = NULL;
4636 gst_object_unref(GST_OBJECT(parent));
4641 /* release pipeline with it's childs */
4642 if ( mainbin[MMPLAYER_M_PIPE].gst )
4644 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4647 MMPLAYER_FREEIF( player->pipeline );
4648 MMPLAYER_FREEIF( mainbin );
4650 return MM_ERROR_PLAYER_INTERNAL;
4655 __mmplayer_gst_destroy_pipeline(mm_player_t* player) // @
4658 int ret = MM_ERROR_NONE;
4662 return_val_if_fail ( player, MM_ERROR_INVALID_HANDLE );
4664 /* cleanup stuffs */
4665 MMPLAYER_FREEIF(player->type);
4666 player->have_dynamic_pad = FALSE;
4667 player->no_more_pad = FALSE;
4668 player->num_dynamic_pad = 0;
4670 if (player->v_stream_caps)
4672 gst_caps_unref(player->v_stream_caps);
4673 player->v_stream_caps = NULL;
4676 if (ahs_appsrc_cb_probe_id )
4679 pad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "src" );
4681 gst_pad_remove_buffer_probe (pad, ahs_appsrc_cb_probe_id);
4682 gst_object_unref(pad);
4684 ahs_appsrc_cb_probe_id = 0;
4687 if ( player->sink_elements )
4688 g_list_free ( player->sink_elements );
4689 player->sink_elements = NULL;
4691 /* cleanup unlinked mime type */
4692 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4693 MMPLAYER_FREEIF(player->unlinked_video_mime);
4694 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4696 /* cleanup running stuffs */
4697 __mmplayer_cancel_delayed_eos( player );
4699 /* cleanup gst stuffs */
4700 if ( player->pipeline )
4702 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
4703 GstTagList* tag_list = player->pipeline->tag_list;
4705 /* first we need to disconnect all signal hander */
4706 __mmplayer_release_signal_connection( player );
4708 /* disconnecting bus watch */
4709 if ( player->bus_watcher )
4710 g_source_remove( player->bus_watcher );
4711 player->bus_watcher = 0;
4715 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4716 MMPlayerGstElement* videobin = player->pipeline->videobin;
4717 MMPlayerGstElement* textbin = player->pipeline->textbin;
4718 GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE (mainbin[MMPLAYER_M_PIPE].gst));
4719 gst_bus_set_sync_handler (bus, NULL, NULL);
4721 debug_log("pipeline status before set state to NULL\n");
4722 __mmplayer_dump_pipeline_state( player );
4724 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4725 ret = __mmplayer_gst_set_state ( player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout );
4726 if ( ret != MM_ERROR_NONE )
4728 debug_error("fail to change state to NULL\n");
4729 return MM_ERROR_PLAYER_INTERNAL;
4732 debug_log("pipeline status before unrefering pipeline\n");
4733 __mmplayer_dump_pipeline_state( player );
4735 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4738 if ( mainbin[MMPLAYER_M_SRC_FAKESINK].gst )
4739 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4741 /* free avsysaudiosink
4742 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4743 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4745 MMPLAYER_FREEIF( audiobin );
4746 MMPLAYER_FREEIF( videobin );
4747 MMPLAYER_FREEIF( textbin );
4748 MMPLAYER_FREEIF( mainbin );
4752 gst_tag_list_free(tag_list);
4754 MMPLAYER_FREEIF( player->pipeline );
4757 player->pipeline_is_constructed = FALSE;
4764 static int __gst_realize(mm_player_t* player) // @
4767 int ret = MM_ERROR_NONE;
4771 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4773 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4775 __ta__("__mmplayer_gst_create_pipeline",
4776 ret = __mmplayer_gst_create_pipeline(player);
4779 debug_critical("failed to create pipeline\n");
4784 /* set pipeline state to READY */
4785 /* NOTE : state change to READY must be performed sync. */
4786 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4787 ret = __mmplayer_gst_set_state(player,
4788 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4790 if ( ret != MM_ERROR_NONE )
4792 /* return error if failed to set state */
4793 debug_error("failed to set state PAUSED (live : READY).\n");
4795 /* dump state of all element */
4796 __mmplayer_dump_pipeline_state( player );
4802 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_READY );
4805 /* create dot before error-return. for debugging */
4806 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-realize" );
4813 static int __gst_unrealize(mm_player_t* player) // @
4815 int ret = MM_ERROR_NONE;
4819 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4821 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4822 MMPLAYER_PRINT_STATE(player);
4824 /* release miscellaneous information */
4825 __mmplayer_release_misc( player );
4827 /* destroy pipeline */
4828 ret = __mmplayer_gst_destroy_pipeline( player );
4829 if ( ret != MM_ERROR_NONE )
4831 debug_error("failed to destory pipeline\n");
4835 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_NULL );
4842 static int __gst_pending_seek ( mm_player_t* player )
4844 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
4845 MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
4846 int ret = MM_ERROR_NONE;
4850 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
4852 if ( !player->pending_seek.is_pending )
4854 debug_log("pending seek is not reserved. nothing to do.\n" );
4858 /* check player state if player could pending seek or not. */
4859 current_state = MMPLAYER_CURRENT_STATE(player);
4860 pending_state = MMPLAYER_PENDING_STATE(player);
4862 if ( current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING )
4864 debug_warning("try to pending seek in %s state, try next time. \n",
4865 MMPLAYER_STATE_GET_NAME(current_state));
4869 debug_log("trying to play from (%lu) pending position\n", player->pending_seek.pos);
4871 ret = __gst_set_position ( player, player->pending_seek.format, player->pending_seek.pos, FALSE );
4873 if ( MM_ERROR_NONE != ret )
4874 debug_error("failed to seek pending postion. just keep staying current position.\n");
4876 player->pending_seek.is_pending = FALSE;
4883 static int __gst_start(mm_player_t* player) // @
4885 gboolean sound_extraction = 0;
4886 int ret = MM_ERROR_NONE;
4890 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
4892 /* get sound_extraction property */
4893 mm_attrs_get_int_by_name(player->attrs, "pcm_extraction", &sound_extraction);
4895 /* NOTE : if SetPosition was called before Start. do it now */
4896 /* streaming doesn't support it. so it should be always sync */
4897 /* !! create one more api to check if there is pending seek rather than checking variables */
4898 if ( (player->pending_seek.is_pending || sound_extraction) && !MMPLAYER_IS_STREAMING(player))
4900 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
4901 ret = __gst_pause(player, FALSE);
4902 if ( ret != MM_ERROR_NONE )
4904 debug_error("failed to set state to PAUSED for pending seek\n");
4908 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
4910 if ( sound_extraction )
4912 debug_log("setting pcm extraction\n");
4914 ret = __mmplayer_set_pcm_extraction(player);
4915 if ( MM_ERROR_NONE != ret )
4917 debug_warning("failed to set pcm extraction\n");
4923 if ( MM_ERROR_NONE != __gst_pending_seek(player) )
4925 debug_warning("failed to seek pending postion. starting from the begin of content.\n");
4930 debug_log("current state before doing transition");
4931 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
4932 MMPLAYER_PRINT_STATE(player);
4934 /* set pipeline state to PLAYING */
4935 ret = __mmplayer_gst_set_state(player,
4936 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player) );
4937 if (ret == MM_ERROR_NONE)
4939 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
4943 debug_error("failed to set state to PLAYING");
4945 /* dump state of all element */
4946 __mmplayer_dump_pipeline_state( player );
4951 /* FIXIT : analyze so called "async problem" */
4953 __gst_set_async_state_change( player, FALSE );
4955 /* generating debug info before returning error */
4956 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-start" );
4963 static void __mmplayer_do_sound_fadedown(mm_player_t* player, unsigned int time)
4967 return_if_fail(player
4969 && player->pipeline->audiobin
4970 && player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
4972 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", 2, NULL);
4979 static void __mmplayer_undo_sound_fadedown(mm_player_t* player)
4983 return_if_fail(player
4985 && player->pipeline->audiobin
4986 && player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
4988 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", 0, NULL);
4993 static int __gst_stop(mm_player_t* player) // @
4995 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
4996 MMHandleType attrs = 0;
4997 gboolean fadewown = FALSE;
4998 gboolean rewind = FALSE;
5000 int ret = MM_ERROR_NONE;
5004 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5006 debug_log("current state before doing transition");
5007 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
5008 MMPLAYER_PRINT_STATE(player);
5010 attrs = MMPLAYER_GET_ATTRS(player);
5013 debug_error("cannot get content attribute\n");
5014 return MM_ERROR_PLAYER_INTERNAL;
5017 mm_attrs_get_int_by_name(attrs,"sound_fadedown", &fadewown);
5019 /* enable fadedown */
5021 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
5023 /* Just set state to PAUESED and the rewind. it's usual player behavior. */
5024 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT ( player );
5025 if ( player->profile.uri_type == MM_PLAYER_URI_TYPE_BUFF || player->profile.uri_type == MM_PLAYER_URI_TYPE_HLS)
5027 ret = __mmplayer_gst_set_state(player,
5028 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout );
5032 ret = __mmplayer_gst_set_state( player,
5033 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout );
5035 if ( !MMPLAYER_IS_STREAMING(player))
5039 /* disable fadeout */
5041 __mmplayer_undo_sound_fadedown(player);
5044 /* return if set_state has failed */
5045 if ( ret != MM_ERROR_NONE )
5047 debug_error("failed to set state.\n");
5049 /* dump state of all element. don't care it success or not */
5050 __mmplayer_dump_pipeline_state( player );
5058 if ( ! __gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
5059 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
5060 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE) )
5062 debug_warning("failed to rewind\n");
5063 ret = MM_ERROR_PLAYER_SEEK;
5068 player->sent_bos = FALSE;
5070 /* wait for seek to complete */
5071 change_ret = gst_element_get_state (player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
5072 if ( change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL )
5074 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_READY );
5078 debug_error("fail to stop player.\n");
5079 ret = MM_ERROR_PLAYER_INTERNAL;
5082 /* generate dot file if enabled */
5083 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-stop" );
5090 int __gst_pause(mm_player_t* player, gboolean async) // @
5092 int ret = MM_ERROR_NONE;
5096 return_val_if_fail(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5098 debug_log("current state before doing transition");
5099 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
5100 MMPLAYER_PRINT_STATE(player);
5102 /* set pipeline status to PAUSED */
5103 ret = __mmplayer_gst_set_state(player,
5104 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5106 if ( ret != MM_ERROR_NONE )
5108 debug_error("failed to set state to PAUSED\n");
5110 /* dump state of all element */
5111 __mmplayer_dump_pipeline_state( player );
5117 if ( async == FALSE )
5119 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_PAUSED );
5123 /* FIXIT : analyze so called "async problem" */
5125 __gst_set_async_state_change( player, TRUE);
5127 /* generate dot file before returning error */
5128 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-pause" );
5135 int __gst_resume(mm_player_t* player, gboolean async) // @
5137 int ret = MM_ERROR_NONE;
5142 return_val_if_fail(player && player->pipeline,
5143 MM_ERROR_PLAYER_NOT_INITIALIZED);
5145 debug_log("current state before doing transition");
5146 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
5147 MMPLAYER_PRINT_STATE(player);
5149 /* generate dot file before returning error */
5150 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-resume" );
5152 __mmplayer_set_antishock( player , FALSE );
5155 debug_log("do async state transition to PLAYING.\n");
5157 /* set pipeline state to PLAYING */
5158 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5159 ret = __mmplayer_gst_set_state(player,
5160 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout );
5161 if (ret != MM_ERROR_NONE)
5163 debug_error("failed to set state to PLAYING\n");
5165 /* dump state of all element */
5166 __mmplayer_dump_pipeline_state( player );
5174 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_PLAYING );
5178 /* FIXIT : analyze so called "async problem" */
5180 __gst_set_async_state_change( player, FALSE );
5182 /* generate dot file before returning error */
5183 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-resume" );
5191 __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called) // @
5193 GstFormat fmt = GST_FORMAT_TIME;
5194 unsigned long dur_msec = 0;
5195 gint64 dur_nsec = 0;
5196 gint64 pos_nsec = 0;
5197 gboolean ret = TRUE;
5200 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
5201 return_val_if_fail ( !MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP );
5203 if ( MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
5204 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED )
5207 /* check duration */
5208 /* NOTE : duration cannot be zero except live streaming.
5209 * Since some element could have some timing problemn with quering duration, try again.
5211 if ( !player->duration )
5213 if ( !gst_element_query_duration( player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &fmt, &dur_nsec ))
5217 player->duration = dur_nsec;
5220 if ( player->duration )
5222 dur_msec = GST_TIME_AS_MSECONDS(player->duration);
5226 debug_error("could not get the duration. fail to seek.\n");
5230 debug_log("playback rate: %f\n", player->playback_rate);
5235 case MM_PLAYER_POS_FORMAT_TIME:
5237 /* check position is valid or not */
5238 if ( position > dur_msec )
5241 debug_log("seeking to (%lu) msec, duration is %d msec\n", position, dur_msec);
5243 if (player->doing_seek)
5245 debug_log("not completed seek");
5246 return MM_ERROR_PLAYER_DOING_SEEK;
5249 if ( !internal_called)
5250 player->doing_seek = TRUE;
5252 pos_nsec = position * G_GINT64_CONSTANT(1000000);
5253 ret = __gst_seek ( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
5254 GST_FORMAT_TIME, ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ),
5255 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE );
5258 debug_error("failed to set position. dur[%lu] pos[%lu] pos_msec[%llu]\n", dur_msec, position, pos_nsec);
5264 case MM_PLAYER_POS_FORMAT_PERCENT:
5266 debug_log("seeking to (%lu)%% \n", position);
5268 if (player->doing_seek)
5270 debug_log("not completed seek");
5271 return MM_ERROR_PLAYER_DOING_SEEK;
5274 if ( !internal_called)
5275 player->doing_seek = TRUE;
5277 /* FIXIT : why don't we use 'GST_FORMAT_PERCENT' */
5278 pos_nsec = (gint64) ( ( position * player->duration ) / 100 );
5279 ret = __gst_seek ( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
5280 GST_FORMAT_TIME, ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ),
5281 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE );
5284 debug_error("failed to set position. dur[%lud] pos[%lud] pos_msec[%llud]\n", dur_msec, position, pos_nsec);
5295 /* NOTE : store last seeking point to overcome some bad operation
5296 * ( returning zero when getting current position ) of some elements
5298 player->last_position = pos_nsec;
5300 /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
5301 if ( player->playback_rate > 1.0 )
5302 _mmplayer_set_playspeed ( (MMHandleType)player, player->playback_rate );
5305 return MM_ERROR_NONE;
5308 player->pending_seek.is_pending = TRUE;
5309 player->pending_seek.format = format;
5310 player->pending_seek.pos = position;
5312 debug_warning("player current-state : %s, pending-state : %s, just preserve pending position(%lu).\n",
5313 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)), MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)), player->pending_seek.pos);
5315 return MM_ERROR_NONE;
5318 debug_error("invalid arguments, position : %ld dur : %ld format : %d \n", position, dur_msec, format);
5319 return MM_ERROR_INVALID_ARGUMENT;
5322 player->doing_seek = FALSE;
5323 return MM_ERROR_PLAYER_SEEK;
5326 #define TRICKPLAY_OFFSET GST_MSECOND
5329 __gst_get_position(mm_player_t* player, int format, unsigned long* position) // @
5331 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
5332 GstFormat fmt = GST_FORMAT_TIME;
5333 signed long long pos_msec = 0;
5334 gboolean ret = TRUE;
5336 return_val_if_fail( player && position && player->pipeline && player->pipeline->mainbin,
5337 MM_ERROR_PLAYER_NOT_INITIALIZED );
5339 current_state = MMPLAYER_CURRENT_STATE(player);
5341 /* NOTE : query position except paused state to overcome some bad operation
5342 * please refer to below comments in details
5344 if ( current_state != MM_PLAYER_STATE_PAUSED )
5346 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &fmt, &pos_msec);
5349 /* NOTE : get last point to overcome some bad operation of some elements
5350 * ( returning zero when getting current position in paused state
5351 * and when failed to get postion during seeking
5353 if ( ( current_state == MM_PLAYER_STATE_PAUSED )
5355 //|| ( player->last_position != 0 && pos_msec == 0 ) )
5357 debug_warning ("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS (pos_msec), ret, current_state);
5359 if(player->playback_rate < 0.0)
5360 pos_msec = player->last_position - TRICKPLAY_OFFSET;
5362 pos_msec = player->last_position;
5365 pos_msec = player->last_position;
5367 player->last_position = pos_msec;
5369 debug_warning("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_msec));
5374 player->last_position = pos_msec;
5378 case MM_PLAYER_POS_FORMAT_TIME:
5379 *position = GST_TIME_AS_MSECONDS(pos_msec);
5382 case MM_PLAYER_POS_FORMAT_PERCENT:
5387 dur = player->duration / GST_SECOND;
5390 debug_log ("duration is [%d], so returning position 0\n",dur);
5395 pos = pos_msec / GST_SECOND;
5396 *position = pos * 100 / dur;
5401 return MM_ERROR_PLAYER_INTERNAL;
5404 debug_log("current position : %lu\n", *position);
5407 return MM_ERROR_NONE;
5411 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
5413 GstElement *element = NULL;
5414 GstQuery *query = NULL;
5416 return_val_if_fail( player &&
5418 player->pipeline->mainbin,
5419 MM_ERROR_PLAYER_NOT_INITIALIZED );
5421 return_val_if_fail( start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT );
5423 if ( MMPLAYER_IS_HTTP_STREAMING ( player ))
5425 /* Note : In case of http streaming or HLS, the buffering queue [ queue2 ] could handle buffering query. */
5426 element = GST_ELEMENT ( player->pipeline->mainbin[MMPLAYER_M_S_BUFFER].gst );
5428 else if ( MMPLAYER_IS_RTSP_STREAMING ( player ) )
5430 debug_warning ( "it's not supported yet.\n" );
5431 return MM_ERROR_NONE;
5435 debug_warning ( "it's only used for streaming case.\n" );
5436 return MM_ERROR_NONE;
5444 case MM_PLAYER_POS_FORMAT_PERCENT :
5446 query = gst_query_new_buffering ( GST_FORMAT_PERCENT );
5447 if ( gst_element_query ( element, query ) )
5454 gst_query_parse_buffering_percent ( query, &busy, &percent);
5455 gst_query_parse_buffering_range ( query, &format, &start, &stop, NULL );
5457 debug_log ( "buffering start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT "\n", start, stop);
5460 *start_pos = 100 * start / GST_FORMAT_PERCENT_MAX;
5465 *stop_pos = 100 * stop / GST_FORMAT_PERCENT_MAX;
5469 gst_query_unref (query);
5473 case MM_PLAYER_POS_FORMAT_TIME :
5474 debug_warning ( "Time format is not supported yet.\n" );
5481 debug_log("current buffer position : %lu~%lu \n", *start_pos, *stop_pos );
5483 return MM_ERROR_NONE;
5487 __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param) // @
5493 debug_warning("set_message_callback is called with invalid player handle\n");
5494 return MM_ERROR_PLAYER_NOT_INITIALIZED;
5497 player->msg_cb = callback;
5498 player->msg_cb_param = user_param;
5500 debug_log("msg_cb : 0x%x msg_cb_param : 0x%x\n", (guint)callback, (guint)user_param);
5504 return MM_ERROR_NONE;
5507 static gboolean __mmfplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data) // @
5509 gboolean ret = FALSE;
5514 return_val_if_fail ( uri , FALSE);
5515 return_val_if_fail ( data , FALSE);
5516 return_val_if_fail ( ( strlen(uri) <= MM_MAX_URL_LEN ), FALSE );
5518 memset(data, 0, sizeof(MMPlayerParseProfile));
5520 if ((path = strstr(uri, "file://")))
5522 if (util_exist_file_path(path + 7)) {
5523 strncpy(data->uri, path, MM_MAX_URL_LEN-1);
5525 if ( util_is_sdp_file ( path ) )
5527 debug_log("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
5528 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
5532 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
5538 debug_warning("could access %s.\n", path);
5541 else if ((path = strstr(uri, "buff://")))
5543 data->uri_type = MM_PLAYER_URI_TYPE_BUFF;
5546 else if ((path = strstr(uri, "rtsp://")))
5549 strcpy(data->uri, uri);
5550 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
5554 else if ((path = strstr(uri, "http://")))
5557 strcpy(data->uri, uri);
5558 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
5563 else if ((path = strstr(uri, "https://")))
5566 strcpy(data->uri, uri);
5567 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
5572 else if ((path = strstr(uri, "rtspu://")))
5575 strcpy(data->uri, uri);
5576 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
5580 else if ((path = strstr(uri, "rtspr://")))
5582 strcpy(data->uri, path);
5583 char *separater =strstr(path, "*");
5587 char *urgent = separater + strlen("*");
5589 if ((urgent_len = strlen(urgent))) {
5590 data->uri[strlen(path) - urgent_len - strlen("*")] = '\0';
5591 strcpy(data->urgent, urgent);
5592 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
5597 else if ((path = strstr(uri, "mms://")))
5600 strcpy(data->uri, uri);
5601 data->uri_type = MM_PLAYER_URI_TYPE_URL_MMS;
5605 else if ((path = strstr(uri, "mem://")))
5609 char *buffer = NULL;
5610 char *seperator = strchr(path, ',');
5611 char ext[100] = {0,}, size[100] = {0,};
5614 if ((buffer = strstr(path, "ext="))) {
5615 buffer += strlen("ext=");
5617 if (strlen(buffer)) {
5618 strcpy(ext, buffer);
5620 if ((seperator = strchr(ext, ','))
5621 || (seperator = strchr(ext, ' '))
5622 || (seperator = strchr(ext, '\0'))) {
5623 seperator[0] = '\0';
5628 if ((buffer = strstr(path, "size="))) {
5629 buffer += strlen("size=");
5631 if (strlen(buffer) > 0) {
5632 strcpy(size, buffer);
5634 if ((seperator = strchr(size, ','))
5635 || (seperator = strchr(size, ' '))
5636 || (seperator = strchr(size, '\0'))) {
5637 seperator[0] = '\0';
5640 mem_size = atoi(size);
5645 debug_log("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
5646 if ( mem_size && param) {
5648 data->mem_size = mem_size;
5649 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
5656 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
5657 if (util_exist_file_path(uri))
5659 debug_warning("uri has no protocol-prefix. giving 'file://' by default.\n");
5660 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", uri);
5662 if ( util_is_sdp_file( (char*)uri ) )
5664 debug_log("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
5665 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
5669 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
5675 debug_error ("invalid uri, could not play..\n");
5676 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
5680 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE) {
5684 /* dump parse result */
5685 debug_log("profile parsing result ---\n");
5686 debug_warning("incomming uri : %s\n", uri);
5687 debug_log("uri : %s\n", data->uri);
5688 debug_log("uri_type : %d\n", data->uri_type);
5689 debug_log("play_mode : %d\n", data->play_mode);
5690 debug_log("mem : 0x%x\n", (guint)data->mem);
5691 debug_log("mem_size : %d\n", data->mem_size);
5692 debug_log("urgent : %s\n", data->urgent);
5693 debug_log("--------------------------\n");
5700 gboolean _asm_postmsg(gpointer *data)
5702 mm_player_t* player = (mm_player_t*)data;
5703 MMMessageParamType msg = {0, };
5707 return_val_if_fail ( player, FALSE );
5709 msg.union_type = MM_MSG_UNION_CODE;
5710 msg.code = player->sm.event_src;
5712 MMPLAYER_POST_MSG( player, MM_MESSAGE_READY_TO_RESUME, &msg);
5716 gboolean _asm_lazy_pause(gpointer *data)
5718 mm_player_t* player = (mm_player_t*)data;
5719 int ret = MM_ERROR_NONE;
5723 return_val_if_fail ( player, FALSE );
5725 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING)
5727 debug_log ("Ready to proceed lazy pause\n");
5728 ret = _mmplayer_pause((MMHandleType)player);
5729 if(MM_ERROR_NONE != ret)
5731 debug_error("MMPlayer pause failed in ASM callback lazy pause\n");
5736 debug_log ("Invalid state to proceed lazy pause\n");
5740 if (player->pipeline && player->pipeline->audiobin)
5741 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", 0, NULL);
5743 player->sm.by_asm_cb = 0; //should be reset here
5750 __mmplayer_asm_callback(int handle, ASM_event_sources_t event_src, ASM_sound_commands_t command, unsigned int sound_status, void* cb_data)
5752 mm_player_t* player = (mm_player_t*) cb_data;
5753 ASM_cb_result_t cb_res = ASM_CB_RES_IGNORE;
5754 int result = MM_ERROR_NONE;
5755 gboolean lazy_pause = FALSE;
5759 return_val_if_fail ( player && player->pipeline, ASM_CB_RES_IGNORE );
5760 return_val_if_fail ( player->attrs, MM_ERROR_PLAYER_INTERNAL );
5762 if (player->is_sound_extraction)
5764 debug_log("sound extraction is working...so, asm command is ignored.\n");
5768 player->sm.by_asm_cb = 1; // it should be enabled for player state transition with called application command
5769 player->sm.event_src = event_src;
5771 if(event_src == ASM_EVENT_SOURCE_EARJACK_UNPLUG )
5773 int stop_by_asm = 0;
5775 mm_attrs_get_int_by_name(player->attrs, "sound_stop_when_unplugged", &stop_by_asm);
5779 else if (event_src == ASM_EVENT_SOURCE_RESOURCE_CONFLICT)
5781 /* can use video overlay simultaneously */
5782 /* video resource conflict */
5783 if(player->pipeline->videobin)
5785 if (PLAYER_INI()->multiple_codec_supported)
5787 debug_log("video conflict but, can support to use video overlay simultaneously");
5788 result = _mmplayer_pause((MMHandleType)player);
5789 cb_res = ASM_CB_RES_PAUSE;
5793 debug_log("video conflict, can't support for multiple codec instance");
5794 result = _mmplayer_unrealize((MMHandleType)player);
5795 cb_res = ASM_CB_RES_STOP;
5803 case ASM_COMMAND_PLAY:
5804 debug_warning ("Got unexpected asm command (%d)", command);
5807 case ASM_COMMAND_STOP: // notification case
5809 debug_log("Got msg from asm to stop");
5811 result = _mmplayer_stop((MMHandleType)player);
5812 if (result != MM_ERROR_NONE)
5814 debug_warning("fail to set stop state by asm");
5815 cb_res = ASM_CB_RES_IGNORE;
5819 cb_res = ASM_CB_RES_STOP;
5821 player->sm.by_asm_cb = 0; // reset because no message any more from asm
5825 case ASM_COMMAND_PAUSE:
5827 debug_log("Got msg from asm to Pause");
5829 if(event_src == ASM_EVENT_SOURCE_CALL_START
5830 || event_src == ASM_EVENT_SOURCE_ALARM_START
5831 || event_src == ASM_EVENT_SOURCE_MEDIA)
5833 //hold 0.7 second to excute "fadedown mute" effect
5834 debug_log ("do fade down->pause->undo fade down");
5836 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
5838 result = _mmplayer_pause((MMHandleType)player);
5839 if (result != MM_ERROR_NONE)
5841 debug_warning("fail to set Pause state by asm");
5842 cb_res = ASM_CB_RES_IGNORE;
5845 __mmplayer_undo_sound_fadedown(player);
5847 else if(event_src == ASM_EVENT_SOURCE_OTHER_PLAYER_APP)
5849 lazy_pause = TRUE; // return as soon as possible, for fast start of other app
5851 if ( player->pipeline->audiobin && player->pipeline->audiobin[MMPLAYER_A_SINK].gst )
5852 g_object_set( player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "mute", 2, NULL);
5854 player->lazy_pause_event_id = g_timeout_add(LAZY_PAUSE_TIMEOUT_MSEC, (GSourceFunc)_asm_lazy_pause, (gpointer)player);
5855 debug_log ("set lazy pause timer (id=[%d], timeout=[%d ms])", player->lazy_pause_event_id, LAZY_PAUSE_TIMEOUT_MSEC);
5860 debug_log ("immediate pause");
5861 result = _mmplayer_pause((MMHandleType)player);
5863 cb_res = ASM_CB_RES_PAUSE;
5867 case ASM_COMMAND_RESUME:
5869 debug_log("Got msg from asm to Resume. So, application can resume. code (%d) \n", event_src);
5870 player->sm.by_asm_cb = 0;
5871 //ASM server is single thread daemon. So use g_idle_add() to post resume msg
5872 g_idle_add((GSourceFunc)_asm_postmsg, (gpointer)player);
5873 cb_res = ASM_CB_RES_IGNORE;
5882 player->sm.by_asm_cb = 0;
5890 _mmplayer_create_player(MMHandleType handle) // @
5892 mm_player_t* player = MM_PLAYER_CAST(handle);
5897 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
5899 MMTA_ACUM_ITEM_BEGIN("[KPI] media player service create->playing", FALSE);
5901 /* initialize player state */
5902 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
5903 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
5904 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
5905 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
5907 /* check current state */
5908 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL ( player, MMPLAYER_COMMAND_CREATE );
5910 /* construct attributes */
5911 player->attrs = _mmplayer_construct_attribute(handle);
5913 if ( !player->attrs )
5915 debug_critical("Failed to construct attributes\n");
5919 /* initialize gstreamer with configured parameter */
5920 if ( ! __mmplayer_gstreamer_init() )
5922 debug_critical("Initializing gstreamer failed\n");
5926 /* initialize factories if not using decodebin */
5927 if ( FALSE == PLAYER_INI()->use_decodebin )
5929 if( player->factories == NULL )
5930 __mmplayer_init_factories(player);
5933 /* create lock. note that g_tread_init() has already called in gst_init() */
5934 player->fsink_lock = g_mutex_new();
5935 if ( ! player->fsink_lock )
5937 debug_critical("Cannot create mutex for command lock\n");
5941 /* create repeat mutex */
5942 player->repeat_thread_mutex = g_mutex_new();
5943 if ( ! player->repeat_thread_mutex )
5945 debug_critical("Cannot create repeat mutex\n");
5949 /* create repeat cond */
5950 player->repeat_thread_cond = g_cond_new();
5951 if ( ! player->repeat_thread_cond )
5953 debug_critical("Cannot create repeat cond\n");
5957 /* create repeat thread */
5958 player->repeat_thread =
5959 g_thread_create (__mmplayer_repeat_thread, (gpointer)player, TRUE, NULL);
5960 if ( ! player->repeat_thread )
5965 if ( MM_ERROR_NONE != _mmplayer_initialize_video_capture(player))
5967 debug_error("failed to initialize video capture\n");
5971 /* register to asm */
5972 if ( MM_ERROR_NONE != _mmplayer_asm_register(&player->sm, (ASM_sound_cb_t)__mmplayer_asm_callback, (void*)player) )
5974 /* NOTE : we are dealing it as an error since we cannot expect it's behavior */
5975 debug_error("failed to register asm server\n");
5976 return MM_ERROR_POLICY_INTERNAL;
5979 if (MMPLAYER_IS_HTTP_PD(player))
5981 player->pd_downloader = NULL;
5982 player->pd_file_save_path = NULL;
5985 /* give default value of audio effect setting */
5986 player->bypass_audio_effect = TRUE;
5987 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
5988 player->playback_rate = DEFAULT_PLAYBACK_RATE;
5989 player->no_more_pad = TRUE;
5991 player->play_subtitle = FALSE;
5992 player->use_textoverlay = FALSE;
5994 /* set player state to null */
5995 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = PLAYER_INI()->localplayback_state_change_timeout;
5996 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_NULL );
6000 return MM_ERROR_NONE;
6004 if ( player->fsink_lock )
6005 g_mutex_free( player->fsink_lock );
6006 player->fsink_lock = NULL;
6009 if ( player->repeat_thread_cond &&
6010 player->repeat_thread_mutex &&
6011 player->repeat_thread )
6013 player->repeat_thread_exit = TRUE;
6014 g_cond_signal( player->repeat_thread_cond );
6016 g_thread_join( player->repeat_thread );
6017 player->repeat_thread = NULL;
6019 g_mutex_free ( player->repeat_thread_mutex );
6020 player->repeat_thread_mutex = NULL;
6022 g_cond_free ( player->repeat_thread_cond );
6023 player->repeat_thread_cond = NULL;
6025 /* clear repeat thread mutex/cond if still alive
6026 * this can happen if only thread creating has failed
6028 if ( player->repeat_thread_mutex )
6029 g_mutex_free ( player->repeat_thread_mutex );
6031 if ( player->repeat_thread_cond )
6032 g_cond_free ( player->repeat_thread_cond );
6034 /* release attributes */
6035 _mmplayer_deconstruct_attribute(handle);
6037 return MM_ERROR_PLAYER_INTERNAL;
6041 __mmplayer_gstreamer_init(void) // @
6043 static gboolean initialized = FALSE;
6044 static const int max_argc = 50;
6046 gchar** argv = NULL;
6054 debug_log("gstreamer already initialized.\n");
6059 argc = malloc( sizeof(int) );
6060 argv = malloc( sizeof(gchar*) * max_argc );
6062 if ( !argc || !argv )
6065 memset( argv, 0, sizeof(gchar*) * max_argc );
6069 argv[0] = g_strdup( "mmplayer" );
6072 for ( i = 0; i < 5; i++ ) /* FIXIT : num of param is now fixed to 5. make it dynamic */
6074 if ( strlen( PLAYER_INI()->gst_param[i] ) > 0 )
6076 argv[*argc] = g_strdup( PLAYER_INI()->gst_param[i] );
6081 /* we would not do fork for scanning plugins */
6082 argv[*argc] = g_strdup("--gst-disable-registry-fork");
6085 /* check disable registry scan */
6086 if ( PLAYER_INI()->skip_rescan )
6088 argv[*argc] = g_strdup("--gst-disable-registry-update");
6092 /* check disable segtrap */
6093 if ( PLAYER_INI()->disable_segtrap )
6095 argv[*argc] = g_strdup("--gst-disable-segtrap");
6099 debug_log("initializing gstreamer with following parameter\n");
6100 debug_log("argc : %d\n", *argc);
6102 for ( i = 0; i < *argc; i++ )
6104 debug_log("argv[%d] : %s\n", i, argv[i]);
6108 /* initializing gstreamer */
6109 __ta__("gst_init time",
6111 if ( ! gst_init_check (argc, &argv, &err))
6113 debug_error("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
6124 for ( i = 0; i < *argc; i++ )
6126 MMPLAYER_FREEIF( argv[i] );
6129 MMPLAYER_FREEIF( argv );
6130 MMPLAYER_FREEIF( argc );
6141 MMPLAYER_FREEIF( argv );
6142 MMPLAYER_FREEIF( argc );
6148 __mmplayer_destroy_streaming_ext(mm_player_t* player)
6150 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6152 if (player->pd_downloader)
6153 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
6155 if (MMPLAYER_IS_HTTP_PD(player))
6156 _mmplayer_destroy_pd_downloader((MMHandleType)player);
6158 if (MMPLAYER_IS_STREAMING(player))
6160 if (player->streamer)
6162 __mm_player_streaming_deinitialize (player->streamer);
6163 __mm_player_streaming_destroy(player->streamer);
6164 player->streamer = NULL;
6167 return MM_ERROR_NONE;
6171 _mmplayer_destroy(MMHandleType handle) // @
6173 mm_player_t* player = MM_PLAYER_CAST(handle);
6177 /* check player handle */
6178 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6180 /* destroy can called at anytime */
6181 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL ( player, MMPLAYER_COMMAND_DESTROY );
6183 __mmplayer_destroy_streaming_ext(player);
6185 /* release repeat thread */
6186 if ( player->repeat_thread_cond &&
6187 player->repeat_thread_mutex &&
6188 player->repeat_thread )
6190 player->repeat_thread_exit = TRUE;
6191 g_cond_signal( player->repeat_thread_cond );
6193 debug_log("waitting for repeat thread exit\n");
6194 g_thread_join ( player->repeat_thread );
6195 g_mutex_free ( player->repeat_thread_mutex );
6196 g_cond_free ( player->repeat_thread_cond );
6197 debug_log("repeat thread released\n");
6200 if (MM_ERROR_NONE != _mmplayer_release_video_capture(player))
6202 debug_error("failed to release video capture\n");
6203 return MM_ERROR_PLAYER_INTERNAL;
6207 if ( MM_ERROR_NONE != _mmplayer_asm_deregister(&player->sm) )
6209 debug_error("failed to deregister asm server\n");
6210 return MM_ERROR_PLAYER_INTERNAL;
6213 /* release pipeline */
6214 if ( MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline( player ) )
6216 debug_error("failed to destory pipeline\n");
6217 return MM_ERROR_PLAYER_INTERNAL;
6220 /* release attributes */
6221 _mmplayer_deconstruct_attribute( handle );
6223 /* release factories */
6224 __mmplayer_release_factories( player );
6227 if ( player->fsink_lock )
6228 g_mutex_free( player->fsink_lock );
6230 if ( player->msg_cb_lock )
6231 g_mutex_free( player->msg_cb_lock );
6233 if (player->lazy_pause_event_id)
6235 g_source_remove (player->lazy_pause_event_id);
6236 player->lazy_pause_event_id = 0;
6241 return MM_ERROR_NONE;
6245 __mmplayer_realize_streaming_ext(mm_player_t* player)
6247 int ret = MM_ERROR_NONE;
6250 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6252 if (MMPLAYER_IS_HTTP_PD(player))
6254 gboolean bret = FALSE;
6256 player->pd_downloader = _mmplayer_create_pd_downloader();
6257 if ( !player->pd_downloader )
6259 debug_error ("Unable to create PD Downloader...");
6260 ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
6263 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
6267 debug_error ("Unable to create PD Downloader...");
6268 ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
6277 _mmplayer_realize(MMHandleType hplayer) // @
6279 mm_player_t* player = (mm_player_t*)hplayer;
6282 int application_pid = -1;
6283 gboolean update_registry = FALSE;
6284 MMHandleType attrs = 0;
6285 int ret = MM_ERROR_NONE;
6289 /* check player handle */
6290 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED )
6292 /* check current state */
6293 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_REALIZE );
6295 attrs = MMPLAYER_GET_ATTRS(player);
6298 debug_error("fail to get attributes.\n");
6299 return MM_ERROR_PLAYER_INTERNAL;
6302 mm_attrs_get_int_by_name(attrs, "sound_application_pid", &application_pid );
6303 player->sm.pid = application_pid;
6305 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
6306 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
6308 if (! __mmfplayer_parse_profile((const char*)uri, param, &player->profile) )
6310 debug_error("failed to parse profile\n");
6311 return MM_ERROR_PLAYER_INVALID_URI;
6314 /* FIXIT : we can use thouse in player->profile directly */
6315 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM)
6317 player->mem_buf.buf = (char *)player->profile.mem;
6318 player->mem_buf.len = player->profile.mem_size;
6319 player->mem_buf.offset = 0;
6322 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS)
6324 debug_warning("mms protocol is not supported format.\n");
6325 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
6328 if (MMPLAYER_IS_STREAMING(player))
6329 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = PLAYER_INI()->live_state_change_timeout;
6331 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = PLAYER_INI()->localplayback_state_change_timeout;
6333 player->videodec_linked = 0;
6334 player->videosink_linked = 0;
6335 player->audiodec_linked = 0;
6336 player->audiosink_linked = 0;
6337 player->textsink_linked = 0;
6339 /* set the subtitle ON default */
6340 player->is_subtitle_off = FALSE;
6342 /* we need to update content attrs only the content has changed */
6343 player->need_update_content_attrs = TRUE;
6344 player->need_update_content_dur = FALSE;
6346 /* registry should be updated for downloadable codec */
6347 mm_attrs_get_int_by_name(attrs, "profile_update_registry", &update_registry);
6349 if ( update_registry )
6351 debug_log("updating registry...\n");
6352 gst_update_registry();
6354 /* then we have to rebuild factories */
6355 __mmplayer_release_factories( player );
6356 __mmplayer_init_factories(player);
6359 /* realize pipeline */
6360 ret = __gst_realize( player );
6361 if ( ret != MM_ERROR_NONE )
6363 debug_error("fail to realize the player.\n");
6367 __mmplayer_realize_streaming_ext(player);
6376 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
6379 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6381 /* destroy can called at anytime */
6382 if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player))
6384 _mmplayer_unrealize_pd_downloader ((MMHandleType)player);
6385 player->pd_downloader = NULL;
6389 return MM_ERROR_NONE;
6393 _mmplayer_unrealize(MMHandleType hplayer) // @
6395 mm_player_t* player = (mm_player_t*)hplayer;
6396 int ret = MM_ERROR_NONE;
6400 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED )
6402 /* check current state */
6403 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_UNREALIZE );
6405 __mmplayer_unrealize_streaming_ext(player);
6407 /* unrealize pipeline */
6408 ret = __gst_unrealize( player );
6410 /* set player state if success */
6411 if ( MM_ERROR_NONE == ret )
6413 ret = _mmplayer_asm_set_state(hplayer, ASM_STATE_STOP);
6416 debug_error("failed to set asm state to STOP\n");
6427 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param) // @
6429 mm_player_t* player = (mm_player_t*)hplayer;
6431 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6433 return __gst_set_message_callback(player, callback, user_param);
6437 _mmplayer_get_state(MMHandleType hplayer, int* state) // @
6439 mm_player_t *player = (mm_player_t*)hplayer;
6441 return_val_if_fail(state, MM_ERROR_INVALID_ARGUMENT);
6443 *state = MMPLAYER_CURRENT_STATE(player);
6445 return MM_ERROR_NONE;
6450 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume) // @
6452 mm_player_t* player = (mm_player_t*) hplayer;
6453 GstElement* vol_element = NULL;
6458 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6460 debug_log("volume [L]=%f:[R]=%f\n",
6461 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
6463 /* invalid factor range or not */
6464 for ( i = 0; i < MM_VOLUME_CHANNEL_NUM; i++ )
6466 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
6467 debug_error("Invalid factor! (valid factor:0~1.0)\n");
6468 return MM_ERROR_INVALID_ARGUMENT;
6472 /* Save volume to handle. Currently the first array element will be saved. */
6473 player->sound.volume = volume.level[0];
6475 /* check pipeline handle */
6476 if ( ! player->pipeline || ! player->pipeline->audiobin )
6478 debug_log("audiobin is not created yet\n");
6479 debug_log("but, current stored volume will be set when it's created.\n");
6481 /* NOTE : stored volume will be used in create_audiobin
6482 * returning MM_ERROR_NONE here makes application to able to
6483 * set volume at anytime.
6485 return MM_ERROR_NONE;
6488 /* setting volume to volume element */
6489 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
6493 debug_log("volume is set [%f]\n", player->sound.volume);
6494 g_object_set(vol_element, "volume", player->sound.volume, NULL);
6499 return MM_ERROR_NONE;
6504 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
6506 mm_player_t* player = (mm_player_t*) hplayer;
6511 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6512 return_val_if_fail( volume, MM_ERROR_INVALID_ARGUMENT );
6514 /* returning stored volume */
6515 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
6516 volume->level[i] = player->sound.volume;
6520 return MM_ERROR_NONE;
6526 _mmplayer_set_mute(MMHandleType hplayer, int mute) // @
6528 mm_player_t* player = (mm_player_t*) hplayer;
6529 GstElement* vol_element = NULL;
6533 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6535 debug_log("mute : %d\n", mute);
6537 /* mute value shoud 0 or 1 */
6538 if ( mute != 0 && mute != 1 )
6540 debug_error("bad mute value\n");
6542 /* FIXIT : definitly, we need _BAD_PARAM error code */
6543 return MM_ERROR_INVALID_ARGUMENT;
6547 /* just hold mute value if pipeline is not ready */
6548 if ( !player->pipeline || !player->pipeline->audiobin )
6550 debug_log("pipeline is not ready. holding mute value\n");
6551 player->sound.mute = mute;
6552 return MM_ERROR_NONE;
6556 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
6558 /* NOTE : volume will only created when the bt is enabled */
6561 g_object_set(vol_element, "mute", mute, NULL);
6565 debug_log("volume elemnet is not created. using volume in audiosink\n");
6568 player->sound.mute = mute;
6572 return MM_ERROR_NONE;
6576 _mmplayer_get_mute(MMHandleType hplayer, int* pmute) // @
6578 mm_player_t* player = (mm_player_t*) hplayer;
6579 GstElement* vol_element = NULL;
6583 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6584 return_val_if_fail ( pmute, MM_ERROR_INVALID_ARGUMENT );
6586 /* just hold mute value if pipeline is not ready */
6587 if ( !player->pipeline || !player->pipeline->audiobin )
6589 debug_log("pipeline is not ready. returning stored value\n");
6590 *pmute = player->sound.mute;
6591 return MM_ERROR_NONE;
6595 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
6599 g_object_get(vol_element, "mute", pmute, NULL);
6600 debug_log("mute=%d\n\n", *pmute);
6604 *pmute = player->sound.mute;
6609 return MM_ERROR_NONE;
6613 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param) // @
6615 mm_player_t* player = (mm_player_t*) hplayer;
6619 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6620 return_val_if_fail ( callback, MM_ERROR_INVALID_ARGUMENT );
6622 player->video_stream_cb = callback;
6623 player->video_stream_cb_user_param = user_param;
6624 player->use_video_stream = TRUE;
6625 debug_log("Stream cb Handle value is %p : %p\n", player, player->video_stream_cb);
6629 return MM_ERROR_NONE;
6633 _mmplayer_set_audiostream_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param) // @
6635 mm_player_t* player = (mm_player_t*) hplayer;
6639 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6640 return_val_if_fail(callback, MM_ERROR_INVALID_ARGUMENT);
6642 player->audio_stream_cb = callback;
6643 player->audio_stream_cb_user_param = user_param;
6644 debug_log("Audio Stream cb Handle value is %p : %p\n", player, player->audio_stream_cb);
6648 return MM_ERROR_NONE;
6652 _mmplayer_set_audiobuffer_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param) // @
6654 mm_player_t* player = (mm_player_t*) hplayer;
6658 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6659 return_val_if_fail(callback, MM_ERROR_INVALID_ARGUMENT);
6661 player->audio_buffer_cb = callback;
6662 player->audio_buffer_cb_user_param = user_param;
6663 debug_log("Audio Stream cb Handle value is %p : %p\n", player, player->audio_buffer_cb);
6667 return MM_ERROR_NONE;
6671 _mmplayer_set_buffer_need_data_cb(MMHandleType hplayer, mm_player_buffer_need_data_callback callback, void *user_param) // @
6673 mm_player_t* player = (mm_player_t*) hplayer;
6677 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
6678 return_val_if_fail(callback, MM_ERROR_INVALID_ARGUMENT);
6680 player->need_data_cb = callback;
6681 player->buffer_cb_user_param = user_param;
6683 debug_log("buffer need dataHandle value is %p : %p\n", player, player->need_data_cb);
6687 return MM_ERROR_NONE;
6691 _mmplayer_set_buffer_enough_data_cb(MMHandleType hplayer, mm_player_buffer_enough_data_callback callback, void *user_param) // @
6693 mm_player_t* player = (mm_player_t*) hplayer;
6697 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
6698 return_val_if_fail(callback, MM_ERROR_INVALID_ARGUMENT);
6700 player->enough_data_cb = callback;
6701 player->buffer_cb_user_param = user_param;
6703 debug_log("buffer enough data cb Handle value is %p : %p\n", player, player->enough_data_cb);
6707 return MM_ERROR_NONE;
6711 _mmplayer_set_buffer_seek_data_cb(MMHandleType hplayer, mm_player_buffer_seek_data_callback callback, void *user_param) // @
6713 mm_player_t* player = (mm_player_t*) hplayer;
6717 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
6718 return_val_if_fail(callback, MM_ERROR_INVALID_ARGUMENT);
6720 player->seek_data_cb = callback;
6721 player->buffer_cb_user_param = user_param;
6723 debug_log("buffer seek data cb Handle value is %p : %p\n", player, player->seek_data_cb);
6727 return MM_ERROR_NONE;
6730 int __mmplayer_start_streaming_ext(mm_player_t *player)
6732 gint ret = MM_ERROR_NONE;
6735 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6737 if (MMPLAYER_IS_HTTP_PD(player))
6739 if ( !player->pd_downloader )
6741 ret = __mmplayer_realize_streaming_ext(player);
6743 if ( ret != MM_ERROR_NONE)
6745 debug_error ("failed to realize streaming ext\n");
6750 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI)
6752 ret = _mmplayer_start_pd_downloader ((MMHandleType)player);
6755 debug_error ("ERROR while starting PD...\n");
6756 return MM_ERROR_PLAYER_NOT_INITIALIZED;
6758 ret = MM_ERROR_NONE;
6767 _mmplayer_start(MMHandleType hplayer) // @
6769 mm_player_t* player = (mm_player_t*) hplayer;
6770 gint ret = MM_ERROR_NONE;
6774 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6776 /* check current state */
6777 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_START );
6779 ret = _mmplayer_asm_set_state(hplayer, ASM_STATE_PLAYING);
6780 if ( ret != MM_ERROR_NONE )
6782 debug_error("failed to set asm state to PLAYING\n");
6786 /* NOTE : we should check and create pipeline again if not created as we destroy
6787 * whole pipeline when stopping in streamming playback
6789 if ( ! player->pipeline )
6791 ret = __gst_realize( player );
6792 if ( MM_ERROR_NONE != ret )
6794 debug_error("failed to realize before starting. only in streamming\n");
6799 ret = __mmplayer_start_streaming_ext(player);
6800 if ( ret != MM_ERROR_NONE )
6802 debug_error("failed to start streaming ext \n");
6805 /* start pipeline */
6806 ret = __gst_start( player );
6807 if ( ret != MM_ERROR_NONE )
6809 debug_error("failed to start player.\n");
6817 /* NOTE: post "not supported codec message" to application
6818 * when one codec is not found during AUTOPLUGGING in MSL.
6819 * So, it's separated with error of __mmplayer_gst_callback().
6820 * And, if any codec is not found, don't send message here.
6821 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
6824 __mmplayer_post_missed_plugin(mm_player_t* player)
6826 MMMessageParamType msg_param;
6827 memset (&msg_param, 0, sizeof(MMMessageParamType));
6828 gboolean post_msg_direct = FALSE;
6832 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6834 debug_log("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
6835 player->not_supported_codec, player->can_support_codec);
6837 if( player->not_found_demuxer )
6839 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
6840 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
6842 MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param );
6843 MMPLAYER_FREEIF(msg_param.data);
6845 return MM_ERROR_NONE;
6848 if (player->not_supported_codec)
6850 if ( player->can_support_codec ) // There is one codec to play
6852 post_msg_direct = TRUE;
6856 if ( player->pipeline->audiobin ) // Some content has only PCM data in container.
6857 post_msg_direct = TRUE;
6860 if ( post_msg_direct )
6862 MMMessageParamType msg_param;
6863 memset (&msg_param, 0, sizeof(MMMessageParamType));
6865 if ( player->not_supported_codec == MISSING_PLUGIN_AUDIO )
6867 debug_warning("not found AUDIO codec, posting error code to application.\n");
6869 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
6870 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
6872 else if ( player->not_supported_codec == MISSING_PLUGIN_VIDEO )
6874 debug_warning("not found VIDEO codec, posting error code to application.\n");
6876 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
6877 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
6880 MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param );
6882 MMPLAYER_FREEIF(msg_param.data);
6884 return MM_ERROR_NONE;
6886 else // no any supported codec case
6888 debug_warning("not found any codec, posting error code to application.\n");
6890 if ( player->not_supported_codec == MISSING_PLUGIN_AUDIO )
6892 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
6893 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
6897 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
6898 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
6901 MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param );
6903 MMPLAYER_FREEIF(msg_param.data);
6909 return MM_ERROR_NONE;
6912 /* NOTE : it should be able to call 'stop' anytime*/
6914 _mmplayer_stop(MMHandleType hplayer) // @
6916 mm_player_t* player = (mm_player_t*)hplayer;
6917 int ret = MM_ERROR_NONE;
6921 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6923 /* check current state */
6924 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_STOP );
6926 /* NOTE : application should not wait for EOS after calling STOP */
6927 __mmplayer_cancel_delayed_eos( player );
6929 __mmplayer_unrealize_streaming_ext(player);
6932 ret = __gst_stop( player );
6934 if ( ret != MM_ERROR_NONE )
6936 debug_error("failed to stop player.\n");
6945 _mmplayer_pause(MMHandleType hplayer) // @
6947 mm_player_t* player = (mm_player_t*)hplayer;
6948 GstFormat fmt = GST_FORMAT_TIME;
6949 gint64 pos_msec = 0;
6950 gboolean async = FALSE;
6951 gint ret = MM_ERROR_NONE;
6955 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6957 /* check current state */
6958 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_PAUSE );
6960 switch (MMPLAYER_CURRENT_STATE(player))
6962 case MM_PLAYER_STATE_READY:
6964 /* check prepare async or not.
6965 * In the case of streaming playback, it's recommned to avoid blocking wait.
6967 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
6968 debug_log("prepare mode : %s", (async ? "async" : "sync"));
6972 case MM_PLAYER_STATE_PLAYING:
6974 /* NOTE : store current point to overcome some bad operation
6975 * ( returning zero when getting current position in paused state) of some
6978 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &fmt, &pos_msec);
6980 debug_warning("getting current position failed in paused\n");
6982 player->last_position = pos_msec;
6987 /* pause pipeline */
6988 ret = __gst_pause( player, async );
6990 if ( ret != MM_ERROR_NONE )
6992 debug_error("failed to pause player.\n");
7001 _mmplayer_resume(MMHandleType hplayer)
7003 mm_player_t* player = (mm_player_t*)hplayer;
7004 int ret = MM_ERROR_NONE;
7008 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7010 ret = _mmplayer_asm_set_state(hplayer, ASM_STATE_PLAYING);
7013 debug_error("failed to set asm state to PLAYING\n");
7017 /* check current state */
7018 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_RESUME );
7020 /* resume pipeline */
7021 ret = __gst_resume( player, FALSE );
7023 if ( ret != MM_ERROR_NONE )
7025 debug_error("failed to resume player.\n");
7035 __mmplayer_set_play_count(mm_player_t* player, gint count)
7037 MMHandleType attrs = 0;
7041 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7043 attrs = MMPLAYER_GET_ATTRS(player);
7046 debug_error("fail to get attributes.\n");
7047 return MM_ERROR_PLAYER_INTERNAL;
7050 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
7051 if ( mmf_attrs_commit ( attrs ) ) /* return -1 if error */
7052 debug_error("failed to commit\n");
7056 return MM_ERROR_NONE;
7060 _mmplayer_activate_section_repeat(MMHandleType hplayer, unsigned long start, unsigned long end)
7062 mm_player_t* player = (mm_player_t*)hplayer;
7063 gint64 start_pos = 0;
7069 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7070 return_val_if_fail ( end <= GST_TIME_AS_MSECONDS(player->duration), MM_ERROR_INVALID_ARGUMENT );
7072 player->section_repeat = TRUE;
7073 player->section_repeat_start = start;
7074 player->section_repeat_end = end;
7076 start_pos = player->section_repeat_start * G_GINT64_CONSTANT(1000000);
7077 end_pos = player->section_repeat_end * G_GINT64_CONSTANT(1000000);
7079 __mmplayer_set_play_count( player, infinity );
7081 if ( (!__gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
7084 ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ),
7085 GST_SEEK_TYPE_SET, start_pos,
7086 GST_SEEK_TYPE_SET, end_pos)))
7088 debug_error("failed to activate section repeat\n");
7090 return MM_ERROR_PLAYER_SEEK;
7093 debug_log("succeeded to set section repeat from %d to %d\n",
7094 player->section_repeat_start, player->section_repeat_end);
7098 return MM_ERROR_NONE;
7102 __mmplayer_set_pcm_extraction(mm_player_t* player)
7104 guint64 start_nsec = 0;
7105 guint64 end_nsec = 0;
7106 guint64 dur_nsec = 0;
7107 guint64 dur_msec = 0;
7108 GstFormat fmt = GST_FORMAT_TIME;
7109 int required_start = 0;
7110 int required_end = 0;
7115 return_val_if_fail( player, FALSE );
7117 mm_attrs_multiple_get(player->attrs,
7119 "pcm_extraction_start_msec", &required_start,
7120 "pcm_extraction_end_msec", &required_end,
7123 debug_log("pcm extraction required position is from [%d] to [%d] (msec)\n", required_start, required_end);
7125 if (required_start == 0 && required_end == 0)
7127 debug_log("extracting entire stream");
7128 return MM_ERROR_NONE;
7130 else if (required_start < 0 || required_start > required_end || required_end < 0 )
7132 debug_log("invalid range for pcm extraction");
7133 return MM_ERROR_INVALID_ARGUMENT;
7137 ret = gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &fmt, &dur_nsec);
7140 debug_error("failed to get duration");
7141 return MM_ERROR_PLAYER_INTERNAL;
7143 dur_msec = GST_TIME_AS_MSECONDS(dur_nsec);
7145 if (dur_msec < required_end) // FIXME
7147 debug_log("invalid end pos for pcm extraction");
7148 return MM_ERROR_INVALID_ARGUMENT;
7151 start_nsec = required_start * G_GINT64_CONSTANT(1000000);
7152 end_nsec = required_end * G_GINT64_CONSTANT(1000000);
7154 if ( (!__gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
7157 ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ),
7158 GST_SEEK_TYPE_SET, start_nsec,
7159 GST_SEEK_TYPE_SET, end_nsec)))
7161 debug_error("failed to seek for pcm extraction\n");
7163 return MM_ERROR_PLAYER_SEEK;
7166 debug_log("succeeded to set up segment extraction from [%llu] to [%llu] (nsec)\n", start_nsec, end_nsec);
7170 return MM_ERROR_NONE;
7174 _mmplayer_deactivate_section_repeat(MMHandleType hplayer)
7176 mm_player_t* player = (mm_player_t*)hplayer;
7178 GstFormat fmt = GST_FORMAT_TIME;
7183 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7185 player->section_repeat = FALSE;
7187 __mmplayer_set_play_count( player, onetime );
7189 gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &fmt, &cur_pos);
7191 if ( (!__gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
7194 ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ),
7195 GST_SEEK_TYPE_SET, cur_pos,
7196 GST_SEEK_TYPE_SET, player->duration )))
7198 debug_error("failed to deactivate section repeat\n");
7200 return MM_ERROR_PLAYER_SEEK;
7205 return MM_ERROR_NONE;
7209 _mmplayer_set_playspeed(MMHandleType hplayer, gdouble rate)
7211 mm_player_t* player = (mm_player_t*)hplayer;
7212 signed long long pos_msec = 0;
7213 int ret = MM_ERROR_NONE;
7215 GstFormat format =GST_FORMAT_TIME;
7216 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7219 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
7220 return_val_if_fail ( !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API );
7222 /* The sound of video is not supported under 0.0 and over 2.0. */
7223 if(rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN)
7225 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
7228 _mmplayer_set_mute(hplayer, mute);
7230 if (player->playback_rate == rate)
7231 return MM_ERROR_NONE;
7233 /* If the position is reached at start potion during fast backward, EOS is posted.
7234 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
7236 player->playback_rate = rate;
7238 current_state = MMPLAYER_CURRENT_STATE(player);
7240 if ( current_state != MM_PLAYER_STATE_PAUSED )
7241 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &format, &pos_msec);
7243 debug_log ("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS (pos_msec), ret, current_state);
7245 if ( ( current_state == MM_PLAYER_STATE_PAUSED )
7247 //|| ( player->last_position != 0 && pos_msec == 0 ) )
7249 debug_warning("returning last point : %lld\n", player->last_position );
7250 pos_msec = player->last_position;
7253 if ((!gst_element_seek (player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
7256 ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ),
7257 //( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_KEY_UNIT),
7258 GST_SEEK_TYPE_SET, pos_msec,
7259 //GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE,
7260 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)))
7262 debug_error("failed to set speed playback\n");
7263 return MM_ERROR_PLAYER_SEEK;
7266 debug_log("succeeded to set speed playback as %fl\n", rate);
7270 return MM_ERROR_NONE;;
7274 _mmplayer_set_position(MMHandleType hplayer, int format, int position) // @
7276 mm_player_t* player = (mm_player_t*)hplayer;
7277 int ret = MM_ERROR_NONE;
7281 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7283 ret = __gst_set_position ( player, format, (unsigned long)position, FALSE );
7291 _mmplayer_get_position(MMHandleType hplayer, int format, unsigned long *position) // @
7293 mm_player_t* player = (mm_player_t*)hplayer;
7294 int ret = MM_ERROR_NONE;
7296 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7298 ret = __gst_get_position ( player, format, position );
7304 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos) // @
7306 mm_player_t* player = (mm_player_t*)hplayer;
7307 int ret = MM_ERROR_NONE;
7309 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7311 ret = __gst_get_buffer_position ( player, format, start_pos, stop_pos );
7317 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position) // @
7319 mm_player_t* player = (mm_player_t*)hplayer;
7320 int ret = MM_ERROR_NONE;
7324 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7326 ret = __gst_adjust_subtitle_position(player, format, position);
7334 __mmplayer_is_midi_type( gchar* str_caps)
7336 if ( ( g_strrstr(str_caps, "audio/midi") ) ||
7337 ( g_strrstr(str_caps, "application/x-gst_ff-mmf") ) ||
7338 ( g_strrstr(str_caps, "application/x-smaf") ) ||
7339 ( g_strrstr(str_caps, "audio/x-imelody") ) ||
7340 ( g_strrstr(str_caps, "audio/mobile-xmf") ) ||
7341 ( g_strrstr(str_caps, "audio/xmf") ) ||
7342 ( g_strrstr(str_caps, "audio/mxmf") ) )
7344 debug_log("midi\n");
7349 debug_log("not midi.\n");
7355 __mmplayer_is_amr_type (gchar *str_caps)
7357 if ((g_strrstr(str_caps, "AMR")) ||
7358 (g_strrstr(str_caps, "amr")))
7366 __mmplayer_is_only_mp3_type (gchar *str_caps)
7368 if (g_strrstr(str_caps, "application/x-id3") ||
7369 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
7377 __mmplayer_typefind_have_type( GstElement *tf, guint probability, // @
7378 GstCaps *caps, gpointer data)
7380 mm_player_t* player = (mm_player_t*)data;
7385 return_if_fail( player && tf && caps );
7387 /* store type string */
7388 MMPLAYER_FREEIF(player->type);
7389 player->type = gst_caps_to_string(caps);
7391 debug_log("meida type %s found, probability %d%% / %d\n", player->type, probability, gst_caps_get_size(caps));
7393 /* midi type should be stored because it will be used to set audio gain in avsysaudiosink */
7394 if ( __mmplayer_is_midi_type(player->type))
7396 player->profile.play_mode = MM_PLAYER_MODE_MIDI;
7398 else if (__mmplayer_is_amr_type(player->type))
7400 player->bypass_audio_effect = FALSE;
7401 if ( (PLAYER_INI()->use_audio_effect_preset || PLAYER_INI()->use_audio_effect_custom) )
7403 if ( player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_PRESET )
7405 if (!_mmplayer_audio_effect_preset_apply(player, player->audio_effect_info.preset))
7407 debug_msg("apply audio effect(preset:%d) setting success\n",player->audio_effect_info.preset);
7410 else if ( player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM )
7412 if (!_mmplayer_audio_effect_custom_apply(player))
7414 debug_msg("apply audio effect(custom) setting success\n");
7419 else if ( g_strrstr(player->type, "application/x-hls"))
7421 /* If it can't know exact type when it parses uri because of redirection case,
7422 * it will be fixed by typefinder here.
7424 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
7427 pad = gst_element_get_static_pad(tf, "src");
7430 debug_error("fail to get typefind src pad.\n");
7436 if ( ! __mmplayer_try_to_plug( player, pad, caps ) )
7438 debug_error("failed to autoplug for type : %s\n", player->type);
7440 if ( ( PLAYER_INI()->async_start ) &&
7441 ( player->posted_msg == FALSE ) )
7443 __mmplayer_post_missed_plugin( player );
7449 /* finish autopluging if no dynamic pad waiting */
7450 if( ( ! player->have_dynamic_pad) && ( ! player->has_many_types) )
7452 if ( ! MMPLAYER_IS_RTSP_STREAMING( player ) )
7454 __mmplayer_pipeline_complete( NULL, (gpointer)player );
7459 gst_object_unref( GST_OBJECT(pad) );
7467 __mmplayer_warm_up_video_codec( mm_player_t* player, GstElementFactory *factory)
7469 GstElement *element;
7470 GstStateChangeReturn ret;
7471 gboolean usable = TRUE;
7473 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7474 return_val_if_fail ( factory, MM_ERROR_COMMON_INVALID_ARGUMENT );
7476 element = gst_element_factory_create (factory, NULL);
7478 ret = gst_element_set_state (element, GST_STATE_READY);
7480 if (ret != GST_STATE_CHANGE_SUCCESS)
7482 debug_error ("resource conflict so, %s unusable\n", GST_PLUGIN_FEATURE_NAME (factory));
7486 gst_element_set_state (element, GST_STATE_NULL);
7487 gst_object_unref (element);
7492 /* it will return first created element */
7494 __mmplayer_try_to_plug(mm_player_t* player, GstPad *pad, const GstCaps *caps) // @
7496 MMPlayerGstElement* mainbin = NULL;
7497 const char* mime = NULL;
7498 const GList* item = NULL;
7499 const gchar* klass = NULL;
7500 GstCaps* res = NULL;
7501 gboolean skip = FALSE;
7502 GstPad* queue_pad = NULL;
7503 GstElement* queue = NULL;
7504 GstElement *element = NULL;
7508 return_val_if_fail( player &&
7510 player->pipeline->mainbin,
7514 mainbin = player->pipeline->mainbin;
7516 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
7518 /* return if we got raw output */
7519 if(g_str_has_prefix(mime, "video/x-raw") || g_str_has_prefix(mime, "audio/x-raw") || g_str_has_prefix(mime, "text/plain") ||g_str_has_prefix(mime, "text/x-pango-markup"))
7522 element = (GstElement*)gst_pad_get_parent(pad);
7525 /* NOTE : When no decoder has added during autoplugging. like a simple wave playback.
7526 * No queue will be added. I think it can caused breaking sound when playing raw audio
7527 * frames but there's no different. Decodebin also doesn't add with those wav fils.
7528 * Anyway, currentely raw-queue seems not necessary.
7531 /* NOTE : check if previously linked element is demuxer/depayloader/parse means no decoder
7532 * has linked. if so, we need to add queue for quality of output. note that
7533 * decodebin also has same problem.
7536 klass = gst_element_factory_get_klass( gst_element_get_factory(element) );
7538 /* add queue if needed */
7539 if( (g_strrstr(klass, "Demux") ||
7540 g_strrstr(klass, "Depayloader") ||
7541 g_strrstr(klass, "Parse")) && !g_str_has_prefix(mime, "text"))
7543 debug_log("adding raw queue\n");
7545 queue = gst_element_factory_make("queue", NULL);
7548 debug_warning("failed to create queue\n");
7553 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_READY) )
7555 debug_warning("failed to set state READY to queue\n");
7559 /* add to pipeline */
7560 if ( ! gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue) )
7562 debug_warning("failed to add queue\n");
7567 queue_pad = gst_element_get_static_pad(queue, "sink");
7569 if ( GST_PAD_LINK_OK != gst_pad_link(pad, queue_pad) )
7571 debug_warning("failed to link queue\n");
7574 gst_object_unref ( GST_OBJECT(queue_pad) );
7578 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_PAUSED) )
7580 debug_warning("failed to set state READY to queue\n");
7584 /* replace given pad to queue:src */
7585 pad = gst_element_get_static_pad(queue, "src");
7588 debug_warning("failed to get pad from queue\n");
7593 /* check if player can do start continually */
7594 MMPLAYER_CHECK_CMD_IF_EXIT(player);
7596 if(__mmplayer_link_sink(player,pad))
7597 __mmplayer_gst_decode_callback(element, pad, FALSE, player);
7599 gst_object_unref( GST_OBJECT(element));
7605 item = player->factories;
7606 for(; item != NULL ; item = item->next)
7609 GstElementFactory *factory = GST_ELEMENT_FACTORY(item->data);
7615 /* filtering exclude keyword */
7616 for ( idx = 0; PLAYER_INI()->exclude_element_keyword[idx][0] != '\0'; idx++ )
7618 if ( g_strrstr(GST_PLUGIN_FEATURE_NAME (factory),
7619 PLAYER_INI()->exclude_element_keyword[idx] ) )
7621 debug_warning("skipping [%s] by exculde keyword [%s]\n",
7622 GST_PLUGIN_FEATURE_NAME (factory),
7623 PLAYER_INI()->exclude_element_keyword[idx] );
7630 if ( skip ) continue;
7633 /* check factory class for filtering */
7634 klass = gst_element_factory_get_klass(GST_ELEMENT_FACTORY(factory));
7636 /* NOTE : msl don't need to use image plugins.
7637 * So, those plugins should be skipped for error handling.
7639 if ( g_strrstr(klass, "Codec/Decoder/Image") )
7641 debug_log("player doesn't need [%s] so, skipping it\n",
7642 GST_PLUGIN_FEATURE_NAME (factory) );
7648 /* check pad compatability */
7649 for(pads = gst_element_factory_get_static_pad_templates(factory);
7650 pads != NULL; pads=pads->next)
7652 GstStaticPadTemplate *temp1 = pads->data;
7653 GstCaps* static_caps = NULL;
7655 if( temp1->direction != GST_PAD_SINK ||
7656 temp1->presence != GST_PAD_ALWAYS)
7660 if ( GST_IS_CAPS( &temp1->static_caps.caps) )
7662 /* using existing caps */
7663 static_caps = gst_caps_ref( &temp1->static_caps.caps );
7668 static_caps = gst_caps_from_string ( temp1->static_caps.string );
7671 res = gst_caps_intersect(caps, static_caps);
7673 gst_caps_unref( static_caps );
7676 if( res && !gst_caps_is_empty(res) )
7678 GstElement *new_element;
7679 GList *elements = player->parsers;
7680 char *name_template = g_strdup(temp1->name_template);
7681 gchar *name_to_plug = GST_PLUGIN_FEATURE_NAME(factory);
7683 gst_caps_unref(res);
7685 debug_log("found %s to plug\n", name_to_plug);
7687 new_element = gst_element_factory_create(GST_ELEMENT_FACTORY(factory), NULL);
7688 if ( ! new_element )
7690 debug_error("failed to create element [%s]. continue with next.\n",
7691 GST_PLUGIN_FEATURE_NAME (factory));
7693 MMPLAYER_FREEIF(name_template);
7698 /* check and skip it if it was already used. Otherwise, it can be an infinite loop
7699 * because parser can accept its own output as input.
7701 if (g_strrstr(klass, "Parser"))
7703 gchar *selected = NULL;
7705 for ( ; elements; elements = g_list_next(elements))
7707 gchar *element_name = elements->data;
7709 if (g_strrstr(element_name, name_to_plug))
7711 debug_log("but, %s already linked, so skipping it\n", name_to_plug);
7718 selected = g_strdup(name_to_plug);
7720 player->parsers = g_list_append(player->parsers, selected);
7723 /* store specific handles for futher control */
7724 if(g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse"))
7726 /* FIXIT : first value will be overwritten if there's more
7727 * than 1 demuxer/parser
7729 debug_log("plugged element is demuxer. take it\n");
7730 mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7731 mainbin[MMPLAYER_M_DEMUX].gst = new_element;
7733 else if(g_strrstr(klass, "Decoder") && __mmplayer_link_decoder(player,pad))
7735 if(mainbin[MMPLAYER_M_DEC1].gst == NULL)
7737 debug_log("plugged element is decoder. take it[MMPLAYER_M_DEC1]\n");
7738 mainbin[MMPLAYER_M_DEC1].id = MMPLAYER_M_DEC1;
7739 mainbin[MMPLAYER_M_DEC1].gst = new_element;
7741 else if(mainbin[MMPLAYER_M_DEC2].gst == NULL)
7743 debug_log("plugged element is decoder. take it[MMPLAYER_M_DEC2]\n");
7744 mainbin[MMPLAYER_M_DEC2].id = MMPLAYER_M_DEC2;
7745 mainbin[MMPLAYER_M_DEC2].gst = new_element;
7748 /* NOTE : IF one codec is found, add it to supported_codec and remove from
7749 * missing plugin. Both of them are used to check what's supported codec
7750 * before returning result of play start. And, missing plugin should be
7751 * updated here for multi track files.
7753 if(g_str_has_prefix(mime, "video"))
7755 GstPad *src_pad = NULL;
7756 GstPadTemplate *pad_templ = NULL;
7757 GstCaps *caps = NULL;
7758 gchar *caps_type = NULL;
7760 debug_log("found VIDEO decoder\n");
7761 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7762 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7764 src_pad = gst_element_get_static_pad (new_element, "src");
7765 pad_templ = gst_pad_get_pad_template (src_pad);
7766 caps = GST_PAD_TEMPLATE_CAPS(pad_templ);
7768 caps_type = gst_caps_to_string(caps);
7770 if ( g_strrstr( caps_type, "ST12") )
7771 player->is_nv12_tiled = TRUE;
7774 MMPLAYER_FREEIF( caps_type );
7775 gst_object_unref (src_pad);
7777 else if (g_str_has_prefix(mime, "audio"))
7779 debug_log("found AUDIO decoder\n");
7780 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7781 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7784 if ( ! __mmplayer_close_link(player, pad, new_element,
7785 name_template,gst_element_factory_get_static_pad_templates(factory)) )
7787 if (player->keep_detecting_vcodec)
7790 /* Link is failed even though a supportable codec is found. */
7791 __mmplayer_check_not_supported_codec(player, (gchar *)mime);
7793 MMPLAYER_FREEIF(name_template);
7794 debug_error("failed to call _close_link\n");
7798 MMPLAYER_FREEIF(name_template);
7802 gst_caps_unref(res);
7808 /* There is no any found codec. */
7809 __mmplayer_check_not_supported_codec(player,(gchar *)mime);
7811 debug_error("failed to autoplug\n");
7822 gst_object_unref( queue );
7826 gst_object_unref( queue_pad );
7829 gst_object_unref ( element );
7836 int __mmplayer_check_not_supported_codec(mm_player_t* player, gchar* mime)
7840 return_val_if_fail(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7841 return_val_if_fail ( mime, MM_ERROR_INVALID_ARGUMENT );
7843 debug_log("mimetype to check: %s\n", mime );
7845 /* add missing plugin */
7846 /* NOTE : msl should check missing plugin for image mime type.
7847 * Some motion jpeg clips can have playable audio track.
7848 * So, msl have to play audio after displaying popup written video format not supported.
7850 if ( !( player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst ) )
7852 if ( !( player->can_support_codec | player->videodec_linked | player->audiodec_linked ) )
7854 debug_log("not found demuxer\n");
7855 player->not_found_demuxer = TRUE;
7856 player->unlinked_demuxer_mime = g_strdup_printf ( "%s", mime );
7862 if( ( g_str_has_prefix(mime, "video") ) ||( g_str_has_prefix(mime, "image") ) )
7864 debug_log("can support codec=%d, vdec_linked=%d, adec_linked=%d\n",
7865 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
7867 /* check that clip have multi tracks or not */
7868 if ( ( player->can_support_codec & FOUND_PLUGIN_VIDEO ) && ( player->videodec_linked ) )
7870 debug_log("video plugin is already linked\n");
7874 debug_warning("add VIDEO to missing plugin\n");
7875 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
7878 else if ( g_str_has_prefix(mime, "audio") )
7880 if ( ( player->can_support_codec & FOUND_PLUGIN_AUDIO ) && ( player->audiodec_linked ) )
7882 debug_log("audio plugin is already linked\n");
7886 debug_warning("add AUDIO to missing plugin\n");
7887 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
7894 return MM_ERROR_NONE;
7898 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data) // @
7900 mm_player_t* player = (mm_player_t*)data;
7904 return_if_fail( player );
7906 /* remove fakesink */
7907 if ( ! __mmplayer_gst_remove_fakesink( player,
7908 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]) )
7910 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
7911 * signaling mechanism ( pad-added, no-more-pad, new-decoded-pad ) from various
7912 * source element are not same. To overcome this situation, this function will called
7913 * several places and several times. Therefore, this is not an error case.
7917 debug_log("pipeline has completely constructed\n");
7919 player->pipeline_is_constructed = TRUE;
7921 if ( ( PLAYER_INI()->async_start ) &&
7922 ( player->posted_msg == FALSE ) &&
7923 ( player->cmd >= MMPLAYER_COMMAND_START ))
7925 __mmplayer_post_missed_plugin( player );
7928 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-complete" );
7931 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player)
7935 return_val_if_fail ( player, FALSE );
7938 if ( MMPLAYER_IS_STREAMING(player) )
7941 /* This callback can be set to music player only. */
7942 if((player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO)
7944 debug_warning("audio callback is not supported for video");
7948 if (player->audio_stream_cb)
7953 pad = gst_element_get_static_pad (player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
7957 debug_error("failed to get sink pad from audiosink to probe data\n");
7961 player->audio_cb_probe_id = gst_pad_add_buffer_probe (pad,
7962 G_CALLBACK (__mmplayer_audio_stream_probe), player);
7964 gst_object_unref (pad);
7971 debug_error("There is no audio callback to configure.\n");
7981 __mmplayer_init_factories(mm_player_t* player) // @
7985 return_if_fail ( player );
7987 player->factories = gst_registry_feature_filter(gst_registry_get_default(),
7988 (GstPluginFeatureFilter)__mmplayer_feature_filter, FALSE, NULL);
7990 player->factories = g_list_sort(player->factories, (GCompareFunc)util_factory_rank_compare);
7996 __mmplayer_release_factories(mm_player_t* player) // @
8000 return_if_fail ( player );
8002 if (player->factories)
8004 gst_plugin_feature_list_free (player->factories);
8005 player->factories = NULL;
8012 __mmplayer_release_misc(mm_player_t* player)
8017 return_if_fail ( player );
8019 player->use_video_stream = FALSE;
8020 player->video_stream_cb = NULL;
8021 player->video_stream_cb_user_param = NULL;
8023 player->audio_stream_cb = NULL;
8024 player->audio_stream_cb_user_param = NULL;
8026 player->audio_buffer_cb = NULL;
8027 player->audio_buffer_cb_user_param = NULL;
8029 player->sent_bos = FALSE;
8030 player->playback_rate = DEFAULT_PLAYBACK_RATE;
8032 player->doing_seek = FALSE;
8034 player->streamer = NULL;
8035 player->updated_bitrate_count = 0;
8036 player->total_bitrate = 0;
8037 player->updated_maximum_bitrate_count = 0;
8038 player->total_maximum_bitrate = 0;
8040 player->not_found_demuxer = 0;
8042 player->last_position = 0;
8043 player->duration = 0;
8044 player->http_content_size = 0;
8045 player->not_supported_codec = MISSING_PLUGIN_NONE;
8046 player->can_support_codec = FOUND_PLUGIN_NONE;
8047 player->need_update_content_dur = FALSE;
8048 player->pending_seek.is_pending = FALSE;
8049 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
8050 player->pending_seek.pos = 0;
8051 player->posted_msg = FALSE;
8052 player->has_many_types = FALSE;
8054 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++)
8056 player->bitrate[i] = 0;
8057 player->maximum_bitrate[i] = 0;
8060 /* clean found parsers */
8061 if (player->parsers)
8063 g_list_free(player->parsers);
8064 player->parsers = NULL;
8067 MMPLAYER_FREEIF(player->album_art);
8069 /* free memory related to audio effect */
8070 if(player->audio_effect_info.custom_ext_level_for_plugin)
8072 free(player->audio_effect_info.custom_ext_level_for_plugin);
8078 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name)
8080 GstElement *element = NULL;
8083 debug_log("creating %s to plug\n", name);
8085 element = gst_element_factory_make(name, NULL);
8088 debug_error("failed to create queue\n");
8092 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(element, GST_STATE_READY) )
8094 debug_error("failed to set state READY to %s\n", name);
8098 if ( ! gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), element))
8100 debug_error("failed to add %s\n", name);
8104 sinkpad = gst_element_get_static_pad(element, "sink");
8106 if ( GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad) )
8108 debug_error("failed to link %s\n", name);
8109 gst_object_unref (sinkpad);
8114 debug_log("linked %s to pipeline successfully\n", name);
8116 gst_object_unref (sinkpad);
8122 __mmplayer_close_link(mm_player_t* player, GstPad *srcpad, GstElement *sinkelement,
8123 const char *padname, const GList *templlist)
8126 gboolean has_dynamic_pads = FALSE;
8127 gboolean has_many_types = FALSE;
8128 const char *klass = NULL;
8129 GstStaticPadTemplate *padtemplate = NULL;
8130 GstElementFactory *factory = NULL;
8131 GstElement* queue = NULL;
8132 GstElement* parser = NULL;
8133 GstPad *pssrcpad = NULL;
8134 GstPad *qsrcpad = NULL, *qsinkpad = NULL;
8135 MMPlayerGstElement *mainbin = NULL;
8136 GstStructure* str = NULL;
8137 GstCaps* srccaps = NULL;
8138 GstState warmup = GST_STATE_READY;
8139 gboolean isvideo_decoder = FALSE;
8140 guint q_max_size_time = 0;
8144 return_val_if_fail ( player &&
8146 player->pipeline->mainbin,
8149 mainbin = player->pipeline->mainbin;
8151 debug_log("plugging pad %s:%s to newly create %s:%s\n",
8152 GST_ELEMENT_NAME( GST_PAD_PARENT ( srcpad ) ),
8153 GST_PAD_NAME( srcpad ),
8154 GST_ELEMENT_NAME( sinkelement ),
8157 factory = gst_element_get_factory(sinkelement);
8158 klass = gst_element_factory_get_klass(factory);
8160 /* check if player can do start continually */
8161 MMPLAYER_CHECK_CMD_IF_EXIT(player);
8163 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkelement, warmup) )
8165 if (isvideo_decoder)
8166 player->keep_detecting_vcodec = TRUE;
8168 debug_error("failed to set %d state to %s\n", warmup, GST_ELEMENT_NAME( sinkelement ));
8172 /* add to pipeline */
8173 if ( ! gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), sinkelement) )
8175 debug_error("failed to add %s to mainbin\n", GST_ELEMENT_NAME( sinkelement ));
8179 debug_log("element klass : %s\n", klass);
8181 /* added to support multi track files */
8182 /* only decoder case and any of the video/audio still need to link*/
8183 if(g_strrstr(klass, "Decoder") && __mmplayer_link_decoder(player,srcpad))
8187 name = g_strdup(GST_ELEMENT_NAME( GST_PAD_PARENT ( srcpad )));
8189 if (g_strrstr(name, "mpegtsdemux"))
8191 gchar *demux_caps = NULL;
8192 gchar *parser_name = NULL;
8193 GstCaps *dcaps = NULL;
8195 dcaps = gst_pad_get_caps(srcpad);
8196 demux_caps = gst_caps_to_string(dcaps);
8198 if (g_strrstr(demux_caps, "video/x-h264"))
8200 parser_name = g_strdup("h264parse");
8202 else if (g_strrstr(demux_caps, "video/mpeg"))
8204 parser_name = g_strdup("mpeg4videoparse");
8207 gst_caps_unref(dcaps);
8208 MMPLAYER_FREEIF( demux_caps );
8212 parser = __mmplayer_element_create_and_link(player, srcpad, parser_name);
8214 MMPLAYER_FREEIF(parser_name);
8218 debug_error("failed to create parser\n");
8222 /* update srcpad if parser is created */
8223 pssrcpad = gst_element_get_static_pad(parser, "src");
8228 MMPLAYER_FREEIF(name);
8230 queue = __mmplayer_element_create_and_link(player, srcpad, "queue"); // parser - queue or demuxer - queue
8233 debug_error("failed to create queue\n");
8237 /* update srcpad to link with decoder */
8238 qsrcpad = gst_element_get_static_pad(queue, "src");
8241 q_max_size_time = GST_QUEUE_DEFAULT_TIME;
8243 /* assigning queue handle for futher manipulation purpose */
8244 /* FIXIT : make it some kind of list so that msl can support more then two stream (text, data, etc...) */
8245 if(mainbin[MMPLAYER_M_Q1].gst == NULL)
8247 mainbin[MMPLAYER_M_Q1].id = MMPLAYER_M_Q1;
8248 mainbin[MMPLAYER_M_Q1].gst = queue;
8250 g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q1].gst), "max-size-time", q_max_size_time * GST_SECOND, NULL);
8252 else if(mainbin[MMPLAYER_M_Q2].gst == NULL)
8254 mainbin[MMPLAYER_M_Q2].id = MMPLAYER_M_Q2;
8255 mainbin[MMPLAYER_M_Q2].gst = queue;
8257 g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q2].gst), "max-size-time", q_max_size_time * GST_SECOND, NULL);
8261 debug_critical("Not supporting more then two elementary stream\n");
8265 pad = gst_element_get_static_pad(sinkelement, padname);
8269 debug_warning("failed to get pad(%s) from %s. retrying with [sink]\n",
8270 padname, GST_ELEMENT_NAME(sinkelement) );
8272 pad = gst_element_get_static_pad(sinkelement, "sink");
8275 debug_error("failed to get pad(sink) from %s. \n",
8276 GST_ELEMENT_NAME(sinkelement) );
8281 /* to check the video/audio type set the proper flag*/
8283 srccaps = gst_pad_get_caps( srcpad );
8287 str = gst_caps_get_structure( srccaps, 0 );
8291 name = gst_structure_get_name(str);
8296 /* link queue and decoder. so, it will be queue - decoder. */
8297 if ( GST_PAD_LINK_OK != gst_pad_link(srcpad, pad) )
8299 gst_object_unref(GST_OBJECT(pad));
8300 debug_error("failed to link (%s) to pad(%s)\n", GST_ELEMENT_NAME( sinkelement ), padname );
8302 /* reconstitute supportable codec */
8303 if (strstr(name, "video"))
8305 player->can_support_codec ^= FOUND_PLUGIN_VIDEO;
8307 else if (strstr(name, "audio"))
8309 player->can_support_codec ^= FOUND_PLUGIN_AUDIO;
8314 if (strstr(name, "video"))
8316 player->videodec_linked = 1;
8317 debug_msg("player->videodec_linked set to 1\n");
8320 else if (strstr(name, "audio"))
8322 player->audiodec_linked = 1;
8323 debug_msg("player->auddiodec_linked set to 1\n");
8326 gst_object_unref(GST_OBJECT(pad));
8327 gst_caps_unref(GST_CAPS(srccaps));
8331 if ( !MMPLAYER_IS_HTTP_PD(player) )
8333 if( (g_strrstr(klass, "Demux") && !g_strrstr(klass, "Metadata")) || (g_strrstr(klass, "Parser") ) )
8335 if (MMPLAYER_IS_HTTP_STREAMING(player))
8337 GstFormat fmt = GST_FORMAT_BYTES;
8338 gint64 dur_bytes = 0L;
8339 gchar *file_buffering_path = NULL;
8340 gboolean use_file_buffer = FALSE;
8342 if ( !mainbin[MMPLAYER_M_S_BUFFER].gst)
8344 debug_log("creating http streaming buffering queue\n");
8346 queue = gst_element_factory_make("queue2", "http_streaming_buffer");
8349 debug_critical ( "failed to create buffering queue element\n" );
8353 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_READY) )
8355 debug_error("failed to set state READY to buffering queue\n");
8359 if ( !gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue) )
8361 debug_error("failed to add buffering queue\n");
8365 qsinkpad = gst_element_get_static_pad(queue, "sink");
8366 qsrcpad = gst_element_get_static_pad(queue, "src");
8368 if ( GST_PAD_LINK_OK != gst_pad_link(srcpad, qsinkpad) )
8370 debug_error("failed to link buffering queue\n");
8376 mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_S_BUFFER;
8377 mainbin[MMPLAYER_M_S_BUFFER].gst = queue;
8379 if ( !MMPLAYER_IS_HTTP_LIVE_STREAMING(player))
8381 if ( !gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, &fmt, &dur_bytes))
8382 debug_error("fail to get duration.\n");
8386 use_file_buffer = MMPLAYER_USE_FILE_FOR_BUFFERING(player);
8387 file_buffering_path = g_strdup(PLAYER_INI()->http_file_buffer_path);
8391 __mm_player_streaming_set_buffer(player->streamer,
8394 PLAYER_INI()->http_max_size_bytes,
8396 PLAYER_INI()->http_buffering_limit,
8397 PLAYER_INI()->http_buffering_time,
8399 file_buffering_path,
8402 MMPLAYER_FREEIF(file_buffering_path);
8407 /* if it is not decoder or */
8408 /* in decoder case any of the video/audio still need to link*/
8409 if(!g_strrstr(klass, "Decoder"))
8412 pad = gst_element_get_static_pad(sinkelement, padname);
8415 debug_warning("failed to get pad(%s) from %s. retrying with [sink]\n",
8416 padname, GST_ELEMENT_NAME(sinkelement) );
8418 pad = gst_element_get_static_pad(sinkelement, "sink");
8422 debug_error("failed to get pad(sink) from %s. \n",
8423 GST_ELEMENT_NAME(sinkelement) );
8428 if ( GST_PAD_LINK_OK != gst_pad_link(srcpad, pad) )
8430 gst_object_unref(GST_OBJECT(pad));
8431 debug_error("failed to link (%s) to pad(%s)\n", GST_ELEMENT_NAME( sinkelement ), padname );
8435 gst_object_unref(GST_OBJECT(pad));
8438 for(;templlist != NULL; templlist = templlist->next)
8440 padtemplate = templlist->data;
8442 debug_log ("director = [%d], presence = [%d]\n", padtemplate->direction, padtemplate->presence);
8444 if( padtemplate->direction != GST_PAD_SRC ||
8445 padtemplate->presence == GST_PAD_REQUEST )
8448 switch(padtemplate->presence)
8450 case GST_PAD_ALWAYS:
8452 GstPad *srcpad = gst_element_get_static_pad(sinkelement, "src");
8453 GstCaps *caps = gst_pad_get_caps(srcpad);
8455 /* Check whether caps has many types */
8456 if ( gst_caps_get_size (caps) > 1 && g_strrstr(klass, "Parser")) {
8457 debug_log ("has_many_types for this caps [%s]\n", gst_caps_to_string(caps));
8458 has_many_types = TRUE;
8462 if ( ! __mmplayer_try_to_plug(player, srcpad, caps) )
8464 gst_object_unref(GST_OBJECT(srcpad));
8465 gst_caps_unref(GST_CAPS(caps));
8467 debug_error("failed to plug something after %s\n", GST_ELEMENT_NAME( sinkelement ));
8471 gst_caps_unref(GST_CAPS(caps));
8472 gst_object_unref(GST_OBJECT(srcpad));
8478 case GST_PAD_SOMETIMES:
8479 has_dynamic_pads = TRUE;
8487 /* check if player can do start continually */
8488 MMPLAYER_CHECK_CMD_IF_EXIT(player);
8490 if( has_dynamic_pads )
8492 player->have_dynamic_pad = TRUE;
8493 MMPLAYER_SIGNAL_CONNECT ( player, sinkelement, "pad-added",
8494 G_CALLBACK(__mmplayer_add_new_pad), player);
8496 /* for streaming, more then one typefind will used for each elementary stream
8497 * so this doesn't mean the whole pipeline completion
8499 if ( ! MMPLAYER_IS_RTSP_STREAMING( player ) )
8501 MMPLAYER_SIGNAL_CONNECT( player, sinkelement, "no-more-pads",
8502 G_CALLBACK(__mmplayer_pipeline_complete), player);
8510 player->has_many_types = has_many_types;
8512 pad = gst_element_get_static_pad(sinkelement, "src");
8513 MMPLAYER_SIGNAL_CONNECT (player, pad, "notify::caps", G_CALLBACK(__mmplayer_add_new_caps), player);
8514 gst_object_unref (GST_OBJECT(pad));
8518 /* check if player can do start continually */
8519 MMPLAYER_CHECK_CMD_IF_EXIT(player);
8521 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkelement, GST_STATE_PAUSED) )
8523 debug_error("failed to set state PAUSED to %s\n", GST_ELEMENT_NAME( sinkelement ));
8529 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state (queue, GST_STATE_PAUSED) )
8531 debug_error("failed to set state PAUSED to queue\n");
8537 gst_object_unref (GST_OBJECT(qsrcpad));
8543 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state (parser, GST_STATE_PAUSED) )
8545 debug_error("failed to set state PAUSED to queue\n");
8551 gst_object_unref (GST_OBJECT(pssrcpad));
8563 gst_object_unref(GST_OBJECT(qsrcpad));
8565 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
8566 * You need to explicitly set elements to the NULL state before
8567 * dropping the final reference, to allow them to clean up.
8569 gst_element_set_state(queue, GST_STATE_NULL);
8570 /* And, it still has a parent "player".
8571 * You need to let the parent manage the object instead of unreffing the object directly.
8574 gst_bin_remove (GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue);
8575 //gst_object_unref( queue );
8579 gst_caps_unref(GST_CAPS(srccaps));
8584 static gboolean __mmplayer_feature_filter(GstPluginFeature *feature, gpointer data) // @
8587 //const gchar *name;
8589 /* we only care about element factories */
8590 if (!GST_IS_ELEMENT_FACTORY(feature))
8593 /* only parsers, demuxers and decoders */
8594 klass = gst_element_factory_get_klass(GST_ELEMENT_FACTORY(feature));
8595 //name = gst_element_factory_get_longname(GST_ELEMENT_FACTORY(feature));
8597 if( g_strrstr(klass, "Demux") == NULL &&
8598 g_strrstr(klass, "Codec/Decoder") == NULL &&
8599 g_strrstr(klass, "Depayloader") == NULL &&
8600 g_strrstr(klass, "Parse") == NULL)
8608 static void __mmplayer_add_new_caps(GstPad* pad, GParamSpec* unused, gpointer data)
8610 mm_player_t* player = (mm_player_t*) data;
8611 GstCaps *caps = NULL;
8612 GstStructure *str = NULL;
8617 return_if_fail ( pad )
8618 return_if_fail ( unused )
8619 return_if_fail ( data )
8621 caps = gst_pad_get_caps(pad);
8625 str = gst_caps_get_structure(caps, 0);
8629 name = gst_structure_get_name(str);
8632 debug_log("name=%s\n", name);
8634 if ( ! __mmplayer_try_to_plug(player, pad, caps) )
8636 debug_error("failed to autoplug for type (%s)\n", name);
8637 gst_caps_unref(caps);
8641 gst_caps_unref(caps);
8643 __mmplayer_pipeline_complete( NULL, (gpointer)player );
8650 static void __mmplayer_set_unlinked_mime_type(mm_player_t* player, GstCaps *caps)
8654 const char *stream_type;
8655 gchar *version_field = NULL;
8659 return_if_fail ( player );
8660 return_if_fail ( caps );
8662 str = gst_caps_get_structure(caps, 0);
8666 stream_type = gst_structure_get_name(str);
8671 /* set unlinked mime type for downloadable codec */
8672 if (g_str_has_prefix(stream_type, "video/"))
8674 if (g_str_has_prefix(stream_type, "video/mpeg"))
8676 gst_structure_get_int (str, MM_PLAYER_MPEG_VNAME, &version);
8677 version_field = MM_PLAYER_MPEG_VNAME;
8679 else if (g_str_has_prefix(stream_type, "video/x-wmv"))
8681 gst_structure_get_int (str, MM_PLAYER_WMV_VNAME, &version);
8682 version_field = MM_PLAYER_WMV_VNAME;
8685 else if (g_str_has_prefix(stream_type, "video/x-divx"))
8687 gst_structure_get_int (str, MM_PLAYER_DIVX_VNAME, &version);
8688 version_field = MM_PLAYER_DIVX_VNAME;
8693 player->unlinked_video_mime = g_strdup_printf("%s, %s=%d", stream_type, version_field, version);
8697 player->unlinked_video_mime = g_strdup_printf("%s", stream_type);
8700 else if (g_str_has_prefix(stream_type, "audio/"))
8702 if (g_str_has_prefix(stream_type, "audio/mpeg")) // mp3 or aac
8704 gst_structure_get_int (str, MM_PLAYER_MPEG_VNAME, &version);
8705 version_field = MM_PLAYER_MPEG_VNAME;
8707 else if (g_str_has_prefix(stream_type, "audio/x-wma"))
8709 gst_structure_get_int (str, MM_PLAYER_WMA_VNAME, &version);
8710 version_field = MM_PLAYER_WMA_VNAME;
8715 player->unlinked_audio_mime = g_strdup_printf("%s, %s=%d", stream_type, version_field, version);
8719 player->unlinked_audio_mime = g_strdup_printf("%s", stream_type);
8726 static void __mmplayer_add_new_pad(GstElement *element, GstPad *pad, gpointer data)
8728 mm_player_t* player = (mm_player_t*) data;
8729 GstCaps *caps = NULL;
8730 GstStructure *str = NULL;
8734 return_if_fail ( player );
8735 return_if_fail ( pad );
8737 GST_OBJECT_LOCK (pad);
8738 if ((caps = GST_PAD_CAPS(pad)))
8740 GST_OBJECT_UNLOCK (pad);
8744 caps = gst_pad_get_caps(pad);
8745 if ( !caps ) return;
8748 //MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8750 str = gst_caps_get_structure(caps, 0);
8754 name = gst_structure_get_name(str);
8758 player->num_dynamic_pad++;
8759 debug_log("stream count inc : %d\n", player->num_dynamic_pad);
8761 /* Note : If the stream is the subtitle, we try not to play it. Just close the demuxer subtitle pad.
8762 * If want to play it, remove this code.
8764 if (g_strrstr(name, "application"))
8766 if (g_strrstr(name, "x-id3") || g_strrstr(name, "x-apetag"))
8768 /* If id3/ape tag comes, keep going */
8769 debug_log("application mime exception : id3/ape tag");
8773 /* Otherwise, we assume that this stream is subtile. */
8774 debug_log(" application mime type pad is closed.");
8778 else if (g_strrstr(name, "audio"))
8780 gint samplerate = 0, channels = 0;
8782 /* set stream information */
8783 /* if possible, set it here because the caps is not distrubed by resampler. */
8784 gst_structure_get_int (str, "rate", &samplerate);
8785 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
8787 gst_structure_get_int (str, "channels", &channels);
8788 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
8790 debug_log("audio samplerate : %d channels : %d", samplerate, channels);
8793 if ( mmf_attrs_commit ( player->attrs ) )
8795 debug_error("failed to update attributes");
8799 else if (g_strrstr(name, "video"))
8802 mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &stype);
8804 /* don't make video because of not required */
8805 if (stype == MM_DISPLAY_SURFACE_NULL)
8807 debug_log("no video because it's not required");
8811 player->v_stream_caps = gst_caps_copy(caps); //if needed, video caps is required when videobin is created
8814 if ( ! __mmplayer_try_to_plug(player, pad, caps) )
8816 debug_error("failed to autoplug for type (%s)", name);
8818 __mmplayer_set_unlinked_mime_type(player, caps);
8821 gst_caps_unref(caps);
8827 /* test API for tuning audio gain. this API should be
8828 * deprecated before the day of final release
8831 _mmplayer_set_volume_tune(MMHandleType hplayer, MMPlayerVolumeType volume)
8833 mm_player_t* player = (mm_player_t*) hplayer;
8834 gint error = MM_ERROR_NONE;
8836 gboolean isMidi = FALSE;
8841 return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
8842 return_val_if_fail( player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED )
8844 debug_log("clip type=%d(1-midi, 0-others), volume [L]=%d:[R]=%d\n",
8845 player->profile.play_mode, volume.level[0], volume.level[1]);
8847 isMidi = ( player->profile.play_mode == MM_PLAYER_MODE_MIDI ) ? TRUE : FALSE;
8854 /* is it proper volume level? */
8855 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; ++i)
8857 if (volume.level[i] < 0 || volume.level[i] > vol_max) {
8858 debug_log("Invalid Volume level!!!! \n");
8859 return MM_ERROR_INVALID_ARGUMENT;
8865 if ( player->pipeline->mainbin )
8867 GstElement *midi_element = player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst;
8869 if ( midi_element && ( strstr(GST_ELEMENT_NAME(midi_element), "midiparse")) )
8871 debug_log("setting volume (%d) level to midi plugin\n", volume.level[0]);
8873 g_object_set(midi_element, "volume", volume.level[0], NULL);
8879 if ( player->pipeline->audiobin )
8881 GstElement *sink_element = player->pipeline->audiobin[MMPLAYER_A_SINK].gst;
8883 /* Set to Avsysaudiosink element */
8887 gboolean mute = FALSE;
8888 vol_value = volume.level[0];
8890 g_object_set(G_OBJECT(sink_element), "tuningvolume", vol_value, NULL);
8892 mute = (vol_value == 0)? TRUE:FALSE;
8894 g_object_set(G_OBJECT(sink_element), "mute", mute, NULL);
8906 __mmplayer_dump_pipeline_state( mm_player_t* player )
8908 GstIterator*iter = NULL;
8909 gboolean done = FALSE;
8911 GstElement *item = NULL;
8912 GstElementFactory *factory = NULL;
8914 GstState state = GST_STATE_VOID_PENDING;
8915 GstState pending = GST_STATE_VOID_PENDING;
8916 GstClockTime time = 200*GST_MSECOND;
8920 return_val_if_fail ( player &&
8922 player->pipeline->mainbin,
8926 iter = gst_bin_iterate_recurse(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst) );
8931 switch ( gst_iterator_next (iter, (gpointer)&item) )
8933 case GST_ITERATOR_OK:
8934 gst_element_get_state(GST_ELEMENT (item),&state, &pending,time);
8936 factory = gst_element_get_factory (item) ;
8937 debug_error("%s:%s : From:%s To:%s refcount : %d\n", GST_OBJECT_NAME(factory) , GST_ELEMENT_NAME(item) ,
8938 gst_element_state_get_name(state), gst_element_state_get_name(pending) , GST_OBJECT_REFCOUNT_VALUE(item));
8941 gst_object_unref (item);
8943 case GST_ITERATOR_RESYNC:
8944 gst_iterator_resync (iter);
8946 case GST_ITERATOR_ERROR:
8949 case GST_ITERATOR_DONE:
8956 item = GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8958 gst_element_get_state(GST_ELEMENT (item),&state, &pending,time);
8960 factory = gst_element_get_factory (item) ;
8962 debug_error("%s:%s : From:%s To:%s refcount : %d\n",
8963 GST_OBJECT_NAME(factory),
8964 GST_ELEMENT_NAME(item),
8965 gst_element_state_get_name(state),
8966 gst_element_state_get_name(pending),
8967 GST_OBJECT_REFCOUNT_VALUE(item) );
8970 gst_iterator_free (iter);
8979 __mmplayer_check_subtitle( mm_player_t* player )
8981 MMHandleType attrs = 0;
8982 char *subtitle_uri = NULL;
8986 return_val_if_fail( player, FALSE );
8988 /* get subtitle attribute */
8989 attrs = MMPLAYER_GET_ATTRS(player);
8993 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8994 if ( !subtitle_uri || !strlen(subtitle_uri))
8997 debug_log ("subtite uri is %s[%d]\n", subtitle_uri, strlen(subtitle_uri));
9005 __mmplayer_can_extract_pcm( mm_player_t* player )
9007 MMHandleType attrs = 0;
9008 gboolean is_drm = FALSE;
9009 gboolean sound_extraction = FALSE;
9013 return_val_if_fail ( player, FALSE );
9015 attrs = MMPLAYER_GET_ATTRS(player);
9018 debug_error("fail to get attributes.");
9022 /* check file is drm or not */
9023 g_object_get(G_OBJECT(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), "is-drm", &is_drm, NULL);
9025 /* get sound_extraction property */
9026 mm_attrs_get_int_by_name(attrs, "pcm_extraction", &sound_extraction);
9028 if ( ! sound_extraction || is_drm )
9030 debug_log("pcm extraction param.. is drm = %d, extraction mode = %d", is_drm, sound_extraction);
9040 __mmplayer_handle_gst_error ( mm_player_t* player, GstMessage * message, GError* error )
9042 MMMessageParamType msg_param;
9043 gchar *msg_src_element;
9047 return_val_if_fail( player, FALSE );
9048 return_val_if_fail( error, FALSE );
9050 /* NOTE : do somthing necessary inside of __gst_handle_XXX_error. not here */
9052 memset (&msg_param, 0, sizeof(MMMessageParamType));
9054 if ( error->domain == GST_CORE_ERROR )
9056 msg_param.code = __gst_handle_core_error( player, error->code );
9058 else if ( error->domain == GST_LIBRARY_ERROR )
9060 msg_param.code = __gst_handle_library_error( player, error->code );
9062 else if ( error->domain == GST_RESOURCE_ERROR )
9064 msg_param.code = __gst_handle_resource_error( player, error->code );
9066 else if ( error->domain == GST_STREAM_ERROR )
9068 msg_param.code = __gst_handle_stream_error( player, error, message );
9072 debug_warning("This error domain is not defined.\n");
9074 /* we treat system error as an internal error */
9075 msg_param.code = MM_ERROR_PLAYER_INVALID_STREAM;
9080 msg_src_element = GST_ELEMENT_NAME( GST_ELEMENT_CAST( message->src ) );
9082 msg_param.data = (void *) error->message;
9084 debug_error("-Msg src : [%s] Domain : [%s] Error : [%s] Code : [%d] is tranlated to error code : [0x%x]\n",
9085 msg_src_element, g_quark_to_string (error->domain), error->message, error->code, msg_param.code);
9088 /* post error to application */
9089 if ( ! player->posted_msg )
9091 if (msg_param.code == MM_MESSAGE_DRM_NOT_AUTHORIZED )
9093 MMPLAYER_POST_MSG( player, MM_MESSAGE_DRM_NOT_AUTHORIZED, NULL );
9097 MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param );
9100 /* don't post more if one was sent already */
9101 player->posted_msg = TRUE;
9105 debug_log("skip error post because it's sent already.\n");
9114 __mmplayer_handle_streaming_error ( mm_player_t* player, GstMessage * message )
9117 MMMessageParamType msg_param;
9118 gchar *msg_src_element = NULL;
9119 GstStructure *s = NULL;
9121 gchar *error_string = NULL;
9125 return_val_if_fail ( player, FALSE );
9126 return_val_if_fail ( message, FALSE );
9128 s = malloc( sizeof(GstStructure) );
9129 memcpy ( s, gst_message_get_structure ( message ), sizeof(GstStructure));
9131 if ( !gst_structure_get_uint (s, "error_id", &error_id) )
9132 error_id = MMPLAYER_STREAMING_ERROR_NONE;
9136 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
9137 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
9139 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
9140 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
9142 case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
9143 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
9145 case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
9146 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
9148 case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
9149 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
9151 case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
9152 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
9154 case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
9155 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
9157 case MMPLAYER_STREAMING_ERROR_INVALID_URL:
9158 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
9160 case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
9161 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
9163 case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
9164 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
9166 case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
9167 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
9169 case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
9170 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
9172 case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
9173 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
9175 case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
9176 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
9178 case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
9179 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
9181 case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
9182 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
9184 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
9185 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
9187 case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
9188 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
9190 case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
9191 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
9193 case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
9194 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
9196 case MMPLAYER_STREAMING_ERROR_GONE:
9197 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
9199 case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
9200 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
9202 case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
9203 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
9205 case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
9206 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
9208 case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
9209 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
9211 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
9212 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
9214 case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
9215 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
9217 case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
9218 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
9220 case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
9221 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
9223 case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
9224 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
9226 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
9227 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
9229 case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
9230 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
9232 case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
9233 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
9235 case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
9236 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
9238 case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
9239 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
9241 case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
9242 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
9244 case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
9245 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
9247 case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
9248 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
9250 case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
9251 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
9253 case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
9254 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
9256 case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
9257 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
9259 case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
9260 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
9262 case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
9263 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
9265 case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
9266 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
9268 case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
9269 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
9272 return MM_ERROR_PLAYER_STREAMING_FAIL;
9275 error_string = g_strdup(gst_structure_get_string (s, "error_string"));
9277 msg_param.data = (void *) error_string;
9281 msg_src_element = GST_ELEMENT_NAME( GST_ELEMENT_CAST( message->src ) );
9283 debug_error("-Msg src : [%s] Code : [%x] Error : [%s] \n",
9284 msg_src_element, msg_param.code, (char*)msg_param.data );
9287 /* post error to application */
9288 if ( ! player->posted_msg )
9290 MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param );
9292 /* don't post more if one was sent already */
9293 player->posted_msg = TRUE;
9297 debug_log("skip error post because it's sent already.\n");
9307 __gst_handle_core_error( mm_player_t* player, int code )
9309 gint trans_err = MM_ERROR_NONE;
9313 return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9317 case GST_CORE_ERROR_STATE_CHANGE:
9318 case GST_CORE_ERROR_MISSING_PLUGIN:
9319 case GST_CORE_ERROR_SEEK:
9320 case GST_CORE_ERROR_NOT_IMPLEMENTED:
9321 case GST_CORE_ERROR_FAILED:
9322 case GST_CORE_ERROR_TOO_LAZY:
9323 case GST_CORE_ERROR_PAD:
9324 case GST_CORE_ERROR_THREAD:
9325 case GST_CORE_ERROR_NEGOTIATION:
9326 case GST_CORE_ERROR_EVENT:
9327 case GST_CORE_ERROR_CAPS:
9328 case GST_CORE_ERROR_TAG:
9329 case GST_CORE_ERROR_CLOCK:
9330 case GST_CORE_ERROR_DISABLED:
9332 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
9342 __gst_handle_library_error( mm_player_t* player, int code )
9344 gint trans_err = MM_ERROR_NONE;
9348 return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9352 case GST_LIBRARY_ERROR_FAILED:
9353 case GST_LIBRARY_ERROR_TOO_LAZY:
9354 case GST_LIBRARY_ERROR_INIT:
9355 case GST_LIBRARY_ERROR_SHUTDOWN:
9356 case GST_LIBRARY_ERROR_SETTINGS:
9357 case GST_LIBRARY_ERROR_ENCODE:
9359 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
9370 __gst_handle_resource_error( mm_player_t* player, int code )
9372 gint trans_err = MM_ERROR_NONE;
9376 return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9380 case GST_RESOURCE_ERROR_NO_SPACE_LEFT:
9381 trans_err = MM_ERROR_PLAYER_NO_FREE_SPACE;
9383 case GST_RESOURCE_ERROR_NOT_FOUND:
9384 case GST_RESOURCE_ERROR_OPEN_READ:
9385 if ( MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING ( player ) )
9387 trans_err = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
9390 case GST_RESOURCE_ERROR_READ:
9391 if ( MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING ( player ))
9393 trans_err = MM_ERROR_PLAYER_STREAMING_FAIL;
9396 case GST_RESOURCE_ERROR_SEEK:
9397 case GST_RESOURCE_ERROR_FAILED:
9398 case GST_RESOURCE_ERROR_TOO_LAZY:
9399 case GST_RESOURCE_ERROR_BUSY:
9400 case GST_RESOURCE_ERROR_OPEN_WRITE:
9401 case GST_RESOURCE_ERROR_OPEN_READ_WRITE:
9402 case GST_RESOURCE_ERROR_CLOSE:
9403 case GST_RESOURCE_ERROR_WRITE:
9404 case GST_RESOURCE_ERROR_SYNC:
9405 case GST_RESOURCE_ERROR_SETTINGS:
9407 trans_err = MM_ERROR_PLAYER_FILE_NOT_FOUND;
9418 __gst_handle_stream_error( mm_player_t* player, GError* error, GstMessage * message )
9420 gint trans_err = MM_ERROR_NONE;
9424 return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9425 return_val_if_fail( error, MM_ERROR_INVALID_ARGUMENT );
9426 return_val_if_fail ( message, MM_ERROR_INVALID_ARGUMENT );
9428 switch ( error->code )
9430 case GST_STREAM_ERROR_FAILED:
9431 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
9432 case GST_STREAM_ERROR_DECODE:
9433 case GST_STREAM_ERROR_WRONG_TYPE:
9434 case GST_STREAM_ERROR_DECRYPT:
9435 case GST_STREAM_ERROR_DECRYPT_NOKEY:
9436 trans_err = __gst_transform_gsterror( player, message, error );
9439 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
9440 case GST_STREAM_ERROR_NOT_IMPLEMENTED:
9441 case GST_STREAM_ERROR_TOO_LAZY:
9442 case GST_STREAM_ERROR_ENCODE:
9443 case GST_STREAM_ERROR_DEMUX:
9444 case GST_STREAM_ERROR_MUX:
9445 case GST_STREAM_ERROR_FORMAT:
9447 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
9457 /* NOTE : decide gstreamer state whether there is some playable track or not. */
9459 __gst_transform_gsterror( mm_player_t* player, GstMessage * message, GError* error )
9461 gchar *src_element_name = NULL;
9462 GstElement *src_element = NULL;
9463 GstElementFactory *factory = NULL;
9464 const gchar* klass = NULL;
9469 return_val_if_fail ( message, MM_ERROR_INVALID_ARGUMENT );
9470 return_val_if_fail ( message->src, MM_ERROR_INVALID_ARGUMENT );
9471 return_val_if_fail ( error, MM_ERROR_INVALID_ARGUMENT );
9473 src_element = GST_ELEMENT_CAST(message->src);
9475 goto INTERNAL_ERROR;
9477 src_element_name = GST_ELEMENT_NAME(src_element);
9478 if ( !src_element_name )
9479 goto INTERNAL_ERROR;
9481 factory = gst_element_get_factory(src_element);
9483 goto INTERNAL_ERROR;
9485 klass = gst_element_factory_get_klass(factory);
9487 goto INTERNAL_ERROR;
9489 debug_log("error code=%d, msg=%s, src element=%s, class=%s\n",
9490 error->code, error->message, src_element_name, klass);
9493 switch ( error->code )
9495 case GST_STREAM_ERROR_DECODE:
9497 /* NOTE : Delay is needed because gst callback is sometime sent
9498 * before completing autoplugging.
9499 * Timer is more better than usleep.
9500 * But, transformed msg value should be stored in player handle
9501 * for function to call by timer.
9503 if ( PLAYER_INI()->async_start )
9506 /* Demuxer can't parse one track because it's corrupted.
9507 * So, the decoder for it is not linked.
9508 * But, it has one playable track.
9510 if ( g_strrstr(klass, "Demux") )
9512 if ( player->can_support_codec == FOUND_PLUGIN_VIDEO )
9514 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9516 else if ( player->can_support_codec == FOUND_PLUGIN_AUDIO )
9518 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
9522 if ( player->pipeline->audiobin ) // PCM
9524 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
9528 goto CODEC_NOT_FOUND;
9532 return MM_ERROR_PLAYER_INVALID_STREAM;
9536 case GST_STREAM_ERROR_WRONG_TYPE:
9538 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
9542 case GST_STREAM_ERROR_FAILED:
9544 /* Decoder Custom Message */
9545 if ( strstr(error->message, "ongoing") )
9547 if ( strcasestr(klass, "audio") )
9549 if ( ( player->can_support_codec & FOUND_PLUGIN_VIDEO ) )
9551 debug_log("Video can keep playing.\n");
9552 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9556 goto CODEC_NOT_FOUND;
9560 else if ( strcasestr(klass, "video") )
9562 if ( ( player->can_support_codec & FOUND_PLUGIN_AUDIO ) )
9564 debug_log("Audio can keep playing.\n");
9565 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
9569 goto CODEC_NOT_FOUND;
9573 return MM_ERROR_PLAYER_INVALID_STREAM;
9577 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
9579 goto CODEC_NOT_FOUND;
9583 case GST_STREAM_ERROR_DECRYPT:
9584 case GST_STREAM_ERROR_DECRYPT_NOKEY:
9586 debug_error("decryption error, [%s] failed, reason : [%s]\n", src_element_name, error->message);
9587 return MM_MESSAGE_DRM_NOT_AUTHORIZED;
9597 return MM_ERROR_PLAYER_INVALID_STREAM;
9600 return MM_ERROR_PLAYER_INTERNAL;
9603 debug_log("not found any available codec. Player should be destroyed.\n");
9604 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9608 __mmplayer_post_delayed_eos( mm_player_t* player, int delay_in_ms )
9612 return_if_fail( player );
9614 /* cancel if existing */
9615 __mmplayer_cancel_delayed_eos( player );
9618 /* post now if delay is zero */
9619 if ( delay_in_ms == 0 || player->is_sound_extraction)
9621 debug_log("eos delay is zero. posting EOS now\n");
9622 MMPLAYER_POST_MSG( player, MM_MESSAGE_END_OF_STREAM, NULL );
9624 if ( player->is_sound_extraction )
9625 __mmplayer_cancel_delayed_eos(player);
9630 /* init new timeout */
9631 /* NOTE : consider give high priority to this timer */
9633 debug_log("posting EOS message after [%d] msec\n", delay_in_ms);
9634 player->eos_timer = g_timeout_add( delay_in_ms,
9635 __mmplayer_eos_timer_cb, player );
9638 /* check timer is valid. if not, send EOS now */
9639 if ( player->eos_timer == 0 )
9641 debug_warning("creating timer for delayed EOS has failed. sending EOS now\n");
9642 MMPLAYER_POST_MSG( player, MM_MESSAGE_END_OF_STREAM, NULL );
9649 __mmplayer_cancel_delayed_eos( mm_player_t* player )
9653 return_if_fail( player );
9655 if ( player->eos_timer )
9657 g_source_remove( player->eos_timer );
9660 player->eos_timer = 0;
9668 __mmplayer_eos_timer_cb(gpointer u_data)
9670 mm_player_t* player = NULL;
9671 player = (mm_player_t*) u_data;
9675 return_val_if_fail( player, FALSE );
9678 MMPLAYER_POST_MSG( player, MM_MESSAGE_END_OF_STREAM, NULL );
9680 /* cleare timer id */
9681 player->eos_timer = 0;
9685 /* we are returning FALSE as we need only one posting */
9689 static void __mmplayer_set_antishock( mm_player_t* player, gboolean disable_by_force)
9691 gint antishock = FALSE;
9692 MMHandleType attrs = 0;
9696 return_if_fail ( player && player->pipeline );
9698 /* It should be passed for video only clip */
9699 if ( ! player->pipeline->audiobin )
9702 if ( ( g_strrstr(PLAYER_INI()->name_of_audiosink, "avsysaudiosink")) )
9704 attrs = MMPLAYER_GET_ATTRS(player);
9707 debug_error("fail to get attributes.\n");
9711 mm_attrs_get_int_by_name(attrs, "sound_fadeup", &antishock);
9713 debug_log("setting antishock as (%d)\n", antishock);
9715 if ( disable_by_force )
9717 debug_log("but, antishock is disabled by force when is seeked\n");
9722 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "fadeup", antishock, NULL);
9732 __mmplayer_link_decoder( mm_player_t* player, GstPad *srcpad)
9734 const gchar* name = NULL;
9735 GstStructure* str = NULL;
9736 GstCaps* srccaps = NULL;
9740 return_val_if_fail( player, FALSE );
9741 return_val_if_fail ( srcpad, FALSE );
9743 /* to check any of the decoder (video/audio) need to be linked to parser*/
9744 srccaps = gst_pad_get_caps( srcpad );
9748 str = gst_caps_get_structure( srccaps, 0 );
9752 name = gst_structure_get_name(str);
9756 if (strstr(name, "video"))
9758 if(player->videodec_linked)
9760 debug_msg("Video decoder already linked\n");
9764 if (strstr(name, "audio"))
9766 if(player->audiodec_linked)
9768 debug_msg("Audio decoder already linked\n");
9773 gst_caps_unref( srccaps );
9781 gst_caps_unref( srccaps );
9787 __mmplayer_link_sink( mm_player_t* player , GstPad *srcpad)
9789 const gchar* name = NULL;
9790 GstStructure* str = NULL;
9791 GstCaps* srccaps = NULL;
9795 return_val_if_fail ( player, FALSE );
9796 return_val_if_fail ( srcpad, FALSE );
9798 /* to check any of the decoder (video/audio) need to be linked to parser*/
9799 srccaps = gst_pad_get_caps( srcpad );
9803 str = gst_caps_get_structure( srccaps, 0 );
9807 name = gst_structure_get_name(str);
9811 if (strstr(name, "video"))
9813 if(player->videosink_linked)
9815 debug_msg("Video Sink already linked\n");
9819 if (strstr(name, "audio"))
9821 if(player->audiosink_linked)
9823 debug_msg("Audio Sink already linked\n");
9827 if (strstr(name, "text"))
9829 if(player->textsink_linked)
9831 debug_msg("Text Sink already linked\n");
9836 gst_caps_unref( srccaps );
9841 //return (!player->videosink_linked || !player->audiosink_linked);
9845 gst_caps_unref( srccaps );
9851 /* sending event to one of sinkelements */
9853 __gst_send_event_to_sink( mm_player_t* player, GstEvent* event )
9855 GstEvent * event2 = NULL;
9856 GList *sinks = NULL;
9857 gboolean res = FALSE;
9861 return_val_if_fail( player, FALSE );
9862 return_val_if_fail ( event, FALSE );
9864 if ( player->play_subtitle && !player->use_textoverlay)
9865 event2 = gst_event_copy((const GstEvent *)event);
9867 sinks = player->sink_elements;
9870 GstElement *sink = GST_ELEMENT_CAST (sinks->data);
9872 if (GST_IS_ELEMENT(sink))
9874 /* keep ref to the event */
9875 gst_event_ref (event);
9877 if ( (res = gst_element_send_event (sink, event)) )
9879 debug_log("sending event[%s] to sink element [%s] success!\n",
9880 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink) );
9884 debug_log("sending event[%s] to sink element [%s] failed. try with next one.\n",
9885 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink) );
9888 sinks = g_list_next (sinks);
9891 /* Note : Textbin is not linked to the video or audio bin.
9892 * It needs to send the event to the text sink seperatelly.
9894 if ( player->play_subtitle && !player->use_textoverlay)
9896 GstElement *text_sink = GST_ELEMENT_CAST (player->pipeline->textbin[MMPLAYER_T_SINK].gst);
9898 if (GST_IS_ELEMENT(text_sink))
9900 /* keep ref to the event */
9901 gst_event_ref (event2);
9903 if ( (res != gst_element_send_event (text_sink, event2)) )
9905 debug_error("sending event[%s] to subtitle sink element [%s] failed!\n",
9906 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink) );
9910 debug_log("sending event[%s] to subtitle sink element [%s] success!\n",
9911 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink) );
9914 gst_event_unref (event2);
9918 gst_event_unref (event);
9926 __mmplayer_add_sink( mm_player_t* player, GstElement* sink )
9930 return_if_fail ( player );
9931 return_if_fail ( sink );
9933 player->sink_elements =
9934 g_list_append(player->sink_elements, sink);
9940 __mmplayer_del_sink( mm_player_t* player, GstElement* sink )
9944 return_if_fail ( player );
9945 return_if_fail ( sink );
9947 player->sink_elements =
9948 g_list_remove(player->sink_elements, sink);
9954 __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
9955 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
9956 gint64 cur, GstSeekType stop_type, gint64 stop )
9958 GstEvent* event = NULL;
9959 gboolean result = FALSE;
9963 return_val_if_fail( player, FALSE );
9965 event = gst_event_new_seek (rate, format, flags, cur_type,
9966 cur, stop_type, stop);
9968 result = __gst_send_event_to_sink( player, event );
9975 /* NOTE : be careful with calling this api. please refer to below glib comment
9976 * glib comment : Note that there is a bug in GObject that makes this function much
9977 * less useful than it might seem otherwise. Once gobject is disposed, the callback
9978 * will no longer be called, but, the signal handler is not currently disconnected.
9979 * If the instance is itself being freed at the same time than this doesn't matter,
9980 * since the signal will automatically be removed, but if instance persists,
9981 * then the signal handler will leak. You should not remove the signal yourself
9982 * because in a future versions of GObject, the handler will automatically be
9985 * It's possible to work around this problem in a way that will continue to work
9986 * with future versions of GObject by checking that the signal handler is still
9987 * connected before disconnected it:
9989 * if (g_signal_handler_is_connected (instance, id))
9990 * g_signal_handler_disconnect (instance, id);
9993 __mmplayer_release_signal_connection(mm_player_t* player)
9995 GList* sig_list = player->signals;
9996 MMPlayerSignalItem* item = NULL;
10000 return_if_fail( player );
10002 for ( ; sig_list; sig_list = sig_list->next )
10004 item = sig_list->data;
10006 if ( item && item->obj && GST_IS_ELEMENT(item->obj) )
10008 debug_log("checking signal connection : [%lud] from [%s]\n", item->sig, GST_OBJECT_NAME( item->obj ));
10010 if ( g_signal_handler_is_connected ( item->obj, item->sig ) )
10012 debug_log("signal disconnecting : [%lud] from [%s]\n", item->sig, GST_OBJECT_NAME( item->obj ));
10013 g_signal_handler_disconnect ( item->obj, item->sig );
10017 MMPLAYER_FREEIF( item );
10020 g_list_free ( player->signals );
10021 player->signals = NULL;
10029 /* Note : if silent is true, then subtitle would not be displayed. :*/
10030 int _mmplayer_set_subtitle_silent (MMHandleType hplayer, int silent)
10032 mm_player_t* player = (mm_player_t*) hplayer;
10036 /* check player handle */
10037 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED );
10039 player->is_subtitle_off = silent;
10041 debug_log("subtitle is %s.\n", player->is_subtitle_off ? "ON" : "OFF");
10045 return MM_ERROR_NONE;
10049 int _mmplayer_get_subtitle_silent (MMHandleType hplayer, int* silent)
10051 mm_player_t* player = (mm_player_t*) hplayer;
10055 /* check player handle */
10056 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED );
10058 *silent = player->is_subtitle_off;
10060 debug_log("subtitle is %s.\n", silent ? "ON" : "OFF");
10064 return MM_ERROR_NONE;
10067 int _mmplayer_get_track_count(MMHandleType hplayer, MMPlayerTrackType track_type, int *count)
10069 mm_player_t* player = (mm_player_t*) hplayer;
10070 MMHandleType attrs = 0;
10071 int ret = MM_ERROR_NONE;
10075 /* check player handle */
10076 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10077 return_val_if_fail(count, MM_ERROR_COMMON_INVALID_ARGUMENT);
10078 return_val_if_fail((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
10079 ||(MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING),
10080 MM_ERROR_PLAYER_INVALID_STATE);
10082 attrs = MMPLAYER_GET_ATTRS(player);
10085 debug_error("cannot get content attribute");
10086 return MM_ERROR_PLAYER_INTERNAL;
10089 switch (track_type)
10091 case MM_PLAYER_TRACK_TYPE_AUDIO:
10092 ret = mm_attrs_get_int_by_name(attrs, "content_audio_track_num", count);
10094 case MM_PLAYER_TRACK_TYPE_VIDEO:
10095 ret = mm_attrs_get_int_by_name(attrs, "content_video_track_num", count);
10097 case MM_PLAYER_TRACK_TYPE_TEXT:
10098 ret = mm_attrs_get_int_by_name(attrs, "content_text_track_num", count);
10101 ret = MM_ERROR_COMMON_INVALID_ARGUMENT;
10105 debug_log ("%d track num is %d\n", track_type, *count);
10115 __get_state_name ( int state )
10119 case MM_PLAYER_STATE_NULL:
10121 case MM_PLAYER_STATE_READY:
10123 case MM_PLAYER_STATE_PAUSED:
10125 case MM_PLAYER_STATE_PLAYING:
10127 case MM_PLAYER_STATE_NONE:
10134 __is_rtsp_streaming ( mm_player_t* player )
10136 return_val_if_fail ( player, FALSE );
10138 return ( player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_RTSP ) ? TRUE : FALSE;
10142 __is_http_streaming ( mm_player_t* player )
10144 return_val_if_fail ( player, FALSE );
10146 return ( player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_HTTP ) ? TRUE : FALSE;
10150 __is_streaming ( mm_player_t* player )
10152 return_val_if_fail ( player, FALSE );
10154 return ( __is_rtsp_streaming ( player ) || __is_http_streaming ( player ) || __is_http_live_streaming ( player )) ? TRUE : FALSE;
10158 __is_live_streaming ( mm_player_t* player )
10160 return_val_if_fail ( player, FALSE );
10162 return ( __is_rtsp_streaming ( player ) && player->streaming_type == STREAMING_SERVICE_LIVE ) ? TRUE : FALSE;
10166 __is_http_live_streaming( mm_player_t* player )
10168 return_val_if_fail( player, FALSE );
10170 return ( player->profile.uri_type == MM_PLAYER_URI_TYPE_HLS ) ? TRUE : FALSE;
10174 __is_http_progressive_down(mm_player_t* player)
10176 return_val_if_fail( player, FALSE );
10178 return ((player->pd_mode) ? TRUE:FALSE);