4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <gst/app/gstappsrc.h>
31 #include <gst/interfaces/xoverlay.h>
39 #include <mm_attrs_private.h>
42 #include "mm_player_priv.h"
43 #include "mm_player_ini.h"
44 #include "mm_player_attrs.h"
45 #include "mm_player_capture.h"
47 /*===========================================================================================
49 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
51 ========================================================================================== */
53 /*---------------------------------------------------------------------------
54 | GLOBAL CONSTANT DEFINITIONS: |
55 ---------------------------------------------------------------------------*/
57 /*---------------------------------------------------------------------------
58 | IMPORTED VARIABLE DECLARATIONS: |
59 ---------------------------------------------------------------------------*/
61 /*---------------------------------------------------------------------------
62 | IMPORTED FUNCTION DECLARATIONS: |
63 ---------------------------------------------------------------------------*/
65 /*---------------------------------------------------------------------------
67 ---------------------------------------------------------------------------*/
68 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
69 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
71 #define MM_VOLUME_FACTOR_DEFAULT 1.0
72 #define MM_VOLUME_FACTOR_MIN 0
73 #define MM_VOLUME_FACTOR_MAX 1.0
75 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 700000 // 700 msec
77 #define MM_PLAYER_MPEG_VNAME "mpegversion"
78 #define MM_PLAYER_DIVX_VNAME "divxversion"
79 #define MM_PLAYER_WMV_VNAME "wmvversion"
80 #define MM_PLAYER_WMA_VNAME "wmaversion"
82 #define DEFAULT_PLAYBACK_RATE 1.0
84 #define GST_QUEUE_DEFAULT_TIME 2
85 #define GST_QUEUE_HLS_TIME 8
87 /* video capture callback*/
88 gulong ahs_appsrc_cb_probe_id = 0;
90 #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 MMPLAYER_PLAY_SUBTITLE(player) ((player)->play_subtitle)
93 #define LAZY_PAUSE_TIMEOUT_MSEC 700
95 /*---------------------------------------------------------------------------
96 | LOCAL CONSTANT DEFINITIONS: |
97 ---------------------------------------------------------------------------*/
99 /*---------------------------------------------------------------------------
100 | LOCAL DATA TYPE DEFINITIONS: |
101 ---------------------------------------------------------------------------*/
103 /*---------------------------------------------------------------------------
104 | GLOBAL VARIABLE DEFINITIONS: |
105 ---------------------------------------------------------------------------*/
107 /*---------------------------------------------------------------------------
108 | LOCAL VARIABLE DEFINITIONS: |
109 ---------------------------------------------------------------------------*/
111 /*---------------------------------------------------------------------------
112 | LOCAL FUNCTION PROTOTYPES: |
113 ---------------------------------------------------------------------------*/
114 static gboolean __mmplayer_set_state(mm_player_t* player, int state);
115 static int __mmplayer_get_state(mm_player_t* player);
116 static int __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps *caps);
117 static int __mmplayer_gst_create_audio_pipeline(mm_player_t* player);
118 static int __mmplayer_gst_create_text_pipeline(mm_player_t* player);
119 static int __mmplayer_gst_create_subtitle_pipeline(mm_player_t* player);
120 static int __mmplayer_gst_create_pipeline(mm_player_t* player);
121 static int __mmplayer_gst_destroy_pipeline(mm_player_t* player);
122 static int __mmplayer_gst_element_link_bucket(GList* element_bucket);
124 static gboolean __mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data);
125 static void __mmplayer_gst_decode_callback(GstElement *decodebin, GstPad *pad, gboolean last, gpointer data);
127 static void __mmplayer_typefind_have_type( GstElement *tf, guint probability, GstCaps *caps, gpointer data);
128 static gboolean __mmplayer_try_to_plug(mm_player_t* player, GstPad *pad, const GstCaps *caps);
129 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
130 static gboolean __mmplayer_is_midi_type(gchar* str_caps);
131 static gboolean __mmplayer_is_amr_type (gchar *str_caps);
132 static gboolean __mmplayer_is_only_mp3_type (gchar *str_caps);
134 static gboolean __mmplayer_close_link(mm_player_t* player, GstPad *srcpad, GstElement *sinkelement, const char *padname, const GList *templlist);
135 static gboolean __mmplayer_feature_filter(GstPluginFeature *feature, gpointer data);
136 static void __mmplayer_add_new_pad(GstElement *element, GstPad *pad, gpointer data);
138 static void __mmplayer_gst_rtp_no_more_pads (GstElement *element, gpointer data);
139 static void __mmplayer_gst_rtp_dynamic_pad (GstElement *element, GstPad *pad, gpointer data);
140 static gboolean __mmplayer_update_stream_service_type( mm_player_t* player );
141 static gboolean __mmplayer_update_subtitle( GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
144 static void __mmplayer_init_factories(mm_player_t* player);
145 static void __mmplayer_release_factories(mm_player_t* player);
146 static void __mmplayer_release_misc(mm_player_t* player);
147 static gboolean __mmplayer_gstreamer_init(void);
149 static int __mmplayer_gst_set_state (mm_player_t* player, GstElement * pipeline, GstState state, gboolean async, gint timeout );
150 gboolean __mmplayer_post_message(mm_player_t* player, enum MMMessageType msgtype, MMMessageParamType* param);
151 static gboolean __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage *msg);
152 int __mmplayer_switch_audio_sink (mm_player_t* player);
153 static gboolean __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink);
154 static int __mmplayer_check_state(mm_player_t* player, enum PlayerCommandState command);
155 static gboolean __mmplayer_audio_stream_probe (GstPad *pad, GstBuffer *buffer, gpointer u_data);
157 static gboolean __mmplayer_dump_pipeline_state( mm_player_t* player );
158 static gboolean __mmplayer_check_subtitle( mm_player_t* player );
159 static gboolean __mmplayer_handle_gst_error ( mm_player_t* player, GstMessage * message, GError* error );
160 static gboolean __mmplayer_handle_streaming_error ( mm_player_t* player, GstMessage * message );
161 static void __mmplayer_post_delayed_eos( mm_player_t* player, int delay_in_ms );
162 static void __mmplayer_cancel_delayed_eos( mm_player_t* player );
163 static gboolean __mmplayer_eos_timer_cb(gpointer u_data);
164 static gboolean __mmplayer_link_decoder( mm_player_t* player,GstPad *srcpad);
165 static gboolean __mmplayer_link_sink( mm_player_t* player,GstPad *srcpad);
166 static int __mmplayer_post_missed_plugin(mm_player_t* player);
167 static int __mmplayer_check_not_supported_codec(mm_player_t* player, gchar* mime);
168 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player);
169 static void __mmplayer_add_sink( mm_player_t* player, GstElement* sink);
170 static void __mmplayer_release_signal_connection(mm_player_t* player);
171 static void __mmplayer_set_antishock( mm_player_t* player, gboolean disable_by_force);
172 static gpointer __mmplayer_repeat_thread(gpointer data);
173 int _mmplayer_get_track_count(MMHandleType hplayer, MMPlayerTrackType track_type, int *count);
175 static int __gst_realize(mm_player_t* player);
176 static int __gst_unrealize(mm_player_t* player);
177 static int __gst_start(mm_player_t* player);
178 static int __gst_stop(mm_player_t* player);
179 int __gst_pause(mm_player_t* player, gboolean async);
180 int __gst_resume(mm_player_t* player, gboolean async);
181 static gboolean __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
182 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
183 gint64 cur, GstSeekType stop_type, gint64 stop );
184 static int __gst_pending_seek ( mm_player_t* player );
186 static int __gst_set_position(mm_player_t* player, int format, unsigned long position);
187 static int __gst_get_position(mm_player_t* player, int format, unsigned long *position);
188 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos);
189 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position);
190 static int __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param);
191 static void __gst_set_async_state_change(mm_player_t* player, gboolean async);
193 static gint __gst_handle_core_error( mm_player_t* player, int code );
194 static gint __gst_handle_library_error( mm_player_t* player, int code );
195 static gint __gst_handle_resource_error( mm_player_t* player, int code );
196 static gint __gst_handle_stream_error( mm_player_t* player, GError* error, GstMessage * message );
197 static gint __gst_transform_gsterror( mm_player_t* player, GstMessage * message, GError* error);
198 static gboolean __gst_send_event_to_sink( mm_player_t* player, GstEvent* event );
200 static int __mmplayer_get_video_frame_from_buffer(mm_player_t* player, GstBuffer *buffer);
201 static int __mmplayer_set_pcm_extraction(mm_player_t* player);
202 static gboolean __mmplayer_can_extract_pcm( mm_player_t* player );
205 static void __mmplayer_do_sound_fadedown(mm_player_t* player, unsigned int time);
206 static void __mmplayer_undo_sound_fadedown(mm_player_t* player);
208 static void __mmplayer_add_new_caps(GstPad* pad, GParamSpec* unused, gpointer data);
209 static void __mmplayer_set_unlinked_mime_type(mm_player_t* player, GstCaps *caps);
210 static void __mmplayer_set_videosink_type(mm_player_t* player);
213 const gchar * __get_state_name ( int state );
214 static gboolean __is_streaming( mm_player_t* player );
215 static gboolean __is_rtsp_streaming( mm_player_t* player );
216 static gboolean __is_live_streaming ( mm_player_t* player );
217 static gboolean __is_http_streaming( mm_player_t* player );
218 static gboolean __is_http_live_streaming( mm_player_t* player );
219 static gboolean __is_http_progressive_down(mm_player_t* player);
221 static gboolean __mmplayer_warm_up_video_codec( mm_player_t* player, GstElementFactory *factory);
222 static GstBusSyncReply __mmplayer_bus_sync_callback (GstBus * bus, GstMessage * message, gpointer data);
224 /*===========================================================================================
226 | FUNCTION DEFINITIONS |
228 ========================================================================================== */
230 /* implementing player FSM */
231 /* FIXIT : We need to handle state transition also at here since start api is no more sync */
233 __mmplayer_check_state(mm_player_t* player, enum PlayerCommandState command)
235 MMPlayerStateType current_state = MM_PLAYER_STATE_NUM;
236 MMPlayerStateType pending_state = MM_PLAYER_STATE_NUM;
237 MMPlayerStateType target_state = MM_PLAYER_STATE_NUM;
238 MMPlayerStateType prev_state = MM_PLAYER_STATE_NUM;
242 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
244 current_state = MMPLAYER_CURRENT_STATE(player);
245 pending_state = MMPLAYER_PENDING_STATE(player);
246 target_state = MMPLAYER_TARGET_STATE(player);
247 prev_state = MMPLAYER_PREV_STATE(player);
249 MMPLAYER_PRINT_STATE(player);
251 debug_log("incomming command : %d", command );
255 case MMPLAYER_COMMAND_CREATE:
257 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
259 if ( current_state == MM_PLAYER_STATE_NULL ||
260 current_state == MM_PLAYER_STATE_READY ||
261 current_state == MM_PLAYER_STATE_PAUSED ||
262 current_state == MM_PLAYER_STATE_PLAYING )
267 case MMPLAYER_COMMAND_DESTROY:
269 /* destroy can called anytime */
271 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
275 case MMPLAYER_COMMAND_REALIZE:
277 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
279 if ( pending_state != MM_PLAYER_STATE_NONE )
285 /* need ready state to realize */
286 if ( current_state == MM_PLAYER_STATE_READY )
289 if ( current_state != MM_PLAYER_STATE_NULL )
295 case MMPLAYER_COMMAND_UNREALIZE:
297 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
299 if ( current_state == MM_PLAYER_STATE_NULL )
304 case MMPLAYER_COMMAND_START:
306 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
308 if ( pending_state == MM_PLAYER_STATE_NONE )
310 if ( current_state == MM_PLAYER_STATE_PLAYING )
312 else if ( current_state != MM_PLAYER_STATE_READY &&
313 current_state != MM_PLAYER_STATE_PAUSED )
316 else if ( pending_state == MM_PLAYER_STATE_PLAYING )
320 else if ( pending_state == MM_PLAYER_STATE_PAUSED )
322 debug_log("player is going to paused state, just change the pending state as playing");
331 case MMPLAYER_COMMAND_STOP:
333 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
335 if ( current_state == MM_PLAYER_STATE_READY )
338 /* need playing/paused state to stop */
339 if ( current_state != MM_PLAYER_STATE_PLAYING &&
340 current_state != MM_PLAYER_STATE_PAUSED )
345 case MMPLAYER_COMMAND_PAUSE:
347 if ( MMPLAYER_IS_LIVE_STREAMING( player ) )
350 if (player->doing_seek)
351 goto NOT_COMPLETED_SEEK;
353 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
355 if ( pending_state == MM_PLAYER_STATE_NONE )
357 if ( current_state == MM_PLAYER_STATE_PAUSED )
359 else if ( current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY ) // support loading state of broswer
362 else if ( pending_state == MM_PLAYER_STATE_PAUSED )
366 else if ( pending_state == MM_PLAYER_STATE_PLAYING )
368 if ( current_state == MM_PLAYER_STATE_PAUSED ) {
369 debug_log("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
377 case MMPLAYER_COMMAND_RESUME:
379 if ( MMPLAYER_IS_LIVE_STREAMING(player) )
382 if (player->doing_seek)
383 goto NOT_COMPLETED_SEEK;
385 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
387 if ( pending_state == MM_PLAYER_STATE_NONE )
389 if ( current_state == MM_PLAYER_STATE_PLAYING )
391 else if ( current_state != MM_PLAYER_STATE_PAUSED )
394 else if ( pending_state == MM_PLAYER_STATE_PLAYING )
398 else if ( pending_state == MM_PLAYER_STATE_PAUSED )
400 debug_log("player is going to paused state, just change the pending state as playing");
413 debug_log("status OK\n");
414 player->cmd = command;
417 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 return MM_ERROR_PLAYER_DOING_SEEK;
429 debug_warning("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
430 return MM_ERROR_PLAYER_NO_OP;
433 debug_warning("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
434 return MM_ERROR_PLAYER_NO_OP;
438 __mmplayer_gst_set_state (mm_player_t* player, GstElement * element, GstState state, gboolean async, gint timeout) // @
440 GstState element_state = GST_STATE_VOID_PENDING;
441 GstState element_pending_state = GST_STATE_VOID_PENDING;
442 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
446 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
447 return_val_if_fail ( element, MM_ERROR_INVALID_ARGUMENT );
449 debug_log("setting [%s] state to : %d\n", GST_ELEMENT_NAME(element), state);
452 ret = gst_element_set_state(element, state);
454 if ( ret == GST_STATE_CHANGE_FAILURE )
456 debug_error("failed to set [%s] state to [%d]\n", GST_ELEMENT_NAME(element), state);
457 return MM_ERROR_PLAYER_INTERNAL;
460 /* return here so state transition to be done in async mode */
463 debug_log("async state transition. not waiting for state complete.\n");
464 return MM_ERROR_NONE;
467 /* wait for state transition */
468 ret = gst_element_get_state( element, &element_state, &element_pending_state, timeout * GST_SECOND );
470 if ( ret == GST_STATE_CHANGE_FAILURE || ( state != element_state ) )
472 debug_error("failed to change [%s] state to [%s] within %d sec\n",
473 GST_ELEMENT_NAME(element),
474 gst_element_state_get_name(state), timeout );
476 debug_error(" [%s] state : %s pending : %s \n",
477 GST_ELEMENT_NAME(element),
478 gst_element_state_get_name(element_state),
479 gst_element_state_get_name(element_pending_state) );
481 return MM_ERROR_PLAYER_INTERNAL;
484 debug_log("[%s] state has changed to %s \n",
485 GST_ELEMENT_NAME(element),
486 gst_element_state_get_name(element_state));
490 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 );
503 if (player->video_stream_cb )
505 length = width * height * 4; // for rgb 32bit
506 player->video_stream_cb(stream, length, player->video_stream_cb_user_param, width, height);
511 _mmplayer_update_content_attrs(mm_player_t* player) // @
513 GstFormat fmt = GST_FORMAT_TIME;
515 GstStructure* p = NULL;
516 MMHandleType attrs = 0;
517 gint retry_count = 0;
518 gint retry_count_max = 10;
522 return_val_if_fail ( player, FALSE );
524 if ( ! player->need_update_content_attrs )
526 debug_log("content attributes are already updated");
530 /* get content attribute first */
531 attrs = MMPLAYER_GET_ATTRS(player);
534 debug_error("cannot get content attribute");
539 * NOTE : we need to wait for a while until is possible to get duration from pipeline
540 * as getting duration timing is depends on behavier of demuxers ( or etc ).
541 * we set timeout 100ms * 10 as initial value. fix it if needed.
543 if ( player->need_update_content_dur )
545 while ( retry_count < retry_count_max)
547 if ( FALSE == gst_element_query_duration( player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
550 /* retry if failed */
551 debug_warning("failed to get duraton. waiting 100ms and then retrying...");
557 if ( dur_nsec == 0 && ( !MMPLAYER_IS_LIVE_STREAMING( player ) ) )
559 /* retry if duration is zero in case of not live stream */
560 debug_warning("returned duration is zero. but it's not an live stream. retrying...");
569 player->duration = dur_nsec;
570 debug_log("duration : %lld msec", GST_TIME_AS_MSECONDS(dur_nsec));
572 /* try to get streaming service type */
573 __mmplayer_update_stream_service_type( player );
575 /* check duration is OK */
576 if ( dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING( player ) )
578 /* FIXIT : find another way to get duration here. */
579 debug_error("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
583 player->need_update_content_dur = FALSE;
587 mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(dur_nsec));
591 debug_log("no ready to get or content duration already updated");
594 /* update rate, channels */
595 if ( player->pipeline->audiobin &&
596 player->pipeline->audiobin[MMPLAYER_A_SINK].gst )
598 GstCaps *caps_a = NULL;
600 gint samplerate = 0, channels = 0;
602 pad = gst_element_get_static_pad(
603 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink" );
607 caps_a = gst_pad_get_negotiated_caps( pad );
611 p = gst_caps_get_structure (caps_a, 0);
613 gst_structure_get_int (p, "rate", &samplerate);
614 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
616 gst_structure_get_int (p, "channels", &channels);
617 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
618 gst_caps_unref( caps_a );
621 debug_log("samplerate : %d channels : %d", samplerate, channels);
625 debug_warning("not ready to get audio caps");
628 gst_object_unref( pad );
632 debug_warning("failed to get pad from audiosink");
636 /* update width, height, framerate */
637 if ( player->pipeline->videobin &&
638 player->pipeline->videobin[MMPLAYER_V_SINK].gst )
640 GstCaps *caps_v = NULL;
645 if (player->use_multi_surface)
647 /* NOTE : if v_stream_caps were deprecated, it might be implemented by using "pad-added" signal callback */
648 if (player->v_stream_caps)
650 caps_v = player->v_stream_caps;
651 p = gst_caps_get_structure (caps_v, 0);
652 gst_structure_get_int (p, "width", &width);
653 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
655 gst_structure_get_int (p, "height", &height);
656 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
658 gst_structure_get_fraction (p, "framerate", &tmpNu, &tmpDe);
660 debug_log("width : %d height : %d", width, height );
664 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
665 debug_log("fps : %d", tmpNu / tmpDe);
670 debug_warning("failed to get caps from v_stream_caps when using multi-surface");
675 pad = gst_element_get_static_pad( player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink" );
678 caps_v = gst_pad_get_negotiated_caps( pad );
681 p = gst_caps_get_structure (caps_v, 0);
682 gst_structure_get_int (p, "width", &width);
683 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
685 gst_structure_get_int (p, "height", &height);
686 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
688 gst_structure_get_fraction (p, "framerate", &tmpNu, &tmpDe);
690 debug_log("width : %d height : %d", width, height );
692 gst_caps_unref( caps_v );
697 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
698 debug_log("fps : %d", tmpNu / tmpDe);
703 debug_warning("failed to get negitiated caps from videosink");
705 if (!player->use_multi_surface)
707 gst_object_unref( pad );
713 debug_warning("failed to get pad from videosink");
718 if (player->duration)
720 guint64 data_size = 0;
722 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO))
724 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
726 if (stat(path, &sb) == 0)
728 data_size = (guint64)sb.st_size;
731 else if (MMPLAYER_IS_HTTP_STREAMING(player))
733 data_size = player->http_content_size;
739 guint64 msec_dur = 0;
741 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
742 bitrate = data_size * 8 * 1000 / msec_dur;
743 debug_log("file size : %u, video bitrate = %llu", data_size, bitrate);
744 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
750 if ( mmf_attrs_commit ( attrs ) )
752 debug_error("failed to update attributes\n");
756 player->need_update_content_attrs = FALSE;
761 gboolean __mmplayer_update_stream_service_type( mm_player_t* player )
763 MMHandleType attrs = 0;
764 gint streaming_type = STREAMING_SERVICE_NONE;
768 return_val_if_fail ( player &&
770 player->pipeline->mainbin &&
771 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
774 /* streaming service type if streaming */
775 if ( ! MMPLAYER_IS_STREAMING(player) );
778 if (MMPLAYER_IS_RTSP_STREAMING(player))
780 /* get property from rtspsrc element */
781 g_object_get(G_OBJECT(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), "service_type", &streaming_type, NULL);
783 else if (MMPLAYER_IS_HTTP_STREAMING(player))
785 if ( player->duration <= 0)
786 streaming_type = STREAMING_SERVICE_LIVE;
788 streaming_type = STREAMING_SERVICE_VOD;
791 player->streaming_type = streaming_type;
793 if ( player->streaming_type == STREAMING_SERVICE_LIVE)
795 debug_log("It's live streaming. pause/resume/seek are not working.\n");
797 else if (player->streaming_type == STREAMING_SERVICE_LIVE)
799 debug_log("It's vod streaming. pause/resume/seek are working.\n");
803 debug_warning("fail to determine streaming type. pause/resume/seek may not working properly if stream is live stream\n");
806 /* get profile attribute */
807 attrs = MMPLAYER_GET_ATTRS(player);
810 debug_error("cannot get content attribute\n");
814 mm_attrs_set_int_by_name ( attrs, "streaming_type", streaming_type );
816 if ( mmf_attrs_commit ( attrs ) )
818 debug_warning("updating streaming service type failed. pause/resume/seek may not working properly if stream is live stream\n");
828 /* this function sets the player state and also report
829 * it to applicaton by calling callback function
832 __mmplayer_set_state(mm_player_t* player, int state) // @
834 MMMessageParamType msg = {0, };
835 int asm_result = MM_ERROR_NONE;
836 int new_state = state;
840 return_val_if_fail ( player, FALSE );
842 if ( MMPLAYER_CURRENT_STATE(player) == new_state )
844 debug_warning("already same state(%s)\n", MMPLAYER_STATE_GET_NAME(state));
848 /* update player states */
849 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
850 MMPLAYER_CURRENT_STATE(player) = new_state;
851 if ( MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player) )
852 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
855 MMPLAYER_PRINT_STATE(player);
857 /* post message to application */
858 if (MMPLAYER_TARGET_STATE(player) == new_state)
860 /* fill the message with state of player */
861 msg.state.previous = MMPLAYER_PREV_STATE(player);
862 msg.state.current = MMPLAYER_CURRENT_STATE(player);
864 /* state changed by asm callback */
865 if ( player->sm.by_asm_cb )
867 msg.union_type = MM_MSG_UNION_CODE;
868 msg.code = player->sm.event_src;
869 MMPLAYER_POST_MSG( player, MM_MESSAGE_STATE_INTERRUPTED, &msg );
871 /* state changed by usecase */
874 MMPLAYER_POST_MSG( player, MM_MESSAGE_STATE_CHANGED, &msg );
877 debug_log ("player reach the target state, then do something in each state(%s).\n",
878 MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
882 debug_log ("intermediate state, do nothing.\n");
886 switch ( MMPLAYER_TARGET_STATE(player) )
888 case MM_PLAYER_STATE_NULL:
889 case MM_PLAYER_STATE_READY:
891 if (player->cmd == MMPLAYER_COMMAND_STOP)
893 asm_result = _mmplayer_asm_set_state((MMHandleType)player, ASM_STATE_STOP);
894 if ( asm_result != MM_ERROR_NONE )
896 debug_error("failed to set asm state to stop\n");
903 case MM_PLAYER_STATE_PAUSED:
905 /* special care for local playback. normaly we can get some content attribute
906 * when the demuxer is changed to PAUSED. so we are trying it. it will be tried again
907 * when PLAYING state has signalled if failed.
908 * note that this is only happening pause command has come before the state of pipeline
909 * reach to the PLAYING.
911 _mmplayer_update_content_attrs( player );
913 /* add audio callback probe if condition is satisfied */
914 if ( ! player->audio_cb_probe_id && player->is_sound_extraction )
915 __mmplayer_configure_audio_callback(player);
917 asm_result = _mmplayer_asm_set_state((MMHandleType)player, ASM_STATE_PAUSE);
920 debug_error("failed to set asm state to PAUSE\n");
926 case MM_PLAYER_STATE_PLAYING:
928 /* update attributes which are only available on playing status */
929 player->need_update_content_attrs = TRUE;
930 _mmplayer_update_content_attrs ( player );
932 if ( player->cmd == MMPLAYER_COMMAND_START && !player->sent_bos )
934 __mmplayer_post_missed_plugin ( player );
936 /* update video resource status */
937 if ( ( player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO )
939 asm_result = _mmplayer_asm_set_state((MMHandleType)player, ASM_STATE_PLAYING);
942 MMMessageParamType msg = {0, };
944 debug_error("failed to go ahead because of video conflict\n");
946 msg.union_type = MM_MSG_UNION_CODE;
947 msg.code = MM_ERROR_POLICY_INTERRUPTED;
948 MMPLAYER_POST_MSG( player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
950 _mmplayer_unrealize((MMHandleType)player);
957 if ( player->resumed_by_rewind && player->playback_rate < 0.0 )
959 /* initialize because auto resume is done well. */
960 player->resumed_by_rewind = FALSE;
961 player->playback_rate = 1.0;
964 if ( !player->sent_bos )
966 /* check audio codec field is set or not
967 * we can get it from typefinder or codec's caps.
969 gchar *audio_codec = NULL;
970 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
972 /* The codec format can't be sent for audio only case like amr, mid etc.
973 * Because, parser don't make related TAG.
974 * So, if it's not set yet, fill it with found data.
978 if ( g_strrstr(player->type, "audio/midi"))
980 audio_codec = g_strdup("MIDI");
983 else if ( g_strrstr(player->type, "audio/x-amr"))
985 audio_codec = g_strdup("AMR");
987 else if ( g_strrstr(player->type, "audio/mpeg") && !g_strrstr(player->type, "mpegversion=(int)1"))
989 audio_codec = g_strdup("AAC");
993 audio_codec = g_strdup("unknown");
995 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
997 MMPLAYER_FREEIF(audio_codec);
998 mmf_attrs_commit(player->attrs);
999 debug_log("set audio codec type with caps\n");
1002 MMTA_ACUM_ITEM_END("[KPI] start media player service", FALSE);
1003 MMTA_ACUM_ITEM_END("[KPI] media player service create->playing", FALSE);
1005 MMPLAYER_POST_MSG ( player, MM_MESSAGE_BEGIN_OF_STREAM, NULL );
1006 player->sent_bos = TRUE;
1011 case MM_PLAYER_STATE_NONE:
1013 debug_warning("invalid target state, there is nothing to do.\n");
1024 __mmplayer_post_message(mm_player_t* player, enum MMMessageType msgtype, MMMessageParamType* param) // @
1026 return_val_if_fail( player, FALSE );
1030 if ( !player->msg_cb )
1032 debug_warning("no msg callback. can't post\n");
1036 //debug_log("Message (type : %d) will be posted using msg-cb(%p). \n", msgtype, player->msg_cb);
1038 player->msg_cb(msgtype, param, player->msg_cb_param);
1047 __mmplayer_get_state(mm_player_t* player) // @
1049 int state = MM_PLAYER_STATE_NONE;
1053 return_val_if_fail ( player, MM_PLAYER_STATE_NONE );
1055 state = MMPLAYER_CURRENT_STATE(player);
1057 debug_log("player state is %s.\n", MMPLAYER_STATE_GET_NAME(state));
1065 __gst_set_async_state_change(mm_player_t* player, gboolean async)
1069 return_if_fail( player && player->pipeline && player->pipeline->mainbin );
1071 /* need only when we are using decodebin */
1072 if ( ! PLAYER_INI()->use_decodebin )
1076 if ( player->pipeline->audiobin &&
1077 player->pipeline->audiobin[MMPLAYER_A_SINK].gst )
1079 debug_log("audiosink async : %d\n", async);
1080 g_object_set (G_OBJECT (player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "async", async, NULL);
1084 if ( player->pipeline->videobin &&
1085 player->pipeline->videobin[MMPLAYER_V_SINK].gst )
1087 debug_log("videosink async : %d\n", async);
1088 g_object_set (G_OBJECT (player->pipeline->videobin[MMPLAYER_V_SINK].gst), "async", async, NULL);
1091 /* decodebin if enabled */
1092 if ( PLAYER_INI()->use_decodebin )
1094 debug_log("decodebin async : %d\n", async);
1095 g_object_set (G_OBJECT (player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst), "async-handling", async, NULL);
1101 static gpointer __mmplayer_repeat_thread(gpointer data)
1103 mm_player_t* player = (mm_player_t*) data;
1104 gboolean ret_value = FALSE;
1105 MMHandleType attrs = 0;
1108 return_val_if_fail ( player, NULL );
1110 while ( ! player->repeat_thread_exit )
1112 debug_log("repeat thread started. waiting for signal.\n");
1113 g_cond_wait( player->repeat_thread_cond, player->repeat_thread_mutex );
1115 if ( player->repeat_thread_exit )
1117 debug_log("exiting repeat thread\n");
1122 MMPLAYER_CMD_LOCK( player );
1124 return_val_if_fail( player, NULL );
1126 attrs = MMPLAYER_GET_ATTRS(player);
1128 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
1130 debug_error("can not get play count\n");
1134 if ( player->section_repeat )
1136 ret_value = _mmplayer_activate_section_repeat((MMHandleType)player, player->section_repeat_start, player->section_repeat_end);
1140 if ( player->playback_rate < 0.0 )
1142 player->resumed_by_rewind = TRUE;
1143 _mmplayer_set_mute((MMHandleType)player, 0);
1144 MMPLAYER_POST_MSG( player, MM_MESSAGE_RESUMED_BY_REW, NULL );
1147 ret_value = __gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
1148 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET,
1149 0, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
1152 player->sent_bos = FALSE;
1157 debug_error("failed to set position to zero for rewind\n");
1161 /* decrease play count */
1164 /* we successeded to rewind. update play count and then wait for next EOS */
1167 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
1169 /* commit attribute */
1170 if ( mmf_attrs_commit ( attrs ) )
1172 debug_error("failed to commit attribute\n");
1177 MMPLAYER_CMD_UNLOCK( player );
1184 __mmplayer_handle_buffering_message ( mm_player_t* player )
1186 MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
1187 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
1188 MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
1189 MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
1191 return_if_fail ( player );
1193 prev_state = MMPLAYER_PREV_STATE(player),
1194 current_state = MMPLAYER_CURRENT_STATE(player);
1195 target_state = MMPLAYER_TARGET_STATE(player);
1196 pending_state = MMPLAYER_PENDING_STATE(player);
1198 if ( !player->streamer->is_buffering )
1200 debug_log( "player state : prev %s, current %s, pending %s, target %s \n",
1201 MMPLAYER_STATE_GET_NAME(prev_state),
1202 MMPLAYER_STATE_GET_NAME(current_state),
1203 MMPLAYER_STATE_GET_NAME(pending_state),
1204 MMPLAYER_STATE_GET_NAME(target_state));
1206 /* NOTE : if buffering has done, player has to go to target state. */
1207 switch ( target_state )
1209 case MM_PLAYER_STATE_PAUSED :
1211 if ( MMPLAYER_IS_RTSP_STREAMING(player) )
1214 switch ( pending_state )
1216 case MM_PLAYER_STATE_PLAYING:
1218 __gst_pause ( player, TRUE );
1222 case MM_PLAYER_STATE_PAUSED:
1224 debug_log("player is already going to paused state, there is nothing to do.\n");
1228 case MM_PLAYER_STATE_NONE:
1229 case MM_PLAYER_STATE_NULL:
1230 case MM_PLAYER_STATE_READY:
1233 debug_warning("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state) );
1240 case MM_PLAYER_STATE_PLAYING :
1242 if ( MMPLAYER_IS_RTSP_STREAMING(player) )
1244 __gst_resume ( player, TRUE );
1246 /* now we can overcome 'state-lost' situation */
1247 player->state_lost = FALSE;
1252 switch ( pending_state )
1254 case MM_PLAYER_STATE_NONE:
1256 if (current_state != MM_PLAYER_STATE_PLAYING)
1257 __gst_resume ( player, TRUE );
1261 case MM_PLAYER_STATE_PAUSED:
1263 __gst_resume ( player, TRUE );
1267 case MM_PLAYER_STATE_PLAYING:
1269 debug_log("player is already going to playing state, there is nothing to do.\n");
1273 case MM_PLAYER_STATE_NULL:
1274 case MM_PLAYER_STATE_READY:
1277 debug_warning("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state) );
1284 case MM_PLAYER_STATE_NULL :
1285 case MM_PLAYER_STATE_READY :
1286 case MM_PLAYER_STATE_NONE :
1289 debug_warning("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state) );
1296 /* NOTE : in case of rtsp streaming, the src plugin provide the pipeline clock.
1297 * the src plugin is buffering, the pipeline clock stop automatically.
1298 * so don't need to pause the player.
1300 if ( MMPLAYER_IS_RTSP_STREAMING(player) )
1302 player->state_lost = TRUE;
1306 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1307 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
1309 switch ( pending_state )
1311 case MM_PLAYER_STATE_NONE:
1313 if (current_state != MM_PLAYER_STATE_PAUSED)
1314 __gst_pause ( player, TRUE );
1318 case MM_PLAYER_STATE_PLAYING:
1320 __gst_pause ( player, TRUE );
1324 case MM_PLAYER_STATE_PAUSED:
1326 debug_log("player is already going to paused state, there is nothing to do.\n");
1330 case MM_PLAYER_STATE_NULL:
1331 case MM_PLAYER_STATE_READY:
1334 debug_warning("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state) );
1342 __mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data) // @
1344 mm_player_t* player = (mm_player_t*) data;
1345 gboolean ret = TRUE;
1346 static gboolean async_done = FALSE;
1348 return_val_if_fail ( player, FALSE );
1349 return_val_if_fail ( msg && GST_IS_MESSAGE(msg), FALSE );
1351 switch ( GST_MESSAGE_TYPE( msg ) )
1353 case GST_MESSAGE_UNKNOWN:
1354 debug_warning("unknown message received\n");
1357 case GST_MESSAGE_EOS:
1359 MMHandleType attrs = 0;
1362 debug_log("GST_MESSAGE_EOS received\n");
1364 /* NOTE : EOS event is comming multiple time. watch out it */
1365 /* check state. we only process EOS when pipeline state goes to PLAYING */
1366 if ( ! (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) )
1368 debug_warning("EOS received on non-playing state. ignoring it\n");
1372 if ( (player->audio_stream_cb) && (player->is_sound_extraction) )
1376 pad = gst_element_get_static_pad (player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
1378 debug_error("release audio callback\n");
1380 /* release audio callback */
1381 gst_pad_remove_buffer_probe (pad, player->audio_cb_probe_id);
1382 player->audio_cb_probe_id = 0;
1383 /* audio callback should be free because it can be called even though probe remove.*/
1384 player->audio_stream_cb = NULL;
1385 player->audio_stream_cb_user_param = NULL;
1389 /* rewind if repeat count is greater then zero */
1390 /* get play count */
1391 attrs = MMPLAYER_GET_ATTRS(player);
1395 gboolean smooth_repeat = FALSE;
1397 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1398 mm_attrs_get_int_by_name(attrs, "profile_smooth_repeat", &smooth_repeat);
1400 debug_log("remaining play count: %d, playback rate: %f\n", count, player->playback_rate);
1402 if ( count > 1 || count == -1 || player->playback_rate < 0.0 ) /* default value is 1 */
1404 if ( smooth_repeat )
1406 debug_log("smooth repeat enabled. seeking operation will be excuted in new thread\n");
1408 g_cond_signal( player->repeat_thread_cond );
1416 if ( player->section_repeat )
1418 ret_value = _mmplayer_activate_section_repeat((MMHandleType)player, player->section_repeat_start, player->section_repeat_end);
1423 if ( player->playback_rate < 0.0 )
1425 player->resumed_by_rewind = TRUE;
1426 _mmplayer_set_mute((MMHandleType)player, 0);
1427 MMPLAYER_POST_MSG( player, MM_MESSAGE_RESUMED_BY_REW, NULL );
1430 ret_value = __gst_set_position( player, MM_PLAYER_POS_FORMAT_TIME, 0 );
1433 player->sent_bos = FALSE;
1436 if ( MM_ERROR_NONE != ret_value )
1438 debug_error("failed to set position to zero for rewind\n");
1444 /* we successeded to rewind. update play count and then wait for next EOS */
1447 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
1449 if ( mmf_attrs_commit ( attrs ) )
1450 debug_error("failed to commit attrs\n");
1459 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-eos" );
1461 /* post eos message to application */
1462 __mmplayer_post_delayed_eos( player, PLAYER_INI()->eos_delay );
1464 /* reset last position */
1465 player->last_position = 0;
1469 case GST_MESSAGE_ERROR:
1471 GError *error = NULL;
1472 gchar* debug = NULL;
1473 gchar *msg_src_element = NULL;
1475 /* generating debug info before returning error */
1476 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-error" );
1478 /* get error code */
1479 gst_message_parse_error( msg, &error, &debug );
1481 msg_src_element = GST_ELEMENT_NAME( GST_ELEMENT_CAST( msg->src ) );
1482 if ( gst_structure_has_name ( msg->structure, "streaming_error" ) )
1484 /* Note : the streaming error from the streaming source is handled
1485 * using __mmplayer_handle_streaming_error.
1487 __mmplayer_handle_streaming_error ( player, msg );
1489 /* dump state of all element */
1490 __mmplayer_dump_pipeline_state( player );
1494 /* traslate gst error code to msl error code. then post it
1495 * to application if needed
1497 __mmplayer_handle_gst_error( player, msg, error );
1499 /* dump state of all element */
1500 __mmplayer_dump_pipeline_state( player );
1504 if (MMPLAYER_IS_HTTP_PD(player))
1506 _mmplayer_pd_stop ((MMHandleType)player);
1509 MMPLAYER_FREEIF( debug );
1510 g_error_free( error );
1514 case GST_MESSAGE_WARNING:
1517 GError* error = NULL;
1519 gst_message_parse_warning(msg, &error, &debug);
1521 debug_warning("warning : %s\n", error->message);
1522 debug_warning("debug : %s\n", debug);
1524 MMPLAYER_POST_MSG( player, MM_MESSAGE_WARNING, NULL );
1526 MMPLAYER_FREEIF( debug );
1527 g_error_free( error );
1531 case GST_MESSAGE_INFO: debug_log("GST_MESSAGE_STATE_DIRTY\n"); break;
1533 case GST_MESSAGE_TAG:
1535 debug_log("GST_MESSAGE_TAG\n");
1536 if ( ! __mmplayer_gst_extract_tag_from_msg( player, msg ) )
1538 debug_warning("failed to extract tags from gstmessage\n");
1543 case GST_MESSAGE_BUFFERING:
1545 MMMessageParamType msg_param = {0, };
1546 gboolean update_buffering_percent = TRUE;
1548 if ( !MMPLAYER_IS_STREAMING(player) || (player->profile.uri_type == MM_PLAYER_URI_TYPE_HLS) ) // pure hlsdemux case, don't consider buffering of msl currently
1551 __mm_player_streaming_buffering (player->streamer, msg);
1553 __mmplayer_handle_buffering_message ( player );
1555 update_buffering_percent = player->pipeline_is_constructed || MMPLAYER_IS_RTSP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player);
1556 if (update_buffering_percent)
1558 msg_param.connection.buffering = player->streamer->buffering_percent;
1559 MMPLAYER_POST_MSG ( player, MM_MESSAGE_BUFFERING, &msg_param );
1564 case GST_MESSAGE_STATE_CHANGED:
1566 MMPlayerGstElement *mainbin;
1567 const GValue *voldstate, *vnewstate, *vpending;
1568 GstState oldstate, newstate, pending;
1570 if ( ! ( player->pipeline && player->pipeline->mainbin ) )
1572 debug_error("player pipeline handle is null");
1577 mainbin = player->pipeline->mainbin;
1579 /* get state info from msg */
1580 voldstate = gst_structure_get_value (msg->structure, "old-state");
1581 vnewstate = gst_structure_get_value (msg->structure, "new-state");
1582 vpending = gst_structure_get_value (msg->structure, "pending-state");
1584 oldstate = (GstState)voldstate->data[0].v_int;
1585 newstate = (GstState)vnewstate->data[0].v_int;
1586 pending = (GstState)vpending->data[0].v_int;
1588 if (oldstate == newstate)
1591 debug_log("state changed [%s] : %s ---> %s final : %s\n",
1592 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1593 gst_element_state_get_name( (GstState)oldstate ),
1594 gst_element_state_get_name( (GstState)newstate ),
1595 gst_element_state_get_name( (GstState)pending ) );
1597 /* we only handle messages from pipeline */
1598 if( msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst )
1603 case GST_STATE_VOID_PENDING:
1606 case GST_STATE_NULL:
1609 case GST_STATE_READY:
1612 case GST_STATE_PAUSED:
1614 if ( ! player->audio_cb_probe_id && player->is_sound_extraction )
1615 __mmplayer_configure_audio_callback(player);
1618 if ( MMPLAYER_IS_STREAMING(player) )
1620 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_PAUSED );
1622 __mm_player_streaming_set_content_bitrate(player->streamer, player->total_maximum_bitrate, player->total_bitrate);
1624 /* check pending seek and do now */
1625 if ( player->pending_seek.is_pending )
1626 __gst_pending_seek ( player );
1629 player->need_update_content_dur = TRUE;
1633 case GST_STATE_PLAYING:
1636 gboolean is_async = FALSE;
1638 if (player->doing_seek && async_done)
1640 player->doing_seek = FALSE;
1642 MMPLAYER_POST_MSG ( player, MM_MESSAGE_SEEK_COMPLETED, NULL );
1645 /* It should be called in case of async start only.
1646 * don't need to call in the case of resume and sync start (currently, resume is sync.)
1648 mm_attrs_get_int_by_name(player->attrs,"profile_async_start", &is_async);
1649 if (is_async && player->cmd == MMPLAYER_COMMAND_START)
1650 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_PLAYING );
1660 case GST_MESSAGE_STATE_DIRTY: debug_log("GST_MESSAGE_STATE_DIRTY\n"); break;
1661 case GST_MESSAGE_STEP_DONE: debug_log("GST_MESSAGE_STEP_DONE\n"); break;
1662 case GST_MESSAGE_CLOCK_PROVIDE: debug_log("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
1664 case GST_MESSAGE_CLOCK_LOST:
1666 GstClock *clock = NULL;
1667 gst_message_parse_clock_lost (msg, &clock);
1668 debug_log("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME (clock) : "NULL"));
1669 g_print ("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME (clock) : "NULL"));
1671 if (PLAYER_INI()->provide_clock)
1673 debug_log ("Provide clock is TRUE, do pause->resume\n");
1674 __gst_pause(player, FALSE);
1675 __gst_resume(player, FALSE);
1680 case GST_MESSAGE_NEW_CLOCK:
1682 GstClock *clock = NULL;
1683 gst_message_parse_new_clock (msg, &clock);
1684 debug_log("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME (clock) : "NULL"));
1688 case GST_MESSAGE_STRUCTURE_CHANGE: debug_log("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
1689 case GST_MESSAGE_STREAM_STATUS: debug_log("GST_MESSAGE_STREAM_STATUS\n"); break;
1690 case GST_MESSAGE_APPLICATION: debug_log("GST_MESSAGE_APPLICATION\n"); break;
1692 case GST_MESSAGE_ELEMENT:
1694 debug_log("GST_MESSAGE_ELEMENT\n");
1698 case GST_MESSAGE_SEGMENT_START: debug_log("GST_MESSAGE_SEGMENT_START\n"); break;
1699 case GST_MESSAGE_SEGMENT_DONE: debug_log("GST_MESSAGE_SEGMENT_DONE\n"); break;
1701 case GST_MESSAGE_DURATION:
1703 debug_log("GST_MESSAGE_DURATION\n");
1707 case GST_MESSAGE_LATENCY: debug_log("GST_MESSAGE_LATENCY\n"); break;
1708 case GST_MESSAGE_ASYNC_START: debug_log("GST_MESSAGE_ASYNC_DONE : %s\n", gst_element_get_name(GST_MESSAGE_SRC(msg))); break;
1710 case GST_MESSAGE_ASYNC_DONE:
1712 debug_log("GST_MESSAGE_ASYNC_DONE : %s\n", gst_element_get_name(GST_MESSAGE_SRC(msg)));
1714 if (player->doing_seek)
1716 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED)
1718 player->doing_seek = FALSE;
1719 MMPLAYER_POST_MSG ( player, MM_MESSAGE_SEEK_COMPLETED, NULL );
1721 else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING)
1729 case GST_MESSAGE_REQUEST_STATE: debug_log("GST_MESSAGE_REQUEST_STATE\n"); break;
1730 case GST_MESSAGE_STEP_START: debug_log("GST_MESSAGE_STEP_START\n"); break;
1731 case GST_MESSAGE_QOS: debug_log("GST_MESSAGE_QOS\n"); break;
1732 case GST_MESSAGE_PROGRESS: debug_log("GST_MESSAGE_PROGRESS\n"); break;
1733 case GST_MESSAGE_ANY: debug_log("GST_MESSAGE_ANY\n"); break;
1736 debug_warning("unhandled message\n");
1740 /* FIXIT : this cause so many warnings/errors from glib/gstreamer. we should not call it since
1741 * gst_element_post_message api takes ownership of the message.
1743 //gst_message_unref( msg );
1749 __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg) // @
1752 /* macro for better code readability */
1753 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
1754 if (gst_tag_list_get_string(tag_list, gsttag, &string)) \
1756 if (string != NULL)\
1758 debug_log ( "update tag string : %s\n", string); \
1759 mm_attrs_set_string_by_name(attribute, playertag, string); \
1765 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
1766 value = gst_tag_list_get_value_index(tag_list, gsttag, index); \
1769 buffer = gst_value_get_buffer (value); \
1770 debug_log ( "update album cover data : %p, size : %d\n", GST_BUFFER_DATA(buffer), GST_BUFFER_SIZE(buffer)); \
1771 player->album_art = (gchar *)g_malloc(GST_BUFFER_SIZE(buffer)); \
1772 if (player->album_art); \
1774 memcpy(player->album_art, GST_BUFFER_DATA(buffer), GST_BUFFER_SIZE(buffer)); \
1775 mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, GST_BUFFER_SIZE(buffer)); \
1779 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
1780 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint))\
1784 if(gsttag==GST_TAG_BITRATE)\
1786 if (player->updated_bitrate_count == 0) \
1787 mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
1788 if (player->updated_bitrate_count<MM_PLAYER_STREAM_COUNT_MAX) \
1790 player->bitrate[player->updated_bitrate_count] = v_uint;\
1791 player->total_bitrate += player->bitrate[player->updated_maximum_bitrate_count]; \
1792 player->updated_bitrate_count++; \
1793 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate);\
1794 debug_log ( "update bitrate %d[bps] of stream #%d.\n", v_uint, player->updated_bitrate_count);\
1797 else if (gsttag==GST_TAG_MAXIMUM_BITRATE)\
1799 if (player->updated_maximum_bitrate_count<MM_PLAYER_STREAM_COUNT_MAX) \
1801 player->maximum_bitrate[player->updated_maximum_bitrate_count] = v_uint;\
1802 player->total_maximum_bitrate += player->maximum_bitrate[player->updated_maximum_bitrate_count]; \
1803 player->updated_maximum_bitrate_count++; \
1804 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate); \
1805 debug_log ( "update maximum bitrate %d[bps] of stream #%d\n", v_uint, player->updated_maximum_bitrate_count);\
1810 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
1816 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
1817 if (gst_tag_list_get_date(tag_list, gsttag, &date))\
1821 string = g_strdup_printf("%d", g_date_get_year(date));\
1822 mm_attrs_set_string_by_name(attribute, playertag, string);\
1823 debug_log ( "metainfo year : %s\n", string);\
1824 MMPLAYER_FREEIF(string);\
1829 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
1830 if(gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64))\
1834 /* FIXIT : don't know how to store date */\
1840 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
1841 if(gst_tag_list_get_double(tag_list, gsttag, &v_double))\
1845 /* FIXIT : don't know how to store date */\
1851 /* function start */
1852 GstTagList* tag_list = NULL;
1854 MMHandleType attrs = 0;
1856 char *string = NULL;
1860 GstBuffer *buffer = NULL;
1862 const GValue *value;
1864 /* currently not used. but those are needed for above macro */
1865 //guint64 v_uint64 = 0;
1866 //gdouble v_double = 0;
1868 return_val_if_fail( player && msg, FALSE );
1870 attrs = MMPLAYER_GET_ATTRS(player);
1872 return_val_if_fail( attrs, FALSE );
1874 /* get tag list from gst message */
1875 gst_message_parse_tag(msg, &tag_list);
1877 /* store tags to player attributes */
1878 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
1879 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
1880 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
1881 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
1882 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
1883 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
1884 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
1885 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
1886 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
1887 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
1888 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
1889 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
1890 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
1891 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
1892 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
1893 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
1894 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
1895 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
1896 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
1897 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
1898 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
1899 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
1900 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
1901 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
1902 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
1903 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
1904 /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
1905 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
1906 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
1907 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
1908 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
1909 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
1910 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
1911 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
1912 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
1913 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
1914 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
1915 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
1916 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
1917 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
1918 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
1919 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
1920 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
1921 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
1922 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
1924 if ( mmf_attrs_commit ( attrs ) )
1925 debug_error("failed to commit.\n");
1927 gst_tag_list_free(tag_list);
1933 __mmplayer_gst_rtp_no_more_pads (GstElement *element, gpointer data) // @
1935 mm_player_t* player = (mm_player_t*) data;
1939 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
1940 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
1941 * num_dynamic_pad. and this is no-more-pad situation which means mo more pad will be added.
1942 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
1944 * [1] audio and video will be dumped with filesink.
1945 * [2] autoplugging is done by just using pad caps.
1946 * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
1947 * and the video will be dumped via filesink.
1949 if ( player->num_dynamic_pad == 0 )
1951 debug_log("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
1953 if ( ! __mmplayer_gst_remove_fakesink( player,
1954 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]) );
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;
2051 enum MainElementID element_id = MMPLAYER_M_NUM;
2053 mm_player_t* player = (mm_player_t*) data;
2057 return_if_fail( element && pad );
2058 return_if_fail( player &&
2060 player->pipeline->mainbin );
2063 /* first, check pt type which we are supporting or not */
2064 if ( MMPLAYER_PT_IS_VIDEO( GST_PAD_NAME( pad ) ) )
2067 debug_log("is video stream. take it.\n");
2068 element_id = MMPLAYER_M_S_VDEC;
2070 else if ( MMPLAYER_PT_IS_AUDIO( GST_PAD_NAME( pad ) ) )
2073 debug_log("is audio stream. take it.\n");
2074 element_id = MMPLAYER_M_S_ADEC;
2078 /* FIXIT : application should know this. need one more message type */
2079 debug_error ("This Payload type is unknown!\n");
2083 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2084 * num_dynamic_pad will decreased after creating a sinkbin.
2086 player->num_dynamic_pad++;
2087 debug_log("stream count inc : %d\n", player->num_dynamic_pad);
2089 /* perform autoplugging if dump is disabled */
2090 if ( ! new_element )
2092 if ( PLAYER_INI()->rtsp_do_typefinding )
2094 /* create autoplugging element */
2095 if( PLAYER_INI()->use_decodebin )
2097 /* create decodebin */
2098 new_element = gst_element_factory_make("decodebin", NULL);
2100 g_object_set(G_OBJECT(new_element), "async-handling", TRUE, NULL);
2102 if ( ! new_element )
2104 debug_error("failed to create autoplug element\n");
2108 /* set signal handler */
2109 MMPLAYER_SIGNAL_CONNECT( player,
2110 G_OBJECT(new_element),
2112 G_CALLBACK(__mmplayer_gst_decode_callback),
2117 /* create typefind */
2118 new_element = gst_element_factory_make( "typefind", NULL );
2119 if ( ! new_element )
2121 debug_error("failed to create typefind\n");
2125 MMPLAYER_SIGNAL_CONNECT( player,
2126 G_OBJECT(new_element),
2128 G_CALLBACK(__mmplayer_typefind_have_type),
2131 /* FIXIT : try to remove it */
2132 player->have_dynamic_pad = FALSE;
2135 else /* NOTE : use pad's caps directely. if enabled. what I am assuming is there's no elemnt has dynamic pad */
2137 debug_log("using pad caps to autopluging instead of doing typefind\n");
2139 caps = gst_pad_get_caps( pad );
2141 MMPLAYER_CHECK_NULL( caps );
2143 /* clear previous result*/
2144 player->have_dynamic_pad = FALSE;
2146 if ( ! __mmplayer_try_to_plug( player, pad, caps ) )
2148 debug_error("failed to autoplug for caps : %s\n", gst_caps_to_string( caps ) );
2152 /* check if there's dynamic pad*/
2153 if( player->have_dynamic_pad )
2155 debug_error("using pad caps assums there's no dynamic pad !\n");
2156 debug_error("try with enalbing rtsp_do_typefinding\n");
2160 gst_caps_unref( caps );
2165 /* excute new_element if created*/
2168 debug_log("adding new element to pipeline\n");
2170 /* set state to READY before add to bin */
2171 MMPLAYER_ELEMENT_SET_STATE( new_element, GST_STATE_READY );
2173 /* add new element to the pipeline */
2174 if ( FALSE == gst_bin_add( GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element) )
2176 debug_error("failed to add autoplug element to bin\n");
2180 /* get pad from element */
2181 sinkpad = gst_element_get_static_pad ( GST_ELEMENT(new_element), "sink" );
2184 debug_error("failed to get sinkpad from autoplug element\n");
2189 if ( GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad) )
2191 debug_error("failed to link autoplug element\n");
2195 gst_object_unref (sinkpad);
2198 /* run. setting PLAYING here since streamming source is live source */
2199 MMPLAYER_ELEMENT_SET_STATE( new_element, GST_STATE_PLAYING );
2202 /* store handle to futher manipulation */
2203 player->pipeline->mainbin[element_id].id = element_id;
2204 player->pipeline->mainbin[element_id].gst = new_element;
2210 STATE_CHANGE_FAILED:
2212 /* FIXIT : take care if new_element has already added to pipeline */
2214 gst_object_unref(GST_OBJECT(new_element));
2217 gst_object_unref(GST_OBJECT(sinkpad));
2220 gst_object_unref(GST_OBJECT(caps));
2222 /* FIXIT : how to inform this error to MSL ????? */
2223 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2224 * then post an error to application
2230 __mmplayer_gst_decode_callback(GstElement *decodebin, GstPad *pad, gboolean last, gpointer data) // @
2232 mm_player_t* player = NULL;
2233 MMHandleType attrs = 0;
2234 GstElement* pipeline = NULL;
2235 GstCaps* caps = NULL;
2236 GstStructure* str = NULL;
2237 const gchar* name = NULL;
2238 GstPad* sinkpad = NULL;
2239 GstElement* sinkbin = NULL;
2242 player = (mm_player_t*) data;
2244 return_if_fail( decodebin && pad );
2245 return_if_fail(player && player->pipeline && player->pipeline->mainbin);
2247 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
2249 attrs = MMPLAYER_GET_ATTRS(player);
2252 debug_error("cannot get content attribute\n");
2256 /* get mimetype from caps */
2257 caps = gst_pad_get_caps( pad );
2260 debug_error("cannot get caps from pad.\n");
2264 str = gst_caps_get_structure( caps, 0 );
2267 debug_error("cannot get structure from capse.\n");
2271 name = gst_structure_get_name(str);
2274 debug_error("cannot get mimetype from structure.\n");
2278 debug_log("detected mimetype : %s\n", name);
2280 if (strstr(name, "audio"))
2282 if (player->pipeline->audiobin == NULL)
2284 __ta__("__mmplayer_gst_create_audio_pipeline",
2285 if (MM_ERROR_NONE != __mmplayer_gst_create_audio_pipeline(player))
2287 debug_error("failed to create audiobin. continuing without audio\n");
2292 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
2293 debug_log("creating audiosink bin success\n");
2297 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
2298 debug_log("re-using audiobin\n");
2301 /* FIXIT : track number shouldn't be hardcoded */
2302 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 1);
2304 player->audiosink_linked = 1;
2305 debug_msg("player->audsink_linked set to 1\n");
2308 else if (strstr(name, "video"))
2310 if (player->pipeline->videobin == NULL)
2312 __mmplayer_set_videosink_type(player);
2314 /* NOTE : not make videobin because application dose not want to play it even though file has video stream.
2316 if (PLAYER_INI()->video_surface == MM_DISPLAY_SURFACE_NULL)
2318 debug_log("not make videobin because it dose not want\n");
2322 __ta__("__mmplayer_gst_create_video_pipeline",
2323 if (MM_ERROR_NONE != __mmplayer_gst_create_video_pipeline(player, caps) )
2325 debug_error("failed to create videobin. continuing without video\n");
2330 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
2331 debug_log("creating videosink bin success\n");
2335 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
2336 debug_log("re-using videobin\n");
2339 /* FIXIT : track number shouldn't be hardcoded */
2340 mm_attrs_set_int_by_name(attrs, "content_video_track_num", 1);
2342 player->videosink_linked = 1;
2343 debug_msg("player->videosink_linked set to 1\n");
2346 else if (strstr(name, "text"))
2348 if (player->pipeline->textbin == NULL)
2350 __ta__("__mmplayer_gst_create_text_pipeline",
2351 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player))
2353 debug_error("failed to create textbin. continuing without text\n");
2358 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
2359 debug_log("creating textink bin success\n");
2363 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
2364 debug_log("re-using textbin\n");
2367 /* FIXIT : track number shouldn't be hardcoded */
2368 mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1);
2370 player->textsink_linked = 1;
2371 debug_msg("player->textsink_linked set to 1\n");
2375 debug_warning("unknown type of elementary stream! ignoring it...\n");
2382 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state( sinkbin, GST_STATE_READY ) )
2384 debug_error("failed to set state(READY) to sinkbin\n");
2389 if ( FALSE == gst_bin_add( GST_BIN(pipeline), sinkbin ) )
2391 debug_error("failed to add sinkbin to pipeline\n");
2395 sinkpad = gst_element_get_static_pad( GST_ELEMENT(sinkbin), "sink" );
2399 debug_error("failed to get pad from sinkbin\n");
2404 if ( GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad) )
2406 debug_error("failed to get pad from sinkbin\n");
2411 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state( sinkbin, GST_STATE_PAUSED ) )
2413 debug_error("failed to set state(PLAYING) to sinkbin\n");
2417 gst_object_unref( sinkpad );
2421 /* update track number attributes */
2422 if ( mmf_attrs_commit ( attrs ) )
2423 debug_error("failed to commit attrs\n");
2425 debug_log("linking sink bin success\n");
2428 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
2429 * streaming task. if the task blocked, then buffer will not flow to the next element
2430 * ( autoplugging element ). so this is special hack for streaming. please try to remove it
2432 /* dec stream count. we can remove fakesink if it's zero */
2433 player->num_dynamic_pad--;
2435 debug_log("stream count dec : %d (num of dynamic pad)\n", player->num_dynamic_pad);
2437 if ( ( player->no_more_pad ) && ( player->num_dynamic_pad == 0 ) )
2439 __mmplayer_pipeline_complete( NULL, player );
2444 gst_caps_unref( caps );
2447 gst_object_unref(GST_OBJECT(sinkpad));
2453 _mmplayer_update_video_param(mm_player_t* player) // @
2455 MMHandleType attrs = 0;
2456 gint videosink_idx_x = 0;
2457 gint videosink_idx_evas = 0;
2458 gboolean is_first_v_sink_x = FALSE;
2462 /* check video sinkbin is created */
2463 return_val_if_fail ( player &&
2465 player->pipeline->videobin &&
2466 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
2467 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2468 MM_ERROR_PLAYER_NOT_INITIALIZED );
2470 attrs = MMPLAYER_GET_ATTRS(player);
2473 debug_error("cannot get content attribute");
2474 return MM_ERROR_PLAYER_INTERNAL;
2477 /* update display surface */
2478 __mmplayer_set_videosink_type(player);
2480 /* check video stream callback is used */
2481 if( player->use_video_stream )
2483 if (player->is_nv12_tiled)
2485 gchar *ename = NULL;
2486 int degree, width, height;
2487 degree = width = height = 0;
2489 mm_attrs_get_int_by_name(attrs, "display_width", &width);
2490 mm_attrs_get_int_by_name(attrs, "display_height", &height);
2491 mm_attrs_get_int_by_name(attrs, "display_rotation", °ree);
2493 /* resize video frame with requested values for fimcconvert */
2494 ename = GST_PLUGIN_FEATURE_NAME(gst_element_get_factory(player->pipeline->videobin[MMPLAYER_V_CONV].gst));
2496 if (g_strrstr(ename, "fimcconvert"))
2499 g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "src-width", width, NULL);
2502 g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "src-height", height, NULL);
2506 case MM_DISPLAY_ROTATION_NONE:
2510 case MM_DISPLAY_ROTATION_90:
2514 case MM_DISPLAY_ROTATION_180:
2518 case MM_DISPLAY_ROTATION_270:
2527 g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "rotate", degree, NULL);
2529 debug_log("updating fimcconvert - r[%d], w[%d], h[%d]", degree, width, height);
2533 debug_error("no available video converter");
2538 int rotate, width, height, orientation, rotation;
2540 rotate = width = height = orientation = rotation = 0;
2542 debug_log("using video stream callback with memsink. player handle : [%p]", player);
2544 mm_attrs_get_int_by_name(attrs, "display_width", &width);
2545 mm_attrs_get_int_by_name(attrs, "display_height", &height);
2546 mm_attrs_get_int_by_name(attrs, "display_rotation", &rotation);
2547 mm_attrs_get_int_by_name(attrs, "display_orientation", &orientation);
2549 if(rotation == MM_DISPLAY_ROTATION_NONE) rotate = 0;
2550 else if(rotation ==MM_DISPLAY_ROTATION_90) rotate = 90;
2551 else if(rotation ==MM_DISPLAY_ROTATION_180) rotate = 180;
2552 else if(rotation ==MM_DISPLAY_ROTATION_270) rotate = 270;
2554 if(orientation == 1) rotate = 90;
2555 else if(orientation == 2) rotate = 180;
2556 else if(orientation == 3) rotate = 270;
2559 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "width", width, NULL);
2562 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "height", height, NULL);
2564 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotate,NULL);
2567 return MM_ERROR_NONE;
2570 if (player->use_multi_surface)
2572 is_first_v_sink_x = !strncmp(GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_SINK_EXT].gst), "videosink_ext_evas", 18);
2573 if (is_first_v_sink_x)
2575 videosink_idx_x = MMPLAYER_V_SINK;
2576 videosink_idx_evas = MMPLAYER_V_SINK_EXT;
2580 videosink_idx_x = MMPLAYER_V_SINK_EXT;
2581 videosink_idx_evas = MMPLAYER_V_SINK;
2583 debug_log("use multi-surface : videosink_idx_x(%d), videosink_idx_evas(%d)", videosink_idx_x,videosink_idx_evas);
2587 videosink_idx_x = videosink_idx_evas = MMPLAYER_V_SINK;
2590 /* configuring display */
2591 switch ( PLAYER_INI()->video_surface )
2593 case MM_DISPLAY_SURFACE_X:
2595 /* ximagesink or xvimagesink */
2599 int display_method = 0;
2604 int force_aspect_ratio = 0;
2606 gboolean visible = TRUE;
2608 /* common case if using multi-surface */
2609 if (player->use_multi_surface)
2611 void *evas_image_object = NULL;
2612 if (is_first_v_sink_x)
2614 mm_attrs_get_data_by_name(attrs, "display_overlay", &xid);
2615 mm_attrs_get_data_by_name(attrs, "display_overlay_ext", &evas_image_object);
2619 mm_attrs_get_data_by_name(attrs, "display_overlay", &evas_image_object);
2620 mm_attrs_get_data_by_name(attrs, "display_overlay_ext", &xid);
2624 debug_log("use multi-surface : xid %d", *(int*)xid);
2625 gst_x_overlay_set_xwindow_id( GST_X_OVERLAY( player->pipeline->videobin[videosink_idx_x].gst ), *(int*)xid );
2629 debug_error("no xwindow");
2630 return MM_ERROR_PLAYER_INTERNAL;
2632 if (evas_image_object)
2634 g_object_set(player->pipeline->videobin[videosink_idx_evas].gst,
2635 "evas-object", evas_image_object,
2641 debug_error("no evas object");
2642 return MM_ERROR_PLAYER_INTERNAL;
2644 debug_log("use multi-surface : evas_image_object (%x)", evas_image_object);
2645 debug_log("use multi-surface : evas visible %d", FALSE);
2647 /* common case if using x surface */
2650 mm_attrs_get_data_by_name(attrs, "display_overlay", &xid);
2653 debug_log("set video param : xid %d", *(int*)xid);
2654 gst_x_overlay_set_xwindow_id( GST_X_OVERLAY( player->pipeline->videobin[MMPLAYER_V_SINK].gst ), *(int*)xid );
2658 /* FIXIT : is it error case? */
2659 debug_warning("still we don't have xid on player attribute. create it's own surface.");
2663 /* if xvimagesink */
2664 if (!strcmp(PLAYER_INI()->videosink_element_x,"xvimagesink"))
2666 mm_attrs_get_int_by_name(attrs, "display_force_aspect_ration", &force_aspect_ratio);
2667 mm_attrs_get_int_by_name(attrs, "display_zoom", &zoom);
2668 mm_attrs_get_int_by_name(attrs, "display_rotation", °ree);
2669 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
2670 mm_attrs_get_int_by_name(attrs, "display_roi_x", &roi_x);
2671 mm_attrs_get_int_by_name(attrs, "display_roi_y", &roi_y);
2672 mm_attrs_get_int_by_name(attrs, "display_roi_width", &roi_w);
2673 mm_attrs_get_int_by_name(attrs, "display_roi_height", &roi_h);
2674 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
2676 g_object_set(player->pipeline->videobin[videosink_idx_x].gst,
2677 "force-aspect-ratio", force_aspect_ratio,
2680 "handle-events", TRUE,
2681 "display-geometry-method", display_method,
2682 "draw-borders", FALSE,
2690 debug_log("set video param : zoom %d", zoom);
2691 debug_log("set video param : rotate %d", degree);
2692 debug_log("set video param : method %d", display_method);
2693 debug_log("set video param : dst-roi-x: %d, dst-roi-y: %d, dst-roi-w: %d, dst-roi-h: %d",
2694 roi_x, roi_y, roi_w, roi_h );
2695 debug_log("set video param : visible %d", visible);
2696 debug_log("set video param : force aspect ratio %d", force_aspect_ratio);
2700 case MM_DISPLAY_SURFACE_EVAS:
2702 void *object = NULL;
2704 gboolean visible = TRUE;
2706 /* common case if using multi-surface */
2707 if (player->use_multi_surface)
2710 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
2711 if (is_first_v_sink_x)
2713 mm_attrs_get_data_by_name(attrs, "display_overlay", &xid);
2714 mm_attrs_get_data_by_name(attrs, "display_overlay_ext", &object);
2718 mm_attrs_get_data_by_name(attrs, "display_overlay", &object);
2719 mm_attrs_get_data_by_name(attrs, "display_overlay_ext", &xid);
2723 g_object_set(player->pipeline->videobin[videosink_idx_evas].gst,
2724 "evas-object", object,
2727 debug_log("use multi-surface : evas-object %x", object);
2728 debug_log("use multi-surface : evas visible %d", object);
2732 debug_error("no evas object");
2733 return MM_ERROR_PLAYER_INTERNAL;
2737 gst_x_overlay_set_xwindow_id( GST_X_OVERLAY( player->pipeline->videobin[videosink_idx_x].gst ), *(int*)xid );
2741 debug_error("no xwindow");
2742 return MM_ERROR_PLAYER_INTERNAL;
2744 /* if xvimagesink */
2745 if (!strcmp(PLAYER_INI()->videosink_element_x,"xvimagesink"))
2747 g_object_set(player->pipeline->videobin[videosink_idx_x].gst,
2751 debug_log("use multi-surface : xid %d", *(int*)xid);
2752 debug_log("use multi-surface : x visible %d", FALSE);
2754 /* common case if using evas surface */
2757 mm_attrs_get_data_by_name(attrs, "display_overlay", &object);
2758 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
2759 mm_attrs_get_int_by_name(attrs, "display_evas_do_scaling", &scaling);
2762 g_object_set(player->pipeline->videobin[videosink_idx_evas].gst,
2763 "evas-object", object,
2766 debug_log("set video param : evas-object %x", object);
2767 debug_log("set video param : visible %d", visible);
2771 debug_error("no evas object");
2772 return MM_ERROR_PLAYER_INTERNAL;
2776 /* if evasimagesink */
2777 if (!strcmp(PLAYER_INI()->videosink_element_evas,"evasimagesink") && player->is_nv12_tiled)
2781 int no_scaling = !scaling;
2783 mm_attrs_get_int_by_name(attrs, "display_width", &width);
2784 mm_attrs_get_int_by_name(attrs, "display_height", &height);
2788 /* no-scaling order to fimcconvert, original width, height size of media src will be passed to sink plugin */
2789 g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst,
2790 "src-width", 0, /* setting 0, output video width will be media src's width */
2791 "src-height", 0, /* setting 0, output video height will be media src's height */
2796 /* scaling order to fimcconvert */
2799 g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "src-width", width, NULL);
2803 g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "src-height", height, NULL);
2805 debug_log("set video param : video frame scaling down to width(%d) height(%d)", width, height);
2807 debug_log("set video param : display_evas_do_scaling %d", scaling);
2810 /* if evaspixmapsink */
2811 if (!strcmp(PLAYER_INI()->videosink_element_evas,"evaspixmapsink"))
2813 int display_method = 0;
2818 int force_aspect_ratio = 0;
2819 int origin_size = !scaling;
2821 mm_attrs_get_int_by_name(attrs, "display_force_aspect_ration", &force_aspect_ratio);
2822 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
2823 mm_attrs_get_int_by_name(attrs, "display_roi_x", &roi_x);
2824 mm_attrs_get_int_by_name(attrs, "display_roi_y", &roi_y);
2825 mm_attrs_get_int_by_name(attrs, "display_roi_width", &roi_w);
2826 mm_attrs_get_int_by_name(attrs, "display_roi_height", &roi_h);
2828 g_object_set(player->pipeline->videobin[videosink_idx_evas].gst,
2829 "force-aspect-ratio", force_aspect_ratio,
2830 "origin-size", origin_size,
2835 "display-geometry-method", display_method,
2838 debug_log("set video param : method %d", display_method);
2839 debug_log("set video param : dst-roi-x: %d, dst-roi-y: %d, dst-roi-w: %d, dst-roi-h: %d",
2840 roi_x, roi_y, roi_w, roi_h );
2841 debug_log("set video param : force aspect ratio %d", force_aspect_ratio);
2842 debug_log("set video param : display_evas_do_scaling %d (origin-size %d)", scaling, origin_size);
2846 case MM_DISPLAY_SURFACE_NULL:
2855 return MM_ERROR_NONE;
2859 __mmplayer_gst_element_link_bucket(GList* element_bucket) // @
2861 GList* bucket = element_bucket;
2862 MMPlayerGstElement* element = NULL;
2863 MMPlayerGstElement* prv_element = NULL;
2864 gint successful_link_count = 0;
2868 return_val_if_fail(element_bucket, -1);
2870 prv_element = (MMPlayerGstElement*)bucket->data;
2871 bucket = bucket->next;
2873 for ( ; bucket; bucket = bucket->next )
2875 element = (MMPlayerGstElement*)bucket->data;
2877 if ( element && element->gst )
2879 if ( GST_ELEMENT_LINK(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst)) )
2881 debug_log("linking [%s] to [%s] success\n",
2882 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2883 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)) );
2884 successful_link_count ++;
2888 debug_log("linking [%s] to [%s] failed\n",
2889 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2890 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)) );
2896 prv_element = element;
2901 return successful_link_count;
2905 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket) // @
2907 GList* bucket = element_bucket;
2908 MMPlayerGstElement* element = NULL;
2909 int successful_add_count = 0;
2913 return_val_if_fail(element_bucket, 0);
2914 return_val_if_fail(bin, 0);
2916 for ( ; bucket; bucket = bucket->next )
2918 element = (MMPlayerGstElement*)bucket->data;
2920 if ( element && element->gst )
2922 if( !gst_bin_add(bin, GST_ELEMENT(element->gst)) )
2924 debug_log("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed\n",
2925 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2926 GST_ELEMENT_NAME(GST_ELEMENT(bin) ) );
2929 successful_add_count ++;
2935 return successful_add_count;
2941 * This function is to create audio pipeline for playing.
2943 * @param player [in] handle of player
2945 * @return This function returns zero on success.
2947 * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_pipeline
2949 #define MMPLAYER_CREATEONLY_ELEMENT(x_bin, x_id, x_factory, x_name) \
2950 x_bin[x_id].id = x_id;\
2951 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
2952 if ( ! x_bin[x_id].gst )\
2954 debug_critical("failed to create %s \n", x_factory);\
2958 /* macro for code readability. just for sinkbin-creation functions */
2959 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket) \
2962 x_bin[x_id].id = x_id;\
2963 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
2964 if ( ! x_bin[x_id].gst )\
2966 debug_critical("failed to create %s \n", x_factory);\
2969 if ( x_add_bucket )\
2970 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
2976 * - Local playback : audioconvert !volume ! capsfilter ! dnse ! audiosink
2977 * - Streaming : audioconvert !volume ! audiosink
2978 * - PCM extraction : audioconvert ! audioresample ! capsfilter ! fakesink
2981 __mmplayer_gst_create_audio_pipeline(mm_player_t* player)
2983 MMPlayerGstElement* first_element = NULL;
2984 MMPlayerGstElement* audiobin = NULL;
2985 MMHandleType attrs = 0;
2987 GstPad *ghostpad = NULL;
2988 GList* element_bucket = NULL;
2989 char *device_name = NULL;
2990 gboolean link_audio_sink_now = TRUE;
2995 return_val_if_fail( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
2998 audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
2999 audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
3002 debug_error("failed to allocate memory for audiobin\n");
3003 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3006 attrs = MMPLAYER_GET_ATTRS(player);
3009 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
3010 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
3011 if ( !audiobin[MMPLAYER_A_BIN].gst )
3013 debug_critical("failed to create audiobin\n");
3018 player->pipeline->audiobin = audiobin;
3020 player->is_sound_extraction = __mmplayer_can_extract_pcm(player);
3022 /* Adding audiotp plugin for reverse trickplay feature */
3023 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TP, "audiotp", "audiotrickplay", TRUE);
3026 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audioconverter", TRUE);
3028 if ( ! player->is_sound_extraction )
3030 /* for logical volume control */
3031 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE);
3032 g_object_set(G_OBJECT (audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
3034 if (player->sound.mute)
3036 debug_log("mute enabled\n");
3037 g_object_set(G_OBJECT (audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
3040 /* NOTE : streaming doesn't need capsfilter and sound effect*/
3041 if ( ! MMPLAYER_IS_RTSP_STREAMING( player ) )
3043 GstCaps* caps = NULL;
3046 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE);
3048 caps = gst_caps_from_string( "audio/x-raw-int, "
3049 "endianness = (int) LITTLE_ENDIAN, "
3050 "signed = (boolean) true, "
3051 "width = (int) 16, "
3052 "depth = (int) 16" );
3054 g_object_set (GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL );
3056 gst_caps_unref( caps );
3058 /* audio filter. if enabled */
3059 if ( PLAYER_INI()->use_audio_filter_preset || PLAYER_INI()->use_audio_filter_custom )
3061 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, "soundalive", "audiofilter", TRUE);
3064 /* create audio sink */
3065 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, PLAYER_INI()->name_of_audiosink,
3066 "audiosink", link_audio_sink_now);
3069 if (MMPLAYER_IS_RTSP_STREAMING (player) )
3070 g_object_set (G_OBJECT (audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL); /* sync off */
3072 g_object_set (G_OBJECT (audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE, NULL); /* sync on */
3075 g_object_set (G_OBJECT (audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
3077 /* FIXIT : using system clock. isn't there another way? */
3078 g_object_set (G_OBJECT (audiobin[MMPLAYER_A_SINK].gst), "provide-clock", PLAYER_INI()->provide_clock, NULL);
3080 __mmplayer_add_sink( player, audiobin[MMPLAYER_A_SINK].gst );
3082 if(player->audio_buffer_cb)
3084 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "audio-handle", player->audio_buffer_cb_user_param, NULL);
3085 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "audio-callback", player->audio_buffer_cb, NULL);
3088 if ( g_strrstr(PLAYER_INI()->name_of_audiosink, "avsysaudiosink") )
3090 gint volume_type = 0;
3091 gint audio_route = 0;
3092 gint sound_priority = FALSE;
3093 gint is_spk_out_only = 0;
3096 * It should be set after player creation through attribute.
3097 * But, it can not be changed during playing.
3099 mm_attrs_get_int_by_name(attrs, "sound_volume_type", &volume_type);
3100 mm_attrs_get_int_by_name(attrs, "sound_route", &audio_route);
3101 mm_attrs_get_int_by_name(attrs, "sound_priority", &sound_priority);
3102 mm_attrs_get_int_by_name(attrs, "sound_spk_out_only", &is_spk_out_only);
3104 /* hook sound_type if emergency case */
3105 if ( player->sm.event == ASM_EVENT_EMERGENCY)
3107 debug_log ("This is emergency session, hook sound_type from [%d] to [%d]\n", volume_type, MM_SOUND_VOLUME_TYPE_EMERGENCY);
3108 volume_type = MM_SOUND_VOLUME_TYPE_EMERGENCY;
3111 g_object_set(audiobin[MMPLAYER_A_SINK].gst,
3112 "volumetype", volume_type,
3113 "audio-route", audio_route,
3114 "priority", sound_priority,
3115 "user-route", is_spk_out_only,
3118 debug_log("audiosink property status...volume type:%d, route:%d, priority=%d, user-route=%d\n",
3119 volume_type, audio_route, sound_priority, is_spk_out_only);
3122 /* Antishock can be enabled when player is resumed by soundCM.
3123 * But, it's not used in MMS, setting and etc.
3124 * Because, player start seems like late.
3126 __mmplayer_set_antishock( player , FALSE );
3128 else // pcm extraction only and no sound output
3130 int dst_samplerate = 0;
3131 int dst_channels = 0;
3133 char *caps_type = NULL;
3134 GstCaps* caps = NULL;
3137 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, "audioresample", "resampler", TRUE);
3139 /* get conf. values */
3140 mm_attrs_multiple_get(player->attrs,
3142 "pcm_extraction_samplerate", &dst_samplerate,
3143 "pcm_extraction_channels", &dst_channels,
3144 "pcm_extraction_depth", &dst_depth,
3147 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE);
3149 caps = gst_caps_new_simple ("audio/x-raw-int",
3150 "rate", G_TYPE_INT, dst_samplerate,
3151 "channels", G_TYPE_INT, dst_channels,
3152 "depth", G_TYPE_INT, dst_depth,
3155 caps_type = gst_caps_to_string(caps);
3156 debug_log("resampler new caps : %s\n", caps_type);
3158 g_object_set (GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL );
3161 gst_caps_unref( caps );
3162 MMPLAYER_FREEIF( caps_type );
3165 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "fakesink", TRUE);
3168 g_object_set (G_OBJECT (audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL);
3170 __mmplayer_add_sink( player, audiobin[MMPLAYER_A_SINK].gst );
3173 /* adding created elements to bin */
3174 debug_log("adding created elements to bin\n");
3175 if( !__mmplayer_gst_element_add_bucket_to_bin( GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket ))
3177 debug_error("failed to add elements\n");
3181 /* linking elements in the bucket by added order. */
3182 debug_log("Linking elements in the bucket by added order.\n");
3183 if ( __mmplayer_gst_element_link_bucket(element_bucket) == -1 )
3185 debug_error("failed to link elements\n");
3189 /* get first element's sinkpad for creating ghostpad */
3190 first_element = (MMPlayerGstElement *)element_bucket->data;
3192 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3195 debug_error("failed to get pad from first element of audiobin\n");
3199 ghostpad = gst_ghost_pad_new("sink", pad);
3202 debug_error("failed to create ghostpad\n");
3206 if ( FALSE == gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad) )
3208 debug_error("failed to add ghostpad to audiobin\n");
3212 gst_object_unref(pad);
3214 if ( !player->bypass_sound_effect && (PLAYER_INI()->use_audio_filter_preset || PLAYER_INI()->use_audio_filter_custom) )
3216 if ( player->audio_filter_info.filter_type == MM_AUDIO_FILTER_TYPE_PRESET )
3218 if (!_mmplayer_sound_filter_preset_apply(player, player->audio_filter_info.preset))
3220 debug_msg("apply sound effect(preset:%d) setting success\n",player->audio_filter_info.preset);
3223 else if ( player->audio_filter_info.filter_type == MM_AUDIO_FILTER_TYPE_CUSTOM )
3225 if (!_mmplayer_sound_filter_custom_apply(player))
3227 debug_msg("apply sound effect(custom) setting success\n");
3232 /* done. free allocated variables */
3233 MMPLAYER_FREEIF( device_name );
3234 g_list_free(element_bucket);
3236 mm_attrs_set_int_by_name(attrs, "content_audio_found", TRUE);
3237 if ( mmf_attrs_commit ( attrs ) ) /* return -1 if error */
3238 debug_error("failed to commit attribute ""content_audio_found"".\n");
3242 return MM_ERROR_NONE;
3246 debug_log("ERROR : releasing audiobin\n");
3248 MMPLAYER_FREEIF( device_name );
3251 gst_object_unref(GST_OBJECT(pad));
3254 gst_object_unref(GST_OBJECT(ghostpad));
3256 g_list_free( element_bucket );
3259 /* release element which are not added to bin */
3260 for ( i = 1; i < MMPLAYER_A_NUM; i++ ) /* NOTE : skip bin */
3262 if ( audiobin[i].gst )
3264 GstObject* parent = NULL;
3265 parent = gst_element_get_parent( audiobin[i].gst );
3269 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3270 audiobin[i].gst = NULL;
3274 gst_object_unref(GST_OBJECT(parent));
3279 /* release audiobin with it's childs */
3280 if ( audiobin[MMPLAYER_A_BIN].gst )
3282 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3285 MMPLAYER_FREEIF( audiobin );
3287 player->pipeline->audiobin = NULL;
3289 return MM_ERROR_PLAYER_INTERNAL;
3293 __mmplayer_audio_stream_probe (GstPad *pad, GstBuffer *buffer, gpointer u_data)
3295 mm_player_t* player = (mm_player_t*) u_data;
3299 data = GST_BUFFER_DATA(buffer);
3300 size = GST_BUFFER_SIZE(buffer);
3302 if (player->audio_stream_cb && size && data)
3303 player->audio_stream_cb((void *)data, size, player->audio_stream_cb_user_param);
3309 __mmplayer_ahs_appsrc_probe (GstPad *pad, GstBuffer *buffer, gpointer u_data)
3311 mm_player_t* player = (mm_player_t*) u_data;
3313 //g_print ("appsrc buf : timestamp = %"GST_TIME_FORMAT", duration = %"GST_TIME_FORMAT"\n",
3314 // GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)), GST_TIME_ARGS (GST_BUFFER_DURATION(buffer)));
3316 if (ahs_check_allow_cache (player->ahs_player))
3318 ahs_store_media_presentation (player->ahs_player, GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer));
3324 * This function is to create video pipeline.
3326 * @param player [in] handle of player
3327 * caps [in] src caps of decoder
3329 * @return This function returns zero on success.
3331 * @see __mmplayer_gst_create_audio_pipeline, __mmplayer_gst_create_midi_pipeline
3335 * - x surface (arm/x86) : xvimagesink
3336 * - evas surface (arm) : evaspixmapsink
3337 * fimcconvert ! evasimagesink
3338 * - evas surface (x86) : videoconvertor ! evasimagesink
3339 * - multi-surface (arm) : tee name=tee ! xvimagesink tee. ! evaspixmapsink
3342 __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps* caps)
3346 GList*element_bucket = NULL;
3347 MMPlayerGstElement* first_element = NULL;
3348 MMPlayerGstElement* videobin = NULL;
3349 gchar* vconv_factory = NULL;
3350 char *err_name = NULL;
3351 gboolean use_multi_surface = FALSE;
3352 char *videosink_element = NULL;
3353 char *videosink_element_ext = NULL;
3357 return_val_if_fail(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3360 videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
3362 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3364 player->pipeline->videobin = videobin;
3366 attrs = MMPLAYER_GET_ATTRS(player);
3369 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3370 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3371 if ( !videobin[MMPLAYER_V_BIN].gst )
3373 debug_critical("failed to create audiobin\n");
3377 mm_player_get_attribute(player, &err_name, "display_surface_use_multi", &use_multi_surface, NULL);
3378 player->use_multi_surface = use_multi_surface;
3380 if( player->use_video_stream ) // video stream callack, so send raw video data to application
3382 GstStructure *str = NULL;
3386 debug_log("using memsink\n");
3388 /* first, create colorspace convert */
3389 if (player->is_nv12_tiled)
3391 vconv_factory = "fimcconvert";
3393 else // get video converter from player ini file
3395 if (strlen(PLAYER_INI()->name_of_video_converter) > 0)
3397 vconv_factory = PLAYER_INI()->name_of_video_converter;
3403 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_CONV, vconv_factory, "video converter", TRUE);
3406 /* then, create video scale to resize if needed */
3407 str = gst_caps_get_structure (caps, 0);
3411 debug_error("cannot get structure\n");
3415 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
3417 ret = gst_structure_get_fourcc (str, "format", &fourcc);
3420 debug_log("not fixed format at this point, and not consider this case\n")
3422 /* NOTE : if the width of I420 format is not multiple of 8, it should be resize before colorspace conversion.
3423 * so, video scale is required for this case only.
3425 if ( GST_MAKE_FOURCC ('I', '4', '2', '0') == fourcc )
3427 gint width = 0; //width of video
3428 gint height = 0; //height of video
3429 gint framerate_n = 0; //numerator of frame rate
3430 gint framerate_d = 0; //denominator of frame rate
3431 GstCaps* video_caps = NULL;
3435 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SCALE, "videoscale", "videoscale", TRUE);
3437 /*to limit width as multiple of 8 */
3438 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_CAPS, "capsfilter", "videocapsfilter", TRUE);
3440 /* get video stream caps parsed by demuxer */
3441 str = gst_caps_get_structure (player->v_stream_caps, 0);
3444 debug_error("cannot get structure\n");
3448 /* check the width if it's a multiple of 8 or not */
3449 ret = gst_structure_get_int (str, "width", &width);
3452 debug_error("cannot get width\n");
3455 width = GST_ROUND_UP_8(width);
3457 ret = gst_structure_get_int(str, "height", &height);
3460 debug_error("cannot get height\n");
3464 fps = gst_structure_get_value (str, "framerate");
3467 debug_error("cannot get fps\n");
3470 framerate_n = gst_value_get_fraction_numerator (fps);
3471 framerate_d = gst_value_get_fraction_denominator (fps);
3473 video_caps = gst_caps_new_simple( "video/x-raw-yuv",
3474 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('I', '4', '2', '0'),
3475 "width", G_TYPE_INT, width,
3476 "height", G_TYPE_INT, height,
3477 "framerate", GST_TYPE_FRACTION, framerate_n, framerate_d,
3480 g_object_set (GST_ELEMENT(videobin[MMPLAYER_V_CAPS].gst), "caps", video_caps, NULL );
3482 gst_caps_unref( video_caps );
3485 /* finally, create video sink. its oupput should be BGRX8888 for application like cario surface. */
3486 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, "avsysmemsink", "videosink", TRUE);
3488 MMPLAYER_SIGNAL_CONNECT( player,
3489 videobin[MMPLAYER_V_SINK].gst,
3491 G_CALLBACK(__mmplayer_videostream_cb),
3494 else // render video data using sink pugin like xvimagesink
3496 debug_log("using videosink");
3498 /*set video converter */
3499 if (strlen(PLAYER_INI()->name_of_video_converter) > 0)
3501 vconv_factory = PLAYER_INI()->name_of_video_converter;
3502 gboolean nv12t_hw_enabled = FALSE;
3504 if (player->is_nv12_tiled && PLAYER_INI()->use_video_hw_accel)
3505 nv12t_hw_enabled = TRUE;
3507 if ( (nv12t_hw_enabled && (PLAYER_INI()->video_surface == MM_DISPLAY_SURFACE_EVAS) && !strcmp(PLAYER_INI()->videosink_element_evas, "evasimagesink")) || (nv12t_hw_enabled && use_multi_surface && !strcmp(PLAYER_INI()->videosink_element_evas, "evasimagesink") ) )
3509 vconv_factory = "fimcconvert";
3511 else if (nv12t_hw_enabled)
3513 vconv_factory = NULL;
3516 if (vconv_factory && !use_multi_surface)
3518 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_CONV, vconv_factory, "video converter", TRUE);
3519 debug_log("using video converter: %s", vconv_factory);
3523 /* videoscaler */ /* NOTE : ini parsing method seems to be more suitable rather than define method */
3524 #if !defined(__arm__)
3525 if (!use_multi_surface) /* NOTE : at now, we did not consider using multi-surface in x86 case */
3527 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SCALE, "videoscale", "videoscaler", TRUE);
3531 /* set video sink */
3532 switch (PLAYER_INI()->video_surface)
3534 case MM_DISPLAY_SURFACE_X:
3535 if (strlen(PLAYER_INI()->videosink_element_x) > 0)
3536 videosink_element = PLAYER_INI()->videosink_element_x;
3540 case MM_DISPLAY_SURFACE_EVAS:
3541 if (strlen(PLAYER_INI()->videosink_element_evas) > 0)
3542 videosink_element = PLAYER_INI()->videosink_element_evas;
3546 case MM_DISPLAY_SURFACE_NULL:
3547 if (strlen(PLAYER_INI()->videosink_element_fake) > 0)
3548 videosink_element = PLAYER_INI()->videosink_element_fake;
3553 debug_error("unidentified surface type");
3557 if (use_multi_surface)
3559 if ( (strlen(PLAYER_INI()->videosink_element_x) > 0 ) && (strlen(PLAYER_INI()->videosink_element_evas) > 0 ) )
3561 /* create elements for multi sink usage */
3562 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_TEE, "tee", "tee", TRUE);
3563 debug_log("using tee");
3567 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_CONV, vconv_factory, "video converter", TRUE);
3568 debug_log("using video converter: %s", vconv_factory);
3571 if (PLAYER_INI()->video_surface == MM_DISPLAY_SURFACE_X)
3573 videosink_element_ext = PLAYER_INI()->videosink_element_evas;
3574 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK_EXT, videosink_element_ext, "videosink_ext_evas", TRUE);
3576 else if (PLAYER_INI()->video_surface == MM_DISPLAY_SURFACE_EVAS)
3578 videosink_element_ext = PLAYER_INI()->videosink_element_x;
3579 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK_EXT, videosink_element_ext, "videosink_ext_x", TRUE);
3583 debug_error("not normal case..multi-surface mode is only available with X and EVAS surface");
3586 debug_log("selected videosink_ext name: %s", videosink_element_ext);
3589 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_element, "videosink", TRUE);
3590 debug_log("selected videosink name: %s", videosink_element);
3593 if ( _mmplayer_update_video_param(player) != MM_ERROR_NONE)
3597 g_object_set (G_OBJECT (videobin[MMPLAYER_V_SINK].gst), "qos", TRUE, NULL);
3599 if (use_multi_surface)
3601 g_object_set (G_OBJECT (videobin[MMPLAYER_V_SINK_EXT].gst), "qos", TRUE, NULL);
3602 g_object_set (G_OBJECT (videobin[MMPLAYER_V_SINK].gst), "async", FALSE, NULL);
3603 g_object_set (G_OBJECT (videobin[MMPLAYER_V_SINK_EXT].gst), "async", FALSE, NULL);
3606 /* store it as it's sink element */
3607 __mmplayer_add_sink( player, videobin[MMPLAYER_V_SINK].gst );
3608 if (use_multi_surface)
3610 __mmplayer_add_sink( player, videobin[MMPLAYER_V_SINK_EXT].gst );
3613 /* adding created elements to bin */
3614 if( ! __mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket) )
3616 debug_error("failed to add elements\n");
3620 if (!use_multi_surface)
3622 /* Linking elements in the bucket by added order */
3623 if ( __mmplayer_gst_element_link_bucket(element_bucket) == -1 )
3625 debug_error("failed to link elements\n");
3633 for (i = 0 ; i < 2 ; i++)
3637 sinkpad = gst_element_get_static_pad (videobin[MMPLAYER_V_SINK+i].gst, "sink");
3638 debug_log("do not need vconv");
3642 if (PLAYER_INI()->video_surface == MM_DISPLAY_SURFACE_X)
3646 sinkpad = gst_element_get_static_pad (videobin[MMPLAYER_V_SINK].gst, "sink");
3650 sinkpad = gst_element_get_static_pad (videobin[MMPLAYER_V_CONV].gst, "sink");
3651 GST_ELEMENT_LINK(GST_ELEMENT(videobin[MMPLAYER_V_CONV].gst), GST_ELEMENT(videobin[MMPLAYER_V_SINK_EXT].gst));
3658 sinkpad = gst_element_get_static_pad (videobin[MMPLAYER_V_CONV].gst, "sink");
3659 GST_ELEMENT_LINK(GST_ELEMENT(videobin[MMPLAYER_V_CONV].gst), GST_ELEMENT(videobin[MMPLAYER_V_SINK].gst));
3663 sinkpad = gst_element_get_static_pad (videobin[MMPLAYER_V_SINK_EXT].gst, "sink");
3667 player->tee_src_pad[i] = gst_element_get_request_pad (videobin[MMPLAYER_V_TEE].gst, "src%d");
3668 if (gst_pad_link (player->tee_src_pad[i], sinkpad) != GST_PAD_LINK_OK) {
3669 debug_error("failed to link tee element with sink element(%d)",i);
3672 gst_object_unref (sinkpad);
3676 /* get first element's sinkpad for creating ghostpad */
3677 first_element = (MMPlayerGstElement *)element_bucket->data;
3678 if ( !first_element )
3680 debug_error("failed to get first element from bucket\n");
3684 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3687 debug_error("failed to get pad from first element\n");
3691 /* create ghostpad */
3692 if ( FALSE == gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, gst_ghost_pad_new("sink", pad)) )
3694 debug_error("failed to add ghostpad to videobin\n");
3697 gst_object_unref(pad);
3699 /* done. free allocated variables */
3700 g_list_free(element_bucket);
3702 mm_attrs_set_int_by_name(attrs, "content_video_found", TRUE);
3703 if ( mmf_attrs_commit ( attrs ) ) /* return -1 if error */
3704 debug_error("failed to commit attribute ""content_video_found"".\n");
3708 return MM_ERROR_NONE;
3711 debug_error("ERROR : releasing videobin\n");
3713 g_list_free( element_bucket );
3716 gst_object_unref(GST_OBJECT(pad));
3718 /* release videobin with it's childs */
3719 if ( videobin[MMPLAYER_V_BIN].gst )
3721 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3725 MMPLAYER_FREEIF( videobin );
3727 player->pipeline->videobin = NULL;
3729 return MM_ERROR_PLAYER_INTERNAL;
3732 static int __mmplayer_gst_create_text_pipeline(mm_player_t* player)
3734 MMPlayerGstElement* first_element = NULL;
3735 MMPlayerGstElement* textbin = NULL;
3736 GList* element_bucket = NULL;
3738 GstPad *ghostpad = NULL;
3743 return_val_if_fail( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
3746 textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
3749 debug_error("failed to allocate memory for textbin\n");
3750 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3754 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3755 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3756 if ( !textbin[MMPLAYER_T_BIN].gst )
3758 debug_critical("failed to create textbin\n");
3763 player->pipeline->textbin = textbin;
3766 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_SINK, "fakesink", "text_sink", TRUE);
3768 g_object_set (G_OBJECT (textbin[MMPLAYER_T_SINK].gst), "sync", TRUE, NULL);
3769 g_object_set (G_OBJECT (textbin[MMPLAYER_T_SINK].gst), "async", FALSE, NULL);
3770 g_object_set (G_OBJECT (textbin[MMPLAYER_T_SINK].gst), "signal-handoffs", TRUE, NULL);
3772 MMPLAYER_SIGNAL_CONNECT( player,
3773 G_OBJECT(textbin[MMPLAYER_T_SINK].gst),
3775 G_CALLBACK(__mmplayer_update_subtitle),
3778 __mmplayer_add_sink (player, GST_ELEMENT(textbin[MMPLAYER_T_SINK].gst));
3780 /* adding created elements to bin */
3781 debug_log("adding created elements to bin\n");
3782 if( !__mmplayer_gst_element_add_bucket_to_bin( GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket ))
3784 debug_error("failed to add elements\n");
3788 /* linking elements in the bucket by added order. */
3789 debug_log("Linking elements in the bucket by added order.\n");
3790 if ( __mmplayer_gst_element_link_bucket(element_bucket) == -1 )
3792 debug_error("failed to link elements\n");
3796 /* get first element's sinkpad for creating ghostpad */
3797 first_element = (MMPlayerGstElement *)element_bucket->data;
3799 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3802 debug_error("failed to get pad from first element of textbin\n");
3806 ghostpad = gst_ghost_pad_new("sink", pad);
3809 debug_error("failed to create ghostpad\n");
3813 if ( FALSE == gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad) )
3815 debug_error("failed to add ghostpad to textbin\n");
3819 gst_object_unref(pad);
3822 /* done. free allocated variables */
3823 g_list_free(element_bucket);
3827 return MM_ERROR_NONE;
3831 debug_log("ERROR : releasing textbin\n");
3834 gst_object_unref(GST_OBJECT(pad));
3837 gst_object_unref(GST_OBJECT(ghostpad));
3839 g_list_free( element_bucket );
3842 /* release element which are not added to bin */
3843 for ( i = 1; i < MMPLAYER_T_NUM; i++ ) /* NOTE : skip bin */
3845 if ( textbin[i].gst )
3847 GstObject* parent = NULL;
3848 parent = gst_element_get_parent( textbin[i].gst );
3852 gst_object_unref(GST_OBJECT(textbin[i].gst));
3853 textbin[i].gst = NULL;
3857 gst_object_unref(GST_OBJECT(parent));
3862 /* release textbin with it's childs */
3863 if ( textbin[MMPLAYER_T_BIN].gst )
3865 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3868 MMPLAYER_FREEIF( textbin );
3870 player->pipeline->textbin = NULL;
3872 return MM_ERROR_PLAYER_INTERNAL;
3877 __mmplayer_gst_create_subtitle_pipeline(mm_player_t* player)
3880 MMPlayerGstElement* subtitlebin = NULL;
3881 MMHandleType attrs = 0;
3882 gchar *subtitle_uri =NULL;
3883 GList*element_bucket = NULL;
3885 #define USE_MESSAGE_FOR_PLAYING_SUBTITLE
3886 #ifndef USE_MESSAGE_FOR_PLAYING_SUBTITLE
3888 gint width =0, height = 0;
3889 gboolean silent=FALSE;
3895 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3897 attrs = MMPLAYER_GET_ATTRS(player);
3900 debug_error("cannot get content attribute\n");
3901 return MM_ERROR_PLAYER_INTERNAL;
3904 mm_attrs_get_string_by_name ( attrs, "subtitle_uri", &subtitle_uri );
3905 if ( !subtitle_uri || strlen(subtitle_uri) < 1)
3907 debug_error("subtitle uri is not proper filepath.\n");
3908 return MM_ERROR_PLAYER_INVALID_URI;
3910 debug_log("subtitle file path is [%s].\n", subtitle_uri);
3914 subtitlebin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_SUB_NUM);
3917 debug_error("failed to allocate memory\n");
3918 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3922 subtitlebin[MMPLAYER_SUB_PIPE].id = MMPLAYER_SUB_PIPE;
3923 subtitlebin[MMPLAYER_SUB_PIPE].gst = gst_pipeline_new("subtitlebin");
3924 if ( !subtitlebin[MMPLAYER_SUB_PIPE].gst )
3926 debug_error("failed to create text pipeline\n");
3929 player->pipeline->subtitlebin = subtitlebin;
3931 /* create the text file source */
3932 MMPLAYER_CREATE_ELEMENT(subtitlebin, MMPLAYER_SUB_SRC, "filesrc", "subtitle_source", TRUE);
3933 g_object_set(G_OBJECT (subtitlebin[MMPLAYER_SUB_SRC].gst), "location", subtitle_uri, NULL);
3936 MMPLAYER_CREATE_ELEMENT(subtitlebin, MMPLAYER_SUB_QUEUE, "queue", NULL, TRUE);
3939 MMPLAYER_CREATE_ELEMENT(subtitlebin, MMPLAYER_SUB_SUBPARSE, "subparse", "subtitle_parser", TRUE);
3941 #ifndef USE_MESSAGE_FOR_PLAYING_SUBTITLE
3943 MMPLAYER_CREATE_ELEMENT(subtitlebin, MMPLAYER_SUB_TEXTRENDER, "textrender", "subtitle_render", TRUE);
3945 mm_attrs_get_int_by_name(attrs,"width", &width);
3946 mm_attrs_get_int_by_name(attrs,"height", &height);
3947 mm_attrs_get_int_by_name(attrs,"silent", &silent);
3948 g_object_set ( G_OBJECT (subtitlebin[MMPLAYER_SUB_TEXTRENDER].gst),"width", width, NULL);
3949 g_object_set ( G_OBJECT (subtitlebin[MMPLAYER_SUB_TEXTRENDER].gst),"height", height, NULL);
3950 g_object_set ( G_OBJECT (subtitlebin[MMPLAYER_SUB_TEXTRENDER].gst),"silent", silent, NULL);
3952 debug_log ( "subtitle winow size is [%dX%d].\n", width, height );
3953 debug_log ( "subtitle silent is [%d].\n", silent );
3956 MMPLAYER_CREATE_ELEMENT(subtitlebin, MMPLAYER_SUB_CONV1, "ffmpegcolorspace", "subtitle_converter1", TRUE);
3959 MMPLAYER_CREATE_ELEMENT(subtitlebin, MMPLAYER_SUB_FLIP, "videoflip", "subtitle_fliper", TRUE);
3962 MMPLAYER_CREATE_ELEMENT(subtitlebin, MMPLAYER_SUB_CONV2, "ffmpegcolorspace", "subtitle_converter2", TRUE);
3965 MMPLAYER_CREATE_ELEMENT(subtitlebin, MMPLAYER_SUB_SINK, "ximagesink", "subtitle_sink", TRUE);
3967 mm_attrs_get_data_by_name(attrs, "xid", &xid);
3970 debug_log("setting subtitle xid = %d\n", *(int*)xid);
3971 gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(subtitlebin[MMPLAYER_SUB_SINK].gst), *(int*)xid);
3975 /* FIXIT : is it error case? */
3976 debug_warning("still we don't have xid on player attribute. create it's own surface.\n");
3980 MMPLAYER_CREATE_ELEMENT(subtitlebin, MMPLAYER_SUB_SINK, "fakesink", "subtitle_sink", TRUE);
3982 g_object_set (G_OBJECT (subtitlebin[MMPLAYER_SUB_SINK].gst), "sync", TRUE, NULL);
3983 g_object_set (G_OBJECT (subtitlebin[MMPLAYER_SUB_SINK].gst), "async", FALSE, NULL);
3984 g_object_set (G_OBJECT (subtitlebin[MMPLAYER_SUB_SINK].gst), "signal-handoffs", TRUE, NULL);
3986 MMPLAYER_SIGNAL_CONNECT( player,
3987 G_OBJECT(subtitlebin[MMPLAYER_SUB_SINK].gst),
3989 G_CALLBACK(__mmplayer_update_subtitle),
3993 /* adding created elements to bin */
3994 if( ! __mmplayer_gst_element_add_bucket_to_bin(GST_BIN(subtitlebin[MMPLAYER_SUB_PIPE].gst), element_bucket) )
3996 debug_error("failed to add elements\n");
4000 /* Linking elements in the bucket by added order */
4001 if ( __mmplayer_gst_element_link_bucket(element_bucket) == -1 )
4003 debug_error("failed to link elements\n");
4007 /* done. free allocated variables */
4008 g_list_free(element_bucket);
4010 player->play_subtitle = TRUE;
4014 return MM_ERROR_NONE;
4018 debug_error("ERROR : releasing text pipeline\n");
4020 g_list_free( element_bucket );
4022 /* release subtitlebin with it's childs */
4023 if ( subtitlebin[MMPLAYER_SUB_PIPE].gst )
4025 gst_object_unref(GST_OBJECT(subtitlebin[MMPLAYER_SUB_PIPE].gst));
4028 MMPLAYER_FREEIF( subtitlebin );
4030 player->pipeline->subtitlebin = NULL;
4032 return MM_ERROR_PLAYER_INTERNAL;
4036 __mmplayer_update_subtitle( GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4038 mm_player_t* player = (mm_player_t*) data;
4039 MMMessageParamType msg = {0, };
4040 GstClockTime duration = 0;
4041 guint8 *text = NULL;
4042 gboolean ret = TRUE;
4046 return_val_if_fail ( player, FALSE );
4047 return_val_if_fail ( buffer, FALSE );
4049 text = GST_BUFFER_DATA(buffer);
4050 duration = GST_BUFFER_DURATION(buffer);
4052 if ( player->is_subtitle_off )
4054 debug_log("subtitle is OFF.\n" );
4060 debug_log("There is no subtitle to be displayed.\n" );
4064 msg.data = (void *) text;
4065 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4067 debug_warning("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data );
4069 MMPLAYER_POST_MSG( player, MM_MESSAGE_UPDATE_SUBTITLE, &msg );
4077 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
4079 GstEvent* event = NULL;
4080 gint64 current_pos = 0;
4081 gint64 adusted_pos = 0;
4082 gboolean ret = TRUE;
4086 /* check player and subtitlebin are created */
4087 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
4088 return_val_if_fail ( MMPLAYER_PLAY_SUBTITLE(player), MM_ERROR_PLAYER_NOT_INITIALIZED );
4092 debug_log("adjusted values is 0, no need to adjust subtitle position.\n");
4093 return MM_ERROR_NONE;
4098 case MM_PLAYER_POS_FORMAT_TIME:
4100 /* check current postion */
4101 ret = gst_element_query_position( GST_ELEMENT(player->pipeline->subtitlebin[MMPLAYER_SUB_PIPE].gst), &format, ¤t_pos );
4104 debug_warning("fail to query current postion.\n");
4105 return MM_ERROR_PLAYER_SEEK;
4109 adusted_pos = current_pos + ((gint64)position * G_GINT64_CONSTANT(1000000));
4110 if (adusted_pos < 0)
4111 adusted_pos = G_GINT64_CONSTANT(0);
4112 debug_log("adjust subtitle postion : %lu -> %lu [msec]\n", GST_TIME_AS_MSECONDS(current_pos), GST_TIME_AS_MSECONDS(adusted_pos));
4115 event = gst_event_new_seek (1.0, GST_FORMAT_TIME,
4116 ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ),
4117 GST_SEEK_TYPE_SET, adusted_pos,
4118 GST_SEEK_TYPE_SET, -1);
4122 case MM_PLAYER_POS_FORMAT_PERCENT:
4124 debug_warning("percent format is not supported yet.\n");
4125 return MM_ERROR_INVALID_ARGUMENT;
4131 debug_warning("invalid format.\n");
4132 return MM_ERROR_INVALID_ARGUMENT;
4136 /* keep ref to the event */
4137 gst_event_ref (event);
4139 debug_log("sending event[%s] to sink element [%s]\n",
4140 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(player->pipeline->subtitlebin[MMPLAYER_SUB_SINK].gst) );
4142 if ( ret = gst_element_send_event (player->pipeline->subtitlebin[MMPLAYER_SUB_SINK].gst, event) )
4144 debug_log("sending event[%s] to sink element [%s] success!\n",
4145 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(player->pipeline->subtitlebin[MMPLAYER_SUB_SINK].gst) );
4148 /* unref to the event */
4149 gst_event_unref (event);
4154 return MM_ERROR_NONE;
4159 __gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data) // @
4161 GstElement *appsrc = element;
4162 tBuffer *buf = (tBuffer *)user_data;
4163 GstBuffer *buffer = NULL;
4164 GstFlowReturn ret = GST_FLOW_OK;
4167 return_if_fail ( element );
4168 return_if_fail ( buf );
4170 buffer = gst_buffer_new ();
4172 if (buf->offset >= buf->len)
4174 debug_log("call eos appsrc\n");
4175 g_signal_emit_by_name (appsrc, "end-of-stream", &ret);
4179 if ( buf->len - buf->offset < size)
4181 len = buf->len - buf->offset + buf->offset;
4184 GST_BUFFER_DATA(buffer) = (guint8*)(buf->buf + buf->offset);
4185 GST_BUFFER_SIZE(buffer) = len;
4186 GST_BUFFER_OFFSET(buffer) = buf->offset;
4187 GST_BUFFER_OFFSET_END(buffer) = buf->offset + len;
4189 debug_log("feed buffer %p, offset %u-%u length %u\n", buffer, buf->offset, buf->len,len);
4190 g_signal_emit_by_name (appsrc, "push-buffer", buffer, &ret);
4196 __gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data) // @
4198 tBuffer *buf = (tBuffer *)user_data;
4200 return_val_if_fail ( buf, FALSE );
4202 buf->offset = (int)size;
4208 __gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data) // @
4210 mm_player_t *player = (mm_player_t*)user_data;
4212 return_if_fail ( player );
4214 debug_msg("app-src: feed data\n");
4216 if(player->need_data_cb)
4217 player->need_data_cb(size, player->buffer_cb_user_param);
4221 __gst_appsrc_seek_data(GstElement *element, guint64 offset, gpointer user_data) // @
4223 mm_player_t *player = (mm_player_t*)user_data;
4225 return_val_if_fail ( player, FALSE );
4227 debug_msg("app-src: seek data\n");
4229 if(player->seek_data_cb)
4230 player->seek_data_cb(offset, player->buffer_cb_user_param);
4237 __gst_appsrc_enough_data(GstElement *element, gpointer user_data) // @
4239 mm_player_t *player = (mm_player_t*)user_data;
4241 return_val_if_fail ( player, FALSE );
4243 debug_msg("app-src: enough data:%p\n", player->enough_data_cb);
4245 if(player->enough_data_cb)
4246 player->enough_data_cb(player->buffer_cb_user_param);
4252 _mmplayer_push_buffer(MMHandleType hplayer, unsigned char *buf, int size) // @
4254 mm_player_t* player = (mm_player_t*)hplayer;
4255 GstBuffer *buffer = NULL;
4256 GstFlowReturn gst_ret = GST_FLOW_OK;
4257 int ret = MM_ERROR_NONE;
4261 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
4263 /* check current state */
4264 // MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_START );
4267 /* NOTE : we should check and create pipeline again if not created as we destroy
4268 * whole pipeline when stopping in streamming playback
4270 if ( ! player->pipeline )
4272 if ( MM_ERROR_NONE != __gst_realize( player ) )
4274 debug_error("failed to realize before starting. only in streamming\n");
4275 return MM_ERROR_PLAYER_INTERNAL;
4279 debug_msg("app-src: pushing data\n");
4283 debug_error("buf is null\n");
4284 return MM_ERROR_NONE;
4287 buffer = gst_buffer_new ();
4291 debug_log("call eos appsrc\n");
4292 g_signal_emit_by_name (player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "end-of-stream", &gst_ret);
4293 return MM_ERROR_NONE;
4296 GST_BUFFER_DATA(buffer) = (guint8*)(buf);
4297 GST_BUFFER_SIZE(buffer) = size;
4299 debug_log("feed buffer %p, length %u\n", buf, size);
4300 g_signal_emit_by_name (player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "push-buffer", buffer, &gst_ret);
4307 static GstBusSyncReply
4308 __mmplayer_bus_sync_callback (GstBus * bus, GstMessage * message, gpointer data)
4310 mm_player_t *player = (mm_player_t *)data;
4311 GstElement *sender = (GstElement *) GST_MESSAGE_SRC (message);
4312 const gchar *name = gst_element_get_name (sender);
4314 switch (GST_MESSAGE_TYPE (message))
4316 case GST_MESSAGE_TAG:
4317 __mmplayer_gst_extract_tag_from_msg(player, message);
4320 case GST_MESSAGE_DURATION:
4321 if (MMPLAYER_IS_STREAMING(player))
4326 gst_message_parse_duration (message, &format, &bytes);
4327 if (format == GST_FORMAT_BYTES)
4329 debug_log("data total size of http content: %lld", bytes);
4330 player->http_content_size = bytes;
4335 player->need_update_content_attrs = TRUE;
4336 _mmplayer_update_content_attrs(player);
4339 return GST_BUS_PASS;
4342 debug_log("GST_MESSAGE_TAG from %s", name);
4343 gst_message_unref (message);
4345 return GST_BUS_DROP;
4349 * This function is to create audio or video pipeline for playing.
4351 * @param player [in] handle of player
4353 * @return This function returns zero on success.
4358 __mmplayer_gst_create_pipeline(mm_player_t* player) // @
4361 MMPlayerGstElement *mainbin = NULL;
4362 MMHandleType attrs = 0;
4363 GstElement* element = NULL;
4364 GList* element_bucket = NULL;
4365 gboolean need_state_holder = TRUE;
4370 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4372 /* get profile attribute */
4373 attrs = MMPLAYER_GET_ATTRS(player);
4376 debug_error("cannot get content attribute\n");
4380 /* create pipeline handles */
4381 if ( player->pipeline )
4383 debug_warning("pipeline should be released before create new one\n");
4387 player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0( sizeof(MMPlayerGstPipelineInfo) );
4388 if (player->pipeline == NULL)
4391 memset( player->pipeline, 0, sizeof(MMPlayerGstPipelineInfo) );
4394 /* create mainbin */
4395 mainbin = (MMPlayerGstElement*) g_malloc0( sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM );
4396 if (mainbin == NULL)
4399 memset( mainbin, 0, sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
4402 /* create pipeline */
4403 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4404 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4405 if ( ! mainbin[MMPLAYER_M_PIPE].gst )
4407 debug_error("failed to create pipeline\n");
4412 /* create source element */
4413 switch ( player->profile.uri_type )
4415 /* rtsp streamming */
4416 case MM_PLAYER_URI_TYPE_URL_RTSP:
4418 gint udp_timeout, network_bandwidth;
4419 gchar *user_agent, *wap_profile;
4421 element = gst_element_factory_make(PLAYER_INI()->name_of_rtspsrc, "streaming_source");
4425 debug_critical("failed to create streaming source element\n");
4429 debug_log("using streamming source [%s].\n", PLAYER_INI()->name_of_rtspsrc);
4432 udp_timeout = network_bandwidth = 0;
4433 user_agent = wap_profile = NULL;
4436 mm_attrs_get_int_by_name ( attrs,"streaming_udp_timeout", &udp_timeout );
4437 mm_attrs_get_string_by_name ( attrs, "streaming_user_agent", &user_agent );
4438 mm_attrs_get_string_by_name ( attrs,"streaming_wap_profile", &wap_profile );
4439 mm_attrs_get_int_by_name ( attrs, "streaming_network_bandwidth", &network_bandwidth );
4441 debug_log("setting streaming source ----------------\n");
4442 debug_log("udp_timeout : %d\n", udp_timeout);
4443 debug_log("user_agent : %s\n", user_agent);
4444 debug_log("wap_profile : %s\n", wap_profile);
4445 debug_log("network_bandwidth : %d\n", network_bandwidth);
4446 debug_log("buffering time : %d\n", PLAYER_INI()->rtsp_buffering_time);
4447 debug_log("rebuffering time : %d\n", PLAYER_INI()->rtsp_rebuffering_time);
4448 debug_log("-----------------------------------------\n");
4450 /* setting property to streaming source */
4451 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
4452 g_object_set(G_OBJECT(element), "timeout", udp_timeout, NULL);
4453 g_object_set(G_OBJECT(element), "bandwidth", network_bandwidth, NULL);
4454 g_object_set(G_OBJECT(element), "buffering_time", PLAYER_INI()->rtsp_buffering_time, NULL);
4455 g_object_set(G_OBJECT(element), "rebuffering_time", PLAYER_INI()->rtsp_rebuffering_time, NULL);
4457 g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL);
4459 g_object_set(G_OBJECT(element), "wap_profile", wap_profile, NULL);
4461 MMPLAYER_SIGNAL_CONNECT ( player, G_OBJECT(element), "pad-added",
4462 G_CALLBACK (__mmplayer_gst_rtp_dynamic_pad), player );
4463 MMPLAYER_SIGNAL_CONNECT ( player, G_OBJECT(element), "no-more-pads",
4464 G_CALLBACK (__mmplayer_gst_rtp_no_more_pads), player );
4466 player->no_more_pad = FALSE;
4467 player->num_dynamic_pad = 0;
4469 /* NOTE : we cannot determine it yet. this filed will be filled by
4470 * _mmplayer_update_content_attrs() after START.
4472 player->streaming_type = STREAMING_SERVICE_NONE;
4477 case MM_PLAYER_URI_TYPE_URL_HTTP:
4479 gchar *user_agent, *proxy, *cookies, **cookie_list;
4480 user_agent = proxy = cookies = NULL;
4482 gint mode = MM_PLAYER_PD_MODE_NONE;
4484 mm_attrs_get_int_by_name ( attrs, "pd_mode", &mode );
4486 player->pd_mode = mode;
4488 debug_log("http playback, PD mode : %d\n", player->pd_mode);
4490 if ( ! MMPLAYER_IS_HTTP_PD(player) )
4492 element = gst_element_factory_make(PLAYER_INI()->name_of_httpsrc, "http_streaming_source");
4495 debug_critical("failed to create http streaming source element[%s].\n", PLAYER_INI()->name_of_httpsrc);
4498 debug_log("using http streamming source [%s].\n", PLAYER_INI()->name_of_httpsrc);
4501 mm_attrs_get_string_by_name ( attrs, "streaming_cookie", &cookies );
4502 mm_attrs_get_string_by_name ( attrs, "streaming_user_agent", &user_agent );
4503 mm_attrs_get_string_by_name ( attrs, "streaming_proxy", &proxy );
4506 debug_log("setting http streaming source ----------------\n");
4507 debug_log("location : %s\n", player->profile.uri);
4508 debug_log("cookies : %s\n", cookies);
4509 debug_log("proxy : %s\n", proxy);
4510 debug_log("user_agent : %s\n", user_agent);
4511 debug_log("timeout : %d\n", PLAYER_INI()->http_timeout);
4512 debug_log("-----------------------------------------\n");
4514 /* setting property to streaming source */
4515 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
4516 g_object_set(G_OBJECT(element), "timeout", PLAYER_INI()->http_timeout, NULL);
4517 /* check if prosy is vailid or not */
4518 if ( util_check_valid_url ( proxy ) )
4519 g_object_set(G_OBJECT(element), "proxy", proxy, NULL);
4520 /* parsing cookies */
4521 if ( ( cookie_list = util_get_cookie_list ((const char*)cookies) ) )
4522 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
4524 g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL);
4526 else // progressive download
4528 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
4532 mm_attrs_get_string_by_name ( attrs, "pd_location", &path );
4534 MMPLAYER_FREEIF(player->pd_file_location);
4536 debug_log("PD Location : %s\n", path);
4540 player->pd_file_location = g_strdup(path);
4544 debug_error("can't find pd location so, it should be set \n");
4545 return MM_ERROR_PLAYER_FILE_NOT_FOUND;
4549 element = gst_element_factory_make("pdpushsrc", "PD pushsrc");
4552 debug_critical("failed to create PD push source element[%s].\n", "pdpushsrc");
4556 g_object_set(G_OBJECT(element), "location", player->pd_file_location, NULL);
4559 player->streaming_type = STREAMING_SERVICE_NONE;
4564 case MM_PLAYER_URI_TYPE_FILE:
4566 char* drmsrc = PLAYER_INI()->name_of_drmsrc;
4568 debug_log("using [%s] for 'file://' handler.\n", drmsrc);
4570 element = gst_element_factory_make(drmsrc, "source");
4573 debug_critical("failed to create %s\n", drmsrc);
4577 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
4578 //g_object_set(G_OBJECT(element), "use-mmap", TRUE, NULL);
4582 #ifdef NO_USE_GST_HLSDEMUX
4583 case MM_PLAYER_URI_TYPE_HLS:
4585 guint64 stream_type = GST_APP_STREAM_TYPE_STREAM;
4587 debug_log("hsl src is selected\n");
4589 element = gst_element_factory_make("appsrc", "hls-source");
4592 debug_critical("failed to create appsrc element\n");
4595 g_object_set( element, "stream-type", stream_type, NULL );
4597 // TODO: need to set time based limit instead of bytes (or) remove constraint.... need to investigate more
4598 g_object_set( element, "max-bytes", 500000, NULL ); // Naveen made queue as un-limited
4603 case MM_PLAYER_URI_TYPE_BUFF:
4605 guint64 stream_type = GST_APP_STREAM_TYPE_STREAM;
4607 debug_log("mem src is selected\n");
4609 element = gst_element_factory_make("appsrc", "buff-source");
4612 debug_critical("failed to create appsrc element\n");
4616 g_object_set( element, "stream-type", stream_type, NULL );
4617 //g_object_set( element, "size", player->mem_buf.len, NULL );
4618 //g_object_set( element, "blocksize", (guint64)20480, NULL );
4620 MMPLAYER_SIGNAL_CONNECT( player, element, "seek-data",
4621 G_CALLBACK(__gst_appsrc_seek_data), player);
4622 MMPLAYER_SIGNAL_CONNECT( player, element, "need-data",
4623 G_CALLBACK(__gst_appsrc_feed_data), player);
4624 MMPLAYER_SIGNAL_CONNECT( player, element, "enough-data",
4625 G_CALLBACK(__gst_appsrc_enough_data), player);
4630 case MM_PLAYER_URI_TYPE_MEM:
4632 guint64 stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
4634 debug_log("mem src is selected\n");
4636 element = gst_element_factory_make("appsrc", "mem-source");
4639 debug_critical("failed to create appsrc element\n");
4643 g_object_set( element, "stream-type", stream_type, NULL );
4644 g_object_set( element, "size", player->mem_buf.len, NULL );
4645 g_object_set( element, "blocksize", (guint64)20480, NULL );
4647 MMPLAYER_SIGNAL_CONNECT( player, element, "seek-data",
4648 G_CALLBACK(__gst_appsrc_seek_data_mem), &player->mem_buf );
4649 MMPLAYER_SIGNAL_CONNECT( player, element, "need-data",
4650 G_CALLBACK(__gst_appsrc_feed_data_mem), &player->mem_buf );
4653 case MM_PLAYER_URI_TYPE_URL:
4656 case MM_PLAYER_URI_TYPE_TEMP:
4659 case MM_PLAYER_URI_TYPE_NONE:
4664 /* check source element is OK */
4667 debug_critical("no source element was created.\n");
4671 /* take source element */
4672 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4673 mainbin[MMPLAYER_M_SRC].gst = element;
4674 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
4676 if (MMPLAYER_IS_STREAMING(player) || (player->profile.uri_type == MM_PLAYER_URI_TYPE_HLS))
4678 player->streamer = __mm_player_streaming_create();
4679 __mm_player_streaming_initialize(player->streamer);
4682 if ( player->profile.uri_type == MM_PLAYER_URI_TYPE_HLS )
4684 debug_log ("adding appsrc's pad probe...\n");
4686 pad = gst_element_get_static_pad(mainbin[MMPLAYER_M_SRC].gst, "src" );
4688 /* register probe */
4689 ahs_appsrc_cb_probe_id = gst_pad_add_buffer_probe (pad,
4690 G_CALLBACK (__mmplayer_ahs_appsrc_probe), player);
4692 gst_object_unref(pad);
4696 if ( MMPLAYER_IS_HTTP_PD(player) )
4698 debug_log ("Picked queue2 element....\n");
4699 element = gst_element_factory_make("queue2", "hls_stream_buffer");
4702 debug_critical ( "failed to create http streaming buffer element\n" );
4707 mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_S_BUFFER;
4708 mainbin[MMPLAYER_M_S_BUFFER].gst = element;
4709 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_S_BUFFER]);
4711 __mm_player_streaming_set_buffer(player->streamer,
4714 PLAYER_INI()->http_max_size_bytes,
4716 PLAYER_INI()->http_buffering_limit,
4717 PLAYER_INI()->http_buffering_time,
4723 /* create autoplugging element if src element is not a streamming src */
4724 if ( player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_RTSP )
4728 if( PLAYER_INI()->use_decodebin )
4730 /* create decodebin */
4731 element = gst_element_factory_make("decodebin", "decodebin");
4733 g_object_set(G_OBJECT(element), "async-handling", TRUE, NULL);
4735 /* set signal handler */
4736 MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(element), "new-decoded-pad",
4737 G_CALLBACK(__mmplayer_gst_decode_callback), player);
4739 /* we don't need state holder, bcz decodebin is doing well by itself */
4740 need_state_holder = FALSE;
4744 element = gst_element_factory_make("typefind", "typefinder");
4745 MMPLAYER_SIGNAL_CONNECT( player, element, "have-type",
4746 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player );
4749 /* check autoplug element is OK */
4752 debug_critical("can not create autoplug element\n");
4756 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
4757 mainbin[MMPLAYER_M_AUTOPLUG].gst = element;
4759 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_AUTOPLUG]);
4763 /* add elements to pipeline */
4764 if( !__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket))
4766 debug_error("Failed to add elements to pipeline\n");
4771 /* linking elements in the bucket by added order. */
4772 if ( __mmplayer_gst_element_link_bucket(element_bucket) == -1 )
4774 debug_error("Failed to link some elements\n");
4779 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4780 if ( need_state_holder )
4783 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4784 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make ("fakesink", "state-holder");
4786 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4788 debug_error ("fakesink element could not be created\n");
4791 GST_OBJECT_FLAG_UNSET (mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_IS_SINK);
4793 /* take ownership of fakesink. we are reusing it */
4794 gst_object_ref( mainbin[MMPLAYER_M_SRC_FAKESINK].gst );
4797 if ( FALSE == gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst),
4798 mainbin[MMPLAYER_M_SRC_FAKESINK].gst) )
4800 debug_error("failed to add fakesink to bin\n");
4805 /* now we have completed mainbin. take it */
4806 player->pipeline->mainbin = mainbin;
4808 /* connect bus callback */
4809 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4812 debug_error ("cannot get bus from pipeline.\n");
4815 player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_callback, player);
4817 /* Note : check whether subtitle atrribute uri is set. If uri is set, then create the text pipeline */
4818 if ( __mmplayer_check_subtitle ( player ) )
4820 debug_log("try to create subtitle pipeline \n");
4822 if ( MM_ERROR_NONE != __mmplayer_gst_create_subtitle_pipeline(player) )
4823 debug_error("fail to create subtitle pipeline")
4825 debug_log("subtitle pipeline is created successfully\n");
4828 /* set sync handler to get tag synchronously */
4829 gst_bus_set_sync_handler(bus, __mmplayer_bus_sync_callback, player);
4833 gst_object_unref(GST_OBJECT(bus));
4834 g_list_free(element_bucket);
4838 return MM_ERROR_NONE;
4842 __mmplayer_gst_destroy_pipeline(player);
4843 g_list_free(element_bucket);
4845 /* release element which are not added to bin */
4846 for ( i = 1; i < MMPLAYER_M_NUM; i++ ) /* NOTE : skip pipeline */
4848 if ( mainbin[i].gst )
4850 GstObject* parent = NULL;
4851 parent = gst_element_get_parent( mainbin[i].gst );
4855 gst_object_unref(GST_OBJECT(mainbin[i].gst));
4856 mainbin[i].gst = NULL;
4860 gst_object_unref(GST_OBJECT(parent));
4865 /* release pipeline with it's childs */
4866 if ( mainbin[MMPLAYER_M_PIPE].gst )
4868 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4871 MMPLAYER_FREEIF( player->pipeline );
4872 MMPLAYER_FREEIF( mainbin );
4874 return MM_ERROR_PLAYER_INTERNAL;
4879 __mmplayer_gst_destroy_pipeline(mm_player_t* player) // @
4882 int ret = MM_ERROR_NONE;
4887 return_val_if_fail ( player, MM_ERROR_INVALID_HANDLE );
4889 /* cleanup stuffs */
4890 MMPLAYER_FREEIF(player->type);
4891 player->have_dynamic_pad = FALSE;
4892 player->no_more_pad = FALSE;
4893 player->num_dynamic_pad = 0;
4894 player->last_position = 0;
4895 player->duration = 0;
4896 player->http_content_size = 0;
4897 player->not_supported_codec = MISSING_PLUGIN_NONE;
4898 player->can_support_codec = FOUND_PLUGIN_NONE;
4899 player->not_found_demuxer = 0;
4900 if (player->v_stream_caps)
4902 gst_caps_unref(player->v_stream_caps);
4903 player->v_stream_caps = NULL;
4906 player->state_lost = FALSE;
4907 player->need_update_content_dur = FALSE;
4909 player->pending_seek.is_pending = FALSE;
4910 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
4911 player->pending_seek.pos = 0;
4913 if (ahs_appsrc_cb_probe_id )
4916 pad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "src" );
4918 gst_pad_remove_buffer_probe (pad, ahs_appsrc_cb_probe_id);
4919 gst_object_unref(pad);
4921 ahs_appsrc_cb_probe_id = 0;
4924 /* free request pads for multi-surface */
4925 if (player->use_multi_surface && player->pipeline && player->pipeline->videobin[MMPLAYER_V_TEE].gst)
4927 for (i = 0 ; i < 2 ; i++)
4929 if (player->tee_src_pad[i])
4931 gst_element_release_request_pad (player->pipeline->videobin[MMPLAYER_V_TEE].gst, player->tee_src_pad[i]);
4932 gst_object_unref(player->tee_src_pad[i]);
4935 player->use_multi_surface = FALSE;
4936 debug_log("release request pads from TEE, and unref TEE's src pads");
4939 if ( player->sink_elements )
4940 g_list_free ( player->sink_elements );
4941 player->sink_elements = NULL;
4943 /* cleanup unlinked mime type */
4944 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4945 MMPLAYER_FREEIF(player->unlinked_video_mime);
4946 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4948 /* cleanup running stuffs */
4949 __mmplayer_cancel_delayed_eos( player );
4951 /* cleanup gst stuffs */
4952 if ( player->pipeline )
4954 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
4955 GstTagList* tag_list = player->pipeline->tag_list;
4956 GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE (mainbin[MMPLAYER_M_PIPE].gst));
4958 /* first we need to disconnect all signal hander */
4959 __mmplayer_release_signal_connection( player );
4961 /* disconnecting bus watch */
4962 if ( player->bus_watcher )
4963 g_source_remove( player->bus_watcher );
4964 player->bus_watcher = 0;
4966 gst_bus_set_sync_handler (bus, NULL, NULL);
4970 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4971 MMPlayerGstElement* videobin = player->pipeline->videobin;
4972 MMPlayerGstElement* textbin = player->pipeline->textbin;
4973 MMPlayerGstElement* subtitlebin = player->pipeline->subtitlebin;
4975 debug_log("pipeline status before set state to NULL\n");
4976 __mmplayer_dump_pipeline_state( player );
4978 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4979 ret = __mmplayer_gst_set_state ( player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout );
4980 if ( ret != MM_ERROR_NONE )
4982 debug_error("fail to change state to NULL\n");
4983 return MM_ERROR_PLAYER_INTERNAL;
4986 debug_log("pipeline status before unrefering pipeline\n");
4987 __mmplayer_dump_pipeline_state( player );
4989 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4992 if ( mainbin[MMPLAYER_M_SRC_FAKESINK].gst )
4993 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4995 /* free avsysaudiosink
4996 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4997 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4999 MMPLAYER_FREEIF( audiobin );
5000 MMPLAYER_FREEIF( videobin );
5001 MMPLAYER_FREEIF( textbin );
5002 MMPLAYER_FREEIF( mainbin );
5006 gst_tag_list_free(tag_list);
5008 MMPLAYER_FREEIF( player->pipeline );
5011 player->pipeline_is_constructed = FALSE;
5018 static int __gst_realize(mm_player_t* player) // @
5021 int ret = MM_ERROR_NONE;
5025 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5027 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
5028 MMPLAYER_PRINT_STATE(player);
5030 __ta__("__mmplayer_gst_create_pipeline",
5031 ret = __mmplayer_gst_create_pipeline(player);
5034 debug_critical("failed to create pipeline\n");
5039 /* set pipeline state to READY */
5040 /* NOTE : state change to READY must be performed sync. */
5041 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5042 ret = __mmplayer_gst_set_state(player,
5043 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
5045 if (MMPLAYER_PLAY_SUBTITLE(player))
5046 ret = __mmplayer_gst_set_state(player,
5047 player->pipeline->subtitlebin[MMPLAYER_SUB_PIPE].gst, GST_STATE_READY, FALSE, timeout);
5049 if ( ret != MM_ERROR_NONE )
5051 /* return error if failed to set state */
5052 debug_error("failed to set state PAUSED (live : READY).\n");
5054 /* dump state of all element */
5055 __mmplayer_dump_pipeline_state( player );
5061 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_READY );
5064 /* create dot before error-return. for debugging */
5065 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-realize" );
5072 static int __gst_unrealize(mm_player_t* player) // @
5074 int ret = MM_ERROR_NONE;
5078 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5080 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
5081 MMPLAYER_PRINT_STATE(player);
5083 player->use_video_stream = FALSE;
5084 player->video_stream_cb = NULL;
5085 player->video_stream_cb_user_param = NULL;
5087 player->audio_stream_cb = NULL;
5088 player->audio_stream_cb_user_param = NULL;
5090 player->audio_buffer_cb = NULL;
5091 player->audio_buffer_cb_user_param = NULL;
5093 player->sent_bos = FALSE;
5094 player->playback_rate = DEFAULT_PLAYBACK_RATE;
5096 /* clean found parsers */
5097 if (player->parsers)
5099 g_list_free(player->parsers);
5100 player->parsers = NULL;
5103 MMPLAYER_FREEIF(player->album_art);
5105 /* destroy pipeline */
5106 ret = __mmplayer_gst_destroy_pipeline( player );
5107 if ( ret != MM_ERROR_NONE )
5109 debug_error("failed to destory pipeline\n");
5114 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_NULL );
5122 static int __gst_pending_seek ( mm_player_t* player )
5124 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
5125 MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
5126 int ret = MM_ERROR_NONE;
5130 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
5132 if ( !player->pending_seek.is_pending )
5134 debug_log("pending seek is not reserved. nothing to do.\n" );
5138 /* check player state if player could pending seek or not. */
5139 current_state = MMPLAYER_CURRENT_STATE(player);
5140 pending_state = MMPLAYER_PENDING_STATE(player);
5142 if ( current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING )
5144 debug_warning("try to pending seek in %s state, try next time. \n",
5145 MMPLAYER_STATE_GET_NAME(current_state));
5149 debug_log("trying to play from (%lu) pending position\n", player->pending_seek.pos);
5151 ret = __gst_set_position ( player, player->pending_seek.format, player->pending_seek.pos );
5153 if ( MM_ERROR_NONE != ret )
5154 debug_error("failed to seek pending postion. just keep staying current position.\n");
5156 player->pending_seek.is_pending = FALSE;
5164 static int __gst_start(mm_player_t* player) // @
5166 gboolean sound_extraction = 0;
5167 gboolean async = FALSE;
5169 int ret = MM_ERROR_NONE;
5173 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
5175 /* get sound_extraction property */
5176 mm_attrs_get_int_by_name(player->attrs, "pcm_extraction", &sound_extraction);
5177 /* NOTE : if SetPosition was called before Start. do it now */
5178 /* streaming doesn't support it. so it should be always sync */
5179 /* !! create one more api to check if there is pending seek rather than checking variables */
5181 if ( (player->pending_seek.is_pending || sound_extraction) && !MMPLAYER_IS_STREAMING(player))
5183 ret = __gst_pause(player, FALSE);
5184 if ( ret != MM_ERROR_NONE )
5186 debug_error("failed to set state to PAUSED for pending seek\n");
5190 if ( sound_extraction )
5192 debug_log("setting pcm extraction\n");
5194 ret = __mmplayer_set_pcm_extraction(player);
5195 if ( MM_ERROR_NONE != ret )
5197 debug_warning("failed to set pcm extraction\n");
5203 if ( MM_ERROR_NONE != __gst_pending_seek(player) )
5205 debug_warning("failed to seek pending postion. starting from the begin of content.\n");
5210 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
5212 MMPLAYER_PRINT_STATE(player);
5214 /* NOTE : note that current variant of rtspsrc has their own buffering mechanism.
5215 * their keeping rtp packets without gst timestamping. there's no easy way to export buffering mechanism to plugin-level. and
5216 * application also not ready. thus, just for now. state transition to PLAYING will done in asyn mode.
5217 * please do not confused with async property hack which done by __gst_set_async_state_change()
5219 /* NOTE : testing async start when local playback also */
5221 mm_attrs_get_int_by_name(player->attrs,"profile_async_start", &async);
5222 debug_log("start mode : %s", (async ? "async" : "sync"));
5224 /* set pipeline state to PLAYING */
5225 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5226 ret = __mmplayer_gst_set_state(player,
5227 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout );
5229 if (MMPLAYER_PLAY_SUBTITLE(player))
5230 ret = __mmplayer_gst_set_state(player,
5231 player->pipeline->subtitlebin[MMPLAYER_SUB_PIPE].gst, GST_STATE_PLAYING, FALSE, timeout );
5233 if (ret == MM_ERROR_NONE)
5238 debug_log("sync state changing is completed");
5240 mm_attrs_get_int_by_name(player->attrs, "content_duration", &duration);
5243 debug_warning("try to update duration more");
5244 player->need_update_content_attrs = TRUE;
5245 player->need_update_content_dur = TRUE;
5246 _mmplayer_update_content_attrs(player);
5249 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
5254 debug_error("failed to set state to PLAYING");
5256 /* dump state of all element */
5257 __mmplayer_dump_pipeline_state( player );
5262 /* FIXIT : analyze so called "async problem" */
5264 __gst_set_async_state_change( player, FALSE );
5266 /* generating debug info before returning error */
5267 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-start" );
5274 static void __mmplayer_do_sound_fadedown(mm_player_t* player, unsigned int time)
5278 return_if_fail(player
5280 && player->pipeline->audiobin
5281 && player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
5283 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", 2, NULL);
5290 static void __mmplayer_undo_sound_fadedown(mm_player_t* player)
5294 return_if_fail(player
5296 && player->pipeline->audiobin
5297 && player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
5299 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", 0, NULL);
5304 static int __gst_stop(mm_player_t* player) // @
5306 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
5307 MMHandleType attrs = 0;
5308 gboolean fadewown = FALSE;
5309 gboolean rewind = FALSE;
5311 int ret = MM_ERROR_NONE;
5315 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5317 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
5318 MMPLAYER_PRINT_STATE(player);
5320 attrs = MMPLAYER_GET_ATTRS(player);
5323 debug_error("cannot get content attribute\n");
5324 return MM_ERROR_PLAYER_INTERNAL;
5327 mm_attrs_get_int_by_name(attrs,"sound_fadedown", &fadewown);
5329 /* enable fadedown */
5331 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
5333 /* Just set state to PAUESED and the rewind. it's usual player behavior. */
5334 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT ( player );
5335 if ( player->profile.uri_type == MM_PLAYER_URI_TYPE_BUFF )
5337 ret = __mmplayer_gst_set_state(player,
5338 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout );
5342 ret = __mmplayer_gst_set_state( player,
5343 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout );
5345 if (MMPLAYER_PLAY_SUBTITLE(player))
5346 ret = __mmplayer_gst_set_state( player,
5347 player->pipeline->subtitlebin[MMPLAYER_SUB_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout );
5349 if ( !MMPLAYER_IS_STREAMING(player))
5353 /* disable fadeout */
5355 __mmplayer_undo_sound_fadedown(player);
5358 /* return if set_state has failed */
5359 if ( ret != MM_ERROR_NONE )
5361 debug_error("failed to set state.\n");
5363 /* dump state of all element. don't care it success or not */
5364 __mmplayer_dump_pipeline_state( player );
5372 if ( ! __gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
5373 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
5374 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE) )
5376 debug_warning("failed to rewind\n");
5377 ret = MM_ERROR_PLAYER_SEEK;
5382 player->sent_bos = FALSE;
5384 /* wait for seek to complete */
5385 change_ret = gst_element_get_state (player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
5386 if (MMPLAYER_PLAY_SUBTITLE(player))
5387 change_ret = gst_element_get_state (player->pipeline->subtitlebin[MMPLAYER_SUB_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
5389 if ( change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL )
5391 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_READY );
5395 debug_error("fail to stop player.\n");
5396 ret = MM_ERROR_PLAYER_INTERNAL;
5399 /* generate dot file if enabled */
5400 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-stop" );
5408 int __gst_pause(mm_player_t* player, gboolean async) // @
5411 int ret = MM_ERROR_NONE;
5415 return_val_if_fail(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5417 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
5418 MMPLAYER_PRINT_STATE(player);
5421 debug_log("do async state transition to PAUSE.\n");
5423 /* set pipeline status to PAUSED */
5424 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5425 ret = __mmplayer_gst_set_state(player,
5426 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, timeout );
5428 if (MMPLAYER_PLAY_SUBTITLE(player))
5429 ret = __mmplayer_gst_set_state(player,
5430 player->pipeline->subtitlebin[MMPLAYER_SUB_PIPE].gst, GST_STATE_PAUSED, async, timeout );
5432 /* NOTE : here we are setting state PAUSED to streaming source element again. because
5433 * main pipeline will not set the state of it's all childs if state of the pipeline
5434 * is already PAUSED for some reason. this situaition can happen when rebuffering or
5435 * buffering after seeking. in both case streaming source will send flush event and then
5436 * sink elements will lost it's state and it will set the state to PAUSED by theyself.
5438 if ( MMPLAYER_IS_RTSP_STREAMING( player ) && player->state_lost )
5440 debug_log("setting PAUSED to streaming source again.\n");
5441 gst_element_set_state(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_STATE_PAUSED);
5444 if ( ret != MM_ERROR_NONE )
5446 debug_error("failed to set state to PAUSED\n");
5448 /* dump state of all element */
5449 __mmplayer_dump_pipeline_state( player );
5455 if ( async == FALSE )
5457 debug_log("sync state changing is completed.");
5458 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_PAUSED );
5462 /* FIXIT : analyze so called "async problem" */
5464 __gst_set_async_state_change( player, TRUE);
5467 /* generate dot file before returning error */
5468 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-pause" );
5475 int __gst_resume(mm_player_t* player, gboolean async) // @
5477 int ret = MM_ERROR_NONE;
5482 return_val_if_fail(player && player->pipeline,
5483 MM_ERROR_PLAYER_NOT_INITIALIZED);
5486 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
5487 MMPLAYER_PRINT_STATE(player);
5489 /* generate dot file before returning error */
5490 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-resume" );
5492 __mmplayer_set_antishock( player , FALSE );
5495 debug_log("do async state transition to PLAYING.\n");
5497 /* set pipeline state to PLAYING */
5498 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5499 ret = __mmplayer_gst_set_state(player,
5500 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout );
5502 if (MMPLAYER_PLAY_SUBTITLE(player))
5503 ret = __mmplayer_gst_set_state(player,
5504 player->pipeline->subtitlebin[MMPLAYER_SUB_PIPE].gst, GST_STATE_PLAYING, async, timeout );
5506 /* NOTE : same reason when pausing */
5507 if ( MMPLAYER_IS_RTSP_STREAMING(player) && player->state_lost )
5509 debug_log("setting PLAYING to streaming source again.\n");
5510 gst_element_set_state(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_STATE_PLAYING);
5513 if (ret != MM_ERROR_NONE)
5515 debug_error("failed to set state to PLAYING\n");
5517 /* dump state of all element */
5518 __mmplayer_dump_pipeline_state( player );
5526 debug_log("sync state changing is completed.");
5527 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_PLAYING );
5531 /* FIXIT : analyze so called "async problem" */
5533 __gst_set_async_state_change( player, FALSE );
5535 /* generate dot file before returning error */
5536 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-resume" );
5544 __gst_set_position(mm_player_t* player, int format, unsigned long position) // @
5546 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
5547 MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
5548 GstFormat fmt = GST_FORMAT_TIME;
5549 unsigned long dur = 0;
5550 gint64 dur_msec = 0;
5551 gint64 pos_msec = 0;
5552 gboolean ret = TRUE;
5556 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
5557 return_val_if_fail ( !MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP );
5559 /* check player state if player could seek or not. */
5560 current_state = MMPLAYER_CURRENT_STATE(player);
5561 pending_state = MMPLAYER_PENDING_STATE(player);
5563 if ( current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_PAUSED )
5566 /* check duration */
5567 /* NOTE : duration cannot be zero except live streaming.
5568 * Since some element could have some timing problemn with quering duration, try again.
5570 if ( player->duration == 0 )
5572 ret = gst_element_query_duration( player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &fmt, &dur_msec );
5576 player->duration = dur_msec;
5579 if ( player->duration )
5581 dur = GST_TIME_AS_MSECONDS(player->duration);
5582 debug_log("duration is %d [msec]. \n", dur);
5586 debug_error("could not get the duration. fail to seek.\n");
5593 case MM_PLAYER_POS_FORMAT_TIME:
5595 /* check position is valid or not */
5596 if ( position > dur )
5599 debug_log("seeking to (%lu) msec\n", position);
5601 if (player->doing_seek)
5603 debug_log("not completed seek");
5604 return MM_ERROR_PLAYER_DOING_SEEK;
5606 player->doing_seek = TRUE;
5608 pos_msec = position * G_GINT64_CONSTANT(1000000);
5609 ret = __gst_seek ( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
5610 GST_FORMAT_TIME, ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ),
5611 GST_SEEK_TYPE_SET, pos_msec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE );
5615 debug_error("failed to set position. dur[%lud] pos[%lud] pos_msec[%llud]\n", dur, position, pos_msec);
5621 case MM_PLAYER_POS_FORMAT_PERCENT:
5623 if ( position < 0 && position > 100 )
5626 debug_log("seeking to (%lu)%% \n", position);
5628 if (player->doing_seek)
5630 debug_log("not completed seek");
5631 return MM_ERROR_PLAYER_DOING_SEEK;
5633 player->doing_seek = TRUE;
5635 /* FIXIT : why don't we use 'GST_FORMAT_PERCENT' */
5636 pos_msec = (gint64) ( ( position * player->duration ) / 100 );
5637 ret = __gst_seek ( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
5638 GST_FORMAT_TIME, ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ),
5639 GST_SEEK_TYPE_SET, pos_msec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE );
5643 debug_error("failed to set position. dur[%lud] pos[%lud] pos_msec[%llud]\n", dur, position, pos_msec);
5655 /* NOTE : store last seeking point to overcome some bad operation
5656 * ( returning zero when getting current position ) of some elements
5658 player->last_position = pos_msec;
5660 debug_log("playback rate: %f\n", player->playback_rate);
5662 /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
5663 if ( player->playback_rate > 1.0 )
5664 _mmplayer_set_playspeed ( (MMHandleType)player, player->playback_rate );
5668 return MM_ERROR_NONE;
5671 player->pending_seek.is_pending = TRUE;
5672 player->pending_seek.format = format;
5673 player->pending_seek.pos = position;
5675 debug_warning("player current-state : %s, pending-state : %s, just preserve pending position(%lu).\n",
5676 MMPLAYER_STATE_GET_NAME(current_state), MMPLAYER_STATE_GET_NAME(pending_state), player->pending_seek.pos);
5678 return MM_ERROR_NONE;
5681 debug_error("invalid arguments, position : %ld dur : %ld format : %d \n", position, dur, format);
5683 return MM_ERROR_PLAYER_INTERNAL;
5686 player->doing_seek = FALSE;
5687 return MM_ERROR_PLAYER_SEEK;
5691 #define TRICKPLAY_OFFSET GST_MSECOND
5694 __gst_get_position(mm_player_t* player, int format, unsigned long* position) // @
5696 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
5697 GstFormat fmt = GST_FORMAT_TIME;
5698 signed long long pos_msec = 0;
5699 gboolean ret = TRUE;
5701 return_val_if_fail( player && position && player->pipeline && player->pipeline->mainbin,
5702 MM_ERROR_PLAYER_NOT_INITIALIZED );
5704 current_state = MMPLAYER_CURRENT_STATE(player);
5706 /* NOTE : query position except paused state to overcome some bad operation
5707 * please refer to below comments in details
5709 if ( current_state != MM_PLAYER_STATE_PAUSED )
5711 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &fmt, &pos_msec);
5714 /* NOTE : get last point to overcome some bad operation of some elements
5715 * ( returning zero when getting current position in paused state
5716 * and when failed to get postion during seeking
5718 if ( ( current_state == MM_PLAYER_STATE_PAUSED )
5720 //|| ( player->last_position != 0 && pos_msec == 0 ) )
5722 debug_warning(" Playback rate is %f\n", player->playback_rate);
5723 debug_warning ("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS (pos_msec), ret, current_state);
5725 if(player->playback_rate < 0.0)
5726 pos_msec = player->last_position - TRICKPLAY_OFFSET;
5728 pos_msec = player->last_position;
5731 pos_msec = player->last_position;
5733 player->last_position = pos_msec;
5735 debug_warning("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_msec));
5740 player->last_position = pos_msec;
5744 case MM_PLAYER_POS_FORMAT_TIME:
5745 *position = GST_TIME_AS_MSECONDS(pos_msec);
5748 case MM_PLAYER_POS_FORMAT_PERCENT:
5753 dur = player->duration / GST_SECOND;
5756 debug_log ("duration is [%d], so returning position 0\n",dur);
5761 pos = pos_msec / GST_SECOND;
5762 *position = pos * 100 / dur;
5767 return MM_ERROR_PLAYER_INTERNAL;
5770 debug_log("current position : %lu\n", *position);
5773 return MM_ERROR_NONE;
5777 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
5779 GstElement *element = NULL;
5780 GstQuery *query = NULL;
5782 return_val_if_fail( player &&
5784 player->pipeline->mainbin,
5785 MM_ERROR_PLAYER_NOT_INITIALIZED );
5787 return_val_if_fail( start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT );
5789 if ( MMPLAYER_IS_HTTP_STREAMING ( player ) || MMPLAYER_IS_HTTP_LIVE_STREAMING ( player ))
5791 /* Note : In case of http streaming or HLS, the buffering queue [ queue2 ] could handle buffering query. */
5792 element = GST_ELEMENT ( player->pipeline->mainbin[MMPLAYER_M_S_BUFFER].gst );
5794 else if ( MMPLAYER_IS_RTSP_STREAMING ( player ) )
5796 debug_warning ( "it's not supported yet.\n" );
5797 return MM_ERROR_NONE;
5801 debug_warning ( "it's only used for streaming case.\n" );
5802 return MM_ERROR_NONE;
5810 case MM_PLAYER_POS_FORMAT_PERCENT :
5812 query = gst_query_new_buffering ( GST_FORMAT_PERCENT );
5813 if ( gst_element_query ( element, query ) )
5820 gst_query_parse_buffering_percent ( query, &busy, &percent);
5821 gst_query_parse_buffering_range ( query, &format, &start, &stop, NULL );
5823 debug_log ( "buffering start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT "\n", start, stop);
5826 *start_pos = 100 * start / GST_FORMAT_PERCENT_MAX;
5831 *stop_pos = 100 * stop / GST_FORMAT_PERCENT_MAX;
5835 gst_query_unref (query);
5839 case MM_PLAYER_POS_FORMAT_TIME :
5840 debug_warning ( "Time format is not supported yet.\n" );
5847 debug_log("current buffer position : %lu~%lu \n", *start_pos, *stop_pos );
5849 return MM_ERROR_NONE;
5853 __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param) // @
5859 debug_warning("set_message_callback is called with invalid player handle\n");
5860 return MM_ERROR_PLAYER_NOT_INITIALIZED;
5863 player->msg_cb = callback;
5864 player->msg_cb_param = user_param;
5866 debug_log("msg_cb : 0x%x msg_cb_param : 0x%x\n", (guint)callback, (guint)user_param);
5870 return MM_ERROR_NONE;
5873 static gboolean __mmfplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data) // @
5875 gboolean ret = FALSE;
5880 return_val_if_fail ( uri , FALSE);
5881 return_val_if_fail ( data , FALSE);
5882 return_val_if_fail ( ( strlen(uri) <= MM_MAX_URL_LEN ), FALSE );
5884 memset(data, 0, sizeof(MMPlayerParseProfile));
5886 if ((path = strstr(uri, "file://")))
5888 if (util_exist_file_path(path + 7)) {
5889 strncpy(data->uri, path, MM_MAX_URL_LEN-1);
5891 if ( util_is_sdp_file ( path ) )
5893 debug_log("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
5894 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
5898 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
5904 debug_warning("could access %s.\n", path);
5907 else if ((path = strstr(uri, "buff://")))
5909 data->uri_type = MM_PLAYER_URI_TYPE_BUFF;
5912 else if ((path = strstr(uri, "rtsp://")))
5915 strcpy(data->uri, uri);
5916 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
5920 else if ((path = strstr(uri, "http://")))
5923 strcpy(data->uri, uri);
5925 #ifdef NO_USE_GST_HLSDEMUX
5926 if ((path = strstr(uri, "m3u")))
5928 debug_log ("++++++++++++++++++++ M3U +++++++++++++++++++++\n");
5929 debug_log ("\n\n\n\n \t HLS profile \n\n\n");
5930 data->uri_type = MM_PLAYER_URI_TYPE_HLS;
5934 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
5939 else if ((path = strstr(uri, "https://")))
5942 strcpy(data->uri, uri);
5944 #ifdef NO_USE_GST_HLSDEMUX
5945 if ((path = strstr(uri, "m3u")))
5947 debug_log ("++++++++++++++++++++ M3U +++++++++++++++++++++\n");
5948 debug_log ("\n\n\n\n \t HLS profile \n\n\n");
5949 data->uri_type = MM_PLAYER_URI_TYPE_HLS;
5953 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
5958 else if ((path = strstr(uri, "rtspu://")))
5961 strcpy(data->uri, uri);
5962 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
5966 else if ((path = strstr(uri, "rtspr://")))
5968 strcpy(data->uri, path);
5969 char *separater =strstr(path, "*");
5973 char *urgent = separater + strlen("*");
5975 if ((urgent_len = strlen(urgent))) {
5976 data->uri[strlen(path) - urgent_len - strlen("*")] = '\0';
5977 strcpy(data->urgent, urgent);
5978 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
5983 else if ((path = strstr(uri, "mms://")))
5986 strcpy(data->uri, uri);
5987 data->uri_type = MM_PLAYER_URI_TYPE_URL_MMS;
5991 else if ((path = strstr(uri, "mem://")))
5995 char *buffer = NULL;
5996 char *seperator = strchr(path, ',');
5997 char ext[100] = {0,}, size[100] = {0,};
6000 if ((buffer = strstr(path, "ext="))) {
6001 buffer += strlen("ext=");
6003 if (strlen(buffer)) {
6004 strcpy(ext, buffer);
6006 if ((seperator = strchr(ext, ','))
6007 || (seperator = strchr(ext, ' '))
6008 || (seperator = strchr(ext, '\0'))) {
6009 seperator[0] = '\0';
6014 if ((buffer = strstr(path, "size="))) {
6015 buffer += strlen("size=");
6017 if (strlen(buffer) > 0) {
6018 strcpy(size, buffer);
6020 if ((seperator = strchr(size, ','))
6021 || (seperator = strchr(size, ' '))
6022 || (seperator = strchr(size, '\0'))) {
6023 seperator[0] = '\0';
6026 mem_size = atoi(size);
6031 debug_log("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
6032 if ( mem_size && param) {
6034 data->mem_size = mem_size;
6035 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
6042 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
6043 if (util_exist_file_path(uri))
6045 debug_warning("uri has no protocol-prefix. giving 'file://' by default.\n");
6047 sprintf( data->uri, "file://%s", uri );
6049 if ( util_is_sdp_file( (char*)uri ) )
6051 debug_log("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
6052 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
6056 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
6062 debug_error ("invalid uri, could not play..\n");
6063 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
6067 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE) {
6072 /* dump parse result */
6073 debug_log("profile parsing result ---\n");
6074 debug_log("incomming uri : %s\n", uri);
6075 debug_log("uri : %s\n", data->uri);
6076 debug_log("uri_type : %d\n", data->uri_type);
6077 debug_log("play_mode : %d\n", data->play_mode);
6078 debug_log("mem : 0x%x\n", (guint)data->mem);
6079 debug_log("mem_size : %d\n", data->mem_size);
6080 debug_log("urgent : %s\n", data->urgent);
6081 debug_log("--------------------------\n");
6088 gboolean _asm_postmsg(gpointer *data)
6090 mm_player_t* player = (mm_player_t*)data;
6091 MMMessageParamType msg = {0, };
6095 return_val_if_fail ( player, FALSE );
6097 msg.union_type = MM_MSG_UNION_CODE;
6098 msg.code = player->sm.event_src;
6100 MMPLAYER_POST_MSG( player, MM_MESSAGE_READY_TO_RESUME, &msg);
6104 gboolean _asm_lazy_pause(gpointer *data)
6106 mm_player_t* player = (mm_player_t*)data;
6107 int ret = MM_ERROR_NONE;
6111 return_val_if_fail ( player, FALSE );
6113 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING)
6115 debug_log ("Ready to proceed lazy pause\n");
6116 ret = _mmplayer_pause((MMHandleType)player);
6117 if(MM_ERROR_NONE != ret)
6119 debug_error("MMPlayer pause failed in ASM callback lazy pause\n");
6124 debug_log ("Invalid state to proceed lazy pause\n");
6128 if (player->pipeline && player->pipeline->audiobin)
6129 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", 0, NULL);
6131 player->sm.by_asm_cb = 0; //should be reset here
6138 __mmplayer_asm_callback(int handle, ASM_event_sources_t event_src, ASM_sound_commands_t command, unsigned int sound_status, void* cb_data)
6140 mm_player_t* player = (mm_player_t*) cb_data;
6141 ASM_cb_result_t cb_res = ASM_CB_RES_IGNORE;
6142 MMHandleType attrs = 0;
6143 int result = MM_ERROR_NONE;
6144 gboolean lazy_pause = FALSE;
6148 return_val_if_fail ( player && player->pipeline, ASM_CB_RES_IGNORE );
6149 return_val_if_fail ( player->attrs, MM_ERROR_PLAYER_INTERNAL );
6151 if (player->is_sound_extraction)
6153 debug_log("sound extraction is working...so, asm command is ignored.\n");
6157 player->sm.by_asm_cb = 1; // it should be enabled for player state transition with called application command
6158 player->sm.event_src = event_src;
6160 if(event_src == ASM_EVENT_SOURCE_OTHER_PLAYER_APP)
6162 player->sm.event_src = ASM_EVENT_SOURCE_OTHER_APP;
6164 else if(event_src == ASM_EVENT_SOURCE_EARJACK_UNPLUG )
6166 int stop_by_asm = 0;
6168 mm_attrs_get_int_by_name(player->attrs, "sound_stop_when_unplugged", &stop_by_asm);
6172 else if (event_src == ASM_EVENT_SOURCE_RESOURCE_CONFLICT)
6174 /* can use video overlay simultaneously */
6175 /* video resource conflict */
6176 if(player->pipeline->videobin)
6178 if (PLAYER_INI()->multiple_codec_supported)
6180 debug_log("video conflict but, can support to use video overlay simultaneously");
6181 result = _mmplayer_pause((MMHandleType)player);
6182 cb_res = ASM_CB_RES_PAUSE;
6186 debug_log("video conflict, can't support for multiple codec instance");
6187 result = _mmplayer_unrealize((MMHandleType)player);
6188 cb_res = ASM_CB_RES_STOP;
6196 case ASM_COMMAND_PLAY:
6197 case ASM_COMMAND_STOP:
6198 debug_warning ("Got unexpected asm command (%d)", command);
6201 case ASM_COMMAND_PAUSE:
6203 debug_log("Got msg from asm to Pause");
6205 if(event_src == ASM_EVENT_SOURCE_CALL_START
6206 || event_src == ASM_EVENT_SOURCE_ALARM_START
6207 || event_src == ASM_EVENT_SOURCE_OTHER_APP)
6209 //hold 0.7 second to excute "fadedown mute" effect
6210 debug_log ("do fade down->pause->undo fade down");
6212 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
6214 result = _mmplayer_pause((MMHandleType)player);
6215 if (result != MM_ERROR_NONE)
6217 debug_warning("fail to set Pause state by asm");
6218 cb_res = ASM_CB_RES_IGNORE;
6221 __mmplayer_undo_sound_fadedown(player);
6223 else if(event_src == ASM_EVENT_SOURCE_OTHER_PLAYER_APP)
6225 lazy_pause = TRUE; // return as soon as possible, for fast start of other app
6227 if ( player->pipeline->audiobin && player->pipeline->audiobin[MMPLAYER_A_SINK].gst )
6228 g_object_set( player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "mute", 2, NULL);
6230 player->lazy_pause_event_id = g_timeout_add(LAZY_PAUSE_TIMEOUT_MSEC, (GSourceFunc)_asm_lazy_pause, (gpointer)player);
6231 debug_log ("set lazy pause timer (id=[%d], timeout=[%d ms])", player->lazy_pause_event_id, LAZY_PAUSE_TIMEOUT_MSEC);
6236 debug_log ("immediate pause");
6237 result = _mmplayer_pause((MMHandleType)player);
6239 cb_res = ASM_CB_RES_PAUSE;
6243 case ASM_COMMAND_RESUME:
6245 debug_log("Got msg from asm to Resume. So, application can resume. code (%d) \n", event_src);
6246 player->sm.by_asm_cb = 0;
6247 //ASM server is single thread daemon. So use g_idle_add() to post resume msg
6248 g_idle_add((GSourceFunc)_asm_postmsg, (gpointer)player);
6249 cb_res = ASM_CB_RES_IGNORE;
6258 player->sm.by_asm_cb = 0;
6266 _mmplayer_create_player(MMHandleType handle) // @
6268 mm_player_t* player = MM_PLAYER_CAST(handle);
6273 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6275 MMTA_ACUM_ITEM_BEGIN("[KPI] media player service create->playing", FALSE);
6277 /* initialize player state */
6278 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
6279 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
6280 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
6281 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
6282 MMPLAYER_PRINT_STATE(player);
6284 /* check current state */
6285 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL ( player, MMPLAYER_COMMAND_CREATE );
6287 /* construct attributes */
6288 player->attrs = _mmplayer_construct_attribute(handle);
6290 if ( !player->attrs )
6292 debug_critical("Failed to construct attributes\n");
6296 /* initialize gstreamer with configured parameter */
6297 if ( ! __mmplayer_gstreamer_init() )
6299 debug_critical("Initializing gstreamer failed\n");
6303 /* initialize factories if not using decodebin */
6304 if ( FALSE == PLAYER_INI()->use_decodebin )
6306 if( player->factories == NULL )
6307 __mmplayer_init_factories(player);
6310 /* create lock. note that g_tread_init() has already called in gst_init() */
6311 player->fsink_lock = g_mutex_new();
6312 if ( ! player->fsink_lock )
6314 debug_critical("Cannot create mutex for command lock\n");
6318 /* create repeat mutex */
6319 player->repeat_thread_mutex = g_mutex_new();
6320 if ( ! player->repeat_thread_mutex )
6322 debug_critical("Cannot create repeat mutex\n");
6326 /* create repeat cond */
6327 player->repeat_thread_cond = g_cond_new();
6328 if ( ! player->repeat_thread_cond )
6330 debug_critical("Cannot create repeat cond\n");
6334 /* create repeat thread */
6335 player->repeat_thread =
6336 g_thread_create (__mmplayer_repeat_thread, (gpointer)player, TRUE, NULL);
6337 if ( ! player->repeat_thread )
6342 if ( MM_ERROR_NONE != _mmplayer_initialize_video_capture(player))
6344 debug_error("failed to initialize video capture\n");
6348 /* register to asm */
6349 if ( MM_ERROR_NONE != _mmplayer_asm_register(&player->sm, (ASM_sound_cb_t)__mmplayer_asm_callback, (void*)player) )
6351 /* NOTE : we are dealing it as an error since we cannot expect it's behavior */
6352 debug_error("failed to register asm server\n");
6353 return MM_ERROR_POLICY_INTERNAL;
6356 if (MMPLAYER_IS_HTTP_PD(player))
6358 player->pd_downloader = NULL;
6359 player->pd_file_location = NULL;
6362 /* give default value of sound effect setting */
6363 player->audio_filter_info.filter_type = MM_AUDIO_FILTER_TYPE_NONE;
6364 player->bypass_sound_effect = TRUE;
6366 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
6368 /* initialize last position */
6369 player->last_position = 0;
6371 /* initialize missing plugin */
6372 player->not_supported_codec = MISSING_PLUGIN_NONE;
6374 /* initialize found plugin */
6375 player->can_support_codec = FOUND_PLUGIN_NONE;
6377 player->posted_msg = FALSE;
6380 /* initialize application client id for dnse */
6381 player->app_id_set_up_dnse = MM_AUDIO_FILTER_CLIENT_NONE;
6383 /* set player state to ready */
6384 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
6386 player->section_repeat = FALSE;
6387 player->section_repeat_start = 0;
6388 player->section_repeat_end = 0;
6389 player->is_sound_extraction = FALSE;
6390 player->playback_rate = DEFAULT_PLAYBACK_RATE;
6391 player->resumed_by_rewind = FALSE;
6392 player->is_nv12_tiled = FALSE;
6393 player->has_many_types = FALSE;
6394 player->no_more_pad = TRUE;
6395 player->parsers = NULL;
6396 player->pipeline_is_constructed = FALSE;
6398 /*initialize adaptive http streaming handle */
6399 player->ahs_player = NULL;
6401 /* set buffering parameter for streaming */
6402 for(i=0; i<MM_PLAYER_STREAM_COUNT_MAX; i++)
6404 player->bitrate[i] = 0;
6405 player->maximum_bitrate[i] = 0;
6407 player->updated_bitrate_count = 0;
6408 player->total_bitrate = 0;
6409 player->updated_maximum_bitrate_count = 0;
6410 player->total_maximum_bitrate = 0;
6412 /* initialize unlinked audio/video mime type */
6413 player->unlinked_audio_mime = NULL;
6414 player->unlinked_video_mime = NULL;
6415 player->unlinked_demuxer_mime = NULL;
6416 player->not_found_demuxer = 0;
6418 player->sent_bos = FALSE;
6420 player->doing_seek = FALSE;
6422 player->lazy_pause_event_id = 0;
6424 player->streamer = NULL;
6426 player->play_subtitle = FALSE;
6428 player->v_stream_caps = NULL;
6430 /* initialize pending seek */
6431 player->pending_seek.is_pending = FALSE;
6432 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
6433 player->pending_seek.pos = 0;
6435 /* set player state to null */
6436 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = PLAYER_INI()->localplayback_state_change_timeout;
6437 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_NULL );
6441 return MM_ERROR_NONE;
6445 if ( player->fsink_lock )
6446 g_mutex_free( player->fsink_lock );
6447 player->fsink_lock = NULL;
6450 if ( player->repeat_thread_cond &&
6451 player->repeat_thread_mutex &&
6452 player->repeat_thread )
6454 player->repeat_thread_exit = TRUE;
6455 g_cond_signal( player->repeat_thread_cond );
6457 g_thread_join( player->repeat_thread );
6458 player->repeat_thread = NULL;
6460 g_mutex_free ( player->repeat_thread_mutex );
6461 player->repeat_thread_mutex = NULL;
6463 g_cond_free ( player->repeat_thread_cond );
6464 player->repeat_thread_cond = NULL;
6466 /* clear repeat thread mutex/cond if still alive
6467 * this can happen if only thread creating has failed
6469 if ( player->repeat_thread_mutex )
6470 g_mutex_free ( player->repeat_thread_mutex );
6472 if ( player->repeat_thread_cond )
6473 g_cond_free ( player->repeat_thread_cond );
6475 /* release attributes */
6476 _mmplayer_deconstruct_attribute(handle);
6478 return MM_ERROR_PLAYER_INTERNAL;
6482 __mmplayer_gstreamer_init(void) // @
6484 static gboolean initialized = FALSE;
6485 static const int max_argc = 50;
6487 gchar** argv = NULL;
6495 debug_log("gstreamer already initialized.\n");
6500 argc = malloc( sizeof(int) );
6501 argv = malloc( sizeof(gchar*) * max_argc );
6503 if ( !argc || !argv )
6506 memset( argv, 0, sizeof(gchar*) * max_argc );
6510 argv[0] = g_strdup( "mmplayer" );
6513 for ( i = 0; i < 5; i++ ) /* FIXIT : num of param is now fixed to 5. make it dynamic */
6515 if ( strlen( PLAYER_INI()->gst_param[i] ) > 0 )
6517 argv[*argc] = g_strdup( PLAYER_INI()->gst_param[i] );
6522 /* we would not do fork for scanning plugins */
6523 argv[*argc] = g_strdup("--gst-disable-registry-fork");
6526 /* check disable registry scan */
6527 if ( PLAYER_INI()->skip_rescan )
6529 argv[*argc] = g_strdup("--gst-disable-registry-update");
6533 /* check disable segtrap */
6534 if ( PLAYER_INI()->disable_segtrap )
6536 argv[*argc] = g_strdup("--gst-disable-segtrap");
6540 debug_log("initializing gstreamer with following parameter\n");
6541 debug_log("argc : %d\n", *argc);
6543 for ( i = 0; i < *argc; i++ )
6545 debug_log("argv[%d] : %s\n", i, argv[i]);
6549 /* initializing gstreamer */
6550 __ta__("gst_init time",
6552 if ( ! gst_init_check (argc, &argv, &err))
6554 debug_error("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
6565 for ( i = 0; i < *argc; i++ )
6567 MMPLAYER_FREEIF( argv[i] );
6570 MMPLAYER_FREEIF( argv );
6571 MMPLAYER_FREEIF( argc );
6582 MMPLAYER_FREEIF( argv );
6583 MMPLAYER_FREEIF( argc );
6589 __mmplayer_release_extended_streaming(mm_player_t* player)
6591 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6593 if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player))
6595 _mmplayer_pd_stop ((MMHandleType)player);
6596 _mmplayer_pd_deinitialize ((MMHandleType)player);
6597 _mmplayer_pd_destroy((MMHandleType)player);
6600 #ifdef NO_USE_GST_HLSDEMUX
6601 /* destroy can called at anytime */
6602 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player))
6604 if (player->ahs_player)
6606 __mm_player_ahs_stop (player->ahs_player);
6607 __mm_player_ahs_deinitialize (player->ahs_player);
6608 __mm_player_ahs_destroy(player->ahs_player);
6609 player->ahs_player = NULL;
6614 if (MMPLAYER_IS_STREAMING(player))
6616 if (player->streamer)
6618 __mm_player_streaming_deinitialize (player->streamer);
6619 __mm_player_streaming_destroy(player->streamer);
6620 player->streamer = NULL;
6626 _mmplayer_destroy(MMHandleType handle) // @
6628 mm_player_t* player = MM_PLAYER_CAST(handle);
6632 /* check player handle */
6633 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6635 /* destroy can called at anytime */
6636 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL ( player, MMPLAYER_COMMAND_DESTROY );
6638 __mmplayer_release_extended_streaming(player);
6640 /* release repeat thread */
6641 if ( player->repeat_thread_cond &&
6642 player->repeat_thread_mutex &&
6643 player->repeat_thread )
6645 player->repeat_thread_exit = TRUE;
6646 g_cond_signal( player->repeat_thread_cond );
6648 debug_log("waitting for repeat thread exit\n");
6649 g_thread_join ( player->repeat_thread );
6650 g_mutex_free ( player->repeat_thread_mutex );
6651 g_cond_free ( player->repeat_thread_cond );
6652 debug_log("repeat thread released\n");
6655 if (MM_ERROR_NONE != _mmplayer_release_video_capture(player))
6657 debug_error("failed to release video capture\n");
6658 return MM_ERROR_PLAYER_INTERNAL;
6662 if ( MM_ERROR_NONE != _mmplayer_asm_deregister(&player->sm) )
6664 debug_error("failed to deregister asm server\n");
6665 return MM_ERROR_PLAYER_INTERNAL;
6668 /* release pipeline */
6669 if ( MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline( player ) )
6671 debug_error("failed to destory pipeline\n");
6672 return MM_ERROR_PLAYER_INTERNAL;
6675 /* release attributes */
6676 _mmplayer_deconstruct_attribute( handle );
6678 /* release factories */
6679 __mmplayer_release_factories( player );
6681 /* release miscellaneous information */
6682 __mmplayer_release_misc( player );
6685 if ( player->fsink_lock )
6686 g_mutex_free( player->fsink_lock );
6688 if ( player->msg_cb_lock )
6689 g_mutex_free( player->msg_cb_lock );
6691 if (player->lazy_pause_event_id)
6693 g_source_remove (player->lazy_pause_event_id);
6694 player->lazy_pause_event_id = 0;
6699 return MM_ERROR_NONE;
6704 __mmplayer_init_extended_streaming(mm_player_t* player)
6706 int ret = MM_ERROR_NONE;
6708 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6710 #ifdef NO_USE_GST_HLSDEMUX
6711 /* prepare adaptive http streaming */
6712 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_HLS)
6714 player->ahs_player = __mm_player_ahs_create ();
6716 if (NULL == player->ahs_player)
6718 debug_error ("Unable to create AHS player\n");
6719 ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
6723 if ( !__mm_player_ahs_initialize (player->ahs_player, player->profile.uri_type,
6724 player->profile.uri, player->pipeline->mainbin[MMPLAYER_M_SRC].gst) )
6726 debug_error ("failed to initialize ahs player\n");
6727 ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
6733 if (MMPLAYER_IS_HTTP_PD(player))
6735 gboolean bret = FALSE;
6736 gchar *src_uri = NULL;
6738 player->pd_downloader = _mmplayer_pd_create ();
6740 if ( !player->pd_downloader )
6742 debug_error ("Unable to create PD Downloader...");
6743 ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
6746 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
6747 src_uri = player->profile.uri;
6749 bret = _mmplayer_pd_initialize ((MMHandleType)player, src_uri, player->pd_file_location, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
6753 debug_error ("Unable to create PD Downloader...");
6754 ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
6762 _mmplayer_realize(MMHandleType hplayer) // @
6764 mm_player_t* player = (mm_player_t*)hplayer;
6767 int application_pid = -1;
6768 gboolean update_registry = FALSE;
6769 MMHandleType attrs = 0;
6770 int ret = MM_ERROR_NONE;
6774 /* check player handle */
6775 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED )
6777 /* check current state */
6778 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_REALIZE );
6780 attrs = MMPLAYER_GET_ATTRS(player);
6783 debug_error("fail to get attributes.\n");
6784 return MM_ERROR_PLAYER_INTERNAL;
6787 mm_attrs_get_int_by_name(attrs, "sound_application_pid", &application_pid );
6788 player->sm.pid = application_pid;
6790 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
6791 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
6793 if (! __mmfplayer_parse_profile((const char*)uri, param, &player->profile) )
6795 debug_error("failed to parse profile\n");
6796 return MM_ERROR_PLAYER_INVALID_URI;
6799 /* FIXIT : we can use thouse in player->profile directly */
6800 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM)
6802 player->mem_buf.buf = (char *)player->profile.mem;
6803 player->mem_buf.len = player->profile.mem_size;
6804 player->mem_buf.offset = 0;
6807 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS)
6809 debug_warning("mms protocol is not supported format.\n");
6810 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
6813 if (MMPLAYER_IS_STREAMING(player))
6814 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = PLAYER_INI()->live_state_change_timeout;
6816 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = PLAYER_INI()->localplayback_state_change_timeout;
6818 player->videodec_linked = 0;
6819 player->videosink_linked = 0;
6820 player->audiodec_linked = 0;
6821 player->audiosink_linked = 0;
6822 player->textsink_linked = 0;
6824 /* set the subtitle ON default */
6825 player->is_subtitle_off = FALSE;
6827 /* we need to update content attrs only the content has changed */
6828 player->need_update_content_attrs = TRUE;
6829 player->need_update_content_dur = FALSE;
6831 /* registry should be updated for downloadable codec */
6832 mm_attrs_get_int_by_name(attrs, "profile_update_registry", &update_registry);
6834 if ( update_registry )
6836 debug_log("updating registry...\n");
6837 gst_update_registry();
6839 /* then we have to rebuild factories */
6840 __mmplayer_release_factories( player );
6841 __mmplayer_init_factories(player);
6844 /* realize pipeline */
6845 ret = __gst_realize( player );
6846 if ( ret != MM_ERROR_NONE )
6848 debug_error("fail to realize the player.\n");
6852 __mmplayer_init_extended_streaming(player);
6861 __mmplayer_deinit_extended_streaming(mm_player_t *player)
6863 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6865 /* destroy can called at anytime */
6866 if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player))
6868 //__mmplayer_pd_deinitalize (player->ahs_player);
6869 _mmplayer_pd_stop ((MMHandleType)player);
6872 #ifdef NO_USE_GST_HLSDEMUX
6873 /* destroy can called at anytime */
6874 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player))
6876 __mm_player_ahs_stop (player->ahs_player);
6877 //__mm_player_ahs_deinitalize (player->ahs_player);
6880 return MM_ERROR_NONE;
6885 _mmplayer_unrealize(MMHandleType hplayer) // @
6887 mm_player_t* player = (mm_player_t*)hplayer;
6888 int ret = MM_ERROR_NONE;
6892 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED )
6894 /* check current state */
6895 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_UNREALIZE );
6897 __mmplayer_deinit_extended_streaming(player);
6899 /* unrealize pipeline */
6900 ret = __gst_unrealize( player );
6902 /* set player state if success */
6903 if ( MM_ERROR_NONE == ret )
6905 ret = _mmplayer_asm_set_state(hplayer, ASM_STATE_STOP);
6908 debug_error("failed to set asm state to STOP\n");
6919 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param) // @
6921 mm_player_t* player = (mm_player_t*)hplayer;
6923 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6925 return __gst_set_message_callback(player, callback, user_param);
6929 _mmplayer_get_state(MMHandleType hplayer, int* state) // @
6931 mm_player_t *player = (mm_player_t*)hplayer;
6933 return_val_if_fail(state, MM_ERROR_INVALID_ARGUMENT);
6935 *state = MMPLAYER_CURRENT_STATE(player);
6937 return MM_ERROR_NONE;
6942 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume) // @
6944 mm_player_t* player = (mm_player_t*) hplayer;
6945 GstElement* vol_element = NULL;
6950 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6952 debug_log("volume [L]=%f:[R]=%f\n",
6953 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
6955 /* invalid factor range or not */
6956 for ( i = 0; i < MM_VOLUME_CHANNEL_NUM; i++ )
6958 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
6959 debug_error("Invalid factor! (valid factor:0~1.0)\n");
6960 return MM_ERROR_INVALID_ARGUMENT;
6964 /* Save volume to handle. Currently the first array element will be saved. */
6965 player->sound.volume = volume.level[0];
6967 /* check pipeline handle */
6968 if ( ! player->pipeline || ! player->pipeline->audiobin )
6970 debug_log("audiobin is not created yet\n");
6971 debug_log("but, current stored volume will be set when it's created.\n");
6973 /* NOTE : stored volume will be used in create_audiobin
6974 * returning MM_ERROR_NONE here makes application to able to
6975 * set volume at anytime.
6977 return MM_ERROR_NONE;
6980 /* setting volume to volume element */
6981 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
6985 debug_log("volume is set [%f]\n", player->sound.volume);
6986 g_object_set(vol_element, "volume", player->sound.volume, NULL);
6991 return MM_ERROR_NONE;
6996 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
6998 mm_player_t* player = (mm_player_t*) hplayer;
7003 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7004 return_val_if_fail( volume, MM_ERROR_INVALID_ARGUMENT );
7006 /* returning stored volume */
7007 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
7008 volume->level[i] = player->sound.volume;
7012 return MM_ERROR_NONE;
7018 _mmplayer_set_mute(MMHandleType hplayer, int mute) // @
7020 mm_player_t* player = (mm_player_t*) hplayer;
7021 GstElement* vol_element = NULL;
7025 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7027 debug_log("mute : %d\n", mute);
7029 /* mute value shoud 0 or 1 */
7030 if ( mute != 0 && mute != 1 )
7032 debug_error("bad mute value\n");
7034 /* FIXIT : definitly, we need _BAD_PARAM error code */
7035 return MM_ERROR_INVALID_ARGUMENT;
7039 /* just hold mute value if pipeline is not ready */
7040 if ( !player->pipeline || !player->pipeline->audiobin )
7042 debug_log("pipeline is not ready. holding mute value\n");
7043 player->sound.mute = mute;
7044 return MM_ERROR_NONE;
7048 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
7050 /* NOTE : volume will only created when the bt is enabled */
7053 g_object_set(vol_element, "mute", mute, NULL);
7057 debug_log("volume elemnet is not created. using volume in audiosink\n");
7060 player->sound.mute = mute;
7064 return MM_ERROR_NONE;
7068 _mmplayer_get_mute(MMHandleType hplayer, int* pmute) // @
7070 mm_player_t* player = (mm_player_t*) hplayer;
7071 GstElement* vol_element = NULL;
7075 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7076 return_val_if_fail ( pmute, MM_ERROR_INVALID_ARGUMENT );
7078 /* just hold mute value if pipeline is not ready */
7079 if ( !player->pipeline || !player->pipeline->audiobin )
7081 debug_log("pipeline is not ready. returning stored value\n");
7082 *pmute = player->sound.mute;
7083 return MM_ERROR_NONE;
7087 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
7091 g_object_get(vol_element, "mute", pmute, NULL);
7092 debug_log("mute=%d\n\n", *pmute);
7096 *pmute = player->sound.mute;
7101 return MM_ERROR_NONE;
7105 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param) // @
7107 mm_player_t* player = (mm_player_t*) hplayer;
7111 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7112 return_val_if_fail ( callback, MM_ERROR_INVALID_ARGUMENT );
7114 player->video_stream_cb = callback;
7115 player->video_stream_cb_user_param = user_param;
7116 player->use_video_stream = TRUE;
7117 debug_log("Stream cb Handle value is %p : %p\n", player, player->video_stream_cb);
7121 return MM_ERROR_NONE;
7125 _mmplayer_set_audiostream_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param) // @
7127 mm_player_t* player = (mm_player_t*) hplayer;
7131 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7132 return_val_if_fail(callback, MM_ERROR_INVALID_ARGUMENT);
7134 player->audio_stream_cb = callback;
7135 player->audio_stream_cb_user_param = user_param;
7136 debug_log("Audio Stream cb Handle value is %p : %p\n", player, player->audio_stream_cb);
7140 return MM_ERROR_NONE;
7144 _mmplayer_set_audiobuffer_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param) // @
7146 mm_player_t* player = (mm_player_t*) hplayer;
7150 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7151 return_val_if_fail(callback, MM_ERROR_INVALID_ARGUMENT);
7153 player->audio_buffer_cb = callback;
7154 player->audio_buffer_cb_user_param = user_param;
7155 debug_log("Audio Stream cb Handle value is %p : %p\n", player, player->audio_buffer_cb);
7159 return MM_ERROR_NONE;
7163 _mmplayer_set_buffer_need_data_cb(MMHandleType hplayer, mm_player_buffer_need_data_callback callback, void *user_param) // @
7165 mm_player_t* player = (mm_player_t*) hplayer;
7169 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
7170 return_val_if_fail(callback, MM_ERROR_INVALID_ARGUMENT);
7172 player->need_data_cb = callback;
7173 player->buffer_cb_user_param = user_param;
7175 debug_log("buffer need dataHandle value is %p : %p\n", player, player->need_data_cb);
7179 return MM_ERROR_NONE;
7183 _mmplayer_set_buffer_enough_data_cb(MMHandleType hplayer, mm_player_buffer_enough_data_callback callback, void *user_param) // @
7185 mm_player_t* player = (mm_player_t*) hplayer;
7189 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
7190 return_val_if_fail(callback, MM_ERROR_INVALID_ARGUMENT);
7192 player->enough_data_cb = callback;
7193 player->buffer_cb_user_param = user_param;
7195 debug_log("buffer enough data cb Handle value is %p : %p\n", player, player->enough_data_cb);
7199 return MM_ERROR_NONE;
7203 _mmplayer_set_buffer_seek_data_cb(MMHandleType hplayer, mm_player_buffer_seek_data_callback callback, void *user_param) // @
7205 mm_player_t* player = (mm_player_t*) hplayer;
7209 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
7210 return_val_if_fail(callback, MM_ERROR_INVALID_ARGUMENT);
7212 player->seek_data_cb = callback;
7213 player->buffer_cb_user_param = user_param;
7215 debug_log("buffer seek data cb Handle value is %p : %p\n", player, player->seek_data_cb);
7219 return MM_ERROR_NONE;
7222 int __mmplayer_start_extended_streaming(mm_player_t *player)
7224 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7226 if (MMPLAYER_IS_HTTP_PD(player) && player->pd_downloader)
7228 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
7230 gboolean bret = FALSE;
7232 bret = _mmplayer_pd_start ((MMHandleType)player);
7235 debug_error ("ERROR while starting PD...\n");
7236 return MM_ERROR_PLAYER_NOT_INITIALIZED;
7241 #ifdef NO_USE_GST_HLSDEMUX
7242 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player))
7244 if ( !__mm_player_ahs_start (player->ahs_player))
7246 debug_error("failed to start ahs\n");
7247 return MM_ERROR_PLAYER_INTERNAL;
7251 return MM_ERROR_NONE;
7255 _mmplayer_start(MMHandleType hplayer) // @
7257 mm_player_t* player = (mm_player_t*) hplayer;
7258 gint ret = MM_ERROR_NONE;
7262 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7264 /* check current state */
7265 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_START );
7267 ret = _mmplayer_asm_set_state(hplayer, ASM_STATE_PLAYING);
7268 if ( ret != MM_ERROR_NONE )
7270 debug_error("failed to set asm state to PLAYING\n");
7274 /* NOTE : we should check and create pipeline again if not created as we destroy
7275 * whole pipeline when stopping in streamming playback
7277 if ( ! player->pipeline )
7279 ret = __gst_realize( player );
7280 if ( MM_ERROR_NONE != ret )
7282 debug_error("failed to realize before starting. only in streamming\n");
7287 if (__mmplayer_start_extended_streaming(player) != MM_ERROR_NONE)
7288 return MM_ERROR_PLAYER_INTERNAL;
7290 /* start pipeline */
7291 ret = __gst_start( player );
7292 if ( ret != MM_ERROR_NONE )
7294 debug_error("failed to start player.\n");
7304 /* NOTE: post "not supported codec message" to application
7305 * when one codec is not found during AUTOPLUGGING in MSL.
7306 * So, it's separated with error of __mmplayer_gst_callback().
7307 * And, if any codec is not found, don't send message here.
7308 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
7311 __mmplayer_post_missed_plugin(mm_player_t* player)
7313 MMMessageParamType msg_param;
7314 memset (&msg_param, 0, sizeof(MMMessageParamType));
7315 gboolean post_msg_direct = FALSE;
7319 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7321 debug_log("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
7322 player->not_supported_codec, player->can_support_codec);
7324 if( player->not_found_demuxer )
7326 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
7327 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
7329 MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param );
7330 MMPLAYER_FREEIF(msg_param.data);
7332 return MM_ERROR_NONE;
7335 if (player->not_supported_codec)
7337 if ( player->can_support_codec ) // There is one codec to play
7339 post_msg_direct = TRUE;
7343 if ( player->pipeline->audiobin ) // Some content has only PCM data in container.
7344 post_msg_direct = TRUE;
7347 if ( post_msg_direct )
7349 MMMessageParamType msg_param;
7350 memset (&msg_param, 0, sizeof(MMMessageParamType));
7352 if ( player->not_supported_codec == MISSING_PLUGIN_AUDIO )
7354 debug_warning("not found AUDIO codec, posting error code to application.\n");
7356 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
7357 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
7359 else if ( player->not_supported_codec == MISSING_PLUGIN_VIDEO )
7361 debug_warning("not found VIDEO codec, posting error code to application.\n");
7363 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
7364 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
7367 MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param );
7369 MMPLAYER_FREEIF(msg_param.data);
7371 return MM_ERROR_NONE;
7373 else // no any supported codec case
7375 debug_warning("not found any codec, posting error code to application.\n");
7377 if ( player->not_supported_codec == MISSING_PLUGIN_AUDIO )
7379 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
7380 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
7384 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
7385 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
7388 MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param );
7390 MMPLAYER_FREEIF(msg_param.data);
7396 return MM_ERROR_NONE;
7399 /* NOTE : it should be able to call 'stop' anytime*/
7401 _mmplayer_stop(MMHandleType hplayer) // @
7403 mm_player_t* player = (mm_player_t*)hplayer;
7404 int ret = MM_ERROR_NONE;
7408 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7410 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player))
7412 __mm_player_ahs_stop (player->ahs_player);
7415 /* check current state */
7416 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_STOP );
7418 /* NOTE : application should not wait for EOS after calling STOP */
7419 __mmplayer_cancel_delayed_eos( player );
7422 ret = __gst_stop( player );
7424 if ( ret != MM_ERROR_NONE )
7426 debug_error("failed to stop player.\n");
7436 _mmplayer_pause(MMHandleType hplayer) // @
7438 mm_player_t* player = (mm_player_t*)hplayer;
7439 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7440 GstFormat fmt = GST_FORMAT_TIME;
7441 signed long long pos_msec = 0;
7442 int ret = MM_ERROR_NONE;
7446 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7448 /* check current state */
7449 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_PAUSE );
7451 /* NOTE : store current point to overcome some bad operation
7452 * ( returning zero when getting current position in paused state) of some
7455 current_state = MMPLAYER_CURRENT_STATE(player);
7456 if ( current_state == MM_PLAYER_STATE_PLAYING )
7458 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &fmt, &pos_msec);
7460 debug_warning("getting current position failed in paused\n");
7462 player->last_position = pos_msec;
7465 /* pause pipeline */
7466 ret = __gst_pause( player, FALSE );
7468 if ( MMPLAYER_IS_HTTP_LIVE_STREAMING ( player ))
7470 //__mm_player_ahs_pause (player->ahs_player); // Not yet implemented
7473 if ( ret != MM_ERROR_NONE )
7475 debug_error("failed to pause player.\n");
7484 _mmplayer_resume(MMHandleType hplayer)
7486 mm_player_t* player = (mm_player_t*)hplayer;
7487 int ret = MM_ERROR_NONE;
7491 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7493 ret = _mmplayer_asm_set_state(hplayer, ASM_STATE_PLAYING);
7496 debug_error("failed to set asm state to PLAYING\n");
7500 /* check current state */
7501 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_RESUME );
7503 /* resume pipeline */
7504 ret = __gst_resume( player, FALSE );
7506 if ( ret != MM_ERROR_NONE )
7508 debug_error("failed to resume player.\n");
7518 __mmplayer_set_play_count(mm_player_t* player, gint count)
7520 MMHandleType attrs = 0;
7524 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7526 attrs = MMPLAYER_GET_ATTRS(player);
7529 debug_error("fail to get attributes.\n");
7530 return MM_ERROR_PLAYER_INTERNAL;
7533 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
7534 if ( mmf_attrs_commit ( attrs ) ) /* return -1 if error */
7535 debug_error("failed to commit\n");
7539 return MM_ERROR_NONE;
7543 _mmplayer_activate_section_repeat(MMHandleType hplayer, unsigned long start, unsigned long end)
7545 mm_player_t* player = (mm_player_t*)hplayer;
7546 gint64 start_pos = 0;
7552 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7553 return_val_if_fail ( end <= GST_TIME_AS_MSECONDS(player->duration), MM_ERROR_INVALID_ARGUMENT );
7555 player->section_repeat = TRUE;
7556 player->section_repeat_start = start;
7557 player->section_repeat_end = end;
7559 start_pos = player->section_repeat_start * G_GINT64_CONSTANT(1000000);
7560 end_pos = player->section_repeat_end * G_GINT64_CONSTANT(1000000);
7562 __mmplayer_set_play_count( player, infinity );
7564 if ( (!__gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
7567 ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ),
7568 GST_SEEK_TYPE_SET, start_pos,
7569 GST_SEEK_TYPE_SET, end_pos)))
7571 debug_error("failed to activate section repeat\n");
7573 return MM_ERROR_PLAYER_SEEK;
7576 debug_log("succeeded to set section repeat from %d to %d\n",
7577 player->section_repeat_start, player->section_repeat_end);
7581 return MM_ERROR_NONE;
7585 __mmplayer_set_pcm_extraction(mm_player_t* player)
7587 guint64 start_nsec = 0;
7588 guint64 end_nsec = 0;
7589 guint64 dur_nsec = 0;
7590 guint64 dur_msec = 0;
7591 GstFormat fmt = GST_FORMAT_TIME;
7592 int required_start = 0;
7593 int required_end = 0;
7598 return_val_if_fail( player, FALSE );
7600 mm_attrs_multiple_get(player->attrs,
7602 "pcm_extraction_start_msec", &required_start,
7603 "pcm_extraction_end_msec", &required_end,
7606 debug_log("pcm extraction required position is from [%d] to [%d] (msec)\n", required_start, required_end);
7608 if (required_start == 0 && required_end == 0)
7610 debug_log("extracting entire stream");
7611 return MM_ERROR_NONE;
7613 else if (required_start < 0 || required_start > required_end || required_end < 0 )
7615 debug_log("invalid range for pcm extraction");
7616 return MM_ERROR_INVALID_ARGUMENT;
7620 ret = gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &fmt, &dur_nsec);
7623 debug_error("failed to get duration");
7624 return MM_ERROR_PLAYER_INTERNAL;
7626 dur_msec = GST_TIME_AS_MSECONDS(dur_nsec);
7628 if (dur_msec < required_end) // FIXME
7630 debug_log("invalid end pos for pcm extraction");
7631 return MM_ERROR_INVALID_ARGUMENT;
7634 start_nsec = required_start * G_GINT64_CONSTANT(1000000);
7635 end_nsec = required_end * G_GINT64_CONSTANT(1000000);
7637 if ( (!__gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
7640 ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ),
7641 GST_SEEK_TYPE_SET, start_nsec,
7642 GST_SEEK_TYPE_SET, end_nsec)))
7644 debug_error("failed to seek for pcm extraction\n");
7646 return MM_ERROR_PLAYER_SEEK;
7649 debug_log("succeeded to set up segment extraction from [%llu] to [%llu] (nsec)\n", start_nsec, end_nsec);
7653 return MM_ERROR_NONE;
7657 void __mmplayer_set_videosink_type(mm_player_t* player)
7663 return_if_fail( player );
7665 mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &type);
7667 debug_log("check display surface attribute: %d\n", type);
7669 if (type >=MM_DISPLAY_SURFACE_X)
7671 PLAYER_INI()->video_surface = type;
7680 _mmplayer_deactivate_section_repeat(MMHandleType hplayer)
7682 mm_player_t* player = (mm_player_t*)hplayer;
7684 GstFormat fmt = GST_FORMAT_TIME;
7689 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7691 player->section_repeat = FALSE;
7693 __mmplayer_set_play_count( player, onetime );
7695 gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &fmt, &cur_pos);
7697 if ( (!__gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
7700 ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ),
7701 GST_SEEK_TYPE_SET, cur_pos,
7702 GST_SEEK_TYPE_SET, player->duration )))
7704 debug_error("failed to deactivate section repeat\n");
7706 return MM_ERROR_PLAYER_SEEK;
7711 return MM_ERROR_NONE;
7715 _mmplayer_set_playspeed(MMHandleType hplayer, gdouble rate)
7717 mm_player_t* player = (mm_player_t*)hplayer;
7718 signed long long pos_msec = 0;
7719 int ret = MM_ERROR_NONE;
7721 GstFormat format =GST_FORMAT_TIME;
7722 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7725 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
7726 return_val_if_fail ( !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API );
7728 /* The sound of video is not supported under 0.0 and over 2.0. */
7729 if(rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN)
7731 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
7734 _mmplayer_set_mute(hplayer, mute);
7736 if (player->playback_rate == rate)
7737 return MM_ERROR_NONE;
7739 /* If the position is reached at start potion during fast backward, EOS is posted.
7740 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
7742 player->playback_rate = rate;
7744 current_state = MMPLAYER_CURRENT_STATE(player);
7746 if ( current_state != MM_PLAYER_STATE_PAUSED )
7747 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &format, &pos_msec);
7749 debug_log ("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS (pos_msec), ret, current_state);
7751 if ( ( current_state == MM_PLAYER_STATE_PAUSED )
7753 //|| ( player->last_position != 0 && pos_msec == 0 ) )
7755 debug_warning("returning last point : %lld\n", player->last_position );
7756 pos_msec = player->last_position;
7759 if ((!gst_element_seek (player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
7762 ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ),
7763 //( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_KEY_UNIT),
7764 GST_SEEK_TYPE_SET, pos_msec,
7765 //GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE,
7766 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)))
7768 debug_error("failed to set speed playback\n");
7769 return MM_ERROR_PLAYER_SEEK;
7772 debug_log("succeeded to set speed playback as %fl\n", rate);
7776 return MM_ERROR_NONE;;
7780 _mmplayer_set_position(MMHandleType hplayer, int format, int position) // @
7782 mm_player_t* player = (mm_player_t*)hplayer;
7783 int ret = MM_ERROR_NONE;
7787 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7789 ret = __gst_set_position ( player, format, (unsigned long)position );
7797 _mmplayer_get_position(MMHandleType hplayer, int format, unsigned long *position) // @
7799 mm_player_t* player = (mm_player_t*)hplayer;
7800 int ret = MM_ERROR_NONE;
7802 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7804 ret = __gst_get_position ( player, format, position );
7810 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos) // @
7812 mm_player_t* player = (mm_player_t*)hplayer;
7813 int ret = MM_ERROR_NONE;
7815 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7817 ret = __gst_get_buffer_position ( player, format, start_pos, stop_pos );
7823 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position) // @
7825 mm_player_t* player = (mm_player_t*)hplayer;
7826 int ret = MM_ERROR_NONE;
7830 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7832 ret = __gst_adjust_subtitle_position(player, format, position);
7840 __mmplayer_is_midi_type( gchar* str_caps)
7842 if ( ( g_strrstr(str_caps, "audio/midi") ) ||
7843 ( g_strrstr(str_caps, "application/x-gst_ff-mmf") ) ||
7844 ( g_strrstr(str_caps, "application/x-smaf") ) ||
7845 ( g_strrstr(str_caps, "audio/x-imelody") ) ||
7846 ( g_strrstr(str_caps, "audio/mobile-xmf") ) ||
7847 ( g_strrstr(str_caps, "audio/xmf") ) ||
7848 ( g_strrstr(str_caps, "audio/mxmf") ) )
7850 debug_log("midi\n");
7855 debug_log("not midi.\n");
7861 __mmplayer_is_amr_type (gchar *str_caps)
7863 if ((g_strrstr(str_caps, "AMR")) ||
7864 (g_strrstr(str_caps, "amr")))
7872 __mmplayer_is_only_mp3_type (gchar *str_caps)
7874 if (g_strrstr(str_caps, "application/x-id3") ||
7875 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
7883 __mmplayer_typefind_have_type( GstElement *tf, guint probability, // @
7884 GstCaps *caps, gpointer data)
7886 mm_player_t* player = (mm_player_t*)data;
7891 return_if_fail( player && tf && caps );
7893 /* store type string */
7894 MMPLAYER_FREEIF(player->type);
7895 player->type = gst_caps_to_string(caps);
7897 debug_log("meida type %s found, probability %d%% / %d\n", player->type, probability, gst_caps_get_size(caps));
7899 /* midi type should be stored because it will be used to set audio gain in avsysauiosink */
7900 if ( __mmplayer_is_midi_type(player->type))
7902 player->profile.play_mode = MM_PLAYER_MODE_MIDI;
7904 else if (__mmplayer_is_amr_type(player->type))
7906 player->bypass_sound_effect = FALSE;
7907 if ( (PLAYER_INI()->use_audio_filter_preset || PLAYER_INI()->use_audio_filter_custom) )
7909 if ( player->audio_filter_info.filter_type == MM_AUDIO_FILTER_TYPE_PRESET )
7911 if (!_mmplayer_sound_filter_preset_apply(player, player->audio_filter_info.preset))
7913 debug_msg("apply sound effect(preset:%d) setting success\n",player->audio_filter_info.preset);
7916 else if ( player->audio_filter_info.filter_type == MM_AUDIO_FILTER_TYPE_CUSTOM )
7918 if (!_mmplayer_sound_filter_custom_apply(player))
7920 debug_msg("apply sound effect(custom) setting success\n");
7925 else if ( g_strrstr(player->type, "application/x-hls"))
7927 /* If it can't know exact type when it parses uri because of redirection case,
7928 * it will be fixed by typefinder here.
7930 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
7933 pad = gst_element_get_static_pad(tf, "src");
7936 debug_error("fail to get typefind src pad.\n");
7942 if ( ! __mmplayer_try_to_plug( player, pad, caps ) )
7944 debug_error("failed to autoplug for type : %s\n", player->type);
7946 if ( ( PLAYER_INI()->async_start ) &&
7947 ( ! MMPLAYER_IS_RTSP_STREAMING ( player ) ) &&
7948 ( player->posted_msg == FALSE ) )
7950 __mmplayer_post_missed_plugin( player );
7956 /* finish autopluging if no dynamic pad waiting */
7957 if( ( ! player->have_dynamic_pad) && ( ! player->has_many_types) )
7959 if ( ! MMPLAYER_IS_RTSP_STREAMING( player ) )
7961 __mmplayer_pipeline_complete( NULL, (gpointer)player );
7966 gst_object_unref( GST_OBJECT(pad) );
7974 __mmplayer_warm_up_video_codec( mm_player_t* player, GstElementFactory *factory)
7976 GstElement *element;
7977 GstStateChangeReturn ret;
7978 gboolean usable = TRUE;
7980 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7981 return_val_if_fail ( factory, MM_ERROR_COMMON_INVALID_ARGUMENT );
7983 element = gst_element_factory_create (factory, NULL);
7985 ret = gst_element_set_state (element, GST_STATE_READY);
7987 if (ret != GST_STATE_CHANGE_SUCCESS)
7989 debug_error ("resource conflict so, %s unusable\n", GST_PLUGIN_FEATURE_NAME (factory));
7993 gst_element_set_state (element, GST_STATE_NULL);
7994 gst_object_unref (element);
7999 /* it will return first created element */
8001 __mmplayer_try_to_plug(mm_player_t* player, GstPad *pad, const GstCaps *caps) // @
8003 MMPlayerGstElement* mainbin = NULL;
8004 const char* mime = NULL;
8005 const GList* item = NULL;
8006 const gchar* klass = NULL;
8007 GstCaps* res = NULL;
8008 gboolean skip = FALSE;
8009 GstPad* queue_pad = NULL;
8010 GstElement* queue = NULL;
8011 GstElement *element = NULL;
8015 return_val_if_fail( player &&
8017 player->pipeline->mainbin,
8021 mainbin = player->pipeline->mainbin;
8023 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
8025 /* return if we got raw output */
8026 if(g_str_has_prefix(mime, "video/x-raw") || g_str_has_prefix(mime, "audio/x-raw") ||g_str_has_prefix(mime, "text/plain") )
8029 element = (GstElement*)gst_pad_get_parent(pad);
8032 /* NOTE : When no decoder has added during autoplugging. like a simple wave playback.
8033 * No queue will be added. I think it can caused breaking sound when playing raw audio
8034 * frames but there's no different. Decodebin also doesn't add with those wav fils.
8035 * Anyway, currentely raw-queue seems not necessary.
8039 /* NOTE : check if previously linked element is demuxer/depayloader/parse means no decoder
8040 * has linked. if so, we need to add queue for quality of output. note that
8041 * decodebin also has same problem.
8044 klass = gst_element_factory_get_klass( gst_element_get_factory(element) );
8046 /* add queue if needed */
8047 if( g_strrstr(klass, "Demux") ||
8048 g_strrstr(klass, "Depayloader") ||
8049 g_strrstr(klass, "Parse") )
8051 debug_log("adding raw queue\n");
8053 queue = gst_element_factory_make("queue", NULL);
8056 debug_warning("failed to create queue\n");
8061 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_READY) )
8063 debug_warning("failed to set state READY to queue\n");
8067 /* add to pipeline */
8068 if ( ! gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue) )
8070 debug_warning("failed to add queue\n");
8075 queue_pad = gst_element_get_static_pad(queue, "sink");
8077 if ( GST_PAD_LINK_OK != gst_pad_link(pad, queue_pad) )
8079 debug_warning("failed to link queue\n");
8082 gst_object_unref ( GST_OBJECT(queue_pad) );
8086 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_PAUSED) )
8088 debug_warning("failed to set state READY to queue\n");
8092 /* replace given pad to queue:src */
8093 pad = gst_element_get_static_pad(queue, "src");
8096 debug_warning("failed to get pad from queue\n");
8101 /* check if player can do start continually */
8102 MMPLAYER_CHECK_CMD_IF_EXIT(player);
8104 if(__mmplayer_link_sink(player,pad))
8105 __mmplayer_gst_decode_callback(element, pad, FALSE, player);
8107 gst_object_unref( GST_OBJECT(element));
8114 item = player->factories;
8115 for(; item != NULL ; item = item->next)
8118 GstElementFactory *factory = GST_ELEMENT_FACTORY(item->data);
8124 /* filtering exclude keyword */
8125 for ( idx = 0; PLAYER_INI()->exclude_element_keyword[idx][0] != '\0'; idx++ )
8127 if ( g_strrstr(GST_PLUGIN_FEATURE_NAME (factory),
8128 PLAYER_INI()->exclude_element_keyword[idx] ) )
8130 debug_warning("skipping [%s] by exculde keyword [%s]\n",
8131 GST_PLUGIN_FEATURE_NAME (factory),
8132 PLAYER_INI()->exclude_element_keyword[idx] );
8139 if ( skip ) continue;
8142 /* check factory class for filtering */
8143 klass = gst_element_factory_get_klass(GST_ELEMENT_FACTORY(factory));
8145 if ( MMPLAYER_IS_RTSP_STREAMING( player ) )
8147 if ( g_strrstr(klass, "Parse") )
8149 debug_log("streaming doesn't need any parser. skipping [%s]\n",
8150 GST_PLUGIN_FEATURE_NAME (factory) );
8156 /* NOTE : msl don't need to use image plugins.
8157 * So, those plugins should be skipped for error handling.
8159 if ( g_strrstr(klass, "Codec/Decoder/Image") )
8161 debug_log("player doesn't need [%s] so, skipping it\n",
8162 GST_PLUGIN_FEATURE_NAME (factory) );
8168 /* check pad compatability */
8169 for(pads = gst_element_factory_get_static_pad_templates(factory);
8170 pads != NULL; pads=pads->next)
8172 GstStaticPadTemplate *temp1 = pads->data;
8173 GstCaps* static_caps = NULL;
8175 if( temp1->direction != GST_PAD_SINK ||
8176 temp1->presence != GST_PAD_ALWAYS)
8180 if ( GST_IS_CAPS( &temp1->static_caps.caps) )
8182 /* using existing caps */
8183 static_caps = gst_caps_ref( &temp1->static_caps.caps );
8188 static_caps = gst_caps_from_string ( temp1->static_caps.string );
8191 res = gst_caps_intersect(caps, static_caps);
8193 gst_caps_unref( static_caps );
8196 if( res && !gst_caps_is_empty(res) )
8198 GstElement *new_element;
8199 GList *elements = player->parsers;
8200 char *name_template = g_strdup(temp1->name_template);
8201 gchar *name_to_plug = GST_PLUGIN_FEATURE_NAME(factory);
8203 gst_caps_unref(res);
8205 debug_log("found %s to plug\n", name_to_plug);
8207 new_element = gst_element_factory_create(GST_ELEMENT_FACTORY(factory), NULL);
8208 if ( ! new_element )
8210 debug_error("failed to create element [%s]. continue with next.\n",
8211 GST_PLUGIN_FEATURE_NAME (factory));
8213 MMPLAYER_FREEIF(name_template);
8218 /* check and skip it if it was already used. Otherwise, it can be an infinite loop
8219 * because parser can accept its own output as input.
8221 if (g_strrstr(klass, "Parser"))
8223 gchar *selected = NULL;
8225 for ( ; elements; elements = g_list_next(elements))
8227 gchar *element_name = elements->data;
8229 if (g_strrstr(element_name, name_to_plug))
8231 debug_log("but, %s already linked, so skipping it\n", name_to_plug);
8238 selected = g_strdup(name_to_plug);
8240 player->parsers = g_list_append(player->parsers, selected);
8243 /* store specific handles for futher control */
8244 if(g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse"))
8246 /* FIXIT : first value will be overwritten if there's more
8247 * than 1 demuxer/parser
8249 debug_log("plugged element is demuxer. take it\n");
8250 mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
8251 mainbin[MMPLAYER_M_DEMUX].gst = new_element;
8253 else if(g_strrstr(klass, "Decoder") && __mmplayer_link_decoder(player,pad))
8255 if(mainbin[MMPLAYER_M_DEC1].gst == NULL)
8257 debug_log("plugged element is decoder. take it[MMPLAYER_M_DEC1]\n");
8258 mainbin[MMPLAYER_M_DEC1].id = MMPLAYER_M_DEC1;
8259 mainbin[MMPLAYER_M_DEC1].gst = new_element;
8261 else if(mainbin[MMPLAYER_M_DEC2].gst == NULL)
8263 debug_log("plugged element is decoder. take it[MMPLAYER_M_DEC2]\n");
8264 mainbin[MMPLAYER_M_DEC2].id = MMPLAYER_M_DEC2;
8265 mainbin[MMPLAYER_M_DEC2].gst = new_element;
8268 /* NOTE : IF one codec is found, add it to supported_codec and remove from
8269 * missing plugin. Both of them are used to check what's supported codec
8270 * before returning result of play start. And, missing plugin should be
8271 * updated here for multi track files.
8273 if(g_str_has_prefix(mime, "video"))
8275 GstPad *src_pad = NULL;
8276 GstPadTemplate *pad_templ = NULL;
8277 GstCaps *caps = NULL;
8278 gchar *caps_type = NULL;
8280 debug_log("found VIDEO decoder\n");
8281 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
8282 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
8284 src_pad = gst_element_get_static_pad (new_element, "src");
8285 pad_templ = gst_pad_get_pad_template (src_pad);
8286 caps = GST_PAD_TEMPLATE_CAPS(pad_templ);
8288 caps_type = gst_caps_to_string(caps);
8290 if ( g_strrstr( caps_type, "ST12") )
8291 player->is_nv12_tiled = TRUE;
8294 MMPLAYER_FREEIF( caps_type );
8295 gst_object_unref (src_pad);
8297 g_object_set( G_OBJECT (new_element), "hw-accel", PLAYER_INI()->use_video_hw_accel, NULL);
8298 g_object_set( G_OBJECT (new_element), "err-conceal", TRUE, NULL);
8300 else if (g_str_has_prefix(mime, "audio"))
8302 debug_log("found AUDIO decoder\n");
8303 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
8304 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
8307 if ( ! __mmplayer_close_link(player, pad, new_element,
8308 name_template,gst_element_factory_get_static_pad_templates(factory)) )
8310 if (player->keep_detecting_vcodec)
8313 /* Link is failed even though a supportable codec is found. */
8314 __mmplayer_check_not_supported_codec(player, (gchar *)mime);
8316 MMPLAYER_FREEIF(name_template);
8317 debug_error("failed to call _close_link\n");
8321 MMPLAYER_FREEIF(name_template);
8325 gst_caps_unref(res);
8331 /* There is no any found codec. */
8332 __mmplayer_check_not_supported_codec(player,(gchar *)mime);
8334 debug_error("failed to autoplug\n");
8345 gst_object_unref( queue );
8349 gst_object_unref( queue_pad );
8352 gst_object_unref ( element );
8359 int __mmplayer_check_not_supported_codec(mm_player_t* player, gchar* mime)
8363 return_val_if_fail(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
8364 return_val_if_fail ( mime, MM_ERROR_INVALID_ARGUMENT );
8366 debug_log("mimetype to check: %s\n", mime );
8368 if ( MMPLAYER_IS_RTSP_STREAMING(player) )
8371 /* add missing plugin */
8372 /* NOTE : msl should check missing plugin for image mime type.
8373 * Some motion jpeg clips can have playable audio track.
8374 * So, msl have to play audio after displaying popup written video format not supported.
8376 if ( !( player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst ) )
8378 if ( !( player->can_support_codec | player->videodec_linked | player->audiodec_linked ) )
8380 debug_log("not found demuxer\n");
8381 player->not_found_demuxer = TRUE;
8382 player->unlinked_demuxer_mime = g_strdup_printf ( "%s", mime );
8388 if( ( g_str_has_prefix(mime, "video") ) ||( g_str_has_prefix(mime, "image") ) )
8390 debug_log("can support codec=%d, vdec_linked=%d, adec_linked=%d\n",
8391 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
8393 /* check that clip have multi tracks or not */
8394 if ( ( player->can_support_codec & FOUND_PLUGIN_VIDEO ) && ( player->videodec_linked ) )
8396 debug_log("video plugin is already linked\n");
8400 debug_warning("add VIDEO to missing plugin\n");
8401 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
8404 else if ( g_str_has_prefix(mime, "audio") )
8406 if ( ( player->can_support_codec & FOUND_PLUGIN_AUDIO ) && ( player->audiodec_linked ) )
8408 debug_log("audio plugin is already linked\n");
8412 debug_warning("add AUDIO to missing plugin\n");
8413 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
8420 return MM_ERROR_NONE;
8424 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data) // @
8426 mm_player_t* player = (mm_player_t*)data;
8430 return_if_fail( player );
8432 /* remove fakesink */
8433 if ( ! __mmplayer_gst_remove_fakesink( player,
8434 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]) )
8436 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
8437 * signaling mechanism ( pad-added, no-more-pad, new-decoded-pad ) from various
8438 * source element are not same. To overcome this situation, this function will called
8439 * several places and several times. Therefore, this is not an error case.
8443 debug_log("pipeline has completely constructed\n");
8445 player->pipeline_is_constructed = TRUE;
8447 if ( ( PLAYER_INI()->async_start ) &&
8448 ( ! MMPLAYER_IS_RTSP_STREAMING ( player ) ) &&
8449 ( player->posted_msg == FALSE ) )
8451 __mmplayer_post_missed_plugin( player );
8454 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-complate" );
8457 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player)
8461 return_val_if_fail ( player, FALSE );
8464 if ( MMPLAYER_IS_STREAMING(player) )
8467 /* This callback can be set to music player only. */
8468 if((player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO)
8470 debug_warning("audio callback is not supported for video");
8474 if (player->audio_stream_cb)
8479 pad = gst_element_get_static_pad (player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
8483 debug_error("failed to get sink pad from audiosink to probe data\n");
8487 player->audio_cb_probe_id = gst_pad_add_buffer_probe (pad,
8488 G_CALLBACK (__mmplayer_audio_stream_probe), player);
8490 gst_object_unref (pad);
8497 debug_error("There is no audio callback to configure.\n");
8507 __mmplayer_init_factories(mm_player_t* player) // @
8511 return_if_fail ( player );
8513 player->factories = gst_registry_feature_filter(gst_registry_get_default(),
8514 (GstPluginFeatureFilter)__mmplayer_feature_filter, FALSE, NULL);
8516 player->factories = g_list_sort(player->factories, (GCompareFunc)util_factory_rank_compare);
8522 __mmplayer_release_factories(mm_player_t* player) // @
8526 return_if_fail ( player );
8528 if (player->factories)
8530 gst_plugin_feature_list_free (player->factories);
8531 player->factories = NULL;
8538 __mmplayer_release_misc(mm_player_t* player)
8542 return_if_fail ( player );
8544 /* free memory related to sound effect */
8545 if(player->audio_filter_info.custom_ext_level_for_plugin)
8547 free(player->audio_filter_info.custom_ext_level_for_plugin);
8553 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name)
8555 GstElement *element = NULL;
8558 debug_log("creating %s to plug\n", name);
8560 element = gst_element_factory_make(name, NULL);
8563 debug_error("failed to create queue\n");
8567 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(element, GST_STATE_READY) )
8569 debug_error("failed to set state READY to %s\n", name);
8573 if ( ! gst_bin_add(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, element) )
8575 debug_error("failed to add %s\n", name);
8579 sinkpad = gst_element_get_static_pad(element, "sink");
8581 if ( GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad) )
8583 debug_error("failed to link %s\n", name);
8584 gst_object_unref (sinkpad);
8589 debug_log("linked %s to pipeline successfully\n", name);
8591 gst_object_unref (sinkpad);
8597 __mmplayer_close_link(mm_player_t* player, GstPad *srcpad, GstElement *sinkelement,
8598 const char *padname, const GList *templlist)
8601 gboolean has_dynamic_pads = FALSE;
8602 gboolean has_many_types = FALSE;
8603 const char *klass = NULL;
8604 GstStaticPadTemplate *padtemplate = NULL;
8605 GstElementFactory *factory = NULL;
8606 GstElement* queue = NULL;
8607 GstElement* parser = NULL;
8608 GstPad *pssrcpad = NULL;
8609 GstPad *qsrcpad = NULL, *qsinkpad = NULL;
8610 MMPlayerGstElement *mainbin = NULL;
8611 GstStructure* str = NULL;
8612 GstCaps* srccaps = NULL;
8613 GstState warmup = GST_STATE_READY;
8614 gboolean isvideo_decoder = FALSE;
8615 guint q_max_size_time = 0;
8619 return_val_if_fail ( player &&
8621 player->pipeline->mainbin,
8624 mainbin = player->pipeline->mainbin;
8626 debug_log("plugging pad %s:%s to newly create %s:%s\n",
8627 GST_ELEMENT_NAME( GST_PAD_PARENT ( srcpad ) ),
8628 GST_PAD_NAME( srcpad ),
8629 GST_ELEMENT_NAME( sinkelement ),
8633 factory = gst_element_get_factory(sinkelement);
8634 klass = gst_element_factory_get_klass(factory);
8636 /* check if player can do start continually */
8637 MMPLAYER_CHECK_CMD_IF_EXIT(player);
8639 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkelement, warmup) )
8641 if (isvideo_decoder)
8642 player->keep_detecting_vcodec = TRUE;
8644 debug_error("failed to set %d state to %s\n", warmup, GST_ELEMENT_NAME( sinkelement ));
8648 /* add to pipeline */
8649 if ( ! gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), sinkelement) )
8651 debug_error("failed to add %s to mainbin\n", GST_ELEMENT_NAME( sinkelement ));
8655 debug_log("element klass : %s\n", klass);
8657 /* added to support multi track files */
8658 /* only decoder case and any of the video/audio still need to link*/
8659 if(g_strrstr(klass, "Decoder") && __mmplayer_link_decoder(player,srcpad))
8663 name = g_strdup(GST_ELEMENT_NAME( GST_PAD_PARENT ( srcpad )));
8665 if (g_strrstr(name, "mpegtsdemux"))
8667 gchar *demux_caps = NULL;
8668 gchar *parser_name = NULL;
8669 GstCaps *dcaps = NULL;
8671 dcaps = gst_pad_get_caps(srcpad);
8672 demux_caps = gst_caps_to_string(dcaps);
8674 if (g_strrstr(demux_caps, "video/x-h264"))
8676 parser_name = g_strdup("h264parse");
8678 else if (g_strrstr(demux_caps, "video/mpeg"))
8680 parser_name = g_strdup("mpeg4videoparse");
8683 gst_caps_unref(dcaps);
8684 MMPLAYER_FREEIF( demux_caps );
8688 parser = __mmplayer_element_create_and_link(player, srcpad, parser_name);
8690 MMPLAYER_FREEIF(parser_name);
8694 debug_error("failed to create parser\n");
8698 /* update srcpad if parser is created */
8699 pssrcpad = gst_element_get_static_pad(parser, "src");
8704 MMPLAYER_FREEIF(name);
8706 queue = __mmplayer_element_create_and_link(player, srcpad, "queue"); // parser - queue or demuxer - queue
8709 debug_error("failed to create queue\n");
8713 /* update srcpad to link with decoder */
8714 qsrcpad = gst_element_get_static_pad(queue, "src");
8717 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player))
8718 q_max_size_time = GST_QUEUE_HLS_TIME;
8720 q_max_size_time = GST_QUEUE_DEFAULT_TIME;
8722 /* assigning queue handle for futher manipulation purpose */
8723 /* FIXIT : make it some kind of list so that msl can support more then two stream (text, data, etc...) */
8724 if(mainbin[MMPLAYER_M_Q1].gst == NULL)
8726 mainbin[MMPLAYER_M_Q1].id = MMPLAYER_M_Q1;
8727 mainbin[MMPLAYER_M_Q1].gst = queue;
8729 g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q1].gst), "max-size-time", q_max_size_time * GST_SECOND, NULL);
8731 else if(mainbin[MMPLAYER_M_Q2].gst == NULL)
8733 mainbin[MMPLAYER_M_Q2].id = MMPLAYER_M_Q2;
8734 mainbin[MMPLAYER_M_Q2].gst = queue;
8736 g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q2].gst), "max-size-time", q_max_size_time * GST_SECOND, NULL);
8740 debug_critical("Not supporting more then two elementary stream\n");
8744 pad = gst_element_get_static_pad(sinkelement, padname);
8748 debug_warning("failed to get pad(%s) from %s. retrying with [sink]\n",
8749 padname, GST_ELEMENT_NAME(sinkelement) );
8751 pad = gst_element_get_static_pad(sinkelement, "sink");
8754 debug_error("failed to get pad(sink) from %s. \n",
8755 GST_ELEMENT_NAME(sinkelement) );
8760 /* to check the video/audio type set the proper flag*/
8762 srccaps = gst_pad_get_caps( srcpad );
8766 str = gst_caps_get_structure( srccaps, 0 );
8770 name = gst_structure_get_name(str);
8775 /* link queue and decoder. so, it will be queue - decoder. */
8776 if ( GST_PAD_LINK_OK != gst_pad_link(srcpad, pad) )
8778 gst_object_unref(GST_OBJECT(pad));
8779 debug_error("failed to link (%s) to pad(%s)\n", GST_ELEMENT_NAME( sinkelement ), padname );
8781 /* reconstitute supportable codec */
8783 if (strstr(name, "video"))
8785 player->can_support_codec ^= FOUND_PLUGIN_VIDEO;
8788 if (strstr(name, "audio"))
8790 player->can_support_codec ^= FOUND_PLUGIN_AUDIO;
8796 gst_object_unref(GST_OBJECT(pad));
8799 if (strstr(name, "video"))
8801 player->videodec_linked = 1;
8802 debug_msg("player->videodec_linked set to 1\n");
8805 if (strstr(name, "audio"))
8807 player->audiodec_linked = 1;
8808 debug_msg("player->auddiodec_linked set to 1\n");
8811 gst_caps_unref(GST_CAPS(srccaps));
8816 if ( !MMPLAYER_IS_HTTP_PD(player) )
8818 if( (g_strrstr(klass, "Demux") && !g_strrstr(klass, "Metadata")) || (g_strrstr(klass, "Parser") ) )
8820 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player))
8822 GstFormat fmt = GST_FORMAT_BYTES;
8823 gint64 dur_bytes = 0L;
8824 gchar *file_buffering_path = NULL;
8825 gboolean use_file_buffer = FALSE;
8827 if ( !mainbin[MMPLAYER_M_S_BUFFER].gst)
8829 debug_log("creating http streaming buffering queue\n");
8831 queue = gst_element_factory_make("queue2", "http_streaming_buffer");
8834 debug_critical ( "failed to create buffering queue element\n" );
8838 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_READY) )
8840 debug_error("failed to set state READY to buffering queue\n");
8844 if ( !gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue) )
8846 debug_error("failed to add buffering queue\n");
8850 qsinkpad = gst_element_get_static_pad(queue, "sink");
8851 qsrcpad = gst_element_get_static_pad(queue, "src");
8853 if ( GST_PAD_LINK_OK != gst_pad_link(srcpad, qsinkpad) )
8855 debug_error("failed to link buffering queue\n");
8861 mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_S_BUFFER;
8862 mainbin[MMPLAYER_M_S_BUFFER].gst = queue;
8864 if ( !MMPLAYER_IS_HTTP_LIVE_STREAMING(player))
8866 if ( !gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, &fmt, &dur_bytes))
8867 debug_error("fail to get duration.\n");
8871 use_file_buffer = MMPLAYER_USE_FILE_FOR_BUFFERING(player);
8872 file_buffering_path = g_strdup(PLAYER_INI()->http_file_buffer_path);
8876 __mm_player_streaming_set_buffer(player->streamer,
8879 PLAYER_INI()->http_max_size_bytes,
8881 PLAYER_INI()->http_buffering_limit,
8882 PLAYER_INI()->http_buffering_time,
8884 file_buffering_path,
8887 MMPLAYER_FREEIF(file_buffering_path);
8892 /* if it is not decoder or */
8893 /* in decoder case any of the video/audio still need to link*/
8894 if(!g_strrstr(klass, "Decoder"))
8897 pad = gst_element_get_static_pad(sinkelement, padname);
8900 debug_warning("failed to get pad(%s) from %s. retrying with [sink]\n",
8901 padname, GST_ELEMENT_NAME(sinkelement) );
8903 pad = gst_element_get_static_pad(sinkelement, "sink");
8907 debug_error("failed to get pad(sink) from %s. \n",
8908 GST_ELEMENT_NAME(sinkelement) );
8913 if ( GST_PAD_LINK_OK != gst_pad_link(srcpad, pad) )
8915 gst_object_unref(GST_OBJECT(pad));
8916 debug_error("failed to link (%s) to pad(%s)\n", GST_ELEMENT_NAME( sinkelement ), padname );
8920 gst_object_unref(GST_OBJECT(pad));
8923 for(;templlist != NULL; templlist = templlist->next)
8925 padtemplate = templlist->data;
8927 debug_log ("director = [%d], presence = [%d]\n", padtemplate->direction, padtemplate->presence);
8929 if( padtemplate->direction != GST_PAD_SRC ||
8930 padtemplate->presence == GST_PAD_REQUEST )
8933 switch(padtemplate->presence)
8935 case GST_PAD_ALWAYS:
8937 GstPad *srcpad = gst_element_get_static_pad(sinkelement, "src");
8938 GstCaps *caps = gst_pad_get_caps(srcpad);
8940 /* Check whether caps has many types */
8941 if ( gst_caps_get_size (caps) > 1 && g_strrstr(klass, "Parser")) {
8942 debug_log ("has_many_types for this caps [%s]\n", gst_caps_to_string(caps));
8943 has_many_types = TRUE;
8947 if ( ! __mmplayer_try_to_plug(player, srcpad, caps) )
8949 gst_object_unref(GST_OBJECT(srcpad));
8950 gst_caps_unref(GST_CAPS(caps));
8952 debug_error("failed to plug something after %s\n", GST_ELEMENT_NAME( sinkelement ));
8956 gst_caps_unref(GST_CAPS(caps));
8957 gst_object_unref(GST_OBJECT(srcpad));
8963 case GST_PAD_SOMETIMES:
8964 has_dynamic_pads = TRUE;
8972 /* check if player can do start continually */
8973 MMPLAYER_CHECK_CMD_IF_EXIT(player);
8975 if( has_dynamic_pads )
8977 player->have_dynamic_pad = TRUE;
8978 MMPLAYER_SIGNAL_CONNECT ( player, sinkelement, "pad-added",
8979 G_CALLBACK(__mmplayer_add_new_pad), player);
8981 /* for streaming, more then one typefind will used for each elementary stream
8982 * so this doesn't mean the whole pipeline completion
8984 if ( ! MMPLAYER_IS_RTSP_STREAMING( player ) )
8986 MMPLAYER_SIGNAL_CONNECT( player, sinkelement, "no-more-pads",
8987 G_CALLBACK(__mmplayer_pipeline_complete), player);
8995 player->has_many_types = has_many_types;
8997 pad = gst_element_get_static_pad(sinkelement, "src");
8998 MMPLAYER_SIGNAL_CONNECT (player, pad, "notify::caps", G_CALLBACK(__mmplayer_add_new_caps), player);
8999 gst_object_unref (GST_OBJECT(pad));
9003 /* check if player can do start continually */
9004 MMPLAYER_CHECK_CMD_IF_EXIT(player);
9006 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkelement, GST_STATE_PAUSED) )
9008 debug_error("failed to set state PAUSED to %s\n", GST_ELEMENT_NAME( sinkelement ));
9014 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state (queue, GST_STATE_PAUSED) )
9016 debug_error("failed to set state PAUSED to queue\n");
9022 gst_object_unref (GST_OBJECT(qsrcpad));
9028 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state (parser, GST_STATE_PAUSED) )
9030 debug_error("failed to set state PAUSED to queue\n");
9036 gst_object_unref (GST_OBJECT(pssrcpad));
9048 gst_object_unref(GST_OBJECT(qsrcpad));
9050 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
9051 * You need to explicitly set elements to the NULL state before
9052 * dropping the final reference, to allow them to clean up.
9054 gst_element_set_state(queue, GST_STATE_NULL);
9055 /* And, it still has a parent "player".
9056 * You need to let the parent manage the object instead of unreffing the object directly.
9059 gst_bin_remove (GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue);
9060 //gst_object_unref( queue );
9064 gst_caps_unref(GST_CAPS(srccaps));
9069 static gboolean __mmplayer_feature_filter(GstPluginFeature *feature, gpointer data) // @
9072 //const gchar *name;
9074 /* we only care about element factories */
9075 if (!GST_IS_ELEMENT_FACTORY(feature))
9078 /* only parsers, demuxers and decoders */
9079 klass = gst_element_factory_get_klass(GST_ELEMENT_FACTORY(feature));
9080 //name = gst_element_factory_get_longname(GST_ELEMENT_FACTORY(feature));
9082 if( g_strrstr(klass, "Demux") == NULL &&
9083 g_strrstr(klass, "Codec/Decoder") == NULL &&
9084 g_strrstr(klass, "Depayloader") == NULL &&
9085 g_strrstr(klass, "Parse") == NULL)
9093 static void __mmplayer_add_new_caps(GstPad* pad, GParamSpec* unused, gpointer data)
9095 mm_player_t* player = (mm_player_t*) data;
9096 GstCaps *caps = NULL;
9097 GstStructure *str = NULL;
9102 return_if_fail ( pad )
9103 return_if_fail ( unused )
9104 return_if_fail ( data )
9106 caps = gst_pad_get_caps(pad);
9110 str = gst_caps_get_structure(caps, 0);
9114 name = gst_structure_get_name(str);
9117 debug_log("name=%s\n", name);
9119 if ( ! __mmplayer_try_to_plug(player, pad, caps) )
9121 debug_error("failed to autoplug for type (%s)\n", name);
9122 gst_caps_unref(caps);
9126 gst_caps_unref(caps);
9128 __mmplayer_pipeline_complete( NULL, (gpointer)player );
9135 static void __mmplayer_set_unlinked_mime_type(mm_player_t* player, GstCaps *caps)
9139 const char *stream_type;
9140 gchar *version_field = NULL;
9144 return_if_fail ( player );
9145 return_if_fail ( caps );
9147 str = gst_caps_get_structure(caps, 0);
9151 stream_type = gst_structure_get_name(str);
9156 /* set unlinked mime type for downloadable codec */
9157 if (g_str_has_prefix(stream_type, "video/"))
9159 if (g_str_has_prefix(stream_type, "video/mpeg"))
9161 gst_structure_get_int (str, MM_PLAYER_MPEG_VNAME, &version);
9162 version_field = MM_PLAYER_MPEG_VNAME;
9164 else if (g_str_has_prefix(stream_type, "video/x-wmv"))
9166 gst_structure_get_int (str, MM_PLAYER_WMV_VNAME, &version);
9167 version_field = MM_PLAYER_WMV_VNAME;
9170 else if (g_str_has_prefix(stream_type, "video/x-divx"))
9172 gst_structure_get_int (str, MM_PLAYER_DIVX_VNAME, &version);
9173 version_field = MM_PLAYER_DIVX_VNAME;
9178 player->unlinked_video_mime = g_strdup_printf("%s, %s=%d", stream_type, version_field, version);
9182 player->unlinked_video_mime = g_strdup_printf("%s", stream_type);
9185 else if (g_str_has_prefix(stream_type, "audio/"))
9187 if (g_str_has_prefix(stream_type, "audio/mpeg")) // mp3 or aac
9189 gst_structure_get_int (str, MM_PLAYER_MPEG_VNAME, &version);
9190 version_field = MM_PLAYER_MPEG_VNAME;
9192 else if (g_str_has_prefix(stream_type, "audio/x-wma"))
9194 gst_structure_get_int (str, MM_PLAYER_WMA_VNAME, &version);
9195 version_field = MM_PLAYER_WMA_VNAME;
9200 player->unlinked_audio_mime = g_strdup_printf("%s, %s=%d", stream_type, version_field, version);
9204 player->unlinked_audio_mime = g_strdup_printf("%s", stream_type);
9211 static void __mmplayer_add_new_pad(GstElement *element, GstPad *pad, gpointer data)
9213 mm_player_t* player = (mm_player_t*) data;
9214 GstCaps *caps = NULL;
9215 GstStructure *str = NULL;
9220 return_if_fail ( player );
9221 return_if_fail ( pad );
9223 GST_OBJECT_LOCK (pad);
9224 if ((caps = GST_PAD_CAPS(pad)))
9226 GST_OBJECT_UNLOCK (pad);
9230 caps = gst_pad_get_caps(pad);
9231 if ( !caps ) return;
9234 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9236 str = gst_caps_get_structure(caps, 0);
9240 name = gst_structure_get_name(str);
9244 player->num_dynamic_pad++;
9245 debug_log("stream count inc : %d\n", player->num_dynamic_pad);
9247 if (__mmplayer_is_amr_type(name))
9249 /* store type string */
9250 MMPLAYER_FREEIF(player->type);
9251 player->type = gst_caps_to_string(caps);
9252 player->bypass_sound_effect = FALSE;
9253 if ( (PLAYER_INI()->use_audio_filter_preset || PLAYER_INI()->use_audio_filter_custom) )
9255 if ( player->audio_filter_info.filter_type == MM_AUDIO_FILTER_TYPE_PRESET )
9257 if (!_mmplayer_sound_filter_preset_apply(player, player->audio_filter_info.preset))
9259 debug_msg("apply sound effect(preset:%d) setting success\n",player->audio_filter_info.preset);
9262 else if ( player->audio_filter_info.filter_type == MM_AUDIO_FILTER_TYPE_CUSTOM )
9264 if (!_mmplayer_sound_filter_custom_apply(player))
9266 debug_msg("apply sound effect(custom) setting success\n");
9271 /* Note : If the stream is the subtitle, we try not to play it. Just close the demuxer subtitle pad.
9272 * If want to play it, remove this code.
9274 else if (g_strrstr(name, "application"))
9276 if (g_strrstr(name, "x-id3") || g_strrstr(name, "x-apetag"))
9278 /* If id3/ape tag comes, keep going */
9279 debug_log("application mime exception : id3/ape tag\n");
9283 /* Otherwise, we assume that this stream is subtile. */
9284 debug_log(" application mime type pad is closed. \n");
9288 else if (g_strrstr(name, "video"))
9291 mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &stype);
9293 /* don't make video because of not required */
9294 if (stype == MM_DISPLAY_SURFACE_NULL)
9296 debug_log("no video because it's not required\n");
9300 player->v_stream_caps = gst_caps_copy(caps); //if needed, video caps is required when videobin is created
9303 if ( ! __mmplayer_try_to_plug(player, pad, caps) )
9305 debug_error("failed to autoplug for type (%s)\n", name);
9307 __mmplayer_set_unlinked_mime_type(player, caps);
9310 gst_caps_unref(caps);
9317 /* test API for tuning audio gain. this API should be
9318 * deprecated before the day of final release
9321 _mmplayer_set_volume_tune(MMHandleType hplayer, MMPlayerVolumeType volume)
9323 mm_player_t* player = (mm_player_t*) hplayer;
9324 gint error = MM_ERROR_NONE;
9326 gboolean isMidi = FALSE;
9331 return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9332 return_val_if_fail( player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED )
9334 debug_log("clip type=%d(1-midi, 0-others), volume [L]=%d:[R]=%d\n",
9335 player->profile.play_mode, volume.level[0], volume.level[1]);
9337 isMidi = ( player->profile.play_mode == MM_PLAYER_MODE_MIDI ) ? TRUE : FALSE;
9344 /* is it proper volume level? */
9345 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; ++i)
9347 if (volume.level[i] < 0 || volume.level[i] > vol_max) {
9348 debug_log("Invalid Volume level!!!! \n");
9349 return MM_ERROR_INVALID_ARGUMENT;
9355 if ( player->pipeline->mainbin )
9357 GstElement *midi_element = player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst;
9359 if ( midi_element && ( strstr(GST_ELEMENT_NAME(midi_element), "midiparse")) )
9361 debug_log("setting volume (%d) level to midi plugin\n", volume.level[0]);
9363 g_object_set(midi_element, "volume", volume.level[0], NULL);
9369 if ( player->pipeline->audiobin )
9371 GstElement *sink_element = player->pipeline->audiobin[MMPLAYER_A_SINK].gst;
9373 /* Set to Avsysaudiosink element */
9377 gboolean mute = FALSE;
9378 vol_value = volume.level[0];
9380 g_object_set(G_OBJECT(sink_element), "tuningvolume", vol_value, NULL);
9382 mute = (vol_value == 0)? TRUE:FALSE;
9384 g_object_set(G_OBJECT(sink_element), "mute", mute, NULL);
9396 __mmplayer_dump_pipeline_state( mm_player_t* player )
9398 GstIterator*iter = NULL;
9399 gboolean done = FALSE;
9401 GstElement *item = NULL;
9402 GstElementFactory *factory = NULL;
9404 GstState state = GST_STATE_VOID_PENDING;
9405 GstState pending = GST_STATE_VOID_PENDING;
9406 GstClockTime time = 200*GST_MSECOND;
9410 return_val_if_fail ( player &&
9412 player->pipeline->mainbin,
9416 iter = gst_bin_iterate_recurse(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst) );
9421 switch ( gst_iterator_next (iter, (gpointer)&item) )
9423 case GST_ITERATOR_OK:
9424 gst_element_get_state(GST_ELEMENT (item),&state, &pending,time);
9426 factory = gst_element_get_factory (item) ;
9427 debug_log("%s:%s : From:%s To:%s refcount : %d\n", GST_OBJECT_NAME(factory) , GST_ELEMENT_NAME(item) ,
9428 gst_element_state_get_name(state), gst_element_state_get_name(pending) , GST_OBJECT_REFCOUNT_VALUE(item));
9431 gst_object_unref (item);
9433 case GST_ITERATOR_RESYNC:
9434 gst_iterator_resync (iter);
9436 case GST_ITERATOR_ERROR:
9439 case GST_ITERATOR_DONE:
9446 item = GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
9448 gst_element_get_state(GST_ELEMENT (item),&state, &pending,time);
9450 factory = gst_element_get_factory (item) ;
9452 debug_log("%s:%s : From:%s To:%s refcount : %d\n",
9453 GST_OBJECT_NAME(factory),
9454 GST_ELEMENT_NAME(item),
9455 gst_element_state_get_name(state),
9456 gst_element_state_get_name(pending),
9457 GST_OBJECT_REFCOUNT_VALUE(item) );
9460 gst_iterator_free (iter);
9469 __mmplayer_check_subtitle( mm_player_t* player )
9471 MMHandleType attrs = 0;
9472 char *subtitle_uri = NULL;
9476 return_val_if_fail( player, FALSE );
9478 /* get subtitle attribute */
9479 attrs = MMPLAYER_GET_ATTRS(player);
9483 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
9484 if ( !subtitle_uri || !strlen(subtitle_uri))
9487 debug_log ("subtite uri is %s[%d]\n", subtitle_uri, strlen(subtitle_uri));
9495 __mmplayer_can_extract_pcm( mm_player_t* player )
9497 MMHandleType attrs = 0;
9498 gboolean is_drm = FALSE;
9499 gboolean sound_extraction = FALSE;
9503 return_val_if_fail ( player, FALSE );
9505 attrs = MMPLAYER_GET_ATTRS(player);
9508 debug_error("fail to get attributes.");
9512 /* check file is drm or not */
9513 g_object_get(G_OBJECT(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), "is-drm", &is_drm, NULL);
9515 /* get sound_extraction property */
9516 mm_attrs_get_int_by_name(attrs, "pcm_extraction", &sound_extraction);
9518 if ( ! sound_extraction || is_drm )
9520 debug_log("pcm extraction param.. is drm = %d, extraction mode = %d", is_drm, sound_extraction);
9530 __mmplayer_handle_gst_error ( mm_player_t* player, GstMessage * message, GError* error )
9532 MMMessageParamType msg_param;
9533 gchar *msg_src_element;
9537 return_val_if_fail( player, FALSE );
9538 return_val_if_fail( error, FALSE );
9540 /* NOTE : do somthing necessary inside of __gst_handle_XXX_error. not here */
9542 memset (&msg_param, 0, sizeof(MMMessageParamType));
9544 if ( error->domain == GST_CORE_ERROR )
9546 msg_param.code = __gst_handle_core_error( player, error->code );
9548 else if ( error->domain == GST_LIBRARY_ERROR )
9550 msg_param.code = __gst_handle_library_error( player, error->code );
9552 else if ( error->domain == GST_RESOURCE_ERROR )
9554 msg_param.code = __gst_handle_resource_error( player, error->code );
9556 else if ( error->domain == GST_STREAM_ERROR )
9558 msg_param.code = __gst_handle_stream_error( player, error, message );
9562 debug_warning("This error domain is not defined.\n");
9564 /* we treat system error as an internal error */
9565 msg_param.code = MM_ERROR_PLAYER_INVALID_STREAM;
9570 msg_src_element = GST_ELEMENT_NAME( GST_ELEMENT_CAST( message->src ) );
9572 msg_param.data = (void *) error->message;
9574 debug_error("-Msg src : [%s] Domain : [%s] Error : [%s] Code : [%d] is tranlated to error code : [0x%x]\n",
9575 msg_src_element, g_quark_to_string (error->domain), error->message, error->code, msg_param.code);
9578 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player))
9580 __mm_player_ahs_stop (player->ahs_player);
9583 /* post error to application */
9584 if ( ! player->posted_msg )
9586 if (msg_param.code == MM_MESSAGE_DRM_NOT_AUTHORIZED)
9588 MMPLAYER_POST_MSG( player, MM_MESSAGE_DRM_NOT_AUTHORIZED, NULL );
9592 MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param );
9595 /* don't post more if one was sent already */
9596 player->posted_msg = TRUE;
9600 debug_log("skip error post because it's sent already.\n");
9609 __mmplayer_handle_streaming_error ( mm_player_t* player, GstMessage * message )
9612 MMMessageParamType msg_param;
9613 gchar *msg_src_element = NULL;
9614 GstStructure *s = NULL;
9616 gchar *error_string = NULL;
9620 return_val_if_fail ( player, FALSE );
9621 return_val_if_fail ( message, FALSE );
9623 s = malloc( sizeof(GstStructure) );
9624 memcpy ( s, gst_message_get_structure ( message ), sizeof(GstStructure));
9626 if ( !gst_structure_get_uint (s, "error_id", &error_id) )
9627 error_id = MMPLAYER_STREAMING_ERROR_NONE;
9631 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
9632 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
9634 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
9635 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
9637 case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
9638 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
9640 case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
9641 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
9643 case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
9644 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
9646 case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
9647 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
9649 case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
9650 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
9652 case MMPLAYER_STREAMING_ERROR_INVALID_URL:
9653 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
9655 case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
9656 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
9658 case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
9659 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
9661 case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
9662 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
9664 case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
9665 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
9667 case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
9668 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
9670 case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
9671 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
9673 case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
9674 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
9676 case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
9677 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
9679 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
9680 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
9682 case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
9683 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
9685 case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
9686 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
9688 case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
9689 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
9691 case MMPLAYER_STREAMING_ERROR_GONE:
9692 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
9694 case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
9695 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
9697 case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
9698 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
9700 case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
9701 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
9703 case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
9704 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
9706 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
9707 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
9709 case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
9710 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
9712 case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
9713 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
9715 case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
9716 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
9718 case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
9719 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
9721 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
9722 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
9724 case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
9725 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
9727 case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
9728 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
9730 case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
9731 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
9733 case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
9734 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
9736 case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
9737 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
9739 case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
9740 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
9742 case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
9743 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
9745 case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
9746 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
9748 case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
9749 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
9751 case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
9752 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
9754 case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
9755 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
9757 case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
9758 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
9760 case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
9761 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
9763 case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
9764 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
9767 return MM_ERROR_PLAYER_STREAMING_FAIL;
9770 error_string = g_strdup(gst_structure_get_string (s, "error_string"));
9772 msg_param.data = (void *) error_string;
9776 msg_src_element = GST_ELEMENT_NAME( GST_ELEMENT_CAST( message->src ) );
9778 debug_error("-Msg src : [%s] Code : [%x] Error : [%s] \n",
9779 msg_src_element, msg_param.code, (char*)msg_param.data );
9782 /* post error to application */
9783 if ( ! player->posted_msg )
9785 MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param );
9787 /* don't post more if one was sent already */
9788 player->posted_msg = TRUE;
9792 debug_log("skip error post because it's sent already.\n");
9802 __gst_handle_core_error( mm_player_t* player, int code )
9804 gint trans_err = MM_ERROR_NONE;
9808 return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9812 case GST_CORE_ERROR_STATE_CHANGE:
9813 case GST_CORE_ERROR_MISSING_PLUGIN:
9814 case GST_CORE_ERROR_SEEK:
9815 case GST_CORE_ERROR_NOT_IMPLEMENTED:
9816 case GST_CORE_ERROR_FAILED:
9817 case GST_CORE_ERROR_TOO_LAZY:
9818 case GST_CORE_ERROR_PAD:
9819 case GST_CORE_ERROR_THREAD:
9820 case GST_CORE_ERROR_NEGOTIATION:
9821 case GST_CORE_ERROR_EVENT:
9822 case GST_CORE_ERROR_CAPS:
9823 case GST_CORE_ERROR_TAG:
9824 case GST_CORE_ERROR_CLOCK:
9825 case GST_CORE_ERROR_DISABLED:
9827 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
9837 __gst_handle_library_error( mm_player_t* player, int code )
9839 gint trans_err = MM_ERROR_NONE;
9843 return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9847 case GST_LIBRARY_ERROR_FAILED:
9848 case GST_LIBRARY_ERROR_TOO_LAZY:
9849 case GST_LIBRARY_ERROR_INIT:
9850 case GST_LIBRARY_ERROR_SHUTDOWN:
9851 case GST_LIBRARY_ERROR_SETTINGS:
9852 case GST_LIBRARY_ERROR_ENCODE:
9854 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
9865 __gst_handle_resource_error( mm_player_t* player, int code )
9867 gint trans_err = MM_ERROR_NONE;
9871 return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9875 case GST_RESOURCE_ERROR_NO_SPACE_LEFT:
9876 trans_err = MM_ERROR_PLAYER_NO_FREE_SPACE;
9878 case GST_RESOURCE_ERROR_NOT_FOUND:
9879 case GST_RESOURCE_ERROR_OPEN_READ:
9880 if ( MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING ( player ) )
9882 trans_err = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
9885 case GST_RESOURCE_ERROR_READ:
9886 if ( MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING ( player ))
9888 trans_err = MM_ERROR_PLAYER_STREAMING_FAIL;
9891 case GST_RESOURCE_ERROR_SEEK:
9892 case GST_RESOURCE_ERROR_FAILED:
9893 case GST_RESOURCE_ERROR_TOO_LAZY:
9894 case GST_RESOURCE_ERROR_BUSY:
9895 case GST_RESOURCE_ERROR_OPEN_WRITE:
9896 case GST_RESOURCE_ERROR_OPEN_READ_WRITE:
9897 case GST_RESOURCE_ERROR_CLOSE:
9898 case GST_RESOURCE_ERROR_WRITE:
9899 case GST_RESOURCE_ERROR_SYNC:
9900 case GST_RESOURCE_ERROR_SETTINGS:
9902 trans_err = MM_ERROR_PLAYER_FILE_NOT_FOUND;
9913 __gst_handle_stream_error( mm_player_t* player, GError* error, GstMessage * message )
9915 gint trans_err = MM_ERROR_NONE;
9919 return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9920 return_val_if_fail( error, MM_ERROR_INVALID_ARGUMENT );
9921 return_val_if_fail ( message, MM_ERROR_INVALID_ARGUMENT );
9923 switch ( error->code )
9925 case GST_STREAM_ERROR_FAILED:
9926 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
9927 case GST_STREAM_ERROR_DECODE:
9928 case GST_STREAM_ERROR_WRONG_TYPE:
9929 case GST_STREAM_ERROR_DECRYPT:
9930 trans_err = __gst_transform_gsterror( player, message, error );
9933 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
9934 case GST_STREAM_ERROR_NOT_IMPLEMENTED:
9935 case GST_STREAM_ERROR_TOO_LAZY:
9936 case GST_STREAM_ERROR_ENCODE:
9937 case GST_STREAM_ERROR_DEMUX:
9938 case GST_STREAM_ERROR_MUX:
9939 case GST_STREAM_ERROR_FORMAT:
9940 case GST_STREAM_ERROR_DECRYPT_NOKEY:
9942 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
9952 /* NOTE : decide gstreamer state whether there is some playable track or not. */
9954 __gst_transform_gsterror( mm_player_t* player, GstMessage * message, GError* error )
9956 gchar *src_element_name = NULL;
9957 GstElement *src_element = NULL;
9958 GstElementFactory *factory = NULL;
9959 const gchar* klass = NULL;
9964 return_val_if_fail ( message, MM_ERROR_INVALID_ARGUMENT );
9965 return_val_if_fail ( message->src, MM_ERROR_INVALID_ARGUMENT );
9966 return_val_if_fail ( error, MM_ERROR_INVALID_ARGUMENT );
9968 src_element = GST_ELEMENT_CAST(message->src);
9970 goto INTERNAL_ERROR;
9972 src_element_name = GST_ELEMENT_NAME(src_element);
9973 if ( !src_element_name )
9974 goto INTERNAL_ERROR;
9976 factory = gst_element_get_factory(src_element);
9978 goto INTERNAL_ERROR;
9980 klass = gst_element_factory_get_klass(factory);
9982 goto INTERNAL_ERROR;
9984 debug_log("error code=%d, msg=%s, src element=%s, class=%s\n",
9985 error->code, error->message, src_element_name, klass);
9988 switch ( error->code )
9990 case GST_STREAM_ERROR_DECODE:
9992 /* NOTE : Delay is needed because gst callback is sometime sent
9993 * before completing autoplugging.
9994 * Timer is more better than usleep.
9995 * But, transformed msg value should be stored in player handle
9996 * for function to call by timer.
9998 if ( PLAYER_INI()->async_start )
10001 /* Demuxer can't parse one track because it's corrupted.
10002 * So, the decoder for it is not linked.
10003 * But, it has one playable track.
10005 if ( g_strrstr(klass, "Demux") )
10007 if ( player->can_support_codec == FOUND_PLUGIN_VIDEO )
10009 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
10011 else if ( player->can_support_codec == FOUND_PLUGIN_AUDIO )
10013 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
10017 if ( player->pipeline->audiobin ) // PCM
10019 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
10023 goto CODEC_NOT_FOUND;
10027 return MM_ERROR_PLAYER_INVALID_STREAM;
10031 case GST_STREAM_ERROR_WRONG_TYPE:
10033 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
10037 case GST_STREAM_ERROR_FAILED:
10039 /* Decoder Custom Message */
10040 if ( strstr(error->message, "ongoing") )
10042 if ( strcasestr(klass, "audio") )
10044 if ( ( player->can_support_codec & FOUND_PLUGIN_VIDEO ) )
10046 debug_log("Video can keep playing.\n");
10047 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
10051 goto CODEC_NOT_FOUND;
10055 else if ( strcasestr(klass, "video") )
10057 if ( ( player->can_support_codec & FOUND_PLUGIN_AUDIO ) )
10059 debug_log("Audio can keep playing.\n");
10060 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
10064 goto CODEC_NOT_FOUND;
10068 return MM_ERROR_PLAYER_INVALID_STREAM;
10072 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
10074 goto CODEC_NOT_FOUND;
10078 case GST_STREAM_ERROR_DECRYPT:
10080 debug_log("%s failed reason : %s\n", src_element_name, error->message);
10081 return MM_MESSAGE_DRM_NOT_AUTHORIZED;
10091 return MM_ERROR_PLAYER_INVALID_STREAM;
10094 return MM_ERROR_PLAYER_INTERNAL;
10097 debug_log("not found any available codec. Player should be destroyed.\n");
10098 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
10102 __mmplayer_post_delayed_eos( mm_player_t* player, int delay_in_ms )
10106 return_if_fail( player );
10108 /* cancel if existing */
10109 __mmplayer_cancel_delayed_eos( player );
10112 /* post now if delay is zero */
10113 if ( delay_in_ms == 0 || player->is_sound_extraction)
10115 debug_log("eos delay is zero. posting EOS now\n");
10116 MMPLAYER_POST_MSG( player, MM_MESSAGE_END_OF_STREAM, NULL );
10118 if ( player->is_sound_extraction )
10119 __mmplayer_cancel_delayed_eos(player);
10124 /* init new timeout */
10125 /* NOTE : consider give high priority to this timer */
10127 debug_log("posting EOS message after [%d] msec\n", delay_in_ms);
10128 player->eos_timer = g_timeout_add( delay_in_ms,
10129 __mmplayer_eos_timer_cb, player );
10132 /* check timer is valid. if not, send EOS now */
10133 if ( player->eos_timer == 0 )
10135 debug_warning("creating timer for delayed EOS has failed. sending EOS now\n");
10136 MMPLAYER_POST_MSG( player, MM_MESSAGE_END_OF_STREAM, NULL );
10143 __mmplayer_cancel_delayed_eos( mm_player_t* player )
10147 return_if_fail( player );
10149 if ( player->eos_timer )
10151 g_source_remove( player->eos_timer );
10154 player->eos_timer = 0;
10162 __mmplayer_eos_timer_cb(gpointer u_data)
10164 mm_player_t* player = NULL;
10165 player = (mm_player_t*) u_data;
10169 return_val_if_fail( player, FALSE );
10172 MMPLAYER_POST_MSG( player, MM_MESSAGE_END_OF_STREAM, NULL );
10174 /* cleare timer id */
10175 player->eos_timer = 0;
10179 /* we are returning FALSE as we need only one posting */
10183 static void __mmplayer_set_antishock( mm_player_t* player, gboolean disable_by_force)
10185 gint antishock = FALSE;
10186 MMHandleType attrs = 0;
10190 return_if_fail ( player && player->pipeline );
10192 /* It should be passed for video only clip */
10193 if ( ! player->pipeline->audiobin )
10196 if ( ( g_strrstr(PLAYER_INI()->name_of_audiosink, "avsysaudiosink")) )
10198 attrs = MMPLAYER_GET_ATTRS(player);
10201 debug_error("fail to get attributes.\n");
10205 mm_attrs_get_int_by_name(attrs, "sound_fadeup", &antishock);
10207 debug_log("setting antishock as (%d)\n", antishock);
10209 if ( disable_by_force )
10211 debug_log("but, antishock is disabled by force when is seeked\n");
10216 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "fadeup", antishock, NULL);
10226 __mmplayer_link_decoder( mm_player_t* player, GstPad *srcpad)
10228 const gchar* name = NULL;
10229 GstStructure* str = NULL;
10230 GstCaps* srccaps = NULL;
10234 return_val_if_fail( player, FALSE );
10235 return_val_if_fail ( srcpad, FALSE );
10237 /* to check any of the decoder (video/audio) need to be linked to parser*/
10238 srccaps = gst_pad_get_caps( srcpad );
10242 str = gst_caps_get_structure( srccaps, 0 );
10246 name = gst_structure_get_name(str);
10250 if (strstr(name, "video"))
10252 if(player->videodec_linked)
10254 debug_msg("Video decoder already linked\n");
10258 if (strstr(name, "audio"))
10260 if(player->audiodec_linked)
10262 debug_msg("Audio decoder already linked\n");
10267 gst_caps_unref( srccaps );
10275 gst_caps_unref( srccaps );
10281 __mmplayer_link_sink( mm_player_t* player , GstPad *srcpad)
10283 const gchar* name = NULL;
10284 GstStructure* str = NULL;
10285 GstCaps* srccaps = NULL;
10289 return_val_if_fail ( player, FALSE );
10290 return_val_if_fail ( srcpad, FALSE );
10292 /* to check any of the decoder (video/audio) need to be linked to parser*/
10293 srccaps = gst_pad_get_caps( srcpad );
10297 str = gst_caps_get_structure( srccaps, 0 );
10301 name = gst_structure_get_name(str);
10305 if (strstr(name, "video"))
10307 if(player->videosink_linked)
10309 debug_msg("Video Sink already linked\n");
10313 if (strstr(name, "audio"))
10315 if(player->audiosink_linked)
10317 debug_msg("Audio Sink already linked\n");
10321 if (strstr(name, "text"))
10323 if(player->textsink_linked)
10325 debug_msg("Text Sink already linked\n");
10330 gst_caps_unref( srccaps );
10335 //return (!player->videosink_linked || !player->audiosink_linked);
10339 gst_caps_unref( srccaps );
10345 /* sending event to one of sinkelements */
10347 __gst_send_event_to_sink( mm_player_t* player, GstEvent* event )
10349 GList *sinks = NULL;
10350 gboolean res = FALSE;
10354 return_val_if_fail( player, FALSE );
10355 return_val_if_fail ( event, FALSE );
10357 sinks = player->sink_elements;
10360 GstElement *sink = GST_ELEMENT_CAST (sinks->data);
10364 /* keep ref to the event */
10365 gst_event_ref (event);
10367 debug_log("sending event[%s] to sink element [%s]\n",
10368 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink) );
10370 if ( (res = gst_element_send_event (sink, event)) )
10372 debug_log("sending event[%s] to sink element [%s] success!\n",
10373 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink) );
10377 debug_log("sending event[%s] to sink element [%s] failed. try with next one.\n",
10378 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink) );
10381 sinks = g_list_next (sinks);
10384 /* Note : Textbin is not linked to the video or audio bin.
10385 * It needs to send the event to the text sink seperatelly.
10387 if ( MMPLAYER_PLAY_SUBTITLE(player) )
10389 GstElement *subtitle_sink = GST_ELEMENT_CAST (player->pipeline->subtitlebin[MMPLAYER_SUB_SINK].gst);
10391 if ( (res != gst_element_send_event (subtitle_sink, event)) )
10393 debug_error("sending event[%s] to subtitle sink element [%s] failed!\n",
10394 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(subtitle_sink) );
10398 debug_log("sending event[%s] to subtitle sink element [%s] success!\n",
10399 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(subtitle_sink) );
10403 gst_event_unref (event);
10411 __mmplayer_add_sink( mm_player_t* player, GstElement* sink )
10415 return_if_fail ( player );
10416 return_if_fail ( sink );
10418 player->sink_elements =
10419 g_list_append(player->sink_elements, sink);
10425 __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
10426 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
10427 gint64 cur, GstSeekType stop_type, gint64 stop )
10429 GstEvent* event = NULL;
10430 gboolean result = FALSE;
10434 return_val_if_fail( player, FALSE );
10436 event = gst_event_new_seek (rate, format, flags, cur_type,
10437 cur, stop_type, stop);
10439 result = __gst_send_event_to_sink( player, event );
10441 /* Note : After sending seek event, the sink elements receive flush event
10442 * Not only buffering state but after seeking, state_lost needs to be set to TRUE.
10444 if ( MMPLAYER_IS_RTSP_STREAMING ( player ) && result )
10445 player->state_lost = TRUE;
10452 /* NOTE : be careful with calling this api. please refer to below glib comment
10453 * glib comment : Note that there is a bug in GObject that makes this function much
10454 * less useful than it might seem otherwise. Once gobject is disposed, the callback
10455 * will no longer be called, but, the signal handler is not currently disconnected.
10456 * If the instance is itself being freed at the same time than this doesn't matter,
10457 * since the signal will automatically be removed, but if instance persists,
10458 * then the signal handler will leak. You should not remove the signal yourself
10459 * because in a future versions of GObject, the handler will automatically be
10462 * It's possible to work around this problem in a way that will continue to work
10463 * with future versions of GObject by checking that the signal handler is still
10464 * connected before disconnected it:
10466 * if (g_signal_handler_is_connected (instance, id))
10467 * g_signal_handler_disconnect (instance, id);
10470 __mmplayer_release_signal_connection(mm_player_t* player)
10472 GList* sig_list = player->signals;
10473 MMPlayerSignalItem* item = NULL;
10477 return_if_fail( player );
10479 for ( ; sig_list; sig_list = sig_list->next )
10481 item = sig_list->data;
10483 if ( item && item->obj && GST_IS_ELEMENT(item->obj) )
10485 debug_log("checking signal connection : [%lud] from [%s]\n", item->sig, GST_OBJECT_NAME( item->obj ));
10487 if ( g_signal_handler_is_connected ( item->obj, item->sig ) )
10489 debug_log("signal disconnecting : [%lud] from [%s]\n", item->sig, GST_OBJECT_NAME( item->obj ));
10490 g_signal_handler_disconnect ( item->obj, item->sig );
10494 MMPLAYER_FREEIF( item );
10497 g_list_free ( player->signals );
10498 player->signals = NULL;
10506 /* Note : if silent is true, then subtitle would not be displayed. :*/
10507 int _mmplayer_set_subtitle_silent (MMHandleType hplayer, int silent)
10509 mm_player_t* player = (mm_player_t*) hplayer;
10513 /* check player handle */
10514 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED );
10515 return_val_if_fail ( MMPLAYER_PLAY_SUBTITLE(player), MM_ERROR_PLAYER_NOT_INITIALIZED );
10517 player->is_subtitle_off = silent;
10519 debug_log("subtitle is %s.\n", player->is_subtitle_off ? "ON" : "OFF");
10523 return MM_ERROR_NONE;
10527 int _mmplayer_get_subtitle_silent (MMHandleType hplayer, int* silent)
10529 mm_player_t* player = (mm_player_t*) hplayer;
10533 /* check player handle */
10534 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED );
10535 return_val_if_fail ( MMPLAYER_PLAY_SUBTITLE(player), MM_ERROR_PLAYER_NOT_INITIALIZED );
10537 *silent = player->is_subtitle_off;
10539 debug_log("subtitle is %s.\n", silent ? "ON" : "OFF");
10543 return MM_ERROR_NONE;
10546 int _mmplayer_get_track_count(MMHandleType hplayer, MMPlayerTrackType track_type, int *count)
10548 mm_player_t* player = (mm_player_t*) hplayer;
10549 MMHandleType attrs = 0;
10550 int ret = MM_ERROR_NONE;
10554 /* check player handle */
10555 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10556 return_val_if_fail(count, MM_ERROR_COMMON_INVALID_ARGUMENT);
10557 return_val_if_fail((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
10558 ||(MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING),
10559 MM_ERROR_PLAYER_INVALID_STATE);
10561 attrs = MMPLAYER_GET_ATTRS(player);
10564 debug_error("cannot get content attribute");
10565 return MM_ERROR_PLAYER_INTERNAL;
10568 switch (track_type)
10570 case MM_PLAYER_TRACK_TYPE_AUDIO:
10571 ret = mm_attrs_get_int_by_name(attrs, "content_audio_track_num", count);
10573 case MM_PLAYER_TRACK_TYPE_VIDEO:
10574 ret = mm_attrs_get_int_by_name(attrs, "content_video_track_num", count);
10576 case MM_PLAYER_TRACK_TYPE_TEXT:
10577 ret = mm_attrs_get_int_by_name(attrs, "content_text_track_num", count);
10580 ret = MM_ERROR_COMMON_INVALID_ARGUMENT;
10584 debug_log ("%d track num is %d\n", track_type, *count);
10594 __get_state_name ( int state )
10598 case MM_PLAYER_STATE_NULL:
10600 case MM_PLAYER_STATE_READY:
10602 case MM_PLAYER_STATE_PAUSED:
10604 case MM_PLAYER_STATE_PLAYING:
10606 case MM_PLAYER_STATE_NONE:
10613 __is_rtsp_streaming ( mm_player_t* player )
10615 return_val_if_fail ( player, FALSE );
10617 return ( player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_RTSP ) ? TRUE : FALSE;
10621 __is_http_streaming ( mm_player_t* player )
10623 return_val_if_fail ( player, FALSE );
10625 return ( player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_HTTP ) ? TRUE : FALSE;
10629 __is_streaming ( mm_player_t* player )
10631 return_val_if_fail ( player, FALSE );
10633 return ( __is_rtsp_streaming ( player ) || __is_http_streaming ( player ) || __is_http_live_streaming ( player )) ? TRUE : FALSE;
10637 __is_live_streaming ( mm_player_t* player )
10639 return_val_if_fail ( player, FALSE );
10641 return ( __is_rtsp_streaming ( player ) && player->streaming_type == STREAMING_SERVICE_LIVE ) ? TRUE : FALSE;
10645 __is_http_live_streaming( mm_player_t* player )
10647 return_val_if_fail( player, FALSE );
10649 return ( (player->ahs_player) && (player->profile.uri_type == MM_PLAYER_URI_TYPE_HLS) ) ? TRUE : FALSE;
10653 __is_http_progressive_down(mm_player_t* player)
10655 return_val_if_fail( player, FALSE );
10657 return ((player->pd_mode) ? TRUE:FALSE);