4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <gst/app/gstappsrc.h>
31 #include <gst/video/videooverlay.h>
33 #include <gst/wayland/wayland.h>
35 #include <gst/audio/gstaudiobasesink.h>
44 #include <mm_attrs_private.h>
47 #include "mm_player_priv.h"
48 #include "mm_player_ini.h"
49 #include "mm_player_attrs.h"
50 #include "mm_player_capture.h"
51 #include "mm_player_utils.h"
52 #include "mm_player_tracks.h"
57 #define MM_SMOOTH_STREAMING
59 /*===========================================================================================
61 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
63 ========================================================================================== */
65 /*---------------------------------------------------------------------------
66 | GLOBAL CONSTANT DEFINITIONS: |
67 ---------------------------------------------------------------------------*/
69 /*---------------------------------------------------------------------------
70 | IMPORTED VARIABLE DECLARATIONS: |
71 ---------------------------------------------------------------------------*/
73 /*---------------------------------------------------------------------------
74 | IMPORTED FUNCTION DECLARATIONS: |
75 ---------------------------------------------------------------------------*/
77 /*---------------------------------------------------------------------------
79 ---------------------------------------------------------------------------*/
80 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
81 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
83 #define MM_VOLUME_FACTOR_DEFAULT 1.0
84 #define MM_VOLUME_FACTOR_MIN 0
85 #define MM_VOLUME_FACTOR_MAX 1.0
87 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 700000 // 700 msec
89 #define MM_PLAYER_MPEG_VNAME "mpegversion"
90 #define MM_PLAYER_DIVX_VNAME "divxversion"
91 #define MM_PLAYER_WMV_VNAME "wmvversion"
92 #define MM_PLAYER_WMA_VNAME "wmaversion"
94 #define DEFAULT_PLAYBACK_RATE 1.0
95 #define PLAYBACK_RATE_EX_AUDIO_MIN 0.5
96 #define PLAYBACK_RATE_EX_AUDIO_MAX 2.0
97 #define PLAYBACK_RATE_EX_VIDEO_MIN 0.5
98 #define PLAYBACK_RATE_EX_VIDEO_MAX 1.5
100 #define GST_QUEUE_DEFAULT_TIME 4
101 #define GST_QUEUE_HLS_TIME 8
103 #define DEFAULT_AUDIO_CH 0
105 #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) )
107 #define LAZY_PAUSE_TIMEOUT_MSEC 700
108 #define MM_PLAYER_NAME "mmplayer"
110 #define SMOOTH_STREAMING_DEMUX "mssdemux"
112 * g_array_index(a,t,i) does not calculate gst private structure.
113 * It replaces the g_array_index(a,t,i)
115 #define g_array_undef_struct_idx_p(a,t,i) ((t *)(void *)((a)->data + ((i) * (a)->len)))
117 //#define ENABLE_DRMSRC
119 /*---------------------------------------------------------------------------
120 | LOCAL CONSTANT DEFINITIONS: |
121 ---------------------------------------------------------------------------*/
123 /*---------------------------------------------------------------------------
124 | LOCAL DATA TYPE DEFINITIONS: |
125 ---------------------------------------------------------------------------*/
127 /*---------------------------------------------------------------------------
128 | GLOBAL VARIABLE DEFINITIONS: |
129 ---------------------------------------------------------------------------*/
131 /*---------------------------------------------------------------------------
132 | LOCAL VARIABLE DEFINITIONS: |
133 ---------------------------------------------------------------------------*/
135 /*---------------------------------------------------------------------------
136 | LOCAL FUNCTION PROTOTYPES: |
137 ---------------------------------------------------------------------------*/
138 static int __mmplayer_set_state(mm_player_t* player, int state);
139 static int __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps *caps, MMDisplaySurfaceType surface_type);
140 static int __mmplayer_gst_create_audio_pipeline(mm_player_t* player);
141 static int __mmplayer_gst_create_text_pipeline(mm_player_t* player);
142 static int __mmplayer_gst_create_subtitle_src(mm_player_t* player);
143 static int __mmplayer_gst_create_pipeline(mm_player_t* player);
144 static int __mmplayer_gst_destroy_pipeline(mm_player_t* player);
145 static int __mmplayer_gst_element_link_bucket(GList* element_bucket);
147 static gboolean __mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data);
148 static GstPadProbeReturn __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data);
149 static void __mmplayer_gst_decode_pad_added(GstElement* elem, GstPad* pad, gpointer data);
150 static void __mmplayer_gst_decode_no_more_pads(GstElement* elem, gpointer data);
151 static void __mmplayer_gst_decode_callback(GstElement *decodebin, GstPad *pad, gpointer data);
152 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad, GstCaps *caps, gpointer data);
153 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad, GstCaps * caps, gpointer data);
154 static gint __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad, GstCaps * caps, GstElementFactory* factory, gpointer data);
155 //static GValueArray* __mmplayer_gst_decode_autoplug_factories(GstElement *bin, GstPad* pad, GstCaps * caps, gpointer data);
156 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad, gpointer data);
157 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
158 static void __mmplayer_gst_element_added(GstElement* bin, GstElement* element, gpointer data);
159 static GstElement * __mmplayer_create_decodebin(mm_player_t* player);
160 static gboolean __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps);
162 static void __mmplayer_typefind_have_type( GstElement *tf, guint probability, GstCaps *caps, gpointer data);
163 static gboolean __mmplayer_try_to_plug(mm_player_t* player, GstPad *pad, const GstCaps *caps);
164 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
165 static gboolean __mmplayer_is_midi_type(gchar* str_caps);
166 static gboolean __mmplayer_is_only_mp3_type (gchar *str_caps);
167 static void __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps);
168 //static void __mmplayer_check_video_zero_cpoy(mm_player_t* player, GstElementFactory* factory);
170 static gboolean __mmplayer_close_link(mm_player_t* player, GstPad *srcpad, GstElement *sinkelement, const char *padname, const GList *templlist);
171 static gboolean __mmplayer_feature_filter(GstPluginFeature *feature, gpointer data);
172 static void __mmplayer_add_new_pad(GstElement *element, GstPad *pad, gpointer data);
174 static void __mmplayer_gst_rtp_no_more_pads (GstElement *element, gpointer data);
175 //static void __mmplayer_gst_wfd_dynamic_pad (GstElement *element, GstPad *pad, gpointer data);
176 static void __mmplayer_gst_rtp_dynamic_pad (GstElement *element, GstPad *pad, gpointer data);
177 static gboolean __mmplayer_get_stream_service_type( mm_player_t* player );
178 static gboolean __mmplayer_update_subtitle( GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
181 static void __mmplayer_init_factories(mm_player_t* player);
182 static void __mmplayer_release_factories(mm_player_t* player);
183 static void __mmplayer_release_misc(mm_player_t* player);
184 static void __mmplayer_release_misc_post(mm_player_t* player);
185 static gboolean __mmplayer_init_gstreamer(mm_player_t* player);
187 static int __mmplayer_gst_set_state (mm_player_t* player, GstElement * pipeline, GstState state, gboolean async, gint timeout );
188 static gboolean __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage *msg);
189 static gboolean __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg);
191 int __mmplayer_switch_audio_sink (mm_player_t* player);
192 static gboolean __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink);
193 static int __mmplayer_check_state(mm_player_t* player, enum PlayerCommandState command);
194 static GstPadProbeReturn __mmplayer_audio_stream_probe (GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
195 static GstPadProbeReturn __mmplayer_video_stream_probe (GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
196 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe (GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
197 static int __mmplayer_change_selector_pad (mm_player_t* player, MMPlayerTrackType type, int index);
199 static gboolean __mmplayer_dump_pipeline_state( mm_player_t* player );
200 static gboolean __mmplayer_check_subtitle( mm_player_t* player );
201 static gboolean __mmplayer_handle_gst_error ( mm_player_t* player, GstMessage * message, GError* error );
202 static gboolean __mmplayer_handle_streaming_error ( mm_player_t* player, GstMessage * message );
203 static void __mmplayer_handle_eos_delay( mm_player_t* player, int delay_in_ms );
204 static void __mmplayer_cancel_eos_timer( mm_player_t* player );
205 static gboolean __mmplayer_eos_timer_cb(gpointer u_data);
206 static gboolean __mmplayer_link_decoder( mm_player_t* player,GstPad *srcpad);
207 static gboolean __mmplayer_link_sink( mm_player_t* player,GstPad *srcpad);
208 static int __mmplayer_handle_missed_plugin(mm_player_t* player);
209 static int __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime);
210 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player);
211 static void __mmplayer_add_sink( mm_player_t* player, GstElement* sink);
212 static void __mmplayer_del_sink( mm_player_t* player, GstElement* sink);
213 static void __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type);
214 static void __mmplayer_set_antishock( mm_player_t* player, gboolean disable_by_force);
215 static gpointer __mmplayer_next_play_thread(gpointer data);
216 static gpointer __mmplayer_repeat_thread(gpointer data);
217 static gboolean _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag);
220 static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element);
221 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
222 static void __mmplayer_release_dump_list (GList *dump_list);
224 static int __gst_realize(mm_player_t* player);
225 static int __gst_unrealize(mm_player_t* player);
226 static int __gst_start(mm_player_t* player);
227 static int __gst_stop(mm_player_t* player);
228 static int __gst_pause(mm_player_t* player, gboolean async);
229 static int __gst_resume(mm_player_t* player, gboolean async);
230 static gboolean __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
231 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
232 gint64 cur, GstSeekType stop_type, gint64 stop );
233 static int __gst_pending_seek ( mm_player_t* player );
235 static int __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called);
236 static int __gst_get_position(mm_player_t* player, int format, unsigned long *position);
237 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos);
238 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position);
239 static int __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param);
241 static gint __gst_handle_core_error( mm_player_t* player, int code );
242 static gint __gst_handle_library_error( mm_player_t* player, int code );
243 static gint __gst_handle_resource_error( mm_player_t* player, int code );
244 static gint __gst_handle_stream_error( mm_player_t* player, GError* error, GstMessage * message );
245 static gint __gst_transform_gsterror( mm_player_t* player, GstMessage * message, GError* error);
246 static gboolean __gst_send_event_to_sink( mm_player_t* player, GstEvent* event );
248 static int __mmplayer_set_pcm_extraction(mm_player_t* player);
249 static gboolean __mmplayer_can_extract_pcm( mm_player_t* player );
252 static void __mmplayer_do_sound_fadedown(mm_player_t* player, unsigned int time);
253 static void __mmplayer_undo_sound_fadedown(mm_player_t* player);
255 static void __mmplayer_add_new_caps(GstPad* pad, GParamSpec* unused, gpointer data);
256 static void __mmplayer_set_unlinked_mime_type(mm_player_t* player, GstCaps *caps);
259 const gchar * __get_state_name ( int state );
260 static gboolean __is_streaming( mm_player_t* player );
261 static gboolean __is_rtsp_streaming( mm_player_t* player );
262 static gboolean __is_wfd_streaming( mm_player_t* player );
263 static gboolean __is_live_streaming ( mm_player_t* player );
264 static gboolean __is_http_streaming( mm_player_t* player );
265 static gboolean __is_http_live_streaming( mm_player_t* player );
266 static gboolean __is_dash_streaming( mm_player_t* player );
267 static gboolean __is_smooth_streaming( mm_player_t* player );
268 static gboolean __is_http_progressive_down(mm_player_t* player);
269 static gboolean __is_es_buff_src(mm_player_t* player);
270 static gboolean __has_suffix(mm_player_t * player, const gchar * suffix);
272 static GstBusSyncReply __mmplayer_bus_sync_callback (GstBus * bus, GstMessage * message, gpointer data);
274 static int __mmplayer_realize_streaming_ext(mm_player_t* player);
275 static int __mmplayer_unrealize_streaming_ext(mm_player_t *player);
276 static int __mmplayer_start_streaming_ext(mm_player_t *player);
277 static int __mmplayer_destroy_streaming_ext(mm_player_t* player);
278 static int __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay);
279 static void __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id);
281 static gboolean __mmplayer_verify_next_play_path(mm_player_t *player);
282 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
283 static void __mmplayer_check_pipeline(mm_player_t* player);
284 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
285 static void __mmplayer_deactivate_old_path(mm_player_t *player);
286 #if 0 // We'll need this in future.
287 static int __mmplayer_gst_switching_element(mm_player_t *player, GstElement *search_from, const gchar *removal_name, const gchar *new_element_name);
290 static void __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg);
291 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name);
292 static gboolean __mmplayer_can_do_interrupt(mm_player_t *player);
294 /* device change post proc */
295 void __mmplayer_device_change_post_process(gpointer user);
296 void __mmplayer_set_required_cb_score(mm_player_t* player, guint score);
297 void __mmplayer_inc_cb_score(mm_player_t* player);
298 void __mmplayer_post_proc_reset(mm_player_t* player);
299 void __mmplayer_device_change_trigger_post_process(mm_player_t* player);
300 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player);
301 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name);
302 static void __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data);
303 static void __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data);
304 static void __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data);
305 static void __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data);
306 static void __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data);
307 static gboolean __gst_seek_audio_data (GstElement * appsrc, guint64 position, gpointer user_data);
308 static gboolean __gst_seek_video_data (GstElement * appsrc, guint64 position, gpointer user_data);
309 static gboolean __gst_seek_subtitle_data (GstElement * appsrc, guint64 position, gpointer user_data);
310 /*===========================================================================================
312 | FUNCTION DEFINITIONS |
314 ========================================================================================== */
318 print_tag (const GstTagList * list, const gchar * tag, gpointer unused)
322 count = gst_tag_list_get_tag_size (list, tag);
324 debug_log("count = %d", count);
326 for (i = 0; i < count; i++) {
329 if (gst_tag_get_type (tag) == G_TYPE_STRING) {
330 if (!gst_tag_list_get_string_index (list, tag, i, &str))
331 g_assert_not_reached ();
334 g_strdup_value_contents (gst_tag_list_get_value_index (list, tag, i));
338 g_print (" %15s: %s\n", gst_tag_get_nick (tag), str);
340 g_print (" : %s\n", str);
348 /* implementing player FSM */
349 /* FIXIT : We need to handle state transition also at here since start api is no more sync */
351 __mmplayer_check_state(mm_player_t* player, enum PlayerCommandState command)
353 MMPlayerStateType current_state = MM_PLAYER_STATE_NUM;
354 MMPlayerStateType pending_state = MM_PLAYER_STATE_NUM;
355 // MMPlayerStateType target_state = MM_PLAYER_STATE_NUM;
356 // MMPlayerStateType prev_state = MM_PLAYER_STATE_NUM;
358 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
360 //debug_log("incomming command : %d \n", command );
362 current_state = MMPLAYER_CURRENT_STATE(player);
363 pending_state = MMPLAYER_PENDING_STATE(player);
364 // target_state = MMPLAYER_TARGET_STATE(player);
365 // prev_state = MMPLAYER_PREV_STATE(player);
367 MMPLAYER_PRINT_STATE(player);
371 case MMPLAYER_COMMAND_CREATE:
373 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
375 if ( current_state == MM_PLAYER_STATE_NULL ||
376 current_state == MM_PLAYER_STATE_READY ||
377 current_state == MM_PLAYER_STATE_PAUSED ||
378 current_state == MM_PLAYER_STATE_PLAYING )
383 case MMPLAYER_COMMAND_DESTROY:
385 /* destroy can called anytime */
387 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
391 case MMPLAYER_COMMAND_REALIZE:
393 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
395 if ( pending_state != MM_PLAYER_STATE_NONE )
401 /* need ready state to realize */
402 if ( current_state == MM_PLAYER_STATE_READY )
405 if ( current_state != MM_PLAYER_STATE_NULL )
411 case MMPLAYER_COMMAND_UNREALIZE:
413 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
415 if ( current_state == MM_PLAYER_STATE_NULL )
420 case MMPLAYER_COMMAND_START:
422 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
424 if ( pending_state == MM_PLAYER_STATE_NONE )
426 if ( current_state == MM_PLAYER_STATE_PLAYING )
428 else if ( current_state != MM_PLAYER_STATE_READY &&
429 current_state != MM_PLAYER_STATE_PAUSED )
432 else if ( pending_state == MM_PLAYER_STATE_PLAYING )
436 else if ( pending_state == MM_PLAYER_STATE_PAUSED )
438 debug_log("player is going to paused state, just change the pending state as playing");
447 case MMPLAYER_COMMAND_STOP:
449 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
451 if ( current_state == MM_PLAYER_STATE_READY )
454 /* need playing/paused state to stop */
455 if ( current_state != MM_PLAYER_STATE_PLAYING &&
456 current_state != MM_PLAYER_STATE_PAUSED )
461 case MMPLAYER_COMMAND_PAUSE:
463 if ( MMPLAYER_IS_LIVE_STREAMING( player ) )
466 if (player->doing_seek)
467 goto NOT_COMPLETED_SEEK;
469 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
471 if ( pending_state == MM_PLAYER_STATE_NONE )
473 if ( current_state == MM_PLAYER_STATE_PAUSED )
475 else if ( current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY ) // support loading state of broswer
478 else if ( pending_state == MM_PLAYER_STATE_PAUSED )
482 else if ( pending_state == MM_PLAYER_STATE_PLAYING )
484 if ( current_state == MM_PLAYER_STATE_PAUSED ) {
485 debug_log("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
493 case MMPLAYER_COMMAND_RESUME:
496 if (player->doing_seek)
497 goto NOT_COMPLETED_SEEK;
499 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
501 if ( pending_state == MM_PLAYER_STATE_NONE )
503 if ( current_state == MM_PLAYER_STATE_PLAYING )
505 else if ( current_state != MM_PLAYER_STATE_PAUSED )
508 else if ( pending_state == MM_PLAYER_STATE_PLAYING )
512 else if ( pending_state == MM_PLAYER_STATE_PAUSED )
514 debug_log("player is going to paused state, just change the pending state as playing");
526 player->cmd = command;
528 return MM_ERROR_NONE;
531 debug_warning("since player is in wrong state(%s). it's not able to apply the command(%d)",
532 MMPLAYER_STATE_GET_NAME(current_state), command);
533 return MM_ERROR_PLAYER_INVALID_STATE;
536 debug_warning("not completed seek");
537 return MM_ERROR_PLAYER_DOING_SEEK;
540 debug_warning("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
541 return MM_ERROR_PLAYER_NO_OP;
544 debug_warning("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
545 return MM_ERROR_PLAYER_NO_OP;
549 __mmplayer_gst_set_state (mm_player_t* player, GstElement * element, GstState state, gboolean async, gint timeout) // @
551 GstState element_state = GST_STATE_VOID_PENDING;
552 GstState element_pending_state = GST_STATE_VOID_PENDING;
553 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
557 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
558 return_val_if_fail ( element, MM_ERROR_INVALID_ARGUMENT );
560 debug_log("setting [%s] element state to : %s\n", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
563 ret = gst_element_set_state(element, state);
565 if ( ret == GST_STATE_CHANGE_FAILURE )
567 debug_error("failed to set [%s] state\n", GST_ELEMENT_NAME(element));
569 /* dump state of all element */
570 __mmplayer_dump_pipeline_state( player );
572 return MM_ERROR_PLAYER_INTERNAL;
575 /* return here so state transition to be done in async mode */
578 debug_log("async state transition. not waiting for state complete.\n");
579 return MM_ERROR_NONE;
582 /* wait for state transition */
583 ret = gst_element_get_state( element, &element_state, &element_pending_state, timeout * GST_SECOND );
585 if ( ret == GST_STATE_CHANGE_FAILURE || ( state != element_state ) )
587 debug_error("failed to change [%s] element state to [%s] within %d sec\n",
588 GST_ELEMENT_NAME(element),
589 gst_element_state_get_name(state), timeout );
591 debug_error(" [%s] state : %s pending : %s \n",
592 GST_ELEMENT_NAME(element),
593 gst_element_state_get_name(element_state),
594 gst_element_state_get_name(element_pending_state) );
596 /* dump state of all element */
597 __mmplayer_dump_pipeline_state( player );
599 return MM_ERROR_PLAYER_INTERNAL;
602 debug_log("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
606 return MM_ERROR_NONE;
610 __mmplayer_videostream_cb(GstElement *element, void *data,
611 int width, int height, gpointer user_data) // @
613 mm_player_t* player = (mm_player_t*)user_data;
615 return_if_fail ( player );
619 if (player->is_drm_file)
621 MMMessageParamType msg_param = { 0, };
622 debug_warning("not supported in drm file");
623 msg_param.code = MM_ERROR_PLAYER_DRM_OUTPUT_PROTECTION;
624 MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param );
626 else if ( !player->set_mode.media_packet_video_stream && player->video_stream_cb)
628 MMPlayerVideoStreamDataType stream;
630 /* clear stream data structure */
631 memset(&stream, 0x0, sizeof(MMPlayerVideoStreamDataType));
633 stream.data[0] = data;
634 stream.length_total = width * height * 4; // for rgb 32bit
635 stream.height = height;
636 stream.width = width;
637 player->video_stream_cb(&stream, player->video_stream_cb_user_param);
644 __mmplayer_videoframe_render_error_cb(GstElement *element, void *error_id, gpointer data)
646 mm_player_t* player = (mm_player_t*)data;
648 return_if_fail ( player );
652 if (player->video_frame_render_error_cb )
656 int surface_type = 0;
657 mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &surface_type);
658 switch (surface_type)
660 case MM_DISPLAY_SURFACE_X_EXT:
661 player->video_frame_render_error_cb((unsigned int*)error_id, player->video_frame_render_error_cb_user_param);
662 debug_log("display surface type(X_EXT) : render error callback(%p) is finished", player->video_frame_render_error_cb);
665 debug_error("video_frame_render_error_cb was set, but this surface type(%d) is not supported", surface_type);
671 debug_error("could not get surface type");
676 debug_warning("video_frame_render_error_cb was not set");
683 __mmplayer_device_change_post_process(gpointer user)
685 mm_player_t* player = (mm_player_t*)user;
686 unsigned long position = 0;
687 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
688 MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
693 ! player->pipeline ||
694 ! player->pipeline->mainbin ||
695 ! player->pipeline->mainbin[MMPLAYER_M_PIPE].gst )
700 current_state = MMPLAYER_CURRENT_STATE(player);
701 pending_state = MMPLAYER_PENDING_STATE(player);
703 if (player->post_proc.need_pause_and_resume)
705 debug_log("pausing");
706 if ((pending_state == MM_PLAYER_STATE_PLAYING) ||
707 ((pending_state == MM_PLAYER_STATE_NONE) && (current_state != MM_PLAYER_STATE_PAUSED)))
708 gst_element_set_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED);
711 /* seek should be done within pause and resume */
712 if (player->post_proc.need_seek)
714 debug_log("seeking");
715 __gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position);
716 debug_log(">> seek to current position = %ld ms", position);
717 __gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, position, TRUE);
720 if (player->post_proc.need_pause_and_resume)
722 debug_log("resuming");
723 if ((pending_state == MM_PLAYER_STATE_PLAYING) ||
724 ((pending_state == MM_PLAYER_STATE_NONE) && (current_state != MM_PLAYER_STATE_PAUSED)))
725 gst_element_set_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING);
729 if (player->post_proc.need_async)
731 debug_log("setting async");
733 /* TODO : need some comment here */
734 if (player->pipeline->textbin && player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst)
735 g_object_set (G_OBJECT (player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst), "async", TRUE, NULL);
740 __mmplayer_post_proc_reset(player);
744 void __mmplayer_set_required_cb_score(mm_player_t* player, guint score)
746 return_if_fail(player);
747 player->post_proc.required_cb_score = score;
748 debug_log("set required score to : %d", score);
751 void __mmplayer_inc_cb_score(mm_player_t* player)
753 return_if_fail(player);
754 player->post_proc.cb_score++;
755 debug_log("post proc cb score increased to %d", player->post_proc.cb_score);
758 void __mmplayer_post_proc_reset(mm_player_t* player)
760 return_if_fail(player);
762 /* check if already triggered */
763 if (player->post_proc.id)
765 /* TODO : need to consider multiple main context. !!!! */
766 if (FALSE == g_source_remove(player->post_proc.id) )
768 debug_error("failed to remove exist post_proc item");
770 player->post_proc.id = 0;
773 memset(&player->post_proc, 0, sizeof(mm_player_post_proc_t));
775 /* set default required cb score 1 as only audio device has changed in this case.
776 if display status is changed with audio device, required cb score is set 2 in display status callback.
777 this logic bases on the assumption which audio device callback is called after calling display status callback. */
778 player->post_proc.required_cb_score = 1;
782 __mmplayer_device_change_trigger_post_process(mm_player_t* player)
784 return_if_fail(player);
787 if ( player->post_proc.cb_score < player->post_proc.required_cb_score )
789 /* wait for next turn */
790 debug_log("wait for next turn. required cb score : %d current score : %d\n",
791 player->post_proc.required_cb_score, player->post_proc.cb_score);
795 /* check if already triggered */
796 if (player->post_proc.id)
798 /* TODO : need to consider multiple main context. !!!! */
799 if (FALSE == g_source_remove(player->post_proc.id) )
801 debug_error("failed to remove exist post_proc item");
803 player->post_proc.id = 0;
806 player->post_proc.id = g_idle_add((GSourceFunc)__mmplayer_device_change_post_process, (gpointer)player);
809 /* NOTE : Sound module has different latency according to output device So,
810 * synchronization problem can be happened whenever device is changed.
811 * To avoid this issue, we do reset avsystem or seek as workaroud.
814 __mmplayer_sound_device_info_changed_cb_func (MMSoundDevice_t device_h, int changed_info_type, void *user_data)
817 mm_sound_device_type_e device_type;
818 mm_player_t* player = (mm_player_t*) user_data;
820 return_if_fail( player );
822 debug_warning("device_info_changed_cb is called, device_h[0x%x], changed_info_type[%d]\n", device_h, changed_info_type);
824 __mmplayer_inc_cb_score(player);
826 /* get device type with device_h*/
827 ret = mm_sound_get_device_type(device_h, &device_type);
829 debug_error("failed to mm_sound_get_device_type()\n");
832 /* do pause and resume only if video is playing */
833 if ( player->videodec_linked && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING )
837 case MM_SOUND_DEVICE_TYPE_BLUETOOTH:
838 case MM_SOUND_DEVICE_TYPE_AUDIOJACK:
839 case MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER:
840 case MM_SOUND_DEVICE_TYPE_HDMI:
841 case MM_SOUND_DEVICE_TYPE_MIRRORING:
843 player->post_proc.need_pause_and_resume = TRUE;
848 debug_log("do nothing");
851 debug_warning("dispatched");
853 __mmplayer_device_change_trigger_post_process(player);
856 /* This function should be called after the pipeline goes PAUSED or higher
859 _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag) // @
861 static gboolean has_duration = FALSE;
862 static gboolean has_video_attrs = FALSE;
863 static gboolean has_audio_attrs = FALSE;
864 static gboolean has_bitrate = FALSE;
865 gboolean missing_only = FALSE;
866 gboolean all = FALSE;
868 GstStructure* p = NULL;
869 MMHandleType attrs = 0;
871 gint stream_service_type = STREAMING_SERVICE_NONE;
876 return_val_if_fail ( player, FALSE );
878 /* check player state here */
879 if ( MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
880 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING )
882 /* give warning now only */
883 debug_warning("be careful. content attributes may not available in this state ");
886 /* get content attribute first */
887 attrs = MMPLAYER_GET_ATTRS(player);
890 debug_error("cannot get content attribute");
894 /* get update flag */
896 if ( flag & ATTR_MISSING_ONLY )
899 debug_log("updating missed attr only");
902 if ( flag & ATTR_ALL )
905 has_duration = FALSE;
906 has_video_attrs = FALSE;
907 has_audio_attrs = FALSE;
910 debug_log("updating all attrs");
913 if ( missing_only && all )
915 debug_warning("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
916 missing_only = FALSE;
919 if ( (flag & ATTR_DURATION) || (!has_duration && missing_only) || all )
921 debug_log("try to update duration");
922 has_duration = FALSE;
924 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec ))
926 player->duration = dur_nsec;
927 debug_warning("duration : %lld msec", GST_TIME_AS_MSECONDS(dur_nsec));
930 /* try to get streaming service type */
931 stream_service_type = __mmplayer_get_stream_service_type( player );
932 mm_attrs_set_int_by_name ( attrs, "streaming_type", stream_service_type );
934 /* check duration is OK */
935 if ( dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING( player ) )
937 /* FIXIT : find another way to get duration here. */
938 debug_error("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
943 mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(dur_nsec));
948 if ( (flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all )
950 /* update audio params
951 NOTE : We need original audio params and it can be only obtained from src pad of audio
952 decoder. Below code only valid when we are not using 'resampler' just before
955 debug_log("try to update audio attrs");
956 has_audio_attrs = FALSE;
958 if ( player->pipeline->audiobin &&
959 player->pipeline->audiobin[MMPLAYER_A_SINK].gst )
961 GstCaps *caps_a = NULL;
963 gint samplerate = 0, channels = 0;
965 pad = gst_element_get_static_pad(
966 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink" );
970 caps_a = gst_pad_get_current_caps( pad );
974 p = gst_caps_get_structure (caps_a, 0);
976 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
978 gst_structure_get_int (p, "rate", &samplerate);
979 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
981 gst_structure_get_int (p, "channels", &channels);
982 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
984 secure_debug_log("samplerate : %d channels : %d", samplerate, channels);
986 gst_caps_unref( caps_a );
989 has_audio_attrs = TRUE;
993 debug_warning("not ready to get audio caps");
996 gst_object_unref( pad );
1000 debug_warning("failed to get pad from audiosink");
1005 if ( (flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all )
1007 debug_log("try to update video attrs");
1008 has_video_attrs = FALSE;
1010 if ( player->pipeline->videobin &&
1011 player->pipeline->videobin[MMPLAYER_V_SINK].gst )
1013 GstCaps *caps_v = NULL;
1018 pad = gst_element_get_static_pad( player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink" );
1021 caps_v = gst_pad_get_current_caps( pad );
1023 /* Use v_stream_caps, if fail to get video_sink sink pad*/
1024 if (!caps_v && player->v_stream_caps)
1026 caps_v = player->v_stream_caps;
1027 gst_caps_ref(caps_v);
1032 p = gst_caps_get_structure (caps_v, 0);
1033 gst_structure_get_int (p, "width", &width);
1034 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
1036 gst_structure_get_int (p, "height", &height);
1037 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
1039 gst_structure_get_fraction (p, "framerate", &tmpNu, &tmpDe);
1041 secure_debug_log("width : %d height : %d", width, height );
1043 gst_caps_unref( caps_v );
1048 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
1049 secure_debug_log("fps : %d", tmpNu / tmpDe);
1052 has_video_attrs = TRUE;
1056 debug_log("no negitiated caps from videosink");
1058 gst_object_unref( pad );
1063 debug_log("no videosink sink pad");
1069 if ( (flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all )
1071 has_bitrate = FALSE;
1073 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
1074 if (player->duration)
1076 guint64 data_size = 0;
1078 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO))
1080 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
1082 if (stat(path, &sb) == 0)
1084 data_size = (guint64)sb.st_size;
1087 else if (MMPLAYER_IS_HTTP_STREAMING(player))
1089 data_size = player->http_content_size;
1091 debug_log("try to update bitrate : data_size = %lld", data_size);
1095 guint64 bitrate = 0;
1096 guint64 msec_dur = 0;
1098 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
1099 bitrate = data_size * 8 * 1000 / msec_dur;
1100 secure_debug_log("file size : %u, video bitrate = %llu", data_size, bitrate);
1101 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
1106 if (MMPLAYER_IS_RTSP_STREAMING(player))
1108 if(player->total_bitrate)
1110 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
1118 if ( mmf_attrs_commit ( attrs ) )
1120 debug_error("failed to update attributes\n");
1129 gint __mmplayer_get_stream_service_type( mm_player_t* player )
1131 gint streaming_type = STREAMING_SERVICE_NONE;
1135 return_val_if_fail ( player &&
1137 player->pipeline->mainbin &&
1138 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
1141 /* streaming service type if streaming */
1142 if ( ! MMPLAYER_IS_STREAMING(player) )
1143 return STREAMING_SERVICE_NONE;
1145 if (MMPLAYER_IS_HTTP_STREAMING(player))
1147 streaming_type = (player->duration == 0) ?
1148 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
1151 switch ( streaming_type )
1153 case STREAMING_SERVICE_LIVE:
1154 debug_log("it's live streaming");
1156 case STREAMING_SERVICE_VOD:
1157 debug_log("it's vod streaming");
1159 case STREAMING_SERVICE_NONE:
1160 debug_error("should not get here");
1163 debug_error("should not get here");
1166 player->streaming_type = streaming_type;
1169 return streaming_type;
1173 /* this function sets the player state and also report
1174 * it to applicaton by calling callback function
1177 __mmplayer_set_state(mm_player_t* player, int state) // @
1179 MMMessageParamType msg = {0, };
1180 int asm_result = MM_ERROR_NONE;
1181 gboolean post_bos = FALSE;
1182 gboolean interrupted_by_asm = FALSE;
1183 int ret = MM_ERROR_NONE;
1185 return_val_if_fail ( player, FALSE );
1187 if ( MMPLAYER_CURRENT_STATE(player) == state )
1189 debug_warning("already same state(%s)\n", MMPLAYER_STATE_GET_NAME(state));
1190 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
1194 /* update player states */
1195 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
1196 MMPLAYER_CURRENT_STATE(player) = state;
1198 /* FIXIT : it's better to do like below code
1199 if ( MMPLAYER_CURRENT_STATE(player) == MMPLAYER_TARGET_STATE(player) )
1200 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
1201 and add more code to handling PENDING_STATE.
1203 if ( MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player) )
1204 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
1207 MMPLAYER_PRINT_STATE(player);
1209 /* do some FSM stuffs before posting new state to application */
1210 interrupted_by_asm = player->sm.by_asm_cb;
1212 switch ( MMPLAYER_CURRENT_STATE(player) )
1214 case MM_PLAYER_STATE_NULL:
1215 case MM_PLAYER_STATE_READY:
1217 if (player->cmd == MMPLAYER_COMMAND_STOP)
1219 asm_result = _mmplayer_asm_set_state((MMHandleType)player, ASM_STATE_STOP, FALSE);
1220 if ( asm_result != MM_ERROR_NONE )
1222 debug_error("failed to set asm state to stop\n");
1223 return MM_ERROR_POLICY_INTERNAL;
1229 case MM_PLAYER_STATE_PAUSED:
1231 if ( ! player->sent_bos )
1234 #define MMPLAYER_MAX_SOUND_PRIORITY 3
1236 /* it's first time to update all content attrs. */
1237 _mmplayer_update_content_attrs( player, ATTR_ALL );
1238 /* set max sound priority to keep own sound and not to mute other's one */
1239 mm_attrs_get_int_by_name(player->attrs, "content_video_found", &found);
1242 mm_attrs_get_int_by_name(player->attrs, "content_audio_found", &found);
1245 debug_log("set max audio priority");
1246 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "priority", MMPLAYER_MAX_SOUND_PRIORITY, NULL);
1252 /* add audio callback probe if condition is satisfied */
1253 if ( ! player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
1255 __mmplayer_configure_audio_callback(player);
1256 /* FIXIT : handle return value */
1259 if (!MMPLAYER_IS_STREAMING(player) || (player->streamer && !player->streamer->is_buffering))
1261 asm_result = _mmplayer_asm_set_state((MMHandleType)player, ASM_STATE_PAUSE, FALSE);
1264 debug_error("failed to set asm state to PAUSE\n");
1265 return MM_ERROR_POLICY_INTERNAL;
1271 case MM_PLAYER_STATE_PLAYING:
1273 /* try to get content metadata */
1274 if ( ! player->sent_bos )
1276 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
1277 * c-api since c-api doesn't use _start() anymore. It may not work propery with
1278 * legacy mmfw-player api */
1279 _mmplayer_update_content_attrs( player, ATTR_MISSING_ONLY);
1282 if ( (player->cmd == MMPLAYER_COMMAND_START) || (player->cmd == MMPLAYER_COMMAND_RESUME) )
1284 if (!player->sent_bos)
1286 __mmplayer_handle_missed_plugin ( player );
1289 /* update ASM state for video and streaming buffering */
1290 asm_result = _mmplayer_asm_set_state((MMHandleType)player, ASM_STATE_PLAYING, TRUE);
1291 if (asm_result != MM_ERROR_NONE)
1293 if (player->pipeline->videobin)
1295 MMMessageParamType msg = {0, };
1297 debug_error("failed to go ahead because of video conflict\n");
1299 msg.union_type = MM_MSG_UNION_CODE;
1300 msg.code = MM_ERROR_POLICY_INTERRUPTED;
1301 MMPLAYER_POST_MSG( player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
1303 _mmplayer_unrealize((MMHandleType)player);
1307 debug_error("failed to play by ASM error : 0x%X\n", asm_result);
1308 _mmplayer_pause((MMHandleType)player);
1312 return MM_ERROR_POLICY_INTERNAL;
1316 if ( player->resumed_by_rewind && player->playback_rate < 0.0 )
1318 /* initialize because auto resume is done well. */
1319 player->resumed_by_rewind = FALSE;
1320 player->playback_rate = 1.0;
1323 if ( !player->sent_bos )
1325 /* check audio codec field is set or not
1326 * we can get it from typefinder or codec's caps.
1328 gchar *audio_codec = NULL;
1329 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
1331 /* The codec format can't be sent for audio only case like amr, mid etc.
1332 * Because, parser don't make related TAG.
1333 * So, if it's not set yet, fill it with found data.
1335 if ( ! audio_codec )
1337 if ( g_strrstr(player->type, "audio/midi"))
1339 audio_codec = g_strdup("MIDI");
1342 else if ( g_strrstr(player->type, "audio/x-amr"))
1344 audio_codec = g_strdup("AMR");
1346 else if ( g_strrstr(player->type, "audio/mpeg") && !g_strrstr(player->type, "mpegversion=(int)1"))
1348 audio_codec = g_strdup("AAC");
1352 audio_codec = g_strdup("unknown");
1354 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
1356 MMPLAYER_FREEIF(audio_codec);
1357 mmf_attrs_commit(player->attrs);
1358 debug_log("set audio codec type with caps\n");
1366 case MM_PLAYER_STATE_NONE:
1368 debug_warning("invalid target state, there is nothing to do.\n");
1373 /* post message to application */
1374 if (MMPLAYER_TARGET_STATE(player) == state)
1376 /* fill the message with state of player */
1377 msg.state.previous = MMPLAYER_PREV_STATE(player);
1378 msg.state.current = MMPLAYER_CURRENT_STATE(player);
1380 debug_log ("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
1382 /* state changed by asm callback */
1383 if ( interrupted_by_asm )
1385 msg.union_type = MM_MSG_UNION_CODE;
1386 msg.code = player->sm.event_src;
1387 MMPLAYER_POST_MSG( player, MM_MESSAGE_STATE_INTERRUPTED, &msg );
1389 /* state changed by usecase */
1392 MMPLAYER_POST_MSG( player, MM_MESSAGE_STATE_CHANGED, &msg );
1397 debug_log ("intermediate state, do nothing.\n");
1398 MMPLAYER_PRINT_STATE(player);
1404 MMPLAYER_POST_MSG ( player, MM_MESSAGE_BEGIN_OF_STREAM, NULL );
1405 player->sent_bos = TRUE;
1412 __mmplayer_post_message(mm_player_t* player, enum MMMessageType msgtype, MMMessageParamType* param) // @
1414 return_val_if_fail( player, FALSE );
1416 if ( !player->msg_cb )
1421 //debug_log("Message (type : %d) will be posted using msg-cb(%p). \n", msgtype, player->msg_cb);
1423 player->msg_cb(msgtype, param, player->msg_cb_param);
1428 static gpointer __mmplayer_next_play_thread(gpointer data)
1430 mm_player_t* player = (mm_player_t*) data;
1431 MMPlayerGstElement *mainbin = NULL;
1433 return_val_if_fail ( player, NULL );
1435 g_mutex_lock(&player->next_play_thread_mutex);
1436 while ( ! player->next_play_thread_exit )
1438 debug_log("next play thread started. waiting for signal.\n");
1439 g_cond_wait(&player->next_play_thread_cond, &player->next_play_thread_mutex );
1441 debug_log("reconfigure pipeline for gapless play.\n");
1443 if ( player->next_play_thread_exit )
1445 if(player->gapless.reconfigure)
1447 player->gapless.reconfigure = false;
1448 MMPLAYER_PLAYBACK_UNLOCK(player);
1450 debug_log("exiting gapless play thread\n");
1454 mainbin = player->pipeline->mainbin;
1456 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
1457 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
1458 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
1459 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
1460 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
1462 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
1464 g_mutex_unlock(&player->next_play_thread_mutex);
1469 static gpointer __mmplayer_repeat_thread(gpointer data)
1471 mm_player_t* player = (mm_player_t*) data;
1472 gboolean ret_value = FALSE;
1473 MMHandleType attrs = 0;
1476 return_val_if_fail ( player, NULL );
1478 g_mutex_lock(&player->repeat_thread_mutex);
1479 while ( ! player->repeat_thread_exit )
1481 debug_log("repeat thread started. waiting for signal.\n");
1482 g_cond_wait(&player->repeat_thread_cond, &player->repeat_thread_mutex );
1484 if ( player->repeat_thread_exit )
1486 debug_log("exiting repeat thread\n");
1492 g_mutex_lock(&player->cmd_lock);
1494 attrs = MMPLAYER_GET_ATTRS(player);
1496 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
1498 debug_error("can not get play count\n");
1502 if ( player->section_repeat )
1504 ret_value = _mmplayer_activate_section_repeat((MMHandleType)player, player->section_repeat_start, player->section_repeat_end);
1508 if ( player->playback_rate < 0.0 )
1510 player->resumed_by_rewind = TRUE;
1511 _mmplayer_set_mute((MMHandleType)player, 0);
1512 MMPLAYER_POST_MSG( player, MM_MESSAGE_RESUMED_BY_REW, NULL );
1515 ret_value = __gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
1516 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET,
1517 0, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
1520 player->sent_bos = FALSE;
1525 debug_error("failed to set position to zero for rewind\n");
1529 /* decrease play count */
1532 /* we successeded to rewind. update play count and then wait for next EOS */
1535 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
1537 /* commit attribute */
1538 if ( mmf_attrs_commit ( attrs ) )
1540 debug_error("failed to commit attribute\n");
1545 g_mutex_unlock(&player->cmd_lock);
1548 g_mutex_unlock(&player->repeat_thread_mutex);
1553 __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg)
1555 MMHandleType attrs = 0;
1556 guint64 data_size = 0;
1558 unsigned long pos_msec = 0;
1561 return_if_fail( player && player->pipeline && player->pipeline->mainbin);
1563 __gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &pos_msec); // update last_position
1565 attrs = MMPLAYER_GET_ATTRS(player);
1568 debug_error("fail to get attributes.\n");
1572 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO))
1574 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
1576 if (stat(path, &sb) == 0)
1578 data_size = (guint64)sb.st_size;
1581 else if (MMPLAYER_IS_HTTP_STREAMING(player))
1583 data_size = player->http_content_size;
1586 __mm_player_streaming_buffering( player->streamer,
1589 player->last_position,
1592 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
1599 __mmplayer_handle_buffering_message ( mm_player_t* player )
1601 MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
1602 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
1603 MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
1604 MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
1606 return_if_fail ( player );
1608 prev_state = MMPLAYER_PREV_STATE(player);
1609 current_state = MMPLAYER_CURRENT_STATE(player);
1610 target_state = MMPLAYER_TARGET_STATE(player);
1611 pending_state = MMPLAYER_PENDING_STATE(player);
1613 if (MMPLAYER_IS_LIVE_STREAMING(player))
1616 if ( !player->streamer->is_buffering )
1618 debug_log( "player state : prev %s, current %s, pending %s, target %s \n",
1619 MMPLAYER_STATE_GET_NAME(prev_state),
1620 MMPLAYER_STATE_GET_NAME(current_state),
1621 MMPLAYER_STATE_GET_NAME(pending_state),
1622 MMPLAYER_STATE_GET_NAME(target_state));
1624 /* NOTE : if buffering has done, player has to go to target state. */
1625 switch ( target_state )
1627 case MM_PLAYER_STATE_PAUSED :
1629 switch ( pending_state )
1631 case MM_PLAYER_STATE_PLAYING:
1633 __gst_pause ( player, TRUE );
1637 case MM_PLAYER_STATE_PAUSED:
1639 debug_log("player is already going to paused state, there is nothing to do.\n");
1643 case MM_PLAYER_STATE_NONE:
1644 case MM_PLAYER_STATE_NULL:
1645 case MM_PLAYER_STATE_READY:
1648 debug_warning("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state) );
1655 case MM_PLAYER_STATE_PLAYING :
1657 switch ( pending_state )
1659 case MM_PLAYER_STATE_NONE:
1661 if (current_state != MM_PLAYER_STATE_PLAYING)
1662 __gst_resume ( player, TRUE );
1666 case MM_PLAYER_STATE_PAUSED:
1668 /* NOTE: It should be worked as asynchronously.
1669 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
1671 __gst_resume ( player, TRUE );
1675 case MM_PLAYER_STATE_PLAYING:
1677 debug_log("player is already going to playing state, there is nothing to do.\n");
1681 case MM_PLAYER_STATE_NULL:
1682 case MM_PLAYER_STATE_READY:
1685 debug_warning("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state) );
1692 case MM_PLAYER_STATE_NULL :
1693 case MM_PLAYER_STATE_READY :
1694 case MM_PLAYER_STATE_NONE :
1697 debug_warning("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state) );
1704 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1705 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
1707 switch ( pending_state )
1709 case MM_PLAYER_STATE_NONE:
1711 if (current_state != MM_PLAYER_STATE_PAUSED)
1713 debug_log("set pause state during buffering\n");
1714 __gst_pause ( player, TRUE );
1716 // to cover the weak-signal environment.
1717 if (MMPLAYER_IS_RTSP_STREAMING(player))
1719 unsigned long position = 0;
1720 gint64 pos_msec = 0;
1722 debug_log("[RTSP] seek to the buffering start point\n");
1724 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position ))
1726 debug_error("failed to get position\n");
1731 pos_msec = position * G_GINT64_CONSTANT(1000000);
1733 __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
1734 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET,
1735 pos_msec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
1741 case MM_PLAYER_STATE_PLAYING:
1743 __gst_pause ( player, TRUE );
1747 case MM_PLAYER_STATE_PAUSED:
1752 case MM_PLAYER_STATE_NULL:
1753 case MM_PLAYER_STATE_READY:
1756 debug_warning("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state) );
1764 __mmplayer_drop_subtitle(mm_player_t* player, gboolean is_drop)
1766 MMPlayerGstElement *textbin;
1769 return_if_fail ( player &&
1771 player->pipeline->textbin);
1773 return_if_fail (player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1775 textbin = player->pipeline->textbin;
1779 debug_log("Drop subtitle text after getting EOS\n");
1781 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", FALSE, NULL);
1782 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
1784 player->is_subtitle_force_drop = TRUE;
1788 if (player->is_subtitle_force_drop == TRUE)
1790 debug_log("Enable subtitle data path without drop\n");
1792 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
1793 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", TRUE, NULL);
1795 debug_log ("non-connected with external display");
1797 player->is_subtitle_force_drop = FALSE;
1803 __mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data) // @
1805 mm_player_t* player = (mm_player_t*) data;
1806 gboolean ret = TRUE;
1807 static gboolean async_done = FALSE;
1809 return_val_if_fail ( player, FALSE );
1810 return_val_if_fail ( msg && GST_IS_MESSAGE(msg), FALSE );
1812 switch ( GST_MESSAGE_TYPE( msg ) )
1814 case GST_MESSAGE_UNKNOWN:
1815 debug_log("unknown message received\n");
1818 case GST_MESSAGE_EOS:
1820 MMHandleType attrs = 0;
1823 debug_log("GST_MESSAGE_EOS received\n");
1825 /* NOTE : EOS event is comming multiple time. watch out it */
1826 /* check state. we only process EOS when pipeline state goes to PLAYING */
1827 if ( ! (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) )
1829 debug_log("EOS received on non-playing state. ignoring it\n");
1833 __mmplayer_drop_subtitle(player, TRUE);
1835 if ( (player->audio_stream_cb) && (player->set_mode.pcm_extraction) && (!player->audio_stream_render_cb_ex))
1839 pad = gst_element_get_static_pad (player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
1841 debug_log("release audio callback\n");
1843 /* release audio callback */
1844 gst_pad_remove_probe (pad, player->audio_cb_probe_id);
1845 player->audio_cb_probe_id = 0;
1846 /* audio callback should be free because it can be called even though probe remove.*/
1847 player->audio_stream_cb = NULL;
1848 player->audio_stream_cb_user_param = NULL;
1852 /* rewind if repeat count is greater then zero */
1853 /* get play count */
1854 attrs = MMPLAYER_GET_ATTRS(player);
1858 gboolean smooth_repeat = FALSE;
1860 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1861 mm_attrs_get_int_by_name(attrs, "profile_smooth_repeat", &smooth_repeat);
1863 player->play_count = count;
1865 debug_log("remaining play count: %d, playback rate: %f\n", count, player->playback_rate);
1867 if ( count > 1 || count == -1 || player->playback_rate < 0.0 ) /* default value is 1 */
1869 if ( smooth_repeat )
1871 debug_log("smooth repeat enabled. seeking operation will be excuted in new thread\n");
1873 g_cond_signal( &player->repeat_thread_cond );
1881 if ( player->section_repeat )
1883 ret_value = _mmplayer_activate_section_repeat((MMHandleType)player, player->section_repeat_start, player->section_repeat_end);
1887 if ( player->playback_rate < 0.0 )
1889 player->resumed_by_rewind = TRUE;
1890 _mmplayer_set_mute((MMHandleType)player, 0);
1891 MMPLAYER_POST_MSG( player, MM_MESSAGE_RESUMED_BY_REW, NULL );
1894 __mmplayer_handle_eos_delay( player, player->ini.delay_before_repeat );
1897 player->sent_bos = FALSE;
1900 if ( MM_ERROR_NONE != ret_value )
1902 debug_error("failed to set position to zero for rewind\n");
1905 /* not posting eos when repeating */
1911 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-eos" );
1913 /* post eos message to application */
1914 __mmplayer_handle_eos_delay( player, player->ini.eos_delay );
1916 /* reset last position */
1917 player->last_position = 0;
1921 case GST_MESSAGE_ERROR:
1923 GError *error = NULL;
1924 gchar* debug = NULL;
1926 /* generating debug info before returning error */
1927 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-error" );
1929 /* get error code */
1930 gst_message_parse_error( msg, &error, &debug );
1932 if ( gst_structure_has_name ( gst_message_get_structure(msg), "streaming_error" ) )
1934 /* Note : the streaming error from the streaming source is handled
1935 * using __mmplayer_handle_streaming_error.
1937 __mmplayer_handle_streaming_error ( player, msg );
1939 /* dump state of all element */
1940 __mmplayer_dump_pipeline_state( player );
1944 /* traslate gst error code to msl error code. then post it
1945 * to application if needed
1947 __mmplayer_handle_gst_error( player, msg, error );
1951 debug_error ("error debug : %s", debug);
1956 if (MMPLAYER_IS_HTTP_PD(player))
1958 _mmplayer_unrealize_pd_downloader ((MMHandleType)player);
1961 MMPLAYER_FREEIF( debug );
1962 g_error_free( error );
1966 case GST_MESSAGE_WARNING:
1969 GError* error = NULL;
1971 gst_message_parse_warning(msg, &error, &debug);
1973 debug_log("warning : %s\n", error->message);
1974 debug_log("debug : %s\n", debug);
1976 MMPLAYER_POST_MSG( player, MM_MESSAGE_WARNING, NULL );
1978 MMPLAYER_FREEIF( debug );
1979 g_error_free( error );
1983 case GST_MESSAGE_TAG:
1985 debug_log("GST_MESSAGE_TAG\n");
1986 if ( ! __mmplayer_gst_extract_tag_from_msg( player, msg ) )
1988 debug_warning("failed to extract tags from gstmessage\n");
1993 case GST_MESSAGE_BUFFERING:
1995 MMMessageParamType msg_param = {0, };
1996 int asm_result = MM_ERROR_NONE;
1998 if (!MMPLAYER_IS_STREAMING(player))
2001 /* ignore the prev buffering message */
2002 if ((player->streamer) && (player->streamer->is_buffering == FALSE) && (player->streamer->is_buffering_done == TRUE))
2004 gint buffer_percent = 0;
2006 gst_message_parse_buffering (msg, &buffer_percent);
2008 if (buffer_percent == MAX_BUFFER_PERCENT)
2010 debug_log ("Ignored all the previous buffering msg! (got %d%%)\n", buffer_percent);
2011 player->streamer->is_buffering_done = FALSE;
2017 /* update ASM state to ASM_STATE_PLAYING */
2018 /* fixed ASM_STATE_WAITING -> ASM_STATE_PLAYING for Samsunlink issue*/
2019 if ((player->streamer) && (player->streamer->is_buffering == FALSE) && (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED))
2021 asm_result = _mmplayer_asm_set_state((MMHandleType)player, ASM_STATE_WAITING, TRUE);
2022 if ( asm_result != MM_ERROR_NONE )
2024 debug_warning("failed to set asm state to waiting, but keep going...\n");
2028 __mmplayer_update_buffer_setting(player, msg);
2030 __mmplayer_handle_buffering_message ( player );
2032 msg_param.connection.buffering = player->streamer->buffering_percent;
2033 MMPLAYER_POST_MSG ( player, MM_MESSAGE_BUFFERING, &msg_param );
2034 if (MMPLAYER_IS_RTSP_STREAMING(player) && (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT))
2036 if (player->doing_seek)
2038 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED)
2040 player->doing_seek = FALSE;
2041 MMPLAYER_POST_MSG ( player, MM_MESSAGE_SEEK_COMPLETED, NULL );
2043 else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING)
2052 case GST_MESSAGE_STATE_CHANGED:
2054 MMPlayerGstElement *mainbin;
2055 const GValue *voldstate, *vnewstate, *vpending;
2056 GstState oldstate, newstate, pending;
2058 if ( ! ( player->pipeline && player->pipeline->mainbin ) )
2060 debug_error("player pipeline handle is null");
2064 mainbin = player->pipeline->mainbin;
2066 /* we only handle messages from pipeline */
2067 if( msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst )
2070 /* get state info from msg */
2071 voldstate = gst_structure_get_value (gst_message_get_structure(msg), "old-state");
2072 vnewstate = gst_structure_get_value (gst_message_get_structure(msg), "new-state");
2073 vpending = gst_structure_get_value (gst_message_get_structure(msg), "pending-state");
2075 oldstate = (GstState)voldstate->data[0].v_int;
2076 newstate = (GstState)vnewstate->data[0].v_int;
2077 pending = (GstState)vpending->data[0].v_int;
2079 debug_log("state changed [%s] : %s ---> %s final : %s\n",
2080 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
2081 gst_element_state_get_name( (GstState)oldstate ),
2082 gst_element_state_get_name( (GstState)newstate ),
2083 gst_element_state_get_name( (GstState)pending ) );
2085 if (oldstate == newstate)
2087 debug_log("pipeline reports state transition to old state");
2093 case GST_STATE_VOID_PENDING:
2096 case GST_STATE_NULL:
2099 case GST_STATE_READY:
2102 case GST_STATE_PAUSED:
2104 gboolean prepare_async = FALSE;
2105 gboolean is_drm = FALSE;
2107 if ( ! player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
2108 __mmplayer_configure_audio_callback(player);
2110 if ( ! player->sent_bos && oldstate == GST_STATE_READY) // managed prepare async case
2112 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
2113 debug_log("checking prepare mode for async transition - %d", prepare_async);
2116 if ( MMPLAYER_IS_STREAMING(player) || prepare_async )
2118 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_PAUSED );
2120 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
2122 __mm_player_streaming_set_content_bitrate(player->streamer,
2123 player->total_maximum_bitrate, player->total_bitrate);
2127 /* NOTE : should consider streaming case */
2128 /* check if drm file */
2129 if ((player->pipeline->mainbin[MMPLAYER_M_SRC].gst) &&
2130 (g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), "is-drm")))
2132 g_object_get(G_OBJECT(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), "is-drm", &is_drm, NULL);
2136 player->is_drm_file = TRUE;
2142 case GST_STATE_PLAYING:
2144 /* for audio tunning */
2146 if (player->can_support_codec == 0x03) {
2148 mm_attrs_get_int_by_name(player->attrs, "sound_volume_type", &volume_type);
2149 volume_type |= MM_SOUND_VOLUME_GAIN_VIDEO;
2150 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "volumetype", volume_type, NULL);
2153 if ( MMPLAYER_IS_STREAMING(player) ) // managed prepare async case when buffering is completed
2155 // pending state should be reset oyherwise, it's still playing even though it's resumed after bufferging.
2156 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
2157 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
2159 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_PLAYING);
2163 if (player->gapless.stream_changed)
2165 _mmplayer_update_content_attrs(player, ATTR_ALL);
2168 if (player->doing_seek && async_done)
2170 player->doing_seek = FALSE;
2172 MMPLAYER_POST_MSG ( player, MM_MESSAGE_SEEK_COMPLETED, NULL );
2183 case GST_MESSAGE_CLOCK_LOST:
2185 GstClock *clock = NULL;
2186 gst_message_parse_clock_lost (msg, &clock);
2187 debug_log("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME (clock) : "NULL"));
2188 g_print ("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME (clock) : "NULL"));
2190 if (((player->ini.provide_clock_for_music) && (!player->videodec_linked)) ||
2191 ((player->ini.provide_clock_for_movie) && (player->videodec_linked)))
2193 debug_log ("Provide clock is TRUE, do pause->resume\n");
2194 __gst_pause(player, FALSE);
2195 __gst_resume(player, FALSE);
2200 case GST_MESSAGE_NEW_CLOCK:
2202 GstClock *clock = NULL;
2203 gst_message_parse_new_clock (msg, &clock);
2204 debug_log("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME (clock) : "NULL"));
2208 case GST_MESSAGE_ELEMENT:
2210 const gchar *structure_name;
2212 MMHandleType attrs = 0;
2214 attrs = MMPLAYER_GET_ATTRS(player);
2217 debug_error("cannot get content attribute");
2222 if(gst_message_get_structure(msg) == NULL)
2225 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
2226 if(!strcmp(structure_name, "Language_list"))
2228 const GValue *lang_list = NULL;
2229 lang_list = gst_structure_get_value (gst_message_get_structure(msg), "lang_list");
2230 if(lang_list != NULL)
2232 count = g_list_length((GList *)g_value_get_pointer (lang_list));
2234 debug_log("Total audio tracks (from parser) = %d \n",count);
2238 if (!strcmp (structure_name, "Ext_Sub_Language_List"))
2240 const GValue *lang_list = NULL;
2241 MMPlayerLangStruct *temp = NULL;
2243 lang_list = gst_structure_get_value (gst_message_get_structure(msg), "lang_list");
2244 if (lang_list != NULL)
2246 count = g_list_length ((GList *)g_value_get_pointer (lang_list));
2249 player->subtitle_language_list = (GList *)g_value_get_pointer (lang_list);
2250 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)count);
2251 if (mmf_attrs_commit (attrs))
2252 debug_error("failed to commit.\n");
2253 debug_log("Total subtitle tracks = %d \n", count);
2257 temp = g_list_nth_data (player->subtitle_language_list, count - 1);
2258 debug_log ("value of lang_key is %s and lang_code is %s",
2259 temp->language_key, temp->language_code);
2265 /* custom message */
2266 if (!strcmp (structure_name, "audio_codec_not_supported")) {
2267 MMMessageParamType msg_param = {0,};
2268 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
2269 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
2274 case GST_MESSAGE_DURATION_CHANGED:
2276 debug_log("GST_MESSAGE_DURATION_CHANGED\n");
2277 ret = __mmplayer_gst_handle_duration(player, msg);
2280 debug_warning("failed to update duration");
2286 case GST_MESSAGE_ASYNC_START:
2288 debug_log("GST_MESSAGE_ASYNC_START : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2292 case GST_MESSAGE_ASYNC_DONE:
2294 debug_log("GST_MESSAGE_ASYNC_DONE : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2296 /* we only handle messages from pipeline */
2297 if( msg->src != (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst )
2300 if (player->doing_seek)
2302 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED)
2304 player->doing_seek = FALSE;
2305 MMPLAYER_POST_MSG ( player, MM_MESSAGE_SEEK_COMPLETED, NULL );
2307 else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING)
2309 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
2310 (player->streamer) &&
2311 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
2312 (player->streamer->is_buffering == FALSE))
2314 GstQuery *query = NULL;
2315 gboolean busy = FALSE;
2318 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer)
2320 query = gst_query_new_buffering ( GST_FORMAT_PERCENT );
2321 if ( gst_element_query (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query ) )
2323 gst_query_parse_buffering_percent ( query, &busy, &percent);
2325 gst_query_unref (query);
2327 debug_log("buffered percent(%s): %d\n",
2328 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
2333 player->streamer->is_buffering = FALSE;
2334 __mmplayer_handle_buffering_message(player);
2344 #if 0 /* delete unnecessary logs */
2345 case GST_MESSAGE_REQUEST_STATE: debug_log("GST_MESSAGE_REQUEST_STATE\n"); break;
2346 case GST_MESSAGE_STEP_START: debug_log("GST_MESSAGE_STEP_START\n"); break;
2347 case GST_MESSAGE_QOS: debug_log("GST_MESSAGE_QOS\n"); break;
2348 case GST_MESSAGE_PROGRESS: debug_log("GST_MESSAGE_PROGRESS\n"); break;
2349 case GST_MESSAGE_ANY: debug_log("GST_MESSAGE_ANY\n"); break;
2350 case GST_MESSAGE_INFO: debug_log("GST_MESSAGE_STATE_DIRTY\n"); break;
2351 case GST_MESSAGE_STATE_DIRTY: debug_log("GST_MESSAGE_STATE_DIRTY\n"); break;
2352 case GST_MESSAGE_STEP_DONE: debug_log("GST_MESSAGE_STEP_DONE\n"); break;
2353 case GST_MESSAGE_CLOCK_PROVIDE: debug_log("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
2354 case GST_MESSAGE_STRUCTURE_CHANGE: debug_log("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
2355 case GST_MESSAGE_STREAM_STATUS: debug_log("GST_MESSAGE_STREAM_STATUS\n"); break;
2356 case GST_MESSAGE_APPLICATION: debug_log("GST_MESSAGE_APPLICATION\n"); break;
2357 case GST_MESSAGE_SEGMENT_START: debug_log("GST_MESSAGE_SEGMENT_START\n"); break;
2358 case GST_MESSAGE_SEGMENT_DONE: debug_log("GST_MESSAGE_SEGMENT_DONE\n"); break;
2359 case GST_MESSAGE_LATENCY: debug_log("GST_MESSAGE_LATENCY\n"); break;
2366 /* FIXIT : this cause so many warnings/errors from glib/gstreamer. we should not call it since
2367 * gst_element_post_message api takes ownership of the message.
2369 //gst_message_unref( msg );
2375 __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg)
2381 return_val_if_fail(player, FALSE);
2382 return_val_if_fail(msg, FALSE);
2384 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
2385 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst))
2387 debug_log("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
2389 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes))
2391 debug_log("data total size of http content: %lld", bytes);
2392 player->http_content_size = bytes;
2397 /* handling audio clip which has vbr. means duration is keep changing */
2398 _mmplayer_update_content_attrs (player, ATTR_DURATION );
2408 __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg) // @
2411 /* macro for better code readability */
2412 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
2413 if (gst_tag_list_get_string(tag_list, gsttag, &string)) \
2415 if (string != NULL)\
2417 secure_debug_log ( "update tag string : %s\n", string); \
2418 mm_attrs_set_string_by_name(attribute, playertag, string); \
2424 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
2425 GstSample *sample = NULL;\
2426 if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample))\
2428 GstMapInfo info = GST_MAP_INFO_INIT;\
2429 buffer = gst_sample_get_buffer(sample);\
2430 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)){\
2431 debug_log("failed to get image data from tag");\
2434 secure_debug_log ( "update album cover data : %p, size : %d\n", info.data, info.size);\
2435 MMPLAYER_FREEIF(player->album_art); \
2436 player->album_art = (gchar *)g_malloc(info.size); \
2437 if (player->album_art) \
2439 memcpy(player->album_art, info.data, info.size); \
2440 mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size); \
2441 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) \
2443 msg_param.data = (void *)player->album_art; \
2444 msg_param.size = info.size; \
2445 MMPLAYER_POST_MSG (player, MM_MESSAGE_IMAGE_BUFFER, &msg_param); \
2446 secure_debug_log ( "post message image buffer data : %p, size : %d\n", info.data, info.size); \
2449 gst_buffer_unmap(buffer, &info); \
2452 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
2453 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint))\
2457 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) \
2459 if (player->updated_bitrate_count == 0) \
2460 mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
2461 if (player->updated_bitrate_count<MM_PLAYER_STREAM_COUNT_MAX) \
2463 player->bitrate[player->updated_bitrate_count] = v_uint;\
2464 player->total_bitrate += player->bitrate[player->updated_maximum_bitrate_count]; \
2465 player->updated_bitrate_count++; \
2466 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate);\
2467 secure_debug_log ( "update bitrate %d[bps] of stream #%d.\n", v_uint, player->updated_bitrate_count);\
2470 else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) \
2472 if (player->updated_maximum_bitrate_count<MM_PLAYER_STREAM_COUNT_MAX) \
2474 player->maximum_bitrate[player->updated_maximum_bitrate_count] = v_uint;\
2475 player->total_maximum_bitrate += player->maximum_bitrate[player->updated_maximum_bitrate_count]; \
2476 player->updated_maximum_bitrate_count++; \
2477 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate); \
2478 secure_debug_log ( "update maximum bitrate %d[bps] of stream #%d\n", v_uint, player->updated_maximum_bitrate_count);\
2483 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
2489 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
2490 if (gst_tag_list_get_date(tag_list, gsttag, &date))\
2494 string = g_strdup_printf("%d", g_date_get_year(date));\
2495 mm_attrs_set_string_by_name(attribute, playertag, string);\
2496 secure_debug_log ( "metainfo year : %s\n", string);\
2497 MMPLAYER_FREEIF(string);\
2502 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
2503 if(gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64))\
2507 /* FIXIT : don't know how to store date */\
2513 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
2514 if(gst_tag_list_get_double(tag_list, gsttag, &v_double))\
2518 /* FIXIT : don't know how to store date */\
2524 /* function start */
2525 GstTagList* tag_list = NULL;
2527 MMHandleType attrs = 0;
2529 char *string = NULL;
2533 GstBuffer *buffer = NULL;
2535 MMMessageParamType msg_param = {0, };
2537 /* currently not used. but those are needed for above macro */
2538 //guint64 v_uint64 = 0;
2539 //gdouble v_double = 0;
2541 return_val_if_fail( player && msg, FALSE );
2543 attrs = MMPLAYER_GET_ATTRS(player);
2545 return_val_if_fail( attrs, FALSE );
2547 /* get tag list from gst message */
2548 gst_message_parse_tag(msg, &tag_list);
2550 /* store tags to player attributes */
2551 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
2552 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
2553 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
2554 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
2555 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
2556 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
2557 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
2558 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
2559 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
2560 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
2561 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
2562 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
2563 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
2564 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
2565 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
2566 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
2567 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
2568 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
2569 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
2570 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
2571 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
2572 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
2573 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
2574 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
2575 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
2576 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
2577 /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
2578 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
2579 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
2580 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
2581 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
2582 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
2583 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
2584 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
2585 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
2586 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
2587 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
2588 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
2589 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
2590 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
2591 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
2592 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
2593 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
2594 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
2595 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
2596 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation");
2598 if ( mmf_attrs_commit ( attrs ) )
2599 debug_error("failed to commit.\n");
2601 gst_tag_list_free(tag_list);
2607 __mmplayer_gst_rtp_no_more_pads (GstElement *element, gpointer data) // @
2609 mm_player_t* player = (mm_player_t*) data;
2613 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2614 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2615 * num_dynamic_pad. and this is no-more-pad situation which means mo more pad will be added.
2616 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2618 * [1] audio and video will be dumped with filesink.
2619 * [2] autoplugging is done by just using pad caps.
2620 * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2621 * and the video will be dumped via filesink.
2623 if ( player->num_dynamic_pad == 0 )
2625 debug_log("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
2627 if ( ! __mmplayer_gst_remove_fakesink( player,
2628 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]) )
2630 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
2631 * signaling mechanism ( pad-added, no-more-pad, new-decoded-pad ) from various
2632 * source element are not same. To overcome this situation, this function will called
2633 * several places and several times. Therefore, this is not an error case.
2639 /* create dot before error-return. for debugging */
2640 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-no-more-pad" );
2642 player->no_more_pad = TRUE;
2648 __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink) // @
2650 GstElement* parent = NULL;
2652 return_val_if_fail(player && player->pipeline, FALSE);
2654 /* if we have no fakesink. this meas we are using decodebin which doesn'
2655 t need to add extra fakesink */
2656 return_val_if_fail(fakesink, TRUE);
2659 g_mutex_lock(&player->fsink_lock );
2661 if ( ! fakesink->gst )
2666 /* get parent of fakesink */
2667 parent = (GstElement*)gst_object_get_parent( (GstObject*)fakesink->gst );
2670 debug_log("fakesink already removed\n");
2674 gst_element_set_locked_state( fakesink->gst, TRUE );
2676 /* setting the state to NULL never returns async
2677 * so no need to wait for completion of state transiton
2679 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state (fakesink->gst, GST_STATE_NULL) )
2681 debug_error("fakesink state change failure!\n");
2683 /* FIXIT : should I return here? or try to proceed to next? */
2687 /* remove fakesink from it's parent */
2688 if ( ! gst_bin_remove( GST_BIN( parent ), fakesink->gst ) )
2690 debug_error("failed to remove fakesink\n");
2692 gst_object_unref( parent );
2697 gst_object_unref( parent );
2699 debug_log("state-holder removed\n");
2701 gst_element_set_locked_state( fakesink->gst, FALSE );
2703 g_mutex_unlock( &player->fsink_lock );
2707 if ( fakesink->gst )
2709 gst_element_set_locked_state( fakesink->gst, FALSE );
2712 g_mutex_unlock( &player->fsink_lock );
2718 __mmplayer_gst_rtp_dynamic_pad (GstElement *element, GstPad *pad, gpointer data) // @
2720 GstPad *sinkpad = NULL;
2721 GstCaps* caps = NULL;
2722 GstElement* new_element = NULL;
2723 GstStructure* str = NULL;
2724 const gchar* name = NULL;
2726 mm_player_t* player = (mm_player_t*) data;
2730 return_if_fail( element && pad );
2731 return_if_fail( player &&
2733 player->pipeline->mainbin );
2736 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2737 * num_dynamic_pad will decreased after creating a sinkbin.
2739 player->num_dynamic_pad++;
2740 debug_log("stream count inc : %d\n", player->num_dynamic_pad);
2742 /* perform autoplugging if dump is disabled */
2743 if ( player->ini.rtsp_do_typefinding )
2745 /* create typefind */
2746 new_element = gst_element_factory_make( "typefind", NULL );
2747 if ( ! new_element )
2749 debug_error("failed to create typefind\n");
2753 MMPLAYER_SIGNAL_CONNECT( player,
2754 G_OBJECT(new_element),
2755 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG,
2757 G_CALLBACK(__mmplayer_typefind_have_type),
2760 /* FIXIT : try to remove it */
2761 player->have_dynamic_pad = FALSE;
2763 else /* NOTE : use pad's caps directely. if enabled. what I am assuming is there's no elemnt has dynamic pad */
2765 debug_log("using pad caps to autopluging instead of doing typefind\n");
2767 caps = gst_pad_query_caps( pad, NULL );
2769 MMPLAYER_CHECK_NULL( caps );
2771 /* clear previous result*/
2772 player->have_dynamic_pad = FALSE;
2774 str = gst_caps_get_structure(caps, 0);
2778 debug_error ("cannot get structure from caps.\n");
2782 name = gst_structure_get_name (str);
2785 debug_error ("cannot get mimetype from structure.\n");
2789 if (strstr(name, "video"))
2792 mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &stype);
2794 if (stype == MM_DISPLAY_SURFACE_NULL)
2796 if (player->v_stream_caps)
2798 gst_caps_unref(player->v_stream_caps);
2799 player->v_stream_caps = NULL;
2802 new_element = gst_element_factory_make("fakesink", NULL);
2803 player->num_dynamic_pad--;
2808 /* clear previous result*/
2809 player->have_dynamic_pad = FALSE;
2811 if ( !__mmplayer_try_to_plug_decodebin(player, pad, caps))
2813 debug_error("failed to autoplug for caps");
2817 /* check if there's dynamic pad*/
2818 if( player->have_dynamic_pad )
2820 debug_error("using pad caps assums there's no dynamic pad !\n");
2821 debug_error("try with enalbing rtsp_do_typefinding\n");
2825 gst_caps_unref( caps );
2831 /* excute new_element if created*/
2834 debug_log("adding new element to pipeline\n");
2836 /* set state to READY before add to bin */
2837 MMPLAYER_ELEMENT_SET_STATE( new_element, GST_STATE_READY );
2839 /* add new element to the pipeline */
2840 if ( FALSE == gst_bin_add( GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element) )
2842 debug_error("failed to add autoplug element to bin\n");
2846 /* get pad from element */
2847 sinkpad = gst_element_get_static_pad ( GST_ELEMENT(new_element), "sink" );
2850 debug_error("failed to get sinkpad from autoplug element\n");
2855 if ( GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad) )
2857 debug_error("failed to link autoplug element\n");
2861 gst_object_unref (sinkpad);
2864 /* run. setting PLAYING here since streamming source is live source */
2865 MMPLAYER_ELEMENT_SET_STATE( new_element, GST_STATE_PLAYING );
2872 STATE_CHANGE_FAILED:
2874 /* FIXIT : take care if new_element has already added to pipeline */
2876 gst_object_unref(GST_OBJECT(new_element));
2879 gst_object_unref(GST_OBJECT(sinkpad));
2882 gst_object_unref(GST_OBJECT(caps));
2884 /* FIXIT : how to inform this error to MSL ????? */
2885 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2886 * then post an error to application
2892 /* FIXIT : check indent */
2895 __mmplayer_gst_wfd_dynamic_pad (GstElement *element, GstPad *pad, gpointer data) // @
2897 GstPad *sinkpad = NULL;
2898 GstCaps* caps = NULL;
2899 GstElement* new_element = NULL;
2900 enum MainElementID element_id = MMPLAYER_M_NUM;
2902 mm_player_t* player = (mm_player_t*) data;
2906 return_if_fail( element && pad );
2907 return_if_fail( player &&
2909 player->pipeline->mainbin );
2911 debug_log("stream count inc : %d\n", player->num_dynamic_pad);
2914 debug_log("using pad caps to autopluging instead of doing typefind\n");
2915 caps = gst_pad_query_caps( pad );
2916 MMPLAYER_CHECK_NULL( caps );
2917 /* clear previous result*/
2918 player->have_dynamic_pad = FALSE;
2919 new_element = gst_element_factory_make("rtpmp2tdepay", "wfd_rtp_depay");
2922 debug_error ( "failed to create wfd rtp depay element\n" );
2925 MMPLAYER_ELEMENT_SET_STATE( new_element, GST_STATE_READY );
2926 /* add new element to the pipeline */
2927 if ( FALSE == gst_bin_add( GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element) )
2929 debug_log("failed to add autoplug element to bin\n");
2932 /* get pad from element */
2933 sinkpad = gst_element_get_static_pad ( GST_ELEMENT(new_element), "sink" );
2936 debug_log("failed to get sinkpad from autoplug element\n");
2940 if ( GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad) )
2942 debug_log("failed to link autoplug element\n");
2945 gst_object_unref (sinkpad);
2947 pad = gst_element_get_static_pad ( GST_ELEMENT(new_element), "src" );
2948 caps = gst_pad_query_caps( pad );
2949 MMPLAYER_CHECK_NULL( caps );
2950 MMPLAYER_ELEMENT_SET_STATE( new_element, GST_STATE_PLAYING );
2951 /* create typefind */
2952 new_element = gst_element_factory_make( "typefind", NULL );
2953 if ( ! new_element )
2955 debug_log("failed to create typefind\n");
2959 MMPLAYER_SIGNAL_CONNECT( player,
2960 G_OBJECT(new_element),
2961 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG,
2963 G_CALLBACK(__mmplayer_typefind_have_type),
2966 player->have_dynamic_pad = FALSE;
2969 /* excute new_element if created*/
2972 debug_log("adding new element to pipeline\n");
2974 /* set state to READY before add to bin */
2975 MMPLAYER_ELEMENT_SET_STATE( new_element, GST_STATE_READY );
2977 /* add new element to the pipeline */
2978 if ( FALSE == gst_bin_add( GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element) )
2980 debug_log("failed to add autoplug element to bin\n");
2984 /* get pad from element */
2985 sinkpad = gst_element_get_static_pad ( GST_ELEMENT(new_element), "sink" );
2988 debug_log("failed to get sinkpad from autoplug element\n");
2993 if ( GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad) )
2995 debug_log("failed to link autoplug element\n");
2999 gst_object_unref (sinkpad);
3002 /* run. setting PLAYING here since streamming source is live source */
3003 MMPLAYER_ELEMENT_SET_STATE( new_element, GST_STATE_PLAYING );
3006 /* store handle to futher manipulation */
3007 player->pipeline->mainbin[element_id].id = element_id;
3008 player->pipeline->mainbin[element_id].gst = new_element;
3014 STATE_CHANGE_FAILED:
3016 /* FIXIT : take care if new_element has already added to pipeline */
3018 gst_object_unref(GST_OBJECT(new_element));
3021 gst_object_unref(GST_OBJECT(sinkpad));
3024 gst_object_unref(GST_OBJECT(caps));
3026 /* FIXIT : how to inform this error to MSL ????? */
3027 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
3028 * then post an error to application
3033 static GstPadProbeReturn
3034 __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data)
3036 debug_log ("pad blocked callback, blocked");
3037 return GST_PAD_PROBE_OK;
3040 static GstPadProbeReturn
3041 __mmplayer_audio_data_probe (GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
3043 mm_player_t* player = (mm_player_t*) u_data;
3044 GstBuffer *pad_buffer = gst_pad_probe_info_get_buffer(info);
3046 /* TO_CHECK: performance */
3047 return_val_if_fail (player && GST_IS_BUFFER(pad_buffer), GST_PAD_PROBE_OK);
3049 if (GST_BUFFER_PTS_IS_VALID(pad_buffer) && GST_BUFFER_DURATION_IS_VALID(pad_buffer))
3050 player->gapless.next_pts = GST_BUFFER_PTS(pad_buffer) + GST_BUFFER_DURATION(pad_buffer);
3052 return GST_PAD_PROBE_OK;
3055 static GstPadProbeReturn
3056 __mmplayer_gst_selector_event_probe (GstPad * pad, GstPadProbeInfo * info, gpointer data)
3058 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
3059 GstEvent *event = GST_PAD_PROBE_INFO_DATA (info);
3060 mm_player_t* player = (mm_player_t*)data;
3062 switch (GST_EVENT_TYPE (event)) {
3063 case GST_EVENT_STREAM_START:
3065 case GST_EVENT_SEGMENT: {
3069 if (!player->gapless.running)
3072 if (player->gapless.stream_changed) {
3073 player->gapless.start_time += player->gapless.next_pts;
3074 player->gapless.stream_changed = FALSE;
3077 debug_log ("event: %" GST_PTR_FORMAT, event);
3078 gst_event_copy_segment (event, &segment);
3080 if (segment.format == GST_FORMAT_TIME)
3082 segment.base = player->gapless.start_time;
3083 debug_log ("base of segment: %" GST_TIME_FORMAT, GST_TIME_ARGS (segment.base));
3085 tmpev = gst_event_new_segment (&segment);
3086 gst_event_set_seqnum (tmpev, gst_event_get_seqnum (event));
3087 gst_event_unref (event);
3088 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
3099 __mmplayer_gst_decode_pad_added (GstElement *elem, GstPad *pad, gpointer data)
3101 mm_player_t* player = NULL;
3102 GstElement* pipeline = NULL;
3103 GstElement* selector = NULL;
3104 GstElement* fakesink = NULL;
3105 GstCaps* caps = NULL;
3106 GstStructure* str = NULL;
3107 const gchar* name = NULL;
3108 GstPad* sinkpad = NULL;
3109 GstPad* srcpad = NULL;
3110 gboolean first_track = FALSE;
3112 enum MainElementID elemId = MMPLAYER_M_NUM;
3113 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
3116 player = (mm_player_t*)data;
3118 return_if_fail (elem && pad);
3119 return_if_fail (player && player->pipeline && player->pipeline->mainbin);
3121 //debug_log ("pad-added signal handling\n");
3123 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
3125 /* get mimetype from caps */
3126 caps = gst_pad_query_caps (pad, NULL);
3129 debug_error ("cannot get caps from pad.\n");
3133 str = gst_caps_get_structure (caps, 0);
3136 debug_error ("cannot get structure from caps.\n");
3140 name = gst_structure_get_name (str);
3143 debug_error ("cannot get mimetype from structure.\n");
3147 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
3148 //debug_log ("detected mimetype : %s\n", name);
3150 if (strstr(name, "video"))
3153 mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &stype);
3155 /* don't make video because of not required, and not support multiple track */
3156 if (stype == MM_DISPLAY_SURFACE_NULL)
3158 debug_log ("no video sink by null surface or multiple track");
3159 gchar *caps_str = gst_caps_to_string(caps);
3160 if (strstr(caps_str, "ST12") || strstr(caps_str, "SN12"))
3162 player->set_mode.video_zc = TRUE;
3164 MMPLAYER_FREEIF( caps_str );
3166 if (player->v_stream_caps)
3168 gst_caps_unref(player->v_stream_caps);
3169 player->v_stream_caps = NULL;
3172 debug_log ("create fakesink instead of videobin");
3175 fakesink = gst_element_factory_make ("fakesink", NULL);
3176 if (fakesink == NULL)
3178 debug_error ("ERROR : fakesink create error\n");
3182 player->video_fakesink = fakesink;
3184 gst_bin_add (GST_BIN(pipeline), fakesink);
3187 sinkpad = gst_element_get_static_pad (fakesink, "sink");
3189 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad))
3191 debug_warning ("failed to link fakesink\n");
3192 gst_object_unref (GST_OBJECT(fakesink));
3196 if (player->set_mode.media_packet_video_stream)
3197 player->video_cb_probe_id = gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_BUFFER, __mmplayer_video_stream_probe, player, NULL);
3199 g_object_set (G_OBJECT (fakesink), "async", TRUE, NULL);
3200 g_object_set (G_OBJECT (fakesink), "sync", TRUE, NULL);
3201 gst_element_set_state (fakesink, GST_STATE_PAUSED);
3205 __mmplayer_gst_decode_callback (elem, pad, player);
3209 if (strstr(name, "audio"))
3211 gint samplerate = 0;
3214 if (MMPLAYER_IS_ES_BUFF_SRC(player))
3216 __mmplayer_gst_decode_callback (elem, pad, player);
3220 debug_log ("audio selector \n");
3221 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
3222 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
3224 gst_structure_get_int (str, "rate", &samplerate);
3225 gst_structure_get_int (str, "channels", &channels);
3227 if ((channels > 0 && samplerate == 0)) {//exclude audio decoding
3229 fakesink = gst_element_factory_make ("fakesink", NULL);
3230 if (fakesink == NULL)
3232 debug_error ("ERROR : fakesink create error\n");
3236 gst_bin_add (GST_BIN(pipeline), fakesink);
3239 sinkpad = gst_element_get_static_pad (fakesink, "sink");
3241 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad))
3243 debug_warning ("failed to link fakesink\n");
3244 gst_object_unref (GST_OBJECT(fakesink));
3248 g_object_set (G_OBJECT (fakesink), "async", TRUE, NULL);
3249 g_object_set (G_OBJECT (fakesink), "sync", TRUE, NULL);
3250 gst_element_set_state (fakesink, GST_STATE_PAUSED);
3255 else if (strstr(name, "text"))
3257 debug_log ("text selector \n");
3258 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
3259 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
3263 debug_error ("wrong elem id \n");
3268 if(strstr(name, "video"))
3271 selector = player->pipeline->mainbin[elemId].gst;
3273 if (selector == NULL)
3275 selector = gst_element_factory_make ("input-selector", NULL);
3276 debug_log ("Creating input-selector\n");
3277 if (selector == NULL)
3279 debug_error ("ERROR : input-selector create error\n");
3282 g_object_set (selector, "sync-streams", TRUE, NULL);
3284 player->pipeline->mainbin[elemId].id = elemId;
3285 player->pipeline->mainbin[elemId].gst = selector;
3288 // player->selector[stream_type].active_pad_index = DEFAULT_TRACK; // default
3290 srcpad = gst_element_get_static_pad (selector, "src");
3292 // debug_log ("blocking %" GST_PTR_FORMAT, srcpad);
3293 // gst_pad_set_blocked_async (srcpad, TRUE, __mmplayer_gst_selector_blocked, NULL);
3294 // gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
3295 // __mmplayer_gst_selector_blocked, NULL, NULL);
3297 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
3298 __mmplayer_gst_selector_event_probe, player, NULL);
3300 gst_element_set_state (selector, GST_STATE_PAUSED);
3301 gst_bin_add (GST_BIN(pipeline), selector);
3305 debug_log ("input-selector is already created.\n");
3306 selector = player->pipeline->mainbin[elemId].gst;
3310 debug_log ("Calling request pad with selector %p \n", selector);
3311 sinkpad = gst_element_get_request_pad (selector, "sink_%u");
3313 debug_log ("got pad %s:%s from selector", GST_DEBUG_PAD_NAME (sinkpad));
3315 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad))
3317 debug_warning ("failed to link selector\n");
3318 gst_object_unref (GST_OBJECT(selector));
3324 debug_log ("this is first track --> active track \n");
3325 g_object_set (selector, "active-pad", sinkpad, NULL);
3328 _mmplayer_track_update_info(player, stream_type, sinkpad);
3336 gst_caps_unref (caps);
3341 gst_object_unref (GST_OBJECT(sinkpad));
3347 gst_object_unref (GST_OBJECT(srcpad));
3354 static void __mmplayer_handle_text_decode_path(mm_player_t* player, GstElement* text_selector)
3356 GstPad* srcpad = NULL;
3357 MMHandleType attrs = 0;
3358 gint active_index = 0;
3360 // [link] input-selector :: textbin
3361 srcpad = gst_element_get_static_pad (text_selector, "src");
3364 debug_error("failed to get srcpad from selector\n");
3368 debug_log ("got pad %s:%s from text selector\n", GST_DEBUG_PAD_NAME(srcpad));
3370 active_index = player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index;
3371 if ((active_index != DEFAULT_TRACK) &&
3372 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_TEXT, active_index) != MM_ERROR_NONE))
3374 debug_warning("failed to change text track\n");
3375 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index = DEFAULT_TRACK;
3378 player->no_more_pad = TRUE;
3379 __mmplayer_gst_decode_callback (text_selector, srcpad, player);
3381 debug_log ("unblocking %" GST_PTR_FORMAT, srcpad);
3382 // gst_pad_set_blocked_async (srcpad, FALSE, __mmplayer_gst_selector_blocked, NULL);
3384 debug_log("Total text tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
3386 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
3387 player->has_closed_caption = TRUE;
3389 attrs = MMPLAYER_GET_ATTRS(player);
3392 mm_attrs_set_int_by_name(attrs, "content_text_track_num",(gint)player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
3393 if (mmf_attrs_commit (attrs))
3394 debug_error("failed to commit.\n");
3398 debug_error("cannot get content attribute");
3403 gst_object_unref ( GST_OBJECT(srcpad) );
3408 int _mmplayer_gst_set_audio_channel(MMHandleType hplayer, MMPlayerAudioChannel ch_idx)
3410 int result = MM_ERROR_NONE;
3412 mm_player_t* player = (mm_player_t*)hplayer;
3413 MMPlayerGstElement* mainbin = NULL;
3414 gchar* change_pad_name = NULL;
3415 GstPad* sinkpad = NULL;
3416 GstCaps* caps = NULL;
3420 return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3422 debug_log ("Change Audio mode to %d\n", ch_idx);
3423 player->use_deinterleave = TRUE;
3425 if ((!player->pipeline) || (!player->pipeline->mainbin))
3427 debug_log ("pre setting : %d\n", ch_idx);
3429 player->audio_mode.active_pad_index = ch_idx;
3433 mainbin = player->pipeline->mainbin;
3435 if (mainbin[MMPLAYER_M_A_SELECTOR].gst == NULL)
3437 if (player->max_audio_channels < 2)
3439 debug_log ("mono channel track only\n");
3443 debug_warning ("selector doesn't exist\n");
3444 return result; /* keep playing */
3447 debug_log ("total_ch_num : %d\n", player->audio_mode.total_track_num);
3449 if (player->audio_mode.total_track_num < 2)
3451 debug_warning ("there is no another audio path\n");
3452 return result; /* keep playing */
3455 if ((ch_idx < 0) || (ch_idx >= player->audio_mode.total_track_num))
3457 debug_warning ("Not a proper ch_idx : %d \n", ch_idx);
3458 return result; /* keep playing */
3461 /*To get the new pad from the selector*/
3462 change_pad_name = g_strdup_printf ("sink%d", ch_idx);
3463 if (change_pad_name == NULL)
3465 debug_warning ("Pad does not exists\n");
3466 goto ERROR; /* keep playing */
3469 debug_log ("new active pad name: %s\n", change_pad_name);
3471 sinkpad = gst_element_get_static_pad (mainbin[MMPLAYER_M_A_SELECTOR].gst, change_pad_name);
3472 if (sinkpad == NULL)
3474 //result = MM_ERROR_PLAYER_INTERNAL;
3475 goto ERROR; /* keep playing */
3478 debug_log ("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
3479 g_object_set (mainbin[MMPLAYER_M_A_SELECTOR].gst, "active-pad", sinkpad, NULL);
3481 caps = gst_pad_get_current_caps(sinkpad);
3482 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
3484 __mmplayer_set_audio_attrs (player, caps);
3485 player->audio_mode.active_pad_index = ch_idx;
3490 gst_object_unref (sinkpad);
3492 MMPLAYER_FREEIF(change_pad_name);
3501 __mmplayer_gst_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
3503 mm_player_t* player = (mm_player_t*)data;
3504 GstElement* selector = NULL;
3505 GstElement* queue = NULL;
3507 GstPad* srcpad = NULL;
3508 GstPad* sinkpad = NULL;
3509 gchar* caps_str= NULL;
3512 return_if_fail (player && player->pipeline && player->pipeline->mainbin);
3514 caps_str = gst_caps_to_string(gst_pad_get_current_caps(pad));
3515 debug_log ("deinterleave new caps : %s\n", caps_str);
3516 MMPLAYER_FREEIF(caps_str);
3518 if ((queue = __mmplayer_element_create_and_link(player, pad, "queue")) == NULL)
3520 debug_error ("ERROR : queue create error\n");
3524 g_object_set(G_OBJECT(queue),
3525 "max-size-buffers", 10,
3526 "max-size-bytes", 0,
3527 "max-size-time", (guint64)0,
3530 selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
3534 debug_error("there is no audio channel selector.\n");
3538 srcpad = gst_element_get_static_pad (queue, "src");
3539 sinkpad = gst_element_get_request_pad (selector, "sink_%u");
3541 debug_log ("link (%s:%s - %s:%s)\n", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
3543 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad))
3545 debug_warning ("failed to link deinterleave - selector\n");
3549 gst_element_set_state (queue, GST_STATE_PAUSED);
3550 player->audio_mode.total_track_num++;
3556 gst_object_unref ( GST_OBJECT(srcpad) );
3562 gst_object_unref ( GST_OBJECT(sinkpad) );
3571 __mmplayer_gst_deinterleave_no_more_pads (GstElement *elem, gpointer data)
3573 mm_player_t* player = NULL;
3574 GstElement* selector = NULL;
3575 GstPad* sinkpad = NULL;
3576 gint active_index = 0;
3577 gchar* change_pad_name = NULL;
3578 GstCaps* caps = NULL; // no need to unref
3581 player = (mm_player_t*) data;
3583 selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
3587 debug_error("there is no audio channel selector.\n");
3591 active_index = player->audio_mode.active_pad_index;
3593 if (active_index != DEFAULT_AUDIO_CH)
3595 gint audio_ch = DEFAULT_AUDIO_CH;
3597 /*To get the new pad from the selector*/
3598 change_pad_name = g_strdup_printf ("sink%d", active_index);
3599 if (change_pad_name != NULL)
3601 sinkpad = gst_element_get_static_pad (selector, change_pad_name);
3602 if (sinkpad != NULL)
3604 debug_log ("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
3605 g_object_set (selector, "active-pad", sinkpad, NULL);
3607 audio_ch = active_index;
3609 caps = gst_pad_get_current_caps(sinkpad);
3610 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
3612 __mmplayer_set_audio_attrs (player, caps);
3616 player->audio_mode.active_pad_index = audio_ch;
3617 debug_log("audio LR info (0:stereo) = %d\n", player->audio_mode.active_pad_index);
3623 gst_object_unref (sinkpad);
3630 __mmplayer_gst_build_deinterleave_path (GstElement *elem, GstPad *pad, gpointer data)
3632 mm_player_t* player = NULL;
3633 MMPlayerGstElement *mainbin = NULL;
3635 GstElement* tee = NULL;
3636 GstElement* stereo_queue = NULL;
3637 GstElement* mono_queue = NULL;
3638 GstElement* conv = NULL;
3639 GstElement* filter = NULL;
3640 GstElement* deinterleave = NULL;
3641 GstElement* selector = NULL;
3643 GstPad* srcpad = NULL;
3644 GstPad* selector_srcpad = NULL;
3645 GstPad* sinkpad = NULL;
3646 GstCaps* caps = NULL;
3651 player = (mm_player_t*) data;
3653 return_if_fail( elem && pad );
3654 return_if_fail( player && player->pipeline && player->pipeline->mainbin );
3656 mainbin = player->pipeline->mainbin;
3659 if ((tee = __mmplayer_element_create_and_link(player, pad, "tee")) == NULL)
3661 debug_error ("ERROR : tee create error\n");
3665 mainbin[MMPLAYER_M_A_TEE].id = MMPLAYER_M_A_TEE;
3666 mainbin[MMPLAYER_M_A_TEE].gst = tee;
3668 gst_element_set_state (tee, GST_STATE_PAUSED);
3671 srcpad = gst_element_get_request_pad (tee, "src_%u");
3672 if ((stereo_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL)
3674 debug_error ("ERROR : stereo queue create error\n");
3678 g_object_set(G_OBJECT(stereo_queue),
3679 "max-size-buffers", 10,
3680 "max-size-bytes", 0,
3681 "max-size-time", (guint64)0,
3684 player->pipeline->mainbin[MMPLAYER_M_A_Q1].id = MMPLAYER_M_A_Q1;
3685 player->pipeline->mainbin[MMPLAYER_M_A_Q1].gst = stereo_queue;
3689 gst_object_unref (GST_OBJECT(srcpad));
3693 srcpad = gst_element_get_request_pad (tee, "src_%u");
3695 if ((mono_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL)
3697 debug_error ("ERROR : mono queue create error\n");
3701 g_object_set(G_OBJECT(mono_queue),
3702 "max-size-buffers", 10,
3703 "max-size-bytes", 0,
3704 "max-size-time", (guint64)0,
3707 player->pipeline->mainbin[MMPLAYER_M_A_Q2].id = MMPLAYER_M_A_Q2;
3708 player->pipeline->mainbin[MMPLAYER_M_A_Q2].gst = mono_queue;
3710 gst_element_set_state (stereo_queue, GST_STATE_PAUSED);
3711 gst_element_set_state (mono_queue, GST_STATE_PAUSED);
3714 srcpad = gst_element_get_static_pad (mono_queue, "src");
3715 if ((conv = __mmplayer_element_create_and_link(player, srcpad, "audioconvert")) == NULL)
3717 debug_error ("ERROR : audioconvert create error\n");
3721 player->pipeline->mainbin[MMPLAYER_M_A_CONV].id = MMPLAYER_M_A_CONV;
3722 player->pipeline->mainbin[MMPLAYER_M_A_CONV].gst = conv;
3727 gst_object_unref (GST_OBJECT(srcpad));
3730 srcpad = gst_element_get_static_pad (conv, "src");
3732 if ((filter = __mmplayer_element_create_and_link(player, srcpad, "capsfilter")) == NULL)
3734 debug_error ("ERROR : capsfilter create error\n");
3738 player->pipeline->mainbin[MMPLAYER_M_A_FILTER].id = MMPLAYER_M_A_FILTER;
3739 player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst = filter;
3741 caps = gst_caps_from_string( "audio/x-raw-int, "
3742 "width = (int) 16, "
3743 "depth = (int) 16, "
3744 "channels = (int) 2");
3746 g_object_set (GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst), "caps", caps, NULL );
3747 gst_caps_unref( caps );
3749 gst_element_set_state (conv, GST_STATE_PAUSED);
3750 gst_element_set_state (filter, GST_STATE_PAUSED);
3755 gst_object_unref (GST_OBJECT(srcpad));
3758 srcpad = gst_element_get_static_pad (filter, "src");
3760 if ((deinterleave = __mmplayer_element_create_and_link(player, srcpad, "deinterleave")) == NULL)
3762 debug_error ("ERROR : deinterleave create error\n");
3766 g_object_set (deinterleave, "keep-positions", TRUE, NULL);
3768 MMPLAYER_SIGNAL_CONNECT (player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
3769 G_CALLBACK (__mmplayer_gst_deinterleave_pad_added), player);
3771 MMPLAYER_SIGNAL_CONNECT (player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
3772 G_CALLBACK (__mmplayer_gst_deinterleave_no_more_pads), player);
3774 player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].id = MMPLAYER_M_A_DEINTERLEAVE;
3775 player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].gst = deinterleave;
3778 selector = gst_element_factory_make ("input-selector", "audio-channel-selector");
3779 if (selector == NULL)
3781 debug_error ("ERROR : audio-selector create error\n");
3785 g_object_set (selector, "sync-streams", TRUE, NULL);
3786 gst_bin_add (GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), selector);
3788 player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].id = MMPLAYER_M_A_SELECTOR;
3789 player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst = selector;
3791 selector_srcpad = gst_element_get_static_pad (selector, "src");
3793 debug_log ("blocking %" GST_PTR_FORMAT, selector_srcpad);
3794 //gst_pad_set_blocked_async (selector_srcpad, TRUE, __mmplayer_gst_selector_blocked, NULL);
3795 gst_pad_add_probe(selector_srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
3796 __mmplayer_gst_selector_blocked, NULL, NULL);
3800 gst_object_unref (GST_OBJECT(srcpad));
3804 srcpad = gst_element_get_static_pad(stereo_queue, "src");
3805 sinkpad = gst_element_get_request_pad (selector, "sink_%u");
3807 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad))
3809 debug_warning ("failed to link queue_stereo - selector\n");
3813 player->audio_mode.total_track_num++;
3815 g_object_set (selector, "active-pad", sinkpad, NULL);
3816 gst_element_set_state (deinterleave, GST_STATE_PAUSED);
3817 gst_element_set_state (selector, GST_STATE_PAUSED);
3819 __mmplayer_gst_decode_callback (selector, selector_srcpad, player);
3821 debug_log ("unblocking %" GST_PTR_FORMAT, selector_srcpad);
3822 // gst_pad_set_blocked_async (selector_srcpad, FALSE, __mmplayer_gst_selector_blocked, NULL);
3827 gst_object_unref (GST_OBJECT(sinkpad));
3833 gst_object_unref (GST_OBJECT(srcpad));
3837 if (selector_srcpad)
3839 gst_object_unref (GST_OBJECT(selector_srcpad));
3840 selector_srcpad = NULL;
3848 __mmplayer_gst_decode_no_more_pads (GstElement *elem, gpointer data)
3850 mm_player_t* player = NULL;
3851 GstPad* srcpad = NULL;
3852 GstElement* audio_selector = NULL;
3853 GstElement* text_selector = NULL;
3854 MMHandleType attrs = 0;
3855 gint active_index = 0;
3856 gint64 dur_bytes = 0L;
3858 player = (mm_player_t*) data;
3860 debug_log("no-more-pad signal handling\n");
3862 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
3863 (player->cmd == MMPLAYER_COMMAND_UNREALIZE))
3865 debug_warning("no need to go more");
3867 if (player->gapless.reconfigure)
3869 player->gapless.reconfigure = FALSE;
3870 MMPLAYER_PLAYBACK_UNLOCK(player);
3876 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
3877 (MMPLAYER_IS_HTTP_STREAMING(player)) &&
3878 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
3879 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst))
3881 #define ESTIMATED_BUFFER_UNIT (1*1024*1024)
3883 if (NULL == player->streamer)
3885 debug_warning("invalid state for buffering");
3889 gdouble init_buffering_time = (gdouble)player->streamer->buffering_req.initial_second;
3890 guint buffer_bytes = init_buffering_time * ESTIMATED_BUFFER_UNIT;
3892 buffer_bytes = MAX(buffer_bytes, player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffering_bytes);
3893 debug_log("[Decodebin2] set use-buffering on Q2 (pre buffer time: %d sec, buffer size : %d)\n", (gint)init_buffering_time, buffer_bytes);
3895 init_buffering_time = (init_buffering_time != 0)?(init_buffering_time):(player->ini.http_buffering_time);
3897 if ( !gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
3898 debug_error("fail to get duration.\n");
3900 // enable use-buffering on queue2 instead of multiqueue (ex)audio only streaming
3901 // use file information was already set on Q2 when it was created.
3902 __mm_player_streaming_set_queue2(player->streamer,
3903 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
3904 TRUE, // use_buffering
3906 init_buffering_time,
3908 player->ini.http_buffering_limit, // high percent
3911 ((dur_bytes>0)?((guint64)dur_bytes):0));
3913 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
3914 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3917 active_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
3918 if ((active_index != DEFAULT_TRACK) &&
3919 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_AUDIO, active_index) != MM_ERROR_NONE))
3921 debug_warning("failed to change audio track\n");
3922 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index = DEFAULT_TRACK;
3925 // [link] input-selector :: audiobin
3926 srcpad = gst_element_get_static_pad (audio_selector, "src");
3929 debug_error("failed to get srcpad from selector\n");
3933 debug_log ("got pad %s:%s from selector\n", GST_DEBUG_PAD_NAME(srcpad));
3935 player->no_more_pad = TRUE;
3937 if ((player->use_deinterleave == TRUE) && (player->max_audio_channels >= 2))
3939 debug_log ("unblocking %" GST_PTR_FORMAT, srcpad);
3940 // gst_pad_set_blocked_async (srcpad, FALSE, __mmplayer_gst_selector_blocked, NULL);
3942 __mmplayer_gst_build_deinterleave_path(audio_selector, srcpad, player);
3946 __mmplayer_gst_decode_callback (audio_selector, srcpad, player);
3948 debug_log ("unblocking %" GST_PTR_FORMAT, srcpad);
3949 // gst_pad_set_blocked_async (srcpad, FALSE, __mmplayer_gst_selector_blocked, NULL);
3952 debug_log("Total audio tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3954 attrs = MMPLAYER_GET_ATTRS(player);
3957 mm_attrs_set_int_by_name(attrs, "content_audio_track_num",(gint)player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3958 if (mmf_attrs_commit (attrs))
3959 debug_error("failed to commit.\n");
3963 debug_error("cannot get content attribute");
3968 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst))
3970 debug_log ("There is no audio track : remove audiobin");
3972 __mmplayer_release_signal_connection( player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN );
3973 __mmplayer_del_sink ( player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst );
3975 MMPLAYER_RELEASE_ELEMENT ( player, player->pipeline->audiobin, MMPLAYER_A_BIN );
3976 MMPLAYER_FREEIF ( player->pipeline->audiobin )
3979 if (player->num_dynamic_pad == 0)
3981 __mmplayer_pipeline_complete (NULL, player);
3986 if (!MMPLAYER_IS_ES_BUFF_SRC(player))
3990 __mmplayer_handle_text_decode_path(player, text_selector);
3999 gst_object_unref ( GST_OBJECT(srcpad) );
4003 if (player->gapless.reconfigure)
4005 player->gapless.reconfigure = FALSE;
4006 MMPLAYER_PLAYBACK_UNLOCK(player);
4011 __mmplayer_gst_decode_callback(GstElement *elem, GstPad *pad, gpointer data) // @
4013 mm_player_t* player = NULL;
4014 MMHandleType attrs = 0;
4015 GstElement* pipeline = NULL;
4016 GstCaps* caps = NULL;
4017 gchar* caps_str = NULL;
4018 GstStructure* str = NULL;
4019 const gchar* name = NULL;
4020 GstPad* sinkpad = NULL;
4021 GstElement* sinkbin = NULL;
4022 gboolean reusing = FALSE;
4023 GstElement *text_selector = NULL;
4026 player = (mm_player_t*) data;
4028 return_if_fail( elem && pad );
4029 return_if_fail(player && player->pipeline && player->pipeline->mainbin);
4031 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4033 attrs = MMPLAYER_GET_ATTRS(player);
4036 debug_error("cannot get content attribute\n");
4040 /* get mimetype from caps */
4041 caps = gst_pad_query_caps( pad, NULL );
4044 debug_error("cannot get caps from pad.\n");
4047 caps_str = gst_caps_to_string(caps);
4049 str = gst_caps_get_structure( caps, 0 );
4052 debug_error("cannot get structure from caps.\n");
4056 name = gst_structure_get_name(str);
4059 debug_error("cannot get mimetype from structure.\n");
4063 //debug_log("detected mimetype : %s\n", name);
4065 if (strstr(name, "audio"))
4067 if (player->pipeline->audiobin == NULL)
4069 if (MM_ERROR_NONE != __mmplayer_gst_create_audio_pipeline(player))
4071 debug_error("failed to create audiobin. continuing without audio\n");
4075 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
4076 debug_log("creating audiosink bin success\n");
4081 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
4082 debug_log("reusing audiobin\n");
4083 _mmplayer_update_content_attrs( player, ATTR_AUDIO);
4086 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num <= 0) // should not update if content have multi audio tracks
4087 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 1);
4089 player->audiosink_linked = 1;
4091 sinkpad = gst_element_get_static_pad( GST_ELEMENT(sinkbin), "sink" );
4094 debug_error("failed to get pad from sinkbin\n");
4098 else if (strstr(name, "video"))
4100 if (strstr(caps_str, "ST12") || strstr(caps_str, "SN12"))
4102 player->set_mode.video_zc = TRUE;
4105 if (player->pipeline->videobin == NULL)
4107 /* NOTE : not make videobin because application dose not want to play it even though file has video stream. */
4108 /* get video surface type */
4109 int surface_type = 0;
4110 mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &surface_type);
4112 if (surface_type == MM_DISPLAY_SURFACE_NULL)
4114 debug_log("not make videobin because it dose not want\n");
4118 if (MM_ERROR_NONE != __mmplayer_gst_create_video_pipeline(player, caps, surface_type) )
4120 debug_error("failed to create videobin. continuing without video\n");
4124 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
4125 debug_log("creating videosink bin success\n");
4130 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
4131 debug_log("re-using videobin\n");
4132 _mmplayer_update_content_attrs( player, ATTR_VIDEO);
4135 /* FIXIT : track number shouldn't be hardcoded */
4136 mm_attrs_set_int_by_name(attrs, "content_video_track_num", 1);
4137 player->videosink_linked = 1;
4139 /* NOTE : intermediate code before doing H/W subtitle compositon */
4140 if ( player->use_textoverlay && player->play_subtitle )
4142 debug_log("using textoverlay for external subtitle");
4143 /* check text bin has created well */
4144 if ( player->pipeline && player->pipeline->textbin )
4146 /* get sinkpad from textoverlay */
4147 sinkpad = gst_element_get_static_pad(
4148 GST_ELEMENT(player->pipeline->textbin[MMPLAYER_T_BIN].gst),
4152 debug_error("failed to get sink pad from textoverlay");
4156 /* link new pad with textoverlay first */
4157 if ( GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad) )
4159 debug_error("failed to get pad from sinkbin\n");
4163 gst_object_unref(sinkpad);
4166 /* alright, override pad to textbin.src for futher link */
4167 pad = gst_element_get_static_pad(
4168 GST_ELEMENT(player->pipeline->textbin[MMPLAYER_T_BIN].gst),
4172 debug_error("failed to get sink pad from textoverlay");
4178 debug_error("should not reach here.");
4183 sinkpad = gst_element_get_static_pad( GST_ELEMENT(sinkbin), "sink" );
4186 debug_error("failed to get pad from sinkbin\n");
4190 else if (strstr(name, "text"))
4192 if (player->pipeline->textbin == NULL)
4194 MMPlayerGstElement* mainbin = NULL;
4196 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player))
4198 debug_error("failed to create textbin. continuing without text\n");
4202 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
4203 debug_log("creating textsink bin success\n");
4205 /* FIXIT : track number shouldn't be hardcoded */
4206 mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1);
4208 player->textsink_linked = 1;
4209 debug_msg("player->textsink_linked set to 1\n");
4211 sinkpad = gst_element_get_static_pad( GST_ELEMENT(sinkbin), "text_sink" );
4214 debug_error("failed to get pad from sinkbin\n");
4218 mainbin = player->pipeline->mainbin;
4220 if (!mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst)
4222 /* input selector */
4223 text_selector = gst_element_factory_make("input-selector", "subtitle_inselector");
4224 if ( !text_selector )
4226 debug_error ( "failed to create subtitle input selector element\n" );
4229 g_object_set (text_selector, "sync-streams", TRUE, NULL);
4231 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].id = MMPLAYER_M_T_INPUT_SELECTOR;
4232 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst = text_selector;
4235 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state (text_selector, GST_STATE_READY))
4237 debug_error("failed to set state(READY) to sinkbin\n");
4241 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), text_selector))
4243 debug_warning("failed to add subtitle input selector\n");
4247 debug_log ("created element input-selector");
4252 debug_log ("already having subtitle input selector");
4253 text_selector = mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
4259 if (!player->textsink_linked)
4261 debug_log("re-using textbin\n");
4264 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
4266 player->textsink_linked = 1;
4267 debug_msg("player->textsink_linked set to 1\n");
4271 debug_log("ignoring internal subtutle since external subtitle is available");
4277 debug_warning("unknown type of elementary stream! ignoring it...\n");
4286 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state( sinkbin, GST_STATE_READY ) )
4288 debug_error("failed to set state(READY) to sinkbin\n");
4292 /* Added for multi audio support to avoid adding audio bin again*/
4294 if ( FALSE == gst_bin_add( GST_BIN(pipeline), sinkbin ) )
4296 debug_error("failed to add sinkbin to pipeline\n");
4302 if (GST_PAD_LINK_OK != GST_PAD_LINK (pad, sinkpad))
4304 debug_error("failed to get pad from sinkbin\n");
4311 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state (sinkbin, GST_STATE_PAUSED))
4313 debug_error("failed to set state(PLAYING) to sinkbin\n");
4319 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state (text_selector, GST_STATE_PAUSED))
4321 debug_error("failed to set state(READY) to sinkbin\n");
4327 gst_object_unref (sinkpad);
4331 debug_log ("linking sink bin success\n");
4333 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
4334 * streaming task. if the task blocked, then buffer will not flow to the next element
4335 * ( autoplugging element ). so this is special hack for streaming. please try to remove it
4337 /* dec stream count. we can remove fakesink if it's zero */
4338 if (player->num_dynamic_pad)
4339 player->num_dynamic_pad--;
4341 debug_log ("no more pads: %d stream count dec : %d (num of dynamic pad)\n", player->no_more_pad, player->num_dynamic_pad);
4343 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
4345 __mmplayer_pipeline_complete (NULL, player);
4348 /* FIXIT : please leave a note why this code is needed */
4349 if(MMPLAYER_IS_WFD_STREAMING( player ))
4351 player->no_more_pad = TRUE;
4356 MMPLAYER_FREEIF(caps_str);
4359 gst_caps_unref( caps );
4362 gst_object_unref(GST_OBJECT(sinkpad));
4364 /* flusing out new attributes */
4365 if ( mmf_attrs_commit ( attrs ) )
4367 debug_error("failed to comit attributes\n");
4374 __mmplayer_get_property_value_for_rotation(mm_player_t* player, int rotation_angle, int *value)
4376 int pro_value = 0; // in the case of expection, default will be returned.
4377 int dest_angle = rotation_angle;
4378 int rotation_type = -1;
4379 #define ROTATION_USING_SINK 0
4380 #define ROTATION_USING_CUSTOM 1
4381 #define ROTATION_USING_FLIP 2
4383 return_val_if_fail(player, FALSE);
4384 return_val_if_fail(value, FALSE);
4385 return_val_if_fail(rotation_angle >= 0, FALSE);
4387 if (rotation_angle >= 360)
4389 dest_angle = rotation_angle - 360;
4392 /* chech if supported or not */
4393 if ( dest_angle % 90 )
4395 debug_log("not supported rotation angle = %d", rotation_angle);
4400 * xvimagesink only (A)
4401 * custom_convert - no xv (e.g. memsink, evasimagesink (B)
4402 * videoflip - avsysmemsink (C)
4404 if (player->set_mode.video_zc)
4406 if (player->pipeline->videobin[MMPLAYER_V_CONV].gst) // B
4408 rotation_type = ROTATION_USING_CUSTOM;
4412 rotation_type = ROTATION_USING_SINK;
4417 int surface_type = 0;
4418 rotation_type = ROTATION_USING_FLIP;
4420 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
4421 debug_log("check display surface type attribute: %d", surface_type);
4423 if ((surface_type == MM_DISPLAY_SURFACE_X) ||
4424 (surface_type == MM_DISPLAY_SURFACE_EVAS && !strcmp(player->ini.videosink_element_evas, "evaspixmapsink")))
4426 rotation_type = ROTATION_USING_SINK;
4430 rotation_type = ROTATION_USING_FLIP; //C
4433 debug_log("using %d type for rotation", rotation_type);
4436 /* get property value for setting */
4437 switch(rotation_type)
4439 case ROTATION_USING_SINK: // xvimagesink, pixmap
4446 pro_value = 3; // clockwise 90
4452 pro_value = 1; // counter-clockwise 90
4457 case ROTATION_USING_CUSTOM:
4459 gchar *ename = NULL;
4460 ename = GST_OBJECT_NAME(gst_element_get_factory(player->pipeline->videobin[MMPLAYER_V_CONV].gst));
4462 if (g_strrstr(ename, "fimcconvert"))
4469 pro_value = 90; // clockwise 90
4475 pro_value = 270; // counter-clockwise 90
4481 case ROTATION_USING_FLIP: // videoflip
4489 pro_value = 1; // clockwise 90
4495 pro_value = 3; // counter-clockwise 90
4502 debug_log("setting rotation property value : %d, used rotation type : %d", pro_value, rotation_type);
4510 _mmplayer_update_video_param(mm_player_t* player) // @
4512 MMHandleType attrs = 0;
4513 int surface_type = 0;
4514 int org_angle = 0; // current supported angle values are 0, 90, 180, 270
4516 int user_angle_type= 0;
4517 int rotation_value = 0;
4518 gchar *org_orient = NULL;
4522 /* check video sinkbin is created */
4523 return_val_if_fail ( player &&
4525 player->pipeline->videobin &&
4526 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
4527 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
4528 MM_ERROR_PLAYER_NOT_INITIALIZED );
4530 attrs = MMPLAYER_GET_ATTRS(player);
4533 debug_error("cannot get content attribute");
4534 return MM_ERROR_PLAYER_INTERNAL;
4537 /* update user roation */
4538 mm_attrs_get_int_by_name(attrs, "display_rotation", &user_angle_type);
4540 /* get angle with user type */
4541 switch(user_angle_type)
4543 case MM_DISPLAY_ROTATION_NONE:
4546 case MM_DISPLAY_ROTATION_90: // counter-clockwise 90
4549 case MM_DISPLAY_ROTATION_180:
4552 case MM_DISPLAY_ROTATION_270: // clockwise 90
4557 /* get original orientation */
4558 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
4562 if (!strcmp (org_orient, "rotate-90"))
4564 else if (!strcmp (org_orient, "rotate-180"))
4566 else if (!strcmp (org_orient, "rotate-270"))
4569 debug_log ("original rotation is %s", org_orient);
4573 debug_log ("content_video_orientation get fail");
4576 debug_log("check user angle: %d, orientation: %d", user_angle, org_angle);
4578 /* check video stream callback is used */
4579 if(!player->set_mode.media_packet_video_stream && player->use_video_stream )
4581 if (player->set_mode.video_zc)
4583 gchar *ename = NULL;
4587 mm_attrs_get_int_by_name(attrs, "display_width", &width);
4588 mm_attrs_get_int_by_name(attrs, "display_height", &height);
4590 /* resize video frame with requested values for fimcconvert */
4591 ename = GST_OBJECT_NAME(gst_element_get_factory(player->pipeline->videobin[MMPLAYER_V_CONV].gst));
4593 if (ename && g_strrstr(ename, "fimcconvert"))
4596 g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "dst-width", width, NULL);
4599 g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "dst-height", height, NULL);
4601 /* NOTE: fimcconvert does not manage index of src buffer from upstream src-plugin, decoder gives frame information in output buffer with no ordering */
4602 g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "src-rand-idx", TRUE, NULL);
4604 /* get rotation value to set */
4605 __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
4607 g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "rotate", rotation_value, NULL);
4609 debug_log("updating fimcconvert - r[%d], w[%d], h[%d]", rotation_value, width, height);
4614 debug_log("using video stream callback with memsink. player handle : [%p]", player);
4616 /* get rotation value to set */
4617 __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
4619 g_object_set(player->pipeline->videobin[MMPLAYER_V_FLIP].gst, "method", rotation_value, NULL);
4622 return MM_ERROR_NONE;
4625 /* update display surface */
4626 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
4627 debug_log("check display surface type attribute: %d", surface_type);
4629 /* configuring display */
4630 switch ( surface_type )
4632 case MM_DISPLAY_SURFACE_X:
4634 /* ximagesink or xvimagesink */
4635 void *surface = NULL;
4636 int display_method = 0;
4645 int force_aspect_ratio = 0;
4646 gboolean visible = TRUE;
4650 void* wl_display = NULL;
4651 GstContext *context = NULL;
4652 int wl_window_x = 0;
4653 int wl_window_y = 0;
4654 int wl_window_width = 0;
4655 int wl_window_height = 0;
4657 mm_attrs_get_data_by_name(attrs, "wl_display", &wl_display);
4659 context = gst_wayland_display_handle_context_new(wl_display);
4661 gst_element_set_context(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), context);
4663 /*It should be set after setting window*/
4664 mm_attrs_get_int_by_name(attrs, "wl_window_render_x", &wl_window_x);
4665 mm_attrs_get_int_by_name(attrs, "wl_window_render_y", &wl_window_y);
4666 mm_attrs_get_int_by_name(attrs, "wl_window_render_width", &wl_window_width);
4667 mm_attrs_get_int_by_name(attrs, "wl_window_render_height", &wl_window_height);
4669 /* common case if using x surface */
4670 mm_attrs_get_data_by_name(attrs, "display_overlay", &surface);
4675 wl_surface = (int*)surface;
4676 debug_log("set video param : xid %p", (int*)surface);
4679 gst_video_overlay_set_window_handle( GST_VIDEO_OVERLAY( player->pipeline->videobin[MMPLAYER_V_SINK].gst ), (int*)surface );
4680 /* After setting window handle, set render rectangle */
4681 gst_video_overlay_set_render_rectangle(
4682 GST_VIDEO_OVERLAY( player->pipeline->videobin[MMPLAYER_V_SINK].gst ),
4683 wl_window_x,wl_window_y,wl_window_width,wl_window_height);
4687 xwin_id = *(int*)surface;
4688 debug_log("set video param : xid %p", *(int*)surface);
4691 gst_video_overlay_set_window_handle( GST_VIDEO_OVERLAY( player->pipeline->videobin[MMPLAYER_V_SINK].gst ), *(int*)surface );
4697 /* FIXIT : is it error case? */
4698 debug_warning("still we don't have xid on player attribute. create it's own surface.");
4701 /* if xvimagesink */
4702 if (!strcmp(player->ini.videosink_element_x,"xvimagesink"))
4704 mm_attrs_get_int_by_name(attrs, "display_force_aspect_ration", &force_aspect_ratio);
4705 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
4706 mm_attrs_get_int_by_name(attrs, "display_src_crop_x", &src_crop_x);
4707 mm_attrs_get_int_by_name(attrs, "display_src_crop_y", &src_crop_y);
4708 mm_attrs_get_int_by_name(attrs, "display_src_crop_width", &src_crop_w);
4709 mm_attrs_get_int_by_name(attrs, "display_src_crop_height", &src_crop_h);
4710 mm_attrs_get_int_by_name(attrs, "display_roi_x", &roi_x);
4711 mm_attrs_get_int_by_name(attrs, "display_roi_y", &roi_y);
4712 mm_attrs_get_int_by_name(attrs, "display_roi_width", &roi_w);
4713 mm_attrs_get_int_by_name(attrs, "display_roi_height", &roi_h);
4714 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
4715 #define DEFAULT_DISPLAY_MODE 2 // TV only, PRI_VIDEO_OFF_AND_SEC_VIDEO_FULL_SCREEN
4717 /* setting for cropping media source */
4718 if (src_crop_w && src_crop_h)
4720 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
4721 "src-crop-x", src_crop_x,
4722 "src-crop-y", src_crop_y,
4723 "src-crop-w", src_crop_w,
4724 "src-crop-h", src_crop_h,
4728 /* setting for ROI mode */
4729 if (display_method == 5) // 5 for ROI mode
4732 mm_attrs_get_int_by_name(attrs, "display_roi_mode", &roi_mode);
4733 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
4734 "dst-roi-mode", roi_mode,
4740 /* get rotation value to set,
4741 do not use org_angle because ROI mode in xvimagesink needs both a rotation value and an orientation value */
4742 __mmplayer_get_property_value_for_rotation(player, user_angle, &rotation_value);
4746 /* get rotation value to set */
4747 __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
4750 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
4751 "force-aspect-ratio", force_aspect_ratio,
4752 "orientation", org_angle/90, // setting for orientation of media, it is used for ROI/ZOOM feature in xvimagesink
4753 "rotate", rotation_value,
4754 "handle-events", TRUE,
4755 "display-geometry-method", display_method,
4756 "draw-borders", FALSE,
4757 "handle-expose", FALSE,
4759 "display-mode", DEFAULT_DISPLAY_MODE,
4762 debug_log("set video param : rotate %d, method %d visible %d", rotation_value, display_method, visible);
4763 debug_log("set video param : dst-roi-x: %d, dst-roi-y: %d, dst-roi-w: %d, dst-roi-h: %d", roi_x, roi_y, roi_w, roi_h );
4764 debug_log("set video param : force aspect ratio %d, display mode %d", force_aspect_ratio, DEFAULT_DISPLAY_MODE);
4768 case MM_DISPLAY_SURFACE_EVAS:
4770 void *object = NULL;
4772 gboolean visible = TRUE;
4773 int display_method = 0;
4775 /* common case if using evas surface */
4776 mm_attrs_get_data_by_name(attrs, "display_overlay", &object);
4777 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
4778 mm_attrs_get_int_by_name(attrs, "display_evas_do_scaling", &scaling);
4779 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
4781 /* if evasimagesink */
4782 if (!strcmp(player->ini.videosink_element_evas,"evasimagesink"))
4786 /* if it is evasimagesink, we are not supporting rotation */
4787 if (user_angle_type!=MM_DISPLAY_ROTATION_NONE)
4789 mm_attrs_set_int_by_name(attrs, "display_rotation", MM_DISPLAY_ROTATION_NONE);
4790 if (mmf_attrs_commit (attrs)) /* return -1 if error */
4791 debug_error("failed to commit\n");
4792 debug_warning("unsupported feature");
4793 return MM_ERROR_NOT_SUPPORT_API;
4795 __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
4796 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
4797 "evas-object", object,
4799 "display-geometry-method", display_method,
4800 "rotate", rotation_value,
4802 debug_log("set video param : method %d", display_method);
4803 debug_log("set video param : evas-object %x, visible %d", object, visible);
4804 debug_log("set video param : evas-object %x, rotate %d", object, rotation_value);
4808 debug_error("no evas object");
4809 return MM_ERROR_PLAYER_INTERNAL;
4813 /* if evasimagesink using converter */
4814 if (player->set_mode.video_zc && player->pipeline->videobin[MMPLAYER_V_CONV].gst)
4818 int no_scaling = !scaling;
4820 mm_attrs_get_int_by_name(attrs, "display_width", &width);
4821 mm_attrs_get_int_by_name(attrs, "display_height", &height);
4823 /* NOTE: fimcconvert does not manage index of src buffer from upstream src-plugin, decoder gives frame information in output buffer with no ordering */
4824 g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "src-rand-idx", TRUE, NULL);
4825 g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "dst-buffer-num", 5, NULL);
4829 /* no-scaling order to fimcconvert, original width, height size of media src will be passed to sink plugin */
4830 g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst,
4831 "dst-width", 0, /* setting 0, output video width will be media src's width */
4832 "dst-height", 0, /* setting 0, output video height will be media src's height */
4837 /* scaling order to fimcconvert */
4840 g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "dst-width", width, NULL);
4844 g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "dst-height", height, NULL);
4846 debug_log("set video param : video frame scaling down to width(%d) height(%d)", width, height);
4848 debug_log("set video param : display_evas_do_scaling %d", scaling);
4852 /* if evaspixmapsink */
4853 if (!strcmp(player->ini.videosink_element_evas,"evaspixmapsink"))
4857 __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
4858 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
4859 "evas-object", object,
4861 "display-geometry-method", display_method,
4862 "rotate", rotation_value,
4864 debug_log("set video param : method %d", display_method);
4865 debug_log("set video param : evas-object %x, visible %d", object, visible);
4866 debug_log("set video param : evas-object %x, rotate %d", object, rotation_value);
4870 debug_error("no evas object");
4871 return MM_ERROR_PLAYER_INTERNAL;
4874 int display_method = 0;
4879 int origin_size = !scaling;
4881 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
4882 mm_attrs_get_int_by_name(attrs, "display_roi_x", &roi_x);
4883 mm_attrs_get_int_by_name(attrs, "display_roi_y", &roi_y);
4884 mm_attrs_get_int_by_name(attrs, "display_roi_width", &roi_w);
4885 mm_attrs_get_int_by_name(attrs, "display_roi_height", &roi_h);
4887 /* get rotation value to set */
4888 __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
4890 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
4891 "origin-size", origin_size,
4892 "rotate", rotation_value,
4897 "display-geometry-method", display_method,
4900 debug_log("set video param : method %d", display_method);
4901 debug_log("set video param : dst-roi-x: %d, dst-roi-y: %d, dst-roi-w: %d, dst-roi-h: %d",
4902 roi_x, roi_y, roi_w, roi_h );
4903 debug_log("set video param : display_evas_do_scaling %d (origin-size %d)", scaling, origin_size);
4907 case MM_DISPLAY_SURFACE_X_EXT: /* NOTE : this surface type is used for the videoTexture(canvasTexture) overlay */
4909 void *pixmap_id_cb = NULL;
4910 void *pixmap_id_cb_user_data = NULL;
4911 int display_method = 0;
4912 gboolean visible = TRUE;
4914 /* if xvimagesink */
4915 if (strcmp(player->ini.videosink_element_x,"xvimagesink"))
4917 debug_error("videosink is not xvimagesink");
4918 return MM_ERROR_PLAYER_INTERNAL;
4921 /* get information from attributes */
4922 mm_attrs_get_data_by_name(attrs, "display_overlay", &pixmap_id_cb);
4923 mm_attrs_get_data_by_name(attrs, "display_overlay_user_data", &pixmap_id_cb_user_data);
4924 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
4925 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
4929 debug_log("set video param : display_overlay(0x%x)", pixmap_id_cb);
4930 if (pixmap_id_cb_user_data)
4932 debug_log("set video param : display_overlay_user_data(0x%x)", pixmap_id_cb_user_data);
4937 debug_error("failed to set pixmap-id-callback");
4938 return MM_ERROR_PLAYER_INTERNAL;
4940 /* get rotation value to set */
4941 __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
4943 debug_log("set video param : rotate %d, method %d, visible %d", rotation_value, display_method, visible);
4945 /* set properties of videosink plugin */
4946 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
4947 "display-geometry-method", display_method,
4948 "draw-borders", FALSE,
4950 "rotate", rotation_value,
4951 "pixmap-id-callback", pixmap_id_cb,
4952 "pixmap-id-callback-userdata", pixmap_id_cb_user_data,
4956 case MM_DISPLAY_SURFACE_NULL:
4965 return MM_ERROR_NONE;
4969 __mmplayer_gst_element_link_bucket(GList* element_bucket) // @
4971 GList* bucket = element_bucket;
4972 MMPlayerGstElement* element = NULL;
4973 MMPlayerGstElement* prv_element = NULL;
4974 gint successful_link_count = 0;
4978 return_val_if_fail(element_bucket, -1);
4980 prv_element = (MMPlayerGstElement*)bucket->data;
4981 bucket = bucket->next;
4983 for ( ; bucket; bucket = bucket->next )
4985 element = (MMPlayerGstElement*)bucket->data;
4987 if ( element && element->gst )
4989 /* If next element is audio appsrc then make a seprate audio pipeline */
4990 if (!strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),"audio_appsrc") ||
4991 !strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),"subtitle_appsrc"))
4993 prv_element = element;
4997 if ( GST_ELEMENT_LINK(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst)) )
4999 debug_log("linking [%s] to [%s] success\n",
5000 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
5001 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)) );
5002 successful_link_count ++;
5006 debug_log("linking [%s] to [%s] failed\n",
5007 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
5008 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)) );
5013 prv_element = element;
5018 return successful_link_count;
5022 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket) // @
5024 GList* bucket = element_bucket;
5025 MMPlayerGstElement* element = NULL;
5026 int successful_add_count = 0;
5030 return_val_if_fail(element_bucket, 0);
5031 return_val_if_fail(bin, 0);
5033 for ( ; bucket; bucket = bucket->next )
5035 element = (MMPlayerGstElement*)bucket->data;
5037 if ( element && element->gst )
5039 if( !gst_bin_add(bin, GST_ELEMENT(element->gst)) )
5041 debug_log("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed\n",
5042 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
5043 GST_ELEMENT_NAME(GST_ELEMENT(bin) ) );
5046 successful_add_count ++;
5052 return successful_add_count;
5055 static void __mmplayer_gst_caps_notify_cb (GstPad * pad, GParamSpec * unused, gpointer data)
5057 mm_player_t* player = (mm_player_t*) data;
5058 GstCaps *caps = NULL;
5059 GstStructure *str = NULL;
5064 return_if_fail ( pad )
5065 return_if_fail ( unused )
5066 return_if_fail ( data )
5068 caps = gst_pad_query_caps(pad, NULL);
5074 str = gst_caps_get_structure(caps, 0);
5080 name = gst_structure_get_name(str);
5086 debug_log("name = %s\n", name);
5088 if (strstr(name, "audio"))
5090 _mmplayer_update_content_attrs (player, ATTR_AUDIO);
5092 if (player->audio_stream_changed_cb)
5094 debug_error("call the audio stream changed cb\n");
5095 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
5098 else if (strstr(name, "video"))
5100 _mmplayer_update_content_attrs (player, ATTR_VIDEO);
5102 if (player->video_stream_changed_cb)
5104 debug_error("call the video stream changed cb\n");
5105 player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
5115 gst_caps_unref(caps);
5125 * This function is to create audio pipeline for playing.
5127 * @param player [in] handle of player
5129 * @return This function returns zero on success.
5131 * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_pipeline
5133 #define MMPLAYER_CREATEONLY_ELEMENT(x_bin, x_id, x_factory, x_name) \
5134 x_bin[x_id].id = x_id;\
5135 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
5136 if ( ! x_bin[x_id].gst )\
5138 debug_error("failed to create %s \n", x_factory);\
5142 #define MMPLAYER_CREATE_ELEMENT_ADD_BIN(x_bin, x_id, x_factory, x_name, y_bin, x_player) \
5143 x_bin[x_id].id = x_id;\
5144 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
5145 if ( ! x_bin[x_id].gst )\
5147 debug_error("failed to create %s \n", x_factory);\
5152 if (x_player->ini.set_dump_element_flag)\
5153 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
5155 if( !gst_bin_add(GST_BIN(y_bin), GST_ELEMENT(x_bin[x_id].gst)))\
5157 debug_log("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed\n",\
5158 GST_ELEMENT_NAME(GST_ELEMENT(x_bin[x_id].gst)),\
5159 GST_ELEMENT_NAME(GST_ELEMENT(y_bin) ) );\
5163 /* macro for code readability. just for sinkbin-creation functions */
5164 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
5167 x_bin[x_id].id = x_id;\
5168 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
5169 if ( ! x_bin[x_id].gst )\
5171 debug_error("failed to create %s \n", x_factory);\
5176 if (x_player->ini.set_dump_element_flag)\
5177 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
5179 if ( x_add_bucket )\
5180 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
5184 __mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5186 mm_player_t* player = (mm_player_t*) data;
5191 gint endianness = 0;
5192 guint64 channel_mask = 0;
5194 MMPlayerAudioStreamDataType audio_stream = { 0, };
5195 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5198 return_if_fail(player->audio_stream_render_cb_ex);
5200 debug_log ("__mmplayer_audio_stream_decoded_render_cb new pad: %s", GST_PAD_NAME (pad));
5202 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
5203 audio_stream.data = mapinfo.data;
5204 audio_stream.data_size = mapinfo.size;
5206 GstCaps *caps = gst_pad_get_current_caps( pad );
5207 GstStructure *structure = gst_caps_get_structure (caps, 0);
5209 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
5210 gst_structure_get_int (structure, "rate", &rate);
5211 gst_structure_get_int (structure, "channels", &channel);
5212 gst_structure_get_int (structure, "depth", &depth);
5213 gst_structure_get_int (structure, "endianness", &endianness);
5214 gst_structure_get (structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
5216 gst_caps_unref(GST_CAPS(caps));
5218 audio_stream.bitrate = rate;
5219 audio_stream.channel = channel;
5220 audio_stream.depth = depth;
5221 audio_stream.is_little_endian = (endianness == 1234 ? 1 : 0);
5222 audio_stream.channel_mask = channel_mask;
5223 debug_log ("bitrate : %d channel : %d depth: %d ls_little_endian : %d channel_mask: %d, %p", rate, channel, depth, endianness, channel_mask, player->audio_stream_cb_user_param);
5224 player->audio_stream_render_cb_ex(&audio_stream, player->audio_stream_cb_user_param);
5225 gst_buffer_unmap(buffer, &mapinfo);
5231 __mmplayer_gst_audio_deinterleave_pad_added (GstElement *elem, GstPad *pad, gpointer data)
5233 mm_player_t* player = (mm_player_t*)data;
5234 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
5235 GstPad* sinkpad = NULL;
5236 GstElement *queue = NULL, *sink = NULL;
5239 return_if_fail (player && player->pipeline && player->pipeline->mainbin);
5241 queue = gst_element_factory_make ("queue", NULL);
5244 debug_log ("fail make queue\n");
5248 sink = gst_element_factory_make ("fakesink", NULL);
5251 debug_log ("fail make fakesink\n");
5255 gst_bin_add_many (GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
5257 if (!gst_element_link_pads_full (queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING))
5259 debug_warning("failed to link queue & sink\n");
5263 sinkpad = gst_element_get_static_pad (queue, "sink");
5265 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad))
5267 debug_warning ("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad));
5271 debug_error("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync);
5273 gst_object_unref (sinkpad);
5274 g_object_set (sink, "sync", player->audio_stream_sink_sync, NULL);
5275 g_object_set (sink, "signal-handoffs", TRUE, NULL);
5277 gst_element_set_state (sink, GST_STATE_PAUSED);
5278 gst_element_set_state (queue, GST_STATE_PAUSED);
5280 MMPLAYER_SIGNAL_CONNECT( player,
5282 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
5284 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
5291 debug_error("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n");
5294 gst_object_unref(GST_OBJECT(queue));
5299 gst_object_unref(GST_OBJECT(sink));
5304 gst_object_unref ( GST_OBJECT(sinkpad) );
5311 void __mmplayer_gst_set_audiosink_property(mm_player_t* player, MMHandleType attrs)
5313 #define MAX_PROPS_LEN 64
5314 gint volume_type = 0;
5315 gint latency_mode = 0;
5316 gchar *stream_type = NULL;
5318 gchar stream_props[MAX_PROPS_LEN] = {0,};
5319 GstStructure *props = NULL;
5322 * It should be set after player creation through attribute.
5323 * But, it can not be changed during playing.
5326 mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
5327 mm_attrs_get_string_by_name (attrs, "sound_stream_type", &stream_type );
5329 if ( stream_id < 1 || !stream_type || strlen(stream_type) < 1)
5331 debug_error("stream_id[%d] or stream_type[%s] is not valid.\n", stream_id, stream_type);
5335 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d", stream_type, stream_id);
5336 props = gst_structure_from_string(stream_props, NULL);
5337 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
5338 debug_log("stream_id[%d], stream_type[%s], result[%s].\n", stream_id, stream_type, stream_props);
5341 mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
5342 mm_attrs_get_int_by_name(attrs, "sound_volume_type", &volume_type);
5344 /* hook sound_type if emergency case */
5345 if (player->sm.event == ASM_EVENT_EMERGENCY)
5347 debug_log ("emergency session, hook sound_type from [%d] to [%d]\n", volume_type, MM_SOUND_VOLUME_TYPE_EMERGENCY);
5348 volume_type = MM_SOUND_VOLUME_TYPE_EMERGENCY;
5351 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
5352 "latency", latency_mode,
5353 "volumetype", volume_type,
5356 debug_log("audiosink property - volume type=%d, latency=%d \n",
5357 volume_type, latency_mode);
5363 __mmplayer_gst_create_audio_pipeline(mm_player_t* player)
5365 MMPlayerGstElement* first_element = NULL;
5366 MMPlayerGstElement* audiobin = NULL;
5367 MMHandleType attrs = 0;
5369 GstPad *ghostpad = NULL;
5370 GList* element_bucket = NULL;
5371 gboolean link_audio_sink_now = TRUE;
5376 return_val_if_fail( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
5379 audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
5382 debug_error("failed to allocate memory for audiobin\n");
5383 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5386 attrs = MMPLAYER_GET_ATTRS(player);
5389 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
5390 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
5391 if ( !audiobin[MMPLAYER_A_BIN].gst )
5393 debug_error("failed to create audiobin\n");
5398 player->pipeline->audiobin = audiobin;
5400 player->set_mode.pcm_extraction = __mmplayer_can_extract_pcm(player);
5402 /* Adding audiotp plugin for reverse trickplay feature */
5403 // MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TP, "audiotp", "audio trickplay", TRUE, player);
5406 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
5409 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.name_of_audio_resampler, "audio resampler", TRUE, player);
5411 if (player->set_mode.pcm_extraction) // pcm extraction only and no sound output
5413 if(player->audio_stream_render_cb_ex)
5415 char *caps_str = NULL;
5416 GstCaps* caps = NULL;
5417 gchar *format = NULL;
5420 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
5422 mm_attrs_get_string_by_name (player->attrs, "pcm_audioformat", &format );
5424 debug_log("contents : format: %s samplerate : %d pcm_channel: %d", format, player->pcm_samplerate, player->pcm_channel);
5426 caps = gst_caps_new_simple ("audio/x-raw",
5427 "format", G_TYPE_STRING, format,
5428 "rate", G_TYPE_INT, player->pcm_samplerate,
5429 "channels", G_TYPE_INT, player->pcm_channel,
5431 caps_str = gst_caps_to_string(caps);
5432 debug_log("new caps : %s\n", caps_str);
5434 g_object_set (GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL );
5437 gst_caps_unref( caps );
5438 MMPLAYER_FREEIF( caps_str );
5440 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
5442 g_object_set (G_OBJECT (audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
5443 /* raw pad handling signal */
5444 MMPLAYER_SIGNAL_CONNECT( player,
5445 (audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
5446 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5447 G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), player);
5451 int dst_samplerate = 0;
5452 int dst_channels = 0;
5454 char *caps_str = NULL;
5455 GstCaps* caps = NULL;
5457 /* get conf. values */
5458 mm_attrs_multiple_get(player->attrs,
5460 "pcm_extraction_samplerate", &dst_samplerate,
5461 "pcm_extraction_channels", &dst_channels,
5462 "pcm_extraction_depth", &dst_depth,
5466 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
5467 caps = gst_caps_new_simple ("audio/x-raw",
5468 "rate", G_TYPE_INT, dst_samplerate,
5469 "channels", G_TYPE_INT, dst_channels,
5470 "depth", G_TYPE_INT, dst_depth,
5472 caps_str = gst_caps_to_string(caps);
5473 debug_log("new caps : %s\n", caps_str);
5475 g_object_set (GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL );
5478 gst_caps_unref( caps );
5479 MMPLAYER_FREEIF( caps_str );
5482 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "fakesink", TRUE, player);
5485 g_object_set (G_OBJECT (audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL);
5488 else // normal playback
5490 //GstCaps* caps = NULL;
5493 /* for logical volume control */
5494 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
5495 g_object_set(G_OBJECT (audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
5497 if (player->sound.mute)
5499 debug_log("mute enabled\n");
5500 g_object_set(G_OBJECT (audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
5505 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE, player);
5506 caps = gst_caps_from_string( "audio/x-raw-int, "
5507 "endianness = (int) LITTLE_ENDIAN, "
5508 "signed = (boolean) true, "
5509 "width = (int) 16, "
5510 "depth = (int) 16" );
5511 g_object_set (GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL );
5512 gst_caps_unref( caps );
5515 /* chech if multi-chennels */
5516 if (player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)
5518 GstPad *srcpad = NULL;
5519 GstCaps *caps = NULL;
5521 if ((srcpad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "src")))
5523 if ((caps = gst_pad_query_caps(srcpad, NULL)))
5525 //MMPLAYER_LOG_GST_CAPS_TYPE(caps);
5526 GstStructure *str = gst_caps_get_structure(caps, 0);
5528 gst_structure_get_int (str, "channels", &channels);
5529 gst_caps_unref(caps);
5531 gst_object_unref(srcpad);
5535 /* audio effect element. if audio effect is enabled */
5536 if ( (strcmp(player->ini.name_of_audio_effect, ""))
5538 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom) )
5540 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.name_of_audio_effect, "audio effect filter", TRUE, player);
5542 debug_log("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
5544 if ( (!player->bypass_audio_effect)
5545 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom) )
5547 if ( MM_AUDIO_EFFECT_TYPE_CUSTOM == player->audio_effect_info.effect_type )
5549 if (!_mmplayer_audio_effect_custom_apply(player))
5551 debug_msg("apply audio effect(custom) setting success\n");
5556 if ( (strcmp(player->ini.name_of_audio_effect_sec, ""))
5557 && (player->set_mode.rich_audio) )
5559 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.name_of_audio_effect_sec, "audio effect filter", TRUE, player);
5562 if (!MMPLAYER_IS_RTSP_STREAMING(player))
5564 if (player->set_mode.rich_audio && channels <= 2)
5565 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VSP, "audiovsp", "x-speed", TRUE, player);
5568 /* create audio sink */
5569 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.name_of_audiosink, "audiosink", link_audio_sink_now, player);
5572 g_object_set (G_OBJECT (audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
5573 g_object_set (G_OBJECT (audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
5575 /* FIXIT : using system clock. isn't there another way? */
5576 if (player->videodec_linked)
5578 debug_log("provide clock for movie = %s", (player->ini.provide_clock_for_movie)?"audio_clock":"sys_clock");
5579 g_object_set (G_OBJECT (audiobin[MMPLAYER_A_SINK].gst), "provide-clock", player->ini.provide_clock_for_movie, NULL);
5583 debug_log("provide clock for music = %s", (player->ini.provide_clock_for_music)?"audio_clock":"sys_clock");
5584 g_object_set (G_OBJECT (audiobin[MMPLAYER_A_SINK].gst), "provide-clock", player->ini.provide_clock_for_music, NULL);
5587 if (g_strrstr(player->ini.name_of_audiosink, "pulsesink"))
5588 __mmplayer_gst_set_audiosink_property(player, attrs);
5590 /* Antishock can be enabled when player is resumed by soundCM.
5591 * But, it's not used in MMS, setting and etc.
5592 * Because, player start seems like late.
5594 __mmplayer_set_antishock( player , FALSE );
5597 if (audiobin[MMPLAYER_A_SINK].gst)
5599 GstPad *sink_pad = NULL;
5600 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
5601 MMPLAYER_SIGNAL_CONNECT (player, sink_pad, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
5602 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
5603 gst_object_unref (GST_OBJECT(sink_pad));
5606 __mmplayer_add_sink( player, audiobin[MMPLAYER_A_SINK].gst );
5608 /* adding created elements to bin */
5609 debug_log("adding created elements to bin\n");
5610 if( !__mmplayer_gst_element_add_bucket_to_bin( GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket ))
5612 debug_error("failed to add elements\n");
5616 /* linking elements in the bucket by added order. */
5617 debug_log("Linking elements in the bucket by added order.\n");
5618 if ( __mmplayer_gst_element_link_bucket(element_bucket) == -1 )
5620 debug_error("failed to link elements\n");
5624 /* get first element's sinkpad for creating ghostpad */
5625 first_element = (MMPlayerGstElement *)element_bucket->data;
5627 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
5630 debug_error("failed to get pad from first element of audiobin\n");
5634 ghostpad = gst_ghost_pad_new("sink", pad);
5637 debug_error("failed to create ghostpad\n");
5641 if ( FALSE == gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad) )
5643 debug_error("failed to add ghostpad to audiobin\n");
5647 player->gapless.audio_data_probe_id = gst_pad_add_probe(ghostpad, GST_PAD_PROBE_TYPE_BUFFER,
5648 __mmplayer_audio_data_probe, player, NULL);
5650 gst_object_unref(pad);
5652 g_list_free(element_bucket);
5654 mm_attrs_set_int_by_name(attrs, "content_audio_found", TRUE);
5658 return MM_ERROR_NONE;
5662 debug_log("ERROR : releasing audiobin\n");
5665 gst_object_unref(GST_OBJECT(pad));
5668 gst_object_unref(GST_OBJECT(ghostpad));
5670 g_list_free( element_bucket );
5672 /* release element which are not added to bin */
5673 for ( i = 1; i < MMPLAYER_A_NUM; i++ ) /* NOTE : skip bin */
5675 if ( audiobin[i].gst )
5677 GstObject* parent = NULL;
5678 parent = gst_element_get_parent( audiobin[i].gst );
5682 gst_object_unref(GST_OBJECT(audiobin[i].gst));
5683 audiobin[i].gst = NULL;
5687 gst_object_unref(GST_OBJECT(parent));
5692 /* release audiobin with it's childs */
5693 if ( audiobin[MMPLAYER_A_BIN].gst )
5695 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
5698 MMPLAYER_FREEIF( audiobin );
5700 player->pipeline->audiobin = NULL;
5702 return MM_ERROR_PLAYER_INTERNAL;
5705 static GstPadProbeReturn
5706 __mmplayer_audio_stream_probe (GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
5708 mm_player_t* player = (mm_player_t*) u_data;
5709 GstBuffer *pad_buffer = gst_pad_probe_info_get_buffer(info);
5710 GstMapInfo probe_info = GST_MAP_INFO_INIT;
5712 gst_buffer_map(pad_buffer, &probe_info, GST_MAP_READ);
5714 if (player->audio_stream_cb && probe_info.size && probe_info.data)
5715 player->audio_stream_cb((void *)probe_info.data, probe_info.size, player->audio_stream_cb_user_param);
5717 return GST_PAD_PROBE_OK;
5720 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
5722 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
5725 static GstPadProbeReturn
5726 __mmplayer_video_stream_probe (GstPad *pad, GstPadProbeInfo *info, gpointer user_data)
5728 GstCaps *caps = NULL;
5729 MMPlayerVideoStreamDataType stream;
5730 MMVideoBuffer *video_buffer = NULL;
5731 GstMemory *dataBlock = NULL;
5732 GstMemory *metaBlock = NULL;
5733 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5734 GstStructure *structure = NULL;
5735 const gchar *string_format = NULL;
5736 unsigned int fourcc = 0;
5737 mm_player_t* player = (mm_player_t*)user_data;
5738 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
5740 return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
5741 return_val_if_fail(gst_buffer_n_memory(buffer) , GST_PAD_PROBE_DROP);
5743 caps = gst_pad_get_current_caps(pad);
5745 debug_error( "Caps is NULL." );
5746 return GST_PAD_PROBE_OK;
5749 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
5751 /* clear stream data structure */
5752 memset(&stream, 0x0, sizeof(MMPlayerVideoStreamDataType));
5754 structure = gst_caps_get_structure( caps, 0 );
5755 gst_structure_get_int(structure, "width", &(stream.width));
5756 gst_structure_get_int(structure, "height", &(stream.height));
5757 string_format = gst_structure_get_string(structure, "format");
5759 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
5761 stream.format = util_get_pixtype(fourcc);
5762 gst_caps_unref( caps );
5766 debug_log( "Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
5767 GST_BUFFER_DATA(buffer), stream.width, stream.height, stream.format );
5770 if (stream.width == 0 || stream.height == 0 || stream.format == MM_PIXEL_FORMAT_INVALID) {
5771 debug_error("Wrong condition!!");
5775 /* set size and timestamp */
5776 dataBlock = gst_buffer_peek_memory(buffer, 0);
5777 stream.length_total = gst_memory_get_sizes(dataBlock, NULL, NULL);
5778 stream.timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/1000000); /* nano sec -> mili sec */
5780 /* check zero-copy */
5781 if (player->set_mode.video_zc &&
5782 player->set_mode.media_packet_video_stream &&
5783 gst_buffer_n_memory(buffer) > 1) {
5784 metaBlock = gst_buffer_peek_memory(buffer, 1);
5785 gst_memory_map(metaBlock, &mapinfo, GST_MAP_READ);
5786 video_buffer = (MMVideoBuffer *)mapinfo.data;
5791 if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
5792 /* copy pointer of tbm bo, stride, elevation */
5793 memcpy(stream.bo, video_buffer->handle.bo,
5794 sizeof(void *) * MM_VIDEO_BUFFER_PLANE_MAX);
5796 else if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_PHYSICAL_ADDRESS) {
5797 memcpy(stream.data, video_buffer->data,
5798 sizeof(void *) * MM_VIDEO_BUFFER_PLANE_MAX);
5800 memcpy(stream.stride, video_buffer->stride_width,
5801 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5802 memcpy(stream.elevation, video_buffer->stride_height,
5803 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5804 /* set gst buffer */
5805 stream.internal_buffer = buffer;
5807 tbm_bo_handle thandle;
5808 int stride = ((stream.width + 3) & (~3));
5809 int elevation = stream.height;
5810 int size = stride * elevation * 3 / 2;
5812 gst_ret = gst_memory_map(dataBlock, &mapinfo, GST_MAP_READWRITE);
5814 debug_error("fail to gst_memory_map");
5815 return GST_PAD_PROBE_OK;
5818 stream.stride[0] = stride;
5819 stream.elevation[0] = elevation;
5820 if(stream.format == MM_PIXEL_FORMAT_I420) {
5821 stream.stride[1] = stream.stride[2] = stride / 2;
5822 stream.elevation[1] = stream.elevation[2] = elevation / 2;
5825 debug_error("default #plane is 2, format %d", stream.format);
5826 stream.stride[1] = stride;
5827 stream.elevation[1] = elevation / 2;
5830 stream.bo[0] = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
5832 debug_error("Fail to tbm_bo_alloc!!");
5835 thandle = tbm_bo_map(stream.bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
5836 if(thandle.ptr && mapinfo.data)
5837 memcpy(thandle.ptr, mapinfo.data, size);
5839 debug_error("data pointer is wrong. dest : %p, src : %p",
5840 thandle.ptr, mapinfo.data);
5842 tbm_bo_unmap(stream.bo[0]);
5846 if (player->video_stream_cb) {
5847 player->video_stream_cb(&stream, player->video_stream_cb_user_param);
5851 gst_memory_unmap(metaBlock, &mapinfo);
5853 gst_memory_unmap(dataBlock, &mapinfo);
5854 tbm_bo_unref(stream.bo[0]);
5857 return GST_PAD_PROBE_OK;
5861 __mmplayer_gst_create_video_filters(mm_player_t* player, GList** bucket, gboolean use_video_stream)
5863 gchar* video_csc = "videoconvert"; // default colorspace converter
5864 GList* element_bucket = *bucket;
5866 return_val_if_fail(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5870 if (!player->set_mode.media_packet_video_stream && use_video_stream)
5872 if (player->set_mode.video_zc && strlen(player->ini.name_of_video_converter) > 0)
5874 video_csc = player->ini.name_of_video_converter;
5877 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
5878 debug_log("using video converter: %s", video_csc);
5880 if ( !player->set_mode.video_zc)
5882 gint width = 0; //width of video
5883 gint height = 0; //height of video
5884 GstCaps* video_caps = NULL;
5885 GstStructure *structure = NULL;
5887 /* rotator, scaler and capsfilter */
5888 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
5889 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_SCALE, "videoscale", "video scaler", TRUE, player);
5890 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CAPS, "capsfilter", "videocapsfilter", TRUE, player);
5892 /* get video stream caps parsed by demuxer */
5894 mm_attrs_get_int_by_name(player->attrs, "display_width", &width);
5897 structure = gst_structure_new("video/x-raw", "width", G_TYPE_INT, width, NULL);
5899 mm_attrs_get_int_by_name(player->attrs, "display_height", &height);
5901 if(structure && height) {
5902 gst_structure_set (structure, "height", G_TYPE_INT, height, NULL);
5904 video_caps = gst_caps_new_full(structure, NULL);
5905 g_object_set (GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_CAPS].gst), "caps", video_caps, NULL );
5906 MMPLAYER_LOG_GST_CAPS_TYPE(video_caps);
5907 gst_caps_unref(video_caps);
5910 debug_error("fail to set capsfilter %p, width %d, height %d", structure, width, height);
5913 gst_structure_free(structure);
5919 MMDisplaySurfaceType surface_type = MM_DISPLAY_SURFACE_NULL;
5920 mm_attrs_get_int_by_name (player->attrs, "display_surface_type", (int *)&surface_type);
5922 if (player->set_mode.video_zc)
5924 if ( (surface_type == MM_DISPLAY_SURFACE_EVAS) && ( !strcmp(player->ini.videosink_element_evas, "evasimagesink")) )
5926 video_csc = player->ini.name_of_video_converter;
5934 if (video_csc && (strcmp(video_csc, "")))
5936 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
5937 debug_log("using video converter: %s", video_csc);
5940 /* set video rotator */
5941 if ( !player->set_mode.video_zc )
5942 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
5945 #if !defined(__arm__)
5946 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_SCALE, "videoscale", "videoscaler", TRUE, player);
5950 *bucket = element_bucket;
5952 return MM_ERROR_NONE;
5957 return MM_ERROR_PLAYER_INTERNAL;
5961 * This function is to create video pipeline.
5963 * @param player [in] handle of player
5964 * caps [in] src caps of decoder
5965 * surface_type [in] surface type for video rendering
5967 * @return This function returns zero on success.
5969 * @see __mmplayer_gst_create_audio_pipeline, __mmplayer_gst_create_midi_pipeline
5973 * - x surface (arm/x86) : xvimagesink
5974 * - evas surface (arm) : evaspixmapsink
5975 * fimcconvert ! evasimagesink
5976 * - evas surface (x86) : videoconvertor ! videoflip ! evasimagesink
5979 __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
5983 GList*element_bucket = NULL;
5984 MMPlayerGstElement* first_element = NULL;
5985 MMPlayerGstElement* videobin = NULL;
5986 gchar *videosink_element = NULL;
5990 return_val_if_fail(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5993 videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
5996 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5999 player->pipeline->videobin = videobin;
6001 attrs = MMPLAYER_GET_ATTRS(player);
6004 debug_error("cannot get content attribute");
6005 return MM_ERROR_PLAYER_INTERNAL;
6009 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
6010 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
6011 if ( !videobin[MMPLAYER_V_BIN].gst )
6013 debug_error("failed to create videobin");
6017 if( player->use_video_stream ) // video stream callback, so send raw video data to application
6019 debug_log("using memsink\n");
6021 if ( __mmplayer_gst_create_video_filters(player, &element_bucket, TRUE) != MM_ERROR_NONE)
6024 /* finally, create video sink. output will be BGRA8888. */
6025 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, "avsysmemsink", "videosink", TRUE, player);
6027 MMPLAYER_SIGNAL_CONNECT( player,
6028 videobin[MMPLAYER_V_SINK].gst,
6029 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
6031 G_CALLBACK(__mmplayer_videostream_cb),
6034 else // render video data using sink plugin like xvimagesink
6036 if ( __mmplayer_gst_create_video_filters(player, &element_bucket, FALSE) != MM_ERROR_NONE)
6039 /* set video sink */
6040 switch (surface_type)
6042 case MM_DISPLAY_SURFACE_X:
6043 if (strlen(player->ini.videosink_element_x) > 0)
6044 videosink_element = player->ini.videosink_element_x;
6048 case MM_DISPLAY_SURFACE_EVAS:
6049 if (strlen(player->ini.videosink_element_evas) > 0)
6050 videosink_element = player->ini.videosink_element_evas;
6054 case MM_DISPLAY_SURFACE_X_EXT:
6056 void *pixmap_id_cb = NULL;
6057 mm_attrs_get_data_by_name(attrs, "display_overlay", &pixmap_id_cb);
6058 if (pixmap_id_cb) /* this is used for the videoTextue(canvasTexture) overlay */
6060 videosink_element = player->ini.videosink_element_x;
6064 debug_error("something wrong.. callback function for getting pixmap id is null");
6069 case MM_DISPLAY_SURFACE_NULL:
6070 if (strlen(player->ini.videosink_element_fake) > 0)
6071 videosink_element = player->ini.videosink_element_fake;
6076 debug_error("unidentified surface type");
6080 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_element, videosink_element, TRUE, player);
6081 debug_log("selected videosink name: %s", videosink_element);
6083 /* connect signal handlers for sink plug-in */
6084 switch (surface_type) {
6085 case MM_DISPLAY_SURFACE_X_EXT:
6086 MMPLAYER_SIGNAL_CONNECT( player,
6087 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
6088 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
6089 "frame-render-error",
6090 G_CALLBACK(__mmplayer_videoframe_render_error_cb),
6092 debug_log("videoTexture usage, connect a signal handler for pixmap rendering error");
6099 if (_mmplayer_update_video_param(player) != MM_ERROR_NONE)
6102 if (videobin[MMPLAYER_V_SINK].gst)
6104 GstPad *sink_pad = NULL;
6105 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
6108 MMPLAYER_SIGNAL_CONNECT (player, sink_pad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
6109 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
6110 gst_object_unref (GST_OBJECT(sink_pad));
6114 debug_warning("failed to get sink pad from videosink\n");
6118 /* store it as it's sink element */
6119 __mmplayer_add_sink( player, videobin[MMPLAYER_V_SINK].gst );
6121 /* adding created elements to bin */
6122 if( ! __mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket) )
6124 debug_error("failed to add elements\n");
6128 /* Linking elements in the bucket by added order */
6129 if ( __mmplayer_gst_element_link_bucket(element_bucket) == -1 )
6131 debug_error("failed to link elements\n");
6135 /* get first element's sinkpad for creating ghostpad */
6136 first_element = (MMPlayerGstElement *)element_bucket->data;
6137 if ( !first_element )
6139 debug_error("failed to get first element from bucket\n");
6143 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
6146 debug_error("failed to get pad from first element\n");
6150 /* create ghostpad */
6151 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
6152 if ( FALSE == gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin) )
6154 debug_error("failed to add ghostpad to videobin\n");
6157 gst_object_unref(pad);
6159 /* done. free allocated variables */
6160 g_list_free(element_bucket);
6162 mm_attrs_set_int_by_name(attrs, "content_video_found", TRUE);
6166 return MM_ERROR_NONE;
6169 debug_error("ERROR : releasing videobin\n");
6171 g_list_free( element_bucket );
6174 gst_object_unref(GST_OBJECT(pad));
6176 /* release videobin with it's childs */
6177 if ( videobin[MMPLAYER_V_BIN].gst )
6179 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
6183 MMPLAYER_FREEIF( videobin );
6185 player->pipeline->videobin = NULL;
6187 return MM_ERROR_PLAYER_INTERNAL;
6190 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
6192 GList *element_bucket = NULL;
6193 MMPlayerGstElement *textbin = player->pipeline->textbin;
6195 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
6196 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
6197 g_object_set (G_OBJECT (textbin[MMPLAYER_T_IDENTITY].gst),
6198 "signal-handoffs", FALSE,
6201 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
6202 MMPLAYER_SIGNAL_CONNECT( player,
6203 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
6204 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
6206 G_CALLBACK(__mmplayer_update_subtitle),
6209 g_object_set (G_OBJECT (textbin[MMPLAYER_T_FAKE_SINK].gst), "async", TRUE, NULL);
6210 g_object_set (G_OBJECT (textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE, NULL);
6211 g_object_set (G_OBJECT (textbin[MMPLAYER_T_FAKE_SINK].gst), "signal-handoffs", TRUE, NULL);
6213 if (!player->play_subtitle)
6215 debug_log ("add textbin sink as sink element of whole pipeline.\n");
6216 __mmplayer_add_sink (player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
6219 /* adding created elements to bin */
6220 debug_log("adding created elements to bin\n");
6221 if( !__mmplayer_gst_element_add_bucket_to_bin( GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket ))
6223 debug_error("failed to add elements\n");
6227 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
6228 GST_OBJECT_FLAG_UNSET (textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
6229 GST_OBJECT_FLAG_UNSET (textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
6231 /* linking elements in the bucket by added order. */
6232 debug_log("Linking elements in the bucket by added order.\n");
6233 if ( __mmplayer_gst_element_link_bucket(element_bucket) == -1 )
6235 debug_error("failed to link elements\n");
6239 /* done. free allocated variables */
6240 g_list_free(element_bucket);
6242 if (textbin[MMPLAYER_T_QUEUE].gst)
6245 GstPad *ghostpad = NULL;
6247 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
6250 debug_error("failed to get video pad of textbin\n");
6251 return MM_ERROR_PLAYER_INTERNAL;
6254 ghostpad = gst_ghost_pad_new("text_sink", pad);
6255 gst_object_unref(pad);
6259 debug_error("failed to create ghostpad of textbin\n");
6263 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad))
6265 debug_error("failed to add ghostpad to textbin\n");
6270 return MM_ERROR_NONE;
6273 g_list_free(element_bucket);
6275 return MM_ERROR_PLAYER_INTERNAL;
6278 static int __mmplayer_gst_create_text_pipeline(mm_player_t* player)
6280 MMPlayerGstElement *textbin = NULL;
6281 GList *element_bucket = NULL;
6286 return_val_if_fail( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
6289 textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
6292 debug_error("failed to allocate memory for textbin\n");
6293 return MM_ERROR_PLAYER_NO_FREE_SPACE;
6297 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
6298 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
6299 if ( !textbin[MMPLAYER_T_BIN].gst )
6301 debug_error("failed to create textbin\n");
6306 player->pipeline->textbin = textbin;
6309 if (player->use_textoverlay)
6311 debug_log ("use textoverlay for displaying \n");
6313 MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_QUEUE, "queue", "text_t_queue", textbin[MMPLAYER_T_BIN].gst, player);
6315 MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_VIDEO_QUEUE, "queue", "text_v_queue", textbin[MMPLAYER_T_BIN].gst, player);
6317 MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_VIDEO_CONVERTER, "fimcconvert", "text_v_converter", textbin[MMPLAYER_T_BIN].gst, player);
6319 MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_OVERLAY, "textoverlay", "text_overlay", textbin[MMPLAYER_T_BIN].gst, player);
6321 if (!gst_element_link_pads (textbin[MMPLAYER_T_VIDEO_QUEUE].gst, "src", textbin[MMPLAYER_T_VIDEO_CONVERTER].gst, "sink"))
6323 debug_error("failed to link queue and converter\n");
6327 if (!gst_element_link_pads (textbin[MMPLAYER_T_VIDEO_CONVERTER].gst, "src", textbin[MMPLAYER_T_OVERLAY].gst, "video_sink"))
6329 debug_error("failed to link queue and textoverlay\n");
6333 if (!gst_element_link_pads (textbin[MMPLAYER_T_QUEUE].gst, "src", textbin[MMPLAYER_T_OVERLAY].gst, "text_sink"))
6335 debug_error("failed to link queue and textoverlay\n");
6341 int surface_type = 0;
6343 debug_log ("use subtitle message for displaying \n");
6345 mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &surface_type);
6347 switch(surface_type)
6349 case MM_DISPLAY_SURFACE_X:
6350 case MM_DISPLAY_SURFACE_EVAS:
6351 case MM_DISPLAY_SURFACE_GL:
6352 case MM_DISPLAY_SURFACE_NULL:
6353 case MM_DISPLAY_SURFACE_X_EXT:
6354 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE)
6356 debug_error("failed to make plain text elements\n");
6368 return MM_ERROR_NONE;
6372 debug_log("ERROR : releasing textbin\n");
6374 g_list_free( element_bucket );
6376 /* release element which are not added to bin */
6377 for ( i = 1; i < MMPLAYER_T_NUM; i++ ) /* NOTE : skip bin */
6379 if ( textbin[i].gst )
6381 GstObject* parent = NULL;
6382 parent = gst_element_get_parent( textbin[i].gst );
6386 gst_object_unref(GST_OBJECT(textbin[i].gst));
6387 textbin[i].gst = NULL;
6391 gst_object_unref(GST_OBJECT(parent));
6396 /* release textbin with it's childs */
6397 if ( textbin[MMPLAYER_T_BIN].gst )
6399 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
6402 MMPLAYER_FREEIF( textbin );
6404 player->pipeline->textbin = NULL;
6406 return MM_ERROR_PLAYER_INTERNAL;
6411 __mmplayer_gst_create_subtitle_src(mm_player_t* player)
6413 MMPlayerGstElement* mainbin = NULL;
6414 MMHandleType attrs = 0;
6415 GstElement *subsrc = NULL;
6416 GstElement *subparse = NULL;
6417 gchar *subtitle_uri =NULL;
6418 const gchar *charset = NULL;
6424 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6426 mainbin = player->pipeline->mainbin;
6428 attrs = MMPLAYER_GET_ATTRS(player);
6431 debug_error("cannot get content attribute\n");
6432 return MM_ERROR_PLAYER_INTERNAL;
6435 mm_attrs_get_string_by_name ( attrs, "subtitle_uri", &subtitle_uri );
6436 if ( !subtitle_uri || strlen(subtitle_uri) < 1)
6438 debug_error("subtitle uri is not proper filepath.\n");
6439 return MM_ERROR_PLAYER_INVALID_URI;
6441 debug_log("subtitle file path is [%s].\n", subtitle_uri);
6444 /* create the subtitle source */
6445 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
6448 debug_error ( "failed to create filesrc element\n" );
6451 g_object_set(G_OBJECT (subsrc), "location", subtitle_uri, NULL);
6453 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
6454 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
6456 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc))
6458 debug_warning("failed to add queue\n");
6463 subparse = gst_element_factory_make("subparse", "subtitle_parser");
6466 debug_error ( "failed to create subparse element\n" );
6470 charset = util_get_charset(subtitle_uri);
6473 debug_log ("detected charset is %s\n", charset );
6474 g_object_set (G_OBJECT (subparse), "subtitle-encoding", charset, NULL);
6477 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
6478 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
6480 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse))
6482 debug_warning("failed to add subparse\n");
6486 if (!gst_element_link_pads (subsrc, "src", subparse, "sink"))
6488 debug_warning("failed to link subsrc and subparse\n");
6492 player->play_subtitle = TRUE;
6493 player->adjust_subtitle_pos = 0;
6495 debug_log ("play subtitle using subtitle file\n");
6497 if (player->pipeline->textbin == NULL)
6499 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player))
6501 debug_error("failed to create textbin. continuing without text\n");
6505 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(player->pipeline->textbin[MMPLAYER_T_BIN].gst)))
6507 debug_warning("failed to add textbin\n");
6511 debug_log ("link text input selector and textbin ghost pad");
6513 player->textsink_linked = 1;
6514 player->external_text_idx = 0;
6515 debug_msg("player->textsink_linked set to 1\n");
6519 debug_log("text bin has been created. reuse it.");
6520 player->external_text_idx = 1;
6523 if (!gst_element_link_pads (subparse, "src", player->pipeline->textbin[MMPLAYER_T_BIN].gst, "text_sink"))
6525 debug_warning("failed to link subparse and textbin\n");
6529 pad = gst_element_get_static_pad (player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
6533 debug_error("failed to get sink pad from textsink to probe data");
6534 return MM_ERROR_PLAYER_INTERNAL;
6537 gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER,
6538 __mmplayer_subtitle_adjust_position_probe, player, NULL);
6540 gst_object_unref(pad);
6543 /* create dot. for debugging */
6544 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-with-subtitle" );
6547 return MM_ERROR_NONE;
6550 player->textsink_linked = 0;
6551 return MM_ERROR_PLAYER_INTERNAL;
6555 __mmplayer_update_subtitle( GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
6557 mm_player_t* player = (mm_player_t*) data;
6558 MMMessageParamType msg = {0, };
6559 GstClockTime duration = 0;
6560 gpointer text = NULL;
6561 guint text_size = 0;
6562 gboolean ret = TRUE;
6563 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
6567 return_val_if_fail ( player, FALSE );
6568 return_val_if_fail ( buffer, FALSE );
6570 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
6571 text = g_memdup(mapinfo.data, mapinfo.size);
6572 text_size = mapinfo.size;
6573 duration = GST_BUFFER_DURATION(buffer);
6576 if ( player->set_mode.subtitle_off )
6578 debug_log("subtitle is OFF.\n" );
6582 if ( !text || (text_size == 0))
6584 debug_log("There is no subtitle to be displayed.\n" );
6588 msg.data = (void *) text;
6589 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
6591 debug_log("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data );
6593 MMPLAYER_POST_MSG( player, MM_MESSAGE_UPDATE_SUBTITLE, &msg );
6594 gst_buffer_unmap(buffer, &mapinfo);
6601 static GstPadProbeReturn
6602 __mmplayer_subtitle_adjust_position_probe (GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
6605 mm_player_t *player = (mm_player_t *) u_data;
6606 GstClockTime cur_timestamp = 0;
6607 gint64 adjusted_timestamp = 0;
6608 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
6609 GstMapInfo probe_info = GST_MAP_INFO_INIT;
6611 return_val_if_fail ( player, FALSE );
6613 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
6615 if ( player->set_mode.subtitle_off )
6617 debug_log("subtitle is OFF.\n" );
6621 if (player->adjust_subtitle_pos == 0 )
6623 debug_log("nothing to do");
6627 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
6628 adjusted_timestamp = (gint64) cur_timestamp + ((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
6630 gst_buffer_unmap(buffer, &probe_info);
6632 if ( adjusted_timestamp < 0)
6634 debug_log("adjusted_timestamp under zero");
6639 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
6640 debug_log("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
6641 GST_TIME_ARGS(cur_timestamp),
6642 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
6644 return GST_PAD_PROBE_OK;
6646 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
6650 /* check player and subtitlebin are created */
6651 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
6652 return_val_if_fail ( player->play_subtitle, MM_ERROR_NOT_SUPPORT_API );
6656 debug_log ("nothing to do\n");
6658 return MM_ERROR_NONE;
6663 case MM_PLAYER_POS_FORMAT_TIME:
6665 /* check current postion */
6666 player->adjust_subtitle_pos = position;
6668 debug_log("save adjust_subtitle_pos in player") ;
6674 debug_warning("invalid format.\n");
6676 return MM_ERROR_INVALID_ARGUMENT;
6682 return MM_ERROR_NONE;
6684 static int __gst_adjust_video_position(mm_player_t* player, int offset)
6687 debug_log("adjusting video_pos in player") ;
6688 int current_pos = 0;
6689 /* check player and videobin are created */
6690 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
6691 if ( !player->pipeline->videobin ||
6692 !player->pipeline->videobin[MMPLAYER_V_SINK].gst )
6694 debug_log("no video pipeline or sink is there");
6695 return MM_ERROR_PLAYER_INVALID_STATE ;
6699 debug_log ("nothing to do\n");
6701 return MM_ERROR_NONE;
6703 if(__gst_get_position ( player, MM_PLAYER_POS_FORMAT_TIME, (unsigned long*)¤t_pos ) != MM_ERROR_NONE )
6705 debug_log("failed to get current position");
6706 return MM_ERROR_PLAYER_INTERNAL;
6708 if ( (current_pos - offset ) < GST_TIME_AS_MSECONDS(player->duration) )
6710 debug_log("enter video delay is valid");
6713 debug_log("enter video delay is crossing content boundary");
6714 return MM_ERROR_INVALID_ARGUMENT ;
6716 g_object_set (G_OBJECT (player->pipeline->videobin[MMPLAYER_V_SINK].gst),"ts-offset",((gint64) offset * G_GINT64_CONSTANT(1000000)),NULL);
6717 debug_log("video delay has been done");
6720 return MM_ERROR_NONE;
6724 __gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data) // @
6726 GstElement *appsrc = element;
6727 tBuffer *buf = (tBuffer *)user_data;
6728 GstBuffer *buffer = NULL;
6729 GstFlowReturn ret = GST_FLOW_OK;
6732 return_if_fail ( element );
6733 return_if_fail ( buf );
6735 buffer = gst_buffer_new ();
6737 if (buf->offset >= buf->len)
6739 debug_log("call eos appsrc\n");
6740 g_signal_emit_by_name (appsrc, "end-of-stream", &ret);
6744 if ( buf->len - buf->offset < size)
6746 len = buf->len - buf->offset + buf->offset;
6749 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, (guint8*)(buf->buf + buf->offset), g_free));
6750 GST_BUFFER_OFFSET(buffer) = buf->offset;
6751 GST_BUFFER_OFFSET_END(buffer) = buf->offset + len;
6753 //debug_log("feed buffer %p, offset %u-%u length %u\n", buffer, buf->offset, buf->len,len);
6754 g_signal_emit_by_name (appsrc, "push-buffer", buffer, &ret);
6760 __gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data) // @
6762 tBuffer *buf = (tBuffer *)user_data;
6764 return_val_if_fail ( buf, FALSE );
6766 buf->offset = (int)size;
6772 __gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data) // @
6774 mm_player_t *player = (mm_player_t*)user_data;
6775 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
6777 return_if_fail ( player );
6779 debug_msg("app-src: feed data\n");
6781 if (player->media_stream_buffer_status_cb[type])
6782 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, player->buffer_cb_user_param);
6786 __gst_appsrc_seek_data(GstElement *element, guint64 offset, gpointer user_data) // @
6788 mm_player_t *player = (mm_player_t*)user_data;
6789 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
6791 return_val_if_fail ( player, FALSE );
6793 debug_msg("app-src: seek data\n");
6795 if(player->media_stream_seek_data_cb[type])
6796 player->media_stream_seek_data_cb[type](type, offset, player->buffer_cb_user_param);
6803 __gst_appsrc_enough_data(GstElement *element, gpointer user_data) // @
6805 mm_player_t *player = (mm_player_t*)user_data;
6806 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
6808 return_val_if_fail ( player, FALSE );
6810 debug_msg("app-src: enough data:%p\n", player->media_stream_buffer_status_cb[type]);
6812 if (player->media_stream_buffer_status_cb[type])
6813 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, player->buffer_cb_user_param);
6819 _mmplayer_push_buffer(MMHandleType hplayer, unsigned char *buf, int size) // @
6821 mm_player_t* player = (mm_player_t*)hplayer;
6822 GstBuffer *buffer = NULL;
6823 GstFlowReturn gst_ret = GST_FLOW_OK;
6824 int ret = MM_ERROR_NONE;
6829 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6831 /* check current state */
6832 // MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_START );
6835 /* NOTE : we should check and create pipeline again if not created as we destroy
6836 * whole pipeline when stopping in streamming playback
6838 if ( ! player->pipeline )
6840 if ( MM_ERROR_NONE != __gst_realize( player ) )
6842 debug_error("failed to realize before starting. only in streamming\n");
6843 return MM_ERROR_PLAYER_INTERNAL;
6847 debug_msg("app-src: pushing data\n");
6851 debug_error("buf is null\n");
6852 return MM_ERROR_NONE;
6855 buffer = gst_buffer_new ();
6859 debug_log("call eos appsrc\n");
6860 g_signal_emit_by_name (player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "end-of-stream", &gst_ret);
6861 return MM_ERROR_NONE;
6864 //gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, (guint8*)(buf->buf + buf->offset), g_free));
6866 debug_log("feed buffer %p, length %u\n", buf, size);
6867 g_signal_emit_by_name (player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "push-buffer", buffer, &gst_ret);
6874 /* if retval is FALSE, it will be dropped for perfomance. */
6876 __mmplayer_check_useful_message(mm_player_t *player, GstMessage * message)
6878 gboolean retval = FALSE;
6880 if ( !(player->pipeline && player->pipeline->mainbin) )
6882 debug_error("player pipeline handle is null");
6886 switch (GST_MESSAGE_TYPE (message))
6888 case GST_MESSAGE_TAG:
6889 case GST_MESSAGE_EOS:
6890 case GST_MESSAGE_ERROR:
6891 case GST_MESSAGE_WARNING:
6892 case GST_MESSAGE_CLOCK_LOST:
6893 case GST_MESSAGE_NEW_CLOCK:
6894 case GST_MESSAGE_ELEMENT:
6895 case GST_MESSAGE_DURATION_CHANGED:
6896 case GST_MESSAGE_ASYNC_START:
6899 case GST_MESSAGE_ASYNC_DONE:
6900 case GST_MESSAGE_STATE_CHANGED:
6901 /* we only handle messages from pipeline */
6902 if(( message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst ) && (!player->gapless.reconfigure))
6907 case GST_MESSAGE_BUFFERING:
6909 gint buffer_percent = 0;
6911 gst_message_parse_buffering (message, &buffer_percent);
6913 if ((MMPLAYER_IS_STREAMING(player)) &&
6914 (player->streamer) &&
6915 (player->streamer->is_buffering == TRUE) &&
6916 (buffer_percent == MAX_BUFFER_PERCENT))
6918 debug_log (">>> [%s] Buffering DONE is detected !!\n", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)));
6919 player->streamer->is_buffering_done = TRUE;
6933 static GstBusSyncReply
6934 __mmplayer_bus_sync_callback (GstBus * bus, GstMessage * message, gpointer data)
6936 mm_player_t *player = (mm_player_t *)data;
6937 GstBusSyncReply reply = GST_BUS_DROP;
6939 if ( ! ( player->pipeline && player->pipeline->mainbin ) )
6941 debug_error("player pipeline handle is null");
6942 return GST_BUS_PASS;
6945 if (!__mmplayer_check_useful_message(player, message))
6947 gst_message_unref (message);
6948 return GST_BUS_DROP;
6951 switch (GST_MESSAGE_TYPE (message))
6953 case GST_MESSAGE_STATE_CHANGED:
6954 /* post directly for fast launch */
6955 if (player->sync_handler) {
6956 __mmplayer_gst_callback(NULL, message, player);
6957 reply = GST_BUS_DROP;
6960 reply = GST_BUS_PASS;
6963 case GST_MESSAGE_TAG:
6964 __mmplayer_gst_extract_tag_from_msg(player, message);
6968 GstTagList *tags = NULL;
6970 gst_message_parse_tag (message, &tags);
6972 debug_error("TAGS received from element \"%s\".\n",
6973 GST_STR_NULL (GST_ELEMENT_NAME (GST_MESSAGE_SRC (message))));
6975 gst_tag_list_foreach (tags, print_tag, NULL);
6976 gst_tag_list_free (tags);
6984 case GST_MESSAGE_DURATION_CHANGED:
6985 __mmplayer_gst_handle_duration(player, message);
6987 case GST_MESSAGE_ASYNC_DONE:
6988 /* NOTE:Don't call gst_callback directly
6989 * because previous frame can be showed even though this message is received for seek.
6992 reply = GST_BUS_PASS;
6996 if (reply == GST_BUS_DROP)
6997 gst_message_unref (message);
7003 __mmplayer_gst_create_decoder ( mm_player_t *player,
7004 MMPlayerTrackType track,
7006 enum MainElementID elemId,
7009 gboolean ret = TRUE;
7010 GstPad *sinkpad = NULL;
7014 return_val_if_fail( player &&
7016 player->pipeline->mainbin, FALSE);
7017 return_val_if_fail((track == MM_PLAYER_TRACK_TYPE_AUDIO || track == MM_PLAYER_TRACK_TYPE_VIDEO), FALSE);
7018 return_val_if_fail(srcpad, FALSE);
7019 return_val_if_fail((player->pipeline->mainbin[elemId].gst == NULL), FALSE);
7021 GstElement *decodebin = NULL;
7022 GstCaps *dec_caps = NULL;
7024 /* create decodebin */
7025 decodebin = gst_element_factory_make("decodebin", name);
7029 debug_error("error : fail to create decodebin for %d decoder\n", track);
7034 /* raw pad handling signal */
7035 MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
7036 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
7038 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
7039 before looking for any elements that can handle that stream.*/
7040 MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
7041 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
7043 /* This signal is emitted when a element is added to the bin.*/
7044 MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
7045 G_CALLBACK(__mmplayer_gst_element_added), player);
7047 if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), decodebin))
7049 debug_error("failed to add new decodebin\n");
7054 dec_caps = gst_pad_query_caps (srcpad, NULL);
7057 //debug_log ("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
7058 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
7059 gst_caps_unref(dec_caps);
7062 player->pipeline->mainbin[elemId].id = elemId;
7063 player->pipeline->mainbin[elemId].gst = decodebin;
7065 sinkpad = gst_element_get_static_pad (decodebin, "sink");
7067 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad))
7069 debug_warning ("failed to link [%s:%s] to decoder\n", GST_DEBUG_PAD_NAME(srcpad));
7070 gst_object_unref (GST_OBJECT(decodebin));
7073 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent (decodebin))
7075 debug_error("failed to sync second level decodebin state with parent\n");
7078 debug_log ("unblocking %" GST_PTR_FORMAT, srcpad);
7079 // TO CHECK : gst_pad_set_blocked_async (srcpad, FALSE, __mm_player_src_pad_block_cb, NULL);
7081 debug_log("Total num of %d tracks = %d \n", track, player->selector[track].total_track_num);
7086 gst_object_unref ( GST_OBJECT(sinkpad) );
7095 * This function is to create audio or video pipeline for playing.
7097 * @param player [in] handle of player
7099 * @return This function returns zero on success.
7104 __mmplayer_gst_create_pipeline(mm_player_t* player) // @
7107 MMPlayerGstElement *mainbin = NULL;
7108 MMHandleType attrs = 0;
7109 GstElement* element = NULL;
7110 GstElement* elem_src_audio = NULL;
7111 GstElement* elem_src_subtitle = NULL;
7112 GstElement* es_video_queue = NULL;
7113 GstElement* es_audio_queue = NULL;
7114 GstElement* es_subtitle_queue = NULL;
7115 GList* element_bucket = NULL;
7116 gboolean need_state_holder = TRUE;
7121 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7123 /* get profile attribute */
7124 attrs = MMPLAYER_GET_ATTRS(player);
7127 debug_error("cannot get content attribute\n");
7131 /* create pipeline handles */
7132 if ( player->pipeline )
7134 debug_warning("pipeline should be released before create new one\n");
7138 player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0( sizeof(MMPlayerGstPipelineInfo) );
7139 if (player->pipeline == NULL)
7142 memset( player->pipeline, 0, sizeof(MMPlayerGstPipelineInfo) );
7145 /* create mainbin */
7146 mainbin = (MMPlayerGstElement*) g_malloc0( sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM );
7147 if (mainbin == NULL)
7150 memset( mainbin, 0, sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
7152 /* create pipeline */
7153 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
7154 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
7155 if ( ! mainbin[MMPLAYER_M_PIPE].gst )
7157 debug_error("failed to create pipeline\n");
7160 player->demux_pad_index = 0;
7161 player->subtitle_language_list = NULL;
7163 player->is_subtitle_force_drop = FALSE;
7164 player->last_multiwin_status = FALSE;
7166 _mmplayer_track_initialize(player);
7168 /* create source element */
7169 switch ( player->profile.uri_type )
7171 /* rtsp streamming */
7172 case MM_PLAYER_URI_TYPE_URL_RTSP:
7174 gint network_bandwidth;
7175 gchar *user_agent, *wap_profile;
7177 element = gst_element_factory_make(player->ini.name_of_rtspsrc, "streaming_source");
7181 debug_error("failed to create streaming source element\n");
7185 debug_log("using streamming source [%s].\n", player->ini.name_of_rtspsrc);
7188 network_bandwidth = 0;
7189 user_agent = wap_profile = NULL;
7192 mm_attrs_get_string_by_name ( attrs, "streaming_user_agent", &user_agent );
7193 mm_attrs_get_string_by_name ( attrs,"streaming_wap_profile", &wap_profile );
7194 mm_attrs_get_int_by_name ( attrs, "streaming_network_bandwidth", &network_bandwidth );
7196 secure_debug_log("user_agent : %s\n", user_agent);
7197 secure_debug_log("wap_profile : %s\n", wap_profile);
7199 /* setting property to streaming source */
7200 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
7202 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
7204 g_object_set(G_OBJECT(element), "wap_profile", wap_profile, NULL);
7206 MMPLAYER_SIGNAL_CONNECT ( player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
7207 G_CALLBACK (__mmplayer_gst_rtp_dynamic_pad), player );
7208 MMPLAYER_SIGNAL_CONNECT ( player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
7209 G_CALLBACK (__mmplayer_gst_rtp_no_more_pads), player );
7211 player->use_decodebin = FALSE;
7215 /* WFD streamming */
7216 case MM_PLAYER_URI_TYPE_URL_WFD:
7218 element = gst_element_factory_make("wfdrtspsrc", "wfd_source");
7221 debug_error("failed to create wfd streaming source element\n");
7224 debug_log("using wfd streamming source wfdrtspsrc.\n");
7225 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
7226 g_object_set(G_OBJECT(element), "debug", TRUE, NULL);
7227 g_object_set(G_OBJECT(element), "latency", 0, NULL);
7228 MMPLAYER_SIGNAL_CONNECT ( player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
7229 G_CALLBACK (__mmplayer_gst_wfd_dynamic_pad), player );
7231 player->use_decodebin = FALSE;
7236 case MM_PLAYER_URI_TYPE_URL_HTTP:
7238 gchar *user_agent, *proxy, *cookies, **cookie_list;
7239 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
7240 user_agent = proxy = cookies = NULL;
7242 gint mode = MM_PLAYER_PD_MODE_NONE;
7244 mm_attrs_get_int_by_name ( attrs, "pd_mode", &mode );
7246 player->pd_mode = mode;
7248 debug_log("http playback, PD mode : %d\n", player->pd_mode);
7250 if ( ! MMPLAYER_IS_HTTP_PD(player) )
7252 element = gst_element_factory_make(player->ini.name_of_httpsrc, "http_streaming_source");
7255 debug_error("failed to create http streaming source element[%s].\n", player->ini.name_of_httpsrc);
7258 debug_log("using http streamming source [%s].\n", player->ini.name_of_httpsrc);
7261 mm_attrs_get_string_by_name ( attrs, "streaming_cookie", &cookies );
7262 mm_attrs_get_string_by_name ( attrs, "streaming_user_agent", &user_agent );
7263 mm_attrs_get_string_by_name ( attrs, "streaming_proxy", &proxy );
7264 mm_attrs_get_int_by_name ( attrs, "streaming_timeout", &http_timeout );
7266 if ((http_timeout == DEFAULT_HTTP_TIMEOUT) &&
7267 (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT))
7269 debug_log("get timeout from ini\n");
7270 http_timeout = player->ini.http_timeout;
7274 secure_debug_log("location : %s\n", player->profile.uri);
7275 secure_debug_log("cookies : %s\n", cookies);
7276 secure_debug_log("proxy : %s\n", proxy);
7277 secure_debug_log("user_agent : %s\n", user_agent);
7278 debug_log("timeout : %d\n", http_timeout);
7280 /* setting property to streaming source */
7281 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
7282 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
7283 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
7285 /* check if prosy is vailid or not */
7286 if ( util_check_valid_url ( proxy ) )
7287 g_object_set(G_OBJECT(element), "proxy", proxy, NULL);
7288 /* parsing cookies */
7289 if ( ( cookie_list = util_get_cookie_list ((const char*)cookies) ) )
7290 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
7292 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
7294 if ( MMPLAYER_URL_HAS_DASH_SUFFIX(player) )
7296 debug_warning("it's dash. and it's still experimental feature.");
7299 else // progressive download
7301 gchar* location = NULL;
7303 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
7307 mm_attrs_get_string_by_name ( attrs, "pd_location", &path );
7309 MMPLAYER_FREEIF(player->pd_file_save_path);
7311 debug_log("PD Location : %s\n", path);
7315 player->pd_file_save_path = g_strdup(path);
7319 debug_error("can't find pd location so, it should be set \n");
7320 return MM_ERROR_PLAYER_FILE_NOT_FOUND;
7324 element = gst_element_factory_make("pdpushsrc", "PD pushsrc");
7327 debug_error("failed to create PD push source element[%s].\n", "pdpushsrc");
7331 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
7332 g_object_set(G_OBJECT(element), "location", player->pd_file_save_path, NULL);
7334 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
7336 g_object_get(element, "location", &location, NULL);
7337 debug_log("PD_LOCATION [%s].\n", location);
7345 case MM_PLAYER_URI_TYPE_FILE:
7348 debug_log("using filesrc for 'file://' handler.\n");
7350 element = gst_element_factory_make("filesrc", "source");
7354 debug_error("failed to create filesrc\n");
7358 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
7359 //g_object_set(G_OBJECT(element), "use-mmap", TRUE, NULL);
7363 case MM_PLAYER_URI_TYPE_SS:
7365 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
7366 element = gst_element_factory_make("souphttpsrc", "http streaming source");
7369 debug_error("failed to create http streaming source element[%s]", player->ini.name_of_httpsrc);
7373 mm_attrs_get_int_by_name ( attrs, "streaming_timeout", &http_timeout );
7375 if ((http_timeout == DEFAULT_HTTP_TIMEOUT) &&
7376 (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT))
7378 debug_log("get timeout from ini\n");
7379 http_timeout = player->ini.http_timeout;
7382 /* setting property to streaming source */
7383 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
7384 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
7389 case MM_PLAYER_URI_TYPE_BUFF:
7391 guint64 stream_type = GST_APP_STREAM_TYPE_STREAM;
7393 debug_log("mem src is selected\n");
7395 element = gst_element_factory_make("appsrc", "buff-source");
7398 debug_error("failed to create appsrc element\n");
7402 g_object_set( element, "stream-type", stream_type, NULL );
7403 //g_object_set( element, "size", player->mem_buf.len, NULL );
7404 //g_object_set( element, "blocksize", (guint64)20480, NULL );
7406 MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
7407 G_CALLBACK(__gst_appsrc_seek_data), player);
7408 MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
7409 G_CALLBACK(__gst_appsrc_feed_data), player);
7410 MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
7411 G_CALLBACK(__gst_appsrc_enough_data), player);
7414 case MM_PLAYER_URI_TYPE_ES_BUFF:
7416 debug_log("es buff src is selected\n");
7418 if (player->v_stream_caps)
7420 element = gst_element_factory_make("appsrc", "video_appsrc");
7423 debug_critical("failed to create video app source element[appsrc].\n" );
7427 if ( player->a_stream_caps )
7429 elem_src_audio = gst_element_factory_make("appsrc", "audio_appsrc");
7430 if ( !elem_src_audio )
7432 debug_critical("failed to create audio app source element[appsrc].\n" );
7437 else if ( player->a_stream_caps )
7439 /* no video, only audio pipeline*/
7440 element = gst_element_factory_make("appsrc", "audio_appsrc");
7443 debug_critical("failed to create audio app source element[appsrc].\n" );
7448 if ( player->s_stream_caps )
7450 elem_src_subtitle = gst_element_factory_make("appsrc", "subtitle_appsrc");
7451 if ( !elem_src_subtitle )
7453 debug_critical("failed to create subtitle app source element[appsrc].\n" );
7458 debug_log("setting app sources properties.\n");
7459 debug_log("location : %s\n", player->profile.uri);
7461 if ( player->v_stream_caps && element )
7463 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
7464 "blocksize", (guint)1048576, /* size of many video frames are larger than default blocksize as 4096 */
7465 "caps", player->v_stream_caps, NULL);
7467 if ( player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
7468 g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
7469 if ( player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
7470 g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
7472 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
7473 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
7474 MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
7475 G_CALLBACK(__gst_seek_video_data), player);
7477 if (player->a_stream_caps && elem_src_audio)
7479 g_object_set(G_OBJECT(elem_src_audio), "format", GST_FORMAT_TIME,
7480 "caps", player->a_stream_caps, NULL);
7482 if ( player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
7483 g_object_set(G_OBJECT(elem_src_audio), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
7484 if ( player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
7485 g_object_set(G_OBJECT(elem_src_audio), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
7487 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
7488 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_audio), GST_APP_STREAM_TYPE_SEEKABLE);
7489 MMPLAYER_SIGNAL_CONNECT( player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
7490 G_CALLBACK(__gst_seek_audio_data), player);
7493 else if (player->a_stream_caps && element)
7495 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
7496 "caps", player->a_stream_caps, NULL);
7498 if ( player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
7499 g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
7500 if ( player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
7501 g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
7503 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
7504 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
7505 MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
7506 G_CALLBACK(__gst_seek_audio_data), player);
7509 if (player->s_stream_caps && elem_src_subtitle)
7511 g_object_set(G_OBJECT(elem_src_subtitle), "format", GST_FORMAT_TIME,
7512 "caps", player->s_stream_caps, NULL);
7514 if ( player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
7515 g_object_set(G_OBJECT(elem_src_subtitle), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
7516 if ( player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
7517 g_object_set(G_OBJECT(elem_src_subtitle), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
7519 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_subtitle), GST_APP_STREAM_TYPE_SEEKABLE);
7521 MMPLAYER_SIGNAL_CONNECT( player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
7522 G_CALLBACK(__gst_seek_subtitle_data), player);
7525 if (!player->es_player_push_mode)
7527 if (player->v_stream_caps && element)
7529 MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
7530 G_CALLBACK(__gst_appsrc_feed_video_data), player);
7531 MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
7532 G_CALLBACK(__gst_appsrc_enough_video_data), player);
7534 if (player->a_stream_caps && elem_src_audio)
7536 MMPLAYER_SIGNAL_CONNECT( player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
7537 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
7538 MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
7539 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
7542 else if (player->a_stream_caps && element)
7544 MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
7545 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
7546 MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
7547 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
7550 if (player->s_stream_caps && elem_src_subtitle)
7552 MMPLAYER_SIGNAL_CONNECT( player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
7553 G_CALLBACK(__gst_appsrc_feed_subtitle_data), player);
7557 need_state_holder = FALSE;
7561 case MM_PLAYER_URI_TYPE_MEM:
7563 guint64 stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
7565 debug_log("mem src is selected\n");
7567 element = gst_element_factory_make("appsrc", "mem-source");
7570 debug_error("failed to create appsrc element\n");
7574 g_object_set( element, "stream-type", stream_type, NULL );
7575 g_object_set( element, "size", player->mem_buf.len, NULL );
7576 g_object_set( element, "blocksize", (guint64)20480, NULL );
7578 MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
7579 G_CALLBACK(__gst_appsrc_seek_data_mem), &player->mem_buf );
7580 MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
7581 G_CALLBACK(__gst_appsrc_feed_data_mem), &player->mem_buf );
7584 case MM_PLAYER_URI_TYPE_URL:
7587 case MM_PLAYER_URI_TYPE_TEMP:
7590 case MM_PLAYER_URI_TYPE_NONE:
7595 /* check source element is OK */
7598 debug_error("no source element was created.\n");
7602 /* take source element */
7603 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
7604 mainbin[MMPLAYER_M_SRC].gst = element;
7605 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
7607 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL))
7609 player->streamer = __mm_player_streaming_create();
7610 __mm_player_streaming_initialize(player->streamer);
7613 if ( MMPLAYER_IS_HTTP_PD(player) )
7615 gdouble pre_buffering_time = (gdouble)player->streamer->buffering_req.initial_second;
7617 debug_log ("Picked queue2 element(pre buffer : %d sec)....\n", pre_buffering_time);
7618 element = gst_element_factory_make("queue2", "queue2");
7621 debug_error ( "failed to create http streaming buffer element\n" );
7626 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
7627 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element;
7628 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]);
7630 pre_buffering_time = (pre_buffering_time > 0)?(pre_buffering_time):(player->ini.http_buffering_time);
7632 __mm_player_streaming_set_queue2(player->streamer,
7635 player->ini.http_max_size_bytes,
7638 player->ini.http_buffering_limit,
7643 if (MMPLAYER_IS_ES_BUFF_SRC(player))
7645 if (player->v_stream_caps)
7647 es_video_queue = gst_element_factory_make("queue2", "video_queue");
7648 if (!es_video_queue)
7650 debug_error ("create es_video_queue for es player failed\n");
7653 mainbin[MMPLAYER_M_V_BUFFER].id = MMPLAYER_M_V_BUFFER;
7654 mainbin[MMPLAYER_M_V_BUFFER].gst = es_video_queue;
7655 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_V_BUFFER]);
7657 /* Adding audio appsrc to bucket */
7658 if (player->a_stream_caps && elem_src_audio)
7660 mainbin[MMPLAYER_M_2ND_SRC].id = MMPLAYER_M_2ND_SRC;
7661 mainbin[MMPLAYER_M_2ND_SRC].gst = elem_src_audio;
7662 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_2ND_SRC]);
7664 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
7665 if (!es_audio_queue)
7667 debug_error ("create es_audio_queue for es player failed\n");
7670 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
7671 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
7672 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
7675 /* Only audio stream, no video */
7676 else if (player->a_stream_caps)
7678 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
7679 if (!es_audio_queue)
7681 debug_error ("create es_audio_queue for es player failed\n");
7684 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
7685 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
7686 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
7689 if (player->s_stream_caps && elem_src_subtitle)
7691 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
7692 mainbin[MMPLAYER_M_SUBSRC].gst = elem_src_subtitle;
7693 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SUBSRC]);
7695 es_subtitle_queue = gst_element_factory_make("queue2", "subtitle_queue");
7696 if (!es_subtitle_queue)
7698 debug_error ("create es_subtitle_queue for es player failed\n");
7701 mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_V_BUFFER;
7702 mainbin[MMPLAYER_M_S_BUFFER].gst = es_subtitle_queue;
7703 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_S_BUFFER]);
7707 /* create autoplugging element if src element is not a rtsp src */
7708 if ((player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_RTSP) &&
7709 (player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_WFD) &&
7710 (player->profile.uri_type != MM_PLAYER_URI_TYPE_ES_BUFF))
7713 enum MainElementID elemId = MMPLAYER_M_NUM;
7715 if ((player->use_decodebin) &&
7716 ((MMPLAYER_IS_HTTP_PD(player)) ||
7717 (!MMPLAYER_IS_HTTP_STREAMING(player))))
7719 elemId = MMPLAYER_M_AUTOPLUG;
7720 element = __mmplayer_create_decodebin(player);
7721 need_state_holder = FALSE;
7725 elemId = MMPLAYER_M_TYPEFIND;
7726 element = gst_element_factory_make("typefind", "typefinder");
7727 MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
7728 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player );
7732 /* check autoplug element is OK */
7735 debug_error("can not create element (%d)\n", elemId);
7739 mainbin[elemId].id = elemId;
7740 mainbin[elemId].gst = element;
7742 element_bucket = g_list_append(element_bucket, &mainbin[elemId]);
7745 /* add elements to pipeline */
7746 if( !__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket))
7748 debug_error("Failed to add elements to pipeline\n");
7753 /* linking elements in the bucket by added order. */
7754 if ( __mmplayer_gst_element_link_bucket(element_bucket) == -1 )
7756 debug_error("Failed to link some elements\n");
7761 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
7762 if ( need_state_holder )
7765 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
7766 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make ("fakesink", "state-holder");
7768 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
7770 debug_error ("fakesink element could not be created\n");
7773 GST_OBJECT_FLAG_UNSET (mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
7775 /* take ownership of fakesink. we are reusing it */
7776 gst_object_ref( mainbin[MMPLAYER_M_SRC_FAKESINK].gst );
7779 if ( FALSE == gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst),
7780 mainbin[MMPLAYER_M_SRC_FAKESINK].gst) )
7782 debug_error("failed to add fakesink to bin\n");
7787 /* now we have completed mainbin. take it */
7788 player->pipeline->mainbin = mainbin;
7790 if (MMPLAYER_IS_ES_BUFF_SRC(player))
7792 GstPad *srcpad = NULL;
7794 if (mainbin[MMPLAYER_M_V_BUFFER].gst)
7796 srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_V_BUFFER].gst, "src");
7799 __mmplayer_gst_create_decoder ( player,
7800 MM_PLAYER_TRACK_TYPE_VIDEO,
7802 MMPLAYER_M_AUTOPLUG_V_DEC,
7805 gst_object_unref ( GST_OBJECT(srcpad) );
7810 if ((player->a_stream_caps) && (mainbin[MMPLAYER_M_A_BUFFER].gst))
7812 srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_A_BUFFER].gst, "src");
7815 __mmplayer_gst_create_decoder ( player,
7816 MM_PLAYER_TRACK_TYPE_AUDIO,
7818 MMPLAYER_M_AUTOPLUG_A_DEC,
7821 gst_object_unref ( GST_OBJECT(srcpad) );
7826 if (mainbin[MMPLAYER_M_S_BUFFER].gst)
7828 __mmplayer_try_to_plug_decodebin(player, gst_element_get_static_pad(mainbin[MMPLAYER_M_S_BUFFER].gst, "src"), player->s_stream_caps);
7832 /* connect bus callback */
7833 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
7836 debug_error ("cannot get bus from pipeline.\n");
7840 player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_callback, player);
7842 player->context.thread_default = g_main_context_get_thread_default();
7844 if (NULL == player->context.thread_default)
7846 player->context.thread_default = g_main_context_default();
7847 debug_log("thread-default context is the global default context");
7849 debug_warning("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
7851 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
7852 if ( __mmplayer_check_subtitle ( player ) )
7854 if ( MM_ERROR_NONE != __mmplayer_gst_create_subtitle_src(player) )
7855 debug_error("fail to create subtitle src\n");
7858 /* set sync handler to get tag synchronously */
7859 gst_bus_set_sync_handler(bus, __mmplayer_bus_sync_callback, player, NULL);
7862 gst_object_unref(GST_OBJECT(bus));
7863 g_list_free(element_bucket);
7867 return MM_ERROR_NONE;
7871 __mmplayer_gst_destroy_pipeline(player);
7872 g_list_free(element_bucket);
7874 /* release element which are not added to bin */
7875 for ( i = 1; i < MMPLAYER_M_NUM; i++ ) /* NOTE : skip pipeline */
7877 if ( mainbin[i].gst )
7879 GstObject* parent = NULL;
7880 parent = gst_element_get_parent( mainbin[i].gst );
7884 gst_object_unref(GST_OBJECT(mainbin[i].gst));
7885 mainbin[i].gst = NULL;
7889 gst_object_unref(GST_OBJECT(parent));
7894 /* release pipeline with it's childs */
7895 if ( mainbin[MMPLAYER_M_PIPE].gst )
7897 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
7900 MMPLAYER_FREEIF( player->pipeline );
7901 MMPLAYER_FREEIF( mainbin );
7903 return MM_ERROR_PLAYER_INTERNAL;
7906 void __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
7908 GSource *source = NULL;
7912 source = g_main_context_find_source_by_id (context, source_id);
7916 debug_warning("context: %p, source id: %d, source: %p", context, source_id, source);
7917 g_source_destroy(source);
7924 __mmplayer_reset_gapless_state(mm_player_t* player)
7927 return_if_fail(player
7929 && player->pipeline->audiobin
7930 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
7932 if (player->gapless.audio_data_probe_id != 0)
7935 sinkpad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_BIN].gst, "sink");
7936 gst_pad_remove_probe (sinkpad, player->gapless.audio_data_probe_id);
7937 gst_object_unref (sinkpad);
7939 memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
7946 __mmplayer_gst_destroy_pipeline(mm_player_t* player) // @
7949 int ret = MM_ERROR_NONE;
7953 return_val_if_fail ( player, MM_ERROR_INVALID_HANDLE );
7955 /* cleanup stuffs */
7956 MMPLAYER_FREEIF(player->type);
7957 player->have_dynamic_pad = FALSE;
7958 player->no_more_pad = FALSE;
7959 player->num_dynamic_pad = 0;
7960 player->demux_pad_index = 0;
7961 player->subtitle_language_list = NULL;
7962 player->use_deinterleave = FALSE;
7963 player->max_audio_channels = 0;
7964 player->video_share_api_delta = 0;
7965 player->video_share_clock_delta = 0;
7966 player->video_hub_download_mode = 0;
7967 __mmplayer_reset_gapless_state(player);
7968 __mmplayer_post_proc_reset(player);
7970 if (player->streamer)
7972 __mm_player_streaming_deinitialize (player->streamer);
7973 __mm_player_streaming_destroy(player->streamer);
7974 player->streamer = NULL;
7977 /* cleanup unlinked mime type */
7978 MMPLAYER_FREEIF(player->unlinked_audio_mime);
7979 MMPLAYER_FREEIF(player->unlinked_video_mime);
7980 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
7982 /* cleanup running stuffs */
7983 __mmplayer_cancel_eos_timer( player );
7985 /* remove sound cb */
7986 if ( MM_ERROR_NONE != mm_sound_remove_device_information_changed_callback())
7988 debug_error("failed to mm_sound_remove_device_information_changed_callback()");
7991 /* cleanup gst stuffs */
7992 if ( player->pipeline )
7994 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
7995 GstTagList* tag_list = player->pipeline->tag_list;
7997 /* first we need to disconnect all signal hander */
7998 __mmplayer_release_signal_connection( player, MM_PLAYER_SIGNAL_TYPE_ALL );
8000 /* disconnecting bus watch */
8001 if ( player->bus_watcher )
8002 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
8003 player->bus_watcher = 0;
8007 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
8008 MMPlayerGstElement* videobin = player->pipeline->videobin;
8009 MMPlayerGstElement* textbin = player->pipeline->textbin;
8010 GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE (mainbin[MMPLAYER_M_PIPE].gst));
8011 gst_bus_set_sync_handler (bus, NULL, NULL, NULL);
8012 gst_object_unref(bus);
8014 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
8015 ret = __mmplayer_gst_set_state ( player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout );
8016 if ( ret != MM_ERROR_NONE )
8018 debug_error("fail to change state to NULL\n");
8019 return MM_ERROR_PLAYER_INTERNAL;
8022 debug_warning("succeeded in chaning state to NULL\n");
8024 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
8027 if ( mainbin[MMPLAYER_M_SRC_FAKESINK].gst )
8028 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
8030 /* free avsysaudiosink
8031 avsysaudiosink should be unref when destory pipeline just after start play with BT.
8032 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
8034 MMPLAYER_FREEIF( audiobin );
8035 MMPLAYER_FREEIF( videobin );
8036 MMPLAYER_FREEIF( textbin );
8037 MMPLAYER_FREEIF( mainbin );
8041 gst_tag_list_free(tag_list);
8043 MMPLAYER_FREEIF( player->pipeline );
8045 MMPLAYER_FREEIF(player->album_art);
8047 if (player->v_stream_caps)
8049 gst_caps_unref(player->v_stream_caps);
8050 player->v_stream_caps = NULL;
8052 if (player->a_stream_caps)
8054 gst_caps_unref(player->a_stream_caps);
8055 player->a_stream_caps = NULL;
8057 if (player->s_stream_caps)
8059 gst_caps_unref(player->s_stream_caps);
8060 player->s_stream_caps = NULL;
8062 _mmplayer_track_destroy(player);
8064 if ( player->sink_elements )
8065 g_list_free ( player->sink_elements );
8066 player->sink_elements = NULL;
8068 debug_warning("finished destroy pipeline\n");
8075 static int __gst_realize(mm_player_t* player) // @
8078 int ret = MM_ERROR_NONE;
8082 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8084 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
8086 ret = __mmplayer_gst_create_pipeline(player);
8089 debug_error("failed to create pipeline\n");
8093 /* set pipeline state to READY */
8094 /* NOTE : state change to READY must be performed sync. */
8095 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
8096 ret = __mmplayer_gst_set_state(player,
8097 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
8099 if ( ret != MM_ERROR_NONE )
8101 /* return error if failed to set state */
8102 debug_error("failed to set READY state");
8107 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_READY );
8110 /* create dot before error-return. for debugging */
8111 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-realize" );
8118 static int __gst_unrealize(mm_player_t* player) // @
8120 int ret = MM_ERROR_NONE;
8124 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8126 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
8127 MMPLAYER_PRINT_STATE(player);
8129 /* release miscellaneous information */
8130 __mmplayer_release_misc( player );
8132 /* destroy pipeline */
8133 ret = __mmplayer_gst_destroy_pipeline( player );
8134 if ( ret != MM_ERROR_NONE )
8136 debug_error("failed to destory pipeline\n");
8140 /* release miscellaneous information.
8141 these info needs to be released after pipeline is destroyed. */
8142 __mmplayer_release_misc_post( player );
8144 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_NULL );
8151 static int __gst_pending_seek ( mm_player_t* player )
8153 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
8154 int ret = MM_ERROR_NONE;
8158 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
8160 if ( !player->pending_seek.is_pending )
8162 debug_log("pending seek is not reserved. nothing to do.\n" );
8166 /* check player state if player could pending seek or not. */
8167 current_state = MMPLAYER_CURRENT_STATE(player);
8169 if ( current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING )
8171 debug_warning("try to pending seek in %s state, try next time. \n",
8172 MMPLAYER_STATE_GET_NAME(current_state));
8176 debug_log("trying to play from (%lu) pending position\n", player->pending_seek.pos);
8178 ret = __gst_set_position ( player, player->pending_seek.format, player->pending_seek.pos, FALSE );
8180 if ( MM_ERROR_NONE != ret )
8181 debug_error("failed to seek pending postion. just keep staying current position.\n");
8183 player->pending_seek.is_pending = FALSE;
8190 static int __gst_start(mm_player_t* player) // @
8192 gboolean sound_extraction = 0;
8193 int ret = MM_ERROR_NONE;
8194 gboolean async = FALSE;
8198 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
8200 /* get sound_extraction property */
8201 mm_attrs_get_int_by_name(player->attrs, "pcm_extraction", &sound_extraction);
8203 /* NOTE : if SetPosition was called before Start. do it now */
8204 /* streaming doesn't support it. so it should be always sync */
8205 /* !! create one more api to check if there is pending seek rather than checking variables */
8206 if ( (player->pending_seek.is_pending || sound_extraction) && !MMPLAYER_IS_STREAMING(player))
8208 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
8209 ret = __gst_pause(player, FALSE);
8210 if ( ret != MM_ERROR_NONE )
8212 debug_error("failed to set state to PAUSED for pending seek\n");
8216 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
8218 if ( sound_extraction )
8220 debug_log("setting pcm extraction\n");
8222 ret = __mmplayer_set_pcm_extraction(player);
8223 if ( MM_ERROR_NONE != ret )
8225 debug_warning("failed to set pcm extraction\n");
8231 if ( MM_ERROR_NONE != __gst_pending_seek(player) )
8233 debug_warning("failed to seek pending postion. starting from the begin of content.\n");
8238 debug_log("current state before doing transition");
8239 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
8240 MMPLAYER_PRINT_STATE(player);
8242 /* set pipeline state to PLAYING */
8243 if (player->es_player_push_mode)
8247 /* set pipeline state to PLAYING */
8248 ret = __mmplayer_gst_set_state(player,
8249 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player) );
8251 if (ret == MM_ERROR_NONE)
8253 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
8257 debug_error("failed to set state to PLAYING");
8261 /* generating debug info before returning error */
8262 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-start" );
8269 static void __mmplayer_do_sound_fadedown(mm_player_t* player, unsigned int time)
8273 return_if_fail(player
8275 && player->pipeline->audiobin
8276 && player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
8278 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", 2, NULL);
8285 static void __mmplayer_undo_sound_fadedown(mm_player_t* player)
8289 return_if_fail(player
8291 && player->pipeline->audiobin
8292 && player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
8294 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", 0, NULL);
8299 static int __gst_stop(mm_player_t* player) // @
8301 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
8302 MMHandleType attrs = 0;
8303 gboolean fadedown = FALSE;
8304 gboolean rewind = FALSE;
8306 int ret = MM_ERROR_NONE;
8308 gboolean async = FALSE;
8312 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
8313 return_val_if_fail ( player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8315 debug_log("current state before doing transition");
8316 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
8317 MMPLAYER_PRINT_STATE(player);
8319 attrs = MMPLAYER_GET_ATTRS(player);
8322 debug_error("cannot get content attribute\n");
8323 return MM_ERROR_PLAYER_INTERNAL;
8326 mm_attrs_get_int_by_name(attrs, "sound_fadedown", &fadedown);
8328 /* enable fadedown */
8329 if (fadedown || player->sm.by_asm_cb)
8330 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
8332 /* Just set state to PAUESED and the rewind. it's usual player behavior. */
8333 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT ( player );
8335 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_BUFF ||
8336 player->profile.uri_type == MM_PLAYER_URI_TYPE_HLS)
8338 state = GST_STATE_READY;
8342 state = GST_STATE_PAUSED;
8344 if ( ! MMPLAYER_IS_STREAMING(player) ||
8345 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked)) {
8350 if (player->es_player_push_mode)
8355 ret = __mmplayer_gst_set_state( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, state, async, timeout );
8357 /* disable fadeout */
8358 if (fadedown || player->sm.by_asm_cb)
8359 __mmplayer_undo_sound_fadedown(player);
8361 /* return if set_state has failed */
8362 if ( ret != MM_ERROR_NONE )
8364 debug_error("failed to set state.\n");
8371 if ( ! __gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
8372 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
8373 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE) )
8375 debug_warning("failed to rewind\n");
8376 ret = MM_ERROR_PLAYER_SEEK;
8381 player->sent_bos = FALSE;
8383 if (player->es_player_push_mode) //for cloudgame
8388 /* wait for seek to complete */
8389 change_ret = gst_element_get_state (player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
8390 if ( change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL )
8392 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_READY );
8396 debug_error("fail to stop player.\n");
8397 ret = MM_ERROR_PLAYER_INTERNAL;
8398 __mmplayer_dump_pipeline_state(player);
8401 /* generate dot file if enabled */
8402 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-stop" );
8409 int __gst_pause(mm_player_t* player, gboolean async) // @
8411 int ret = MM_ERROR_NONE;
8415 return_val_if_fail(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
8416 return_val_if_fail(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8418 debug_log("current state before doing transition");
8419 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
8420 MMPLAYER_PRINT_STATE(player);
8422 /* set pipeline status to PAUSED */
8423 player->ignore_asyncdone = TRUE;
8425 ret = __mmplayer_gst_set_state(player,
8426 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
8428 player->ignore_asyncdone = FALSE;
8430 if ( FALSE == async )
8432 if ( ret != MM_ERROR_NONE )
8434 GstMessage *msg = NULL;
8435 GTimer *timer = NULL;
8436 gdouble MAX_TIMEOUT_SEC = 3;
8438 debug_error("failed to set state to PAUSED");
8440 timer = g_timer_new();
8441 g_timer_start(timer);
8443 GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8444 gboolean got_msg = FALSE;
8445 /* check if gst error posted or not */
8448 msg = gst_bus_timed_pop(bus, GST_SECOND /2);
8451 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR)
8453 GError *error = NULL;
8455 /* parse error code */
8456 gst_message_parse_error(msg, &error, NULL);
8458 if ( gst_structure_has_name ( gst_message_get_structure(msg), "streaming_error" ) )
8460 /* Note : the streaming error from the streaming source is handled
8461 * using __mmplayer_handle_streaming_error.
8463 __mmplayer_handle_streaming_error ( player, msg );
8468 debug_error("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
8470 if (error->domain == GST_STREAM_ERROR)
8472 ret = __gst_handle_stream_error( player, error, msg );
8474 else if (error->domain == GST_RESOURCE_ERROR)
8476 ret = __gst_handle_resource_error( player, error->code );
8478 else if (error->domain == GST_LIBRARY_ERROR)
8480 ret = __gst_handle_library_error( player, error->code );
8482 else if (error->domain == GST_CORE_ERROR)
8484 ret = __gst_handle_core_error( player, error->code );
8489 player->msg_posted = TRUE;
8491 gst_message_unref(msg);
8493 } while (!got_msg && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
8495 gst_object_unref(bus);
8496 g_timer_stop (timer);
8497 g_timer_destroy (timer);
8501 else if ( (!player->pipeline->videobin) && (!player->pipeline->audiobin) )
8503 if (MMPLAYER_IS_RTSP_STREAMING(player))
8505 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
8507 else if ( ret== MM_ERROR_NONE)
8509 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_PAUSED );
8513 /* generate dot file before returning error */
8514 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-pause" );
8521 int __gst_resume(mm_player_t* player, gboolean async) // @
8523 int ret = MM_ERROR_NONE;
8528 return_val_if_fail(player && player->pipeline,
8529 MM_ERROR_PLAYER_NOT_INITIALIZED);
8531 debug_log("current state before doing transition");
8532 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
8533 MMPLAYER_PRINT_STATE(player);
8535 /* generate dot file before returning error */
8536 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-resume" );
8538 __mmplayer_set_antishock( player , FALSE );
8541 debug_log("do async state transition to PLAYING.\n");
8543 /* set pipeline state to PLAYING */
8544 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
8546 ret = __mmplayer_gst_set_state(player,
8547 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout );
8548 if (ret != MM_ERROR_NONE)
8550 debug_error("failed to set state to PLAYING\n");
8557 // MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_PLAYING );
8558 debug_log("update state machine to %d\n", MM_PLAYER_STATE_PLAYING);
8559 ret = __mmplayer_set_state(player, MM_PLAYER_STATE_PLAYING);
8563 /* generate dot file before returning error */
8564 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-resume" );
8572 __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called) // @
8574 unsigned long dur_msec = 0;
8575 gint64 dur_nsec = 0;
8576 gint64 pos_nsec = 0;
8577 gboolean ret = TRUE;
8578 gboolean accurated = FALSE;
8579 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
8582 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
8583 return_val_if_fail ( !MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP );
8585 if ( MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
8586 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED )
8589 if( !MMPLAYER_IS_ES_BUFF_SRC(player) )
8591 /* check duration */
8592 /* NOTE : duration cannot be zero except live streaming.
8593 * Since some element could have some timing problemn with quering duration, try again.
8595 if ( !player->duration )
8597 if ( !gst_element_query_duration( player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec ))
8601 player->duration = dur_nsec;
8604 if ( player->duration )
8606 dur_msec = GST_TIME_AS_MSECONDS(player->duration);
8610 debug_error("could not get the duration. fail to seek.\n");
8614 debug_log("playback rate: %f\n", player->playback_rate);
8616 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
8619 seek_flags |= GST_SEEK_FLAG_ACCURATE;
8623 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
8629 case MM_PLAYER_POS_FORMAT_TIME:
8631 if( !MMPLAYER_IS_ES_BUFF_SRC(player) )
8633 /* check position is valid or not */
8634 if ( position > dur_msec )
8637 debug_log("seeking to (%lu) msec, duration is %d msec\n", position, dur_msec);
8639 if ( player->doing_seek )
8641 debug_log("not completed seek");
8642 return MM_ERROR_PLAYER_DOING_SEEK;
8646 if ( !internal_called )
8647 player->doing_seek = TRUE;
8649 pos_nsec = position * G_GINT64_CONSTANT(1000000);
8651 if ((MMPLAYER_IS_HTTP_STREAMING(player)) && (!player->videodec_linked))
8653 gint64 cur_time = 0;
8655 /* get current position */
8656 gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_time);
8659 GstEvent *event = gst_event_new_seek (1.0,
8661 (GstSeekFlags)GST_SEEK_FLAG_FLUSH,
8662 GST_SEEK_TYPE_SET, cur_time,
8663 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
8665 __gst_send_event_to_sink(player, event);
8668 __gst_pause( player, FALSE );
8671 ret = __gst_seek ( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
8672 GST_FORMAT_TIME, seek_flags,
8673 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE );
8676 debug_error("failed to set position. dur[%lu] pos[%lu] pos_msec[%llu]\n", dur_msec, position, pos_nsec);
8682 case MM_PLAYER_POS_FORMAT_PERCENT:
8684 debug_log("seeking to (%lu)%% \n", position);
8686 if (player->doing_seek)
8688 debug_log("not completed seek");
8689 return MM_ERROR_PLAYER_DOING_SEEK;
8692 if ( !internal_called)
8693 player->doing_seek = TRUE;
8695 /* FIXIT : why don't we use 'GST_FORMAT_PERCENT' */
8696 pos_nsec = (gint64) ( ( position * player->duration ) / 100 );
8697 ret = __gst_seek ( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
8698 GST_FORMAT_TIME, seek_flags,
8699 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE );
8702 debug_error("failed to set position. dur[%lud] pos[%lud] pos_msec[%llud]\n", dur_msec, position, pos_nsec);
8713 /* NOTE : store last seeking point to overcome some bad operation
8714 * ( returning zero when getting current position ) of some elements
8716 player->last_position = pos_nsec;
8718 /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
8719 if ( player->playback_rate > 1.0 )
8720 _mmplayer_set_playspeed ( (MMHandleType)player, player->playback_rate );
8723 return MM_ERROR_NONE;
8726 player->pending_seek.is_pending = TRUE;
8727 player->pending_seek.format = format;
8728 player->pending_seek.pos = position;
8730 debug_warning("player current-state : %s, pending-state : %s, just preserve pending position(%lu).\n",
8731 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)), MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)), player->pending_seek.pos);
8733 return MM_ERROR_NONE;
8736 debug_error("invalid arguments, position : %ld dur : %ld format : %d \n", position, dur_msec, format);
8737 return MM_ERROR_INVALID_ARGUMENT;
8740 player->doing_seek = FALSE;
8741 return MM_ERROR_PLAYER_SEEK;
8744 #define TRICKPLAY_OFFSET GST_MSECOND
8747 __gst_get_position(mm_player_t* player, int format, unsigned long* position) // @
8749 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
8750 signed long long pos_msec = 0;
8751 gboolean ret = TRUE;
8753 return_val_if_fail( player && position && player->pipeline && player->pipeline->mainbin,
8754 MM_ERROR_PLAYER_NOT_INITIALIZED );
8756 current_state = MMPLAYER_CURRENT_STATE(player);
8758 /* NOTE : query position except paused state to overcome some bad operation
8759 * please refer to below comments in details
8761 if ( current_state != MM_PLAYER_STATE_PAUSED )
8763 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
8766 /* NOTE : get last point to overcome some bad operation of some elements
8767 * ( returning zero when getting current position in paused state
8768 * and when failed to get postion during seeking
8770 if ( ( current_state == MM_PLAYER_STATE_PAUSED )
8772 //|| ( player->last_position != 0 && pos_msec == 0 ) )
8774 debug_log ("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS (pos_msec), ret, current_state);
8776 if(player->playback_rate < 0.0)
8777 pos_msec = player->last_position - TRICKPLAY_OFFSET;
8779 pos_msec = player->last_position;
8782 pos_msec = player->last_position;
8784 player->last_position = pos_msec;
8786 debug_log("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_msec));
8791 if (player->duration > 0 && pos_msec > player->duration) {
8792 pos_msec = player->duration;
8795 if (player->sm.keep_last_pos) {
8796 debug_log("return last pos as stop by asm, %"GST_TIME_FORMAT, GST_TIME_ARGS(player->last_position));
8797 pos_msec = player->last_position;
8800 player->last_position = pos_msec;
8805 case MM_PLAYER_POS_FORMAT_TIME:
8806 *position = GST_TIME_AS_MSECONDS(pos_msec);
8809 case MM_PLAYER_POS_FORMAT_PERCENT:
8814 dur = player->duration / GST_SECOND;
8817 debug_log ("duration is [%d], so returning position 0\n",dur);
8822 pos = pos_msec / GST_SECOND;
8823 *position = pos * 100 / dur;
8828 return MM_ERROR_PLAYER_INTERNAL;
8831 return MM_ERROR_NONE;
8835 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
8837 #define STREAMING_IS_FINISHED 0
8838 #define BUFFERING_MAX_PER 100
8840 GstQuery *query = NULL;
8842 return_val_if_fail( player &&
8844 player->pipeline->mainbin,
8845 MM_ERROR_PLAYER_NOT_INITIALIZED );
8847 return_val_if_fail( start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT );
8849 if (!MMPLAYER_IS_HTTP_STREAMING ( player ))
8851 /* and rtsp is not ready yet. */
8852 debug_warning ( "it's only used for http streaming case.\n" );
8853 return MM_ERROR_NONE;
8861 case MM_PLAYER_POS_FORMAT_PERCENT :
8863 gint start_per = -1, stop_per = -1;
8864 gint64 buffered_total = 0;
8866 unsigned long position = 0;
8867 guint curr_size_bytes = 0;
8868 gint64 buffering_left = -1;
8869 gint buffered_sec = -1;
8871 gint64 content_duration = player->duration;
8872 guint64 content_size = player->http_content_size;
8874 if (content_duration > 0)
8876 if (!__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position))
8878 debug_log ("[Time] pos %d ms / dur %d sec / %lld bytes", position, (guint)(content_duration/GST_SECOND), content_size);
8879 start_per = 100 * (position*GST_MSECOND) / content_duration;
8881 /* buffered size info from multiqueue */
8882 if (player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst)
8884 g_object_get(G_OBJECT(player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst), "curr-size-bytes", &curr_size_bytes, NULL);
8885 debug_log ("[MQ] curr_size_bytes = %d", curr_size_bytes);
8887 buffered_total += curr_size_bytes;
8890 /* buffered size info from queue2 */
8891 if (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)
8893 query = gst_query_new_buffering ( GST_FORMAT_BYTES );
8894 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query))
8896 GstBufferingMode mode;
8897 gint byte_in_rate = 0, byte_out_rate = 0;
8898 gint64 start_byte = 0, stop_byte = 0;
8899 guint num_of_ranges = 0;
8902 num_of_ranges = gst_query_get_n_buffering_ranges(query);
8903 for ( idx=0 ; idx<num_of_ranges ; idx++ )
8905 gst_query_parse_nth_buffering_range (query, idx, &start_byte, &stop_byte);
8906 debug_log ("[Q2][range %d] %lld ~ %lld\n", idx, start_byte, stop_byte);
8908 buffered_total += (stop_byte - start_byte);
8911 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, &buffering_left);
8912 debug_log ("[Q2] in_rate %d, out_rate %d, left %lld\n", byte_in_rate, byte_out_rate, buffering_left);
8914 gst_query_unref (query);
8917 if (buffering_left == STREAMING_IS_FINISHED)
8919 stop_per = BUFFERING_MAX_PER;
8923 guint dur_sec = (guint)(content_duration/GST_SECOND);
8924 guint avg_byterate = (dur_sec>0)?((guint)(content_size/dur_sec)):(0);
8926 if (avg_byterate > 0)
8927 buffered_sec = (gint)(buffered_total/avg_byterate);
8928 else if (player->total_maximum_bitrate > 0)
8929 buffered_sec = (gint)(GET_BIT_FROM_BYTE(buffered_total)/(gint64)player->total_maximum_bitrate);
8930 else if (player->total_bitrate > 0)
8931 buffered_sec = (gint)(GET_BIT_FROM_BYTE(buffered_total)/(gint64)player->total_bitrate);
8933 if ((buffered_sec >= 0) && (dur_sec > 0))
8934 stop_per = start_per + (100 * buffered_sec / dur_sec);
8937 debug_log ("[Buffered Total] %lld bytes, %d sec, per %d~%d\n", buffered_total, buffered_sec, start_per, stop_per);
8941 if (((buffered_total == 0) || (start_per < 0) || (stop_per < 0)) &&
8942 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst))
8944 query = gst_query_new_buffering ( GST_FORMAT_PERCENT );
8945 if ( gst_element_query ( player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query ) )
8948 gint64 range_start_per = -1, range_stop_per = -1;
8950 gst_query_parse_buffering_range ( query, &format, &range_start_per, &range_stop_per, NULL );
8952 debug_log ("[Q2] range start %" G_GINT64_FORMAT " ~ stop %" G_GINT64_FORMAT "\n", range_start_per , range_stop_per);
8954 if (range_start_per != -1)
8955 start_per = (gint)(100 * range_start_per / GST_FORMAT_PERCENT_MAX);
8957 if (range_stop_per != -1)
8958 stop_per = (gint)(100 * range_stop_per / GST_FORMAT_PERCENT_MAX);
8960 gst_query_unref (query);
8964 *start_pos = (start_per < 100)?(start_per):(100);
8969 *stop_pos = (stop_per < 100)?(stop_per):(100);
8975 case MM_PLAYER_POS_FORMAT_TIME :
8976 debug_warning ( "Time format is not supported yet.\n" );
8983 debug_log("current buffer position : %lu~%lu \n", *start_pos, *stop_pos );
8985 return MM_ERROR_NONE;
8989 __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param) // @
8995 debug_warning("set_message_callback is called with invalid player handle\n");
8996 return MM_ERROR_PLAYER_NOT_INITIALIZED;
8999 player->msg_cb = callback;
9000 player->msg_cb_param = user_param;
9002 debug_log("msg_cb : 0x%x msg_cb_param : 0x%x\n", (guint)callback, (guint)user_param);
9006 return MM_ERROR_NONE;
9009 static int __mmfplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data) // @
9011 int ret = MM_ERROR_PLAYER_INVALID_URI;
9016 return_val_if_fail ( uri , FALSE);
9017 return_val_if_fail ( data , FALSE);
9018 return_val_if_fail ( ( strlen(uri) <= MM_MAX_URL_LEN ), FALSE );
9020 memset(data, 0, sizeof(MMPlayerParseProfile));
9022 if ((path = strstr(uri, "file://")))
9024 int file_stat = MM_ERROR_NONE;
9026 file_stat = util_exist_file_path(path + 7);
9028 if (file_stat == MM_ERROR_NONE)
9030 strncpy(data->uri, path, MM_MAX_URL_LEN-1);
9032 if ( util_is_sdp_file ( path ) )
9034 debug_log("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
9035 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9039 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9041 ret = MM_ERROR_NONE;
9043 else if (file_stat == MM_ERROR_PLAYER_PERMISSION_DENIED)
9045 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9049 debug_warning("could access %s.\n", path);
9052 else if ((path = strstr(uri, "es_buff://")))
9056 strcpy(data->uri, uri);
9057 data->uri_type = MM_PLAYER_URI_TYPE_ES_BUFF;
9058 ret = MM_ERROR_NONE;
9061 else if ((path = strstr(uri, "buff://")))
9063 data->uri_type = MM_PLAYER_URI_TYPE_BUFF;
9064 ret = MM_ERROR_NONE;
9066 else if ((path = strstr(uri, "rtsp://")))
9069 if((path = strstr(uri, "/wfd1.0/"))) {
9070 strcpy(data->uri, uri);
9071 data->uri_type = MM_PLAYER_URI_TYPE_URL_WFD;
9072 ret = MM_ERROR_NONE;
9073 debug_log("uri is actually a wfd client path. giving it to wfdrtspsrc\n");
9076 strcpy(data->uri, uri);
9077 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9078 ret = MM_ERROR_NONE;
9082 else if ((path = strstr(uri, "http://")))
9085 strcpy(data->uri, uri);
9086 #ifdef MM_SMOOTH_STREAMING
9087 if (g_str_has_suffix (g_ascii_strdown(uri, strlen(uri)), ".ism/manifest") ||
9088 g_str_has_suffix (g_ascii_strdown(uri, strlen(uri)), ".isml/manifest"))
9090 data->uri_type = MM_PLAYER_URI_TYPE_SS;
9094 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
9096 ret = MM_ERROR_NONE;
9099 else if ((path = strstr(uri, "https://")))
9102 strcpy(data->uri, uri);
9103 #ifdef MM_SMOOTH_STREAMING
9104 if (g_str_has_suffix (g_ascii_strdown(uri, strlen(uri)), ".ism/manifest") ||
9105 g_str_has_suffix (g_ascii_strdown(uri, strlen(uri)), ".isml/manifest"))
9107 data->uri_type = MM_PLAYER_URI_TYPE_SS;
9110 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
9112 ret = MM_ERROR_NONE;
9115 else if ((path = strstr(uri, "rtspu://")))
9118 strcpy(data->uri, uri);
9119 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9120 ret = MM_ERROR_NONE;
9123 else if ((path = strstr(uri, "rtspr://")))
9125 strcpy(data->uri, path);
9126 char *separater =strstr(path, "*");
9130 char *urgent = separater + strlen("*");
9132 if ((urgent_len = strlen(urgent))) {
9133 data->uri[strlen(path) - urgent_len - strlen("*")] = '\0';
9134 strcpy(data->urgent, urgent);
9135 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9136 ret = MM_ERROR_NONE;
9140 else if ((path = strstr(uri, "mms://")))
9143 strcpy(data->uri, uri);
9144 data->uri_type = MM_PLAYER_URI_TYPE_URL_MMS;
9145 ret = MM_ERROR_NONE;
9148 else if ((path = strstr(uri, "mem://")))
9152 char *buffer = NULL;
9153 char *seperator = strchr(path, ',');
9154 char ext[100] = {0,}, size[100] = {0,};
9157 if ((buffer = strstr(path, "ext="))) {
9158 buffer += strlen("ext=");
9160 if (strlen(buffer)) {
9161 strcpy(ext, buffer);
9163 if ((seperator = strchr(ext, ','))
9164 || (seperator = strchr(ext, ' '))
9165 || (seperator = strchr(ext, '\0'))) {
9166 seperator[0] = '\0';
9171 if ((buffer = strstr(path, "size="))) {
9172 buffer += strlen("size=");
9174 if (strlen(buffer) > 0) {
9175 strcpy(size, buffer);
9177 if ((seperator = strchr(size, ','))
9178 || (seperator = strchr(size, ' '))
9179 || (seperator = strchr(size, '\0'))) {
9180 seperator[0] = '\0';
9183 mem_size = atoi(size);
9188 debug_log("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
9189 if ( mem_size && param)
9192 data->mem_size = mem_size;
9193 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9194 ret = MM_ERROR_NONE;
9200 int file_stat = MM_ERROR_NONE;
9202 file_stat = util_exist_file_path(uri);
9204 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9205 if (file_stat == MM_ERROR_NONE)
9207 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", uri);
9209 if ( util_is_sdp_file( (char*)uri ) )
9211 debug_log("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
9212 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9216 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9218 ret = MM_ERROR_NONE;
9220 else if (file_stat == MM_ERROR_PLAYER_PERMISSION_DENIED)
9222 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9226 debug_error ("invalid uri, could not play..\n");
9227 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9231 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE) {
9232 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
9233 } else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION){
9234 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
9237 /* dump parse result */
9238 secure_debug_warning("incomming uri : %s\n", uri);
9239 debug_log("uri_type : %d, mem : 0x%x, mem_size : %d, urgent : %s\n",
9240 data->uri_type, (guint)data->mem, data->mem_size, data->urgent);
9247 gboolean _asm_postmsg(gpointer *data)
9249 mm_player_t* player = (mm_player_t*)data;
9250 MMMessageParamType msg = {0, };
9253 return_val_if_fail ( player, FALSE );
9254 debug_warning("get notified");
9256 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
9257 (player->cmd == MMPLAYER_COMMAND_UNREALIZE))
9259 debug_warning("dispatched");
9264 msg.union_type = MM_MSG_UNION_CODE;
9265 msg.code = player->sm.event_src;
9267 #if 0 // should remove
9268 if (player->sm.event_src == ASM_EVENT_SOURCE_RESUMABLE_CANCELED)
9270 /* fill the message with state of player */
9271 msg.state.current = MMPLAYER_CURRENT_STATE(player);
9272 MMPLAYER_POST_MSG( player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
9273 player->resumable_cancel_id = 0;
9278 MMPLAYER_POST_MSG( player, MM_MESSAGE_READY_TO_RESUME, &msg);
9279 player->resume_event_id = 0;
9282 debug_warning("dispatched");
9286 gboolean _asm_lazy_pause(gpointer *data)
9288 mm_player_t* player = (mm_player_t*)data;
9289 int ret = MM_ERROR_NONE;
9293 return_val_if_fail ( player, FALSE );
9295 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING)
9297 debug_log ("Ready to proceed lazy pause\n");
9298 ret = _mmplayer_pause((MMHandleType)player);
9299 if(MM_ERROR_NONE != ret)
9301 debug_error("MMPlayer pause failed in ASM callback lazy pause\n");
9306 debug_log ("Invalid state to proceed lazy pause\n");
9310 if (player->pipeline && player->pipeline->audiobin)
9311 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", 0, NULL);
9313 player->sm.by_asm_cb = FALSE; //should be reset here
9321 __mmplayer_can_do_interrupt(mm_player_t *player)
9323 if (!player || !player->pipeline || !player->attrs)
9325 debug_warning("not initialized");
9329 if ((player->sm.exit_cb) || (player->set_mode.pcm_extraction))
9331 debug_warning("leave from asm cb right now, %d, %d", player->sm.exit_cb, player->set_mode.pcm_extraction);
9335 /* check if seeking */
9336 if (player->doing_seek)
9338 MMMessageParamType msg_param;
9339 memset (&msg_param, 0, sizeof(MMMessageParamType));
9340 msg_param.code = MM_ERROR_PLAYER_SEEK;
9341 player->doing_seek = FALSE;
9342 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9346 /* check other thread */
9347 if (!g_mutex_trylock(&player->cmd_lock))
9349 debug_warning("locked already, cmd state : %d", player->cmd);
9351 /* check application command */
9352 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)
9354 debug_warning("playing.. should wait cmd lock then, will be interrupted");
9355 g_mutex_lock(&player->cmd_lock);
9358 debug_warning("nothing to do");
9363 debug_warning("can interrupt immediately");
9375 __mmplayer_asm_callback(int handle, ASM_event_sources_t event_src, ASM_sound_commands_t command, unsigned int sound_status, void* cb_data)
9377 mm_player_t* player = (mm_player_t*) cb_data;
9378 ASM_cb_result_t cb_res = ASM_CB_RES_IGNORE;
9379 int result = MM_ERROR_NONE;
9380 gboolean lazy_pause = FALSE;
9382 debug_warning("get notified");
9384 if (!__mmplayer_can_do_interrupt(player))
9386 debug_warning("no need to interrupt, so leave");
9390 player->sm.cb_pending = TRUE;
9391 debug_warning("asm event src type : %d, command : 0x%x", event_src, command);
9393 player->sm.by_asm_cb = TRUE;
9394 player->sm.event_src = event_src;
9396 /* first, check event source */
9397 if(event_src == ASM_EVENT_SOURCE_EARJACK_UNPLUG)
9399 int stop_by_asm = 0;
9400 mm_attrs_get_int_by_name(player->attrs, "sound_stop_when_unplugged", &stop_by_asm);
9404 else if (event_src == ASM_EVENT_SOURCE_RESOURCE_CONFLICT)
9406 if(player->pipeline->videobin)
9408 debug_log("video conflict so, resource will be freed.");
9409 result = _mmplayer_unrealize((MMHandleType)player);
9410 cb_res = ASM_CB_RES_STOP;
9412 else if (player->pipeline->audiobin)
9414 debug_log("audio resource conflict");
9415 result = _mmplayer_pause((MMHandleType)player);
9416 if (result != MM_ERROR_NONE)
9418 debug_warning("fail to set pause by asm");
9420 cb_res = ASM_CB_RES_PAUSE;
9424 #if 0 // should remove
9425 else if (event_src == ASM_EVENT_SOURCE_RESUMABLE_CANCELED)
9427 debug_warning("Got msg from asm for resumable canceled.\n");
9428 player->sm.antishock = TRUE;
9429 player->sm.by_asm_cb = FALSE;
9431 player->resumable_cancel_id = g_idle_add((GSourceFunc)_asm_postmsg, (gpointer)player);
9432 cb_res = ASM_CB_RES_IGNORE;
9436 /* then, check command */
9439 case ASM_COMMAND_PLAY:
9440 debug_warning ("Got unexpected asm command (%d)", command);
9443 case ASM_COMMAND_STOP: // notification case
9445 debug_warning("Got msg from asm to stop");
9447 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &player->last_position)) {
9448 debug_error("failed to get position");
9449 player->last_position = 0;
9452 debug_log ("pos_msec = %"GST_TIME_FORMAT"", GST_TIME_ARGS(player->last_position));
9454 result = _mmplayer_stop((MMHandleType)player);
9455 if (result != MM_ERROR_NONE)
9457 debug_warning("fail to set stop state by asm");
9458 cb_res = ASM_CB_RES_IGNORE;
9462 cb_res = ASM_CB_RES_STOP;
9464 player->sm.by_asm_cb = FALSE; // reset because no message any more from asm
9465 player->sm.keep_last_pos = TRUE;
9469 case ASM_COMMAND_PAUSE:
9471 debug_warning("Got msg from asm to Pause");
9472 if(event_src == ASM_EVENT_SOURCE_CALL_START ||
9473 event_src == ASM_EVENT_SOURCE_ALARM_START ||
9474 event_src == ASM_EVENT_SOURCE_MEDIA)
9476 if ( ! MMPLAYER_IS_RTSP_STREAMING(player) ) {
9477 //hold 0.7 second to excute "fadedown mute" effect
9478 debug_warning ("do fade down->pause->undo fade down");
9480 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
9482 result = _mmplayer_pause((MMHandleType)player);
9483 if (result != MM_ERROR_NONE)
9485 debug_warning("fail to set Pause state by asm");
9486 cb_res = ASM_CB_RES_IGNORE;
9489 __mmplayer_undo_sound_fadedown(player);
9491 /* rtsp should connect again in specific network becasue tcp session can't be kept any more */
9492 _mmplayer_unrealize((MMHandleType)player);
9495 #ifdef USE_LAZY_PAUSE // if enabled, should consider event id and context when removed
9496 else if(event_src == ASM_EVENT_SOURCE_OTHER_PLAYER_APP)
9498 lazy_pause = TRUE; // return as soon as possible, for fast start of other app
9500 if ( player->pipeline->audiobin && player->pipeline->audiobin[MMPLAYER_A_SINK].gst )
9501 g_object_set( player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "mute", 2, NULL);
9503 player->lazy_pause_event_id = g_timeout_add(LAZY_PAUSE_TIMEOUT_MSEC, (GSourceFunc)_asm_lazy_pause, (gpointer)player);
9504 debug_warning ("set lazy pause timer (id=[%d], timeout=[%d ms])", player->lazy_pause_event_id, LAZY_PAUSE_TIMEOUT_MSEC);
9509 debug_warning ("pause immediately");
9510 result = _mmplayer_pause((MMHandleType)player);
9512 cb_res = ASM_CB_RES_PAUSE;
9516 case ASM_COMMAND_RESUME:
9518 debug_warning("Got msg from asm to Resume. So, application can resume. code (%d) \n", event_src);
9519 player->sm.antishock = TRUE;
9520 player->sm.by_asm_cb = FALSE;
9522 //ASM server is single thread daemon. So use g_idle_add() to post resume msg
9523 player->resume_event_id = g_idle_add((GSourceFunc)_asm_postmsg, (gpointer)player);
9524 cb_res = ASM_CB_RES_IGNORE;
9536 player->sm.by_asm_cb = FALSE;
9538 player->sm.cb_pending = FALSE;
9539 MMPLAYER_CMD_UNLOCK( player );
9542 debug_warning("dispatched");
9547 _mmplayer_create_player(MMHandleType handle) // @
9549 mm_player_t* player = MM_PLAYER_CAST(handle);
9553 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9555 /* initialize player state */
9556 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
9557 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
9558 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
9559 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
9561 /* check current state */
9562 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL ( player, MMPLAYER_COMMAND_CREATE );
9564 /* construct attributes */
9565 player->attrs = _mmplayer_construct_attribute(handle);
9567 if ( !player->attrs )
9569 debug_error("Failed to construct attributes\n");
9573 /* initialize gstreamer with configured parameter */
9574 if ( ! __mmplayer_init_gstreamer(player) )
9576 debug_error("Initializing gstreamer failed\n");
9580 /* initialize factories if not using decodebin */
9581 if( player->factories == NULL )
9582 __mmplayer_init_factories(player);
9584 /* create lock. note that g_tread_init() has already called in gst_init() */
9585 g_mutex_init(&player->fsink_lock);
9587 /* create repeat mutex */
9588 g_mutex_init(&player->repeat_thread_mutex);
9590 /* create repeat cond */
9591 g_cond_init(&player->repeat_thread_cond);
9593 /* create repeat thread */
9594 player->repeat_thread =
9595 g_thread_try_new ("repeat_thread", __mmplayer_repeat_thread, (gpointer)player, NULL);
9598 /* create next play mutex */
9599 g_mutex_init(&player->next_play_thread_mutex);
9601 /* create next play cond */
9602 g_cond_init(&player->next_play_thread_cond);
9604 /* create next play thread */
9605 player->next_play_thread =
9606 g_thread_try_new ("next_play_thread", __mmplayer_next_play_thread, (gpointer)player, NULL);
9607 if ( ! player->next_play_thread )
9609 debug_error("failed to create next play thread");
9613 if ( MM_ERROR_NONE != _mmplayer_initialize_video_capture(player))
9615 debug_error("failed to initialize video capture\n");
9619 /* register to asm */
9620 if ( MM_ERROR_NONE != _mmplayer_asm_register(&player->sm, (ASM_sound_cb_t)__mmplayer_asm_callback, (void*)player) )
9622 /* NOTE : we are dealing it as an error since we cannot expect it's behavior */
9623 debug_error("failed to register asm server\n");
9624 return MM_ERROR_POLICY_INTERNAL;
9627 /* to add active device callback */
9628 if ( MM_ERROR_NONE != mm_sound_add_device_information_changed_callback(MM_SOUND_DEVICE_STATE_ACTIVATED_FLAG, __mmplayer_sound_device_info_changed_cb_func, (void*)player))
9630 debug_error("failed mm_sound_add_device_information_changed_callback \n");
9634 if (MMPLAYER_IS_HTTP_PD(player))
9636 player->pd_downloader = NULL;
9637 player->pd_file_save_path = NULL;
9640 player->streaming_type = STREAMING_SERVICE_NONE;
9642 /* give default value of audio effect setting */
9643 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
9644 player->playback_rate = DEFAULT_PLAYBACK_RATE;
9646 player->play_subtitle = FALSE;
9647 player->use_textoverlay = FALSE;
9648 player->play_count = 0;
9649 player->use_decodebin = TRUE;
9650 player->ignore_asyncdone = FALSE;
9651 player->use_deinterleave = FALSE;
9652 player->max_audio_channels = 0;
9653 player->video_share_api_delta = 0;
9654 player->video_share_clock_delta = 0;
9655 player->has_closed_caption = FALSE;
9657 __mmplayer_post_proc_reset(player);
9659 if (player->ini.dump_element_keyword[0][0] == '\0')
9661 player->ini.set_dump_element_flag= FALSE;
9665 player->ini.set_dump_element_flag = TRUE;
9668 /* set player state to null */
9669 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
9670 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_NULL );
9672 return MM_ERROR_NONE;
9676 g_mutex_clear(&player->fsink_lock );
9679 if ( player->repeat_thread )
9681 player->repeat_thread_exit = TRUE;
9682 g_cond_signal( &player->repeat_thread_cond );
9684 g_thread_join( player->repeat_thread );
9685 player->repeat_thread = NULL;
9687 g_mutex_clear(&player->repeat_thread_mutex );
9689 g_cond_clear (&player->repeat_thread_cond );
9691 /* clear repeat thread mutex/cond if still alive
9692 * this can happen if only thread creating has failed
9694 g_mutex_clear(&player->repeat_thread_mutex );
9695 g_cond_clear ( &player->repeat_thread_cond );
9697 /* free next play thread */
9698 if ( player->next_play_thread )
9700 player->next_play_thread_exit = TRUE;
9701 g_cond_signal( &player->next_play_thread_cond );
9703 g_thread_join( player->next_play_thread );
9704 player->next_play_thread = NULL;
9706 g_mutex_clear(&player->next_play_thread_mutex );
9708 g_cond_clear ( &player->next_play_thread_cond );
9710 /* clear next play thread mutex/cond if still alive
9711 * this can happen if only thread creating has failed
9713 g_mutex_clear(&player->next_play_thread_mutex );
9715 g_cond_clear ( &player->next_play_thread_cond );
9717 /* release attributes */
9718 _mmplayer_deconstruct_attribute(handle);
9722 return MM_ERROR_PLAYER_INTERNAL;
9726 __mmplayer_init_gstreamer(mm_player_t* player) // @
9728 static gboolean initialized = FALSE;
9729 static const int max_argc = 50;
9731 gchar** argv = NULL;
9732 gchar** argv2 = NULL;
9739 debug_log("gstreamer already initialized.\n");
9744 argc = malloc( sizeof(int) );
9745 argv = malloc( sizeof(gchar*) * max_argc );
9746 argv2 = malloc( sizeof(gchar*) * max_argc );
9748 if ( !argc || !argv )
9751 memset( argv, 0, sizeof(gchar*) * max_argc );
9752 memset( argv2, 0, sizeof(gchar*) * max_argc );
9756 argv[0] = g_strdup( "mmplayer" );
9759 for ( i = 0; i < 5; i++ ) /* FIXIT : num of param is now fixed to 5. make it dynamic */
9761 if ( strlen( player->ini.gst_param[i] ) > 0 )
9763 argv[*argc] = g_strdup( player->ini.gst_param[i] );
9768 /* we would not do fork for scanning plugins */
9769 argv[*argc] = g_strdup("--gst-disable-registry-fork");
9772 /* check disable registry scan */
9773 if ( player->ini.skip_rescan )
9775 argv[*argc] = g_strdup("--gst-disable-registry-update");
9779 /* check disable segtrap */
9780 if ( player->ini.disable_segtrap )
9782 argv[*argc] = g_strdup("--gst-disable-segtrap");
9786 debug_log("initializing gstreamer with following parameter\n");
9787 debug_log("argc : %d\n", *argc);
9790 for ( i = 0; i < arg_count; i++ )
9793 debug_log("argv[%d] : %s\n", i, argv2[i]);
9797 /* initializing gstreamer */
9798 if ( ! gst_init_check (argc, &argv, &err))
9800 debug_error("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
9809 for ( i = 0; i < arg_count; i++ )
9811 //debug_log("release - argv[%d] : %s\n", i, argv2[i]);
9812 MMPLAYER_FREEIF( argv2[i] );
9815 MMPLAYER_FREEIF( argv );
9816 MMPLAYER_FREEIF( argv2 );
9817 MMPLAYER_FREEIF( argc );
9827 for ( i = 0; i < arg_count; i++ )
9829 debug_log("free[%d] : %s\n", i, argv2[i]);
9830 MMPLAYER_FREEIF( argv2[i] );
9833 MMPLAYER_FREEIF( argv );
9834 MMPLAYER_FREEIF( argv2 );
9835 MMPLAYER_FREEIF( argc );
9841 __mmplayer_destroy_streaming_ext(mm_player_t* player)
9843 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9845 if (player->pd_downloader)
9847 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
9848 MMPLAYER_FREEIF(player->pd_downloader);
9851 if (MMPLAYER_IS_HTTP_PD(player))
9853 _mmplayer_destroy_pd_downloader((MMHandleType)player);
9854 MMPLAYER_FREEIF(player->pd_file_save_path);
9857 return MM_ERROR_NONE;
9861 _mmplayer_destroy(MMHandleType handle) // @
9863 mm_player_t* player = MM_PLAYER_CAST(handle);
9867 /* check player handle */
9868 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9870 /* destroy can called at anytime */
9871 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL ( player, MMPLAYER_COMMAND_DESTROY );
9873 __mmplayer_destroy_streaming_ext(player);
9875 /* release repeat thread */
9876 if ( player->repeat_thread )
9878 player->repeat_thread_exit = TRUE;
9879 g_cond_signal( &player->repeat_thread_cond );
9881 debug_log("waitting for repeat thread exit\n");
9882 g_thread_join ( player->repeat_thread );
9883 g_mutex_clear(&player->repeat_thread_mutex );
9884 g_cond_clear (&player->repeat_thread_cond );
9885 debug_log("repeat thread released\n");
9888 /* release next play thread */
9889 if ( player->next_play_thread )
9891 player->next_play_thread_exit = TRUE;
9892 g_cond_signal( &player->next_play_thread_cond );
9894 debug_log("waitting for next play thread exit\n");
9895 g_thread_join ( player->next_play_thread );
9896 g_mutex_clear(&player->next_play_thread_mutex );
9897 g_cond_clear(&player->next_play_thread_cond );
9898 debug_log("next play thread released\n");
9901 _mmplayer_release_video_capture(player);
9903 /* flush any pending asm_cb */
9904 if (player->sm.cb_pending)
9906 /* set a flag for make sure asm_cb to be returned immediately */
9907 debug_warning("asm cb has pending state");
9908 player->sm.exit_cb = TRUE;
9910 /* make sure to release any pending asm_cb which locked by cmd_lock */
9911 MMPLAYER_CMD_UNLOCK(player);
9913 MMPLAYER_CMD_LOCK(player);
9917 if ( MM_ERROR_NONE != _mmplayer_asm_unregister(&player->sm) )
9919 debug_error("failed to deregister asm server\n");
9922 #ifdef USE_LAZY_PAUSE
9923 if (player->lazy_pause_event_id)
9925 __mmplayer_remove_g_source_from_context(player->context.global_default, player->lazy_pause_event_id);
9926 player->lazy_pause_event_id = 0;
9930 if (player->resume_event_id)
9932 g_source_remove (player->resume_event_id);
9933 player->resume_event_id = 0;
9936 if (player->resumable_cancel_id)
9938 g_source_remove (player->resumable_cancel_id);
9939 player->resumable_cancel_id = 0;
9942 /* release pipeline */
9943 if ( MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline( player ) )
9945 debug_error("failed to destory pipeline\n");
9946 return MM_ERROR_PLAYER_INTERNAL;
9949 if (player->is_external_subtitle_present && player->subtitle_language_list)
9951 g_list_free (player->subtitle_language_list);
9952 player->subtitle_language_list = NULL;
9955 __mmplayer_release_dump_list (player->dump_list);
9957 /* release miscellaneous information.
9958 these info needs to be released after pipeline is destroyed. */
9959 __mmplayer_release_misc_post( player );
9961 /* release attributes */
9962 _mmplayer_deconstruct_attribute( handle );
9964 /* release factories */
9965 __mmplayer_release_factories( player );
9968 g_mutex_clear(&player->fsink_lock );
9970 g_mutex_clear(&player->msg_cb_lock );
9974 return MM_ERROR_NONE;
9978 __mmplayer_realize_streaming_ext(mm_player_t* player)
9980 int ret = MM_ERROR_NONE;
9983 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9985 if (MMPLAYER_IS_HTTP_PD(player))
9987 gboolean bret = FALSE;
9989 player->pd_downloader = _mmplayer_create_pd_downloader();
9990 if ( !player->pd_downloader )
9992 debug_error ("Unable to create PD Downloader...");
9993 ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
9996 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
10000 debug_error ("Unable to create PD Downloader...");
10001 ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
10010 _mmplayer_realize(MMHandleType hplayer) // @
10012 mm_player_t* player = (mm_player_t*)hplayer;
10014 void *param = NULL;
10015 int application_pid = -1;
10016 gboolean update_registry = FALSE;
10017 MMHandleType attrs = 0;
10018 int ret = MM_ERROR_NONE;
10022 /* check player handle */
10023 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED )
10025 /* check current state */
10026 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_REALIZE );
10028 attrs = MMPLAYER_GET_ATTRS(player);
10031 debug_error("fail to get attributes.\n");
10032 return MM_ERROR_PLAYER_INTERNAL;
10035 mm_attrs_get_int_by_name(attrs, "sound_application_pid", &application_pid );
10036 player->sm.pid = application_pid;
10038 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
10039 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
10041 ret = __mmfplayer_parse_profile((const char*)uri, param, &player->profile);
10043 if (ret != MM_ERROR_NONE)
10045 debug_error("failed to parse profile\n");
10049 /* FIXIT : we can use thouse in player->profile directly */
10050 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM)
10052 player->mem_buf.buf = (char *)player->profile.mem;
10053 player->mem_buf.len = player->profile.mem_size;
10054 player->mem_buf.offset = 0;
10057 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_ES_BUFF)
10059 if (strstr(uri, "es_buff://push_mode"))
10061 player->es_player_push_mode = TRUE;
10065 player->es_player_push_mode = FALSE;
10069 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS)
10071 debug_warning("mms protocol is not supported format.\n");
10072 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
10075 if (MMPLAYER_IS_STREAMING(player))
10076 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
10078 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
10080 player->smooth_streaming = FALSE;
10081 player->videodec_linked = 0;
10082 player->videosink_linked = 0;
10083 player->audiodec_linked = 0;
10084 player->audiosink_linked = 0;
10085 player->textsink_linked = 0;
10086 player->is_external_subtitle_present = FALSE;
10087 /* set the subtitle ON default */
10088 player->is_subtitle_off = FALSE;
10090 /* registry should be updated for downloadable codec */
10091 mm_attrs_get_int_by_name(attrs, "profile_update_registry", &update_registry);
10093 if ( update_registry )
10095 debug_log("updating registry...\n");
10096 gst_update_registry();
10098 /* then we have to rebuild factories */
10099 __mmplayer_release_factories( player );
10100 __mmplayer_init_factories(player);
10103 /* realize pipeline */
10104 ret = __gst_realize( player );
10105 if ( ret != MM_ERROR_NONE )
10107 debug_error("fail to realize the player.\n");
10111 ret = __mmplayer_realize_streaming_ext(player);
10120 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
10123 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
10125 /* destroy can called at anytime */
10126 if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player))
10128 _mmplayer_unrealize_pd_downloader ((MMHandleType)player);
10129 MMPLAYER_FREEIF(player->pd_downloader);
10133 return MM_ERROR_NONE;
10137 _mmplayer_unrealize(MMHandleType hplayer)
10139 mm_player_t* player = (mm_player_t*)hplayer;
10140 int ret = MM_ERROR_NONE;
10144 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED )
10146 /* check current state */
10147 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_UNREALIZE );
10149 __mmplayer_unrealize_streaming_ext(player);
10151 /* unrealize pipeline */
10152 ret = __gst_unrealize( player );
10154 /* set asm stop if success */
10155 if (MM_ERROR_NONE == ret)
10157 if (player->sm.state != ASM_STATE_STOP)
10159 /* NOTE : Stop asm after pipeline unrealize. Keep this sequence. */
10160 ret = _mmplayer_asm_set_state(hplayer, ASM_STATE_STOP, FALSE);
10163 debug_error("failed to set asm state to STOP");
10170 debug_error("failed and don't change asm state to stop");
10179 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param) // @
10181 mm_player_t* player = (mm_player_t*)hplayer;
10183 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10185 return __gst_set_message_callback(player, callback, user_param);
10189 _mmplayer_get_state(MMHandleType hplayer, int* state) // @
10191 mm_player_t *player = (mm_player_t*)hplayer;
10193 return_val_if_fail(state, MM_ERROR_INVALID_ARGUMENT);
10195 *state = MMPLAYER_CURRENT_STATE(player);
10197 return MM_ERROR_NONE;
10202 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume) // @
10204 mm_player_t* player = (mm_player_t*) hplayer;
10205 GstElement* vol_element = NULL;
10210 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
10212 debug_log("volume [L]=%f:[R]=%f\n",
10213 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
10215 /* invalid factor range or not */
10216 for ( i = 0; i < MM_VOLUME_CHANNEL_NUM; i++ )
10218 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
10219 debug_error("Invalid factor! (valid factor:0~1.0)\n");
10220 return MM_ERROR_INVALID_ARGUMENT;
10224 /* not support to set other value into each channel */
10225 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
10226 return MM_ERROR_INVALID_ARGUMENT;
10228 /* Save volume to handle. Currently the first array element will be saved. */
10229 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
10231 /* check pipeline handle */
10232 if ( ! player->pipeline || ! player->pipeline->audiobin )
10234 debug_log("audiobin is not created yet\n");
10235 debug_log("but, current stored volume will be set when it's created.\n");
10237 /* NOTE : stored volume will be used in create_audiobin
10238 * returning MM_ERROR_NONE here makes application to able to
10239 * set volume at anytime.
10241 return MM_ERROR_NONE;
10244 /* setting volume to volume element */
10245 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
10249 debug_log("volume is set [%f]\n", player->sound.volume);
10250 g_object_set(vol_element, "volume", player->sound.volume, NULL);
10255 return MM_ERROR_NONE;
10260 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
10262 mm_player_t* player = (mm_player_t*) hplayer;
10267 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
10268 return_val_if_fail( volume, MM_ERROR_INVALID_ARGUMENT );
10270 /* returning stored volume */
10271 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
10272 volume->level[i] = player->sound.volume;
10276 return MM_ERROR_NONE;
10282 _mmplayer_set_mute(MMHandleType hplayer, int mute) // @
10284 mm_player_t* player = (mm_player_t*) hplayer;
10285 GstElement* vol_element = NULL;
10289 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
10291 /* mute value shoud 0 or 1 */
10292 if ( mute != 0 && mute != 1 )
10294 debug_error("bad mute value\n");
10296 /* FIXIT : definitly, we need _BAD_PARAM error code */
10297 return MM_ERROR_INVALID_ARGUMENT;
10300 player->sound.mute = mute;
10302 /* just hold mute value if pipeline is not ready */
10303 if ( !player->pipeline || !player->pipeline->audiobin )
10305 debug_log("pipeline is not ready. holding mute value\n");
10306 return MM_ERROR_NONE;
10309 vol_element = player->pipeline->audiobin[MMPLAYER_A_SINK].gst;
10311 /* NOTE : volume will only created when the bt is enabled */
10314 debug_log("mute : %d\n", mute);
10315 g_object_set(vol_element, "mute", mute, NULL);
10319 debug_log("volume elemnet is not created. using volume in audiosink\n");
10324 return MM_ERROR_NONE;
10328 _mmplayer_get_mute(MMHandleType hplayer, int* pmute) // @
10330 mm_player_t* player = (mm_player_t*) hplayer;
10334 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
10335 return_val_if_fail ( pmute, MM_ERROR_INVALID_ARGUMENT );
10337 /* just hold mute value if pipeline is not ready */
10338 if ( !player->pipeline || !player->pipeline->audiobin )
10340 debug_log("pipeline is not ready. returning stored value\n");
10341 *pmute = player->sound.mute;
10342 return MM_ERROR_NONE;
10345 *pmute = player->sound.mute;
10349 return MM_ERROR_NONE;
10353 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
10355 mm_player_t* player = (mm_player_t*) hplayer;
10359 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
10361 player->video_stream_changed_cb = callback;
10362 player->video_stream_changed_cb_user_param = user_param;
10363 debug_log("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
10367 return MM_ERROR_NONE;
10371 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
10373 mm_player_t* player = (mm_player_t*) hplayer;
10377 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
10379 player->audio_stream_changed_cb = callback;
10380 player->audio_stream_changed_cb_user_param = user_param;
10381 debug_log("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
10385 return MM_ERROR_NONE;
10389 _mmplayer_set_audiostream_cb_ex(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback_ex callback, void *user_param) // @
10391 mm_player_t* player = (mm_player_t*) hplayer;
10395 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
10397 player->audio_stream_render_cb_ex = callback;
10398 player->audio_stream_cb_user_param = user_param;
10399 player->audio_stream_sink_sync = sync;
10400 debug_log("Audio Stream cb Handle value is %p : %p audio_stream_sink_sync : %d\n", player, player->audio_stream_render_cb_ex, player->audio_stream_sink_sync);
10404 return MM_ERROR_NONE;
10408 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param) // @
10410 mm_player_t* player = (mm_player_t*) hplayer;
10414 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
10416 player->video_stream_cb = callback;
10417 player->video_stream_cb_user_param = user_param;
10418 player->use_video_stream = TRUE;
10419 debug_log("Stream cb Handle value is %p : %p\n", player, player->video_stream_cb);
10423 return MM_ERROR_NONE;
10427 _mmplayer_set_audiostream_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param) // @
10429 mm_player_t* player = (mm_player_t*) hplayer;
10433 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
10435 player->audio_stream_cb = callback;
10436 player->audio_stream_cb_user_param = user_param;
10437 debug_log("Audio Stream cb Handle value is %p : %p\n", player, player->audio_stream_cb);
10441 return MM_ERROR_NONE;
10444 // set prepare size
10446 _mmplayer_set_prepare_buffering_time(MMHandleType hplayer, int second)
10448 mm_player_t* player = (mm_player_t*) hplayer;
10452 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
10454 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL)
10455 return MM_ERROR_PLAYER_INVALID_STATE;
10457 debug_log("pre buffer size : %d sec\n", second);
10461 debug_error("bad size value\n");
10462 return MM_ERROR_INVALID_ARGUMENT;
10465 if (player->streamer == NULL)
10467 player->streamer = __mm_player_streaming_create();
10468 __mm_player_streaming_initialize(player->streamer);
10471 player->streamer->buffering_req.initial_second = second;
10475 return MM_ERROR_NONE;
10478 // set runtime mode
10480 _mmplayer_set_runtime_buffering_mode(MMHandleType hplayer, MMPlayerBufferingMode mode, int second)
10482 mm_player_t* player = (mm_player_t*) hplayer;
10486 return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10488 debug_log("mode %d\n", mode);
10490 if ((mode < 0) || (mode > MM_PLAYER_BUFFERING_MODE_MAX) ||
10491 ((mode == MM_PLAYER_BUFFERING_MODE_FIXED) && (second <= 0)))
10492 return MM_ERROR_INVALID_ARGUMENT;
10494 if (player->streamer == NULL)
10496 player->streamer = __mm_player_streaming_create();
10497 __mm_player_streaming_initialize(player->streamer);
10500 player->streamer->buffering_req.mode = mode;
10502 if ((second > 0) &&
10503 ((mode == MM_PLAYER_BUFFERING_MODE_FIXED) ||
10504 (mode == MM_PLAYER_BUFFERING_MODE_ADAPTIVE)))
10505 player->streamer->buffering_req.runtime_second = second;
10509 return MM_ERROR_NONE;
10513 _mmplayer_set_videoframe_render_error_cb(MMHandleType hplayer, mm_player_video_frame_render_error_callback callback, void *user_param) // @
10515 mm_player_t* player = (mm_player_t*) hplayer;
10519 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
10520 return_val_if_fail ( callback, MM_ERROR_INVALID_ARGUMENT );
10522 player->video_frame_render_error_cb = callback;
10523 player->video_frame_render_error_cb_user_param = user_param;
10525 debug_log("Video frame render error cb Handle value is %p : %p\n", player, player->video_frame_render_error_cb);
10529 return MM_ERROR_NONE;
10533 __mmplayer_start_streaming_ext(mm_player_t *player)
10535 gint ret = MM_ERROR_NONE;
10538 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
10540 if (MMPLAYER_IS_HTTP_PD(player))
10542 if ( !player->pd_downloader )
10544 ret = __mmplayer_realize_streaming_ext(player);
10546 if ( ret != MM_ERROR_NONE)
10548 debug_error ("failed to realize streaming ext\n");
10553 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI)
10555 ret = _mmplayer_start_pd_downloader ((MMHandleType)player);
10558 debug_error ("ERROR while starting PD...\n");
10559 return MM_ERROR_PLAYER_NOT_INITIALIZED;
10561 ret = MM_ERROR_NONE;
10570 _mmplayer_start(MMHandleType hplayer) // @
10572 mm_player_t* player = (mm_player_t*) hplayer;
10573 gint ret = MM_ERROR_NONE;
10577 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
10579 /* check current state */
10580 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_START );
10582 ret = _mmplayer_asm_set_state(hplayer, ASM_STATE_PLAYING, TRUE);
10583 if ( ret != MM_ERROR_NONE )
10585 debug_error("failed to set asm state to PLAYING\n");
10589 /* NOTE : we should check and create pipeline again if not created as we destroy
10590 * whole pipeline when stopping in streamming playback
10592 if ( ! player->pipeline )
10594 ret = __gst_realize( player );
10595 if ( MM_ERROR_NONE != ret )
10597 debug_error("failed to realize before starting. only in streamming\n");
10603 ret = __mmplayer_start_streaming_ext(player);
10604 if ( ret != MM_ERROR_NONE )
10606 debug_error("failed to start streaming ext \n");
10609 /* start pipeline */
10610 ret = __gst_start( player );
10611 if ( ret != MM_ERROR_NONE )
10613 debug_error("failed to start player.\n");
10621 /* NOTE: post "not supported codec message" to application
10622 * when one codec is not found during AUTOPLUGGING in MSL.
10623 * So, it's separated with error of __mmplayer_gst_callback().
10624 * And, if any codec is not found, don't send message here.
10625 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
10628 __mmplayer_handle_missed_plugin(mm_player_t* player)
10630 MMMessageParamType msg_param;
10631 memset (&msg_param, 0, sizeof(MMMessageParamType));
10632 gboolean post_msg_direct = FALSE;
10636 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10638 debug_log("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
10639 player->not_supported_codec, player->can_support_codec);
10641 if( player->not_found_demuxer )
10643 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
10644 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
10646 MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param );
10647 MMPLAYER_FREEIF(msg_param.data);
10649 return MM_ERROR_NONE;
10652 if (player->not_supported_codec)
10654 if ( player->can_support_codec ) // There is one codec to play
10656 post_msg_direct = TRUE;
10660 if ( player->pipeline->audiobin ) // Some content has only PCM data in container.
10661 post_msg_direct = TRUE;
10664 if ( post_msg_direct )
10666 MMMessageParamType msg_param;
10667 memset (&msg_param, 0, sizeof(MMMessageParamType));
10669 if ( player->not_supported_codec == MISSING_PLUGIN_AUDIO )
10671 debug_warning("not found AUDIO codec, posting error code to application.\n");
10673 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
10674 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
10676 else if ( player->not_supported_codec == MISSING_PLUGIN_VIDEO )
10678 debug_warning("not found VIDEO codec, posting error code to application.\n");
10680 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
10681 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
10684 MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param );
10686 MMPLAYER_FREEIF(msg_param.data);
10688 return MM_ERROR_NONE;
10690 else // no any supported codec case
10692 debug_warning("not found any codec, posting error code to application.\n");
10694 if ( player->not_supported_codec == MISSING_PLUGIN_AUDIO )
10696 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
10697 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
10701 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
10702 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
10705 MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param );
10707 MMPLAYER_FREEIF(msg_param.data);
10713 return MM_ERROR_NONE;
10716 static void __mmplayer_check_pipeline(mm_player_t* player)
10718 GstState element_state = GST_STATE_VOID_PENDING;
10719 GstState element_pending_state = GST_STATE_VOID_PENDING;
10721 int ret = MM_ERROR_NONE;
10723 if (player->gapless.reconfigure)
10725 debug_warning("pipeline is under construction.\n");
10727 MMPLAYER_PLAYBACK_LOCK(player);
10728 MMPLAYER_PLAYBACK_UNLOCK(player);
10730 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT ( player );
10732 /* wait for state transition */
10733 ret = gst_element_get_state( player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND );
10735 if ( ret == GST_STATE_CHANGE_FAILURE )
10737 debug_error("failed to change pipeline state within %d sec\n", timeout );
10742 /* NOTE : it should be able to call 'stop' anytime*/
10744 _mmplayer_stop(MMHandleType hplayer) // @
10746 mm_player_t* player = (mm_player_t*)hplayer;
10747 int ret = MM_ERROR_NONE;
10751 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
10753 /* check current state */
10754 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_STOP );
10756 /* check pipline building state */
10757 __mmplayer_check_pipeline(player);
10758 player->gapless.start_time = 0;
10760 /* NOTE : application should not wait for EOS after calling STOP */
10761 __mmplayer_cancel_eos_timer( player );
10763 __mmplayer_unrealize_streaming_ext(player);
10766 player->doing_seek = FALSE;
10768 /* stop pipeline */
10769 ret = __gst_stop( player );
10771 if ( ret != MM_ERROR_NONE )
10773 debug_error("failed to stop player.\n");
10782 _mmplayer_pause(MMHandleType hplayer) // @
10784 mm_player_t* player = (mm_player_t*)hplayer;
10785 gint64 pos_msec = 0;
10786 gboolean async = FALSE;
10787 gint ret = MM_ERROR_NONE;
10791 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
10793 /* check current state */
10794 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_PAUSE );
10796 /* check pipline building state */
10797 __mmplayer_check_pipeline(player);
10799 switch (MMPLAYER_CURRENT_STATE(player))
10801 case MM_PLAYER_STATE_READY:
10803 /* check prepare async or not.
10804 * In the case of streaming playback, it's recommned to avoid blocking wait.
10806 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
10807 debug_log("prepare working mode : %s", (async ? "async" : "sync"));
10811 case MM_PLAYER_STATE_PLAYING:
10813 /* NOTE : store current point to overcome some bad operation
10814 * ( returning zero when getting current position in paused state) of some
10817 if ( !gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec))
10818 debug_warning("getting current position failed in paused\n");
10820 player->last_position = pos_msec;
10825 /* pause pipeline */
10826 ret = __gst_pause( player, async );
10828 if ( ret != MM_ERROR_NONE )
10830 debug_error("failed to pause player. ret : 0x%x\n", ret);
10839 _mmplayer_resume(MMHandleType hplayer)
10841 mm_player_t* player = (mm_player_t*)hplayer;
10842 int ret = MM_ERROR_NONE;
10843 gboolean async = FALSE;
10847 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
10849 ret = _mmplayer_asm_set_state(hplayer, ASM_STATE_PLAYING, TRUE);
10852 debug_error("failed to set asm state to PLAYING\n");
10856 /* check current state */
10857 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_RESUME );
10859 ret = __gst_resume( player, async );
10861 if ( ret != MM_ERROR_NONE )
10863 debug_error("failed to resume player.\n");
10872 __mmplayer_set_play_count(mm_player_t* player, gint count)
10874 MMHandleType attrs = 0;
10878 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
10880 attrs = MMPLAYER_GET_ATTRS(player);
10883 debug_error("fail to get attributes.\n");
10884 return MM_ERROR_PLAYER_INTERNAL;
10887 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
10888 if ( mmf_attrs_commit ( attrs ) ) /* return -1 if error */
10889 debug_error("failed to commit\n");
10893 return MM_ERROR_NONE;
10897 _mmplayer_activate_section_repeat(MMHandleType hplayer, unsigned long start, unsigned long end)
10899 mm_player_t* player = (mm_player_t*)hplayer;
10900 gint64 start_pos = 0;
10901 gint64 end_pos = 0;
10902 gint infinity = -1;
10906 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
10907 return_val_if_fail ( end <= GST_TIME_AS_MSECONDS(player->duration), MM_ERROR_INVALID_ARGUMENT );
10909 player->section_repeat = TRUE;
10910 player->section_repeat_start = start;
10911 player->section_repeat_end = end;
10913 start_pos = player->section_repeat_start * G_GINT64_CONSTANT(1000000);
10914 end_pos = player->section_repeat_end * G_GINT64_CONSTANT(1000000);
10916 __mmplayer_set_play_count( player, infinity );
10918 if ( (!__gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
10919 player->playback_rate,
10921 ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ),
10922 GST_SEEK_TYPE_SET, start_pos,
10923 GST_SEEK_TYPE_SET, end_pos)))
10925 debug_error("failed to activate section repeat\n");
10927 return MM_ERROR_PLAYER_SEEK;
10930 debug_log("succeeded to set section repeat from %d to %d\n",
10931 player->section_repeat_start, player->section_repeat_end);
10935 return MM_ERROR_NONE;
10939 __mmplayer_set_pcm_extraction(mm_player_t* player)
10941 gint64 start_nsec = 0;
10942 gint64 end_nsec = 0;
10943 gint64 dur_nsec = 0;
10944 gint64 dur_msec = 0;
10945 int required_start = 0;
10946 int required_end = 0;
10951 return_val_if_fail( player, FALSE );
10953 mm_attrs_multiple_get(player->attrs,
10955 "pcm_extraction_start_msec", &required_start,
10956 "pcm_extraction_end_msec", &required_end,
10959 debug_log("pcm extraction required position is from [%d] to [%d] (msec)\n", required_start, required_end);
10961 if (required_start == 0 && required_end == 0)
10963 debug_log("extracting entire stream");
10964 return MM_ERROR_NONE;
10966 else if (required_start < 0 || required_start > required_end || required_end < 0 )
10968 debug_log("invalid range for pcm extraction");
10969 return MM_ERROR_INVALID_ARGUMENT;
10973 ret = gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec);
10976 debug_error("failed to get duration");
10977 return MM_ERROR_PLAYER_INTERNAL;
10979 dur_msec = GST_TIME_AS_MSECONDS(dur_nsec);
10981 if (dur_msec < required_end) // FIXME
10983 debug_log("invalid end pos for pcm extraction");
10984 return MM_ERROR_INVALID_ARGUMENT;
10987 start_nsec = required_start * G_GINT64_CONSTANT(1000000);
10988 end_nsec = required_end * G_GINT64_CONSTANT(1000000);
10990 if ( (!__gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
10993 ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ),
10994 GST_SEEK_TYPE_SET, start_nsec,
10995 GST_SEEK_TYPE_SET, end_nsec)))
10997 debug_error("failed to seek for pcm extraction\n");
10999 return MM_ERROR_PLAYER_SEEK;
11002 debug_log("succeeded to set up segment extraction from [%llu] to [%llu] (nsec)\n", start_nsec, end_nsec);
11006 return MM_ERROR_NONE;
11010 _mmplayer_deactivate_section_repeat(MMHandleType hplayer)
11012 mm_player_t* player = (mm_player_t*)hplayer;
11013 gint64 cur_pos = 0;
11018 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
11020 player->section_repeat = FALSE;
11022 __mmplayer_set_play_count( player, onetime );
11024 gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_pos);
11026 if ( (!__gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
11029 ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ),
11030 GST_SEEK_TYPE_SET, cur_pos,
11031 GST_SEEK_TYPE_SET, player->duration )))
11033 debug_error("failed to deactivate section repeat\n");
11035 return MM_ERROR_PLAYER_SEEK;
11040 return MM_ERROR_NONE;
11044 _mmplayer_set_playspeed(MMHandleType hplayer, float rate)
11046 mm_player_t* player = (mm_player_t*)hplayer;
11047 signed long long pos_msec = 0;
11048 int ret = MM_ERROR_NONE;
11050 signed long long start = 0, stop = 0;
11051 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
11054 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
11055 return_val_if_fail ( !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API );
11057 /* The sound of video is not supported under 0.0 and over 2.0. */
11058 if(rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN)
11060 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
11063 _mmplayer_set_mute(hplayer, mute);
11065 if (player->playback_rate == rate)
11066 return MM_ERROR_NONE;
11068 /* If the position is reached at start potion during fast backward, EOS is posted.
11069 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
11071 player->playback_rate = rate;
11073 current_state = MMPLAYER_CURRENT_STATE(player);
11075 if ( current_state != MM_PLAYER_STATE_PAUSED )
11076 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
11078 debug_log ("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS (pos_msec), ret, current_state);
11080 if ( ( current_state == MM_PLAYER_STATE_PAUSED )
11082 //|| ( player->last_position != 0 && pos_msec == 0 ) )
11084 debug_warning("returning last point : %lld\n", player->last_position );
11085 pos_msec = player->last_position;
11092 stop = GST_CLOCK_TIME_NONE;
11096 start = GST_CLOCK_TIME_NONE;
11099 if ((!gst_element_seek (player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
11102 ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ),
11103 GST_SEEK_TYPE_SET, start,
11104 GST_SEEK_TYPE_SET, stop)))
11106 debug_error("failed to set speed playback\n");
11107 return MM_ERROR_PLAYER_SEEK;
11110 debug_log("succeeded to set speed playback as %0.1f\n", rate);
11114 return MM_ERROR_NONE;;
11118 _mmplayer_set_position(MMHandleType hplayer, int format, int position) // @
11120 mm_player_t* player = (mm_player_t*)hplayer;
11121 int ret = MM_ERROR_NONE;
11125 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
11127 ret = __gst_set_position ( player, format, (unsigned long)position, FALSE );
11135 _mmplayer_get_position(MMHandleType hplayer, int format, unsigned long *position) // @
11137 mm_player_t* player = (mm_player_t*)hplayer;
11138 int ret = MM_ERROR_NONE;
11140 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
11142 ret = __gst_get_position ( player, format, position );
11148 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos) // @
11150 mm_player_t* player = (mm_player_t*)hplayer;
11151 int ret = MM_ERROR_NONE;
11153 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
11155 ret = __gst_get_buffer_position ( player, format, start_pos, stop_pos );
11161 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position) // @
11163 mm_player_t* player = (mm_player_t*)hplayer;
11164 int ret = MM_ERROR_NONE;
11168 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
11170 ret = __gst_adjust_subtitle_position(player, format, position);
11177 _mmplayer_adjust_video_postion(MMHandleType hplayer, int offset) // @
11179 mm_player_t* player = (mm_player_t*)hplayer;
11180 int ret = MM_ERROR_NONE;
11184 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
11186 ret = __gst_adjust_video_position(player, offset);
11194 __mmplayer_is_midi_type( gchar* str_caps)
11196 if ( ( g_strrstr(str_caps, "audio/midi") ) ||
11197 ( g_strrstr(str_caps, "application/x-gst_ff-mmf") ) ||
11198 ( g_strrstr(str_caps, "application/x-smaf") ) ||
11199 ( g_strrstr(str_caps, "audio/x-imelody") ) ||
11200 ( g_strrstr(str_caps, "audio/mobile-xmf") ) ||
11201 ( g_strrstr(str_caps, "audio/xmf") ) ||
11202 ( g_strrstr(str_caps, "audio/mxmf") ) )
11204 debug_log("midi\n");
11213 __mmplayer_is_only_mp3_type (gchar *str_caps)
11215 if (g_strrstr(str_caps, "application/x-id3") ||
11216 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
11224 __mmplayer_set_audio_attrs (mm_player_t* player, GstCaps* caps)
11226 GstStructure* caps_structure = NULL;
11227 gint samplerate = 0;
11231 return_if_fail (player && caps);
11233 caps_structure = gst_caps_get_structure(caps, 0);
11235 /* set stream information */
11236 gst_structure_get_int (caps_structure, "rate", &samplerate);
11237 mm_attrs_set_int_by_name (player->attrs, "content_audio_samplerate", samplerate);
11239 gst_structure_get_int (caps_structure, "channels", &channels);
11240 mm_attrs_set_int_by_name (player->attrs, "content_audio_channels", channels);
11242 debug_log ("audio samplerate : %d channels : %d\n", samplerate, channels);
11246 __mmplayer_update_content_type_info(mm_player_t* player)
11249 return_if_fail( player && player->type);
11251 if (__mmplayer_is_midi_type(player->type))
11253 player->bypass_audio_effect = TRUE;
11255 else if (g_strrstr(player->type, "application/x-hls"))
11257 /* If it can't know exact type when it parses uri because of redirection case,
11258 * it will be fixed by typefinder or when doing autoplugging.
11260 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
11261 if (player->streamer)
11263 player->streamer->is_adaptive_streaming = TRUE;
11264 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
11265 player->streamer->buffering_req.runtime_second = 5;
11268 else if (g_strrstr(player->type, "application/dash+xml"))
11270 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
11277 __mmplayer_typefind_have_type( GstElement *tf, guint probability, // @
11278 GstCaps *caps, gpointer data)
11280 mm_player_t* player = (mm_player_t*)data;
11281 GstPad* pad = NULL;
11285 return_if_fail( player && tf && caps );
11287 /* store type string */
11288 MMPLAYER_FREEIF(player->type);
11289 player->type = gst_caps_to_string(caps);
11291 debug_log("meida type %s found, probability %d%% / %d\n", player->type, probability, gst_caps_get_size(caps));
11293 if ( (!MMPLAYER_IS_WFD_STREAMING( player )) &&
11294 (!MMPLAYER_IS_RTSP_STREAMING( player )) &&
11295 (g_strrstr(player->type, "audio/x-raw-int")))
11297 debug_error("not support media format\n");
11299 if (player->msg_posted == FALSE)
11301 MMMessageParamType msg_param;
11302 memset (&msg_param, 0, sizeof(MMMessageParamType));
11304 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
11305 MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param );
11307 /* don't post more if one was sent already */
11308 player->msg_posted = TRUE;
11313 __mmplayer_update_content_type_info(player);
11315 pad = gst_element_get_static_pad(tf, "src");
11318 debug_error("fail to get typefind src pad.\n");
11322 if (player->use_decodebin)
11324 if(!__mmplayer_try_to_plug_decodebin( player, pad, caps ))
11326 gboolean async = FALSE;
11327 debug_error("failed to autoplug %s\n", player->type);
11329 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
11331 if ( async && player->msg_posted == FALSE )
11333 __mmplayer_handle_missed_plugin( player );
11342 if ( ! __mmplayer_try_to_plug( player, pad, caps ) )
11344 gboolean async = FALSE;
11345 debug_error("failed to autoplug %s\n", player->type);
11347 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
11349 if ( async && player->msg_posted == FALSE )
11351 __mmplayer_handle_missed_plugin( player );
11357 /* finish autopluging if no dynamic pad waiting */
11358 if( ( ! player->have_dynamic_pad) && ( ! player->has_many_types) )
11360 if ( ! MMPLAYER_IS_RTSP_STREAMING( player ) )
11362 __mmplayer_pipeline_complete( NULL, (gpointer)player );
11368 gst_object_unref( GST_OBJECT(pad) );
11375 #ifdef _MM_PLAYER_ALP_PARSER
11376 void check_name (void *data, void *user_data)
11378 mm_player_t* player = user_data;
11380 if (g_strrstr((gchar*)data, "mpegaudioparse"))
11382 debug_log("mpegaudioparse - set alp-mp3dec\n");
11383 g_object_set(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "alp-mp3dec", TRUE, NULL);
11388 static GstElement *
11389 __mmplayer_create_decodebin (mm_player_t* player)
11391 GstElement *decodebin = NULL;
11395 /* create decodebin */
11396 decodebin = gst_element_factory_make("decodebin", NULL);
11400 debug_error("fail to create decodebin\n");
11404 /* raw pad handling signal */
11405 MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
11406 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
11408 /* no-more-pad pad handling signal */
11409 MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
11410 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), player);
11412 MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
11413 G_CALLBACK(__mmplayer_gst_decode_pad_removed), player);
11415 /* This signal is emitted when a pad for which there is no further possible
11416 decoding is added to the decodebin.*/
11417 MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
11418 G_CALLBACK(__mmplayer_gst_decode_unknown_type), player );
11420 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
11421 before looking for any elements that can handle that stream.*/
11422 MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
11423 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), player);
11425 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
11426 before looking for any elements that can handle that stream.*/
11427 MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
11428 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
11430 /* This signal is emitted once decodebin has finished decoding all the data.*/
11431 MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
11432 G_CALLBACK(__mmplayer_gst_decode_drained), player);
11434 /* This signal is emitted when a element is added to the bin.*/
11435 MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
11436 G_CALLBACK(__mmplayer_gst_element_added), player);
11443 __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
11445 MMPlayerGstElement* mainbin = NULL;
11446 GstElement* decodebin = NULL;
11447 GstElement* queue2 = NULL;
11448 GstPad* sinkpad = NULL;
11449 GstPad* qsrcpad= NULL;
11450 gchar *caps_str = NULL;
11451 gint64 dur_bytes = 0L;
11452 gchar* file_buffering_path = NULL;
11453 gboolean use_file_buffer = FALSE;
11455 guint max_buffer_size_bytes = 0;
11456 gdouble init_buffering_time = (gdouble)player->streamer->buffering_req.initial_second;
11459 return_val_if_fail (player && player->pipeline && player->pipeline->mainbin, FALSE);
11461 mainbin = player->pipeline->mainbin;
11463 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
11464 (MMPLAYER_IS_HTTP_STREAMING(player)))
11466 debug_log ("creating http streaming buffering queue (queue2)\n");
11468 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)
11470 debug_error ("MMPLAYER_M_MUXED_S_BUFFER is not null\n");
11474 queue2 = gst_element_factory_make ("queue2", "queue2");
11477 debug_error ("failed to create buffering queue element\n");
11481 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2))
11483 debug_error("failed to add buffering queue\n");
11487 sinkpad = gst_element_get_static_pad(queue2, "sink");
11488 qsrcpad = gst_element_get_static_pad(queue2, "src");
11490 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad))
11492 debug_error("failed to link buffering queue\n");
11496 // if ( !MMPLAYER_IS_HTTP_LIVE_STREAMING(player))
11498 if ( !gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
11499 debug_error("fail to get duration.\n");
11501 debug_log("dur_bytes = %lld\n", dur_bytes);
11505 use_file_buffer = MMPLAYER_USE_FILE_FOR_BUFFERING(player);
11506 file_buffering_path = g_strdup(player->ini.http_file_buffer_path);
11514 /* NOTE : we cannot get any duration info from ts container in case of streaming */
11515 // if(!g_strrstr(GST_ELEMENT_NAME(sinkelement), "mpegtsdemux"))
11516 if(!g_strrstr(player->type, "video/mpegts"))
11518 max_buffer_size_bytes = (use_file_buffer)?(player->ini.http_max_size_bytes):(5*1024*1024);
11519 debug_log("max_buffer_size_bytes = %d\n", max_buffer_size_bytes);
11521 __mm_player_streaming_set_queue2(player->streamer,
11524 max_buffer_size_bytes,
11525 player->ini.http_buffering_time,
11527 player->ini.http_buffering_limit, // no meaning
11529 file_buffering_path,
11530 (guint64)dur_bytes);
11533 MMPLAYER_FREEIF(file_buffering_path);
11534 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent (queue2))
11536 debug_error("failed to sync queue2 state with parent\n");
11542 gst_object_unref(GST_OBJECT(sinkpad));
11544 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
11545 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
11549 /* create decodebin */
11550 decodebin = __mmplayer_create_decodebin(player);
11554 debug_error("can not create autoplug element\n");
11558 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin))
11560 debug_error("failed to add decodebin\n");
11564 /* to force caps on the decodebin element and avoid reparsing stuff by
11565 * typefind. It also avoids a deadlock in the way typefind activates pads in
11566 * the state change */
11567 g_object_set (decodebin, "sink-caps", caps, NULL);
11569 sinkpad = gst_element_get_static_pad(decodebin, "sink");
11571 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad))
11573 debug_error("failed to link decodebin\n");
11577 gst_object_unref(GST_OBJECT(sinkpad));
11579 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
11580 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
11582 /* set decodebin property about buffer in streaming playback. *
11583 * in case of hls, it does not need to have big buffer *
11584 * because it is kind of adaptive streaming. */
11585 if ( ((!MMPLAYER_IS_HTTP_PD(player)) &&
11586 (MMPLAYER_IS_HTTP_STREAMING(player))) || MMPLAYER_IS_DASH_STREAMING (player))
11588 guint max_size_bytes = MAX_DECODEBIN_BUFFER_BYTES;
11589 guint64 max_size_time = MAX_DECODEBIN_BUFFER_TIME;
11590 init_buffering_time = (init_buffering_time != 0)?(init_buffering_time):(player->ini.http_buffering_time);
11592 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {
11593 max_size_bytes = MAX_DECODEBIN_ADAPTIVE_BUFFER_BYTES;
11594 max_size_time = MAX_DECODEBIN_ADAPTIVE_BUFFER_TIME;
11597 g_object_set (G_OBJECT(decodebin), "use-buffering", TRUE,
11598 "high-percent", (gint)player->ini.http_buffering_limit,
11599 "low-percent", 1, // 1%
11600 "max-size-bytes", max_size_bytes,
11601 "max-size-time", (guint64)(max_size_time * GST_SECOND),
11602 "max-size-buffers", 0, NULL); // disable or automatic
11605 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin))
11607 debug_error("failed to sync decodebin state with parent\n");
11617 MMPLAYER_FREEIF( caps_str );
11620 gst_object_unref(GST_OBJECT(sinkpad));
11624 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
11625 * You need to explicitly set elements to the NULL state before
11626 * dropping the final reference, to allow them to clean up.
11628 gst_element_set_state(queue2, GST_STATE_NULL);
11630 /* And, it still has a parent "player".
11631 * You need to let the parent manage the object instead of unreffing the object directly.
11633 gst_bin_remove (GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
11634 gst_object_unref (queue2);
11640 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
11641 * You need to explicitly set elements to the NULL state before
11642 * dropping the final reference, to allow them to clean up.
11644 gst_element_set_state(decodebin, GST_STATE_NULL);
11646 /* And, it still has a parent "player".
11647 * You need to let the parent manage the object instead of unreffing the object directly.
11650 gst_bin_remove (GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
11651 gst_object_unref (decodebin);
11658 /* it will return first created element */
11660 __mmplayer_try_to_plug(mm_player_t* player, GstPad *pad, const GstCaps *caps) // @
11662 MMPlayerGstElement* mainbin = NULL;
11663 const char* mime = NULL;
11664 const GList* item = NULL;
11665 const gchar* klass = NULL;
11666 GstCaps* res = NULL;
11667 gboolean skip = FALSE;
11668 GstPad* queue_pad = NULL;
11669 GstElement* queue = NULL;
11670 GstElement *element = NULL;
11674 return_val_if_fail( player && player->pipeline && player->pipeline->mainbin, FALSE );
11676 mainbin = player->pipeline->mainbin;
11678 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
11680 /* return if we got raw output */
11681 if(g_str_has_prefix(mime, "video/x-raw") || g_str_has_prefix(mime, "audio/x-raw")
11682 || g_str_has_prefix(mime, "text/plain") ||g_str_has_prefix(mime, "text/x-pango-markup"))
11685 element = (GstElement*)gst_pad_get_parent(pad);
11686 /* NOTE : When no decoder has added during autoplugging. like a simple wave playback.
11687 * No queue will be added. I think it can caused breaking sound when playing raw audio
11688 * frames but there's no different. Decodebin also doesn't add with those wav fils.
11689 * Anyway, currentely raw-queue seems not necessary.
11692 /* NOTE : check if previously linked element is demuxer/depayloader/parse means no decoder
11693 * has linked. if so, we need to add queue for quality of output. note that
11694 * decodebin also has same problem.
11696 klass = gst_element_factory_get_klass( gst_element_get_factory(element) );
11698 /* add queue if needed */
11699 if( (g_strrstr(klass, "Demux") || g_strrstr(klass, "Depayloader")
11700 || g_strrstr(klass, "Parse")) && !g_str_has_prefix(mime, "text"))
11702 debug_log("adding raw queue\n");
11704 queue = gst_element_factory_make("queue", NULL);
11707 debug_warning("failed to create queue\n");
11712 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_READY) )
11714 debug_warning("failed to set state READY to queue\n");
11718 /* add to pipeline */
11719 if ( ! gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue) )
11721 debug_warning("failed to add queue\n");
11726 queue_pad = gst_element_get_static_pad(queue, "sink");
11728 if ( GST_PAD_LINK_OK != gst_pad_link(pad, queue_pad) )
11730 debug_warning("failed to link queue\n");
11733 gst_object_unref ( GST_OBJECT(queue_pad) );
11737 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_PAUSED) )
11739 debug_warning("failed to set state READY to queue\n");
11743 /* replace given pad to queue:src */
11744 pad = gst_element_get_static_pad(queue, "src");
11747 debug_warning("failed to get pad from queue\n");
11752 /* check if player can do start continually */
11753 MMPLAYER_CHECK_CMD_IF_EXIT(player);
11755 if(__mmplayer_link_sink(player,pad))
11756 __mmplayer_gst_decode_callback(element, pad, player);
11758 gst_object_unref( GST_OBJECT(element));
11764 item = player->factories;
11765 for(; item != NULL ; item = item->next)
11767 GstElementFactory *factory = GST_ELEMENT_FACTORY(item->data);
11773 /* filtering exclude keyword */
11774 for ( idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++ )
11776 if ( g_strrstr(GST_OBJECT_NAME (factory),
11777 player->ini.exclude_element_keyword[idx] ) )
11779 debug_warning("skipping [%s] by exculde keyword [%s]\n",
11780 GST_OBJECT_NAME (factory),
11781 player->ini.exclude_element_keyword[idx] );
11788 if ( MMPLAYER_IS_RTSP_STREAMING(player) && g_strrstr(GST_OBJECT_NAME (factory), "omx_mpeg4dec"))
11790 // omx decoder can not support mpeg4video data partitioned
11791 // rtsp streaming didn't know mpeg4video data partitioned format
11792 // so, if rtsp playback, player will skip omx_mpeg4dec.
11793 debug_warning("skipping [%s] when rtsp streaming \n",
11794 GST_OBJECT_NAME (factory));
11799 if ( skip ) continue;
11801 /* check factory class for filtering */
11802 klass = gst_element_factory_get_klass(GST_ELEMENT_FACTORY(factory));
11804 /*parsers are not required in case of external feeder*/
11805 if (g_strrstr(klass, "Codec/Parser") && MMPLAYER_IS_ES_BUFF_SRC(player))
11808 /* NOTE : msl don't need to use image plugins.
11809 * So, those plugins should be skipped for error handling.
11811 if ( g_strrstr(klass, "Codec/Decoder/Image") )
11813 debug_log("skipping [%s] by not required\n", GST_OBJECT_NAME (factory));
11817 /* check pad compatability */
11818 for(pads = gst_element_factory_get_static_pad_templates(factory);
11819 pads != NULL; pads=pads->next)
11821 GstStaticPadTemplate *temp1 = pads->data;
11822 GstCaps* static_caps = NULL;
11824 if( temp1->direction != GST_PAD_SINK
11825 || temp1->presence != GST_PAD_ALWAYS)
11828 if ( GST_IS_CAPS( &temp1->static_caps.caps) )
11830 /* using existing caps */
11831 static_caps = gst_caps_ref(temp1->static_caps.caps );
11836 static_caps = gst_caps_from_string ( temp1->static_caps.string );
11839 res = gst_caps_intersect((GstCaps*)caps, static_caps);
11840 gst_caps_unref( static_caps );
11841 static_caps = NULL;
11843 if( res && !gst_caps_is_empty(res) )
11845 GstElement *new_element;
11846 GList *elements = player->parsers;
11847 char *name_template = g_strdup(temp1->name_template);
11848 gchar *name_to_plug = GST_OBJECT_NAME(factory);
11849 gst_caps_unref(res);
11851 /* check ALP Codec can be used or not */
11852 if ((g_strrstr(klass, "Codec/Decoder/Audio")))
11854 /* consider mp3 audio only */
11855 if ( !MMPLAYER_IS_STREAMING(player) && __mmplayer_is_only_mp3_type(player->type) )
11857 /* try to use ALP decoder first instead of selected decoder */
11858 GstElement *element = NULL;
11859 GstElementFactory * element_facory;
11860 gchar *path = NULL;
11861 guint64 data_size = 0;
11862 #define MIN_THRESHOLD_SIZE 320 * 1024 // 320K
11865 mm_attrs_get_string_by_name(player->attrs, "profile_uri", &path);
11867 if (stat(path, &sb) == 0)
11869 data_size = (guint64)sb.st_size;
11871 debug_log("file size : %u", data_size);
11873 if (data_size > MIN_THRESHOLD_SIZE)
11875 debug_log("checking if ALP can be used or not");
11876 element = gst_element_factory_make("omx_mp3dec", "omx mp3 decoder");
11879 /* check availability because multi-instance is not supported */
11880 GstStateChangeReturn ret = gst_element_set_state(element, GST_STATE_READY);
11882 if (ret != GST_STATE_CHANGE_SUCCESS) // use just selected decoder
11884 gst_object_unref (element);
11886 else if (ret == GST_STATE_CHANGE_SUCCESS) // replace facotry to use omx
11889 gst_element_set_state(element, GST_STATE_NULL);
11890 gst_object_unref (element);
11892 element_facory = gst_element_factory_find("omx_mp3dec");
11893 /* replace, otherwise use selected thing instead */
11894 if (element_facory)
11896 factory = element_facory;
11897 name_to_plug = GST_OBJECT_NAME(factory);
11900 /* make parser alp mode */
11901 #ifdef _MM_PLAYER_ALP_PARSER
11902 g_list_foreach (player->parsers, check_name, player);
11909 else if ((g_strrstr(klass, "Codec/Decoder/Video")))
11911 if ( g_strrstr(GST_OBJECT_NAME(factory), "omx_") )
11913 char *env = getenv ("MM_PLAYER_HW_CODEC_DISABLE");
11916 if (strncasecmp(env, "yes", 3) == 0)
11918 debug_log("skipping [%s] by disabled\n", name_to_plug);
11919 MMPLAYER_FREEIF(name_template);
11926 debug_log("found %s to plug\n", name_to_plug);
11928 new_element = gst_element_factory_create(GST_ELEMENT_FACTORY(factory), NULL);
11929 if ( ! new_element )
11931 debug_error("failed to create element [%s]. continue with next.\n",
11932 GST_OBJECT_NAME (factory));
11934 MMPLAYER_FREEIF(name_template);
11939 /* check and skip it if it was already used. Otherwise, it can be an infinite loop
11940 * because parser can accept its own output as input.
11942 if (g_strrstr(klass, "Parser"))
11944 gchar *selected = NULL;
11946 for ( ; elements; elements = g_list_next(elements))
11948 gchar *element_name = elements->data;
11950 if (g_strrstr(element_name, name_to_plug))
11952 debug_log("but, %s already linked, so skipping it\n", name_to_plug);
11959 MMPLAYER_FREEIF(name_template);
11963 selected = g_strdup(name_to_plug);
11964 player->parsers = g_list_append(player->parsers, selected);
11967 /* store specific handles for futher control */
11968 if(g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse"))
11970 /* FIXIT : first value will be overwritten if there's more
11971 * than 1 demuxer/parser
11973 debug_log("plugged element is demuxer. take it\n");
11974 mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
11975 mainbin[MMPLAYER_M_DEMUX].gst = new_element;
11977 /*Added for multi audio support */
11978 if(g_strrstr(klass, "Demux"))
11980 mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
11981 mainbin[MMPLAYER_M_DEMUX_EX].gst = new_element;
11983 /* NOTE : workaround for bug in mpegtsdemux since doesn't emit
11984 no-more-pad signal. this may cause wrong content attributes at PAUSED state
11985 this code should be removed after mpegtsdemux is fixed */
11986 if ( g_strrstr(GST_OBJECT_NAME(factory), "mpegtsdemux") )
11988 debug_warning("force no-more-pad to TRUE since mpegtsdemux os not giving no-more-pad signal. content attributes may wrong");
11989 player->no_more_pad = TRUE;
11992 if (g_strrstr(name_to_plug, "asfdemux")) // to support trust-zone only
11994 g_object_set(mainbin[MMPLAYER_M_DEMUX_EX].gst, "file-location", player->profile.uri,NULL);
11997 else if(g_strrstr(klass, "Decoder") && __mmplayer_link_decoder(player,pad))
11999 if(mainbin[MMPLAYER_M_DEC1].gst == NULL)
12001 debug_log("plugged element is decoder. take it[MMPLAYER_M_DEC1]\n");
12002 mainbin[MMPLAYER_M_DEC1].id = MMPLAYER_M_DEC1;
12003 mainbin[MMPLAYER_M_DEC1].gst = new_element;
12005 else if(mainbin[MMPLAYER_M_DEC2].gst == NULL)
12007 debug_log("plugged element is decoder. take it[MMPLAYER_M_DEC2]\n");
12008 mainbin[MMPLAYER_M_DEC2].id = MMPLAYER_M_DEC2;
12009 mainbin[MMPLAYER_M_DEC2].gst = new_element;
12011 /* NOTE : IF one codec is found, add it to supported_codec and remove from
12012 * missing plugin. Both of them are used to check what's supported codec
12013 * before returning result of play start. And, missing plugin should be
12014 * updated here for multi track files.
12016 if(g_str_has_prefix(mime, "video"))
12018 GstPad *src_pad = NULL;
12019 GstPadTemplate *pad_templ = NULL;
12020 GstCaps *caps = NULL;
12021 gchar *caps_str = NULL;
12023 debug_log("found VIDEO decoder\n");
12024 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
12025 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
12027 src_pad = gst_element_get_static_pad (new_element, "src");
12028 pad_templ = gst_pad_get_pad_template (src_pad);
12029 caps = GST_PAD_TEMPLATE_CAPS(pad_templ);
12031 caps_str = gst_caps_to_string(caps);
12034 MMPLAYER_FREEIF( caps_str );
12035 gst_object_unref (src_pad);
12037 else if (g_str_has_prefix(mime, "audio"))
12039 debug_log("found AUDIO decoder\n");
12040 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
12041 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
12045 if ( ! __mmplayer_close_link(player, pad, new_element,
12046 name_template,gst_element_factory_get_static_pad_templates(factory)) )
12048 MMPLAYER_FREEIF(name_template);
12049 if (player->keep_detecting_vcodec)
12052 /* Link is failed even though a supportable codec is found. */
12053 __mmplayer_check_not_supported_codec(player, klass, mime);
12055 debug_error("failed to call _close_link\n");
12059 MMPLAYER_FREEIF(name_template);
12063 gst_caps_unref(res);
12068 /* There is no available codec. */
12069 __mmplayer_check_not_supported_codec(player, klass, mime);
12077 gst_object_unref( queue );
12080 gst_object_unref( queue_pad );
12083 gst_object_unref ( element );
12090 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
12094 return_val_if_fail(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
12095 return_val_if_fail ( mime, MM_ERROR_INVALID_ARGUMENT );
12097 debug_log("class : %s, mime : %s \n", factory_class, mime );
12099 /* add missing plugin */
12100 /* NOTE : msl should check missing plugin for image mime type.
12101 * Some motion jpeg clips can have playable audio track.
12102 * So, msl have to play audio after displaying popup written video format not supported.
12104 if ( !( player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst ) )
12106 if ( !( player->can_support_codec | player->videodec_linked | player->audiodec_linked ) )
12108 debug_log("not found demuxer\n");
12109 player->not_found_demuxer = TRUE;
12110 player->unlinked_demuxer_mime = g_strdup_printf ( "%s", mime );
12116 if( !g_strrstr(factory_class, "Demuxer"))
12118 if( ( g_str_has_prefix(mime, "video") ) ||( g_str_has_prefix(mime, "image") ) )
12120 debug_log("can support codec=%d, vdec_linked=%d, adec_linked=%d\n",
12121 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
12123 /* check that clip have multi tracks or not */
12124 if ( ( player->can_support_codec & FOUND_PLUGIN_VIDEO ) && ( player->videodec_linked ) )
12126 debug_log("video plugin is already linked\n");
12130 debug_warning("add VIDEO to missing plugin\n");
12131 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
12134 else if ( g_str_has_prefix(mime, "audio") )
12136 if ( ( player->can_support_codec & FOUND_PLUGIN_AUDIO ) && ( player->audiodec_linked ) )
12138 debug_log("audio plugin is already linked\n");
12142 debug_warning("add AUDIO to missing plugin\n");
12143 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
12151 return MM_ERROR_NONE;
12156 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
12158 mm_player_t* player = (mm_player_t*)data;
12162 return_if_fail( player );
12164 /* remove fakesink. */
12165 if ( !__mmplayer_gst_remove_fakesink( player,
12166 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]) )
12168 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
12169 * signaling mechanism ( pad-added, no-more-pad, new-decoded-pad ) from various
12170 * source element are not same. To overcome this situation, this function will called
12171 * several places and several times. Therefore, this is not an error case.
12176 debug_log("pipeline has completely constructed\n");
12178 if (( player->ini.async_start ) &&
12179 ( player->msg_posted == FALSE ) &&
12180 ( player->cmd >= MMPLAYER_COMMAND_START ))
12182 __mmplayer_handle_missed_plugin( player );
12185 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-complete" );
12189 __mmplayer_verify_next_play_path(mm_player_t *player)
12191 MMHandleType attrs = 0;
12192 MMPlayerParseProfile profile;
12193 gint uri_idx = 0, check_cnt = 0;
12195 gint mode = MM_PLAYER_PD_MODE_NONE;
12197 guint num_of_list = 0;
12201 debug_log("checking for gapless play");
12203 if (player->pipeline->textbin)
12205 debug_error("subtitle path is enabled. gapless play is not supported.\n");
12209 attrs = MMPLAYER_GET_ATTRS(player);
12212 debug_error("fail to get attributes.\n");
12216 /* seamless playback is supported in case of audio only */
12217 mm_attrs_get_int_by_name(attrs, "content_video_found", &mode);
12220 debug_log("video found");
12224 if (mm_attrs_get_int_by_name (attrs, "pd_mode", &mode) == MM_ERROR_NONE)
12228 debug_warning("pd mode\n");
12233 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
12235 debug_error("can not get play count\n");
12238 num_of_list = g_list_length(player->uri_info.uri_list);
12240 debug_log("repeat count = %d, num_of_list = %d\n", count, num_of_list);
12242 if ( num_of_list == 0 )
12244 if (mm_attrs_get_string_by_name(player->attrs, "profile_uri", &uri) != MM_ERROR_NONE)
12246 debug_error("can not get profile_uri\n");
12252 debug_error("uri list is empty.\n");
12256 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
12257 debug_log("add original path : %s ", uri);
12263 uri_idx = player->uri_info.uri_idx;
12269 if (check_cnt > num_of_list)
12271 debug_error("there is no valid uri.");
12275 debug_log("uri idx : %d / %d\n", uri_idx, num_of_list);
12277 if ( uri_idx < num_of_list-1 )
12283 if ((count <= 1) && (count != -1))
12285 debug_log("no repeat.");
12288 else if ( count > 1 ) /* decrease play count */
12290 /* we successeded to rewind. update play count and then wait for next EOS */
12293 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
12295 /* commit attribute */
12296 if ( mmf_attrs_commit ( attrs ) )
12298 debug_error("failed to commit attribute\n");
12302 /* count < 0 : repeat continually */
12306 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
12307 debug_log("uri idx : %d, uri = %s\n", uri_idx, uri);
12311 debug_warning("next uri does not exist\n");
12315 if (__mmfplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE)
12317 debug_error("failed to parse profile\n");
12321 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
12322 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP))
12324 debug_warning("uri type is not supported (%d).", profile.uri_type);
12331 player->uri_info.uri_idx = uri_idx;
12332 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
12335 if (mmf_attrs_commit(player->attrs))
12337 debug_error("failed to commit.\n");
12341 debug_log("next uri %s (%d)\n", uri, uri_idx);
12347 debug_error("unable to play next path. EOS will be posted soon.\n");
12352 __mmplayer_initialize_next_play(mm_player_t *player)
12358 player->smooth_streaming = FALSE;
12359 player->videodec_linked = 0;
12360 player->audiodec_linked = 0;
12361 player->videosink_linked = 0;
12362 player->audiosink_linked = 0;
12363 player->textsink_linked = 0;
12364 player->is_external_subtitle_present = FALSE;
12365 player->not_supported_codec = MISSING_PLUGIN_NONE;
12366 player->can_support_codec = FOUND_PLUGIN_NONE;
12367 player->pending_seek.is_pending = FALSE;
12368 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
12369 player->pending_seek.pos = 0;
12370 player->msg_posted = FALSE;
12371 player->has_many_types = FALSE;
12372 player->no_more_pad = FALSE;
12373 player->is_drm_file = FALSE;
12374 player->not_found_demuxer = 0;
12375 player->doing_seek = FALSE;
12376 player->max_audio_channels = 0;
12377 player->is_subtitle_force_drop = FALSE;
12378 player->play_subtitle = FALSE;
12379 player->use_textoverlay = FALSE;
12380 player->adjust_subtitle_pos = 0;
12382 player->updated_bitrate_count = 0;
12383 player->total_bitrate = 0;
12384 player->updated_maximum_bitrate_count = 0;
12385 player->total_maximum_bitrate = 0;
12387 _mmplayer_track_initialize(player);
12389 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++)
12391 player->bitrate[i] = 0;
12392 player->maximum_bitrate[i] = 0;
12395 if (player->v_stream_caps)
12397 gst_caps_unref(player->v_stream_caps);
12398 player->v_stream_caps = NULL;
12401 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
12402 mm_attrs_set_int_by_name(player->attrs, "content_audio_found", 0);
12404 /* clean found parsers */
12405 if (player->parsers)
12407 GList *parsers = player->parsers;
12408 for ( ;parsers ; parsers = g_list_next(parsers))
12410 gchar *name = parsers->data;
12411 MMPLAYER_FREEIF(name);
12413 g_list_free(player->parsers);
12414 player->parsers = NULL;
12417 /* clean found audio decoders */
12418 if (player->audio_decoders)
12420 GList *a_dec = player->audio_decoders;
12421 for ( ;a_dec ; a_dec = g_list_next(a_dec))
12423 gchar *name = a_dec->data;
12424 MMPLAYER_FREEIF(name);
12426 g_list_free(player->audio_decoders);
12427 player->audio_decoders = NULL;
12434 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
12436 MMPlayerGstElement *mainbin = NULL;
12437 MMMessageParamType msg_param = {0,};
12438 GstElement *element = NULL;
12439 MMHandleType attrs = 0;
12441 enum MainElementID elemId = MMPLAYER_M_NUM;
12445 if ((player == NULL) ||
12446 (player->pipeline == NULL) ||
12447 (player->pipeline->mainbin == NULL))
12449 debug_error("player is null.\n");
12453 mainbin = player->pipeline->mainbin;
12454 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
12456 attrs = MMPLAYER_GET_ATTRS(player);
12459 debug_error("fail to get attributes.\n");
12463 /* Initialize Player values */
12464 __mmplayer_initialize_next_play(player);
12466 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
12468 if (__mmfplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE)
12470 debug_error("failed to parse profile\n");
12471 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
12475 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
12476 (MMPLAYER_URL_HAS_HLS_SUFFIX(player)))
12478 debug_error("it's dash or hls. not support.");
12479 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
12484 switch ( player->profile.uri_type )
12487 case MM_PLAYER_URI_TYPE_FILE:
12489 debug_log("using filesrc for 'file://' handler.\n");
12491 element = gst_element_factory_make("filesrc", "source");
12495 debug_error("failed to create filesrc\n");
12499 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
12502 case MM_PLAYER_URI_TYPE_URL_HTTP:
12504 gchar *user_agent, *proxy, *cookies, **cookie_list;
12505 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
12506 user_agent = proxy = cookies = NULL;
12507 cookie_list = NULL;
12509 element = gst_element_factory_make(player->ini.name_of_httpsrc, "http_streaming_source");
12512 debug_error("failed to create http streaming source element[%s].\n", player->ini.name_of_httpsrc);
12515 debug_log("using http streamming source [%s].\n", player->ini.name_of_httpsrc);
12517 /* get attribute */
12518 mm_attrs_get_string_by_name ( attrs, "streaming_cookie", &cookies );
12519 mm_attrs_get_string_by_name ( attrs, "streaming_user_agent", &user_agent );
12520 mm_attrs_get_string_by_name ( attrs, "streaming_proxy", &proxy );
12521 mm_attrs_get_int_by_name ( attrs, "streaming_timeout", &http_timeout );
12523 if ((http_timeout == DEFAULT_HTTP_TIMEOUT) &&
12524 (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT))
12526 debug_log("get timeout from ini\n");
12527 http_timeout = player->ini.http_timeout;
12530 /* get attribute */
12531 secure_debug_log("location : %s\n", player->profile.uri);
12532 secure_debug_log("cookies : %s\n", cookies);
12533 secure_debug_log("proxy : %s\n", proxy);
12534 secure_debug_log("user_agent : %s\n", user_agent);
12535 debug_log("timeout : %d\n", http_timeout);
12537 /* setting property to streaming source */
12538 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
12539 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
12540 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
12542 /* check if prosy is vailid or not */
12543 if ( util_check_valid_url ( proxy ) )
12544 g_object_set(G_OBJECT(element), "proxy", proxy, NULL);
12545 /* parsing cookies */
12546 if ( ( cookie_list = util_get_cookie_list ((const char*)cookies) ) )
12547 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
12549 g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL);
12553 debug_error("not support uri type %d\n", player->profile.uri_type);
12559 debug_error("no source element was created.\n");
12563 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE)
12565 debug_error("failed to add source element to pipeline\n");
12566 gst_object_unref(GST_OBJECT(element));
12571 /* take source element */
12572 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
12573 mainbin[MMPLAYER_M_SRC].gst = element;
12577 if (MMPLAYER_IS_HTTP_STREAMING(player))
12579 if (player->streamer == NULL)
12581 player->streamer = __mm_player_streaming_create();
12582 __mm_player_streaming_initialize(player->streamer);
12585 elemId = MMPLAYER_M_TYPEFIND;
12586 element = gst_element_factory_make("typefind", "typefinder");
12587 MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
12588 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player );
12592 elemId = MMPLAYER_M_AUTOPLUG;
12593 element = __mmplayer_create_decodebin(player);
12596 /* check autoplug element is OK */
12599 debug_error("can not create element (%d)\n", elemId);
12603 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE)
12605 debug_error("failed to add sinkbin to pipeline\n");
12606 gst_object_unref(GST_OBJECT(element));
12611 mainbin[elemId].id = elemId;
12612 mainbin[elemId].gst = element;
12614 if ( gst_element_link (mainbin[MMPLAYER_M_SRC].gst, mainbin[elemId].gst) == FALSE )
12616 debug_error("Failed to link src - autoplug (or typefind)\n");
12620 if (gst_element_set_state (mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE)
12622 debug_error("Failed to change state of src element\n");
12626 if (!MMPLAYER_IS_HTTP_STREAMING(player))
12628 if (gst_element_set_state (mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE)
12630 debug_error("Failed to change state of decodebin\n");
12636 if (gst_element_set_state (mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE)
12638 debug_error("Failed to change state of src element\n");
12643 player->gapless.stream_changed = TRUE;
12644 player->gapless.running = TRUE;
12649 MMPLAYER_PLAYBACK_UNLOCK(player);
12651 if (!player->msg_posted)
12653 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
12654 player->msg_posted = TRUE;
12660 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
12662 mm_player_selector_t *selector = &player->selector[type];
12663 MMPlayerGstElement *sinkbin = NULL;
12664 enum MainElementID selectorId = MMPLAYER_M_NUM;
12665 enum MainElementID sinkId = MMPLAYER_M_NUM;
12666 GstPad *srcpad = NULL;
12667 GstPad *sinkpad = NULL;
12670 return_val_if_fail (player, FALSE);
12672 debug_log("type %d", type);
12676 case MM_PLAYER_TRACK_TYPE_AUDIO:
12677 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
12678 sinkId = MMPLAYER_A_BIN;
12679 sinkbin = player->pipeline->audiobin;
12681 case MM_PLAYER_TRACK_TYPE_TEXT:
12682 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
12683 sinkId = MMPLAYER_T_BIN;
12684 sinkbin = player->pipeline->textbin;
12687 debug_error("requested type is not supportable");
12692 if (player->pipeline->mainbin[selectorId].gst)
12696 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
12698 if (selector->event_probe_id != 0)
12699 gst_pad_remove_probe (srcpad, selector->event_probe_id);
12700 selector->event_probe_id = 0;
12702 if ((sinkbin) && (sinkbin[sinkId].gst))
12704 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
12706 if (srcpad && sinkpad)
12708 /* after getting drained signal there is no data flows, so no need to do pad_block */
12709 debug_log("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
12710 gst_pad_unlink (srcpad, sinkpad);
12713 gst_object_unref (sinkpad);
12716 gst_object_unref (srcpad);
12719 debug_log("selector release");
12721 /* release and unref requests pad from the selector */
12722 for (n = 0; n < selector->channels->len; n++)
12724 GstPad *sinkpad = g_ptr_array_index (selector->channels, n);
12725 gst_element_release_request_pad ((player->pipeline->mainbin[selectorId].gst), sinkpad);
12727 g_ptr_array_set_size (selector->channels, 0);
12729 gst_element_set_state (player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
12730 gst_bin_remove (GST_BIN_CAST (player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
12732 player->pipeline->mainbin[selectorId].gst = NULL;
12740 __mmplayer_deactivate_old_path(mm_player_t *player)
12743 return_if_fail ( player );
12745 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
12746 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT)))
12748 debug_error("deactivate selector error");
12752 _mmplayer_track_destroy(player);
12753 __mmplayer_release_signal_connection( player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG );
12755 if (player->streamer)
12757 __mm_player_streaming_deinitialize (player->streamer);
12758 __mm_player_streaming_destroy(player->streamer);
12759 player->streamer = NULL;
12762 MMPLAYER_PLAYBACK_LOCK(player);
12763 g_cond_signal( &player->next_play_thread_cond );
12770 if (!player->msg_posted)
12772 MMMessageParamType msg = {0,};
12775 msg.code = MM_ERROR_PLAYER_INTERNAL;
12776 debug_error("next_uri_play> deactivate error");
12778 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
12779 player->msg_posted = TRUE;
12784 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
12786 int result = MM_ERROR_NONE;
12787 mm_player_t* player = (mm_player_t*) hplayer;
12790 return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12792 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
12793 if (mmf_attrs_commit(player->attrs))
12795 debug_error("failed to commit the original uri.\n");
12796 result = MM_ERROR_PLAYER_INTERNAL;
12800 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
12802 debug_error("failed to add the original uri in the uri list.\n");
12810 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
12812 mm_player_t* player = (mm_player_t*) hplayer;
12813 guint num_of_list = 0;
12817 return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12818 return_val_if_fail (uri, MM_ERROR_INVALID_ARGUMENT);
12820 if (player->pipeline && player->pipeline->textbin)
12822 debug_error("subtitle path is enabled.\n");
12823 return MM_ERROR_PLAYER_INVALID_STATE;
12826 num_of_list = g_list_length(player->uri_info.uri_list);
12828 if (is_first_path == TRUE)
12830 if (num_of_list == 0)
12832 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
12833 debug_log("add original path : %s", uri);
12837 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
12838 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
12840 debug_log("change original path : %s", uri);
12845 if (num_of_list == 0)
12847 MMHandleType attrs = 0;
12848 char *original_uri = NULL;
12850 attrs = MMPLAYER_GET_ATTRS(player);
12853 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
12857 debug_error("there is no original uri.");
12858 return MM_ERROR_PLAYER_INVALID_STATE;
12861 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
12862 player->uri_info.uri_idx = 0;
12864 debug_log("add original path at first : %s (%d)", original_uri);
12868 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
12869 debug_log("add new path : %s (total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
12873 return MM_ERROR_NONE;
12876 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
12878 mm_player_t* player = (mm_player_t*) hplayer;
12879 char *next_uri = NULL;
12880 guint num_of_list = 0;
12883 return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12885 num_of_list = g_list_length(player->uri_info.uri_list);
12887 if (num_of_list > 0)
12889 gint uri_idx = player->uri_info.uri_idx;
12891 if ( uri_idx < num_of_list-1 )
12896 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
12897 debug_error("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
12899 *uri = g_strdup(next_uri);
12903 return MM_ERROR_NONE;
12907 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad,
12908 GstCaps *caps, gpointer data)
12910 mm_player_t* player = (mm_player_t*)data;
12911 const gchar* klass = NULL;
12912 const gchar* mime = NULL;
12913 gchar* caps_str = NULL;
12915 klass = gst_element_factory_get_klass (gst_element_get_factory(elem));
12916 mime = gst_structure_get_name (gst_caps_get_structure(caps, 0));
12917 caps_str = gst_caps_to_string(caps);
12919 debug_warning("unknown type of caps : %s from %s",
12920 caps_str, GST_ELEMENT_NAME (elem));
12922 MMPLAYER_FREEIF(caps_str);
12924 /* There is no available codec. */
12925 __mmplayer_check_not_supported_codec (player, klass, mime);
12929 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad,
12930 GstCaps * caps, gpointer data)
12932 mm_player_t* player = (mm_player_t*)data;
12933 const char* mime = NULL;
12934 gboolean ret = TRUE;
12936 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
12937 mime = gst_structure_get_name (gst_caps_get_structure(caps, 0));
12939 if (g_str_has_prefix(mime, "audio")) {
12940 GstStructure* caps_structure = NULL;
12941 gint samplerate = 0;
12943 gchar *caps_str = NULL;
12945 caps_structure = gst_caps_get_structure(caps, 0);
12946 gst_structure_get_int (caps_structure, "rate", &samplerate);
12947 gst_structure_get_int (caps_structure, "channels", &channels);
12949 if ( (channels > 0 && samplerate == 0)) {
12950 debug_log("exclude audio...");
12954 caps_str = gst_caps_to_string(caps);
12955 /* set it directly because not sent by TAG */
12956 if (g_strrstr(caps_str, "mobile-xmf")) {
12957 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
12959 MMPLAYER_FREEIF (caps_str);
12960 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
12961 debug_log("already video linked");
12964 debug_log("found new stream");
12971 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad,
12972 GstCaps* caps, GstElementFactory* factory, gpointer data)
12974 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
12975 We are defining our own and will be removed when it actually exposed */
12977 GST_AUTOPLUG_SELECT_TRY,
12978 GST_AUTOPLUG_SELECT_EXPOSE,
12979 GST_AUTOPLUG_SELECT_SKIP
12980 } GstAutoplugSelectResult;
12982 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
12983 mm_player_t* player = (mm_player_t*)data;
12985 gchar* factory_name = NULL;
12986 gchar* caps_str = NULL;
12987 const gchar* klass = NULL;
12990 factory_name = GST_OBJECT_NAME (factory);
12991 klass = gst_element_factory_get_klass(factory);
12992 caps_str = gst_caps_to_string(caps);
12994 // debug_log("found new element [%s] to link for caps [%s]", factory_name, caps_str);
12995 debug_log("found new element [%s] to link", factory_name);
12997 /* store type string */
12998 if (player->type == NULL)
13000 player->type = gst_caps_to_string(caps);
13001 __mmplayer_update_content_type_info(player);
13004 /* filtering exclude keyword */
13005 for ( idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++ )
13007 if ( strstr(factory_name, player->ini.exclude_element_keyword[idx] ) )
13009 debug_warning("skipping [%s] by exculde keyword [%s]\n",
13010 factory_name, player->ini.exclude_element_keyword[idx] );
13012 // NOTE : does we need to check n_value against the number of item selected?
13013 result = GST_AUTOPLUG_SELECT_SKIP;
13018 /* check factory class for filtering */
13019 /* NOTE : msl don't need to use image plugins.
13020 * So, those plugins should be skipped for error handling.
13022 if (g_strrstr(klass, "Codec/Decoder/Image"))
13024 debug_log("skipping [%s] by not required\n", factory_name);
13025 result = GST_AUTOPLUG_SELECT_SKIP;
13029 if ((MMPLAYER_IS_ES_BUFF_SRC(player)) &&
13030 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser"))))
13032 // TO CHECK : subtitle if needed, add subparse exception.
13033 debug_log("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
13034 result = GST_AUTOPLUG_SELECT_SKIP;
13038 if (g_strrstr(factory_name, "mpegpsdemux"))
13040 debug_log("skipping PS container - not support\n");
13041 result = GST_AUTOPLUG_SELECT_SKIP;
13045 if (g_strrstr(factory_name, SMOOTH_STREAMING_DEMUX))
13046 player->smooth_streaming = TRUE;
13048 /* check ALP Codec can be used or not */
13049 if ((g_strrstr(klass, "Codec/Decoder/Audio")))
13051 GstStructure* str = NULL;
13054 str = gst_caps_get_structure( caps, 0 );
13057 gst_structure_get_int (str, "channels", &channels);
13059 debug_log ("check audio ch : %d %d\n", player->max_audio_channels, channels);
13060 if (player->max_audio_channels < channels)
13062 player->max_audio_channels = channels;
13066 if (!player->audiodec_linked)
13068 /* set stream information */
13069 __mmplayer_set_audio_attrs (player, caps);
13072 else if ((g_strrstr(klass, "Codec/Decoder/Video")))
13074 if (g_strrstr(factory_name, "omx_"))
13076 char *env = getenv ("MM_PLAYER_HW_CODEC_DISABLE");
13079 if (strncasecmp(env, "yes", 3) == 0)
13081 debug_log ("skipping [%s] by disabled\n", factory_name);
13082 result = GST_AUTOPLUG_SELECT_SKIP;
13089 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
13090 (g_strrstr(klass, "Codec/Decoder/Video")))
13094 GstStructure *str = NULL;
13095 mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &stype);
13097 /* don't make video because of not required */
13098 if (stype == MM_DISPLAY_SURFACE_NULL)
13100 debug_log ("no video because it's not required. -> return expose");
13101 if (player->set_mode.media_packet_video_stream == FALSE)
13103 result = GST_AUTOPLUG_SELECT_EXPOSE;
13108 /* get w/h for omx state-tune */
13109 str = gst_caps_get_structure (caps, 0);
13110 gst_structure_get_int (str, "width", &width);
13113 if (player->v_stream_caps) {
13114 gst_caps_unref(player->v_stream_caps);
13115 player->v_stream_caps = NULL;
13118 player->v_stream_caps = gst_caps_copy(caps);
13119 debug_log ("take caps for video state tune");
13120 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
13124 if (g_strrstr(klass, "Decoder"))
13126 const char* mime = NULL;
13127 mime = gst_structure_get_name (gst_caps_get_structure(caps, 0));
13129 if (g_str_has_prefix(mime, "video"))
13131 // __mmplayer_check_video_zero_cpoy(player, factory);
13133 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
13134 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
13136 player->videodec_linked = 1;
13138 else if(g_str_has_prefix(mime, "audio"))
13140 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
13141 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
13143 player->audiodec_linked = 1;
13148 MMPLAYER_FREEIF(caps_str);
13155 static GValueArray*
13156 __mmplayer_gst_decode_autoplug_factories(GstElement *bin, GstPad* pad,
13157 GstCaps * caps, gpointer data)
13159 //mm_player_t* player = (mm_player_t*)data;
13161 debug_log("decodebin is requesting factories for caps [%s] from element[%s]",
13162 gst_caps_to_string(caps),
13163 GST_ELEMENT_NAME(GST_PAD_PARENT(pad)));
13170 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad,
13171 gpointer data) // @
13173 //mm_player_t* player = (mm_player_t*)data;
13174 GstCaps* caps = NULL;
13176 debug_log("[Decodebin2] pad-removed signal\n");
13178 caps = gst_pad_query_caps(new_pad, NULL);
13181 gchar* caps_str = NULL;
13182 caps_str = gst_caps_to_string(caps);
13184 debug_log("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem) );
13186 MMPLAYER_FREEIF(caps_str);
13191 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
13193 mm_player_t* player = (mm_player_t*)data;
13196 return_if_fail ( player );
13198 debug_log("__mmplayer_gst_decode_drained");
13200 if (player->use_deinterleave == TRUE)
13202 debug_log("group playing mode.");
13206 if (!g_mutex_trylock(&player->cmd_lock))
13208 debug_warning("Fail to get cmd lock");
13212 if (!__mmplayer_verify_next_play_path(player))
13214 debug_log("decoding is finished.");
13215 player->gapless.running = FALSE;
13216 player->gapless.start_time = 0;
13217 g_mutex_unlock(&player->cmd_lock);
13221 player->gapless.reconfigure = TRUE;
13223 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
13224 __mmplayer_deactivate_old_path(player);
13226 g_mutex_unlock(&player->cmd_lock);
13232 __mmplayer_gst_element_added (GstElement *bin, GstElement *element, gpointer data)
13234 mm_player_t* player = (mm_player_t*)data;
13235 const gchar* klass = NULL;
13236 gchar* factory_name = NULL;
13238 klass = gst_element_factory_get_klass (gst_element_get_factory(element));
13239 factory_name = GST_OBJECT_NAME (gst_element_get_factory(element));
13241 debug_log("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
13243 if (__mmplayer_add_dump_buffer_probe(player, element))
13244 debug_log("add buffer probe");
13247 if (g_strrstr(klass, "Codec/Decoder/Audio"))
13249 gchar* selected = NULL;
13250 selected = g_strdup( GST_ELEMENT_NAME(element));
13251 player->audio_decoders = g_list_append (player->audio_decoders, selected);
13255 if (g_strrstr(klass, "Parser"))
13257 gchar* selected = NULL;
13259 selected = g_strdup (factory_name);
13260 player->parsers = g_list_append (player->parsers, selected);
13263 if ((g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) && !(g_strrstr(klass, "Adaptive")))
13265 /* FIXIT : first value will be overwritten if there's more
13266 * than 1 demuxer/parser
13269 //debug_log ("plugged element is demuxer. take it\n");
13270 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
13271 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
13273 /*Added for multi audio support */ // Q. del?
13274 if (g_strrstr(klass, "Demux"))
13276 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
13277 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].gst = element;
13281 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux"))
13283 int surface_type = 0;
13285 mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &surface_type);
13287 #if 0 // this is for 0.10 plugin with downstream modification
13288 /* playback protection if drm file */
13289 if (player->use_video_stream || surface_type == MM_DISPLAY_SURFACE_EVAS || surface_type == MM_DISPLAY_SURFACE_X_EXT)
13291 debug_log("playback can be protected if playready drm");
13292 g_object_set (G_OBJECT(element), "playback-protection", TRUE, NULL);
13297 // to support trust-zone only
13298 if (g_strrstr(factory_name, "asfdemux"))
13300 debug_log ("set file-location %s\n", player->profile.uri);
13301 g_object_set (G_OBJECT(element), "file-location", player->profile.uri, NULL);
13303 if (player->video_hub_download_mode == TRUE)
13305 g_object_set (G_OBJECT(element), "downloading-mode", player->video_hub_download_mode, NULL);
13308 else if (g_strrstr(factory_name, "legacyh264parse")) // SMOOTH_STREAMING_DEMUX
13310 debug_log ("[%s] output-format to legacyh264parse\n", SMOOTH_STREAMING_DEMUX);
13311 g_object_set (G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
13313 else if (g_strrstr(factory_name, "mpegaudioparse"))
13315 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
13316 (__mmplayer_is_only_mp3_type(player->type)))
13318 debug_log ("[mpegaudioparse] set streaming pull mode.");
13319 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
13322 else if (g_strrstr(factory_name, "omx"))
13324 if (g_strrstr(klass, "Codec/Decoder/Video"))
13326 gboolean ret = FALSE;
13328 if (player->v_stream_caps != NULL)
13330 GstPad *pad = gst_element_get_static_pad(element, "sink");
13334 ret = gst_pad_set_caps(pad, player->v_stream_caps);
13335 debug_log("found omx decoder, setting gst_pad_set_caps for omx (ret:%d)", ret);
13336 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
13337 gst_object_unref (pad);
13340 g_object_set (G_OBJECT(element), "state-tuning", TRUE, NULL);
13342 #ifdef _MM_PLAYER_ALP_PARSER
13343 if (g_strrstr(factory_name, "omx_mp3dec"))
13345 g_list_foreach (player->parsers, check_name, player);
13348 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
13351 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
13352 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue")))
13354 debug_log ("plugged element is multiqueue. take it\n");
13356 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
13357 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
13359 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
13360 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)))
13362 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
13363 __mm_player_streaming_set_multiqueue(player->streamer,
13366 player->ini.http_buffering_time,
13368 player->ini.http_buffering_limit);
13370 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
13374 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-added" );
13378 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player)
13381 return_val_if_fail ( player, FALSE );
13383 if ( MMPLAYER_IS_STREAMING(player) )
13386 /* This callback can be set to music player only. */
13387 if((player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO)
13389 debug_warning("audio callback is not supported for video");
13393 if (player->audio_stream_cb)
13396 GstPad *pad = NULL;
13398 pad = gst_element_get_static_pad (player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
13402 debug_error("failed to get sink pad from audiosink to probe data\n");
13405 player->audio_cb_probe_id = gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER,
13406 __mmplayer_audio_stream_probe, player, NULL);
13408 gst_object_unref (pad);
13415 debug_error("There is no audio callback to configure.\n");
13425 __mmplayer_init_factories(mm_player_t* player) // @
13427 return_if_fail ( player );
13429 player->factories = gst_registry_feature_filter(gst_registry_get(),
13430 (GstPluginFeatureFilter)__mmplayer_feature_filter, FALSE, NULL);
13431 player->factories = g_list_sort(player->factories, (GCompareFunc)util_factory_rank_compare);
13435 __mmplayer_release_factories(mm_player_t* player) // @
13438 return_if_fail ( player );
13440 if (player->factories)
13442 gst_plugin_feature_list_free (player->factories);
13443 player->factories = NULL;
13450 __mmplayer_release_misc(mm_player_t* player)
13453 gboolean cur_mode = player->set_mode.rich_audio;
13456 return_if_fail ( player );
13458 player->use_video_stream = FALSE;
13459 player->video_stream_cb = NULL;
13460 player->video_stream_cb_user_param = NULL;
13462 player->audio_stream_cb = NULL;
13463 player->audio_stream_render_cb_ex = NULL;
13464 player->audio_stream_cb_user_param = NULL;
13465 player->audio_stream_sink_sync = false;
13467 player->video_stream_changed_cb = NULL;
13468 player->video_stream_changed_cb_user_param = NULL;
13470 player->audio_stream_changed_cb = NULL;
13471 player->audio_stream_changed_cb_user_param = NULL;
13473 player->sent_bos = FALSE;
13474 player->playback_rate = DEFAULT_PLAYBACK_RATE;
13476 player->doing_seek = FALSE;
13478 player->updated_bitrate_count = 0;
13479 player->total_bitrate = 0;
13480 player->updated_maximum_bitrate_count = 0;
13481 player->total_maximum_bitrate = 0;
13483 player->not_found_demuxer = 0;
13485 player->last_position = 0;
13486 player->duration = 0;
13487 player->http_content_size = 0;
13488 player->not_supported_codec = MISSING_PLUGIN_NONE;
13489 player->can_support_codec = FOUND_PLUGIN_NONE;
13490 player->pending_seek.is_pending = FALSE;
13491 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
13492 player->pending_seek.pos = 0;
13493 player->msg_posted = FALSE;
13494 player->has_many_types = FALSE;
13495 player->is_drm_file = FALSE;
13496 player->max_audio_channels = 0;
13497 player->video_share_api_delta = 0;
13498 player->video_share_clock_delta = 0;
13499 player->sm.keep_last_pos = FALSE;
13500 player->is_subtitle_force_drop = FALSE;
13501 player->play_subtitle = FALSE;
13502 player->use_textoverlay = FALSE;
13503 player->adjust_subtitle_pos = 0;
13504 player->last_multiwin_status = FALSE;
13505 player->has_closed_caption = FALSE;
13506 player->set_mode.media_packet_video_stream = FALSE;
13507 memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
13509 player->set_mode.rich_audio = cur_mode;
13511 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++)
13513 player->bitrate[i] = 0;
13514 player->maximum_bitrate[i] = 0;
13517 /* remove media stream cb (appsrc cb) */
13518 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++)
13520 player->media_stream_buffer_status_cb[i] = NULL;
13521 player->media_stream_seek_data_cb[i] = NULL;
13524 /* free memory related to audio effect */
13525 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
13527 if (player->state_tune_caps)
13529 gst_caps_unref(player->state_tune_caps);
13530 player->state_tune_caps = NULL;
13533 if (player->video_cb_probe_id)
13535 GstPad *pad = NULL;
13537 pad = gst_element_get_static_pad (player->video_fakesink, "sink");
13540 debug_log("release video probe\n");
13542 /* release audio callback */
13543 gst_pad_remove_probe (pad, player->video_cb_probe_id);
13544 player->video_cb_probe_id = 0;
13545 player->video_stream_cb = NULL;
13546 player->video_stream_cb_user_param = NULL;
13554 __mmplayer_release_misc_post(mm_player_t* player)
13556 char *original_uri = NULL;
13559 /* player->pipeline is already released before. */
13561 return_if_fail ( player );
13563 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
13564 mm_attrs_set_int_by_name(player->attrs, "content_audio_found", 0);
13566 /* clean found parsers */
13567 if (player->parsers)
13569 GList *parsers = player->parsers;
13570 for ( ;parsers ; parsers = g_list_next(parsers))
13572 gchar *name = parsers->data;
13573 MMPLAYER_FREEIF(name);
13575 g_list_free(player->parsers);
13576 player->parsers = NULL;
13579 /* clean found audio decoders */
13580 if (player->audio_decoders)
13582 GList *a_dec = player->audio_decoders;
13583 for ( ;a_dec ; a_dec = g_list_next(a_dec))
13585 gchar *name = a_dec->data;
13586 MMPLAYER_FREEIF(name);
13588 g_list_free(player->audio_decoders);
13589 player->audio_decoders = NULL;
13592 /* clean the uri list except original uri */
13593 if (player->uri_info.uri_list)
13595 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
13599 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
13600 debug_log("restore original uri = %s\n", original_uri);
13602 if (mmf_attrs_commit(player->attrs))
13604 debug_error("failed to commit the original uri.\n");
13608 GList *uri_list = player->uri_info.uri_list;
13609 for ( ;uri_list ; uri_list = g_list_next(uri_list))
13611 gchar *uri = uri_list->data;
13612 MMPLAYER_FREEIF(uri);
13614 g_list_free(player->uri_info.uri_list);
13615 player->uri_info.uri_list = NULL;
13618 player->uri_info.uri_idx = 0;
13622 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name)
13624 GstElement *element = NULL;
13627 debug_log("creating %s to plug\n", name);
13629 element = gst_element_factory_make(name, NULL);
13632 debug_error("failed to create queue\n");
13636 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(element, GST_STATE_READY) )
13638 debug_error("failed to set state READY to %s\n", name);
13639 gst_object_unref (element);
13643 if ( ! gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), element))
13645 debug_error("failed to add %s\n", name);
13646 gst_object_unref (element);
13650 sinkpad = gst_element_get_static_pad(element, "sink");
13652 if ( GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad) )
13654 debug_error("failed to link %s\n", name);
13655 gst_object_unref (sinkpad);
13656 gst_object_unref (element);
13660 debug_log("linked %s to pipeline successfully\n", name);
13662 gst_object_unref (sinkpad);
13668 __mmplayer_close_link(mm_player_t* player, GstPad *srcpad, GstElement *sinkelement,
13669 const char *padname, const GList *templlist)
13671 GstPad *pad = NULL;
13672 gboolean has_dynamic_pads = FALSE;
13673 gboolean has_many_types = FALSE;
13674 const char *klass = NULL;
13675 GstStaticPadTemplate *padtemplate = NULL;
13676 GstElementFactory *factory = NULL;
13677 GstElement* queue = NULL;
13678 GstElement* parser = NULL;
13679 GstPad *pssrcpad = NULL;
13680 GstPad *qsrcpad = NULL, *qsinkpad = NULL;
13681 MMPlayerGstElement *mainbin = NULL;
13682 GstStructure* str = NULL;
13683 GstCaps* srccaps = NULL;
13684 GstState target_state = GST_STATE_READY;
13685 gboolean isvideo_decoder = FALSE;
13686 guint q_max_size_time = 0;
13690 return_val_if_fail ( player &&
13691 player->pipeline &&
13692 player->pipeline->mainbin,
13695 mainbin = player->pipeline->mainbin;
13697 debug_log("plugging pad %s:%s to newly create %s:%s\n",
13698 GST_ELEMENT_NAME( GST_PAD_PARENT ( srcpad ) ),
13699 GST_PAD_NAME( srcpad ),
13700 GST_ELEMENT_NAME( sinkelement ),
13703 factory = gst_element_get_factory(sinkelement);
13704 klass = gst_element_factory_get_klass(factory);
13706 /* check if player can do start continually */
13707 MMPLAYER_CHECK_CMD_IF_EXIT(player);
13709 /* need it to warm up omx before linking to pipeline */
13710 if (g_strrstr(GST_ELEMENT_NAME( GST_PAD_PARENT ( srcpad ) ), "demux"))
13712 debug_log("get demux caps.\n");
13713 if (player->state_tune_caps)
13715 gst_caps_unref(player->state_tune_caps);
13716 player->state_tune_caps = NULL;
13718 player->state_tune_caps = gst_caps_copy(gst_pad_get_current_caps(srcpad));
13721 /* NOTE : OMX Codec can check if resource is available or not at this state. */
13722 if (g_strrstr(GST_ELEMENT_NAME(sinkelement), "omx"))
13724 if (player->state_tune_caps != NULL)
13726 debug_log("set demux's caps to omx codec if resource is available");
13727 if (gst_pad_set_caps(gst_element_get_static_pad(sinkelement, "sink"), player->state_tune_caps))
13729 target_state = GST_STATE_PAUSED;
13730 isvideo_decoder = TRUE;
13731 g_object_set(G_OBJECT(sinkelement), "state-tuning", TRUE, NULL);
13735 debug_warning("failed to set caps for state tuning");
13738 gst_caps_unref(player->state_tune_caps);
13739 player->state_tune_caps = NULL;
13742 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkelement, target_state) )
13744 debug_error("failed to set %d state to %s\n", target_state, GST_ELEMENT_NAME( sinkelement ));
13745 if (isvideo_decoder)
13747 gst_element_set_state(sinkelement, GST_STATE_NULL);
13748 gst_object_unref(G_OBJECT(sinkelement));
13749 player->keep_detecting_vcodec = TRUE;
13754 /* add to pipeline */
13755 if ( ! gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), sinkelement) )
13757 debug_error("failed to add %s to mainbin\n", GST_ELEMENT_NAME( sinkelement ));
13761 debug_log("element klass : %s\n", klass);
13763 /* added to support multi track files */
13764 /* only decoder case and any of the video/audio still need to link*/
13765 if(g_strrstr(klass, "Decoder") && __mmplayer_link_decoder(player,srcpad))
13767 gchar *name = g_strdup(GST_ELEMENT_NAME( GST_PAD_PARENT ( srcpad )));
13769 if (g_strrstr(name, "mpegtsdemux")|| g_strrstr(name, SMOOTH_STREAMING_DEMUX))
13771 gchar *src_demux_caps_str = NULL;
13772 gchar *needed_parser = NULL;
13773 GstCaps *src_demux_caps = NULL;
13774 gboolean smooth_streaming = FALSE;
13776 src_demux_caps = gst_pad_query_caps(srcpad, NULL);
13777 src_demux_caps_str = gst_caps_to_string(src_demux_caps);
13779 gst_caps_unref(src_demux_caps);
13781 if (g_strrstr(src_demux_caps_str, "video/x-h264"))
13783 if (g_strrstr(name, SMOOTH_STREAMING_DEMUX))
13785 needed_parser = g_strdup("legacyh264parse");
13786 smooth_streaming = TRUE;
13790 needed_parser = g_strdup("h264parse");
13793 else if (g_strrstr(src_demux_caps_str, "video/mpeg"))
13795 needed_parser = g_strdup("mpeg4videoparse");
13797 MMPLAYER_FREEIF(src_demux_caps_str);
13801 parser = __mmplayer_element_create_and_link(player, srcpad, needed_parser);
13802 MMPLAYER_FREEIF(needed_parser);
13806 debug_error("failed to create parser\n");
13810 if (smooth_streaming)
13812 g_object_set (parser, "output-format", 1, NULL); /* NALU/Byte Stream format */
13815 /* update srcpad if parser is created */
13816 pssrcpad = gst_element_get_static_pad(parser, "src");
13821 MMPLAYER_FREEIF(name);
13823 queue = __mmplayer_element_create_and_link(player, srcpad, "queue"); // parser - queue or demuxer - queue
13826 debug_error("failed to create queue\n");
13830 /* update srcpad to link with decoder */
13831 qsrcpad = gst_element_get_static_pad(queue, "src");
13834 q_max_size_time = GST_QUEUE_DEFAULT_TIME;
13836 /* assigning queue handle for futher manipulation purpose */
13837 /* FIXIT : make it some kind of list so that msl can support more then two stream (text, data, etc...) */
13838 if(mainbin[MMPLAYER_M_Q1].gst == NULL)
13840 mainbin[MMPLAYER_M_Q1].id = MMPLAYER_M_Q1;
13841 mainbin[MMPLAYER_M_Q1].gst = queue;
13843 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_SS)
13845 g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q1].gst), "max-size-time", 0 , NULL);
13846 g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q1].gst), "max-size-buffers", 2, NULL);
13847 g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q1].gst), "max-size-bytes", 0, NULL);
13851 if (!MMPLAYER_IS_RTSP_STREAMING(player))
13852 g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q1].gst), "max-size-time", q_max_size_time * GST_SECOND, NULL);
13855 else if(mainbin[MMPLAYER_M_Q2].gst == NULL)
13857 mainbin[MMPLAYER_M_Q2].id = MMPLAYER_M_Q2;
13858 mainbin[MMPLAYER_M_Q2].gst = queue;
13860 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_SS)
13862 g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q2].gst), "max-size-time", 0 , NULL);
13863 g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q2].gst), "max-size-buffers", 2, NULL);
13864 g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q2].gst), "max-size-bytes", 0, NULL);
13868 if (!MMPLAYER_IS_RTSP_STREAMING(player))
13869 g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q2].gst), "max-size-time", q_max_size_time * GST_SECOND, NULL);
13874 debug_error("Not supporting more then two elementary stream\n");
13878 pad = gst_element_get_static_pad(sinkelement, padname);
13882 debug_warning("failed to get pad(%s) from %s. retrying with [sink]\n",
13883 padname, GST_ELEMENT_NAME(sinkelement) );
13885 pad = gst_element_get_static_pad(sinkelement, "sink");
13888 debug_error("failed to get pad(sink) from %s. \n",
13889 GST_ELEMENT_NAME(sinkelement) );
13894 /* to check the video/audio type set the proper flag*/
13895 const gchar *mime_type = NULL;
13897 srccaps = gst_pad_query_caps(srcpad, NULL);
13901 str = gst_caps_get_structure( srccaps, 0 );
13905 mime_type = gst_structure_get_name(str);
13910 /* link queue and decoder. so, it will be queue - decoder. */
13911 if ( GST_PAD_LINK_OK != gst_pad_link(srcpad, pad) )
13913 gst_object_unref(GST_OBJECT(pad));
13914 debug_error("failed to link (%s) to pad(%s)\n", GST_ELEMENT_NAME( sinkelement ), padname );
13916 /* reconstitute supportable codec */
13917 if (strstr(mime_type, "video"))
13919 player->can_support_codec ^= FOUND_PLUGIN_VIDEO;
13921 else if (strstr(mime_type, "audio"))
13923 player->can_support_codec ^= FOUND_PLUGIN_AUDIO;
13928 if (strstr(mime_type, "video"))
13930 player->videodec_linked = 1;
13931 debug_msg("player->videodec_linked set to 1\n");
13934 else if (strstr(mime_type, "audio"))
13936 player->audiodec_linked = 1;
13937 debug_msg("player->auddiodec_linked set to 1\n");
13940 gst_object_unref(GST_OBJECT(pad));
13941 gst_caps_unref(GST_CAPS(srccaps));
13945 if ( !MMPLAYER_IS_HTTP_PD(player) )
13947 if( (g_strrstr(klass, "Demux") && !g_strrstr(klass, "Metadata")) || (g_strrstr(klass, "Parser") ) )
13949 if (MMPLAYER_IS_HTTP_STREAMING(player))
13951 gint64 dur_bytes = 0L;
13952 gchar *file_buffering_path = NULL;
13953 gboolean use_file_buffer = FALSE;
13955 if ( !mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)
13957 debug_log("creating http streaming buffering queue\n");
13959 queue = gst_element_factory_make("queue2", "queue2");
13962 debug_error ( "failed to create buffering queue element\n" );
13966 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_READY) )
13968 debug_error("failed to set state READY to buffering queue\n");
13972 if ( !gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue) )
13974 debug_error("failed to add buffering queue\n");
13978 qsinkpad = gst_element_get_static_pad(queue, "sink");
13979 qsrcpad = gst_element_get_static_pad(queue, "src");
13981 if ( GST_PAD_LINK_OK != gst_pad_link(srcpad, qsinkpad) )
13983 debug_error("failed to link buffering queue\n");
13989 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
13990 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue;
13992 if ( !MMPLAYER_IS_HTTP_LIVE_STREAMING(player))
13994 if ( !gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
13995 debug_error("fail to get duration.\n");
13999 use_file_buffer = MMPLAYER_USE_FILE_FOR_BUFFERING(player);
14000 file_buffering_path = g_strdup(player->ini.http_file_buffer_path);
14008 /* NOTE : we cannot get any duration info from ts container in case of streaming */
14009 if(!g_strrstr(GST_ELEMENT_NAME(sinkelement), "mpegtsdemux"))
14011 __mm_player_streaming_set_queue2(player->streamer,
14014 player->ini.http_max_size_bytes,
14015 player->ini.http_buffering_time,
14017 player->ini.http_buffering_limit,
14019 file_buffering_path,
14020 (guint64)dur_bytes);
14023 MMPLAYER_FREEIF(file_buffering_path);
14028 /* if it is not decoder or */
14029 /* in decoder case any of the video/audio still need to link*/
14030 if(!g_strrstr(klass, "Decoder"))
14033 pad = gst_element_get_static_pad(sinkelement, padname);
14036 debug_warning("failed to get pad(%s) from %s. retrying with [sink]\n",
14037 padname, GST_ELEMENT_NAME(sinkelement) );
14039 pad = gst_element_get_static_pad(sinkelement, "sink");
14043 debug_error("failed to get pad(sink) from %s. \n",
14044 GST_ELEMENT_NAME(sinkelement) );
14049 if ( GST_PAD_LINK_OK != gst_pad_link(srcpad, pad) )
14051 gst_object_unref(GST_OBJECT(pad));
14052 debug_error("failed to link (%s) to pad(%s)\n", GST_ELEMENT_NAME( sinkelement ), padname );
14056 gst_object_unref(GST_OBJECT(pad));
14059 for(;templlist != NULL; templlist = templlist->next)
14061 padtemplate = templlist->data;
14063 debug_log ("director = [%d], presence = [%d]\n", padtemplate->direction, padtemplate->presence);
14065 if( padtemplate->direction != GST_PAD_SRC ||
14066 padtemplate->presence == GST_PAD_REQUEST )
14069 switch(padtemplate->presence)
14071 case GST_PAD_ALWAYS:
14073 GstPad *srcpad = gst_element_get_static_pad(sinkelement, "src");
14074 GstCaps *caps = gst_pad_query_caps(srcpad, NULL);
14076 /* Check whether caps has many types */
14077 if ( !gst_caps_is_fixed(caps))
14079 debug_log ("always pad but, caps has many types");
14080 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
14081 has_many_types = TRUE;
14085 if ( ! __mmplayer_try_to_plug(player, srcpad, caps) )
14087 gst_object_unref(GST_OBJECT(srcpad));
14088 gst_caps_unref(GST_CAPS(caps));
14090 debug_error("failed to plug something after %s\n", GST_ELEMENT_NAME( sinkelement ));
14094 gst_caps_unref(GST_CAPS(caps));
14095 gst_object_unref(GST_OBJECT(srcpad));
14101 case GST_PAD_SOMETIMES:
14102 has_dynamic_pads = TRUE;
14110 /* check if player can do start continually */
14111 MMPLAYER_CHECK_CMD_IF_EXIT(player);
14113 if( has_dynamic_pads )
14115 player->have_dynamic_pad = TRUE;
14116 MMPLAYER_SIGNAL_CONNECT ( player, sinkelement, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
14117 G_CALLBACK(__mmplayer_add_new_pad), player);
14119 /* for streaming, more then one typefind will used for each elementary stream
14120 * so this doesn't mean the whole pipeline completion
14122 if ( ! MMPLAYER_IS_RTSP_STREAMING( player ) )
14124 MMPLAYER_SIGNAL_CONNECT( player, sinkelement, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
14125 G_CALLBACK(__mmplayer_pipeline_complete), player);
14129 if (has_many_types)
14131 GstPad *pad = NULL;
14133 player->has_many_types = has_many_types;
14135 pad = gst_element_get_static_pad(sinkelement, "src");
14136 MMPLAYER_SIGNAL_CONNECT (player, pad, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "notify::caps", G_CALLBACK(__mmplayer_add_new_caps), player);
14137 gst_object_unref (GST_OBJECT(pad));
14141 /* check if player can do start continually */
14142 MMPLAYER_CHECK_CMD_IF_EXIT(player);
14144 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkelement, GST_STATE_PAUSED) )
14146 debug_error("failed to set state PAUSED to %s\n", GST_ELEMENT_NAME( sinkelement ));
14152 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state (queue, GST_STATE_PAUSED) )
14154 debug_error("failed to set state PAUSED to queue\n");
14160 gst_object_unref (GST_OBJECT(qsrcpad));
14166 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state (parser, GST_STATE_PAUSED) )
14168 debug_error("failed to set state PAUSED to queue\n");
14174 gst_object_unref (GST_OBJECT(pssrcpad));
14186 gst_object_unref(GST_OBJECT(qsrcpad));
14188 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
14189 * You need to explicitly set elements to the NULL state before
14190 * dropping the final reference, to allow them to clean up.
14192 gst_element_set_state(queue, GST_STATE_NULL);
14193 /* And, it still has a parent "player".
14194 * You need to let the parent manage the object instead of unreffing the object directly.
14197 gst_bin_remove (GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue);
14198 //gst_object_unref( queue );
14202 gst_caps_unref(GST_CAPS(srccaps));
14207 static gboolean __mmplayer_feature_filter(GstPluginFeature *feature, gpointer data) // @
14209 const gchar *klass;
14210 //const gchar *name;
14212 /* we only care about element factories */
14213 if (!GST_IS_ELEMENT_FACTORY(feature))
14216 /* only parsers, demuxers and decoders */
14217 klass = gst_element_factory_get_klass(GST_ELEMENT_FACTORY(feature));
14218 //name = gst_element_factory_get_longname(GST_ELEMENT_FACTORY(feature));
14220 if( g_strrstr(klass, "Demux") == NULL &&
14221 g_strrstr(klass, "Codec/Decoder") == NULL &&
14222 g_strrstr(klass, "Depayloader") == NULL &&
14223 g_strrstr(klass, "Parse") == NULL)
14231 static void __mmplayer_add_new_caps(GstPad* pad, GParamSpec* unused, gpointer data)
14233 mm_player_t* player = (mm_player_t*) data;
14234 GstCaps *caps = NULL;
14235 GstStructure *str = NULL;
14240 return_if_fail ( pad )
14241 return_if_fail ( unused )
14242 return_if_fail ( data )
14244 caps = gst_pad_query_caps(pad, NULL);
14248 str = gst_caps_get_structure(caps, 0);
14252 name = gst_structure_get_name(str);
14255 debug_log("name=%s\n", name);
14257 if ( ! __mmplayer_try_to_plug(player, pad, caps) )
14259 debug_error("failed to autoplug for type (%s)\n", name);
14260 gst_caps_unref(caps);
14264 gst_caps_unref(caps);
14266 __mmplayer_pipeline_complete( NULL, (gpointer)player );
14273 static void __mmplayer_set_unlinked_mime_type(mm_player_t* player, GstCaps *caps)
14277 const char *stream_type;
14278 gchar *version_field = NULL;
14282 return_if_fail ( player );
14283 return_if_fail ( caps );
14285 str = gst_caps_get_structure(caps, 0);
14289 stream_type = gst_structure_get_name(str);
14290 if ( !stream_type )
14294 /* set unlinked mime type for downloadable codec */
14295 if (g_str_has_prefix(stream_type, "video/"))
14297 if (g_str_has_prefix(stream_type, "video/mpeg"))
14299 gst_structure_get_int (str, MM_PLAYER_MPEG_VNAME, &version);
14300 version_field = MM_PLAYER_MPEG_VNAME;
14302 else if (g_str_has_prefix(stream_type, "video/x-wmv"))
14304 gst_structure_get_int (str, MM_PLAYER_WMV_VNAME, &version);
14305 version_field = MM_PLAYER_WMV_VNAME;
14308 else if (g_str_has_prefix(stream_type, "video/x-divx"))
14310 gst_structure_get_int (str, MM_PLAYER_DIVX_VNAME, &version);
14311 version_field = MM_PLAYER_DIVX_VNAME;
14316 player->unlinked_video_mime = g_strdup_printf("%s, %s=%d", stream_type, version_field, version);
14320 player->unlinked_video_mime = g_strdup_printf("%s", stream_type);
14323 else if (g_str_has_prefix(stream_type, "audio/"))
14325 if (g_str_has_prefix(stream_type, "audio/mpeg")) // mp3 or aac
14327 gst_structure_get_int (str, MM_PLAYER_MPEG_VNAME, &version);
14328 version_field = MM_PLAYER_MPEG_VNAME;
14330 else if (g_str_has_prefix(stream_type, "audio/x-wma"))
14332 gst_structure_get_int (str, MM_PLAYER_WMA_VNAME, &version);
14333 version_field = MM_PLAYER_WMA_VNAME;
14338 player->unlinked_audio_mime = g_strdup_printf("%s, %s=%d", stream_type, version_field, version);
14342 player->unlinked_audio_mime = g_strdup_printf("%s", stream_type);
14349 static void __mmplayer_add_new_pad(GstElement *element, GstPad *pad, gpointer data)
14351 mm_player_t* player = (mm_player_t*) data;
14352 GstCaps *caps = NULL;
14353 GstStructure *str = NULL;
14357 return_if_fail ( player );
14358 return_if_fail ( pad );
14360 GST_OBJECT_LOCK (pad);
14361 if ((caps = gst_pad_get_current_caps(pad)))
14362 gst_caps_ref(caps);
14363 GST_OBJECT_UNLOCK (pad);
14365 if ( NULL == caps )
14367 caps = gst_pad_query_caps(pad, NULL);
14368 if ( !caps ) return;
14371 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
14373 str = gst_caps_get_structure(caps, 0);
14377 name = gst_structure_get_name(str);
14381 player->num_dynamic_pad++;
14382 debug_log("stream count inc : %d\n", player->num_dynamic_pad);
14384 /* Note : If the stream is the subtitle, we try not to play it. Just close the demuxer subtitle pad.
14385 * If want to play it, remove this code.
14387 if (g_strrstr(name, "application"))
14389 if (g_strrstr(name, "x-id3") || g_strrstr(name, "x-apetag"))
14391 /* If id3/ape tag comes, keep going */
14392 debug_log("application mime exception : id3/ape tag");
14396 /* Otherwise, we assume that this stream is subtile. */
14397 debug_log(" application mime type pad is closed.");
14401 else if (g_strrstr(name, "audio"))
14403 gint samplerate = 0, channels = 0;
14405 if (player->audiodec_linked)
14407 gst_caps_unref(caps);
14408 debug_log("multi tracks. skip to plug");
14412 /* set stream information */
14413 /* if possible, set it here because the caps is not distrubed by resampler. */
14414 gst_structure_get_int (str, "rate", &samplerate);
14415 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
14417 gst_structure_get_int (str, "channels", &channels);
14418 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
14420 debug_log("audio samplerate : %d channels : %d", samplerate, channels);
14422 else if (g_strrstr(name, "video"))
14425 mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &stype);
14427 /* don't make video because of not required */
14428 if (stype == MM_DISPLAY_SURFACE_NULL)
14430 debug_log("no video because it's not required");
14434 player->v_stream_caps = gst_caps_copy(caps); //if needed, video caps is required when videobin is created
14437 if ( ! __mmplayer_try_to_plug(player, pad, caps) )
14439 debug_error("failed to autoplug for type (%s)", name);
14441 __mmplayer_set_unlinked_mime_type(player, caps);
14444 gst_caps_unref(caps);
14451 __mmplayer_dump_pipeline_state( mm_player_t* player )
14453 GstIterator*iter = NULL;
14454 gboolean done = FALSE;
14456 GValue item = {0, };
14457 GstElement *element = NULL;
14458 GstElementFactory *factory = NULL;
14460 GstState state = GST_STATE_VOID_PENDING;
14461 GstState pending = GST_STATE_VOID_PENDING;
14462 GstClockTime time = 200*GST_MSECOND;
14466 return_val_if_fail ( player &&
14467 player->pipeline &&
14468 player->pipeline->mainbin,
14471 iter = gst_bin_iterate_recurse(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst) );
14473 if ( iter != NULL )
14476 switch ( gst_iterator_next (iter, &item) )
14478 case GST_ITERATOR_OK:
14479 element = g_value_get_object(&item);
14480 gst_element_get_state(element,&state, &pending,time);
14482 factory = gst_element_get_factory (element) ;
14485 debug_error("%s:%s : From:%s To:%s refcount : %d\n", GST_OBJECT_NAME(factory) , GST_ELEMENT_NAME(element) ,
14486 gst_element_state_get_name(state), gst_element_state_get_name(pending) , GST_OBJECT_REFCOUNT_VALUE(element));
14488 g_value_reset (&item);
14490 case GST_ITERATOR_RESYNC:
14491 gst_iterator_resync (iter);
14493 case GST_ITERATOR_ERROR:
14496 case GST_ITERATOR_DONE:
14503 element = GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
14505 gst_element_get_state(element,&state, &pending,time);
14507 factory = gst_element_get_factory (element) ;
14511 debug_error("%s:%s : From:%s To:%s refcount : %d\n",
14512 GST_OBJECT_NAME(factory),
14513 GST_ELEMENT_NAME(element),
14514 gst_element_state_get_name(state),
14515 gst_element_state_get_name(pending),
14516 GST_OBJECT_REFCOUNT_VALUE(element) );
14519 g_value_unset(&item);
14522 gst_iterator_free (iter);
14531 __mmplayer_check_subtitle( mm_player_t* player )
14533 MMHandleType attrs = 0;
14534 char *subtitle_uri = NULL;
14538 return_val_if_fail( player, FALSE );
14540 /* get subtitle attribute */
14541 attrs = MMPLAYER_GET_ATTRS(player);
14545 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
14546 if ( !subtitle_uri || !strlen(subtitle_uri))
14549 debug_log ("subtite uri is %s[%d]\n", subtitle_uri, strlen(subtitle_uri));
14550 player->is_external_subtitle_present = TRUE;
14558 __mmplayer_can_extract_pcm( mm_player_t* player )
14560 MMHandleType attrs = 0;
14561 gboolean is_drm = FALSE;
14562 gboolean sound_extraction = FALSE;
14564 return_val_if_fail ( player, FALSE );
14566 attrs = MMPLAYER_GET_ATTRS(player);
14569 debug_error("fail to get attributes.");
14573 /* check file is drm or not */
14574 if (g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), "is-drm"))
14575 g_object_get(G_OBJECT(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), "is-drm", &is_drm, NULL);
14577 /* get sound_extraction property */
14578 mm_attrs_get_int_by_name(attrs, "pcm_extraction", &sound_extraction);
14580 if ( ! sound_extraction || is_drm )
14582 debug_log("checking pcm extraction mode : %d, drm : %d", sound_extraction, is_drm);
14590 __mmplayer_handle_gst_error ( mm_player_t* player, GstMessage * message, GError* error )
14592 MMMessageParamType msg_param;
14593 gchar *msg_src_element;
14597 return_val_if_fail( player, FALSE );
14598 return_val_if_fail( error, FALSE );
14600 /* NOTE : do somthing necessary inside of __gst_handle_XXX_error. not here */
14602 memset (&msg_param, 0, sizeof(MMMessageParamType));
14604 if ( error->domain == GST_CORE_ERROR )
14606 msg_param.code = __gst_handle_core_error( player, error->code );
14608 else if ( error->domain == GST_LIBRARY_ERROR )
14610 msg_param.code = __gst_handle_library_error( player, error->code );
14612 else if ( error->domain == GST_RESOURCE_ERROR )
14614 msg_param.code = __gst_handle_resource_error( player, error->code );
14616 else if ( error->domain == GST_STREAM_ERROR )
14618 msg_param.code = __gst_handle_stream_error( player, error, message );
14622 debug_warning("This error domain is not defined.\n");
14624 /* we treat system error as an internal error */
14625 msg_param.code = MM_ERROR_PLAYER_INVALID_STREAM;
14628 if ( message->src )
14630 msg_src_element = GST_ELEMENT_NAME( GST_ELEMENT_CAST( message->src ) );
14632 msg_param.data = (void *) error->message;
14634 debug_error("-Msg src : [%s] Domain : [%s] Error : [%s] Code : [%d] is tranlated to error code : [0x%x]\n",
14635 msg_src_element, g_quark_to_string (error->domain), error->message, error->code, msg_param.code);
14639 if (msg_param.code == MM_ERROR_NONE)
14642 /* post error to application */
14643 if ( ! player->msg_posted )
14645 MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param );
14646 /* don't post more if one was sent already */
14647 player->msg_posted = TRUE;
14651 debug_log("skip error post because it's sent already.\n");
14660 __mmplayer_handle_streaming_error ( mm_player_t* player, GstMessage * message )
14663 MMMessageParamType msg_param;
14664 gchar *msg_src_element = NULL;
14665 GstStructure *s = NULL;
14666 guint error_id = 0;
14667 gchar *error_string = NULL;
14671 return_val_if_fail ( player, FALSE );
14672 return_val_if_fail ( message, FALSE );
14674 s = malloc( sizeof(GstStructure) );
14675 memcpy ( s, gst_message_get_structure ( message ), sizeof(GstStructure));
14677 if ( !gst_structure_get_uint (s, "error_id", &error_id) )
14678 error_id = MMPLAYER_STREAMING_ERROR_NONE;
14680 switch ( error_id )
14682 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
14683 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
14685 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
14686 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
14688 case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
14689 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
14691 case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
14692 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
14694 case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
14695 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
14697 case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
14698 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
14700 case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
14701 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
14703 case MMPLAYER_STREAMING_ERROR_INVALID_URL:
14704 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
14706 case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
14707 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
14709 case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
14710 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
14712 case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
14713 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
14715 case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
14716 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
14718 case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
14719 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
14721 case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
14722 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
14724 case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
14725 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
14727 case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
14728 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
14730 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
14731 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
14733 case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
14734 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
14736 case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
14737 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
14739 case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
14740 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
14742 case MMPLAYER_STREAMING_ERROR_GONE:
14743 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
14745 case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
14746 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
14748 case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
14749 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
14751 case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
14752 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
14754 case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
14755 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
14757 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
14758 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
14760 case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
14761 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
14763 case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
14764 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
14766 case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
14767 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
14769 case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
14770 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
14772 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
14773 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
14775 case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
14776 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
14778 case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
14779 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
14781 case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
14782 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
14784 case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
14785 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
14787 case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
14788 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
14790 case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
14791 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
14793 case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
14794 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
14796 case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
14797 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
14799 case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
14800 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
14802 case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
14803 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
14805 case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
14806 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
14808 case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
14809 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
14811 case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
14812 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
14814 case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
14815 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
14819 MMPLAYER_FREEIF(s);
14820 return MM_ERROR_PLAYER_STREAMING_FAIL;
14824 error_string = g_strdup(gst_structure_get_string (s, "error_string"));
14825 if ( error_string )
14826 msg_param.data = (void *) error_string;
14828 if ( message->src )
14830 msg_src_element = GST_ELEMENT_NAME( GST_ELEMENT_CAST( message->src ) );
14832 debug_error("-Msg src : [%s] Code : [%x] Error : [%s] \n",
14833 msg_src_element, msg_param.code, (char*)msg_param.data );
14836 /* post error to application */
14837 if ( ! player->msg_posted )
14839 MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param );
14841 /* don't post more if one was sent already */
14842 player->msg_posted = TRUE;
14846 debug_log("skip error post because it's sent already.\n");
14849 MMPLAYER_FREEIF(s);
14851 g_free(error_string);
14858 __gst_handle_core_error( mm_player_t* player, int code )
14860 gint trans_err = MM_ERROR_NONE;
14864 return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
14868 case GST_CORE_ERROR_MISSING_PLUGIN:
14869 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
14870 case GST_CORE_ERROR_STATE_CHANGE:
14871 case GST_CORE_ERROR_SEEK:
14872 case GST_CORE_ERROR_NOT_IMPLEMENTED:
14873 case GST_CORE_ERROR_FAILED:
14874 case GST_CORE_ERROR_TOO_LAZY:
14875 case GST_CORE_ERROR_PAD:
14876 case GST_CORE_ERROR_THREAD:
14877 case GST_CORE_ERROR_NEGOTIATION:
14878 case GST_CORE_ERROR_EVENT:
14879 case GST_CORE_ERROR_CAPS:
14880 case GST_CORE_ERROR_TAG:
14881 case GST_CORE_ERROR_CLOCK:
14882 case GST_CORE_ERROR_DISABLED:
14884 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
14894 __gst_handle_library_error( mm_player_t* player, int code )
14896 gint trans_err = MM_ERROR_NONE;
14900 return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
14904 case GST_LIBRARY_ERROR_FAILED:
14905 case GST_LIBRARY_ERROR_TOO_LAZY:
14906 case GST_LIBRARY_ERROR_INIT:
14907 case GST_LIBRARY_ERROR_SHUTDOWN:
14908 case GST_LIBRARY_ERROR_SETTINGS:
14909 case GST_LIBRARY_ERROR_ENCODE:
14911 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
14922 __gst_handle_resource_error( mm_player_t* player, int code )
14924 gint trans_err = MM_ERROR_NONE;
14928 return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
14932 case GST_RESOURCE_ERROR_NO_SPACE_LEFT:
14933 trans_err = MM_ERROR_PLAYER_NO_FREE_SPACE;
14935 case GST_RESOURCE_ERROR_NOT_FOUND:
14936 case GST_RESOURCE_ERROR_OPEN_READ:
14937 if ( MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING ( player )
14938 || MMPLAYER_IS_RTSP_STREAMING(player))
14940 trans_err = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
14943 case GST_RESOURCE_ERROR_READ:
14944 if ( MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING ( player )
14945 || MMPLAYER_IS_RTSP_STREAMING(player))
14947 trans_err = MM_ERROR_PLAYER_STREAMING_FAIL;
14950 case GST_RESOURCE_ERROR_WRITE:
14951 case GST_RESOURCE_ERROR_FAILED:
14952 case GST_RESOURCE_ERROR_SEEK:
14953 case GST_RESOURCE_ERROR_TOO_LAZY:
14954 case GST_RESOURCE_ERROR_BUSY:
14955 case GST_RESOURCE_ERROR_OPEN_WRITE:
14956 case GST_RESOURCE_ERROR_OPEN_READ_WRITE:
14957 case GST_RESOURCE_ERROR_CLOSE:
14958 case GST_RESOURCE_ERROR_SYNC:
14959 case GST_RESOURCE_ERROR_SETTINGS:
14961 trans_err = MM_ERROR_PLAYER_INTERNAL;
14972 __gst_handle_stream_error( mm_player_t* player, GError* error, GstMessage * message )
14974 gint trans_err = MM_ERROR_NONE;
14978 return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
14979 return_val_if_fail( error, MM_ERROR_INVALID_ARGUMENT );
14980 return_val_if_fail ( message, MM_ERROR_INVALID_ARGUMENT );
14982 switch ( error->code )
14984 case GST_STREAM_ERROR_FAILED:
14985 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
14986 case GST_STREAM_ERROR_DECODE:
14987 case GST_STREAM_ERROR_WRONG_TYPE:
14988 case GST_STREAM_ERROR_DECRYPT:
14989 case GST_STREAM_ERROR_DECRYPT_NOKEY:
14990 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
14991 trans_err = __gst_transform_gsterror( player, message, error );
14994 case GST_STREAM_ERROR_NOT_IMPLEMENTED:
14995 case GST_STREAM_ERROR_TOO_LAZY:
14996 case GST_STREAM_ERROR_ENCODE:
14997 case GST_STREAM_ERROR_DEMUX:
14998 case GST_STREAM_ERROR_MUX:
14999 case GST_STREAM_ERROR_FORMAT:
15001 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
15010 /* NOTE : decide gstreamer state whether there is some playable track or not. */
15012 __gst_transform_gsterror( mm_player_t* player, GstMessage * message, GError* error )
15014 gchar *src_element_name = NULL;
15015 GstElement *src_element = NULL;
15016 GstElementFactory *factory = NULL;
15017 const gchar* klass = NULL;
15022 return_val_if_fail ( message, MM_ERROR_INVALID_ARGUMENT );
15023 return_val_if_fail ( message->src, MM_ERROR_INVALID_ARGUMENT );
15024 return_val_if_fail ( error, MM_ERROR_INVALID_ARGUMENT );
15026 src_element = GST_ELEMENT_CAST(message->src);
15027 if ( !src_element )
15028 goto INTERNAL_ERROR;
15030 src_element_name = GST_ELEMENT_NAME(src_element);
15031 if ( !src_element_name )
15032 goto INTERNAL_ERROR;
15034 factory = gst_element_get_factory(src_element);
15036 goto INTERNAL_ERROR;
15038 klass = gst_element_factory_get_klass(factory);
15040 goto INTERNAL_ERROR;
15042 debug_log("error code=%d, msg=%s, src element=%s, class=%s\n",
15043 error->code, error->message, src_element_name, klass);
15047 if (player->selector) {
15048 int msg_src_pos = 0;
15049 gint active_pad_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
15050 debug_log ("current active pad index -%d", active_pad_index);
15052 if (src_element_name) {
15055 if (player->audio_decoders) {
15056 GList *adec = player->audio_decoders;
15057 for ( ;adec ; adec = g_list_next(adec)) {
15058 gchar *name = adec->data;
15060 debug_log("found audio decoder name = %s", name);
15061 if (g_strrstr(name, src_element_name)) {
15068 debug_log("active pad = %d, error src index = %d", active_pad_index, msg_src_pos);
15071 if (active_pad_index != msg_src_pos) {
15072 debug_log("skip error because error is posted from no activated track");
15073 return MM_ERROR_NONE;
15079 switch ( error->code )
15081 case GST_STREAM_ERROR_DECODE:
15083 /* Demuxer can't parse one track because it's corrupted.
15084 * So, the decoder for it is not linked.
15085 * But, it has one playable track.
15087 if ( g_strrstr(klass, "Demux") )
15089 if ( player->can_support_codec == FOUND_PLUGIN_VIDEO )
15091 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
15093 else if ( player->can_support_codec == FOUND_PLUGIN_AUDIO )
15095 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
15099 if ( player->pipeline->audiobin ) // PCM
15101 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
15105 goto CODEC_NOT_FOUND;
15109 return MM_ERROR_PLAYER_INVALID_STREAM;
15113 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
15114 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
15115 case GST_STREAM_ERROR_WRONG_TYPE:
15116 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
15118 case GST_STREAM_ERROR_FAILED:
15120 /* Decoder Custom Message */
15121 if ( strstr(error->message, "ongoing") )
15123 if ( strncasecmp(klass, "audio", 5) )
15125 if ( ( player->can_support_codec & FOUND_PLUGIN_VIDEO ) )
15127 debug_log("Video can keep playing.\n");
15128 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
15132 goto CODEC_NOT_FOUND;
15136 else if ( strncasecmp(klass, "video", 5) )
15138 if ( ( player->can_support_codec & FOUND_PLUGIN_AUDIO ) )
15140 debug_log("Audio can keep playing.\n");
15141 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
15145 goto CODEC_NOT_FOUND;
15149 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
15153 case GST_STREAM_ERROR_DECRYPT:
15154 case GST_STREAM_ERROR_DECRYPT_NOKEY:
15156 debug_error("decryption error, [%s] failed, reason : [%s]\n", src_element_name, error->message);
15158 if ( strstr(error->message, "rights expired") )
15160 return MM_ERROR_PLAYER_DRM_EXPIRED;
15162 else if ( strstr(error->message, "no rights") )
15164 return MM_ERROR_PLAYER_DRM_NO_LICENSE;
15166 else if ( strstr(error->message, "has future rights") )
15168 return MM_ERROR_PLAYER_DRM_FUTURE_USE;
15170 else if ( strstr(error->message, "opl violation") )
15172 return MM_ERROR_PLAYER_DRM_OUTPUT_PROTECTION;
15174 return MM_ERROR_PLAYER_DRM_NOT_AUTHORIZED;
15184 return MM_ERROR_PLAYER_INVALID_STREAM;
15187 return MM_ERROR_PLAYER_INTERNAL;
15190 debug_log("not found any available codec. Player should be destroyed.\n");
15191 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
15195 __mmplayer_handle_eos_delay( mm_player_t* player, int delay_in_ms )
15197 return_if_fail( player );
15200 /* post now if delay is zero */
15201 if ( delay_in_ms == 0 || player->set_mode.pcm_extraction)
15203 debug_log("eos delay is zero. posting EOS now\n");
15204 MMPLAYER_POST_MSG( player, MM_MESSAGE_END_OF_STREAM, NULL );
15206 if ( player->set_mode.pcm_extraction )
15207 __mmplayer_cancel_eos_timer(player);
15212 /* cancel if existing */
15213 __mmplayer_cancel_eos_timer( player );
15215 /* init new timeout */
15216 /* NOTE : consider give high priority to this timer */
15217 debug_log("posting EOS message after [%d] msec\n", delay_in_ms);
15219 player->eos_timer = g_timeout_add( delay_in_ms,
15220 __mmplayer_eos_timer_cb, player );
15222 player->context.global_default = g_main_context_default ();
15223 debug_log("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
15225 /* check timer is valid. if not, send EOS now */
15226 if ( player->eos_timer == 0 )
15228 debug_warning("creating timer for delayed EOS has failed. sending EOS now\n");
15229 MMPLAYER_POST_MSG( player, MM_MESSAGE_END_OF_STREAM, NULL );
15234 __mmplayer_cancel_eos_timer( mm_player_t* player )
15236 return_if_fail( player );
15238 if ( player->eos_timer )
15240 debug_log("cancel eos timer");
15241 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
15242 player->eos_timer = 0;
15249 __mmplayer_eos_timer_cb(gpointer u_data)
15251 mm_player_t* player = NULL;
15252 player = (mm_player_t*) u_data;
15254 return_val_if_fail( player, FALSE );
15256 if ( player->play_count > 1 )
15258 gint ret_value = 0;
15259 ret_value = __gst_set_position( player, MM_PLAYER_POS_FORMAT_TIME, 0, TRUE);
15260 if (ret_value == MM_ERROR_NONE)
15262 MMHandleType attrs = 0;
15263 attrs = MMPLAYER_GET_ATTRS(player);
15265 /* we successeded to rewind. update play count and then wait for next EOS */
15266 player->play_count--;
15268 mm_attrs_set_int_by_name(attrs, "profile_play_count", player->play_count);
15269 mmf_attrs_commit ( attrs );
15273 debug_error("seeking to 0 failed in repeat play");
15279 MMPLAYER_POST_MSG( player, MM_MESSAGE_END_OF_STREAM, NULL );
15282 /* we are returning FALSE as we need only one posting */
15286 static void __mmplayer_set_antishock( mm_player_t* player, gboolean disable_by_force)
15288 gint antishock = FALSE;
15289 MMHandleType attrs = 0;
15293 return_if_fail ( player && player->pipeline );
15295 /* It should be passed for video only clip */
15296 if ( ! player->pipeline->audiobin )
15299 if ( ( g_strrstr(player->ini.name_of_audiosink, "avsysaudiosink")) )
15301 attrs = MMPLAYER_GET_ATTRS(player);
15304 debug_error("fail to get attributes.\n");
15308 mm_attrs_get_int_by_name(attrs, "sound_fadeup", &antishock);
15310 if (player->sm.antishock) {
15312 player->sm.antishock = 0;
15315 debug_log("setting antishock as (%d)\n", antishock);
15317 if ( disable_by_force )
15319 debug_log("but, antishock is disabled by force when is seeked\n");
15324 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "fadeup", antishock, NULL);
15334 __mmplayer_link_decoder( mm_player_t* player, GstPad *srcpad)
15336 const gchar* name = NULL;
15337 GstStructure* str = NULL;
15338 GstCaps* srccaps = NULL;
15342 return_val_if_fail( player, FALSE );
15343 return_val_if_fail ( srcpad, FALSE );
15345 /* to check any of the decoder (video/audio) need to be linked to parser*/
15346 srccaps = gst_pad_query_caps( srcpad, NULL);
15350 str = gst_caps_get_structure( srccaps, 0 );
15354 name = gst_structure_get_name(str);
15358 if (strstr(name, "video"))
15360 if(player->videodec_linked)
15362 debug_msg("Video decoder already linked\n");
15366 if (strstr(name, "audio"))
15368 if(player->audiodec_linked)
15370 debug_msg("Audio decoder already linked\n");
15375 gst_caps_unref( srccaps );
15383 gst_caps_unref( srccaps );
15389 __mmplayer_link_sink( mm_player_t* player , GstPad *srcpad)
15391 const gchar* name = NULL;
15392 GstStructure* str = NULL;
15393 GstCaps* srccaps = NULL;
15397 return_val_if_fail ( player, FALSE );
15398 return_val_if_fail ( srcpad, FALSE );
15400 /* to check any of the decoder (video/audio) need to be linked to parser*/
15401 srccaps = gst_pad_query_caps( srcpad, NULL );
15405 str = gst_caps_get_structure( srccaps, 0 );
15409 name = gst_structure_get_name(str);
15413 if (strstr(name, "video"))
15415 if(player->videosink_linked)
15417 debug_msg("Video Sink already linked\n");
15421 if (strstr(name, "audio"))
15423 if(player->audiosink_linked)
15425 debug_msg("Audio Sink already linked\n");
15429 if (strstr(name, "text"))
15431 if(player->textsink_linked)
15433 debug_msg("Text Sink already linked\n");
15438 gst_caps_unref( srccaps );
15443 //return (!player->videosink_linked || !player->audiosink_linked);
15447 gst_caps_unref( srccaps );
15453 /* sending event to one of sinkelements */
15455 __gst_send_event_to_sink( mm_player_t* player, GstEvent* event )
15457 GstEvent * event2 = NULL;
15458 GList *sinks = NULL;
15459 gboolean res = FALSE;
15462 return_val_if_fail( player, FALSE );
15463 return_val_if_fail ( event, FALSE );
15465 if ( player->play_subtitle && !player->use_textoverlay)
15466 event2 = gst_event_copy((const GstEvent *)event);
15468 sinks = player->sink_elements;
15471 GstElement *sink = GST_ELEMENT_CAST (sinks->data);
15473 if (GST_IS_ELEMENT(sink))
15475 /* keep ref to the event */
15476 gst_event_ref (event);
15478 if ( (res = gst_element_send_event (sink, event)) )
15480 debug_log("sending event[%s] to sink element [%s] success!\n",
15481 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink) );
15483 /* rtsp case, asyn_done is not called after seek during pause state */
15484 if (MMPLAYER_IS_RTSP_STREAMING(player))
15486 if (strstr(GST_EVENT_TYPE_NAME(event), "seek"))
15488 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED)
15490 debug_log("RTSP seek completed, after pause state..\n");
15491 player->doing_seek = FALSE;
15492 MMPLAYER_POST_MSG ( player, MM_MESSAGE_SEEK_COMPLETED, NULL );
15498 if( MMPLAYER_IS_ES_BUFF_SRC(player))
15500 sinks = g_list_next (sinks);
15507 debug_log("sending event[%s] to sink element [%s] failed. try with next one.\n",
15508 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink) );
15511 sinks = g_list_next (sinks);
15516 request pad name = sink0;
15518 request pad name = sink1; // external
15521 /* Note : Textbin is not linked to the video or audio bin.
15522 * It needs to send the event to the text sink seperatelly.
15524 if ( player->play_subtitle && !player->use_textoverlay)
15526 GstElement *text_sink = GST_ELEMENT_CAST (player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
15528 if (GST_IS_ELEMENT(text_sink))
15530 /* keep ref to the event */
15531 gst_event_ref (event2);
15533 if ((res = gst_element_send_event (text_sink, event2)))
15535 debug_log("sending event[%s] to subtitle sink element [%s] success!\n",
15536 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink) );
15540 debug_error("sending event[%s] to subtitle sink element [%s] failed!\n",
15541 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink) );
15544 gst_event_unref (event2);
15548 gst_event_unref (event);
15556 __mmplayer_add_sink( mm_player_t* player, GstElement* sink )
15560 return_if_fail ( player );
15561 return_if_fail ( sink );
15563 player->sink_elements =
15564 g_list_append(player->sink_elements, sink);
15570 __mmplayer_del_sink( mm_player_t* player, GstElement* sink )
15574 return_if_fail ( player );
15575 return_if_fail ( sink );
15577 player->sink_elements =
15578 g_list_remove(player->sink_elements, sink);
15584 __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
15585 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
15586 gint64 cur, GstSeekType stop_type, gint64 stop )
15588 GstEvent* event = NULL;
15589 gboolean result = FALSE;
15593 return_val_if_fail( player, FALSE );
15595 __mmplayer_drop_subtitle(player, FALSE);
15597 event = gst_event_new_seek (rate, format, flags, cur_type,
15598 cur, stop_type, stop);
15600 result = __gst_send_event_to_sink( player, event );
15607 /* NOTE : be careful with calling this api. please refer to below glib comment
15608 * glib comment : Note that there is a bug in GObject that makes this function much
15609 * less useful than it might seem otherwise. Once gobject is disposed, the callback
15610 * will no longer be called, but, the signal handler is not currently disconnected.
15611 * If the instance is itself being freed at the same time than this doesn't matter,
15612 * since the signal will automatically be removed, but if instance persists,
15613 * then the signal handler will leak. You should not remove the signal yourself
15614 * because in a future versions of GObject, the handler will automatically be
15617 * It's possible to work around this problem in a way that will continue to work
15618 * with future versions of GObject by checking that the signal handler is still
15619 * connected before disconnected it:
15621 * if (g_signal_handler_is_connected (instance, id))
15622 * g_signal_handler_disconnect (instance, id);
15625 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
15627 GList* sig_list = NULL;
15628 MMPlayerSignalItem* item = NULL;
15632 return_if_fail( player );
15634 debug_log("release signals type : %d", type);
15636 if ((type < MM_PLAYER_SIGNAL_TYPE_AUTOPLUG) || (type >= MM_PLAYER_SIGNAL_TYPE_ALL))
15638 __mmplayer_release_signal_connection (player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
15639 __mmplayer_release_signal_connection (player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
15640 __mmplayer_release_signal_connection (player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
15641 __mmplayer_release_signal_connection (player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
15642 __mmplayer_release_signal_connection (player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
15646 sig_list = player->signals[type];
15648 for ( ; sig_list; sig_list = sig_list->next )
15650 item = sig_list->data;
15652 if ( item && item->obj && GST_IS_ELEMENT(item->obj) )
15654 if ( g_signal_handler_is_connected ( item->obj, item->sig ) )
15656 g_signal_handler_disconnect ( item->obj, item->sig );
15660 MMPLAYER_FREEIF( item );
15663 g_list_free ( player->signals[type] );
15664 player->signals[type] = NULL;
15671 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
15673 mm_player_t* player = 0;
15674 int prev_display_surface_type = 0;
15675 void *prev_display_overlay = NULL;
15676 const gchar *klass = NULL;
15677 gchar *cur_videosink_name = NULL;
15680 int num_of_dec = 2; /* DEC1, DEC2 */
15684 return_val_if_fail(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
15685 return_val_if_fail(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
15687 player = MM_PLAYER_CAST(handle);
15689 if (surface_type < MM_DISPLAY_SURFACE_X && surface_type > MM_DISPLAY_SURFACE_EVAS)
15691 debug_error("Not support this surface type(%d) for changing vidoesink", surface_type);
15693 return MM_ERROR_INVALID_ARGUMENT;
15696 /* load previous attributes */
15699 mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &prev_display_surface_type);
15700 mm_attrs_get_data_by_name (player->attrs, "display_overlay", &prev_display_overlay);
15701 debug_log("[0: X surface, 1: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
15702 if (prev_display_surface_type == surface_type)
15704 debug_log("incoming display surface type is same as previous one, do nothing..");
15706 return MM_ERROR_NONE;
15711 debug_error("failed to load attributes");
15713 return MM_ERROR_PLAYER_INTERNAL;
15716 /* check videosink element is created */
15717 if (!player->pipeline || !player->pipeline->videobin ||
15718 !player->pipeline->videobin[MMPLAYER_V_SINK].gst )
15720 debug_log("videosink element is not yet ready");
15722 /* videobin is not created yet, so we just set attributes related to display surface */
15723 debug_log("store display attribute for given surface type(%d)", surface_type);
15724 mm_attrs_set_int_by_name (player->attrs, "display_surface_type", surface_type);
15725 mm_attrs_set_data_by_name (player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
15726 if ( mmf_attrs_commit ( player->attrs ) )
15728 debug_error("failed to commit attribute");
15730 return MM_ERROR_PLAYER_INTERNAL;
15733 return MM_ERROR_NONE;
15737 /* get player command status */
15738 if ( !(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME || player->cmd == MMPLAYER_COMMAND_PAUSE) )
15740 debug_error("invalid player command status(%d), __mmplayer_do_change_videosink() is only available with START/RESUME/PAUSE command",player->cmd);
15742 return MM_ERROR_PLAYER_INVALID_STATE;
15745 /* get a current videosink name */
15746 cur_videosink_name = GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
15748 /* surface change */
15749 for ( i = 0 ; i < num_of_dec ; i++)
15751 if ( player->pipeline->mainbin &&
15752 player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst )
15754 klass = gst_element_factory_get_klass( gst_element_get_factory(player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst) );
15755 if ((g_strrstr(klass, "Codec/Decoder/Video")))
15757 if ( !strncmp(cur_videosink_name, "x", 1) && (surface_type == MM_DISPLAY_SURFACE_EVAS) )
15759 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, player->ini.videosink_element_evas, surface_type, display_overlay);
15766 debug_warning("success to changing display surface(%d)",surface_type);
15768 return MM_ERROR_NONE;
15771 else if (!strncmp(cur_videosink_name, "evas", 4) && (surface_type == MM_DISPLAY_SURFACE_X) )
15773 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, player->ini.videosink_element_x, surface_type, display_overlay);
15780 debug_warning("success to changing display surface(%d)",surface_type);
15782 return MM_ERROR_NONE;
15787 debug_error("invalid incoming surface type(%d) and current videosink_name(%s) for changing display surface",surface_type, cur_videosink_name);
15788 ret = MM_ERROR_PLAYER_INTERNAL;
15797 /* rollback to previous attributes */
15798 mm_attrs_set_int_by_name (player->attrs, "display_surface_type", prev_display_surface_type);
15799 mm_attrs_set_data_by_name(player->attrs, "display_overlay", prev_display_overlay, sizeof(void*));
15800 if ( mmf_attrs_commit ( player->attrs ) )
15802 debug_error("failed to commit attributes to rollback");
15804 return MM_ERROR_PLAYER_INTERNAL;
15810 /* NOTE : It does not support some use cases, eg using colorspace converter */
15812 __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay)
15814 GstPad *src_pad_dec = NULL;
15815 GstPad *sink_pad_videosink = NULL;
15816 GstPad *sink_pad_videobin = NULL;
15817 GstClock *clock = NULL;
15818 MMPlayerStateType previous_state = MM_PLAYER_STATE_NUM;
15819 int ret = MM_ERROR_NONE;
15820 gboolean is_audiobin_created = TRUE;
15824 return_val_if_fail(player, MM_ERROR_COMMON_INVALID_ARGUMENT);
15825 return_val_if_fail(videosink_element, MM_ERROR_COMMON_INVALID_ARGUMENT);
15826 return_val_if_fail(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
15828 debug_log("video dec is found(idx:%d), we are going to change videosink to %s", dec_index, videosink_element);
15829 debug_log("surface type(%d), display overlay(%x)", surface_type, display_overlay);
15831 /* get information whether if audiobin is created */
15832 if ( !player->pipeline->audiobin ||
15833 !player->pipeline->audiobin[MMPLAYER_A_SINK].gst )
15835 debug_warning("audiobin is null, this video content may not have audio data");
15836 is_audiobin_created = FALSE;
15839 /* get current state of player */
15840 previous_state = MMPLAYER_CURRENT_STATE(player);
15841 debug_log("previous state(%d)", previous_state);
15844 /* get src pad of decoder and block it */
15845 src_pad_dec = gst_element_get_static_pad (GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), "src");
15848 debug_error("failed to get src pad from decode in mainbin");
15849 return MM_ERROR_PLAYER_INTERNAL;
15852 if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING)
15854 debug_warning("trying to block pad(video)");
15855 // if (!gst_pad_set_blocked (src_pad_dec, TRUE))
15856 gst_pad_add_probe(src_pad_dec, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
15860 debug_error("failed to set block pad(video)");
15861 return MM_ERROR_PLAYER_INTERNAL;
15863 debug_warning("pad is blocked(video)");
15867 /* no data flows, so no need to do pad_block */
15868 if (player->doing_seek) {
15869 debug_warning("not completed seek(%d), do nothing", player->doing_seek);
15871 debug_log("MM_PLAYER_STATE is not PLAYING now, skip pad-block(TRUE)");
15875 if (!gst_element_remove_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst,
15876 GST_PAD_CAST(GST_GHOST_PAD(player->ghost_pad_for_videobin))))
15878 debug_error("failed to remove previous ghost_pad for videobin");
15879 return MM_ERROR_PLAYER_INTERNAL;
15882 /* change state of videobin to NULL */
15883 debug_log("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_NULL);
15884 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_NULL);
15885 if (ret != GST_STATE_CHANGE_SUCCESS)
15887 debug_error("failed to change state of videobin to NULL");
15888 return MM_ERROR_PLAYER_INTERNAL;
15891 /* unlink between decoder and videobin and remove previous videosink from videobin */
15892 GST_ELEMENT_UNLINK(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst),GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst));
15893 if ( !gst_bin_remove (GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst)) )
15895 debug_error("failed to remove former videosink from videobin");
15896 return MM_ERROR_PLAYER_INTERNAL;
15899 __mmplayer_del_sink( player, player->pipeline->videobin[MMPLAYER_V_SINK].gst );
15901 /* create a new videosink and add it to videobin */
15902 player->pipeline->videobin[MMPLAYER_V_SINK].gst = gst_element_factory_make(videosink_element, videosink_element);
15903 gst_bin_add (GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst));
15904 __mmplayer_add_sink( player, player->pipeline->videobin[MMPLAYER_V_SINK].gst );
15905 g_object_set (G_OBJECT (player->pipeline->videobin[MMPLAYER_V_SINK].gst), "qos", TRUE, NULL);
15907 /* save attributes */
15910 /* set a new display surface type */
15911 mm_attrs_set_int_by_name (player->attrs, "display_surface_type", surface_type);
15912 /* set a new diplay overlay */
15913 switch (surface_type)
15915 case MM_DISPLAY_SURFACE_X:
15916 debug_log("save attributes related to display surface to X : xid = %d", *(int*)display_overlay);
15917 mm_attrs_set_data_by_name (player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
15919 case MM_DISPLAY_SURFACE_EVAS:
15920 debug_log("save attributes related to display surface to EVAS : evas image object = %x", display_overlay);
15921 mm_attrs_set_data_by_name (player->attrs, "display_overlay", display_overlay, sizeof(void*));
15924 debug_error("invalid type(%d) for changing display surface",surface_type);
15926 return MM_ERROR_INVALID_ARGUMENT;
15928 if ( mmf_attrs_commit ( player->attrs ) )
15930 debug_error("failed to commit");
15932 return MM_ERROR_PLAYER_INTERNAL;
15937 debug_error("player->attrs is null, failed to save attributes");
15939 return MM_ERROR_PLAYER_INTERNAL;
15942 /* update video param */
15943 if ( MM_ERROR_NONE != _mmplayer_update_video_param( player ) )
15945 debug_error("failed to update video param");
15946 return MM_ERROR_PLAYER_INTERNAL;
15949 /* change state of videobin to READY */
15950 debug_log("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_READY);
15951 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_READY);
15952 if (ret != GST_STATE_CHANGE_SUCCESS)
15954 debug_error("failed to change state of videobin to READY");
15955 return MM_ERROR_PLAYER_INTERNAL;
15958 /* change ghostpad */
15959 sink_pad_videosink = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "sink");
15960 if ( !sink_pad_videosink )
15962 debug_error("failed to get sink pad from videosink element");
15963 return MM_ERROR_PLAYER_INTERNAL;
15965 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", sink_pad_videosink);
15966 if (!gst_pad_set_active(player->ghost_pad_for_videobin, TRUE))
15968 debug_error("failed to set active to ghost_pad");
15969 return MM_ERROR_PLAYER_INTERNAL;
15971 if ( FALSE == gst_element_add_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin) )
15973 debug_error("failed to change ghostpad for videobin");
15974 return MM_ERROR_PLAYER_INTERNAL;
15976 gst_object_unref(sink_pad_videosink);
15978 /* link decoder with videobin */
15979 sink_pad_videobin = gst_element_get_static_pad( GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst), "sink");
15980 if ( !sink_pad_videobin )
15982 debug_error("failed to get sink pad from videobin");
15983 return MM_ERROR_PLAYER_INTERNAL;
15985 if ( GST_PAD_LINK_OK != GST_PAD_LINK(src_pad_dec, sink_pad_videobin) )
15987 debug_error("failed to link");
15988 return MM_ERROR_PLAYER_INTERNAL;
15990 gst_object_unref(sink_pad_videobin);
15992 /* clock setting for a new videosink plugin */
15993 /* NOTE : Below operation is needed, because a new videosink plugin doesn't have clock for basesink,
15994 so we set it from audiosink plugin or pipeline(system clock) */
15995 if (!is_audiobin_created)
15997 debug_warning("audiobin is not created, get clock from pipeline..");
15998 clock = GST_ELEMENT_CLOCK (player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
16002 clock = GST_ELEMENT_CLOCK (player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
16007 GstClockTime base_time;
16008 debug_log("set the clock to videosink");
16009 gst_element_set_clock (GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), clock);
16010 clock = GST_ELEMENT_CLOCK (player->pipeline->videobin[MMPLAYER_V_SINK].gst);
16013 debug_log("got clock of videosink");
16014 now = gst_clock_get_time ( clock );
16015 base_time = GST_ELEMENT_CAST (player->pipeline->videobin[MMPLAYER_V_SINK].gst)->base_time;
16016 debug_log ("at time %" GST_TIME_FORMAT ", base %"
16017 GST_TIME_FORMAT, GST_TIME_ARGS (now), GST_TIME_ARGS (base_time));
16021 debug_error("failed to get clock of videosink after setting clock");
16022 return MM_ERROR_PLAYER_INTERNAL;
16027 debug_warning("failed to get clock, maybe it is the time before first playing");
16030 if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING)
16032 /* change state of videobin to PAUSED */
16033 debug_log("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PLAYING);
16034 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PLAYING);
16035 if (ret != GST_STATE_CHANGE_FAILURE)
16037 debug_warning("change state of videobin to PLAYING, ret(%d)", ret);
16041 debug_error("failed to change state of videobin to PLAYING");
16042 return MM_ERROR_PLAYER_INTERNAL;
16045 /* release blocked and unref src pad of video decoder */
16047 if (!gst_pad_set_blocked (src_pad_dec, FALSE))
16049 debug_error("failed to set pad blocked FALSE(video)");
16050 return MM_ERROR_PLAYER_INTERNAL;
16053 debug_warning("pad is unblocked(video)");
16057 if (player->doing_seek) {
16058 debug_warning("not completed seek(%d)", player->doing_seek);
16060 /* change state of videobin to PAUSED */
16061 debug_log("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PAUSED);
16062 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PAUSED);
16063 if (ret != GST_STATE_CHANGE_FAILURE)
16065 debug_warning("change state of videobin to PAUSED, ret(%d)", ret);
16069 debug_error("failed to change state of videobin to PLAYING");
16070 return MM_ERROR_PLAYER_INTERNAL;
16073 /* already skipped pad block */
16074 debug_log("previous MM_PLAYER_STATE is not PLAYING, skip pad-block(FALSE)");
16077 /* do get/set position for new videosink plugin */
16079 unsigned long position = 0;
16080 gint64 pos_msec = 0;
16082 debug_log("do get/set position for new videosink plugin");
16083 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position ))
16085 debug_error("failed to get position");
16086 return MM_ERROR_PLAYER_INTERNAL;
16088 #ifdef SINKCHANGE_WITH_ACCURATE_SEEK
16089 /* accurate seek */
16090 if (__gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, position, TRUE ))
16092 debug_error("failed to set position");
16093 return MM_ERROR_PLAYER_INTERNAL;
16096 /* key unit seek */
16097 pos_msec = position * G_GINT64_CONSTANT(1000000);
16098 ret = __gst_seek ( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
16099 GST_FORMAT_TIME, ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT ),
16100 GST_SEEK_TYPE_SET, pos_msec,
16101 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE );
16104 debug_error("failed to set position");
16105 return MM_ERROR_PLAYER_INTERNAL;
16112 gst_object_unref (src_pad_dec);
16114 debug_log("success to change sink");
16118 return MM_ERROR_NONE;
16122 /* Note : if silent is true, then subtitle would not be displayed. :*/
16123 int _mmplayer_set_subtitle_silent (MMHandleType hplayer, int silent)
16125 mm_player_t* player = (mm_player_t*) hplayer;
16129 /* check player handle */
16130 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED );
16132 player->set_mode.subtitle_off = silent;
16134 debug_log("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
16138 return MM_ERROR_NONE;
16141 int _mmplayer_remove_audio_parser_decoder(mm_player_t* player,GstPad *inpad)
16143 int result = MM_ERROR_NONE;
16144 GstPad *peer = NULL,*pad = NULL;
16145 GstElement *Element = NULL;
16146 MMPlayerGstElement* mainbin = NULL;
16147 mainbin = player->pipeline->mainbin;
16150 if(!gst_pad_set_blocked(inpad,TRUE))
16152 result = MM_ERROR_PLAYER_INTERNAL;
16156 gst_pad_add_probe(inpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
16159 /*Getting pad connected to demuxer audio pad */
16160 peer = gst_pad_get_peer(inpad);
16161 /* Disconnecting Demuxer and its peer plugin [audio] */
16164 if(!gst_pad_unlink(inpad,peer))
16166 result = MM_ERROR_PLAYER_INTERNAL;
16172 result = MM_ERROR_PLAYER_INTERNAL;
16175 /*Removing elements between Demuxer and audiobin*/
16176 while(peer != NULL)
16178 gchar *Element_name = NULL;
16179 gchar *factory_name = NULL;
16180 GList *elements = NULL;
16181 GstElementFactory *factory = NULL;
16182 /*Getting peer element*/
16183 Element = gst_pad_get_parent_element(peer);
16184 if(Element == NULL)
16186 gst_object_unref(peer);
16187 result = MM_ERROR_PLAYER_INTERNAL;
16191 Element_name = gst_element_get_name(Element);
16192 factory = gst_element_get_factory(Element);
16193 /*checking the element is audio bin*/
16194 if(!strcmp(Element_name,"audiobin"))
16196 gst_object_unref(peer);
16197 result = MM_ERROR_NONE;
16198 g_free(Element_name);
16201 factory_name = GST_OBJECT_NAME(factory);
16202 pad = gst_element_get_static_pad(Element,"src");
16205 result = MM_ERROR_PLAYER_INTERNAL;
16206 g_free(Element_name);
16209 gst_object_unref(peer);
16210 peer = gst_pad_get_peer(pad);
16213 if(!gst_pad_unlink(pad,peer))
16215 gst_object_unref(peer);
16216 gst_object_unref(pad);
16217 result = MM_ERROR_PLAYER_INTERNAL;
16218 g_free(Element_name);
16222 elements = player->parsers;
16223 /* Removing the element form the list*/
16224 for ( ; elements; elements = g_list_next(elements))
16226 Element_name = elements->data;
16227 if(g_strrstr(Element_name,factory_name))
16229 player->parsers = g_list_remove(player->parsers,elements->data);
16232 gst_element_set_state(Element,GST_STATE_NULL);
16233 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst),Element);
16234 gst_object_unref(pad);
16235 if(Element == mainbin[MMPLAYER_M_Q1].gst)
16237 mainbin[MMPLAYER_M_Q1].gst = NULL;
16239 else if(Element == mainbin[MMPLAYER_M_Q2].gst)
16241 mainbin[MMPLAYER_M_Q2].gst = NULL;
16243 else if(Element == mainbin[MMPLAYER_M_DEC1].gst)
16245 mainbin[MMPLAYER_M_DEC1].gst = NULL;
16247 else if(Element == mainbin[MMPLAYER_M_DEC2].gst)
16249 mainbin[MMPLAYER_M_DEC2].gst = NULL;
16251 gst_object_unref(Element);
16257 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
16259 MMPlayerGstElement* mainbin = NULL;
16260 MMPlayerGstElement* textbin = NULL;
16261 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
16262 GstState current_state = GST_STATE_VOID_PENDING;
16263 GstState element_state = GST_STATE_VOID_PENDING;
16264 GstState element_pending_state = GST_STATE_VOID_PENDING;
16266 GstEvent *event = NULL;
16267 int result = MM_ERROR_NONE;
16269 GstClock *curr_clock = NULL;
16270 GstClockTime base_time, start_time, curr_time;
16275 /* check player handle */
16276 return_val_if_fail ( player && player->pipeline , MM_ERROR_PLAYER_NOT_INITIALIZED);
16278 if (!(player->pipeline->mainbin) || !(player->pipeline->textbin))
16280 debug_error("Pipeline is not in proper state\n");
16281 result = MM_ERROR_PLAYER_NOT_INITIALIZED;
16285 mainbin = player->pipeline->mainbin;
16286 textbin = player->pipeline->textbin;
16288 current_state = GST_STATE (mainbin[MMPLAYER_M_PIPE].gst);
16290 // sync clock with current pipeline
16291 curr_clock = GST_ELEMENT_CLOCK (player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
16292 curr_time = gst_clock_get_time (curr_clock);
16294 base_time = gst_element_get_base_time (GST_ELEMENT_CAST (player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
16295 start_time = gst_element_get_start_time (GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
16297 debug_log ("base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
16298 GST_TIME_ARGS (base_time), GST_TIME_ARGS (start_time), GST_TIME_ARGS (curr_time));
16300 if (current_state > GST_STATE_READY)
16302 // sync state with current pipeline
16303 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
16304 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
16305 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
16307 ret = gst_element_get_state (mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
16308 if ( GST_STATE_CHANGE_FAILURE == ret )
16310 debug_error("fail to state change.\n");
16314 gst_element_set_base_time (textbin[MMPLAYER_T_BIN].gst, base_time);
16315 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
16319 gst_element_set_clock (textbin[MMPLAYER_T_BIN].gst, curr_clock);
16320 gst_object_unref (curr_clock);
16323 // seek to current position
16324 if (!gst_element_query_position (mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time))
16326 result = MM_ERROR_PLAYER_INVALID_STATE;
16327 debug_error("gst_element_query_position failed, invalid state\n");
16331 debug_log("seek time = %lld\n", time);
16332 event = gst_event_new_seek (1.0, GST_FORMAT_TIME, (GstSeekFlags)(GST_SEEK_FLAG_FLUSH), GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
16335 __gst_send_event_to_sink(player, event);
16339 result = MM_ERROR_PLAYER_INTERNAL;
16340 debug_error("gst_event_new_seek failed\n");
16344 // sync state with current pipeline
16345 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
16346 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
16347 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
16354 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
16356 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
16357 GstState current_state = GST_STATE_VOID_PENDING;
16359 MMHandleType attrs = 0;
16360 MMPlayerGstElement* mainbin = NULL;
16361 MMPlayerGstElement* textbin = NULL;
16363 gchar* subtitle_uri = NULL;
16364 int result = MM_ERROR_NONE;
16365 const gchar *charset = NULL;
16369 /* check player handle */
16370 return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
16371 return_val_if_fail( filepath, MM_ERROR_COMMON_INVALID_ARGUMENT );
16373 if (!(player->pipeline) || !(player->pipeline->mainbin))
16375 result = MM_ERROR_PLAYER_INVALID_STATE;
16376 debug_error("Pipeline is not in proper state\n");
16380 mainbin = player->pipeline->mainbin;
16381 textbin = player->pipeline->textbin;
16383 current_state = GST_STATE (mainbin[MMPLAYER_M_PIPE].gst);
16384 if (current_state < GST_STATE_READY)
16386 result = MM_ERROR_PLAYER_INVALID_STATE;
16387 debug_error("Pipeline is not in proper state\n");
16391 attrs = MMPLAYER_GET_ATTRS(player);
16394 debug_error("cannot get content attribute\n");
16395 result = MM_ERROR_PLAYER_INTERNAL;
16399 mm_attrs_get_string_by_name (attrs, "subtitle_uri", &subtitle_uri);
16400 if (!subtitle_uri || strlen(subtitle_uri) < 1)
16402 debug_error("subtitle uri is not proper filepath\n");
16403 result = MM_ERROR_PLAYER_INVALID_URI;
16407 debug_log("old subtitle file path is [%s]\n", subtitle_uri);
16408 debug_log("new subtitle file path is [%s]\n", filepath);
16410 if (!strcmp (filepath, subtitle_uri))
16412 debug_log("No need to swtich subtitle, as input filepath is same as current filepath\n");
16417 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
16418 if (mmf_attrs_commit(player->attrs))
16420 debug_error("failed to commit.\n");
16425 //gst_pad_set_blocked_async(src-srcpad, TRUE)
16427 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
16428 if (ret != GST_STATE_CHANGE_SUCCESS)
16430 debug_error("failed to change state of textbin to READY");
16431 result = MM_ERROR_PLAYER_INTERNAL;
16435 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
16436 if (ret != GST_STATE_CHANGE_SUCCESS)
16438 debug_error("failed to change state of subparse to READY");
16439 result = MM_ERROR_PLAYER_INTERNAL;
16443 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
16444 if (ret != GST_STATE_CHANGE_SUCCESS)
16446 debug_error("failed to change state of filesrc to READY");
16447 result = MM_ERROR_PLAYER_INTERNAL;
16451 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
16453 charset = util_get_charset(filepath);
16456 debug_log ("detected charset is %s\n", charset );
16457 g_object_set (G_OBJECT (mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
16460 result = _mmplayer_sync_subtitle_pipeline(player);
16467 /* API to switch between external subtitles */
16468 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
16470 int result = MM_ERROR_NONE;
16471 mm_player_t* player = (mm_player_t*)hplayer;
16475 /* check player handle */
16476 return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
16478 if (!player->pipeline) // IDLE state
16480 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
16481 if (mmf_attrs_commit(player->attrs))
16483 debug_error("failed to commit.\n");
16484 result= MM_ERROR_PLAYER_INTERNAL;
16487 else // curr state <> IDLE (READY, PAUSE, PLAYING..)
16489 if ( filepath == NULL )
16490 return MM_ERROR_COMMON_INVALID_ARGUMENT;
16492 if (!__mmplayer_check_subtitle(player))
16494 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
16495 if (mmf_attrs_commit(player->attrs))
16497 debug_error("failed to commit.\n");
16498 result = MM_ERROR_PLAYER_INTERNAL;
16501 if ( MM_ERROR_NONE != __mmplayer_gst_create_subtitle_src(player) )
16502 debug_error("fail to create subtitle src\n");
16504 result = _mmplayer_sync_subtitle_pipeline(player);
16508 result = __mmplayer_change_external_subtitle_language(player, filepath);
16517 __mmplayer_change_selector_pad (mm_player_t* player, MMPlayerTrackType type, int index)
16519 int result = MM_ERROR_NONE;
16520 gchar* change_pad_name = NULL;
16521 GstPad* sinkpad = NULL;
16522 MMPlayerGstElement* mainbin = NULL;
16523 enum MainElementID elemId = MMPLAYER_M_NUM;
16524 GstCaps* caps = NULL;
16525 gint total_track_num = 0;
16529 return_val_if_fail (player && player->pipeline && player->pipeline->mainbin,
16530 MM_ERROR_PLAYER_NOT_INITIALIZED);
16532 debug_log ("Change Track(%d) to %d\n", type, index);
16534 mainbin = player->pipeline->mainbin;
16536 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
16538 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
16540 else if (type == MM_PLAYER_TRACK_TYPE_TEXT)
16542 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
16546 debug_error ("Track Type Error\n");
16550 if (mainbin[elemId].gst == NULL)
16552 result = MM_ERROR_PLAYER_NO_OP;
16553 debug_log ("Req track doesn't exist\n");
16557 total_track_num = player->selector[type].total_track_num;
16558 if (total_track_num <= 0)
16560 result = MM_ERROR_PLAYER_NO_OP;
16561 debug_log ("Language list is not available \n");
16565 if ((index < 0) || (index >= total_track_num))
16567 result = MM_ERROR_INVALID_ARGUMENT;
16568 debug_log ("Not a proper index : %d \n", index);
16572 /*To get the new pad from the selector*/
16573 change_pad_name = g_strdup_printf ("sink_%u", index);
16574 if (change_pad_name == NULL)
16576 result = MM_ERROR_PLAYER_INTERNAL;
16577 debug_log ("Pad does not exists\n");
16581 debug_log ("new active pad name: %s\n", change_pad_name);
16583 sinkpad = gst_element_get_static_pad (mainbin[elemId].gst, change_pad_name);
16584 if (sinkpad == NULL)
16586 debug_log ("sinkpad is NULL");
16587 result = MM_ERROR_PLAYER_INTERNAL;
16591 debug_log ("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
16592 g_object_set (mainbin[elemId].gst, "active-pad", sinkpad, NULL);
16594 caps = gst_pad_get_current_caps(sinkpad);
16595 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
16598 gst_object_unref (sinkpad);
16600 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
16602 __mmplayer_set_audio_attrs (player, caps);
16607 MMPLAYER_FREEIF(change_pad_name);
16611 int _mmplayer_change_track_language (MMHandleType hplayer, MMPlayerTrackType type, int index)
16613 int result = MM_ERROR_NONE;
16614 mm_player_t* player = NULL;
16615 MMPlayerGstElement* mainbin = NULL;
16617 gint current_active_index = 0;
16619 GstState current_state = GST_STATE_VOID_PENDING;
16620 GstEvent* event = NULL;
16625 player = (mm_player_t*)hplayer;
16626 return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED);
16628 if (!player->pipeline)
16630 debug_error ("Track %d pre setting -> %d\n", type, index);
16632 player->selector[type].active_pad_index = index;
16636 mainbin = player->pipeline->mainbin;
16638 current_active_index = player->selector[type].active_pad_index;
16640 /*If index is same as running index no need to change the pad*/
16641 if (current_active_index == index)
16646 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time))
16648 result = MM_ERROR_PLAYER_INVALID_STATE;
16652 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
16653 if (current_state < GST_STATE_PAUSED)
16655 result = MM_ERROR_PLAYER_INVALID_STATE;
16656 debug_warning ("Pipeline not in porper state\n");
16660 result = __mmplayer_change_selector_pad(player, type, index);
16661 if (result != MM_ERROR_NONE)
16663 debug_error ("change selector pad error\n");
16667 player->selector[type].active_pad_index = index;
16669 if (current_state == GST_STATE_PLAYING)
16671 event = gst_event_new_seek (1.0, GST_FORMAT_TIME,(GstSeekFlags) (GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
16674 __gst_send_event_to_sink (player, event);
16678 result = MM_ERROR_PLAYER_INTERNAL;
16687 int _mmplayer_get_subtitle_silent (MMHandleType hplayer, int* silent)
16689 mm_player_t* player = (mm_player_t*) hplayer;
16693 /* check player handle */
16694 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED );
16696 *silent = player->set_mode.subtitle_off;
16698 debug_log("subtitle is %s.\n", silent ? "ON" : "OFF");
16702 return MM_ERROR_NONE;
16706 __get_state_name ( int state )
16710 case MM_PLAYER_STATE_NULL:
16712 case MM_PLAYER_STATE_READY:
16714 case MM_PLAYER_STATE_PAUSED:
16716 case MM_PLAYER_STATE_PLAYING:
16718 case MM_PLAYER_STATE_NONE:
16726 __is_rtsp_streaming ( mm_player_t* player )
16728 return_val_if_fail ( player, FALSE );
16730 return ( player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_RTSP ) ? TRUE : FALSE;
16734 __is_wfd_streaming ( mm_player_t* player )
16736 return_val_if_fail ( player, FALSE );
16738 return ( player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_WFD ) ? TRUE : FALSE;
16742 __is_http_streaming ( mm_player_t* player )
16744 return_val_if_fail ( player, FALSE );
16746 return ( player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_HTTP ) ? TRUE : FALSE;
16750 __is_streaming ( mm_player_t* player )
16752 return_val_if_fail ( player, FALSE );
16754 return ( __is_http_progressive_down( player ) || __is_rtsp_streaming ( player ) || __is_wfd_streaming ( player ) || __is_http_streaming ( player )
16755 || __is_http_live_streaming ( player ) || __is_dash_streaming ( player ) || __is_smooth_streaming(player) ) ? TRUE : FALSE;
16759 __is_live_streaming ( mm_player_t* player )
16761 return_val_if_fail ( player, FALSE );
16763 return ( __is_rtsp_streaming ( player ) && player->streaming_type == STREAMING_SERVICE_LIVE ) ? TRUE : FALSE;
16767 __is_http_live_streaming( mm_player_t* player )
16769 return_val_if_fail( player, FALSE );
16771 return ( player->profile.uri_type == MM_PLAYER_URI_TYPE_HLS ) ? TRUE : FALSE;
16775 __is_dash_streaming ( mm_player_t* player )
16777 return_val_if_fail ( player, FALSE );
16779 return ( player->profile.uri_type == MM_PLAYER_URI_TYPE_DASH ) ? TRUE : FALSE;
16783 __is_smooth_streaming ( mm_player_t* player )
16785 return_val_if_fail ( player, FALSE );
16787 return ( player->profile.uri_type == MM_PLAYER_URI_TYPE_SS ) ? TRUE : FALSE;
16792 __is_http_progressive_down(mm_player_t* player)
16794 return_val_if_fail( player, FALSE );
16796 return ((player->pd_mode) ? TRUE:FALSE);
16800 __is_es_buff_src( mm_player_t* player )
16802 return_val_if_fail ( player, FALSE );
16804 return ( player->profile.uri_type == MM_PLAYER_URI_TYPE_ES_BUFF) ? TRUE : FALSE;
16808 __has_suffix(mm_player_t* player, const gchar* suffix)
16810 return_val_if_fail( player, FALSE );
16811 return_val_if_fail( suffix, FALSE );
16813 gboolean ret = FALSE;
16814 gchar* t_url = g_ascii_strdown(player->profile.uri, -1);
16815 gchar* t_suffix = g_ascii_strdown(suffix, -1);
16817 if ( g_str_has_suffix(player->profile.uri, suffix) )
16822 MMPLAYER_FREEIF(t_url);
16823 MMPLAYER_FREEIF(t_suffix);
16829 _mmplayer_set_display_zoom(MMHandleType hplayer, float level, int x, int y)
16831 mm_player_t* player = (mm_player_t*) hplayer;
16833 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
16835 MMPLAYER_VIDEO_SINK_CHECK(player);
16837 debug_log("setting display zoom level = %f, offset = %d, %d", level, x, y);
16839 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "zoom", level, "zoom-pos-x", x, "zoom-pos-y", y, NULL);
16841 return MM_ERROR_NONE;
16844 _mmplayer_get_display_zoom(MMHandleType hplayer, float *level, int *x, int *y)
16847 mm_player_t* player = (mm_player_t*) hplayer;
16848 float _level = 0.0;
16852 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
16854 MMPLAYER_VIDEO_SINK_CHECK(player);
16856 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "zoom", &_level, "zoom-pos-x", &_x, "zoom-pos-y", &_y, NULL);
16858 debug_log("display zoom level = %f, start off x = %d, y = %d", _level, _x, _y);
16864 return MM_ERROR_NONE;
16868 _mmplayer_set_video_hub_download_mode(MMHandleType hplayer, bool mode)
16870 mm_player_t* player = (mm_player_t*) hplayer;
16872 return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED);
16874 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL)
16876 MMPLAYER_PRINT_STATE(player);
16877 debug_error("wrong-state : can't set the download mode to parse");
16878 return MM_ERROR_PLAYER_INVALID_STATE;
16881 debug_log("set video hub download mode to %s", (mode)?"ON":"OFF");
16882 player->video_hub_download_mode = mode;
16884 return MM_ERROR_NONE;
16888 _mmplayer_enable_sync_handler(MMHandleType hplayer, bool enable)
16890 mm_player_t* player = (mm_player_t*) hplayer;
16892 return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED);
16894 debug_log("enable sync handler : %s", (enable)?"ON":"OFF");
16895 player->sync_handler = enable;
16897 return MM_ERROR_NONE;
16901 _mmplayer_use_system_clock (MMHandleType hplayer)
16903 mm_player_t* player = (mm_player_t*) hplayer;
16905 return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED);
16907 debug_log("change clock provider to system");
16909 // to use system clock
16910 player->ini.provide_clock_for_movie = FALSE;
16911 player->ini.provide_clock_for_music = FALSE;
16913 return MM_ERROR_NONE;
16917 _mmplayer_set_video_share_master_clock( MMHandleType hplayer,
16919 long long clock_delta,
16920 long long video_time,
16921 long long media_clock,
16922 long long audio_time)
16924 mm_player_t* player = (mm_player_t*) hplayer;
16925 MMPlayerGstElement* mainbin = NULL;
16926 GstClockTime start_time_audio = 0, start_time_video = 0;
16927 GstClockTimeDiff base_time = 0, new_base_time = 0;
16928 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
16929 gint64 api_delta = 0;
16930 gint64 position = 0, position_delta = 0;
16931 gint64 adj_base_time = 0;
16932 GstClock *curr_clock = NULL;
16933 GstClockTime curr_time = 0;
16934 gboolean query_ret = TRUE;
16935 int result = MM_ERROR_NONE;
16939 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
16940 return_val_if_fail ( player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
16941 return_val_if_fail ( player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
16943 // debug_log("in(us) : %lld, %lld, %lld, %lld, %lld", clock, clock_delta, video_time, media_clock, audio_time);
16945 if ((video_time < 0) || (player->doing_seek))
16947 debug_log("skip setting master clock. %lld", video_time);
16951 mainbin = player->pipeline->mainbin;
16953 curr_clock = gst_pipeline_get_clock (GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
16954 curr_time = gst_clock_get_time (curr_clock);
16956 current_state = MMPLAYER_CURRENT_STATE(player);
16958 if ( current_state == MM_PLAYER_STATE_PLAYING )
16959 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
16961 if ( ( current_state != MM_PLAYER_STATE_PLAYING ) ||
16964 position = player->last_position;
16965 debug_log ("query fail. %lld", position);
16968 clock*= GST_USECOND;
16969 clock_delta *= GST_USECOND;
16971 api_delta = clock - curr_time;
16972 if ((player->video_share_api_delta == 0 ) || (player->video_share_api_delta > api_delta))
16974 player->video_share_api_delta = api_delta;
16978 clock_delta += (api_delta - player->video_share_api_delta);
16981 if ((player->video_share_clock_delta == 0 ) || (player->video_share_clock_delta > clock_delta))
16983 player->video_share_clock_delta = (gint64)clock_delta;
16985 position_delta = (position/GST_USECOND) - video_time;
16986 position_delta *= GST_USECOND;
16988 adj_base_time = position_delta;
16989 debug_log ("video_share_clock_delta = %lld, adj = %lld", player->video_share_clock_delta, adj_base_time);
16994 gint64 new_play_time = 0;
16995 gint64 network_delay =0;
16997 video_time *= GST_USECOND;
16999 network_delay = clock_delta - player->video_share_clock_delta;
17000 new_play_time = video_time + network_delay;
17002 adj_base_time = position - new_play_time;
17004 debug_log ("%lld(delay) = %lld - %lld / %lld(adj) = %lld(slave_pos) - %lld(master_pos) - %lld(delay)",
17005 network_delay, clock_delta, player->video_share_clock_delta, adj_base_time, position, video_time, network_delay);
17008 /* Adjust Current Stream Time with base_time of sink
17009 * 1. Set Start time to CLOCK NONE, to control the base time by MSL
17010 * 2. Set new base time
17011 * if adj_base_time is positive value, the stream time will be decreased.
17012 * 3. If seek event is occurred, the start time will be reset. */
17013 if ((player->pipeline->audiobin) &&
17014 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst))
17016 start_time_audio = gst_element_get_start_time (player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
17018 if (start_time_audio != GST_CLOCK_TIME_NONE)
17020 debug_log ("audio sink : gst_element_set_start_time -> NONE");
17021 gst_element_set_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, GST_CLOCK_TIME_NONE);
17024 base_time = gst_element_get_base_time (player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
17027 if ((player->pipeline->videobin) &&
17028 (player->pipeline->videobin[MMPLAYER_V_SINK].gst))
17030 start_time_video = gst_element_get_start_time (player->pipeline->videobin[MMPLAYER_V_SINK].gst);
17032 if (start_time_video != GST_CLOCK_TIME_NONE)
17034 debug_log ("video sink : gst_element_set_start_time -> NONE");
17035 gst_element_set_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst, GST_CLOCK_TIME_NONE);
17038 // if videobin exist, get base_time from videobin.
17039 base_time = gst_element_get_base_time (player->pipeline->videobin[MMPLAYER_V_SINK].gst);
17042 new_base_time = base_time + adj_base_time;
17044 if ((player->pipeline->audiobin) &&
17045 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst))
17046 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), (GstClockTime)new_base_time);
17048 if ((player->pipeline->videobin) &&
17049 (player->pipeline->videobin[MMPLAYER_V_SINK].gst))
17050 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), (GstClockTime)new_base_time);
17059 _mmplayer_get_video_share_master_clock( MMHandleType hplayer,
17060 long long *video_time,
17061 long long *media_clock,
17062 long long *audio_time)
17064 mm_player_t* player = (mm_player_t*) hplayer;
17065 MMPlayerGstElement* mainbin = NULL;
17066 GstClock *curr_clock = NULL;
17067 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
17068 gint64 position = 0;
17069 gboolean query_ret = TRUE;
17073 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
17074 return_val_if_fail ( player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
17075 return_val_if_fail ( player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
17077 return_val_if_fail ( video_time, MM_ERROR_COMMON_INVALID_ARGUMENT );
17078 return_val_if_fail ( media_clock, MM_ERROR_COMMON_INVALID_ARGUMENT );
17079 return_val_if_fail ( audio_time, MM_ERROR_COMMON_INVALID_ARGUMENT );
17081 mainbin = player->pipeline->mainbin;
17083 curr_clock = gst_pipeline_get_clock (GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
17085 current_state = MMPLAYER_CURRENT_STATE(player);
17087 if ( current_state != MM_PLAYER_STATE_PAUSED )
17088 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
17090 if ( ( current_state == MM_PLAYER_STATE_PAUSED ) ||
17093 position = player->last_position;
17096 *media_clock = *video_time = *audio_time = (position/GST_USECOND);
17098 debug_log("media_clock: %lld, video_time: %lld (us)", *media_clock, *video_time);
17101 gst_object_unref (curr_clock);
17105 return MM_ERROR_NONE;
17109 _mmplayer_get_video_rotate_angle(MMHandleType hplayer, int *angle)
17111 mm_player_t* player = (mm_player_t*) hplayer;
17116 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
17117 return_val_if_fail ( angle, MM_ERROR_COMMON_INVALID_ARGUMENT );
17119 if (player->v_stream_caps)
17121 GstStructure *str = NULL;
17123 str = gst_caps_get_structure (player->v_stream_caps, 0);
17124 if ( !gst_structure_get_int (str, "orientation", &org_angle))
17126 debug_log ("missing 'orientation' field in video caps");
17130 debug_log("orientation: %d", org_angle);
17131 *angle = org_angle;
17134 return MM_ERROR_NONE;
17138 __mmplayer_is_streaming(mm_player_t* player)
17140 gboolean result = FALSE;
17144 return_val_if_fail (player, FALSE);
17145 result = __is_streaming (player) ;
17152 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
17154 return_val_if_fail (player, FALSE);
17155 return_val_if_fail (element, FALSE);
17157 gchar *factory_name = GST_OBJECT_NAME (gst_element_get_factory(element));
17158 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
17162 for ( idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++ )
17164 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx]))
17166 debug_log("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
17167 mm_player_dump_t *dump_s;
17168 dump_s = g_malloc (sizeof(mm_player_dump_t));
17170 if (dump_s == NULL)
17172 debug_error ("malloc fail");
17176 dump_s->dump_element_file = NULL;
17177 dump_s->dump_pad = NULL;
17178 dump_s->dump_pad = gst_element_get_static_pad (element, "sink");
17180 if (dump_s->dump_pad)
17182 memset (dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
17183 sprintf (dump_file_name, "%s/%s_sink_pad.dump", player->ini.dump_element_path, player->ini.dump_element_keyword[idx]);
17184 dump_s->dump_element_file = fopen(dump_file_name,"w+");
17185 dump_s->probe_handle_id = gst_pad_add_probe (dump_s->dump_pad, GST_PAD_PROBE_TYPE_BUFFER, __mmplayer_dump_buffer_probe_cb, dump_s->dump_element_file, NULL);
17186 /* add list for removed buffer probe and close FILE */
17187 player->dump_list = g_list_append (player->dump_list, dump_s);
17188 debug_log ("%s sink pad added buffer probe for dump", factory_name);
17195 debug_error ("failed to get %s sink pad added", factory_name);
17204 static GstPadProbeReturn
17205 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
17207 FILE *dump_data = (FILE *) u_data;
17208 // int written = 0;
17209 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
17210 GstMapInfo probe_info = GST_MAP_INFO_INIT;
17212 return_val_if_fail ( dump_data, FALSE );
17214 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
17216 // debug_log ("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS( GST_BUFFER_TIMESTAMP(buffer)));
17218 fwrite ( probe_info.data, 1, probe_info.size , dump_data);
17220 return GST_PAD_PROBE_OK;
17224 __mmplayer_release_dump_list (GList *dump_list)
17228 GList *d_list = dump_list;
17229 for ( ;d_list ; d_list = g_list_next(d_list))
17231 mm_player_dump_t *dump_s = d_list->data;
17232 if (dump_s->dump_pad)
17234 if (dump_s->probe_handle_id)
17236 gst_pad_remove_probe (dump_s->dump_pad, dump_s->probe_handle_id);
17240 if (dump_s->dump_element_file)
17242 fclose(dump_s->dump_element_file);
17243 dump_s->dump_element_file = NULL;
17245 MMPLAYER_FREEIF(dump_s);
17247 g_list_free(dump_list);
17253 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
17255 mm_player_t* player = (mm_player_t*) hplayer;
17259 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
17260 return_val_if_fail ( exist, MM_ERROR_INVALID_ARGUMENT );
17262 *exist = player->has_closed_caption;
17266 return MM_ERROR_NONE;
17270 _mmplayer_enable_media_packet_video_stream(MMHandleType hplayer, bool enable)
17272 mm_player_t* player = (mm_player_t*) hplayer;
17276 return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED);
17277 return_val_if_fail (enable == TRUE || enable == FALSE, MM_ERROR_INVALID_ARGUMENT);
17279 player->bufmgr = tbm_bufmgr_init(-1);
17281 tbm_bufmgr_deinit(player->bufmgr);
17282 player->bufmgr = NULL;
17285 player->set_mode.media_packet_video_stream = enable;
17289 return MM_ERROR_NONE;
17292 void * _mm_player_media_packet_video_stream_internal_buffer_ref(void *buffer)
17296 /* increase ref count of gst buffer */
17298 ret = gst_buffer_ref((GstBuffer *)buffer);
17304 void _mm_player_media_packet_video_stream_internal_buffer_unref(void *buffer)
17308 gst_buffer_unref((GstBuffer *)buffer);
17315 __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data)
17317 mm_player_t *player = (mm_player_t*)user_data;
17318 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
17320 return_if_fail ( player );
17322 debug_msg("app-src: feed audio\n");
17324 if (player->media_stream_buffer_status_cb[type])
17326 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, player->buffer_cb_user_param);
17331 __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data)
17333 mm_player_t *player = (mm_player_t*)user_data;
17334 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
17336 return_if_fail ( player );
17338 debug_msg("app-src: feed video\n");
17340 if (player->media_stream_buffer_status_cb[type])
17342 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, player->buffer_cb_user_param);
17347 __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data)
17349 mm_player_t *player = (mm_player_t*)user_data;
17350 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
17352 return_if_fail ( player );
17354 debug_msg("app-src: feed subtitle\n");
17356 if (player->media_stream_buffer_status_cb[type])
17358 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, player->buffer_cb_user_param);
17363 __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data)
17365 mm_player_t *player = (mm_player_t*)user_data;
17366 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
17368 return_if_fail ( player );
17370 debug_msg("app-src: audio buffer is full.\n");
17372 if (player->media_stream_buffer_status_cb[type])
17374 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, player->buffer_cb_user_param);
17379 __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data)
17381 mm_player_t *player = (mm_player_t*)user_data;
17382 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
17384 return_if_fail ( player );
17386 debug_msg("app-src: video buffer is full.\n");
17388 if (player->media_stream_buffer_status_cb[type])
17390 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, player->buffer_cb_user_param);
17395 __gst_seek_audio_data (GstElement * appsrc, guint64 position, gpointer user_data)
17397 mm_player_t *player = (mm_player_t*)user_data;
17398 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
17400 return_val_if_fail( player, FALSE );
17402 debug_log("app-src: seek audio data\n");
17404 if (player->media_stream_seek_data_cb[type])
17406 player->media_stream_seek_data_cb[type](type, position, player->buffer_cb_user_param);
17413 __gst_seek_video_data (GstElement * appsrc, guint64 position, gpointer user_data)
17415 mm_player_t *player = (mm_player_t*)user_data;
17416 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
17418 return_val_if_fail( player, FALSE );
17420 debug_log("app-src: seek video data\n");
17422 if (player->media_stream_seek_data_cb[type])
17424 player->media_stream_seek_data_cb[type](type, position, player->buffer_cb_user_param);
17431 __gst_seek_subtitle_data (GstElement * appsrc, guint64 position, gpointer user_data)
17433 mm_player_t *player = (mm_player_t*)user_data;
17434 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
17436 return_val_if_fail( player, FALSE );
17438 debug_log("app-src: seek subtitle data\n");
17440 if (player->media_stream_seek_data_cb[type])
17442 player->media_stream_seek_data_cb[type](type, position, player->buffer_cb_user_param);
17449 _mmplayer_set_pcm_spec(MMHandleType hplayer, int samplerate, int channel)
17451 mm_player_t* player = (mm_player_t*) hplayer;
17455 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
17457 player->pcm_samplerate = samplerate;
17458 player->pcm_channel = channel;
17461 return MM_ERROR_NONE;