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"
56 #include <mm_sound_focus.h>
58 #define MM_SMOOTH_STREAMING
60 /*===========================================================================================
62 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
64 ========================================================================================== */
66 /*---------------------------------------------------------------------------
67 | GLOBAL CONSTANT DEFINITIONS: |
68 ---------------------------------------------------------------------------*/
70 /*---------------------------------------------------------------------------
71 | IMPORTED VARIABLE DECLARATIONS: |
72 ---------------------------------------------------------------------------*/
74 /*---------------------------------------------------------------------------
75 | IMPORTED FUNCTION DECLARATIONS: |
76 ---------------------------------------------------------------------------*/
78 /*---------------------------------------------------------------------------
80 ---------------------------------------------------------------------------*/
81 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
82 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
84 #define MM_VOLUME_FACTOR_DEFAULT 1.0
85 #define MM_VOLUME_FACTOR_MIN 0
86 #define MM_VOLUME_FACTOR_MAX 1.0
88 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 700000 // 700 msec
90 #define MM_PLAYER_MPEG_VNAME "mpegversion"
91 #define MM_PLAYER_DIVX_VNAME "divxversion"
92 #define MM_PLAYER_WMV_VNAME "wmvversion"
93 #define MM_PLAYER_WMA_VNAME "wmaversion"
95 #define DEFAULT_PLAYBACK_RATE 1.0
96 #define PLAYBACK_RATE_EX_AUDIO_MIN 0.5
97 #define PLAYBACK_RATE_EX_AUDIO_MAX 2.0
98 #define PLAYBACK_RATE_EX_VIDEO_MIN 0.5
99 #define PLAYBACK_RATE_EX_VIDEO_MAX 1.5
101 #define GST_QUEUE_DEFAULT_TIME 4
102 #define GST_QUEUE_HLS_TIME 8
104 #define DEFAULT_AUDIO_CH 0
106 #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) )
108 #define LAZY_PAUSE_TIMEOUT_MSEC 700
109 #define MM_PLAYER_NAME "mmplayer"
111 #define SMOOTH_STREAMING_DEMUX "mssdemux"
113 * g_array_index(a,t,i) does not calculate gst private structure.
114 * It replaces the g_array_index(a,t,i)
116 #define g_array_undef_struct_idx_p(a,t,i) ((t *)(void *)((a)->data + ((i) * (a)->len)))
118 //#define ENABLE_DRMSRC
120 /*---------------------------------------------------------------------------
121 | LOCAL CONSTANT DEFINITIONS: |
122 ---------------------------------------------------------------------------*/
124 /*---------------------------------------------------------------------------
125 | LOCAL DATA TYPE DEFINITIONS: |
126 ---------------------------------------------------------------------------*/
128 /*---------------------------------------------------------------------------
129 | GLOBAL VARIABLE DEFINITIONS: |
130 ---------------------------------------------------------------------------*/
132 /*---------------------------------------------------------------------------
133 | LOCAL VARIABLE DEFINITIONS: |
134 ---------------------------------------------------------------------------*/
136 /*---------------------------------------------------------------------------
137 | LOCAL FUNCTION PROTOTYPES: |
138 ---------------------------------------------------------------------------*/
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 GstPadProbeReturn __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data);
148 static void __mmplayer_gst_decode_pad_added(GstElement* elem, GstPad* pad, gpointer data);
149 static void __mmplayer_gst_decode_no_more_pads(GstElement* elem, gpointer data);
150 static void __mmplayer_gst_decode_callback(GstElement *decodebin, GstPad *pad, gpointer data);
151 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad, GstCaps *caps, gpointer data);
152 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad, GstCaps * caps, gpointer data);
153 static gint __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad, GstCaps * caps, GstElementFactory* factory, gpointer data);
154 //static GValueArray* __mmplayer_gst_decode_autoplug_factories(GstElement *bin, GstPad* pad, GstCaps * caps, gpointer data);
155 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad, gpointer data);
156 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
157 static void __mmplayer_gst_element_added(GstElement* bin, GstElement* element, gpointer data);
158 static GstElement * __mmplayer_create_decodebin(mm_player_t* player);
159 static gboolean __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps);
161 static void __mmplayer_typefind_have_type( GstElement *tf, guint probability, GstCaps *caps, gpointer data);
162 static gboolean __mmplayer_try_to_plug(mm_player_t* player, GstPad *pad, const GstCaps *caps);
163 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
164 static gboolean __mmplayer_is_midi_type(gchar* str_caps);
165 static gboolean __mmplayer_is_only_mp3_type (gchar *str_caps);
166 static void __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps);
167 //static void __mmplayer_check_video_zero_cpoy(mm_player_t* player, GstElementFactory* factory);
169 static gboolean __mmplayer_close_link(mm_player_t* player, GstPad *srcpad, GstElement *sinkelement, const char *padname, const GList *templlist);
170 static gboolean __mmplayer_feature_filter(GstPluginFeature *feature, gpointer data);
171 static void __mmplayer_add_new_pad(GstElement *element, GstPad *pad, gpointer data);
173 static void __mmplayer_gst_rtp_no_more_pads (GstElement *element, gpointer data);
174 //static void __mmplayer_gst_wfd_dynamic_pad (GstElement *element, GstPad *pad, gpointer data);
175 static void __mmplayer_gst_rtp_dynamic_pad (GstElement *element, GstPad *pad, gpointer data);
176 static gboolean __mmplayer_get_stream_service_type( mm_player_t* player );
177 static gboolean __mmplayer_update_subtitle( GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
180 static void __mmplayer_init_factories(mm_player_t* player);
181 static void __mmplayer_release_factories(mm_player_t* player);
182 static void __mmplayer_release_misc(mm_player_t* player);
183 static void __mmplayer_release_misc_post(mm_player_t* player);
184 static gboolean __mmplayer_init_gstreamer(mm_player_t* player);
185 static GstBusSyncReply __mmplayer_bus_sync_callback (GstBus * bus, GstMessage * message, gpointer data);
186 static gboolean __mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data);
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 GstPadProbeReturn __mmplayer_audio_stream_probe (GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
194 static GstPadProbeReturn __mmplayer_video_stream_probe (GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
195 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe (GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
196 static int __mmplayer_change_selector_pad (mm_player_t* player, MMPlayerTrackType type, int index);
198 static gboolean __mmplayer_check_subtitle( mm_player_t* player );
199 static gboolean __mmplayer_handle_streaming_error ( mm_player_t* player, GstMessage * message );
200 static void __mmplayer_handle_eos_delay( mm_player_t* player, int delay_in_ms );
201 static void __mmplayer_cancel_eos_timer( mm_player_t* player );
202 static gboolean __mmplayer_eos_timer_cb(gpointer u_data);
203 static gboolean __mmplayer_link_decoder( mm_player_t* player,GstPad *srcpad);
204 static gboolean __mmplayer_link_sink( mm_player_t* player,GstPad *srcpad);
205 static int __mmplayer_handle_missed_plugin(mm_player_t* player);
206 static int __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime);
207 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player);
208 static void __mmplayer_add_sink( mm_player_t* player, GstElement* sink);
209 static void __mmplayer_del_sink( mm_player_t* player, GstElement* sink);
210 static void __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type);
211 static gpointer __mmplayer_next_play_thread(gpointer data);
212 static gpointer __mmplayer_repeat_thread(gpointer data);
213 static gboolean _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag);
216 static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element);
217 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
218 static void __mmplayer_release_dump_list (GList *dump_list);
220 static int __gst_realize(mm_player_t* player);
221 static int __gst_unrealize(mm_player_t* player);
222 static int __gst_start(mm_player_t* player);
223 static int __gst_stop(mm_player_t* player);
224 static int __gst_pause(mm_player_t* player, gboolean async);
225 static int __gst_resume(mm_player_t* player, gboolean async);
226 static gboolean __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
227 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
228 gint64 cur, GstSeekType stop_type, gint64 stop );
229 static int __gst_pending_seek ( mm_player_t* player );
231 static int __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called);
232 static int __gst_get_position(mm_player_t* player, int format, unsigned long *position);
233 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos);
234 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position);
235 static int __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param);
237 static gboolean __gst_send_event_to_sink( mm_player_t* player, GstEvent* event );
239 static int __mmplayer_set_pcm_extraction(mm_player_t* player);
240 static gboolean __mmplayer_can_extract_pcm( mm_player_t* player );
243 static void __mmplayer_do_sound_fadedown(mm_player_t* player, unsigned int time);
244 static void __mmplayer_undo_sound_fadedown(mm_player_t* player);
246 static void __mmplayer_add_new_caps(GstPad* pad, GParamSpec* unused, gpointer data);
247 static void __mmplayer_set_unlinked_mime_type(mm_player_t* player, GstCaps *caps);
250 static gboolean __is_es_buff_src(mm_player_t* player);
251 static gboolean __has_suffix(mm_player_t * player, const gchar * suffix);
253 static int __mmplayer_realize_streaming_ext(mm_player_t* player);
254 static int __mmplayer_unrealize_streaming_ext(mm_player_t *player);
255 static int __mmplayer_start_streaming_ext(mm_player_t *player);
256 static int __mmplayer_destroy_streaming_ext(mm_player_t* player);
257 static int __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay);
259 static gboolean __mmplayer_verify_next_play_path(mm_player_t *player);
260 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
261 static void __mmplayer_check_pipeline(mm_player_t* player);
262 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
263 static void __mmplayer_deactivate_old_path(mm_player_t *player);
264 #if 0 // We'll need this in future.
265 static int __mmplayer_gst_switching_element(mm_player_t *player, GstElement *search_from, const gchar *removal_name, const gchar *new_element_name);
268 static void __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg);
269 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name);
270 static gboolean __mmplayer_can_do_interrupt(mm_player_t *player);
272 /* device change post proc */
273 void __mmplayer_device_change_post_process(gpointer user);
274 void __mmplayer_set_required_cb_score(mm_player_t* player, guint score);
275 void __mmplayer_inc_cb_score(mm_player_t* player);
276 void __mmplayer_post_proc_reset(mm_player_t* player);
277 void __mmplayer_device_change_trigger_post_process(mm_player_t* player);
278 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player);
279 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name);
280 static void __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data);
281 static void __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data);
282 static void __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data);
283 static void __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data);
284 static void __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data);
285 static gboolean __gst_seek_audio_data (GstElement * appsrc, guint64 position, gpointer user_data);
286 static gboolean __gst_seek_video_data (GstElement * appsrc, guint64 position, gpointer user_data);
287 static gboolean __gst_seek_subtitle_data (GstElement * appsrc, guint64 position, gpointer user_data);
288 /*===========================================================================================
290 | FUNCTION DEFINITIONS |
292 ========================================================================================== */
296 print_tag (const GstTagList * list, const gchar * tag, gpointer unused)
300 count = gst_tag_list_get_tag_size (list, tag);
302 debug_log("count = %d", count);
304 for (i = 0; i < count; i++) {
307 if (gst_tag_get_type (tag) == G_TYPE_STRING) {
308 if (!gst_tag_list_get_string_index (list, tag, i, &str))
309 g_assert_not_reached ();
312 g_strdup_value_contents (gst_tag_list_get_value_index (list, tag, i));
316 g_print (" %15s: %s\n", gst_tag_get_nick (tag), str);
318 g_print (" : %s\n", str);
327 __mmplayer_videostream_cb(GstElement *element, void *data,
328 int width, int height, gpointer user_data) // @
330 mm_player_t* player = (mm_player_t*)user_data;
332 return_if_fail ( player );
336 if (player->is_drm_file)
338 MMMessageParamType msg_param = { 0, };
339 debug_warning("not supported in drm file");
340 msg_param.code = MM_ERROR_PLAYER_DRM_OUTPUT_PROTECTION;
341 MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param );
343 else if ( !player->set_mode.media_packet_video_stream && player->video_stream_cb)
345 MMPlayerVideoStreamDataType stream;
347 /* clear stream data structure */
348 memset(&stream, 0x0, sizeof(MMPlayerVideoStreamDataType));
350 stream.data[0] = data;
351 stream.length_total = width * height * 4; // for rgb 32bit
352 stream.height = height;
353 stream.width = width;
354 player->video_stream_cb(&stream, player->video_stream_cb_user_param);
361 __mmplayer_videoframe_render_error_cb(GstElement *element, void *error_id, gpointer data)
363 mm_player_t* player = (mm_player_t*)data;
365 return_if_fail ( player );
369 if (player->video_frame_render_error_cb )
373 int surface_type = 0;
374 mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &surface_type);
375 switch (surface_type)
377 case MM_DISPLAY_SURFACE_X_EXT:
378 player->video_frame_render_error_cb((unsigned int*)error_id, player->video_frame_render_error_cb_user_param);
379 debug_log("display surface type(X_EXT) : render error callback(%p) is finished", player->video_frame_render_error_cb);
382 debug_error("video_frame_render_error_cb was set, but this surface type(%d) is not supported", surface_type);
388 debug_error("could not get surface type");
393 debug_warning("video_frame_render_error_cb was not set");
400 __mmplayer_device_change_post_process(gpointer user)
402 mm_player_t* player = (mm_player_t*)user;
403 unsigned long position = 0;
404 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
405 MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
410 ! player->pipeline ||
411 ! player->pipeline->mainbin ||
412 ! player->pipeline->mainbin[MMPLAYER_M_PIPE].gst )
417 current_state = MMPLAYER_CURRENT_STATE(player);
418 pending_state = MMPLAYER_PENDING_STATE(player);
420 if (player->post_proc.need_pause_and_resume)
422 debug_log("pausing");
423 if ((pending_state == MM_PLAYER_STATE_PLAYING) ||
424 ((pending_state == MM_PLAYER_STATE_NONE) && (current_state != MM_PLAYER_STATE_PAUSED)))
425 gst_element_set_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED);
428 /* seek should be done within pause and resume */
429 if (player->post_proc.need_seek)
431 debug_log("seeking");
432 __gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position);
433 debug_log(">> seek to current position = %ld ms", position);
434 __gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, position, TRUE);
437 if (player->post_proc.need_pause_and_resume)
439 debug_log("resuming");
440 if ((pending_state == MM_PLAYER_STATE_PLAYING) ||
441 ((pending_state == MM_PLAYER_STATE_NONE) && (current_state != MM_PLAYER_STATE_PAUSED)))
442 gst_element_set_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING);
446 if (player->post_proc.need_async)
448 debug_log("setting async");
450 /* TODO : need some comment here */
451 if (player->pipeline->textbin && player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst)
452 g_object_set (G_OBJECT (player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst), "async", TRUE, NULL);
457 __mmplayer_post_proc_reset(player);
461 void __mmplayer_set_required_cb_score(mm_player_t* player, guint score)
463 return_if_fail(player);
464 player->post_proc.required_cb_score = score;
465 debug_log("set required score to : %d", score);
468 void __mmplayer_inc_cb_score(mm_player_t* player)
470 return_if_fail(player);
471 player->post_proc.cb_score++;
472 debug_log("post proc cb score increased to %d", player->post_proc.cb_score);
475 void __mmplayer_post_proc_reset(mm_player_t* player)
477 return_if_fail(player);
479 /* check if already triggered */
480 if (player->post_proc.id)
482 /* TODO : need to consider multiple main context. !!!! */
483 if (FALSE == g_source_remove(player->post_proc.id) )
485 debug_error("failed to remove exist post_proc item");
487 player->post_proc.id = 0;
490 memset(&player->post_proc, 0, sizeof(mm_player_post_proc_t));
492 /* set default required cb score 1 as only audio device has changed in this case.
493 if display status is changed with audio device, required cb score is set 2 in display status callback.
494 this logic bases on the assumption which audio device callback is called after calling display status callback. */
495 player->post_proc.required_cb_score = 1;
499 __mmplayer_device_change_trigger_post_process(mm_player_t* player)
501 return_if_fail(player);
504 if ( player->post_proc.cb_score < player->post_proc.required_cb_score )
506 /* wait for next turn */
507 debug_log("wait for next turn. required cb score : %d current score : %d\n",
508 player->post_proc.required_cb_score, player->post_proc.cb_score);
512 /* check if already triggered */
513 if (player->post_proc.id)
515 /* TODO : need to consider multiple main context. !!!! */
516 if (FALSE == g_source_remove(player->post_proc.id) )
518 debug_error("failed to remove exist post_proc item");
520 player->post_proc.id = 0;
523 player->post_proc.id = g_idle_add((GSourceFunc)__mmplayer_device_change_post_process, (gpointer)player);
526 /* NOTE : Sound module has different latency according to output device So,
527 * synchronization problem can be happened whenever device is changed.
528 * To avoid this issue, we do reset avsystem or seek as workaroud.
531 __mmplayer_sound_device_info_changed_cb_func (MMSoundDevice_t device_h, int changed_info_type, void *user_data)
534 mm_sound_device_type_e device_type;
535 mm_player_t* player = (mm_player_t*) user_data;
537 return_if_fail( player );
539 debug_warning("device_info_changed_cb is called, device_h[0x%x], changed_info_type[%d]\n", device_h, changed_info_type);
541 __mmplayer_inc_cb_score(player);
543 /* get device type with device_h*/
544 ret = mm_sound_get_device_type(device_h, &device_type);
546 debug_error("failed to mm_sound_get_device_type()\n");
549 /* do pause and resume only if video is playing */
550 if ( player->videodec_linked && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING )
554 case MM_SOUND_DEVICE_TYPE_BLUETOOTH:
555 case MM_SOUND_DEVICE_TYPE_AUDIOJACK:
556 case MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER:
557 case MM_SOUND_DEVICE_TYPE_HDMI:
558 case MM_SOUND_DEVICE_TYPE_MIRRORING:
560 player->post_proc.need_pause_and_resume = TRUE;
565 debug_log("do nothing");
568 debug_warning("dispatched");
570 __mmplayer_device_change_trigger_post_process(player);
573 /* This function should be called after the pipeline goes PAUSED or higher
576 _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag) // @
578 static gboolean has_duration = FALSE;
579 static gboolean has_video_attrs = FALSE;
580 static gboolean has_audio_attrs = FALSE;
581 static gboolean has_bitrate = FALSE;
582 gboolean missing_only = FALSE;
583 gboolean all = FALSE;
585 GstStructure* p = NULL;
586 MMHandleType attrs = 0;
588 gint stream_service_type = STREAMING_SERVICE_NONE;
593 return_val_if_fail ( player, FALSE );
595 /* check player state here */
596 if ( MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
597 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING )
599 /* give warning now only */
600 debug_warning("be careful. content attributes may not available in this state ");
603 /* get content attribute first */
604 attrs = MMPLAYER_GET_ATTRS(player);
607 debug_error("cannot get content attribute");
611 /* get update flag */
613 if ( flag & ATTR_MISSING_ONLY )
616 debug_log("updating missed attr only");
619 if ( flag & ATTR_ALL )
622 has_duration = FALSE;
623 has_video_attrs = FALSE;
624 has_audio_attrs = FALSE;
627 debug_log("updating all attrs");
630 if ( missing_only && all )
632 debug_warning("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
633 missing_only = FALSE;
636 if ( (flag & ATTR_DURATION) || (!has_duration && missing_only) || all )
638 debug_log("try to update duration");
639 has_duration = FALSE;
641 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec ))
643 player->duration = dur_nsec;
644 debug_warning("duration : %lld msec", GST_TIME_AS_MSECONDS(dur_nsec));
647 /* try to get streaming service type */
648 stream_service_type = __mmplayer_get_stream_service_type( player );
649 mm_attrs_set_int_by_name ( attrs, "streaming_type", stream_service_type );
651 /* check duration is OK */
652 if ( dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING( player ) )
654 /* FIXIT : find another way to get duration here. */
655 debug_error("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
660 mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(dur_nsec));
665 if ( (flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all )
667 /* update audio params
668 NOTE : We need original audio params and it can be only obtained from src pad of audio
669 decoder. Below code only valid when we are not using 'resampler' just before
672 debug_log("try to update audio attrs");
673 has_audio_attrs = FALSE;
675 if ( player->pipeline->audiobin &&
676 player->pipeline->audiobin[MMPLAYER_A_SINK].gst )
678 GstCaps *caps_a = NULL;
680 gint samplerate = 0, channels = 0;
682 pad = gst_element_get_static_pad(
683 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink" );
687 caps_a = gst_pad_get_current_caps( pad );
691 p = gst_caps_get_structure (caps_a, 0);
693 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
695 gst_structure_get_int (p, "rate", &samplerate);
696 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
698 gst_structure_get_int (p, "channels", &channels);
699 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
701 secure_debug_log("samplerate : %d channels : %d", samplerate, channels);
703 gst_caps_unref( caps_a );
706 has_audio_attrs = TRUE;
710 debug_warning("not ready to get audio caps");
713 gst_object_unref( pad );
717 debug_warning("failed to get pad from audiosink");
722 if ( (flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all )
724 debug_log("try to update video attrs");
725 has_video_attrs = FALSE;
727 if ( player->pipeline->videobin &&
728 player->pipeline->videobin[MMPLAYER_V_SINK].gst )
730 GstCaps *caps_v = NULL;
735 pad = gst_element_get_static_pad( player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink" );
738 caps_v = gst_pad_get_current_caps( pad );
740 /* Use v_stream_caps, if fail to get video_sink sink pad*/
741 if (!caps_v && player->v_stream_caps)
743 caps_v = player->v_stream_caps;
744 gst_caps_ref(caps_v);
749 p = gst_caps_get_structure (caps_v, 0);
750 gst_structure_get_int (p, "width", &width);
751 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
753 gst_structure_get_int (p, "height", &height);
754 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
756 gst_structure_get_fraction (p, "framerate", &tmpNu, &tmpDe);
758 secure_debug_log("width : %d height : %d", width, height );
760 gst_caps_unref( caps_v );
765 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
766 secure_debug_log("fps : %d", tmpNu / tmpDe);
769 has_video_attrs = TRUE;
773 debug_log("no negitiated caps from videosink");
775 gst_object_unref( pad );
780 debug_log("no videosink sink pad");
786 if ( (flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all )
790 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
791 if (player->duration)
793 guint64 data_size = 0;
795 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO))
797 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
799 if (stat(path, &sb) == 0)
801 data_size = (guint64)sb.st_size;
804 else if (MMPLAYER_IS_HTTP_STREAMING(player))
806 data_size = player->http_content_size;
808 debug_log("try to update bitrate : data_size = %lld", data_size);
813 guint64 msec_dur = 0;
815 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
816 bitrate = data_size * 8 * 1000 / msec_dur;
817 secure_debug_log("file size : %u, video bitrate = %llu", data_size, bitrate);
818 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
823 if (MMPLAYER_IS_RTSP_STREAMING(player))
825 if(player->total_bitrate)
827 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
835 if ( mmf_attrs_commit ( attrs ) )
837 debug_error("failed to update attributes\n");
846 static gboolean __mmplayer_get_stream_service_type( mm_player_t* player )
848 gint streaming_type = STREAMING_SERVICE_NONE;
852 return_val_if_fail ( player &&
854 player->pipeline->mainbin &&
855 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
858 /* streaming service type if streaming */
859 if ( ! MMPLAYER_IS_STREAMING(player) )
860 return STREAMING_SERVICE_NONE;
862 if (MMPLAYER_IS_HTTP_STREAMING(player))
864 streaming_type = (player->duration == 0) ?
865 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
868 switch ( streaming_type )
870 case STREAMING_SERVICE_LIVE:
871 debug_log("it's live streaming");
873 case STREAMING_SERVICE_VOD:
874 debug_log("it's vod streaming");
876 case STREAMING_SERVICE_NONE:
877 debug_error("should not get here");
880 debug_error("should not get here");
883 player->streaming_type = streaming_type;
886 return streaming_type;
890 /* this function sets the player state and also report
891 * it to applicaton by calling callback function
894 __mmplayer_set_state(mm_player_t* player, int state) // @
896 MMMessageParamType msg = {0, };
897 int sound_result = MM_ERROR_NONE;
898 gboolean post_bos = FALSE;
899 gboolean interrupted_by_asm = FALSE;
900 int ret = MM_ERROR_NONE;
902 return_val_if_fail ( player, FALSE );
904 if ( MMPLAYER_CURRENT_STATE(player) == state )
906 debug_warning("already same state(%s)\n", MMPLAYER_STATE_GET_NAME(state));
907 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
911 /* update player states */
912 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
913 MMPLAYER_CURRENT_STATE(player) = state;
915 /* FIXIT : it's better to do like below code
916 if ( MMPLAYER_CURRENT_STATE(player) == MMPLAYER_TARGET_STATE(player) )
917 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
918 and add more code to handling PENDING_STATE.
920 if ( MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player) )
921 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
924 MMPLAYER_PRINT_STATE(player);
926 /* do some FSM stuffs before posting new state to application */
927 interrupted_by_asm = player->sound_focus.by_asm_cb;
929 switch ( MMPLAYER_CURRENT_STATE(player) )
931 case MM_PLAYER_STATE_NULL:
932 case MM_PLAYER_STATE_READY:
934 if (player->cmd == MMPLAYER_COMMAND_STOP)
936 sound_result = _mmplayer_sound_release_focus(&player->sound_focus);
937 if ( sound_result != MM_ERROR_NONE )
939 debug_error("failed to release sound focus\n");
940 return MM_ERROR_POLICY_INTERNAL;
946 case MM_PLAYER_STATE_PAUSED:
948 if ( ! player->sent_bos )
951 #define MMPLAYER_MAX_SOUND_PRIORITY 3
953 /* it's first time to update all content attrs. */
954 _mmplayer_update_content_attrs( player, ATTR_ALL );
955 /* set max sound priority to keep own sound and not to mute other's one */
956 mm_attrs_get_int_by_name(player->attrs, "content_video_found", &found);
959 mm_attrs_get_int_by_name(player->attrs, "content_audio_found", &found);
962 debug_log("set max audio priority");
963 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "priority", MMPLAYER_MAX_SOUND_PRIORITY, NULL);
969 /* add audio callback probe if condition is satisfied */
970 if ( ! player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
972 __mmplayer_configure_audio_callback(player);
973 /* FIXIT : handle return value */
976 if (!MMPLAYER_IS_STREAMING(player) || (player->streamer && !player->streamer->is_buffering))
978 sound_result = _mmplayer_sound_release_focus(&player->sound_focus);
979 if ( sound_result != MM_ERROR_NONE )
981 debug_error("failed to release sound focus\n");
982 return MM_ERROR_POLICY_INTERNAL;
988 case MM_PLAYER_STATE_PLAYING:
990 /* try to get content metadata */
991 if ( ! player->sent_bos )
993 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
994 * c-api since c-api doesn't use _start() anymore. It may not work propery with
995 * legacy mmfw-player api */
996 _mmplayer_update_content_attrs( player, ATTR_MISSING_ONLY);
999 if ( (player->cmd == MMPLAYER_COMMAND_START) || (player->cmd == MMPLAYER_COMMAND_RESUME) )
1001 if (!player->sent_bos)
1003 __mmplayer_handle_missed_plugin ( player );
1005 sound_result = _mmplayer_sound_acquire_focus(&player->sound_focus);
1006 if (sound_result != MM_ERROR_NONE)
1008 // FIXME : need to check history
1009 if (player->pipeline->videobin)
1011 MMMessageParamType msg = {0, };
1013 debug_error("failed to go ahead because of video conflict\n");
1015 msg.union_type = MM_MSG_UNION_CODE;
1016 msg.code = MM_ERROR_POLICY_INTERRUPTED;
1017 MMPLAYER_POST_MSG( player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
1019 _mmplayer_unrealize((MMHandleType)player);
1023 debug_error("failed to play by sound focus error : 0x%X\n", sound_result);
1024 _mmplayer_pause((MMHandleType)player);
1025 return sound_result;
1028 return MM_ERROR_POLICY_INTERNAL;
1032 if ( player->resumed_by_rewind && player->playback_rate < 0.0 )
1034 /* initialize because auto resume is done well. */
1035 player->resumed_by_rewind = FALSE;
1036 player->playback_rate = 1.0;
1039 if ( !player->sent_bos )
1041 /* check audio codec field is set or not
1042 * we can get it from typefinder or codec's caps.
1044 gchar *audio_codec = NULL;
1045 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
1047 /* The codec format can't be sent for audio only case like amr, mid etc.
1048 * Because, parser don't make related TAG.
1049 * So, if it's not set yet, fill it with found data.
1051 if ( ! audio_codec )
1053 if ( g_strrstr(player->type, "audio/midi"))
1055 audio_codec = g_strdup("MIDI");
1058 else if ( g_strrstr(player->type, "audio/x-amr"))
1060 audio_codec = g_strdup("AMR");
1062 else if ( g_strrstr(player->type, "audio/mpeg") && !g_strrstr(player->type, "mpegversion=(int)1"))
1064 audio_codec = g_strdup("AAC");
1068 audio_codec = g_strdup("unknown");
1070 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
1072 MMPLAYER_FREEIF(audio_codec);
1073 mmf_attrs_commit(player->attrs);
1074 debug_log("set audio codec type with caps\n");
1082 case MM_PLAYER_STATE_NONE:
1084 debug_warning("invalid target state, there is nothing to do.\n");
1089 /* post message to application */
1090 if (MMPLAYER_TARGET_STATE(player) == state)
1092 /* fill the message with state of player */
1093 msg.state.previous = MMPLAYER_PREV_STATE(player);
1094 msg.state.current = MMPLAYER_CURRENT_STATE(player);
1096 debug_log ("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
1098 /* state changed by asm callback */
1099 if ( interrupted_by_asm )
1101 msg.union_type = MM_MSG_UNION_CODE;
1102 msg.code = player->sound_focus.focus_changed_msg; /* FIXME: player.c convert function have to be modified. */
1103 MMPLAYER_POST_MSG( player, MM_MESSAGE_STATE_INTERRUPTED, &msg );
1105 /* state changed by usecase */
1108 MMPLAYER_POST_MSG( player, MM_MESSAGE_STATE_CHANGED, &msg );
1113 debug_log ("intermediate state, do nothing.\n");
1114 MMPLAYER_PRINT_STATE(player);
1120 MMPLAYER_POST_MSG ( player, MM_MESSAGE_BEGIN_OF_STREAM, NULL );
1121 player->sent_bos = TRUE;
1127 static gpointer __mmplayer_next_play_thread(gpointer data)
1129 mm_player_t* player = (mm_player_t*) data;
1130 MMPlayerGstElement *mainbin = NULL;
1132 return_val_if_fail ( player, NULL );
1134 g_mutex_lock(&player->next_play_thread_mutex);
1135 while ( ! player->next_play_thread_exit )
1137 debug_log("next play thread started. waiting for signal.\n");
1138 g_cond_wait(&player->next_play_thread_cond, &player->next_play_thread_mutex );
1140 debug_log("reconfigure pipeline for gapless play.\n");
1142 if ( player->next_play_thread_exit )
1144 if(player->gapless.reconfigure)
1146 player->gapless.reconfigure = false;
1147 MMPLAYER_PLAYBACK_UNLOCK(player);
1149 debug_log("exiting gapless play thread\n");
1153 mainbin = player->pipeline->mainbin;
1155 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
1156 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
1157 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
1158 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
1159 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
1161 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
1163 g_mutex_unlock(&player->next_play_thread_mutex);
1168 static gpointer __mmplayer_repeat_thread(gpointer data)
1170 mm_player_t* player = (mm_player_t*) data;
1171 gboolean ret_value = FALSE;
1172 MMHandleType attrs = 0;
1175 return_val_if_fail ( player, NULL );
1177 g_mutex_lock(&player->repeat_thread_mutex);
1178 while ( ! player->repeat_thread_exit )
1180 debug_log("repeat thread started. waiting for signal.\n");
1181 g_cond_wait(&player->repeat_thread_cond, &player->repeat_thread_mutex );
1183 if ( player->repeat_thread_exit )
1185 debug_log("exiting repeat thread\n");
1191 g_mutex_lock(&player->cmd_lock);
1193 attrs = MMPLAYER_GET_ATTRS(player);
1195 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
1197 debug_error("can not get play count\n");
1201 if ( player->section_repeat )
1203 ret_value = _mmplayer_activate_section_repeat((MMHandleType)player, player->section_repeat_start, player->section_repeat_end);
1207 if ( player->playback_rate < 0.0 )
1209 player->resumed_by_rewind = TRUE;
1210 _mmplayer_set_mute((MMHandleType)player, 0);
1211 MMPLAYER_POST_MSG( player, MM_MESSAGE_RESUMED_BY_REW, NULL );
1214 ret_value = __gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
1215 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET,
1216 0, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
1219 player->sent_bos = FALSE;
1224 debug_error("failed to set position to zero for rewind\n");
1228 /* decrease play count */
1231 /* we successeded to rewind. update play count and then wait for next EOS */
1234 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
1236 /* commit attribute */
1237 if ( mmf_attrs_commit ( attrs ) )
1239 debug_error("failed to commit attribute\n");
1244 g_mutex_unlock(&player->cmd_lock);
1247 g_mutex_unlock(&player->repeat_thread_mutex);
1252 __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg)
1254 MMHandleType attrs = 0;
1255 guint64 data_size = 0;
1257 unsigned long pos_msec = 0;
1260 return_if_fail( player && player->pipeline && player->pipeline->mainbin);
1262 __gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &pos_msec); // update last_position
1264 attrs = MMPLAYER_GET_ATTRS(player);
1267 debug_error("fail to get attributes.\n");
1271 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO))
1273 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
1275 if (stat(path, &sb) == 0)
1277 data_size = (guint64)sb.st_size;
1280 else if (MMPLAYER_IS_HTTP_STREAMING(player))
1282 data_size = player->http_content_size;
1285 __mm_player_streaming_buffering( player->streamer,
1288 player->last_position,
1291 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
1297 __mmplayer_handle_buffering_message ( mm_player_t* player )
1299 int ret = MM_ERROR_NONE;
1300 MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
1301 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
1302 MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
1303 MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
1305 MMPLAYER_CMD_LOCK( player );
1307 if( !player || !player->streamer || MMPLAYER_IS_LIVE_STREAMING(player))
1309 ret = MM_ERROR_PLAYER_INVALID_STATE;
1313 prev_state = MMPLAYER_PREV_STATE(player);
1314 current_state = MMPLAYER_CURRENT_STATE(player);
1315 target_state = MMPLAYER_TARGET_STATE(player);
1316 pending_state = MMPLAYER_PENDING_STATE(player);
1318 debug_log( "player state : prev %s, current %s, pending %s, target %s, buffering %d",
1319 MMPLAYER_STATE_GET_NAME(prev_state),
1320 MMPLAYER_STATE_GET_NAME(current_state),
1321 MMPLAYER_STATE_GET_NAME(pending_state),
1322 MMPLAYER_STATE_GET_NAME(target_state),
1323 player->streamer->is_buffering);
1325 if ( !player->streamer->is_buffering )
1327 /* NOTE : if buffering has done, player has to go to target state. */
1328 switch ( target_state )
1330 case MM_PLAYER_STATE_PAUSED :
1332 switch ( pending_state )
1334 case MM_PLAYER_STATE_PLAYING:
1336 __gst_pause ( player, TRUE );
1340 case MM_PLAYER_STATE_PAUSED:
1342 debug_log("player is already going to paused state, there is nothing to do.\n");
1346 case MM_PLAYER_STATE_NONE:
1347 case MM_PLAYER_STATE_NULL:
1348 case MM_PLAYER_STATE_READY:
1351 debug_warning("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state) );
1358 case MM_PLAYER_STATE_PLAYING :
1360 switch ( pending_state )
1362 case MM_PLAYER_STATE_NONE:
1364 if (current_state != MM_PLAYER_STATE_PLAYING)
1365 __gst_resume ( player, TRUE );
1369 case MM_PLAYER_STATE_PAUSED:
1371 /* NOTE: It should be worked as asynchronously.
1372 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
1374 __gst_resume ( player, TRUE );
1378 case MM_PLAYER_STATE_PLAYING:
1380 debug_log("player is already going to playing state, there is nothing to do.\n");
1384 case MM_PLAYER_STATE_NULL:
1385 case MM_PLAYER_STATE_READY:
1388 debug_warning("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state) );
1395 case MM_PLAYER_STATE_NULL :
1396 case MM_PLAYER_STATE_READY :
1397 case MM_PLAYER_STATE_NONE :
1400 debug_warning("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state) );
1407 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1408 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
1410 switch ( pending_state )
1412 case MM_PLAYER_STATE_NONE:
1414 if (current_state != MM_PLAYER_STATE_PAUSED)
1416 debug_log("set pause state during buffering\n");
1417 __gst_pause ( player, TRUE );
1419 // to cover the weak-signal environment.
1420 if (MMPLAYER_IS_RTSP_STREAMING(player))
1422 unsigned long position = 0;
1423 gint64 pos_msec = 0;
1425 debug_log("[RTSP] seek to the buffering start point\n");
1427 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position ))
1429 debug_error("failed to get position\n");
1434 pos_msec = position * G_GINT64_CONSTANT(1000000);
1436 __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
1437 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET,
1438 pos_msec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
1444 case MM_PLAYER_STATE_PLAYING:
1446 __gst_pause ( player, TRUE );
1450 case MM_PLAYER_STATE_PAUSED:
1455 case MM_PLAYER_STATE_NULL:
1456 case MM_PLAYER_STATE_READY:
1459 debug_warning("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state) );
1466 MMPLAYER_CMD_UNLOCK( player );
1471 __mmplayer_drop_subtitle(mm_player_t* player, gboolean is_drop)
1473 MMPlayerGstElement *textbin;
1476 return_if_fail ( player &&
1478 player->pipeline->textbin);
1480 return_if_fail (player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1482 textbin = player->pipeline->textbin;
1486 debug_log("Drop subtitle text after getting EOS\n");
1488 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", FALSE, NULL);
1489 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
1491 player->is_subtitle_force_drop = TRUE;
1495 if (player->is_subtitle_force_drop == TRUE)
1497 debug_log("Enable subtitle data path without drop\n");
1499 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
1500 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", TRUE, NULL);
1502 debug_log ("non-connected with external display");
1504 player->is_subtitle_force_drop = FALSE;
1510 __mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data) // @
1512 mm_player_t* player = (mm_player_t*) data;
1513 gboolean ret = TRUE;
1514 static gboolean async_done = FALSE;
1516 return_val_if_fail ( player, FALSE );
1517 return_val_if_fail ( msg && GST_IS_MESSAGE(msg), FALSE );
1519 switch ( GST_MESSAGE_TYPE( msg ) )
1521 case GST_MESSAGE_UNKNOWN:
1522 debug_log("unknown message received\n");
1525 case GST_MESSAGE_EOS:
1527 MMHandleType attrs = 0;
1530 debug_log("GST_MESSAGE_EOS received\n");
1532 /* NOTE : EOS event is comming multiple time. watch out it */
1533 /* check state. we only process EOS when pipeline state goes to PLAYING */
1534 if ( ! (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) )
1536 debug_log("EOS received on non-playing state. ignoring it\n");
1540 __mmplayer_drop_subtitle(player, TRUE);
1542 if ( (player->audio_stream_cb) && (player->set_mode.pcm_extraction) && (!player->audio_stream_render_cb_ex))
1546 pad = gst_element_get_static_pad (player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
1548 debug_log("release audio callback\n");
1550 /* release audio callback */
1551 gst_pad_remove_probe (pad, player->audio_cb_probe_id);
1552 player->audio_cb_probe_id = 0;
1553 /* audio callback should be free because it can be called even though probe remove.*/
1554 player->audio_stream_cb = NULL;
1555 player->audio_stream_cb_user_param = NULL;
1559 /* rewind if repeat count is greater then zero */
1560 /* get play count */
1561 attrs = MMPLAYER_GET_ATTRS(player);
1565 gboolean smooth_repeat = FALSE;
1567 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1568 mm_attrs_get_int_by_name(attrs, "profile_smooth_repeat", &smooth_repeat);
1570 player->play_count = count;
1572 debug_log("remaining play count: %d, playback rate: %f\n", count, player->playback_rate);
1574 if ( count > 1 || count == -1 || player->playback_rate < 0.0 ) /* default value is 1 */
1576 if ( smooth_repeat )
1578 debug_log("smooth repeat enabled. seeking operation will be excuted in new thread\n");
1580 g_cond_signal( &player->repeat_thread_cond );
1588 if ( player->section_repeat )
1590 ret_value = _mmplayer_activate_section_repeat((MMHandleType)player, player->section_repeat_start, player->section_repeat_end);
1594 if ( player->playback_rate < 0.0 )
1596 player->resumed_by_rewind = TRUE;
1597 _mmplayer_set_mute((MMHandleType)player, 0);
1598 MMPLAYER_POST_MSG( player, MM_MESSAGE_RESUMED_BY_REW, NULL );
1601 __mmplayer_handle_eos_delay( player, player->ini.delay_before_repeat );
1604 player->sent_bos = FALSE;
1607 if ( MM_ERROR_NONE != ret_value )
1609 debug_error("failed to set position to zero for rewind\n");
1612 /* not posting eos when repeating */
1618 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-eos" );
1620 /* post eos message to application */
1621 __mmplayer_handle_eos_delay( player, player->ini.eos_delay );
1623 /* reset last position */
1624 player->last_position = 0;
1628 case GST_MESSAGE_ERROR:
1630 GError *error = NULL;
1631 gchar* debug = NULL;
1633 /* generating debug info before returning error */
1634 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-error" );
1636 /* get error code */
1637 gst_message_parse_error( msg, &error, &debug );
1639 if ( gst_structure_has_name ( gst_message_get_structure(msg), "streaming_error" ) )
1641 /* Note : the streaming error from the streaming source is handled
1642 * using __mmplayer_handle_streaming_error.
1644 __mmplayer_handle_streaming_error ( player, msg );
1646 /* dump state of all element */
1647 __mmplayer_dump_pipeline_state( player );
1651 /* traslate gst error code to msl error code. then post it
1652 * to application if needed
1654 __mmplayer_handle_gst_error( player, msg, error );
1658 debug_error ("error debug : %s", debug);
1663 if (MMPLAYER_IS_HTTP_PD(player))
1665 _mmplayer_unrealize_pd_downloader ((MMHandleType)player);
1668 MMPLAYER_FREEIF( debug );
1669 g_error_free( error );
1673 case GST_MESSAGE_WARNING:
1676 GError* error = NULL;
1678 gst_message_parse_warning(msg, &error, &debug);
1680 debug_log("warning : %s\n", error->message);
1681 debug_log("debug : %s\n", debug);
1683 MMPLAYER_POST_MSG( player, MM_MESSAGE_WARNING, NULL );
1685 MMPLAYER_FREEIF( debug );
1686 g_error_free( error );
1690 case GST_MESSAGE_TAG:
1692 debug_log("GST_MESSAGE_TAG\n");
1693 if ( ! __mmplayer_gst_extract_tag_from_msg( player, msg ) )
1695 debug_warning("failed to extract tags from gstmessage\n");
1700 case GST_MESSAGE_BUFFERING:
1702 MMMessageParamType msg_param = {0, };
1704 if (!MMPLAYER_IS_STREAMING(player))
1707 /* ignore the prev buffering message */
1708 if ((player->streamer) && (player->streamer->is_buffering == FALSE) && (player->streamer->is_buffering_done == TRUE))
1710 gint buffer_percent = 0;
1712 gst_message_parse_buffering (msg, &buffer_percent);
1714 if (buffer_percent == MAX_BUFFER_PERCENT)
1716 debug_log ("Ignored all the previous buffering msg! (got %d%%)\n", buffer_percent);
1717 player->streamer->is_buffering_done = FALSE;
1723 __mmplayer_update_buffer_setting(player, msg);
1725 if(__mmplayer_handle_buffering_message ( player ) == MM_ERROR_NONE) {
1727 msg_param.connection.buffering = player->streamer->buffering_percent;
1728 MMPLAYER_POST_MSG ( player, MM_MESSAGE_BUFFERING, &msg_param );
1729 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1730 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT))
1732 if (player->doing_seek)
1734 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED)
1736 player->doing_seek = FALSE;
1737 MMPLAYER_POST_MSG ( player, MM_MESSAGE_SEEK_COMPLETED, NULL );
1739 else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING)
1749 case GST_MESSAGE_STATE_CHANGED:
1751 MMPlayerGstElement *mainbin;
1752 const GValue *voldstate, *vnewstate, *vpending;
1753 GstState oldstate, newstate, pending;
1755 if ( ! ( player->pipeline && player->pipeline->mainbin ) )
1757 debug_error("player pipeline handle is null");
1761 mainbin = player->pipeline->mainbin;
1763 /* we only handle messages from pipeline */
1764 if( msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst )
1767 /* get state info from msg */
1768 voldstate = gst_structure_get_value (gst_message_get_structure(msg), "old-state");
1769 vnewstate = gst_structure_get_value (gst_message_get_structure(msg), "new-state");
1770 vpending = gst_structure_get_value (gst_message_get_structure(msg), "pending-state");
1772 oldstate = (GstState)voldstate->data[0].v_int;
1773 newstate = (GstState)vnewstate->data[0].v_int;
1774 pending = (GstState)vpending->data[0].v_int;
1776 debug_log("state changed [%s] : %s ---> %s final : %s\n",
1777 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1778 gst_element_state_get_name( (GstState)oldstate ),
1779 gst_element_state_get_name( (GstState)newstate ),
1780 gst_element_state_get_name( (GstState)pending ) );
1782 if (oldstate == newstate)
1784 debug_log("pipeline reports state transition to old state");
1790 case GST_STATE_VOID_PENDING:
1793 case GST_STATE_NULL:
1796 case GST_STATE_READY:
1799 case GST_STATE_PAUSED:
1801 gboolean prepare_async = FALSE;
1802 gboolean is_drm = FALSE;
1804 if ( ! player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
1805 __mmplayer_configure_audio_callback(player);
1807 if ( ! player->sent_bos && oldstate == GST_STATE_READY) // managed prepare async case
1809 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1810 debug_log("checking prepare mode for async transition - %d", prepare_async);
1813 if ( MMPLAYER_IS_STREAMING(player) || prepare_async )
1815 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_PAUSED );
1817 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1819 __mm_player_streaming_set_content_bitrate(player->streamer,
1820 player->total_maximum_bitrate, player->total_bitrate);
1824 /* NOTE : should consider streaming case */
1825 /* check if drm file */
1826 if ((player->pipeline->mainbin[MMPLAYER_M_SRC].gst) &&
1827 (g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), "is-drm")))
1829 g_object_get(G_OBJECT(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), "is-drm", &is_drm, NULL);
1833 player->is_drm_file = TRUE;
1839 case GST_STATE_PLAYING:
1841 /* for audio tunning */
1843 if (player->can_support_codec == 0x03) {
1845 mm_attrs_get_int_by_name(player->attrs, "sound_volume_type", &volume_type);
1846 volume_type |= MM_SOUND_VOLUME_GAIN_VIDEO;
1847 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "volumetype", volume_type, NULL);
1850 if ( MMPLAYER_IS_STREAMING(player) ) // managed prepare async case when buffering is completed
1852 // pending state should be reset oyherwise, it's still playing even though it's resumed after bufferging.
1853 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1854 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1856 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_PLAYING);
1860 if (player->gapless.stream_changed)
1862 _mmplayer_update_content_attrs(player, ATTR_ALL);
1865 if (player->doing_seek && async_done)
1867 player->doing_seek = FALSE;
1869 MMPLAYER_POST_MSG ( player, MM_MESSAGE_SEEK_COMPLETED, NULL );
1880 case GST_MESSAGE_CLOCK_LOST:
1882 GstClock *clock = NULL;
1883 gboolean need_new_clock = FALSE;
1885 gst_message_parse_clock_lost (msg, &clock);
1886 debug_log("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME (clock) : "NULL"));
1888 if (!player->videodec_linked)
1890 need_new_clock = TRUE;
1892 else if (!player->ini.use_system_clock)
1894 need_new_clock = TRUE;
1897 if (need_new_clock) {
1898 debug_log ("Provide clock is TRUE, do pause->resume\n");
1899 __gst_pause(player, FALSE);
1900 __gst_resume(player, FALSE);
1905 case GST_MESSAGE_NEW_CLOCK:
1907 GstClock *clock = NULL;
1908 gst_message_parse_new_clock (msg, &clock);
1909 debug_log("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME (clock) : "NULL"));
1913 case GST_MESSAGE_ELEMENT:
1915 const gchar *structure_name;
1917 MMHandleType attrs = 0;
1919 attrs = MMPLAYER_GET_ATTRS(player);
1922 debug_error("cannot get content attribute");
1927 if(gst_message_get_structure(msg) == NULL)
1930 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1931 if(!strcmp(structure_name, "Language_list"))
1933 const GValue *lang_list = NULL;
1934 lang_list = gst_structure_get_value (gst_message_get_structure(msg), "lang_list");
1935 if(lang_list != NULL)
1937 count = g_list_length((GList *)g_value_get_pointer (lang_list));
1939 debug_log("Total audio tracks (from parser) = %d \n",count);
1943 if (!strcmp (structure_name, "Ext_Sub_Language_List"))
1945 const GValue *lang_list = NULL;
1946 MMPlayerLangStruct *temp = NULL;
1948 lang_list = gst_structure_get_value (gst_message_get_structure(msg), "lang_list");
1949 if (lang_list != NULL)
1951 count = g_list_length ((GList *)g_value_get_pointer (lang_list));
1954 player->subtitle_language_list = (GList *)g_value_get_pointer (lang_list);
1955 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)count);
1956 if (mmf_attrs_commit (attrs))
1957 debug_error("failed to commit.\n");
1958 debug_log("Total subtitle tracks = %d \n", count);
1962 temp = g_list_nth_data (player->subtitle_language_list, count - 1);
1963 debug_log ("value of lang_key is %s and lang_code is %s",
1964 temp->language_key, temp->language_code);
1970 /* custom message */
1971 if (!strcmp (structure_name, "audio_codec_not_supported")) {
1972 MMMessageParamType msg_param = {0,};
1973 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1974 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1979 case GST_MESSAGE_DURATION_CHANGED:
1981 debug_log("GST_MESSAGE_DURATION_CHANGED\n");
1982 ret = __mmplayer_gst_handle_duration(player, msg);
1985 debug_warning("failed to update duration");
1991 case GST_MESSAGE_ASYNC_START:
1993 debug_log("GST_MESSAGE_ASYNC_START : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1997 case GST_MESSAGE_ASYNC_DONE:
1999 debug_log("GST_MESSAGE_ASYNC_DONE : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2001 /* we only handle messages from pipeline */
2002 if( msg->src != (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst )
2005 if (player->doing_seek)
2007 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED)
2009 player->doing_seek = FALSE;
2010 MMPLAYER_POST_MSG ( player, MM_MESSAGE_SEEK_COMPLETED, NULL );
2012 else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING)
2014 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
2015 (player->streamer) &&
2016 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
2017 (player->streamer->is_buffering == FALSE))
2019 GstQuery *query = NULL;
2020 gboolean busy = FALSE;
2023 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer)
2025 query = gst_query_new_buffering ( GST_FORMAT_PERCENT );
2026 if ( gst_element_query (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query ) )
2028 gst_query_parse_buffering_percent ( query, &busy, &percent);
2030 gst_query_unref (query);
2032 debug_log("buffered percent(%s): %d\n",
2033 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
2038 player->streamer->is_buffering = FALSE;
2039 __mmplayer_handle_buffering_message(player);
2049 #if 0 /* delete unnecessary logs */
2050 case GST_MESSAGE_REQUEST_STATE: debug_log("GST_MESSAGE_REQUEST_STATE\n"); break;
2051 case GST_MESSAGE_STEP_START: debug_log("GST_MESSAGE_STEP_START\n"); break;
2052 case GST_MESSAGE_QOS: debug_log("GST_MESSAGE_QOS\n"); break;
2053 case GST_MESSAGE_PROGRESS: debug_log("GST_MESSAGE_PROGRESS\n"); break;
2054 case GST_MESSAGE_ANY: debug_log("GST_MESSAGE_ANY\n"); break;
2055 case GST_MESSAGE_INFO: debug_log("GST_MESSAGE_STATE_DIRTY\n"); break;
2056 case GST_MESSAGE_STATE_DIRTY: debug_log("GST_MESSAGE_STATE_DIRTY\n"); break;
2057 case GST_MESSAGE_STEP_DONE: debug_log("GST_MESSAGE_STEP_DONE\n"); break;
2058 case GST_MESSAGE_CLOCK_PROVIDE: debug_log("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
2059 case GST_MESSAGE_STRUCTURE_CHANGE: debug_log("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
2060 case GST_MESSAGE_STREAM_STATUS: debug_log("GST_MESSAGE_STREAM_STATUS\n"); break;
2061 case GST_MESSAGE_APPLICATION: debug_log("GST_MESSAGE_APPLICATION\n"); break;
2062 case GST_MESSAGE_SEGMENT_START: debug_log("GST_MESSAGE_SEGMENT_START\n"); break;
2063 case GST_MESSAGE_SEGMENT_DONE: debug_log("GST_MESSAGE_SEGMENT_DONE\n"); break;
2064 case GST_MESSAGE_LATENCY: debug_log("GST_MESSAGE_LATENCY\n"); break;
2071 /* FIXIT : this cause so many warnings/errors from glib/gstreamer. we should not call it since
2072 * gst_element_post_message api takes ownership of the message.
2074 //gst_message_unref( msg );
2080 __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg)
2086 return_val_if_fail(player, FALSE);
2087 return_val_if_fail(msg, FALSE);
2089 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
2090 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst))
2092 debug_log("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
2094 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes))
2096 debug_log("data total size of http content: %lld", bytes);
2097 player->http_content_size = bytes;
2102 /* handling audio clip which has vbr. means duration is keep changing */
2103 _mmplayer_update_content_attrs (player, ATTR_DURATION );
2113 __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg) // @
2116 /* macro for better code readability */
2117 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
2118 if (gst_tag_list_get_string(tag_list, gsttag, &string)) \
2120 if (string != NULL)\
2122 secure_debug_log ( "update tag string : %s\n", string); \
2123 mm_attrs_set_string_by_name(attribute, playertag, string); \
2129 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
2130 GstSample *sample = NULL;\
2131 if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample))\
2133 GstMapInfo info = GST_MAP_INFO_INIT;\
2134 buffer = gst_sample_get_buffer(sample);\
2135 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)){\
2136 debug_log("failed to get image data from tag");\
2139 secure_debug_log ( "update album cover data : %p, size : %d\n", info.data, info.size);\
2140 MMPLAYER_FREEIF(player->album_art); \
2141 player->album_art = (gchar *)g_malloc(info.size); \
2142 if (player->album_art) \
2144 memcpy(player->album_art, info.data, info.size); \
2145 mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size); \
2146 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) \
2148 msg_param.data = (void *)player->album_art; \
2149 msg_param.size = info.size; \
2150 MMPLAYER_POST_MSG (player, MM_MESSAGE_IMAGE_BUFFER, &msg_param); \
2151 secure_debug_log ( "post message image buffer data : %p, size : %d\n", info.data, info.size); \
2154 gst_buffer_unmap(buffer, &info); \
2157 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
2158 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint))\
2162 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) \
2164 if (player->updated_bitrate_count == 0) \
2165 mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
2166 if (player->updated_bitrate_count<MM_PLAYER_STREAM_COUNT_MAX) \
2168 player->bitrate[player->updated_bitrate_count] = v_uint;\
2169 player->total_bitrate += player->bitrate[player->updated_maximum_bitrate_count]; \
2170 player->updated_bitrate_count++; \
2171 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate);\
2172 secure_debug_log ( "update bitrate %d[bps] of stream #%d.\n", v_uint, player->updated_bitrate_count);\
2175 else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) \
2177 if (player->updated_maximum_bitrate_count<MM_PLAYER_STREAM_COUNT_MAX) \
2179 player->maximum_bitrate[player->updated_maximum_bitrate_count] = v_uint;\
2180 player->total_maximum_bitrate += player->maximum_bitrate[player->updated_maximum_bitrate_count]; \
2181 player->updated_maximum_bitrate_count++; \
2182 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate); \
2183 secure_debug_log ( "update maximum bitrate %d[bps] of stream #%d\n", v_uint, player->updated_maximum_bitrate_count);\
2188 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
2194 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
2195 if (gst_tag_list_get_date(tag_list, gsttag, &date))\
2199 string = g_strdup_printf("%d", g_date_get_year(date));\
2200 mm_attrs_set_string_by_name(attribute, playertag, string);\
2201 secure_debug_log ( "metainfo year : %s\n", string);\
2202 MMPLAYER_FREEIF(string);\
2207 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
2208 if(gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64))\
2212 /* FIXIT : don't know how to store date */\
2218 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
2219 if(gst_tag_list_get_double(tag_list, gsttag, &v_double))\
2223 /* FIXIT : don't know how to store date */\
2229 /* function start */
2230 GstTagList* tag_list = NULL;
2232 MMHandleType attrs = 0;
2234 char *string = NULL;
2238 GstBuffer *buffer = NULL;
2240 MMMessageParamType msg_param = {0, };
2242 /* currently not used. but those are needed for above macro */
2243 //guint64 v_uint64 = 0;
2244 //gdouble v_double = 0;
2246 return_val_if_fail( player && msg, FALSE );
2248 attrs = MMPLAYER_GET_ATTRS(player);
2250 return_val_if_fail( attrs, FALSE );
2252 /* get tag list from gst message */
2253 gst_message_parse_tag(msg, &tag_list);
2255 /* store tags to player attributes */
2256 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
2257 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
2258 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
2259 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
2260 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
2261 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
2262 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
2263 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
2264 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
2265 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
2266 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
2267 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
2268 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
2269 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
2270 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
2271 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
2272 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
2273 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
2274 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
2275 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
2276 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
2277 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
2278 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
2279 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
2280 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
2281 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
2282 /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
2283 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
2284 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
2285 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
2286 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
2287 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
2288 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
2289 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
2290 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
2291 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
2292 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
2293 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
2294 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
2295 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
2296 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
2297 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
2298 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
2299 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
2300 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
2301 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation");
2303 if ( mmf_attrs_commit ( attrs ) )
2304 debug_error("failed to commit.\n");
2306 gst_tag_list_free(tag_list);
2312 __mmplayer_gst_rtp_no_more_pads (GstElement *element, gpointer data) // @
2314 mm_player_t* player = (mm_player_t*) data;
2318 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2319 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2320 * num_dynamic_pad. and this is no-more-pad situation which means mo more pad will be added.
2321 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2323 * [1] audio and video will be dumped with filesink.
2324 * [2] autoplugging is done by just using pad caps.
2325 * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2326 * and the video will be dumped via filesink.
2328 if ( player->num_dynamic_pad == 0 )
2330 debug_log("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
2332 if ( ! __mmplayer_gst_remove_fakesink( player,
2333 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]) )
2335 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
2336 * signaling mechanism ( pad-added, no-more-pad, new-decoded-pad ) from various
2337 * source element are not same. To overcome this situation, this function will called
2338 * several places and several times. Therefore, this is not an error case.
2344 /* create dot before error-return. for debugging */
2345 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-no-more-pad" );
2347 player->no_more_pad = TRUE;
2353 __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink) // @
2355 GstElement* parent = NULL;
2357 return_val_if_fail(player && player->pipeline, FALSE);
2359 /* if we have no fakesink. this meas we are using decodebin which doesn'
2360 t need to add extra fakesink */
2361 return_val_if_fail(fakesink, TRUE);
2364 g_mutex_lock(&player->fsink_lock );
2366 if ( ! fakesink->gst )
2371 /* get parent of fakesink */
2372 parent = (GstElement*)gst_object_get_parent( (GstObject*)fakesink->gst );
2375 debug_log("fakesink already removed\n");
2379 gst_element_set_locked_state( fakesink->gst, TRUE );
2381 /* setting the state to NULL never returns async
2382 * so no need to wait for completion of state transiton
2384 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state (fakesink->gst, GST_STATE_NULL) )
2386 debug_error("fakesink state change failure!\n");
2388 /* FIXIT : should I return here? or try to proceed to next? */
2392 /* remove fakesink from it's parent */
2393 if ( ! gst_bin_remove( GST_BIN( parent ), fakesink->gst ) )
2395 debug_error("failed to remove fakesink\n");
2397 gst_object_unref( parent );
2402 gst_object_unref( parent );
2404 debug_log("state-holder removed\n");
2406 gst_element_set_locked_state( fakesink->gst, FALSE );
2408 g_mutex_unlock( &player->fsink_lock );
2412 if ( fakesink->gst )
2414 gst_element_set_locked_state( fakesink->gst, FALSE );
2417 g_mutex_unlock( &player->fsink_lock );
2423 __mmplayer_gst_rtp_dynamic_pad (GstElement *element, GstPad *pad, gpointer data) // @
2425 GstPad *sinkpad = NULL;
2426 GstCaps* caps = NULL;
2427 GstElement* new_element = NULL;
2428 GstStructure* str = NULL;
2429 const gchar* name = NULL;
2431 mm_player_t* player = (mm_player_t*) data;
2435 return_if_fail( element && pad );
2436 return_if_fail( player &&
2438 player->pipeline->mainbin );
2441 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2442 * num_dynamic_pad will decreased after creating a sinkbin.
2444 player->num_dynamic_pad++;
2445 debug_log("stream count inc : %d\n", player->num_dynamic_pad);
2447 caps = gst_pad_query_caps( pad, NULL );
2449 MMPLAYER_CHECK_NULL( caps );
2451 /* clear previous result*/
2452 player->have_dynamic_pad = FALSE;
2454 str = gst_caps_get_structure(caps, 0);
2458 debug_error ("cannot get structure from caps.\n");
2462 name = gst_structure_get_name (str);
2465 debug_error ("cannot get mimetype from structure.\n");
2469 if (strstr(name, "video"))
2472 mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &stype);
2474 if (stype == MM_DISPLAY_SURFACE_NULL)
2476 if (player->v_stream_caps)
2478 gst_caps_unref(player->v_stream_caps);
2479 player->v_stream_caps = NULL;
2482 new_element = gst_element_factory_make("fakesink", NULL);
2483 player->num_dynamic_pad--;
2488 /* clear previous result*/
2489 player->have_dynamic_pad = FALSE;
2491 if ( !__mmplayer_try_to_plug_decodebin(player, pad, caps))
2493 debug_error("failed to autoplug for caps");
2497 /* check if there's dynamic pad*/
2498 if( player->have_dynamic_pad )
2500 debug_error("using pad caps assums there's no dynamic pad !\n");
2504 gst_caps_unref( caps );
2509 /* excute new_element if created*/
2512 debug_log("adding new element to pipeline\n");
2514 /* set state to READY before add to bin */
2515 MMPLAYER_ELEMENT_SET_STATE( new_element, GST_STATE_READY );
2517 /* add new element to the pipeline */
2518 if ( FALSE == gst_bin_add( GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element) )
2520 debug_error("failed to add autoplug element to bin\n");
2524 /* get pad from element */
2525 sinkpad = gst_element_get_static_pad ( GST_ELEMENT(new_element), "sink" );
2528 debug_error("failed to get sinkpad from autoplug element\n");
2533 if ( GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad) )
2535 debug_error("failed to link autoplug element\n");
2539 gst_object_unref (sinkpad);
2542 /* run. setting PLAYING here since streamming source is live source */
2543 MMPLAYER_ELEMENT_SET_STATE( new_element, GST_STATE_PLAYING );
2550 STATE_CHANGE_FAILED:
2552 /* FIXIT : take care if new_element has already added to pipeline */
2554 gst_object_unref(GST_OBJECT(new_element));
2557 gst_object_unref(GST_OBJECT(sinkpad));
2560 gst_object_unref(GST_OBJECT(caps));
2562 /* FIXIT : how to inform this error to MSL ????? */
2563 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2564 * then post an error to application
2570 /* FIXIT : check indent */
2573 __mmplayer_gst_wfd_dynamic_pad (GstElement *element, GstPad *pad, gpointer data) // @
2575 GstPad *sinkpad = NULL;
2576 GstCaps* caps = NULL;
2577 GstElement* new_element = NULL;
2578 enum MainElementID element_id = MMPLAYER_M_NUM;
2580 mm_player_t* player = (mm_player_t*) data;
2584 return_if_fail( element && pad );
2585 return_if_fail( player &&
2587 player->pipeline->mainbin );
2589 debug_log("stream count inc : %d\n", player->num_dynamic_pad);
2592 debug_log("using pad caps to autopluging instead of doing typefind\n");
2593 caps = gst_pad_query_caps( pad );
2594 MMPLAYER_CHECK_NULL( caps );
2595 /* clear previous result*/
2596 player->have_dynamic_pad = FALSE;
2597 new_element = gst_element_factory_make("rtpmp2tdepay", "wfd_rtp_depay");
2600 debug_error ( "failed to create wfd rtp depay element\n" );
2603 MMPLAYER_ELEMENT_SET_STATE( new_element, GST_STATE_READY );
2604 /* add new element to the pipeline */
2605 if ( FALSE == gst_bin_add( GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element) )
2607 debug_log("failed to add autoplug element to bin\n");
2610 /* get pad from element */
2611 sinkpad = gst_element_get_static_pad ( GST_ELEMENT(new_element), "sink" );
2614 debug_log("failed to get sinkpad from autoplug element\n");
2618 if ( GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad) )
2620 debug_log("failed to link autoplug element\n");
2623 gst_object_unref (sinkpad);
2625 pad = gst_element_get_static_pad ( GST_ELEMENT(new_element), "src" );
2626 caps = gst_pad_query_caps( pad );
2627 MMPLAYER_CHECK_NULL( caps );
2628 MMPLAYER_ELEMENT_SET_STATE( new_element, GST_STATE_PLAYING );
2629 /* create typefind */
2630 new_element = gst_element_factory_make( "typefind", NULL );
2631 if ( ! new_element )
2633 debug_log("failed to create typefind\n");
2637 MMPLAYER_SIGNAL_CONNECT( player,
2638 G_OBJECT(new_element),
2639 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG,
2641 G_CALLBACK(__mmplayer_typefind_have_type),
2644 player->have_dynamic_pad = FALSE;
2647 /* excute new_element if created*/
2650 debug_log("adding new element to pipeline\n");
2652 /* set state to READY before add to bin */
2653 MMPLAYER_ELEMENT_SET_STATE( new_element, GST_STATE_READY );
2655 /* add new element to the pipeline */
2656 if ( FALSE == gst_bin_add( GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element) )
2658 debug_log("failed to add autoplug element to bin\n");
2662 /* get pad from element */
2663 sinkpad = gst_element_get_static_pad ( GST_ELEMENT(new_element), "sink" );
2666 debug_log("failed to get sinkpad from autoplug element\n");
2671 if ( GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad) )
2673 debug_log("failed to link autoplug element\n");
2677 gst_object_unref (sinkpad);
2680 /* run. setting PLAYING here since streamming source is live source */
2681 MMPLAYER_ELEMENT_SET_STATE( new_element, GST_STATE_PLAYING );
2684 /* store handle to futher manipulation */
2685 player->pipeline->mainbin[element_id].id = element_id;
2686 player->pipeline->mainbin[element_id].gst = new_element;
2692 STATE_CHANGE_FAILED:
2694 /* FIXIT : take care if new_element has already added to pipeline */
2696 gst_object_unref(GST_OBJECT(new_element));
2699 gst_object_unref(GST_OBJECT(sinkpad));
2702 gst_object_unref(GST_OBJECT(caps));
2704 /* FIXIT : how to inform this error to MSL ????? */
2705 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2706 * then post an error to application
2711 static GstPadProbeReturn
2712 __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data)
2714 debug_log ("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
2715 return GST_PAD_PROBE_OK;
2718 static GstPadProbeReturn
2719 __mmplayer_audio_data_probe (GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
2721 mm_player_t* player = (mm_player_t*) u_data;
2722 GstBuffer *pad_buffer = gst_pad_probe_info_get_buffer(info);
2724 /* TO_CHECK: performance */
2725 return_val_if_fail (player && GST_IS_BUFFER(pad_buffer), GST_PAD_PROBE_OK);
2727 if (GST_BUFFER_PTS_IS_VALID(pad_buffer) && GST_BUFFER_DURATION_IS_VALID(pad_buffer))
2728 player->gapless.next_pts = GST_BUFFER_PTS(pad_buffer) + GST_BUFFER_DURATION(pad_buffer);
2730 return GST_PAD_PROBE_OK;
2733 static GstPadProbeReturn
2734 __mmplayer_gst_selector_event_probe (GstPad * pad, GstPadProbeInfo * info, gpointer data)
2736 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
2737 GstEvent *event = GST_PAD_PROBE_INFO_DATA (info);
2738 mm_player_t* player = (mm_player_t*)data;
2740 switch (GST_EVENT_TYPE (event)) {
2741 case GST_EVENT_STREAM_START:
2743 case GST_EVENT_SEGMENT: {
2747 if (!player->gapless.running)
2750 if (player->gapless.stream_changed) {
2751 player->gapless.start_time += player->gapless.next_pts;
2752 player->gapless.stream_changed = FALSE;
2755 debug_log ("event: %" GST_PTR_FORMAT, event);
2756 gst_event_copy_segment (event, &segment);
2758 if (segment.format == GST_FORMAT_TIME)
2760 segment.base = player->gapless.start_time;
2761 debug_log ("base of segment: %" GST_TIME_FORMAT, GST_TIME_ARGS (segment.base));
2763 tmpev = gst_event_new_segment (&segment);
2764 gst_event_set_seqnum (tmpev, gst_event_get_seqnum (event));
2765 gst_event_unref (event);
2766 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2777 __mmplayer_gst_decode_pad_added (GstElement *elem, GstPad *pad, gpointer data)
2779 mm_player_t* player = NULL;
2780 GstElement* pipeline = NULL;
2781 GstElement* selector = NULL;
2782 GstElement* fakesink = NULL;
2783 GstCaps* caps = NULL;
2784 GstStructure* str = NULL;
2785 const gchar* name = NULL;
2786 GstPad* sinkpad = NULL;
2787 GstPad* srcpad = NULL;
2788 gboolean first_track = FALSE;
2790 enum MainElementID elemId = MMPLAYER_M_NUM;
2791 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2794 player = (mm_player_t*)data;
2796 return_if_fail (elem && pad);
2797 return_if_fail (player && player->pipeline && player->pipeline->mainbin);
2799 //debug_log ("pad-added signal handling\n");
2801 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
2803 /* get mimetype from caps */
2804 caps = gst_pad_query_caps (pad, NULL);
2807 debug_error ("cannot get caps from pad.\n");
2811 str = gst_caps_get_structure (caps, 0);
2814 debug_error ("cannot get structure from caps.\n");
2818 name = gst_structure_get_name (str);
2821 debug_error ("cannot get mimetype from structure.\n");
2825 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2826 //debug_log ("detected mimetype : %s\n", name);
2828 if (strstr(name, "video"))
2831 mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &stype);
2833 /* don't make video because of not required, and not support multiple track */
2834 if (stype == MM_DISPLAY_SURFACE_NULL)
2836 debug_log ("no video sink by null surface or multiple track");
2837 gchar *caps_str = gst_caps_to_string(caps);
2838 if (strstr(caps_str, "ST12") || strstr(caps_str, "SN12"))
2840 player->set_mode.video_zc = TRUE;
2842 MMPLAYER_FREEIF( caps_str );
2844 if (player->v_stream_caps)
2846 gst_caps_unref(player->v_stream_caps);
2847 player->v_stream_caps = NULL;
2850 debug_log ("create fakesink instead of videobin");
2853 fakesink = gst_element_factory_make ("fakesink", NULL);
2854 if (fakesink == NULL)
2856 debug_error ("ERROR : fakesink create error\n");
2860 player->video_fakesink = fakesink;
2862 gst_bin_add (GST_BIN(pipeline), fakesink);
2865 sinkpad = gst_element_get_static_pad (fakesink, "sink");
2867 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad))
2869 debug_warning ("failed to link fakesink\n");
2870 gst_object_unref (GST_OBJECT(fakesink));
2874 if (player->set_mode.media_packet_video_stream)
2875 player->video_cb_probe_id = gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_BUFFER, __mmplayer_video_stream_probe, player, NULL);
2877 g_object_set (G_OBJECT (fakesink), "async", TRUE, NULL);
2878 g_object_set (G_OBJECT (fakesink), "sync", TRUE, NULL);
2879 gst_element_set_state (fakesink, GST_STATE_PAUSED);
2883 __mmplayer_gst_decode_callback (elem, pad, player);
2887 if (strstr(name, "audio"))
2889 gint samplerate = 0;
2892 if (MMPLAYER_IS_ES_BUFF_SRC(player))
2894 __mmplayer_gst_decode_callback (elem, pad, player);
2898 debug_log ("audio selector \n");
2899 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
2900 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2902 gst_structure_get_int (str, "rate", &samplerate);
2903 gst_structure_get_int (str, "channels", &channels);
2905 if ((channels > 0 && samplerate == 0)) {//exclude audio decoding
2907 fakesink = gst_element_factory_make ("fakesink", NULL);
2908 if (fakesink == NULL)
2910 debug_error ("ERROR : fakesink create error\n");
2914 gst_bin_add (GST_BIN(pipeline), fakesink);
2917 sinkpad = gst_element_get_static_pad (fakesink, "sink");
2919 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad))
2921 debug_warning ("failed to link fakesink\n");
2922 gst_object_unref (GST_OBJECT(fakesink));
2926 g_object_set (G_OBJECT (fakesink), "async", TRUE, NULL);
2927 g_object_set (G_OBJECT (fakesink), "sync", TRUE, NULL);
2928 gst_element_set_state (fakesink, GST_STATE_PAUSED);
2933 else if (strstr(name, "text"))
2935 debug_log ("text selector \n");
2936 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
2937 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
2941 debug_error ("wrong elem id \n");
2946 if(strstr(name, "video"))
2949 selector = player->pipeline->mainbin[elemId].gst;
2951 if (selector == NULL)
2953 selector = gst_element_factory_make ("input-selector", NULL);
2954 debug_log ("Creating input-selector\n");
2955 if (selector == NULL)
2957 debug_error ("ERROR : input-selector create error\n");
2960 g_object_set (selector, "sync-streams", TRUE, NULL);
2962 player->pipeline->mainbin[elemId].id = elemId;
2963 player->pipeline->mainbin[elemId].gst = selector;
2966 // player->selector[stream_type].active_pad_index = DEFAULT_TRACK; // default
2968 srcpad = gst_element_get_static_pad (selector, "src");
2970 debug_log ("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2971 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
2972 __mmplayer_gst_selector_blocked, NULL, NULL);
2973 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
2974 __mmplayer_gst_selector_event_probe, player, NULL);
2976 gst_element_set_state (selector, GST_STATE_PAUSED);
2977 gst_bin_add (GST_BIN(pipeline), selector);
2981 debug_log ("input-selector is already created.\n");
2982 selector = player->pipeline->mainbin[elemId].gst;
2986 debug_log ("Calling request pad with selector %p \n", selector);
2987 sinkpad = gst_element_get_request_pad (selector, "sink_%u");
2989 debug_log ("got pad %s:%s from selector", GST_DEBUG_PAD_NAME (sinkpad));
2991 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad))
2993 debug_warning ("failed to link selector\n");
2994 gst_object_unref (GST_OBJECT(selector));
3000 debug_log ("this is first track --> active track \n");
3001 g_object_set (selector, "active-pad", sinkpad, NULL);
3004 _mmplayer_track_update_info(player, stream_type, sinkpad);
3012 gst_caps_unref (caps);
3017 gst_object_unref (GST_OBJECT(sinkpad));
3023 gst_object_unref (GST_OBJECT(srcpad));
3030 static void __mmplayer_handle_text_decode_path(mm_player_t* player, GstElement* text_selector)
3032 GstPad* srcpad = NULL;
3033 MMHandleType attrs = 0;
3034 gint active_index = 0;
3036 // [link] input-selector :: textbin
3037 srcpad = gst_element_get_static_pad (text_selector, "src");
3040 debug_error("failed to get srcpad from selector\n");
3044 debug_log ("got pad %s:%s from text selector\n", GST_DEBUG_PAD_NAME(srcpad));
3046 active_index = player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index;
3047 if ((active_index != DEFAULT_TRACK) &&
3048 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_TEXT, active_index) != MM_ERROR_NONE))
3050 debug_warning("failed to change text track\n");
3051 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index = DEFAULT_TRACK;
3054 player->no_more_pad = TRUE;
3055 __mmplayer_gst_decode_callback (text_selector, srcpad, player);
3057 debug_log ("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3058 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id)
3060 gst_pad_remove_probe (srcpad, player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id);
3061 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id = 0;
3064 debug_log("Total text tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
3066 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
3067 player->has_closed_caption = TRUE;
3069 attrs = MMPLAYER_GET_ATTRS(player);
3072 mm_attrs_set_int_by_name(attrs, "content_text_track_num",(gint)player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
3073 if (mmf_attrs_commit (attrs))
3074 debug_error("failed to commit.\n");
3078 debug_error("cannot get content attribute");
3083 gst_object_unref ( GST_OBJECT(srcpad) );
3088 int _mmplayer_gst_set_audio_channel(MMHandleType hplayer, MMPlayerAudioChannel ch_idx)
3090 int result = MM_ERROR_NONE;
3092 mm_player_t* player = (mm_player_t*)hplayer;
3093 MMPlayerGstElement* mainbin = NULL;
3094 gchar* change_pad_name = NULL;
3095 GstPad* sinkpad = NULL;
3096 GstCaps* caps = NULL;
3100 return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3102 debug_log ("Change Audio mode to %d\n", ch_idx);
3103 player->use_deinterleave = TRUE;
3105 if ((!player->pipeline) || (!player->pipeline->mainbin))
3107 debug_log ("pre setting : %d\n", ch_idx);
3109 player->audio_mode.active_pad_index = ch_idx;
3113 mainbin = player->pipeline->mainbin;
3115 if (mainbin[MMPLAYER_M_A_SELECTOR].gst == NULL)
3117 if (player->max_audio_channels < 2)
3119 debug_log ("mono channel track only\n");
3123 debug_warning ("selector doesn't exist\n");
3124 return result; /* keep playing */
3127 debug_log ("total_ch_num : %d\n", player->audio_mode.total_track_num);
3129 if (player->audio_mode.total_track_num < 2)
3131 debug_warning ("there is no another audio path\n");
3132 return result; /* keep playing */
3135 if ((ch_idx < 0) || (ch_idx >= player->audio_mode.total_track_num))
3137 debug_warning ("Not a proper ch_idx : %d \n", ch_idx);
3138 return result; /* keep playing */
3141 /*To get the new pad from the selector*/
3142 change_pad_name = g_strdup_printf ("sink%d", ch_idx);
3143 if (change_pad_name == NULL)
3145 debug_warning ("Pad does not exists\n");
3146 goto ERROR; /* keep playing */
3149 debug_log ("new active pad name: %s\n", change_pad_name);
3151 sinkpad = gst_element_get_static_pad (mainbin[MMPLAYER_M_A_SELECTOR].gst, change_pad_name);
3152 if (sinkpad == NULL)
3154 //result = MM_ERROR_PLAYER_INTERNAL;
3155 goto ERROR; /* keep playing */
3158 debug_log ("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
3159 g_object_set (mainbin[MMPLAYER_M_A_SELECTOR].gst, "active-pad", sinkpad, NULL);
3161 caps = gst_pad_get_current_caps(sinkpad);
3162 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
3164 __mmplayer_set_audio_attrs (player, caps);
3165 player->audio_mode.active_pad_index = ch_idx;
3170 gst_object_unref (sinkpad);
3172 MMPLAYER_FREEIF(change_pad_name);
3181 __mmplayer_gst_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
3183 mm_player_t* player = (mm_player_t*)data;
3184 GstElement* selector = NULL;
3185 GstElement* queue = NULL;
3187 GstPad* srcpad = NULL;
3188 GstPad* sinkpad = NULL;
3189 gchar* caps_str= NULL;
3192 return_if_fail (player && player->pipeline && player->pipeline->mainbin);
3194 caps_str = gst_caps_to_string(gst_pad_get_current_caps(pad));
3195 debug_log ("deinterleave new caps : %s\n", caps_str);
3196 MMPLAYER_FREEIF(caps_str);
3198 if ((queue = __mmplayer_element_create_and_link(player, pad, "queue")) == NULL)
3200 debug_error ("ERROR : queue create error\n");
3204 g_object_set(G_OBJECT(queue),
3205 "max-size-buffers", 10,
3206 "max-size-bytes", 0,
3207 "max-size-time", (guint64)0,
3210 selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
3214 debug_error("there is no audio channel selector.\n");
3218 srcpad = gst_element_get_static_pad (queue, "src");
3219 sinkpad = gst_element_get_request_pad (selector, "sink_%u");
3221 debug_log ("link (%s:%s - %s:%s)\n", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
3223 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad))
3225 debug_warning ("failed to link deinterleave - selector\n");
3229 gst_element_set_state (queue, GST_STATE_PAUSED);
3230 player->audio_mode.total_track_num++;
3236 gst_object_unref ( GST_OBJECT(srcpad) );
3242 gst_object_unref ( GST_OBJECT(sinkpad) );
3251 __mmplayer_gst_deinterleave_no_more_pads (GstElement *elem, gpointer data)
3253 mm_player_t* player = NULL;
3254 GstElement* selector = NULL;
3255 GstPad* sinkpad = NULL;
3256 gint active_index = 0;
3257 gchar* change_pad_name = NULL;
3258 GstCaps* caps = NULL; // no need to unref
3261 player = (mm_player_t*) data;
3263 selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
3267 debug_error("there is no audio channel selector.\n");
3271 active_index = player->audio_mode.active_pad_index;
3273 if (active_index != DEFAULT_AUDIO_CH)
3275 gint audio_ch = DEFAULT_AUDIO_CH;
3277 /*To get the new pad from the selector*/
3278 change_pad_name = g_strdup_printf ("sink%d", active_index);
3279 if (change_pad_name != NULL)
3281 sinkpad = gst_element_get_static_pad (selector, change_pad_name);
3282 if (sinkpad != NULL)
3284 debug_log ("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
3285 g_object_set (selector, "active-pad", sinkpad, NULL);
3287 audio_ch = active_index;
3289 caps = gst_pad_get_current_caps(sinkpad);
3290 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
3292 __mmplayer_set_audio_attrs (player, caps);
3296 player->audio_mode.active_pad_index = audio_ch;
3297 debug_log("audio LR info (0:stereo) = %d\n", player->audio_mode.active_pad_index);
3303 gst_object_unref (sinkpad);
3310 __mmplayer_gst_build_deinterleave_path (GstElement *elem, GstPad *pad, gpointer data)
3312 mm_player_t* player = NULL;
3313 MMPlayerGstElement *mainbin = NULL;
3315 GstElement* tee = NULL;
3316 GstElement* stereo_queue = NULL;
3317 GstElement* mono_queue = NULL;
3318 GstElement* conv = NULL;
3319 GstElement* filter = NULL;
3320 GstElement* deinterleave = NULL;
3321 GstElement* selector = NULL;
3323 GstPad* srcpad = NULL;
3324 GstPad* selector_srcpad = NULL;
3325 GstPad* sinkpad = NULL;
3326 GstCaps* caps = NULL;
3327 gulong block_id = 0;
3332 player = (mm_player_t*) data;
3334 return_if_fail( elem && pad );
3335 return_if_fail( player && player->pipeline && player->pipeline->mainbin );
3337 mainbin = player->pipeline->mainbin;
3340 if ((tee = __mmplayer_element_create_and_link(player, pad, "tee")) == NULL)
3342 debug_error ("ERROR : tee create error\n");
3346 mainbin[MMPLAYER_M_A_TEE].id = MMPLAYER_M_A_TEE;
3347 mainbin[MMPLAYER_M_A_TEE].gst = tee;
3349 gst_element_set_state (tee, GST_STATE_PAUSED);
3352 srcpad = gst_element_get_request_pad (tee, "src_%u");
3353 if ((stereo_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL)
3355 debug_error ("ERROR : stereo queue create error\n");
3359 g_object_set(G_OBJECT(stereo_queue),
3360 "max-size-buffers", 10,
3361 "max-size-bytes", 0,
3362 "max-size-time", (guint64)0,
3365 player->pipeline->mainbin[MMPLAYER_M_A_Q1].id = MMPLAYER_M_A_Q1;
3366 player->pipeline->mainbin[MMPLAYER_M_A_Q1].gst = stereo_queue;
3370 gst_object_unref (GST_OBJECT(srcpad));
3374 srcpad = gst_element_get_request_pad (tee, "src_%u");
3376 if ((mono_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL)
3378 debug_error ("ERROR : mono queue create error\n");
3382 g_object_set(G_OBJECT(mono_queue),
3383 "max-size-buffers", 10,
3384 "max-size-bytes", 0,
3385 "max-size-time", (guint64)0,
3388 player->pipeline->mainbin[MMPLAYER_M_A_Q2].id = MMPLAYER_M_A_Q2;
3389 player->pipeline->mainbin[MMPLAYER_M_A_Q2].gst = mono_queue;
3391 gst_element_set_state (stereo_queue, GST_STATE_PAUSED);
3392 gst_element_set_state (mono_queue, GST_STATE_PAUSED);
3395 srcpad = gst_element_get_static_pad (mono_queue, "src");
3396 if ((conv = __mmplayer_element_create_and_link(player, srcpad, "audioconvert")) == NULL)
3398 debug_error ("ERROR : audioconvert create error\n");
3402 player->pipeline->mainbin[MMPLAYER_M_A_CONV].id = MMPLAYER_M_A_CONV;
3403 player->pipeline->mainbin[MMPLAYER_M_A_CONV].gst = conv;
3408 gst_object_unref (GST_OBJECT(srcpad));
3411 srcpad = gst_element_get_static_pad (conv, "src");
3413 if ((filter = __mmplayer_element_create_and_link(player, srcpad, "capsfilter")) == NULL)
3415 debug_error ("ERROR : capsfilter create error\n");
3419 player->pipeline->mainbin[MMPLAYER_M_A_FILTER].id = MMPLAYER_M_A_FILTER;
3420 player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst = filter;
3422 caps = gst_caps_from_string( "audio/x-raw-int, "
3423 "width = (int) 16, "
3424 "depth = (int) 16, "
3425 "channels = (int) 2");
3427 g_object_set (GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst), "caps", caps, NULL );
3428 gst_caps_unref( caps );
3430 gst_element_set_state (conv, GST_STATE_PAUSED);
3431 gst_element_set_state (filter, GST_STATE_PAUSED);
3436 gst_object_unref (GST_OBJECT(srcpad));
3439 srcpad = gst_element_get_static_pad (filter, "src");
3441 if ((deinterleave = __mmplayer_element_create_and_link(player, srcpad, "deinterleave")) == NULL)
3443 debug_error ("ERROR : deinterleave create error\n");
3447 g_object_set (deinterleave, "keep-positions", TRUE, NULL);
3449 MMPLAYER_SIGNAL_CONNECT (player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
3450 G_CALLBACK (__mmplayer_gst_deinterleave_pad_added), player);
3452 MMPLAYER_SIGNAL_CONNECT (player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
3453 G_CALLBACK (__mmplayer_gst_deinterleave_no_more_pads), player);
3455 player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].id = MMPLAYER_M_A_DEINTERLEAVE;
3456 player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].gst = deinterleave;
3459 selector = gst_element_factory_make ("input-selector", "audio-channel-selector");
3460 if (selector == NULL)
3462 debug_error ("ERROR : audio-selector create error\n");
3466 g_object_set (selector, "sync-streams", TRUE, NULL);
3467 gst_bin_add (GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), selector);
3469 player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].id = MMPLAYER_M_A_SELECTOR;
3470 player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst = selector;
3472 selector_srcpad = gst_element_get_static_pad (selector, "src");
3474 debug_log ("blocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3476 gst_pad_add_probe(selector_srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
3477 __mmplayer_gst_selector_blocked, NULL, NULL);
3481 gst_object_unref (GST_OBJECT(srcpad));
3485 srcpad = gst_element_get_static_pad(stereo_queue, "src");
3486 sinkpad = gst_element_get_request_pad (selector, "sink_%u");
3488 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad))
3490 debug_warning ("failed to link queue_stereo - selector\n");
3494 player->audio_mode.total_track_num++;
3496 g_object_set (selector, "active-pad", sinkpad, NULL);
3497 gst_element_set_state (deinterleave, GST_STATE_PAUSED);
3498 gst_element_set_state (selector, GST_STATE_PAUSED);
3500 __mmplayer_gst_decode_callback (selector, selector_srcpad, player);
3504 debug_log ("unblocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3507 gst_pad_remove_probe (selector_srcpad, block_id);
3513 gst_object_unref (GST_OBJECT(sinkpad));
3519 gst_object_unref (GST_OBJECT(srcpad));
3523 if (selector_srcpad)
3525 gst_object_unref (GST_OBJECT(selector_srcpad));
3526 selector_srcpad = NULL;
3534 __mmplayer_gst_decode_no_more_pads (GstElement *elem, gpointer data)
3536 mm_player_t* player = NULL;
3537 GstPad* srcpad = NULL;
3538 GstElement* audio_selector = NULL;
3539 GstElement* text_selector = NULL;
3540 MMHandleType attrs = 0;
3541 gint active_index = 0;
3542 gint64 dur_bytes = 0L;
3544 player = (mm_player_t*) data;
3546 debug_log("no-more-pad signal handling\n");
3548 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
3549 (player->cmd == MMPLAYER_COMMAND_UNREALIZE))
3551 debug_warning("no need to go more");
3553 if (player->gapless.reconfigure)
3555 player->gapless.reconfigure = FALSE;
3556 MMPLAYER_PLAYBACK_UNLOCK(player);
3562 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
3563 (MMPLAYER_IS_HTTP_STREAMING(player)) &&
3564 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
3565 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst))
3567 #define ESTIMATED_BUFFER_UNIT (1*1024*1024)
3569 if (NULL == player->streamer)
3571 debug_warning("invalid state for buffering");
3575 gdouble init_buffering_time = (gdouble)player->streamer->buffering_req.initial_second;
3576 guint buffer_bytes = init_buffering_time * ESTIMATED_BUFFER_UNIT;
3578 buffer_bytes = MAX(buffer_bytes, player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffering_bytes);
3579 debug_log("[Decodebin2] set use-buffering on Q2 (pre buffer time: %d sec, buffer size : %d)\n", (gint)init_buffering_time, buffer_bytes);
3581 init_buffering_time = (init_buffering_time != 0)?(init_buffering_time):(player->ini.http_buffering_time);
3583 if ( !gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
3584 debug_error("fail to get duration.\n");
3586 // enable use-buffering on queue2 instead of multiqueue (ex)audio only streaming
3587 // use file information was already set on Q2 when it was created.
3588 __mm_player_streaming_set_queue2(player->streamer,
3589 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
3590 TRUE, // use_buffering
3592 init_buffering_time,
3594 player->ini.http_buffering_limit, // high percent
3597 ((dur_bytes>0)?((guint64)dur_bytes):0));
3599 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
3600 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3603 active_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
3604 if ((active_index != DEFAULT_TRACK) &&
3605 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_AUDIO, active_index) != MM_ERROR_NONE))
3607 debug_warning("failed to change audio track\n");
3608 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index = DEFAULT_TRACK;
3611 // [link] input-selector :: audiobin
3612 srcpad = gst_element_get_static_pad (audio_selector, "src");
3615 debug_error("failed to get srcpad from selector\n");
3619 debug_log ("got pad %s:%s from selector\n", GST_DEBUG_PAD_NAME(srcpad));
3621 player->no_more_pad = TRUE;
3623 if ((player->use_deinterleave == TRUE) && (player->max_audio_channels >= 2))
3625 debug_log ("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3626 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id)
3628 gst_pad_remove_probe (srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3629 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3632 __mmplayer_gst_build_deinterleave_path(audio_selector, srcpad, player);
3636 __mmplayer_gst_decode_callback (audio_selector, srcpad, player);
3638 debug_log ("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3639 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id)
3641 gst_pad_remove_probe (srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3642 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3646 debug_log("Total audio tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3648 attrs = MMPLAYER_GET_ATTRS(player);
3651 mm_attrs_set_int_by_name(attrs, "content_audio_track_num",(gint)player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3652 if (mmf_attrs_commit (attrs))
3653 debug_error("failed to commit.\n");
3657 debug_error("cannot get content attribute");
3662 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst))
3664 debug_log ("There is no audio track : remove audiobin");
3666 __mmplayer_release_signal_connection( player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN );
3667 __mmplayer_del_sink ( player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst );
3669 MMPLAYER_RELEASE_ELEMENT ( player, player->pipeline->audiobin, MMPLAYER_A_BIN );
3670 MMPLAYER_FREEIF ( player->pipeline->audiobin )
3673 if (player->num_dynamic_pad == 0)
3675 __mmplayer_pipeline_complete (NULL, player);
3680 if (!MMPLAYER_IS_ES_BUFF_SRC(player))
3684 __mmplayer_handle_text_decode_path(player, text_selector);
3693 gst_object_unref ( GST_OBJECT(srcpad) );
3697 if (player->gapless.reconfigure)
3699 player->gapless.reconfigure = FALSE;
3700 MMPLAYER_PLAYBACK_UNLOCK(player);
3705 __mmplayer_gst_decode_callback(GstElement *elem, GstPad *pad, gpointer data) // @
3707 mm_player_t* player = NULL;
3708 MMHandleType attrs = 0;
3709 GstElement* pipeline = NULL;
3710 GstCaps* caps = NULL;
3711 gchar* caps_str = NULL;
3712 GstStructure* str = NULL;
3713 const gchar* name = NULL;
3714 GstPad* sinkpad = NULL;
3715 GstElement* sinkbin = NULL;
3716 gboolean reusing = FALSE;
3717 GstElement *text_selector = NULL;
3720 player = (mm_player_t*) data;
3722 return_if_fail( elem && pad );
3723 return_if_fail(player && player->pipeline && player->pipeline->mainbin);
3725 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
3727 attrs = MMPLAYER_GET_ATTRS(player);
3730 debug_error("cannot get content attribute\n");
3734 /* get mimetype from caps */
3735 caps = gst_pad_query_caps( pad, NULL );
3738 debug_error("cannot get caps from pad.\n");
3741 caps_str = gst_caps_to_string(caps);
3743 str = gst_caps_get_structure( caps, 0 );
3746 debug_error("cannot get structure from caps.\n");
3750 name = gst_structure_get_name(str);
3753 debug_error("cannot get mimetype from structure.\n");
3757 //debug_log("detected mimetype : %s\n", name);
3759 if (strstr(name, "audio"))
3761 if (player->pipeline->audiobin == NULL)
3763 if (MM_ERROR_NONE != __mmplayer_gst_create_audio_pipeline(player))
3765 debug_error("failed to create audiobin. continuing without audio\n");
3769 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3770 debug_log("creating audiosink bin success\n");
3775 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3776 debug_log("reusing audiobin\n");
3777 _mmplayer_update_content_attrs( player, ATTR_AUDIO);
3780 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num <= 0) // should not update if content have multi audio tracks
3781 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 1);
3783 player->audiosink_linked = 1;
3785 sinkpad = gst_element_get_static_pad( GST_ELEMENT(sinkbin), "sink" );
3788 debug_error("failed to get pad from sinkbin\n");
3792 else if (strstr(name, "video"))
3794 if (strstr(caps_str, "ST12") || strstr(caps_str, "SN12"))
3796 player->set_mode.video_zc = TRUE;
3799 if (player->pipeline->videobin == NULL)
3801 /* NOTE : not make videobin because application dose not want to play it even though file has video stream. */
3802 /* get video surface type */
3803 int surface_type = 0;
3804 mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &surface_type);
3806 if (surface_type == MM_DISPLAY_SURFACE_NULL)
3808 debug_log("not make videobin because it dose not want\n");
3812 if (MM_ERROR_NONE != __mmplayer_gst_create_video_pipeline(player, caps, surface_type) )
3814 debug_error("failed to create videobin. continuing without video\n");
3818 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3819 debug_log("creating videosink bin success\n");
3824 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3825 debug_log("re-using videobin\n");
3826 _mmplayer_update_content_attrs( player, ATTR_VIDEO);
3829 /* FIXIT : track number shouldn't be hardcoded */
3830 mm_attrs_set_int_by_name(attrs, "content_video_track_num", 1);
3831 player->videosink_linked = 1;
3833 /* NOTE : intermediate code before doing H/W subtitle compositon */
3834 if ( player->use_textoverlay && player->play_subtitle )
3836 debug_log("using textoverlay for external subtitle");
3837 /* check text bin has created well */
3838 if ( player->pipeline && player->pipeline->textbin )
3840 /* get sinkpad from textoverlay */
3841 sinkpad = gst_element_get_static_pad(
3842 GST_ELEMENT(player->pipeline->textbin[MMPLAYER_T_BIN].gst),
3846 debug_error("failed to get sink pad from textoverlay");
3850 /* link new pad with textoverlay first */
3851 if ( GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad) )
3853 debug_error("failed to get pad from sinkbin\n");
3857 gst_object_unref(sinkpad);
3860 /* alright, override pad to textbin.src for futher link */
3861 pad = gst_element_get_static_pad(
3862 GST_ELEMENT(player->pipeline->textbin[MMPLAYER_T_BIN].gst),
3866 debug_error("failed to get sink pad from textoverlay");
3872 debug_error("should not reach here.");
3877 sinkpad = gst_element_get_static_pad( GST_ELEMENT(sinkbin), "sink" );
3880 debug_error("failed to get pad from sinkbin\n");
3884 else if (strstr(name, "text"))
3886 if (player->pipeline->textbin == NULL)
3888 MMPlayerGstElement* mainbin = NULL;
3890 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player))
3892 debug_error("failed to create textbin. continuing without text\n");
3896 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3897 debug_log("creating textsink bin success\n");
3899 /* FIXIT : track number shouldn't be hardcoded */
3900 mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1);
3902 player->textsink_linked = 1;
3903 debug_msg("player->textsink_linked set to 1\n");
3905 sinkpad = gst_element_get_static_pad( GST_ELEMENT(sinkbin), "text_sink" );
3908 debug_error("failed to get pad from sinkbin\n");
3912 mainbin = player->pipeline->mainbin;
3914 if (!mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst)
3916 /* input selector */
3917 text_selector = gst_element_factory_make("input-selector", "subtitle_inselector");
3918 if ( !text_selector )
3920 debug_error ( "failed to create subtitle input selector element\n" );
3923 g_object_set (text_selector, "sync-streams", TRUE, NULL);
3925 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].id = MMPLAYER_M_T_INPUT_SELECTOR;
3926 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst = text_selector;
3929 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state (text_selector, GST_STATE_READY))
3931 debug_error("failed to set state(READY) to sinkbin\n");
3935 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), text_selector))
3937 debug_warning("failed to add subtitle input selector\n");
3941 debug_log ("created element input-selector");
3946 debug_log ("already having subtitle input selector");
3947 text_selector = mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3953 if (!player->textsink_linked)
3955 debug_log("re-using textbin\n");
3958 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3960 player->textsink_linked = 1;
3961 debug_msg("player->textsink_linked set to 1\n");
3965 debug_log("ignoring internal subtutle since external subtitle is available");
3971 debug_warning("unknown type of elementary stream! ignoring it...\n");
3980 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state( sinkbin, GST_STATE_READY ) )
3982 debug_error("failed to set state(READY) to sinkbin\n");
3986 /* Added for multi audio support to avoid adding audio bin again*/
3988 if ( FALSE == gst_bin_add( GST_BIN(pipeline), sinkbin ) )
3990 debug_error("failed to add sinkbin to pipeline\n");
3996 if (GST_PAD_LINK_OK != GST_PAD_LINK (pad, sinkpad))
3998 debug_error("failed to get pad from sinkbin\n");
4005 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state (sinkbin, GST_STATE_PAUSED))
4007 debug_error("failed to set state(PAUSED) to sinkbin\n");
4013 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state (text_selector, GST_STATE_PAUSED))
4015 debug_error("failed to set state(PAUSED) to sinkbin\n");
4021 gst_object_unref (sinkpad);
4025 debug_log ("linking sink bin success\n");
4027 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
4028 * streaming task. if the task blocked, then buffer will not flow to the next element
4029 * ( autoplugging element ). so this is special hack for streaming. please try to remove it
4031 /* dec stream count. we can remove fakesink if it's zero */
4032 if (player->num_dynamic_pad)
4033 player->num_dynamic_pad--;
4035 debug_log ("no more pads: %d stream count dec : %d (num of dynamic pad)\n", player->no_more_pad, player->num_dynamic_pad);
4037 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
4039 __mmplayer_pipeline_complete (NULL, player);
4042 /* FIXIT : please leave a note why this code is needed */
4043 if(MMPLAYER_IS_WFD_STREAMING( player ))
4045 player->no_more_pad = TRUE;
4050 MMPLAYER_FREEIF(caps_str);
4053 gst_caps_unref( caps );
4056 gst_object_unref(GST_OBJECT(sinkpad));
4058 /* flusing out new attributes */
4059 if ( mmf_attrs_commit ( attrs ) )
4061 debug_error("failed to comit attributes\n");
4068 __mmplayer_gst_element_link_bucket(GList* element_bucket) // @
4070 GList* bucket = element_bucket;
4071 MMPlayerGstElement* element = NULL;
4072 MMPlayerGstElement* prv_element = NULL;
4073 gint successful_link_count = 0;
4077 return_val_if_fail(element_bucket, -1);
4079 prv_element = (MMPlayerGstElement*)bucket->data;
4080 bucket = bucket->next;
4082 for ( ; bucket; bucket = bucket->next )
4084 element = (MMPlayerGstElement*)bucket->data;
4086 if ( element && element->gst )
4088 /* If next element is audio appsrc then make a seprate audio pipeline */
4089 if (!strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),"audio_appsrc") ||
4090 !strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),"subtitle_appsrc"))
4092 prv_element = element;
4096 if ( GST_ELEMENT_LINK(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst)) )
4098 debug_log("linking [%s] to [%s] success\n",
4099 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4100 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)) );
4101 successful_link_count ++;
4105 debug_log("linking [%s] to [%s] failed\n",
4106 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4107 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)) );
4112 prv_element = element;
4117 return successful_link_count;
4121 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket) // @
4123 GList* bucket = element_bucket;
4124 MMPlayerGstElement* element = NULL;
4125 int successful_add_count = 0;
4129 return_val_if_fail(element_bucket, 0);
4130 return_val_if_fail(bin, 0);
4132 for ( ; bucket; bucket = bucket->next )
4134 element = (MMPlayerGstElement*)bucket->data;
4136 if ( element && element->gst )
4138 if( !gst_bin_add(bin, GST_ELEMENT(element->gst)) )
4140 debug_log("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed\n",
4141 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
4142 GST_ELEMENT_NAME(GST_ELEMENT(bin) ) );
4145 successful_add_count ++;
4151 return successful_add_count;
4154 static void __mmplayer_gst_caps_notify_cb (GstPad * pad, GParamSpec * unused, gpointer data)
4156 mm_player_t* player = (mm_player_t*) data;
4157 GstCaps *caps = NULL;
4158 GstStructure *str = NULL;
4163 return_if_fail ( pad )
4164 return_if_fail ( unused )
4165 return_if_fail ( data )
4167 caps = gst_pad_get_current_caps( pad );
4173 str = gst_caps_get_structure(caps, 0);
4179 name = gst_structure_get_name(str);
4185 debug_log("name = %s\n", name);
4187 if (strstr(name, "audio"))
4189 _mmplayer_update_content_attrs (player, ATTR_AUDIO);
4191 if (player->audio_stream_changed_cb)
4193 debug_error("call the audio stream changed cb\n");
4194 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
4197 else if (strstr(name, "video"))
4199 _mmplayer_update_content_attrs (player, ATTR_VIDEO);
4201 if (player->video_stream_changed_cb)
4203 debug_error("call the video stream changed cb\n");
4204 player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
4214 gst_caps_unref(caps);
4224 * This function is to create audio pipeline for playing.
4226 * @param player [in] handle of player
4228 * @return This function returns zero on success.
4230 * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_pipeline
4232 #define MMPLAYER_CREATEONLY_ELEMENT(x_bin, x_id, x_factory, x_name) \
4233 x_bin[x_id].id = x_id;\
4234 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4235 if ( ! x_bin[x_id].gst )\
4237 debug_error("failed to create %s \n", x_factory);\
4241 #define MMPLAYER_CREATE_ELEMENT_ADD_BIN(x_bin, x_id, x_factory, x_name, y_bin, x_player) \
4242 x_bin[x_id].id = x_id;\
4243 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4244 if ( ! x_bin[x_id].gst )\
4246 debug_error("failed to create %s \n", x_factory);\
4251 if (x_player->ini.set_dump_element_flag)\
4252 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
4254 if( !gst_bin_add(GST_BIN(y_bin), GST_ELEMENT(x_bin[x_id].gst)))\
4256 debug_log("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed\n",\
4257 GST_ELEMENT_NAME(GST_ELEMENT(x_bin[x_id].gst)),\
4258 GST_ELEMENT_NAME(GST_ELEMENT(y_bin) ) );\
4262 /* macro for code readability. just for sinkbin-creation functions */
4263 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
4266 x_bin[x_id].id = x_id;\
4267 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4268 if ( ! x_bin[x_id].gst )\
4270 debug_error("failed to create %s \n", x_factory);\
4275 if (x_player->ini.set_dump_element_flag)\
4276 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
4278 if ( x_add_bucket )\
4279 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
4283 __mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4285 mm_player_t* player = (mm_player_t*) data;
4290 gint endianness = 0;
4291 guint64 channel_mask = 0;
4293 MMPlayerAudioStreamDataType audio_stream = { 0, };
4294 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4297 return_if_fail(player->audio_stream_render_cb_ex);
4299 debug_log ("__mmplayer_audio_stream_decoded_render_cb new pad: %s", GST_PAD_NAME (pad));
4301 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4302 audio_stream.data = mapinfo.data;
4303 audio_stream.data_size = mapinfo.size;
4305 GstCaps *caps = gst_pad_get_current_caps( pad );
4306 GstStructure *structure = gst_caps_get_structure (caps, 0);
4308 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
4309 gst_structure_get_int (structure, "rate", &rate);
4310 gst_structure_get_int (structure, "channels", &channel);
4311 gst_structure_get_int (structure, "depth", &depth);
4312 gst_structure_get_int (structure, "endianness", &endianness);
4313 gst_structure_get (structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
4315 gst_caps_unref(GST_CAPS(caps));
4317 audio_stream.bitrate = rate;
4318 audio_stream.channel = channel;
4319 audio_stream.depth = depth;
4320 audio_stream.is_little_endian = (endianness == 1234 ? 1 : 0);
4321 audio_stream.channel_mask = channel_mask;
4322 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);
4323 player->audio_stream_render_cb_ex(&audio_stream, player->audio_stream_cb_user_param);
4324 gst_buffer_unmap(buffer, &mapinfo);
4330 __mmplayer_gst_audio_deinterleave_pad_added (GstElement *elem, GstPad *pad, gpointer data)
4332 mm_player_t* player = (mm_player_t*)data;
4333 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4334 GstPad* sinkpad = NULL;
4335 GstElement *queue = NULL, *sink = NULL;
4338 return_if_fail (player && player->pipeline && player->pipeline->mainbin);
4340 queue = gst_element_factory_make ("queue", NULL);
4343 debug_log ("fail make queue\n");
4347 sink = gst_element_factory_make ("fakesink", NULL);
4350 debug_log ("fail make fakesink\n");
4354 gst_bin_add_many (GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
4356 if (!gst_element_link_pads_full (queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING))
4358 debug_warning("failed to link queue & sink\n");
4362 sinkpad = gst_element_get_static_pad (queue, "sink");
4364 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad))
4366 debug_warning ("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad));
4370 debug_error("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync);
4372 gst_object_unref (sinkpad);
4373 g_object_set (sink, "sync", player->audio_stream_sink_sync, NULL);
4374 g_object_set (sink, "signal-handoffs", TRUE, NULL);
4376 gst_element_set_state (sink, GST_STATE_PAUSED);
4377 gst_element_set_state (queue, GST_STATE_PAUSED);
4379 MMPLAYER_SIGNAL_CONNECT( player,
4381 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4383 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
4390 debug_error("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n");
4393 gst_object_unref(GST_OBJECT(queue));
4398 gst_object_unref(GST_OBJECT(sink));
4403 gst_object_unref ( GST_OBJECT(sinkpad) );
4410 void __mmplayer_gst_set_audiosink_property(mm_player_t* player, MMHandleType attrs)
4412 #define MAX_PROPS_LEN 64
4413 gint volume_type = 0;
4414 gint latency_mode = 0;
4415 gchar *stream_type = NULL;
4416 gchar *latency = NULL;
4418 gchar stream_props[MAX_PROPS_LEN] = {0,};
4419 GstStructure *props = NULL;
4422 * It should be set after player creation through attribute.
4423 * But, it can not be changed during playing.
4426 mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
4427 mm_attrs_get_string_by_name (attrs, "sound_stream_type", &stream_type );
4431 debug_error("stream_type is null.\n");
4435 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d", stream_type, stream_id);
4436 props = gst_structure_from_string(stream_props, NULL);
4437 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
4438 debug_log("stream_id[%d], stream_type[%s], result[%s].\n", stream_id, stream_type, stream_props);
4441 mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
4442 mm_attrs_get_int_by_name(attrs, "sound_volume_type", &volume_type);
4444 switch (latency_mode)
4446 case AUDIO_LATENCY_MODE_LOW:
4447 latency = g_strndup("low", 3);
4449 case AUDIO_LATENCY_MODE_MID:
4450 latency = g_strndup("mid", 3);
4452 case AUDIO_LATENCY_MODE_HIGH:
4453 latency = g_strndup("high", 4);
4457 /* hook sound_type if emergency case */
4458 if (player->sound_focus.focus_changed_msg == MM_PLAYER_FOCUS_CHANGED_BY_EMERGENCY)
4460 debug_log ("emergency session, hook sound_type from [%d] to [%d]\n", volume_type, MM_SOUND_VOLUME_TYPE_EMERGENCY);
4461 volume_type = MM_SOUND_VOLUME_TYPE_EMERGENCY;
4463 #if 0 //need to check
4464 if (player->sound_focus.user_route_policy != 0)
4466 route_path = player->sound_focus.user_route_policy;
4469 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
4470 "latency", latency_mode,
4473 debug_log("audiosink property status...volume type:%d, user-route=%d, latency=%d \n",
4474 volume_type, route_path, latency_mode);
4479 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
4483 debug_log("audiosink property - volume type=%d, latency=%s \n",
4484 volume_type, latency);
4492 __mmplayer_gst_create_audio_pipeline(mm_player_t* player)
4494 MMPlayerGstElement* first_element = NULL;
4495 MMPlayerGstElement* audiobin = NULL;
4496 MMHandleType attrs = 0;
4498 GstPad *ghostpad = NULL;
4499 GList* element_bucket = NULL;
4500 gboolean link_audio_sink_now = TRUE;
4505 return_val_if_fail( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
4508 audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
4511 debug_error("failed to allocate memory for audiobin\n");
4512 return MM_ERROR_PLAYER_NO_FREE_SPACE;
4515 attrs = MMPLAYER_GET_ATTRS(player);
4518 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
4519 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
4520 if ( !audiobin[MMPLAYER_A_BIN].gst )
4522 debug_error("failed to create audiobin\n");
4527 player->pipeline->audiobin = audiobin;
4529 player->set_mode.pcm_extraction = __mmplayer_can_extract_pcm(player);
4531 /* Adding audiotp plugin for reverse trickplay feature */
4532 // MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TP, "audiotp", "audio trickplay", TRUE, player);
4535 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
4538 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", TRUE, player);
4540 if (player->set_mode.pcm_extraction) // pcm extraction only and no sound output
4542 if(player->audio_stream_render_cb_ex)
4544 char *caps_str = NULL;
4545 GstCaps* caps = NULL;
4546 gchar *format = NULL;
4549 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4551 mm_attrs_get_string_by_name (player->attrs, "pcm_audioformat", &format );
4553 debug_log("contents : format: %s samplerate : %d pcm_channel: %d", format, player->pcm_samplerate, player->pcm_channel);
4555 caps = gst_caps_new_simple ("audio/x-raw",
4556 "format", G_TYPE_STRING, format,
4557 "rate", G_TYPE_INT, player->pcm_samplerate,
4558 "channels", G_TYPE_INT, player->pcm_channel,
4560 caps_str = gst_caps_to_string(caps);
4561 debug_log("new caps : %s\n", caps_str);
4563 g_object_set (GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL );
4566 gst_caps_unref( caps );
4567 MMPLAYER_FREEIF( caps_str );
4569 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
4571 g_object_set (G_OBJECT (audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
4572 /* raw pad handling signal */
4573 MMPLAYER_SIGNAL_CONNECT( player,
4574 (audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
4575 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
4576 G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), player);
4580 int dst_samplerate = 0;
4581 int dst_channels = 0;
4583 char *caps_str = NULL;
4584 GstCaps* caps = NULL;
4586 /* get conf. values */
4587 mm_attrs_multiple_get(player->attrs,
4589 "pcm_extraction_samplerate", &dst_samplerate,
4590 "pcm_extraction_channels", &dst_channels,
4591 "pcm_extraction_depth", &dst_depth,
4595 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4596 caps = gst_caps_new_simple ("audio/x-raw",
4597 "rate", G_TYPE_INT, dst_samplerate,
4598 "channels", G_TYPE_INT, dst_channels,
4599 "depth", G_TYPE_INT, dst_depth,
4601 caps_str = gst_caps_to_string(caps);
4602 debug_log("new caps : %s\n", caps_str);
4604 g_object_set (GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL );
4607 gst_caps_unref( caps );
4608 MMPLAYER_FREEIF( caps_str );
4611 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "fakesink", TRUE, player);
4614 g_object_set (G_OBJECT (audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL);
4617 else // normal playback
4619 //GstCaps* caps = NULL;
4622 /* for logical volume control */
4623 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
4624 g_object_set(G_OBJECT (audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
4626 if (player->sound.mute)
4628 debug_log("mute enabled\n");
4629 g_object_set(G_OBJECT (audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
4634 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE, player);
4635 caps = gst_caps_from_string( "audio/x-raw-int, "
4636 "endianness = (int) LITTLE_ENDIAN, "
4637 "signed = (boolean) true, "
4638 "width = (int) 16, "
4639 "depth = (int) 16" );
4640 g_object_set (GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL );
4641 gst_caps_unref( caps );
4644 /* chech if multi-chennels */
4645 if (player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)
4647 GstPad *srcpad = NULL;
4648 GstCaps *caps = NULL;
4650 if ((srcpad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "src")))
4652 if ((caps = gst_pad_query_caps(srcpad, NULL)))
4654 //MMPLAYER_LOG_GST_CAPS_TYPE(caps);
4655 GstStructure *str = gst_caps_get_structure(caps, 0);
4657 gst_structure_get_int (str, "channels", &channels);
4658 gst_caps_unref(caps);
4660 gst_object_unref(srcpad);
4664 /* audio effect element. if audio effect is enabled */
4665 if ( (strcmp(player->ini.audioeffect_element, ""))
4667 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom))
4669 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
4671 debug_log("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
4673 if ( (!player->bypass_audio_effect)
4674 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom) )
4676 if ( MM_AUDIO_EFFECT_TYPE_CUSTOM == player->audio_effect_info.effect_type )
4678 if (!_mmplayer_audio_effect_custom_apply(player))
4680 debug_msg("apply audio effect(custom) setting success\n");
4685 if ( (strcmp(player->ini.audioeffect_element_custom, ""))
4686 && (player->set_mode.rich_audio) )
4688 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
4691 if (!MMPLAYER_IS_RTSP_STREAMING(player))
4693 if (player->set_mode.rich_audio && channels <= 2)
4694 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VSP, "audiovsp", "x-speed", TRUE, player);
4697 /* create audio sink */
4698 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", link_audio_sink_now, player);
4701 g_object_set (G_OBJECT (audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
4702 g_object_set (G_OBJECT (audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
4704 if (player->videodec_linked && player->ini.use_system_clock)
4706 debug_log("system clock will be used.\n");
4707 g_object_set (G_OBJECT (audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
4710 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
4711 __mmplayer_gst_set_audiosink_property(player, attrs);
4714 if (audiobin[MMPLAYER_A_SINK].gst)
4716 GstPad *sink_pad = NULL;
4717 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
4718 MMPLAYER_SIGNAL_CONNECT (player, sink_pad, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4719 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
4720 gst_object_unref (GST_OBJECT(sink_pad));
4723 __mmplayer_add_sink( player, audiobin[MMPLAYER_A_SINK].gst );
4725 /* adding created elements to bin */
4726 debug_log("adding created elements to bin\n");
4727 if( !__mmplayer_gst_element_add_bucket_to_bin( GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket ))
4729 debug_error("failed to add elements\n");
4733 /* linking elements in the bucket by added order. */
4734 debug_log("Linking elements in the bucket by added order.\n");
4735 if ( __mmplayer_gst_element_link_bucket(element_bucket) == -1 )
4737 debug_error("failed to link elements\n");
4741 /* get first element's sinkpad for creating ghostpad */
4742 first_element = (MMPlayerGstElement *)element_bucket->data;
4744 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
4747 debug_error("failed to get pad from first element of audiobin\n");
4751 ghostpad = gst_ghost_pad_new("sink", pad);
4754 debug_error("failed to create ghostpad\n");
4758 if ( FALSE == gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad) )
4760 debug_error("failed to add ghostpad to audiobin\n");
4764 player->gapless.audio_data_probe_id = gst_pad_add_probe(ghostpad, GST_PAD_PROBE_TYPE_BUFFER,
4765 __mmplayer_audio_data_probe, player, NULL);
4767 gst_object_unref(pad);
4769 g_list_free(element_bucket);
4771 mm_attrs_set_int_by_name(attrs, "content_audio_found", TRUE);
4775 return MM_ERROR_NONE;
4779 debug_log("ERROR : releasing audiobin\n");
4782 gst_object_unref(GST_OBJECT(pad));
4785 gst_object_unref(GST_OBJECT(ghostpad));
4787 g_list_free( element_bucket );
4789 /* release element which are not added to bin */
4790 for ( i = 1; i < MMPLAYER_A_NUM; i++ ) /* NOTE : skip bin */
4792 if ( audiobin[i].gst )
4794 GstObject* parent = NULL;
4795 parent = gst_element_get_parent( audiobin[i].gst );
4799 gst_object_unref(GST_OBJECT(audiobin[i].gst));
4800 audiobin[i].gst = NULL;
4804 gst_object_unref(GST_OBJECT(parent));
4809 /* release audiobin with it's childs */
4810 if ( audiobin[MMPLAYER_A_BIN].gst )
4812 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
4815 MMPLAYER_FREEIF( audiobin );
4817 player->pipeline->audiobin = NULL;
4819 return MM_ERROR_PLAYER_INTERNAL;
4822 static GstPadProbeReturn
4823 __mmplayer_audio_stream_probe (GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4825 mm_player_t* player = (mm_player_t*) u_data;
4826 GstBuffer *pad_buffer = gst_pad_probe_info_get_buffer(info);
4827 GstMapInfo probe_info = GST_MAP_INFO_INIT;
4829 gst_buffer_map(pad_buffer, &probe_info, GST_MAP_READ);
4831 if (player->audio_stream_cb && probe_info.size && probe_info.data)
4832 player->audio_stream_cb((void *)probe_info.data, probe_info.size, player->audio_stream_cb_user_param);
4834 return GST_PAD_PROBE_OK;
4837 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
4839 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
4842 static GstPadProbeReturn
4843 __mmplayer_video_stream_probe (GstPad *pad, GstPadProbeInfo *info, gpointer user_data)
4845 GstCaps *caps = NULL;
4846 MMPlayerVideoStreamDataType stream;
4847 MMVideoBuffer *video_buffer = NULL;
4848 GstMemory *dataBlock = NULL;
4849 GstMemory *metaBlock = NULL;
4850 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4851 GstStructure *structure = NULL;
4852 const gchar *string_format = NULL;
4853 unsigned int fourcc = 0;
4854 mm_player_t* player = (mm_player_t*)user_data;
4855 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
4857 return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
4858 return_val_if_fail(gst_buffer_n_memory(buffer) , GST_PAD_PROBE_DROP);
4860 caps = gst_pad_get_current_caps(pad);
4862 debug_error( "Caps is NULL." );
4863 return GST_PAD_PROBE_OK;
4866 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
4868 /* clear stream data structure */
4869 memset(&stream, 0x0, sizeof(MMPlayerVideoStreamDataType));
4871 structure = gst_caps_get_structure( caps, 0 );
4872 gst_structure_get_int(structure, "width", &(stream.width));
4873 gst_structure_get_int(structure, "height", &(stream.height));
4874 string_format = gst_structure_get_string(structure, "format");
4876 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
4878 stream.format = util_get_pixtype(fourcc);
4879 gst_caps_unref( caps );
4883 debug_log( "Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
4884 GST_BUFFER_DATA(buffer), stream.width, stream.height, stream.format );
4887 if (stream.width == 0 || stream.height == 0 || stream.format == MM_PIXEL_FORMAT_INVALID) {
4888 debug_error("Wrong condition!!");
4892 /* set size and timestamp */
4893 dataBlock = gst_buffer_peek_memory(buffer, 0);
4894 stream.length_total = gst_memory_get_sizes(dataBlock, NULL, NULL);
4895 stream.timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/1000000); /* nano sec -> mili sec */
4897 /* check zero-copy */
4898 if (player->set_mode.video_zc &&
4899 player->set_mode.media_packet_video_stream &&
4900 gst_buffer_n_memory(buffer) > 1) {
4901 metaBlock = gst_buffer_peek_memory(buffer, 1);
4902 gst_memory_map(metaBlock, &mapinfo, GST_MAP_READ);
4903 video_buffer = (MMVideoBuffer *)mapinfo.data;
4908 if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
4909 /* copy pointer of tbm bo, stride, elevation */
4910 memcpy(stream.bo, video_buffer->handle.bo,
4911 sizeof(void *) * MM_VIDEO_BUFFER_PLANE_MAX);
4913 else if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_PHYSICAL_ADDRESS) {
4914 memcpy(stream.data, video_buffer->data,
4915 sizeof(void *) * MM_VIDEO_BUFFER_PLANE_MAX);
4917 memcpy(stream.stride, video_buffer->stride_width,
4918 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
4919 memcpy(stream.elevation, video_buffer->stride_height,
4920 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
4921 /* set gst buffer */
4922 stream.internal_buffer = buffer;
4924 tbm_bo_handle thandle;
4925 int stride = ((stream.width + 3) & (~3));
4926 int elevation = stream.height;
4927 int size = stride * elevation * 3 / 2;
4929 gst_ret = gst_memory_map(dataBlock, &mapinfo, GST_MAP_READWRITE);
4931 debug_error("fail to gst_memory_map");
4932 return GST_PAD_PROBE_OK;
4935 stream.stride[0] = stride;
4936 stream.elevation[0] = elevation;
4937 if(stream.format == MM_PIXEL_FORMAT_I420) {
4938 stream.stride[1] = stream.stride[2] = stride / 2;
4939 stream.elevation[1] = stream.elevation[2] = elevation / 2;
4942 debug_error("Not support format %d", stream.format);
4943 gst_memory_unmap(dataBlock, &mapinfo);
4944 return GST_PAD_PROBE_OK;
4947 stream.bo[0] = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
4949 debug_error("Fail to tbm_bo_alloc!!");
4950 gst_memory_unmap(dataBlock, &mapinfo);
4951 return GST_PAD_PROBE_OK;
4953 thandle = tbm_bo_map(stream.bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
4954 if(thandle.ptr && mapinfo.data)
4955 memcpy(thandle.ptr, mapinfo.data, size);
4957 debug_error("data pointer is wrong. dest : %p, src : %p",
4958 thandle.ptr, mapinfo.data);
4960 tbm_bo_unmap(stream.bo[0]);
4963 if (player->video_stream_cb) {
4964 player->video_stream_cb(&stream, player->video_stream_cb_user_param);
4968 gst_memory_unmap(metaBlock, &mapinfo);
4970 gst_memory_unmap(dataBlock, &mapinfo);
4971 tbm_bo_unref(stream.bo[0]);
4974 return GST_PAD_PROBE_OK;
4978 __mmplayer_gst_create_video_filters(mm_player_t* player, GList** bucket, gboolean use_video_stream)
4980 gchar* video_csc = "videoconvert"; // default colorspace converter
4981 GList* element_bucket = *bucket;
4983 return_val_if_fail(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4987 if (!player->set_mode.media_packet_video_stream && use_video_stream)
4989 if (player->set_mode.video_zc && strlen(player->ini.videoconverter_element) > 0)
4991 video_csc = player->ini.videoconverter_element;
4994 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
4995 debug_log("using video converter: %s", video_csc);
4997 if ( !player->set_mode.video_zc)
4999 gint width = 0; //width of video
5000 gint height = 0; //height of video
5001 GstCaps* video_caps = NULL;
5002 GstStructure *structure = NULL;
5004 /* rotator, scaler and capsfilter */
5005 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
5006 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_SCALE, "videoscale", "video scaler", TRUE, player);
5007 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CAPS, "capsfilter", "videocapsfilter", TRUE, player);
5009 /* get video stream caps parsed by demuxer */
5011 mm_attrs_get_int_by_name(player->attrs, "display_width", &width);
5014 structure = gst_structure_new("video/x-raw", "width", G_TYPE_INT, width, NULL);
5016 mm_attrs_get_int_by_name(player->attrs, "display_height", &height);
5018 if(structure && height) {
5019 gst_structure_set (structure, "height", G_TYPE_INT, height, NULL);
5021 video_caps = gst_caps_new_full(structure, NULL);
5022 g_object_set (GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_CAPS].gst), "caps", video_caps, NULL );
5023 MMPLAYER_LOG_GST_CAPS_TYPE(video_caps);
5024 gst_caps_unref(video_caps);
5027 debug_error("fail to set capsfilter %p, width %d, height %d", structure, width, height);
5030 gst_structure_free(structure);
5036 MMDisplaySurfaceType surface_type = MM_DISPLAY_SURFACE_NULL;
5037 mm_attrs_get_int_by_name (player->attrs, "display_surface_type", (int *)&surface_type);
5039 if (player->set_mode.video_zc)
5041 if ( (surface_type == MM_DISPLAY_SURFACE_EVAS) && ( !strcmp(player->ini.videosink_element_evas, "evasimagesink")) )
5043 video_csc = player->ini.videoconverter_element;
5051 if (video_csc && (strcmp(video_csc, "")))
5053 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
5054 debug_log("using video converter: %s", video_csc);
5057 /* set video rotator */
5058 if ( !player->set_mode.video_zc )
5059 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
5062 #if !defined(__arm__)
5063 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_SCALE, "videoscale", "videoscaler", TRUE, player);
5067 *bucket = element_bucket;
5069 return MM_ERROR_NONE;
5074 return MM_ERROR_PLAYER_INTERNAL;
5078 * This function is to create video pipeline.
5080 * @param player [in] handle of player
5081 * caps [in] src caps of decoder
5082 * surface_type [in] surface type for video rendering
5084 * @return This function returns zero on success.
5086 * @see __mmplayer_gst_create_audio_pipeline, __mmplayer_gst_create_midi_pipeline
5090 * - x surface (arm/x86) : xvimagesink
5091 * - evas surface (arm) : evaspixmapsink
5092 * fimcconvert ! evasimagesink
5093 * - evas surface (x86) : videoconvertor ! videoflip ! evasimagesink
5096 __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
5100 GList*element_bucket = NULL;
5101 MMPlayerGstElement* first_element = NULL;
5102 MMPlayerGstElement* videobin = NULL;
5103 gchar *videosink_element = NULL;
5107 return_val_if_fail(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5110 videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
5113 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5116 player->pipeline->videobin = videobin;
5118 attrs = MMPLAYER_GET_ATTRS(player);
5121 debug_error("cannot get content attribute");
5122 return MM_ERROR_PLAYER_INTERNAL;
5126 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
5127 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
5128 if ( !videobin[MMPLAYER_V_BIN].gst )
5130 debug_error("failed to create videobin");
5134 if( player->use_video_stream ) // video stream callback, so send raw video data to application
5136 debug_log("using memsink\n");
5138 if ( __mmplayer_gst_create_video_filters(player, &element_bucket, TRUE) != MM_ERROR_NONE)
5141 /* finally, create video sink. output will be BGRA8888. */
5142 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, "avsysmemsink", "videosink", TRUE, player);
5144 MMPLAYER_SIGNAL_CONNECT( player,
5145 videobin[MMPLAYER_V_SINK].gst,
5146 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5148 G_CALLBACK(__mmplayer_videostream_cb),
5151 else // render video data using sink plugin like xvimagesink
5153 if ( __mmplayer_gst_create_video_filters(player, &element_bucket, FALSE) != MM_ERROR_NONE)
5156 /* set video sink */
5157 switch (surface_type)
5159 case MM_DISPLAY_SURFACE_X:
5160 if (strlen(player->ini.videosink_element_x) > 0)
5161 videosink_element = player->ini.videosink_element_x;
5165 case MM_DISPLAY_SURFACE_EVAS:
5166 if (strlen(player->ini.videosink_element_evas) > 0)
5167 videosink_element = player->ini.videosink_element_evas;
5171 case MM_DISPLAY_SURFACE_X_EXT:
5173 void *pixmap_id_cb = NULL;
5174 mm_attrs_get_data_by_name(attrs, "display_overlay", &pixmap_id_cb);
5175 if (pixmap_id_cb) /* this is used for the videoTextue(canvasTexture) overlay */
5177 videosink_element = player->ini.videosink_element_x;
5181 debug_error("something wrong.. callback function for getting pixmap id is null");
5186 case MM_DISPLAY_SURFACE_NULL:
5187 if (strlen(player->ini.videosink_element_fake) > 0)
5188 videosink_element = player->ini.videosink_element_fake;
5192 case MM_DISPLAY_SURFACE_REMOTE:
5193 if (strlen(player->ini.videosink_element_remote) > 0)
5194 videosink_element = player->ini.videosink_element_remote;
5199 debug_error("unidentified surface type");
5203 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_element, videosink_element, TRUE, player);
5204 debug_log("selected videosink name: %s", videosink_element);
5206 /* additional setting for sink plug-in */
5207 switch (surface_type) {
5208 case MM_DISPLAY_SURFACE_X_EXT:
5209 MMPLAYER_SIGNAL_CONNECT( player,
5210 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
5211 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5212 "frame-render-error",
5213 G_CALLBACK(__mmplayer_videoframe_render_error_cb),
5215 debug_log("videoTexture usage, connect a signal handler for pixmap rendering error");
5217 case MM_DISPLAY_SURFACE_REMOTE:
5219 char *stream_path = NULL;
5220 /* viceo_zc is the result of check ST12/SN12 */
5221 bool use_tbm = player->set_mode.video_zc;
5222 int attr_ret = mm_attrs_get_string_by_name (
5223 attrs, "shm_stream_path", &stream_path );
5224 if(attr_ret == MM_ERROR_NONE && stream_path) {
5225 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5226 "socket-path", stream_path,
5227 "wait-for-connection", FALSE,
5232 debug_log("set path \"%s\" for shmsink", stream_path);
5234 debug_error("Not set attribute of shm_stream_path");
5244 if (_mmplayer_update_video_param(player) != MM_ERROR_NONE)
5247 if (videobin[MMPLAYER_V_SINK].gst)
5249 GstPad *sink_pad = NULL;
5250 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
5253 MMPLAYER_SIGNAL_CONNECT (player, sink_pad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5254 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
5255 gst_object_unref (GST_OBJECT(sink_pad));
5259 debug_warning("failed to get sink pad from videosink\n");
5263 /* store it as it's sink element */
5264 __mmplayer_add_sink( player, videobin[MMPLAYER_V_SINK].gst );
5266 /* adding created elements to bin */
5267 if( ! __mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket) )
5269 debug_error("failed to add elements\n");
5273 /* Linking elements in the bucket by added order */
5274 if ( __mmplayer_gst_element_link_bucket(element_bucket) == -1 )
5276 debug_error("failed to link elements\n");
5280 /* get first element's sinkpad for creating ghostpad */
5281 first_element = (MMPlayerGstElement *)element_bucket->data;
5282 if ( !first_element )
5284 debug_error("failed to get first element from bucket\n");
5288 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
5291 debug_error("failed to get pad from first element\n");
5295 /* create ghostpad */
5296 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
5297 if ( FALSE == gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin) )
5299 debug_error("failed to add ghostpad to videobin\n");
5302 gst_object_unref(pad);
5304 /* done. free allocated variables */
5305 g_list_free(element_bucket);
5307 mm_attrs_set_int_by_name(attrs, "content_video_found", TRUE);
5309 if(surface_type == MM_DISPLAY_SURFACE_REMOTE &&
5310 MMPLAYER_IS_HTTP_PD(player) )
5312 MMMessageParamType msg = {0, };
5313 msg.data = gst_caps_to_string(caps);
5314 MMPLAYER_POST_MSG ( player, MM_MESSAGE_VIDEO_BIN_CREATED, &msg );
5319 return MM_ERROR_NONE;
5322 debug_error("ERROR : releasing videobin\n");
5324 g_list_free( element_bucket );
5327 gst_object_unref(GST_OBJECT(pad));
5329 /* release videobin with it's childs */
5330 if ( videobin[MMPLAYER_V_BIN].gst )
5332 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
5336 MMPLAYER_FREEIF( videobin );
5338 player->pipeline->videobin = NULL;
5340 return MM_ERROR_PLAYER_INTERNAL;
5343 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
5345 GList *element_bucket = NULL;
5346 MMPlayerGstElement *textbin = player->pipeline->textbin;
5348 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
5349 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
5350 g_object_set (G_OBJECT (textbin[MMPLAYER_T_IDENTITY].gst),
5351 "signal-handoffs", FALSE,
5354 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
5355 MMPLAYER_SIGNAL_CONNECT( player,
5356 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
5357 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
5359 G_CALLBACK(__mmplayer_update_subtitle),
5362 g_object_set (G_OBJECT (textbin[MMPLAYER_T_FAKE_SINK].gst), "async", TRUE, NULL);
5363 g_object_set (G_OBJECT (textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE, NULL);
5364 g_object_set (G_OBJECT (textbin[MMPLAYER_T_FAKE_SINK].gst), "signal-handoffs", TRUE, NULL);
5366 if (!player->play_subtitle)
5368 debug_log ("add textbin sink as sink element of whole pipeline.\n");
5369 __mmplayer_add_sink (player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
5372 /* adding created elements to bin */
5373 debug_log("adding created elements to bin\n");
5374 if( !__mmplayer_gst_element_add_bucket_to_bin( GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket ))
5376 debug_error("failed to add elements\n");
5380 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
5381 GST_OBJECT_FLAG_UNSET (textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
5382 GST_OBJECT_FLAG_UNSET (textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
5384 /* linking elements in the bucket by added order. */
5385 debug_log("Linking elements in the bucket by added order.\n");
5386 if ( __mmplayer_gst_element_link_bucket(element_bucket) == -1 )
5388 debug_error("failed to link elements\n");
5392 /* done. free allocated variables */
5393 g_list_free(element_bucket);
5395 if (textbin[MMPLAYER_T_QUEUE].gst)
5398 GstPad *ghostpad = NULL;
5400 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
5403 debug_error("failed to get video pad of textbin\n");
5404 return MM_ERROR_PLAYER_INTERNAL;
5407 ghostpad = gst_ghost_pad_new("text_sink", pad);
5408 gst_object_unref(pad);
5412 debug_error("failed to create ghostpad of textbin\n");
5416 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad))
5418 debug_error("failed to add ghostpad to textbin\n");
5423 return MM_ERROR_NONE;
5426 g_list_free(element_bucket);
5428 return MM_ERROR_PLAYER_INTERNAL;
5431 static int __mmplayer_gst_create_text_pipeline(mm_player_t* player)
5433 MMPlayerGstElement *textbin = NULL;
5434 GList *element_bucket = NULL;
5439 return_val_if_fail( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
5442 textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
5445 debug_error("failed to allocate memory for textbin\n");
5446 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5450 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
5451 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
5452 if ( !textbin[MMPLAYER_T_BIN].gst )
5454 debug_error("failed to create textbin\n");
5459 player->pipeline->textbin = textbin;
5462 if (player->use_textoverlay)
5464 debug_log ("use textoverlay for displaying \n");
5466 MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_QUEUE, "queue", "text_t_queue", textbin[MMPLAYER_T_BIN].gst, player);
5468 MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_VIDEO_QUEUE, "queue", "text_v_queue", textbin[MMPLAYER_T_BIN].gst, player);
5470 MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_VIDEO_CONVERTER, "fimcconvert", "text_v_converter", textbin[MMPLAYER_T_BIN].gst, player);
5472 MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_OVERLAY, "textoverlay", "text_overlay", textbin[MMPLAYER_T_BIN].gst, player);
5474 if (!gst_element_link_pads (textbin[MMPLAYER_T_VIDEO_QUEUE].gst, "src", textbin[MMPLAYER_T_VIDEO_CONVERTER].gst, "sink"))
5476 debug_error("failed to link queue and converter\n");
5480 if (!gst_element_link_pads (textbin[MMPLAYER_T_VIDEO_CONVERTER].gst, "src", textbin[MMPLAYER_T_OVERLAY].gst, "video_sink"))
5482 debug_error("failed to link queue and textoverlay\n");
5486 if (!gst_element_link_pads (textbin[MMPLAYER_T_QUEUE].gst, "src", textbin[MMPLAYER_T_OVERLAY].gst, "text_sink"))
5488 debug_error("failed to link queue and textoverlay\n");
5494 int surface_type = 0;
5496 debug_log ("use subtitle message for displaying \n");
5498 mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &surface_type);
5500 switch(surface_type)
5502 case MM_DISPLAY_SURFACE_X:
5503 case MM_DISPLAY_SURFACE_EVAS:
5504 case MM_DISPLAY_SURFACE_GL:
5505 case MM_DISPLAY_SURFACE_NULL:
5506 case MM_DISPLAY_SURFACE_X_EXT:
5507 case MM_DISPLAY_SURFACE_REMOTE:
5508 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE)
5510 debug_error("failed to make plain text elements\n");
5522 return MM_ERROR_NONE;
5526 debug_log("ERROR : releasing textbin\n");
5528 g_list_free( element_bucket );
5530 /* release element which are not added to bin */
5531 for ( i = 1; i < MMPLAYER_T_NUM; i++ ) /* NOTE : skip bin */
5533 if ( textbin[i].gst )
5535 GstObject* parent = NULL;
5536 parent = gst_element_get_parent( textbin[i].gst );
5540 gst_object_unref(GST_OBJECT(textbin[i].gst));
5541 textbin[i].gst = NULL;
5545 gst_object_unref(GST_OBJECT(parent));
5550 /* release textbin with it's childs */
5551 if ( textbin[MMPLAYER_T_BIN].gst )
5553 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5556 MMPLAYER_FREEIF( textbin );
5558 player->pipeline->textbin = NULL;
5560 return MM_ERROR_PLAYER_INTERNAL;
5565 __mmplayer_gst_create_subtitle_src(mm_player_t* player)
5567 MMPlayerGstElement* mainbin = NULL;
5568 MMHandleType attrs = 0;
5569 GstElement *subsrc = NULL;
5570 GstElement *subparse = NULL;
5571 gchar *subtitle_uri =NULL;
5572 const gchar *charset = NULL;
5578 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5580 mainbin = player->pipeline->mainbin;
5582 attrs = MMPLAYER_GET_ATTRS(player);
5585 debug_error("cannot get content attribute\n");
5586 return MM_ERROR_PLAYER_INTERNAL;
5589 mm_attrs_get_string_by_name ( attrs, "subtitle_uri", &subtitle_uri );
5590 if ( !subtitle_uri || strlen(subtitle_uri) < 1)
5592 debug_error("subtitle uri is not proper filepath.\n");
5593 return MM_ERROR_PLAYER_INVALID_URI;
5595 debug_log("subtitle file path is [%s].\n", subtitle_uri);
5598 /* create the subtitle source */
5599 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
5602 debug_error ( "failed to create filesrc element\n" );
5605 g_object_set(G_OBJECT (subsrc), "location", subtitle_uri, NULL);
5607 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
5608 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
5610 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc))
5612 debug_warning("failed to add queue\n");
5617 subparse = gst_element_factory_make("subparse", "subtitle_parser");
5620 debug_error ( "failed to create subparse element\n" );
5624 charset = util_get_charset(subtitle_uri);
5627 debug_log ("detected charset is %s\n", charset );
5628 g_object_set (G_OBJECT (subparse), "subtitle-encoding", charset, NULL);
5631 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
5632 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
5634 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse))
5636 debug_warning("failed to add subparse\n");
5640 if (!gst_element_link_pads (subsrc, "src", subparse, "sink"))
5642 debug_warning("failed to link subsrc and subparse\n");
5646 player->play_subtitle = TRUE;
5647 player->adjust_subtitle_pos = 0;
5649 debug_log ("play subtitle using subtitle file\n");
5651 if (player->pipeline->textbin == NULL)
5653 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player))
5655 debug_error("failed to create textbin. continuing without text\n");
5659 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(player->pipeline->textbin[MMPLAYER_T_BIN].gst)))
5661 debug_warning("failed to add textbin\n");
5665 debug_log ("link text input selector and textbin ghost pad");
5667 player->textsink_linked = 1;
5668 player->external_text_idx = 0;
5669 debug_msg("player->textsink_linked set to 1\n");
5673 debug_log("text bin has been created. reuse it.");
5674 player->external_text_idx = 1;
5677 if (!gst_element_link_pads (subparse, "src", player->pipeline->textbin[MMPLAYER_T_BIN].gst, "text_sink"))
5679 debug_warning("failed to link subparse and textbin\n");
5683 pad = gst_element_get_static_pad (player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
5687 debug_error("failed to get sink pad from textsink to probe data");
5688 return MM_ERROR_PLAYER_INTERNAL;
5691 gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER,
5692 __mmplayer_subtitle_adjust_position_probe, player, NULL);
5694 gst_object_unref(pad);
5697 /* create dot. for debugging */
5698 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-with-subtitle" );
5701 return MM_ERROR_NONE;
5704 player->textsink_linked = 0;
5705 return MM_ERROR_PLAYER_INTERNAL;
5709 __mmplayer_update_subtitle( GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5711 mm_player_t* player = (mm_player_t*) data;
5712 MMMessageParamType msg = {0, };
5713 GstClockTime duration = 0;
5714 gpointer text = NULL;
5715 guint text_size = 0;
5716 gboolean ret = TRUE;
5717 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5721 return_val_if_fail ( player, FALSE );
5722 return_val_if_fail ( buffer, FALSE );
5724 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
5725 text = g_memdup(mapinfo.data, mapinfo.size);
5726 text_size = mapinfo.size;
5727 duration = GST_BUFFER_DURATION(buffer);
5730 if ( player->set_mode.subtitle_off )
5732 debug_log("subtitle is OFF.\n" );
5736 if ( !text || (text_size == 0))
5738 debug_log("There is no subtitle to be displayed.\n" );
5742 msg.data = (void *) text;
5743 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
5745 debug_log("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data );
5747 MMPLAYER_POST_MSG( player, MM_MESSAGE_UPDATE_SUBTITLE, &msg );
5748 gst_buffer_unmap(buffer, &mapinfo);
5755 static GstPadProbeReturn
5756 __mmplayer_subtitle_adjust_position_probe (GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
5759 mm_player_t *player = (mm_player_t *) u_data;
5760 GstClockTime cur_timestamp = 0;
5761 gint64 adjusted_timestamp = 0;
5762 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
5764 return_val_if_fail ( player, FALSE );
5766 if ( player->set_mode.subtitle_off )
5768 debug_log("subtitle is OFF.\n" );
5772 if (player->adjust_subtitle_pos == 0 )
5774 debug_log("nothing to do");
5778 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
5779 adjusted_timestamp = (gint64) cur_timestamp + ((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
5781 if ( adjusted_timestamp < 0)
5783 debug_log("adjusted_timestamp under zero");
5788 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
5789 debug_log("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
5790 GST_TIME_ARGS(cur_timestamp),
5791 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
5793 return GST_PAD_PROBE_OK;
5795 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
5799 /* check player and subtitlebin are created */
5800 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
5801 return_val_if_fail ( player->play_subtitle, MM_ERROR_NOT_SUPPORT_API );
5805 debug_log ("nothing to do\n");
5807 return MM_ERROR_NONE;
5812 case MM_PLAYER_POS_FORMAT_TIME:
5814 /* check current postion */
5815 player->adjust_subtitle_pos = position;
5817 debug_log("save adjust_subtitle_pos in player") ;
5823 debug_warning("invalid format.\n");
5825 return MM_ERROR_INVALID_ARGUMENT;
5831 return MM_ERROR_NONE;
5833 static int __gst_adjust_video_position(mm_player_t* player, int offset)
5836 debug_log("adjusting video_pos in player") ;
5837 int current_pos = 0;
5838 /* check player and videobin are created */
5839 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
5840 if ( !player->pipeline->videobin ||
5841 !player->pipeline->videobin[MMPLAYER_V_SINK].gst )
5843 debug_log("no video pipeline or sink is there");
5844 return MM_ERROR_PLAYER_INVALID_STATE ;
5848 debug_log ("nothing to do\n");
5850 return MM_ERROR_NONE;
5852 if(__gst_get_position ( player, MM_PLAYER_POS_FORMAT_TIME, (unsigned long*)¤t_pos ) != MM_ERROR_NONE )
5854 debug_log("failed to get current position");
5855 return MM_ERROR_PLAYER_INTERNAL;
5857 if ( (current_pos - offset ) < GST_TIME_AS_MSECONDS(player->duration) )
5859 debug_log("enter video delay is valid");
5862 debug_log("enter video delay is crossing content boundary");
5863 return MM_ERROR_INVALID_ARGUMENT ;
5865 g_object_set (G_OBJECT (player->pipeline->videobin[MMPLAYER_V_SINK].gst),"ts-offset",((gint64) offset * G_GINT64_CONSTANT(1000000)),NULL);
5866 debug_log("video delay has been done");
5869 return MM_ERROR_NONE;
5873 __gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data) // @
5875 GstElement *appsrc = element;
5876 tBuffer *buf = (tBuffer *)user_data;
5877 GstBuffer *buffer = NULL;
5878 GstFlowReturn ret = GST_FLOW_OK;
5881 return_if_fail ( element );
5882 return_if_fail ( buf );
5884 buffer = gst_buffer_new ();
5886 if (buf->offset >= buf->len)
5888 debug_log("call eos appsrc\n");
5889 g_signal_emit_by_name (appsrc, "end-of-stream", &ret);
5893 if ( buf->len - buf->offset < size)
5895 len = buf->len - buf->offset + buf->offset;
5898 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));
5899 GST_BUFFER_OFFSET(buffer) = buf->offset;
5900 GST_BUFFER_OFFSET_END(buffer) = buf->offset + len;
5902 //debug_log("feed buffer %p, offset %u-%u length %u\n", buffer, buf->offset, buf->len,len);
5903 g_signal_emit_by_name (appsrc, "push-buffer", buffer, &ret);
5909 __gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data) // @
5911 tBuffer *buf = (tBuffer *)user_data;
5913 return_val_if_fail ( buf, FALSE );
5915 buf->offset = (int)size;
5921 __gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data) // @
5923 mm_player_t *player = (mm_player_t*)user_data;
5924 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
5926 return_if_fail ( player );
5928 debug_msg("app-src: feed data\n");
5930 if (player->media_stream_buffer_status_cb[type])
5931 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, player->buffer_cb_user_param);
5935 __gst_appsrc_seek_data(GstElement *element, guint64 offset, gpointer user_data) // @
5937 mm_player_t *player = (mm_player_t*)user_data;
5938 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
5940 return_val_if_fail ( player, FALSE );
5942 debug_msg("app-src: seek data\n");
5944 if(player->media_stream_seek_data_cb[type])
5945 player->media_stream_seek_data_cb[type](type, offset, player->buffer_cb_user_param);
5952 __gst_appsrc_enough_data(GstElement *element, gpointer user_data) // @
5954 mm_player_t *player = (mm_player_t*)user_data;
5955 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
5957 return_val_if_fail ( player, FALSE );
5959 debug_msg("app-src: enough data:%p\n", player->media_stream_buffer_status_cb[type]);
5961 if (player->media_stream_buffer_status_cb[type])
5962 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, player->buffer_cb_user_param);
5968 _mmplayer_push_buffer(MMHandleType hplayer, unsigned char *buf, int size) // @
5970 mm_player_t* player = (mm_player_t*)hplayer;
5971 GstBuffer *buffer = NULL;
5972 GstFlowReturn gst_ret = GST_FLOW_OK;
5973 int ret = MM_ERROR_NONE;
5978 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
5980 /* check current state */
5981 // MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_START );
5984 /* NOTE : we should check and create pipeline again if not created as we destroy
5985 * whole pipeline when stopping in streamming playback
5987 if ( ! player->pipeline )
5989 if ( MM_ERROR_NONE != __gst_realize( player ) )
5991 debug_error("failed to realize before starting. only in streamming\n");
5992 return MM_ERROR_PLAYER_INTERNAL;
5996 debug_msg("app-src: pushing data\n");
6000 debug_error("buf is null\n");
6001 return MM_ERROR_NONE;
6004 buffer = gst_buffer_new ();
6008 debug_log("call eos appsrc\n");
6009 g_signal_emit_by_name (player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "end-of-stream", &gst_ret);
6010 return MM_ERROR_NONE;
6013 //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));
6015 debug_log("feed buffer %p, length %u\n", buf, size);
6016 g_signal_emit_by_name (player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "push-buffer", buffer, &gst_ret);
6023 static GstBusSyncReply
6024 __mmplayer_bus_sync_callback (GstBus * bus, GstMessage * message, gpointer data)
6026 mm_player_t *player = (mm_player_t *)data;
6027 GstBusSyncReply reply = GST_BUS_DROP;
6029 if ( ! ( player->pipeline && player->pipeline->mainbin ) )
6031 debug_error("player pipeline handle is null");
6032 return GST_BUS_PASS;
6035 if (!__mmplayer_check_useful_message(player, message))
6037 gst_message_unref (message);
6038 return GST_BUS_DROP;
6041 switch (GST_MESSAGE_TYPE (message))
6043 case GST_MESSAGE_STATE_CHANGED:
6044 /* post directly for fast launch */
6045 if (player->sync_handler) {
6046 __mmplayer_gst_callback(NULL, message, player);
6047 reply = GST_BUS_DROP;
6050 reply = GST_BUS_PASS;
6053 case GST_MESSAGE_TAG:
6054 __mmplayer_gst_extract_tag_from_msg(player, message);
6058 GstTagList *tags = NULL;
6060 gst_message_parse_tag (message, &tags);
6062 debug_error("TAGS received from element \"%s\".\n",
6063 GST_STR_NULL (GST_ELEMENT_NAME (GST_MESSAGE_SRC (message))));
6065 gst_tag_list_foreach (tags, print_tag, NULL);
6066 gst_tag_list_free (tags);
6074 case GST_MESSAGE_DURATION_CHANGED:
6075 __mmplayer_gst_handle_duration(player, message);
6077 case GST_MESSAGE_ASYNC_DONE:
6078 /* NOTE:Don't call gst_callback directly
6079 * because previous frame can be showed even though this message is received for seek.
6082 reply = GST_BUS_PASS;
6086 if (reply == GST_BUS_DROP)
6087 gst_message_unref (message);
6093 __mmplayer_gst_create_decoder ( mm_player_t *player,
6094 MMPlayerTrackType track,
6096 enum MainElementID elemId,
6099 gboolean ret = TRUE;
6100 GstPad *sinkpad = NULL;
6104 return_val_if_fail( player &&
6106 player->pipeline->mainbin, FALSE);
6107 return_val_if_fail((track == MM_PLAYER_TRACK_TYPE_AUDIO || track == MM_PLAYER_TRACK_TYPE_VIDEO), FALSE);
6108 return_val_if_fail(srcpad, FALSE);
6109 return_val_if_fail((player->pipeline->mainbin[elemId].gst == NULL), FALSE);
6111 GstElement *decodebin = NULL;
6112 GstCaps *dec_caps = NULL;
6114 /* create decodebin */
6115 decodebin = gst_element_factory_make("decodebin", name);
6119 debug_error("error : fail to create decodebin for %d decoder\n", track);
6124 /* raw pad handling signal */
6125 MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6126 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
6128 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6129 before looking for any elements that can handle that stream.*/
6130 MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6131 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
6133 /* This signal is emitted when a element is added to the bin.*/
6134 MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6135 G_CALLBACK(__mmplayer_gst_element_added), player);
6137 if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), decodebin))
6139 debug_error("failed to add new decodebin\n");
6144 dec_caps = gst_pad_query_caps (srcpad, NULL);
6147 //debug_log ("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
6148 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
6149 gst_caps_unref(dec_caps);
6152 player->pipeline->mainbin[elemId].id = elemId;
6153 player->pipeline->mainbin[elemId].gst = decodebin;
6155 sinkpad = gst_element_get_static_pad (decodebin, "sink");
6157 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad))
6159 debug_warning ("failed to link [%s:%s] to decoder\n", GST_DEBUG_PAD_NAME(srcpad));
6160 gst_object_unref (GST_OBJECT(decodebin));
6163 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent (decodebin))
6165 debug_error("failed to sync second level decodebin state with parent\n");
6168 debug_log("Total num of %d tracks = %d \n", track, player->selector[track].total_track_num);
6173 gst_object_unref ( GST_OBJECT(sinkpad) );
6182 * This function is to create audio or video pipeline for playing.
6184 * @param player [in] handle of player
6186 * @return This function returns zero on success.
6191 __mmplayer_gst_create_pipeline(mm_player_t* player) // @
6194 MMPlayerGstElement *mainbin = NULL;
6195 MMHandleType attrs = 0;
6196 GstElement* element = NULL;
6197 GstElement* elem_src_audio = NULL;
6198 GstElement* elem_src_subtitle = NULL;
6199 GstElement* es_video_queue = NULL;
6200 GstElement* es_audio_queue = NULL;
6201 GstElement* es_subtitle_queue = NULL;
6202 GList* element_bucket = NULL;
6203 gboolean need_state_holder = TRUE;
6205 #ifdef SW_CODEC_ONLY
6206 int surface_type = 0;
6210 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6212 /* get profile attribute */
6213 attrs = MMPLAYER_GET_ATTRS(player);
6216 debug_error("cannot get content attribute\n");
6220 /* create pipeline handles */
6221 if ( player->pipeline )
6223 debug_warning("pipeline should be released before create new one\n");
6227 player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0( sizeof(MMPlayerGstPipelineInfo) );
6228 if (player->pipeline == NULL)
6231 memset( player->pipeline, 0, sizeof(MMPlayerGstPipelineInfo) );
6234 /* create mainbin */
6235 mainbin = (MMPlayerGstElement*) g_malloc0( sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM );
6236 if (mainbin == NULL)
6239 memset( mainbin, 0, sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
6241 /* create pipeline */
6242 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
6243 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
6244 if ( ! mainbin[MMPLAYER_M_PIPE].gst )
6246 debug_error("failed to create pipeline\n");
6249 player->demux_pad_index = 0;
6250 player->subtitle_language_list = NULL;
6252 player->is_subtitle_force_drop = FALSE;
6253 player->last_multiwin_status = FALSE;
6255 _mmplayer_track_initialize(player);
6257 /* create source element */
6258 switch ( player->profile.uri_type )
6260 /* rtsp streamming */
6261 case MM_PLAYER_URI_TYPE_URL_RTSP:
6263 gint network_bandwidth;
6264 gchar *user_agent, *wap_profile;
6266 element = gst_element_factory_make("rtspsrc", "rtsp source");
6270 debug_error("failed to create streaming source element\n");
6275 network_bandwidth = 0;
6276 user_agent = wap_profile = NULL;
6279 mm_attrs_get_string_by_name ( attrs, "streaming_user_agent", &user_agent );
6280 mm_attrs_get_string_by_name ( attrs,"streaming_wap_profile", &wap_profile );
6281 mm_attrs_get_int_by_name ( attrs, "streaming_network_bandwidth", &network_bandwidth );
6283 secure_debug_log("user_agent : %s\n", user_agent);
6284 secure_debug_log("wap_profile : %s\n", wap_profile);
6286 /* setting property to streaming source */
6287 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6289 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6291 g_object_set(G_OBJECT(element), "wap_profile", wap_profile, NULL);
6293 MMPLAYER_SIGNAL_CONNECT ( player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6294 G_CALLBACK (__mmplayer_gst_rtp_dynamic_pad), player );
6295 MMPLAYER_SIGNAL_CONNECT ( player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6296 G_CALLBACK (__mmplayer_gst_rtp_no_more_pads), player );
6298 player->use_decodebin = FALSE;
6303 case MM_PLAYER_URI_TYPE_URL_HTTP:
6305 gchar *user_agent, *proxy, *cookies, **cookie_list;
6306 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6307 user_agent = proxy = cookies = NULL;
6309 gint mode = MM_PLAYER_PD_MODE_NONE;
6311 mm_attrs_get_int_by_name ( attrs, "pd_mode", &mode );
6313 player->pd_mode = mode;
6315 debug_log("http playback, PD mode : %d\n", player->pd_mode);
6317 if ( ! MMPLAYER_IS_HTTP_PD(player) )
6319 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
6322 debug_error("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
6325 debug_log("using http streamming source [%s].\n", player->ini.httpsrc_element);
6328 mm_attrs_get_string_by_name ( attrs, "streaming_cookie", &cookies );
6329 mm_attrs_get_string_by_name ( attrs, "streaming_user_agent", &user_agent );
6330 mm_attrs_get_string_by_name ( attrs, "streaming_proxy", &proxy );
6331 mm_attrs_get_int_by_name ( attrs, "streaming_timeout", &http_timeout );
6333 if ((http_timeout == DEFAULT_HTTP_TIMEOUT) &&
6334 (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT))
6336 debug_log("get timeout from ini\n");
6337 http_timeout = player->ini.http_timeout;
6341 secure_debug_log("location : %s\n", player->profile.uri);
6342 secure_debug_log("cookies : %s\n", cookies);
6343 secure_debug_log("proxy : %s\n", proxy);
6344 secure_debug_log("user_agent : %s\n", user_agent);
6345 debug_log("timeout : %d\n", http_timeout);
6347 /* setting property to streaming source */
6348 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6349 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6350 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
6352 /* check if prosy is vailid or not */
6353 if ( util_check_valid_url ( proxy ) )
6354 g_object_set(G_OBJECT(element), "proxy", proxy, NULL);
6355 /* parsing cookies */
6356 if ( ( cookie_list = util_get_cookie_list ((const char*)cookies) ) )
6357 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
6359 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6361 if ( MMPLAYER_URL_HAS_DASH_SUFFIX(player) )
6363 debug_warning("it's dash. and it's still experimental feature.");
6366 else // progressive download
6368 gchar* location = NULL;
6370 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
6374 mm_attrs_get_string_by_name ( attrs, "pd_location", &path );
6376 MMPLAYER_FREEIF(player->pd_file_save_path);
6378 debug_log("PD Location : %s\n", path);
6382 player->pd_file_save_path = g_strdup(path);
6386 debug_error("can't find pd location so, it should be set \n");
6387 return MM_ERROR_PLAYER_FILE_NOT_FOUND;
6391 element = gst_element_factory_make("pdpushsrc", "PD pushsrc");
6394 debug_error("failed to create PD push source element[%s].\n", "pdpushsrc");
6398 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
6399 g_object_set(G_OBJECT(element), "location", player->pd_file_save_path, NULL);
6401 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6403 g_object_get(element, "location", &location, NULL);
6404 debug_log("PD_LOCATION [%s].\n", location);
6412 case MM_PLAYER_URI_TYPE_FILE:
6415 debug_log("using filesrc for 'file://' handler.\n");
6417 element = gst_element_factory_make("filesrc", "source");
6421 debug_error("failed to create filesrc\n");
6425 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
6426 //g_object_set(G_OBJECT(element), "use-mmap", TRUE, NULL);
6430 case MM_PLAYER_URI_TYPE_SS:
6432 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6433 element = gst_element_factory_make("souphttpsrc", "http streaming source");
6436 debug_error("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
6440 mm_attrs_get_int_by_name ( attrs, "streaming_timeout", &http_timeout );
6442 if ((http_timeout == DEFAULT_HTTP_TIMEOUT) &&
6443 (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT))
6445 debug_log("get timeout from ini\n");
6446 http_timeout = player->ini.http_timeout;
6449 /* setting property to streaming source */
6450 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6451 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6456 case MM_PLAYER_URI_TYPE_BUFF:
6458 guint64 stream_type = GST_APP_STREAM_TYPE_STREAM;
6460 debug_log("mem src is selected\n");
6462 element = gst_element_factory_make("appsrc", "buff-source");
6465 debug_error("failed to create appsrc element\n");
6469 g_object_set( element, "stream-type", stream_type, NULL );
6470 //g_object_set( element, "size", player->mem_buf.len, NULL );
6471 //g_object_set( element, "blocksize", (guint64)20480, NULL );
6473 MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6474 G_CALLBACK(__gst_appsrc_seek_data), player);
6475 MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6476 G_CALLBACK(__gst_appsrc_feed_data), player);
6477 MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6478 G_CALLBACK(__gst_appsrc_enough_data), player);
6481 case MM_PLAYER_URI_TYPE_ES_BUFF:
6483 debug_log("es buff src is selected\n");
6485 if (player->v_stream_caps)
6487 element = gst_element_factory_make("appsrc", "video_appsrc");
6490 debug_critical("failed to create video app source element[appsrc].\n" );
6494 if ( player->a_stream_caps )
6496 elem_src_audio = gst_element_factory_make("appsrc", "audio_appsrc");
6497 if ( !elem_src_audio )
6499 debug_critical("failed to create audio app source element[appsrc].\n" );
6504 else if ( player->a_stream_caps )
6506 /* no video, only audio pipeline*/
6507 element = gst_element_factory_make("appsrc", "audio_appsrc");
6510 debug_critical("failed to create audio app source element[appsrc].\n" );
6515 if ( player->s_stream_caps )
6517 elem_src_subtitle = gst_element_factory_make("appsrc", "subtitle_appsrc");
6518 if ( !elem_src_subtitle )
6520 debug_critical("failed to create subtitle app source element[appsrc].\n" );
6525 debug_log("setting app sources properties.\n");
6526 debug_log("location : %s\n", player->profile.uri);
6528 if ( player->v_stream_caps && element )
6530 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6531 "blocksize", (guint)1048576, /* size of many video frames are larger than default blocksize as 4096 */
6532 "caps", player->v_stream_caps, NULL);
6534 if ( player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6535 g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6536 if ( player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6537 g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6539 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6540 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6541 MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6542 G_CALLBACK(__gst_seek_video_data), player);
6544 if (player->a_stream_caps && elem_src_audio)
6546 g_object_set(G_OBJECT(elem_src_audio), "format", GST_FORMAT_TIME,
6547 "caps", player->a_stream_caps, NULL);
6549 if ( player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6550 g_object_set(G_OBJECT(elem_src_audio), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6551 if ( player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6552 g_object_set(G_OBJECT(elem_src_audio), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6554 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6555 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_audio), GST_APP_STREAM_TYPE_SEEKABLE);
6556 MMPLAYER_SIGNAL_CONNECT( player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6557 G_CALLBACK(__gst_seek_audio_data), player);
6560 else if (player->a_stream_caps && element)
6562 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6563 "caps", player->a_stream_caps, NULL);
6565 if ( player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6566 g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6567 if ( player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6568 g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6570 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6571 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6572 MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6573 G_CALLBACK(__gst_seek_audio_data), player);
6576 if (player->s_stream_caps && elem_src_subtitle)
6578 g_object_set(G_OBJECT(elem_src_subtitle), "format", GST_FORMAT_TIME,
6579 "caps", player->s_stream_caps, NULL);
6581 if ( player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6582 g_object_set(G_OBJECT(elem_src_subtitle), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6583 if ( player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6584 g_object_set(G_OBJECT(elem_src_subtitle), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6586 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_subtitle), GST_APP_STREAM_TYPE_SEEKABLE);
6588 MMPLAYER_SIGNAL_CONNECT( player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6589 G_CALLBACK(__gst_seek_subtitle_data), player);
6592 if (player->v_stream_caps && element)
6594 MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6595 G_CALLBACK(__gst_appsrc_feed_video_data), player);
6596 MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6597 G_CALLBACK(__gst_appsrc_enough_video_data), player);
6599 if (player->a_stream_caps && elem_src_audio)
6601 MMPLAYER_SIGNAL_CONNECT( player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6602 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6603 MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6604 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6607 else if (player->a_stream_caps && element)
6609 MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6610 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6611 MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6612 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6615 if (player->s_stream_caps && elem_src_subtitle)
6617 MMPLAYER_SIGNAL_CONNECT( player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6618 G_CALLBACK(__gst_appsrc_feed_subtitle_data), player);
6621 need_state_holder = FALSE;
6625 case MM_PLAYER_URI_TYPE_MEM:
6627 guint64 stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
6629 debug_log("mem src is selected\n");
6631 element = gst_element_factory_make("appsrc", "mem-source");
6634 debug_error("failed to create appsrc element\n");
6638 g_object_set( element, "stream-type", stream_type, NULL );
6639 g_object_set( element, "size", player->mem_buf.len, NULL );
6640 g_object_set( element, "blocksize", (guint64)20480, NULL );
6642 MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6643 G_CALLBACK(__gst_appsrc_seek_data_mem), &player->mem_buf );
6644 MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6645 G_CALLBACK(__gst_appsrc_feed_data_mem), &player->mem_buf );
6648 case MM_PLAYER_URI_TYPE_URL:
6651 case MM_PLAYER_URI_TYPE_TEMP:
6654 case MM_PLAYER_URI_TYPE_NONE:
6659 /* check source element is OK */
6662 debug_error("no source element was created.\n");
6666 /* take source element */
6667 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6668 mainbin[MMPLAYER_M_SRC].gst = element;
6669 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
6671 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL))
6673 player->streamer = __mm_player_streaming_create();
6674 __mm_player_streaming_initialize(player->streamer);
6677 if ( MMPLAYER_IS_HTTP_PD(player) )
6679 gdouble pre_buffering_time = (gdouble)player->streamer->buffering_req.initial_second;
6681 debug_log ("Picked queue2 element(pre buffer : %d sec)....\n", pre_buffering_time);
6682 element = gst_element_factory_make("queue2", "queue2");
6685 debug_error ( "failed to create http streaming buffer element\n" );
6690 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6691 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element;
6692 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]);
6694 pre_buffering_time = (pre_buffering_time > 0)?(pre_buffering_time):(player->ini.http_buffering_time);
6696 __mm_player_streaming_set_queue2(player->streamer,
6699 player->ini.http_max_size_bytes,
6702 player->ini.http_buffering_limit,
6707 if (MMPLAYER_IS_ES_BUFF_SRC(player))
6709 if (player->v_stream_caps)
6711 es_video_queue = gst_element_factory_make("queue2", "video_queue");
6712 if (!es_video_queue)
6714 debug_error ("create es_video_queue for es player failed\n");
6717 mainbin[MMPLAYER_M_V_BUFFER].id = MMPLAYER_M_V_BUFFER;
6718 mainbin[MMPLAYER_M_V_BUFFER].gst = es_video_queue;
6719 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_V_BUFFER]);
6721 /* Adding audio appsrc to bucket */
6722 if (player->a_stream_caps && elem_src_audio)
6724 mainbin[MMPLAYER_M_2ND_SRC].id = MMPLAYER_M_2ND_SRC;
6725 mainbin[MMPLAYER_M_2ND_SRC].gst = elem_src_audio;
6726 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_2ND_SRC]);
6728 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6729 if (!es_audio_queue)
6731 debug_error ("create es_audio_queue for es player failed\n");
6734 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6735 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6736 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6739 /* Only audio stream, no video */
6740 else if (player->a_stream_caps)
6742 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6743 if (!es_audio_queue)
6745 debug_error ("create es_audio_queue for es player failed\n");
6748 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6749 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6750 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6753 if (player->s_stream_caps && elem_src_subtitle)
6755 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
6756 mainbin[MMPLAYER_M_SUBSRC].gst = elem_src_subtitle;
6757 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SUBSRC]);
6759 es_subtitle_queue = gst_element_factory_make("queue2", "subtitle_queue");
6760 if (!es_subtitle_queue)
6762 debug_error ("create es_subtitle_queue for es player failed\n");
6765 mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_V_BUFFER;
6766 mainbin[MMPLAYER_M_S_BUFFER].gst = es_subtitle_queue;
6767 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_S_BUFFER]);
6771 /* create autoplugging element if src element is not a rtsp src */
6772 if ((player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_RTSP) &&
6773 (player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_WFD) &&
6774 (player->profile.uri_type != MM_PLAYER_URI_TYPE_ES_BUFF))
6777 enum MainElementID elemId = MMPLAYER_M_NUM;
6779 if ((player->use_decodebin) &&
6780 ((MMPLAYER_IS_HTTP_PD(player)) ||
6781 (!MMPLAYER_IS_HTTP_STREAMING(player))))
6783 elemId = MMPLAYER_M_AUTOPLUG;
6784 element = __mmplayer_create_decodebin(player);
6785 need_state_holder = FALSE;
6789 elemId = MMPLAYER_M_TYPEFIND;
6790 element = gst_element_factory_make("typefind", "typefinder");
6791 MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
6792 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player );
6796 /* check autoplug element is OK */
6799 debug_error("can not create element (%d)\n", elemId);
6803 mainbin[elemId].id = elemId;
6804 mainbin[elemId].gst = element;
6806 element_bucket = g_list_append(element_bucket, &mainbin[elemId]);
6809 /* add elements to pipeline */
6810 if( !__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket))
6812 debug_error("Failed to add elements to pipeline\n");
6817 /* linking elements in the bucket by added order. */
6818 if ( __mmplayer_gst_element_link_bucket(element_bucket) == -1 )
6820 debug_error("Failed to link some elements\n");
6825 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
6826 if ( need_state_holder )
6829 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
6830 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make ("fakesink", "state-holder");
6832 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
6834 debug_error ("fakesink element could not be created\n");
6837 GST_OBJECT_FLAG_UNSET (mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
6839 /* take ownership of fakesink. we are reusing it */
6840 gst_object_ref( mainbin[MMPLAYER_M_SRC_FAKESINK].gst );
6843 if ( FALSE == gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst),
6844 mainbin[MMPLAYER_M_SRC_FAKESINK].gst) )
6846 debug_error("failed to add fakesink to bin\n");
6851 /* now we have completed mainbin. take it */
6852 player->pipeline->mainbin = mainbin;
6854 if (MMPLAYER_IS_ES_BUFF_SRC(player))
6856 GstPad *srcpad = NULL;
6858 if (mainbin[MMPLAYER_M_V_BUFFER].gst)
6860 srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_V_BUFFER].gst, "src");
6863 __mmplayer_gst_create_decoder ( player,
6864 MM_PLAYER_TRACK_TYPE_VIDEO,
6866 MMPLAYER_M_AUTOPLUG_V_DEC,
6869 gst_object_unref ( GST_OBJECT(srcpad) );
6874 if ((player->a_stream_caps) && (mainbin[MMPLAYER_M_A_BUFFER].gst))
6876 srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_A_BUFFER].gst, "src");
6879 __mmplayer_gst_create_decoder ( player,
6880 MM_PLAYER_TRACK_TYPE_AUDIO,
6882 MMPLAYER_M_AUTOPLUG_A_DEC,
6885 gst_object_unref ( GST_OBJECT(srcpad) );
6890 if (mainbin[MMPLAYER_M_S_BUFFER].gst)
6892 __mmplayer_try_to_plug_decodebin(player, gst_element_get_static_pad(mainbin[MMPLAYER_M_S_BUFFER].gst, "src"), player->s_stream_caps);
6896 /* connect bus callback */
6897 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6900 debug_error ("cannot get bus from pipeline.\n");
6904 player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_callback, player);
6906 player->context.thread_default = g_main_context_get_thread_default();
6908 if (NULL == player->context.thread_default)
6910 player->context.thread_default = g_main_context_default();
6911 debug_log("thread-default context is the global default context");
6913 debug_warning("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
6915 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
6916 if ( __mmplayer_check_subtitle ( player ) )
6918 if ( MM_ERROR_NONE != __mmplayer_gst_create_subtitle_src(player) )
6919 debug_error("fail to create subtitle src\n");
6922 /* set sync handler to get tag synchronously */
6923 gst_bus_set_sync_handler(bus, __mmplayer_bus_sync_callback, player, NULL);
6926 gst_object_unref(GST_OBJECT(bus));
6927 g_list_free(element_bucket);
6931 return MM_ERROR_NONE;
6935 __mmplayer_gst_destroy_pipeline(player);
6936 g_list_free(element_bucket);
6938 /* release element which are not added to bin */
6939 for ( i = 1; i < MMPLAYER_M_NUM; i++ ) /* NOTE : skip pipeline */
6941 if ( mainbin[i].gst )
6943 GstObject* parent = NULL;
6944 parent = gst_element_get_parent( mainbin[i].gst );
6948 gst_object_unref(GST_OBJECT(mainbin[i].gst));
6949 mainbin[i].gst = NULL;
6953 gst_object_unref(GST_OBJECT(parent));
6958 /* release pipeline with it's childs */
6959 if ( mainbin[MMPLAYER_M_PIPE].gst )
6961 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
6964 MMPLAYER_FREEIF( player->pipeline );
6965 MMPLAYER_FREEIF( mainbin );
6967 return MM_ERROR_PLAYER_INTERNAL;
6971 __mmplayer_reset_gapless_state(mm_player_t* player)
6974 return_if_fail(player
6976 && player->pipeline->audiobin
6977 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
6979 if (player->gapless.audio_data_probe_id != 0)
6982 sinkpad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_BIN].gst, "sink");
6983 gst_pad_remove_probe (sinkpad, player->gapless.audio_data_probe_id);
6984 gst_object_unref (sinkpad);
6986 memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
6993 __mmplayer_gst_destroy_pipeline(mm_player_t* player) // @
6996 int ret = MM_ERROR_NONE;
7000 return_val_if_fail ( player, MM_ERROR_INVALID_HANDLE );
7002 /* cleanup stuffs */
7003 MMPLAYER_FREEIF(player->type);
7004 player->have_dynamic_pad = FALSE;
7005 player->no_more_pad = FALSE;
7006 player->num_dynamic_pad = 0;
7007 player->demux_pad_index = 0;
7008 player->subtitle_language_list = NULL;
7009 player->use_deinterleave = FALSE;
7010 player->max_audio_channels = 0;
7011 player->video_share_api_delta = 0;
7012 player->video_share_clock_delta = 0;
7013 player->video_hub_download_mode = 0;
7014 __mmplayer_reset_gapless_state(player);
7015 __mmplayer_post_proc_reset(player);
7017 if (player->streamer)
7019 __mm_player_streaming_deinitialize (player->streamer);
7020 __mm_player_streaming_destroy(player->streamer);
7021 player->streamer = NULL;
7024 /* cleanup unlinked mime type */
7025 MMPLAYER_FREEIF(player->unlinked_audio_mime);
7026 MMPLAYER_FREEIF(player->unlinked_video_mime);
7027 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
7029 /* cleanup running stuffs */
7030 __mmplayer_cancel_eos_timer( player );
7031 #if 0 //need to change and test
7032 /* remove sound cb */
7033 if ( MM_ERROR_NONE != mm_sound_remove_device_information_changed_callback())
7035 debug_error("failed to mm_sound_remove_device_information_changed_callback()");
7038 /* cleanup gst stuffs */
7039 if ( player->pipeline )
7041 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
7042 GstTagList* tag_list = player->pipeline->tag_list;
7044 /* first we need to disconnect all signal hander */
7045 __mmplayer_release_signal_connection( player, MM_PLAYER_SIGNAL_TYPE_ALL );
7047 /* disconnecting bus watch */
7048 if ( player->bus_watcher )
7049 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
7050 player->bus_watcher = 0;
7054 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
7055 MMPlayerGstElement* videobin = player->pipeline->videobin;
7056 MMPlayerGstElement* textbin = player->pipeline->textbin;
7057 GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE (mainbin[MMPLAYER_M_PIPE].gst));
7058 gst_bus_set_sync_handler (bus, NULL, NULL, NULL);
7059 gst_object_unref(bus);
7061 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7062 ret = __mmplayer_gst_set_state ( player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout );
7063 if ( ret != MM_ERROR_NONE )
7065 debug_error("fail to change state to NULL\n");
7066 return MM_ERROR_PLAYER_INTERNAL;
7069 debug_warning("succeeded in chaning state to NULL\n");
7071 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
7074 if ( mainbin[MMPLAYER_M_SRC_FAKESINK].gst )
7075 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
7077 /* free avsysaudiosink
7078 avsysaudiosink should be unref when destory pipeline just after start play with BT.
7079 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
7081 MMPLAYER_FREEIF( audiobin );
7082 MMPLAYER_FREEIF( videobin );
7083 MMPLAYER_FREEIF( textbin );
7084 MMPLAYER_FREEIF( mainbin );
7088 gst_tag_list_free(tag_list);
7090 MMPLAYER_FREEIF( player->pipeline );
7092 MMPLAYER_FREEIF(player->album_art);
7094 if (player->v_stream_caps)
7096 gst_caps_unref(player->v_stream_caps);
7097 player->v_stream_caps = NULL;
7099 if (player->a_stream_caps)
7101 gst_caps_unref(player->a_stream_caps);
7102 player->a_stream_caps = NULL;
7104 if (player->s_stream_caps)
7106 gst_caps_unref(player->s_stream_caps);
7107 player->s_stream_caps = NULL;
7109 _mmplayer_track_destroy(player);
7111 if ( player->sink_elements )
7112 g_list_free ( player->sink_elements );
7113 player->sink_elements = NULL;
7115 debug_warning("finished destroy pipeline\n");
7122 static int __gst_realize(mm_player_t* player) // @
7125 int ret = MM_ERROR_NONE;
7129 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7131 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7133 ret = __mmplayer_gst_create_pipeline(player);
7136 debug_error("failed to create pipeline\n");
7140 /* set pipeline state to READY */
7141 /* NOTE : state change to READY must be performed sync. */
7142 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7143 ret = __mmplayer_gst_set_state(player,
7144 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
7146 if ( ret != MM_ERROR_NONE )
7148 /* return error if failed to set state */
7149 debug_error("failed to set READY state");
7154 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_READY );
7157 /* create dot before error-return. for debugging */
7158 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-realize" );
7165 static int __gst_unrealize(mm_player_t* player) // @
7167 int ret = MM_ERROR_NONE;
7171 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7173 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
7174 MMPLAYER_PRINT_STATE(player);
7176 /* release miscellaneous information */
7177 __mmplayer_release_misc( player );
7179 /* destroy pipeline */
7180 ret = __mmplayer_gst_destroy_pipeline( player );
7181 if ( ret != MM_ERROR_NONE )
7183 debug_error("failed to destory pipeline\n");
7187 /* release miscellaneous information.
7188 these info needs to be released after pipeline is destroyed. */
7189 __mmplayer_release_misc_post( player );
7191 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_NULL );
7198 static int __gst_pending_seek ( mm_player_t* player )
7200 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7201 int ret = MM_ERROR_NONE;
7205 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
7207 if ( !player->pending_seek.is_pending )
7209 debug_log("pending seek is not reserved. nothing to do.\n" );
7213 /* check player state if player could pending seek or not. */
7214 current_state = MMPLAYER_CURRENT_STATE(player);
7216 if ( current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING )
7218 debug_warning("try to pending seek in %s state, try next time. \n",
7219 MMPLAYER_STATE_GET_NAME(current_state));
7223 debug_log("trying to play from (%lu) pending position\n", player->pending_seek.pos);
7225 ret = __gst_set_position ( player, player->pending_seek.format, player->pending_seek.pos, FALSE );
7227 if ( MM_ERROR_NONE != ret )
7228 debug_error("failed to seek pending postion. just keep staying current position.\n");
7230 player->pending_seek.is_pending = FALSE;
7237 static int __gst_start(mm_player_t* player) // @
7239 gboolean sound_extraction = 0;
7240 int ret = MM_ERROR_NONE;
7241 gboolean async = FALSE;
7245 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
7247 /* get sound_extraction property */
7248 mm_attrs_get_int_by_name(player->attrs, "pcm_extraction", &sound_extraction);
7250 /* NOTE : if SetPosition was called before Start. do it now */
7251 /* streaming doesn't support it. so it should be always sync */
7252 /* !! create one more api to check if there is pending seek rather than checking variables */
7253 if ( (player->pending_seek.is_pending || sound_extraction) && !MMPLAYER_IS_STREAMING(player))
7255 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
7256 ret = __gst_pause(player, FALSE);
7257 if ( ret != MM_ERROR_NONE )
7259 debug_error("failed to set state to PAUSED for pending seek\n");
7263 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
7265 if ( sound_extraction )
7267 debug_log("setting pcm extraction\n");
7269 ret = __mmplayer_set_pcm_extraction(player);
7270 if ( MM_ERROR_NONE != ret )
7272 debug_warning("failed to set pcm extraction\n");
7278 if ( MM_ERROR_NONE != __gst_pending_seek(player) )
7280 debug_warning("failed to seek pending postion. starting from the begin of content.\n");
7285 debug_log("current state before doing transition");
7286 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7287 MMPLAYER_PRINT_STATE(player);
7289 /* set pipeline state to PLAYING */
7290 if (player->es_player_push_mode)
7294 /* set pipeline state to PLAYING */
7295 ret = __mmplayer_gst_set_state(player,
7296 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player) );
7298 if (ret == MM_ERROR_NONE)
7300 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7304 debug_error("failed to set state to PLAYING");
7308 /* generating debug info before returning error */
7309 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-start" );
7316 static void __mmplayer_do_sound_fadedown(mm_player_t* player, unsigned int time)
7320 return_if_fail(player
7322 && player->pipeline->audiobin
7323 && player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
7325 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", 2, NULL);
7332 static void __mmplayer_undo_sound_fadedown(mm_player_t* player)
7336 return_if_fail(player
7338 && player->pipeline->audiobin
7339 && player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
7341 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", 0, NULL);
7346 static int __gst_stop(mm_player_t* player) // @
7348 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
7349 MMHandleType attrs = 0;
7350 gboolean fadedown = FALSE;
7351 gboolean rewind = FALSE;
7353 int ret = MM_ERROR_NONE;
7355 gboolean async = FALSE;
7359 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7360 return_val_if_fail ( player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7362 debug_log("current state before doing transition");
7363 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7364 MMPLAYER_PRINT_STATE(player);
7366 attrs = MMPLAYER_GET_ATTRS(player);
7369 debug_error("cannot get content attribute\n");
7370 return MM_ERROR_PLAYER_INTERNAL;
7373 mm_attrs_get_int_by_name(attrs, "sound_fadedown", &fadedown);
7375 /* enable fadedown */
7376 if (fadedown || player->sound_focus.by_asm_cb)
7377 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
7379 /* Just set state to PAUESED and the rewind. it's usual player behavior. */
7380 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT ( player );
7382 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_BUFF ||
7383 player->profile.uri_type == MM_PLAYER_URI_TYPE_HLS)
7385 state = GST_STATE_READY;
7389 state = GST_STATE_PAUSED;
7391 if ( ! MMPLAYER_IS_STREAMING(player) ||
7392 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked)) {
7397 if (player->es_player_push_mode)
7402 ret = __mmplayer_gst_set_state( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, state, async, timeout );
7404 /* disable fadeout */
7405 if (fadedown || player->sound_focus.by_asm_cb)
7406 __mmplayer_undo_sound_fadedown(player);
7408 /* return if set_state has failed */
7409 if ( ret != MM_ERROR_NONE )
7411 debug_error("failed to set state.\n");
7418 if ( ! __gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7419 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
7420 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE) )
7422 debug_warning("failed to rewind\n");
7423 ret = MM_ERROR_PLAYER_SEEK;
7428 player->sent_bos = FALSE;
7430 if (player->es_player_push_mode) //for cloudgame
7435 /* wait for seek to complete */
7436 change_ret = gst_element_get_state (player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
7437 if ( change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL )
7439 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_READY );
7443 debug_error("fail to stop player.\n");
7444 ret = MM_ERROR_PLAYER_INTERNAL;
7445 __mmplayer_dump_pipeline_state(player);
7448 /* generate dot file if enabled */
7449 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-stop" );
7456 int __gst_pause(mm_player_t* player, gboolean async) // @
7458 int ret = MM_ERROR_NONE;
7462 return_val_if_fail(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7463 return_val_if_fail(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7465 debug_log("current state before doing transition");
7466 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
7467 MMPLAYER_PRINT_STATE(player);
7469 /* set pipeline status to PAUSED */
7470 player->ignore_asyncdone = TRUE;
7472 ret = __mmplayer_gst_set_state(player,
7473 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7475 player->ignore_asyncdone = FALSE;
7477 if ( FALSE == async )
7479 if ( ret != MM_ERROR_NONE )
7481 GstMessage *msg = NULL;
7482 GTimer *timer = NULL;
7483 gdouble MAX_TIMEOUT_SEC = 3;
7485 debug_error("failed to set state to PAUSED");
7487 timer = g_timer_new();
7488 g_timer_start(timer);
7490 GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7491 gboolean got_msg = FALSE;
7492 /* check if gst error posted or not */
7495 msg = gst_bus_timed_pop(bus, GST_SECOND /2);
7498 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR)
7500 GError *error = NULL;
7502 /* parse error code */
7503 gst_message_parse_error(msg, &error, NULL);
7505 if ( gst_structure_has_name ( gst_message_get_structure(msg), "streaming_error" ) )
7507 /* Note : the streaming error from the streaming source is handled
7508 * using __mmplayer_handle_streaming_error.
7510 __mmplayer_handle_streaming_error ( player, msg );
7515 debug_error("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
7517 if (error->domain == GST_STREAM_ERROR)
7519 ret = __gst_handle_stream_error( player, error, msg );
7521 else if (error->domain == GST_RESOURCE_ERROR)
7523 ret = __gst_handle_resource_error( player, error->code );
7525 else if (error->domain == GST_LIBRARY_ERROR)
7527 ret = __gst_handle_library_error( player, error->code );
7529 else if (error->domain == GST_CORE_ERROR)
7531 ret = __gst_handle_core_error( player, error->code );
7536 player->msg_posted = TRUE;
7538 gst_message_unref(msg);
7540 } while (!got_msg && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
7542 gst_object_unref(bus);
7543 g_timer_stop (timer);
7544 g_timer_destroy (timer);
7548 else if ( (!player->pipeline->videobin) && (!player->pipeline->audiobin) )
7550 if (MMPLAYER_IS_RTSP_STREAMING(player))
7552 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
7554 else if ( ret== MM_ERROR_NONE)
7556 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_PAUSED );
7560 /* generate dot file before returning error */
7561 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-pause" );
7568 int __gst_resume(mm_player_t* player, gboolean async) // @
7570 int ret = MM_ERROR_NONE;
7575 return_val_if_fail(player && player->pipeline,
7576 MM_ERROR_PLAYER_NOT_INITIALIZED);
7578 debug_log("current state before doing transition");
7579 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7580 MMPLAYER_PRINT_STATE(player);
7582 /* generate dot file before returning error */
7583 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-resume" );
7586 debug_log("do async state transition to PLAYING.\n");
7588 /* set pipeline state to PLAYING */
7589 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7591 ret = __mmplayer_gst_set_state(player,
7592 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout );
7593 if (ret != MM_ERROR_NONE)
7595 debug_error("failed to set state to PLAYING\n");
7602 // MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_PLAYING );
7603 debug_log("update state machine to %d\n", MM_PLAYER_STATE_PLAYING);
7604 ret = __mmplayer_set_state(player, MM_PLAYER_STATE_PLAYING);
7608 /* generate dot file before returning error */
7609 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-resume" );
7617 __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called) // @
7619 unsigned long dur_msec = 0;
7620 gint64 dur_nsec = 0;
7621 gint64 pos_nsec = 0;
7622 gboolean ret = TRUE;
7623 gboolean accurated = FALSE;
7624 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
7627 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
7628 return_val_if_fail ( !MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP );
7630 if ( MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
7631 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED )
7634 if( !MMPLAYER_IS_ES_BUFF_SRC(player) )
7636 /* check duration */
7637 /* NOTE : duration cannot be zero except live streaming.
7638 * Since some element could have some timing problemn with quering duration, try again.
7640 if ( !player->duration )
7642 if ( !gst_element_query_duration( player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec ))
7646 player->duration = dur_nsec;
7649 if ( player->duration )
7651 dur_msec = GST_TIME_AS_MSECONDS(player->duration);
7655 debug_error("could not get the duration. fail to seek.\n");
7659 debug_log("playback rate: %f\n", player->playback_rate);
7661 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
7664 seek_flags |= GST_SEEK_FLAG_ACCURATE;
7668 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
7674 case MM_PLAYER_POS_FORMAT_TIME:
7676 if( !MMPLAYER_IS_ES_BUFF_SRC(player) )
7678 /* check position is valid or not */
7679 if ( position > dur_msec )
7682 debug_log("seeking to (%lu) msec, duration is %d msec\n", position, dur_msec);
7684 if ( player->doing_seek )
7686 debug_log("not completed seek");
7687 return MM_ERROR_PLAYER_DOING_SEEK;
7691 if ( !internal_called )
7692 player->doing_seek = TRUE;
7694 pos_nsec = position * G_GINT64_CONSTANT(1000000);
7696 if ((MMPLAYER_IS_HTTP_STREAMING(player)) && (!player->videodec_linked))
7698 gint64 cur_time = 0;
7700 /* get current position */
7701 gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_time);
7704 GstEvent *event = gst_event_new_seek (1.0,
7706 (GstSeekFlags)GST_SEEK_FLAG_FLUSH,
7707 GST_SEEK_TYPE_SET, cur_time,
7708 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7710 __gst_send_event_to_sink(player, event);
7713 __gst_pause( player, FALSE );
7716 ret = __gst_seek ( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7717 GST_FORMAT_TIME, seek_flags,
7718 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE );
7721 debug_error("failed to set position. dur[%lu] pos[%lu] pos_msec[%llu]\n", dur_msec, position, pos_nsec);
7727 case MM_PLAYER_POS_FORMAT_PERCENT:
7729 debug_log("seeking to (%lu)%% \n", position);
7731 if (player->doing_seek)
7733 debug_log("not completed seek");
7734 return MM_ERROR_PLAYER_DOING_SEEK;
7737 if ( !internal_called)
7738 player->doing_seek = TRUE;
7740 /* FIXIT : why don't we use 'GST_FORMAT_PERCENT' */
7741 pos_nsec = (gint64) ( ( position * player->duration ) / 100 );
7742 ret = __gst_seek ( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7743 GST_FORMAT_TIME, seek_flags,
7744 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE );
7747 debug_error("failed to set position. dur[%lud] pos[%lud] pos_msec[%"G_GUINT64_FORMAT"]\n", dur_msec, position, pos_nsec);
7758 /* NOTE : store last seeking point to overcome some bad operation
7759 * ( returning zero when getting current position ) of some elements
7761 player->last_position = pos_nsec;
7763 /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
7764 if ( player->playback_rate > 1.0 )
7765 _mmplayer_set_playspeed ( (MMHandleType)player, player->playback_rate );
7768 return MM_ERROR_NONE;
7771 player->pending_seek.is_pending = TRUE;
7772 player->pending_seek.format = format;
7773 player->pending_seek.pos = position;
7775 debug_warning("player current-state : %s, pending-state : %s, just preserve pending position(%lu).\n",
7776 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)), MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)), player->pending_seek.pos);
7778 return MM_ERROR_NONE;
7781 debug_error("invalid arguments, position : %ld dur : %ld format : %d \n", position, dur_msec, format);
7782 return MM_ERROR_INVALID_ARGUMENT;
7785 player->doing_seek = FALSE;
7786 return MM_ERROR_PLAYER_SEEK;
7789 #define TRICKPLAY_OFFSET GST_MSECOND
7792 __gst_get_position(mm_player_t* player, int format, unsigned long* position) // @
7794 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7795 gint64 pos_msec = 0;
7796 gboolean ret = TRUE;
7798 return_val_if_fail( player && position && player->pipeline && player->pipeline->mainbin,
7799 MM_ERROR_PLAYER_NOT_INITIALIZED );
7801 current_state = MMPLAYER_CURRENT_STATE(player);
7803 /* NOTE : query position except paused state to overcome some bad operation
7804 * please refer to below comments in details
7806 if ( current_state != MM_PLAYER_STATE_PAUSED )
7808 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
7811 /* NOTE : get last point to overcome some bad operation of some elements
7812 * ( returning zero when getting current position in paused state
7813 * and when failed to get postion during seeking
7815 if ( ( current_state == MM_PLAYER_STATE_PAUSED )
7817 //|| ( player->last_position != 0 && pos_msec == 0 ) )
7819 debug_log ("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS (pos_msec), ret, current_state);
7821 if(player->playback_rate < 0.0)
7822 pos_msec = player->last_position - TRICKPLAY_OFFSET;
7824 pos_msec = player->last_position;
7827 pos_msec = player->last_position;
7829 player->last_position = pos_msec;
7831 debug_log("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_msec));
7836 if (player->duration > 0 && pos_msec > player->duration) {
7837 pos_msec = player->duration;
7840 if (player->sound_focus.keep_last_pos) {
7841 debug_log("return last pos as stop by asm, %"GST_TIME_FORMAT, GST_TIME_ARGS(player->last_position));
7842 pos_msec = player->last_position;
7845 player->last_position = pos_msec;
7850 case MM_PLAYER_POS_FORMAT_TIME:
7851 *position = GST_TIME_AS_MSECONDS(pos_msec);
7854 case MM_PLAYER_POS_FORMAT_PERCENT:
7859 dur = player->duration / GST_SECOND;
7862 debug_log ("duration is [%d], so returning position 0\n",dur);
7867 pos = pos_msec / GST_SECOND;
7868 *position = pos * 100 / dur;
7873 return MM_ERROR_PLAYER_INTERNAL;
7876 return MM_ERROR_NONE;
7880 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
7882 #define STREAMING_IS_FINISHED 0
7883 #define BUFFERING_MAX_PER 100
7885 GstQuery *query = NULL;
7887 return_val_if_fail( player &&
7889 player->pipeline->mainbin,
7890 MM_ERROR_PLAYER_NOT_INITIALIZED );
7892 return_val_if_fail( start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT );
7894 if (!MMPLAYER_IS_HTTP_STREAMING ( player ))
7896 /* and rtsp is not ready yet. */
7897 debug_warning ( "it's only used for http streaming case.\n" );
7898 return MM_ERROR_NONE;
7906 case MM_PLAYER_POS_FORMAT_PERCENT :
7908 gint start_per = -1, stop_per = -1;
7909 gint64 buffered_total = 0;
7911 unsigned long position = 0;
7912 guint curr_size_bytes = 0;
7913 gint64 buffering_left = -1;
7914 gint buffered_sec = -1;
7916 gint64 content_duration = player->duration;
7917 guint64 content_size = player->http_content_size;
7919 if (content_duration > 0)
7921 if (!__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position))
7923 debug_log ("[Time] pos %d ms / dur %d sec / %lld bytes", position, (guint)(content_duration/GST_SECOND), content_size);
7924 start_per = 100 * (position*GST_MSECOND) / content_duration;
7926 /* buffered size info from multiqueue */
7927 if (player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst)
7929 g_object_get(G_OBJECT(player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst), "curr-size-bytes", &curr_size_bytes, NULL);
7930 debug_log ("[MQ] curr_size_bytes = %d", curr_size_bytes);
7932 buffered_total += curr_size_bytes;
7935 /* buffered size info from queue2 */
7936 if (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)
7938 query = gst_query_new_buffering ( GST_FORMAT_BYTES );
7939 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query))
7941 GstBufferingMode mode;
7942 gint byte_in_rate = 0, byte_out_rate = 0;
7943 gint64 start_byte = 0, stop_byte = 0;
7944 guint num_of_ranges = 0;
7947 num_of_ranges = gst_query_get_n_buffering_ranges(query);
7948 for ( idx=0 ; idx<num_of_ranges ; idx++ )
7950 gst_query_parse_nth_buffering_range (query, idx, &start_byte, &stop_byte);
7951 debug_log ("[Q2][range %d] %lld ~ %lld\n", idx, start_byte, stop_byte);
7953 buffered_total += (stop_byte - start_byte);
7956 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, &buffering_left);
7957 debug_log ("[Q2] in_rate %d, out_rate %d, left %lld\n", byte_in_rate, byte_out_rate, buffering_left);
7959 gst_query_unref (query);
7962 if (buffering_left == STREAMING_IS_FINISHED)
7964 stop_per = BUFFERING_MAX_PER;
7968 guint dur_sec = (guint)(content_duration/GST_SECOND);
7969 guint avg_byterate = (dur_sec>0)?((guint)(content_size/dur_sec)):(0);
7971 if (avg_byterate > 0)
7972 buffered_sec = (gint)(buffered_total/avg_byterate);
7973 else if (player->total_maximum_bitrate > 0)
7974 buffered_sec = (gint)(GET_BIT_FROM_BYTE(buffered_total)/(gint64)player->total_maximum_bitrate);
7975 else if (player->total_bitrate > 0)
7976 buffered_sec = (gint)(GET_BIT_FROM_BYTE(buffered_total)/(gint64)player->total_bitrate);
7978 if ((buffered_sec >= 0) && (dur_sec > 0))
7979 stop_per = start_per + (100 * buffered_sec / dur_sec);
7982 debug_log ("[Buffered Total] %lld bytes, %d sec, per %d~%d\n", buffered_total, buffered_sec, start_per, stop_per);
7986 if (((buffered_total == 0) || (start_per < 0) || (stop_per < 0)) &&
7987 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst))
7989 query = gst_query_new_buffering ( GST_FORMAT_PERCENT );
7990 if ( gst_element_query ( player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query ) )
7993 gint64 range_start_per = -1, range_stop_per = -1;
7995 gst_query_parse_buffering_range ( query, &format, &range_start_per, &range_stop_per, NULL );
7997 debug_log ("[Q2] range start %" G_GINT64_FORMAT " ~ stop %" G_GINT64_FORMAT "\n", range_start_per , range_stop_per);
7999 if (range_start_per != -1)
8000 start_per = (gint)(100 * range_start_per / GST_FORMAT_PERCENT_MAX);
8002 if (range_stop_per != -1)
8003 stop_per = (gint)(100 * range_stop_per / GST_FORMAT_PERCENT_MAX);
8005 gst_query_unref (query);
8009 *start_pos = (start_per < 100)?(start_per):(100);
8014 *stop_pos = (stop_per < 100)?(stop_per):(100);
8020 case MM_PLAYER_POS_FORMAT_TIME :
8021 debug_warning ( "Time format is not supported yet.\n" );
8028 debug_log("current buffer position : %lu~%lu \n", *start_pos, *stop_pos );
8030 return MM_ERROR_NONE;
8034 __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param) // @
8040 debug_warning("set_message_callback is called with invalid player handle\n");
8041 return MM_ERROR_PLAYER_NOT_INITIALIZED;
8044 player->msg_cb = callback;
8045 player->msg_cb_param = user_param;
8047 debug_log("msg_cb : %p msg_cb_param : %p\n", callback, user_param);
8051 return MM_ERROR_NONE;
8054 static int __mmfplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data) // @
8056 int ret = MM_ERROR_PLAYER_INVALID_URI;
8061 return_val_if_fail ( uri , FALSE);
8062 return_val_if_fail ( data , FALSE);
8063 return_val_if_fail ( ( strlen(uri) <= MM_MAX_URL_LEN ), FALSE );
8065 memset(data, 0, sizeof(MMPlayerParseProfile));
8067 if ((path = strstr(uri, "file://")))
8069 int file_stat = MM_ERROR_NONE;
8071 file_stat = util_exist_file_path(path + 7);
8073 if (file_stat == MM_ERROR_NONE)
8075 strncpy(data->uri, path, MM_MAX_URL_LEN-1);
8077 if ( util_is_sdp_file ( path ) )
8079 debug_log("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
8080 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8084 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8086 ret = MM_ERROR_NONE;
8088 else if (file_stat == MM_ERROR_PLAYER_PERMISSION_DENIED)
8090 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8094 debug_warning("could access %s.\n", path);
8097 else if ((path = strstr(uri, "es_buff://")))
8101 strcpy(data->uri, uri);
8102 data->uri_type = MM_PLAYER_URI_TYPE_ES_BUFF;
8103 ret = MM_ERROR_NONE;
8106 else if ((path = strstr(uri, "buff://")))
8108 data->uri_type = MM_PLAYER_URI_TYPE_BUFF;
8109 ret = MM_ERROR_NONE;
8111 else if ((path = strstr(uri, "rtsp://")))
8114 if((path = strstr(uri, "/wfd1.0/"))) {
8115 strcpy(data->uri, uri);
8116 data->uri_type = MM_PLAYER_URI_TYPE_URL_WFD;
8117 ret = MM_ERROR_NONE;
8118 debug_log("uri is actually a wfd client path. giving it to wfdrtspsrc\n");
8121 strcpy(data->uri, uri);
8122 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8123 ret = MM_ERROR_NONE;
8127 else if ((path = strstr(uri, "http://")))
8130 strcpy(data->uri, uri);
8131 #ifdef MM_SMOOTH_STREAMING
8132 if (g_str_has_suffix (g_ascii_strdown(uri, strlen(uri)), ".ism/manifest") ||
8133 g_str_has_suffix (g_ascii_strdown(uri, strlen(uri)), ".isml/manifest"))
8135 data->uri_type = MM_PLAYER_URI_TYPE_SS;
8139 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
8141 ret = MM_ERROR_NONE;
8144 else if ((path = strstr(uri, "https://")))
8147 strcpy(data->uri, uri);
8148 #ifdef MM_SMOOTH_STREAMING
8149 if (g_str_has_suffix (g_ascii_strdown(uri, strlen(uri)), ".ism/manifest") ||
8150 g_str_has_suffix (g_ascii_strdown(uri, strlen(uri)), ".isml/manifest"))
8152 data->uri_type = MM_PLAYER_URI_TYPE_SS;
8155 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
8157 ret = MM_ERROR_NONE;
8160 else if ((path = strstr(uri, "rtspu://")))
8163 strcpy(data->uri, uri);
8164 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8165 ret = MM_ERROR_NONE;
8168 else if ((path = strstr(uri, "rtspr://")))
8170 strcpy(data->uri, path);
8171 char *separater =strstr(path, "*");
8175 char *urgent = separater + strlen("*");
8177 if ((urgent_len = strlen(urgent))) {
8178 data->uri[strlen(path) - urgent_len - strlen("*")] = '\0';
8179 strcpy(data->urgent, urgent);
8180 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8181 ret = MM_ERROR_NONE;
8185 else if ((path = strstr(uri, "mms://")))
8188 strcpy(data->uri, uri);
8189 data->uri_type = MM_PLAYER_URI_TYPE_URL_MMS;
8190 ret = MM_ERROR_NONE;
8193 else if ((path = strstr(uri, "mem://")))
8197 char *buffer = NULL;
8198 char *seperator = strchr(path, ',');
8199 char ext[100] = {0,}, size[100] = {0,};
8202 if ((buffer = strstr(path, "ext="))) {
8203 buffer += strlen("ext=");
8205 if (strlen(buffer)) {
8206 strcpy(ext, buffer);
8208 if ((seperator = strchr(ext, ','))
8209 || (seperator = strchr(ext, ' '))
8210 || (seperator = strchr(ext, '\0'))) {
8211 seperator[0] = '\0';
8216 if ((buffer = strstr(path, "size="))) {
8217 buffer += strlen("size=");
8219 if (strlen(buffer) > 0) {
8220 strcpy(size, buffer);
8222 if ((seperator = strchr(size, ','))
8223 || (seperator = strchr(size, ' '))
8224 || (seperator = strchr(size, '\0'))) {
8225 seperator[0] = '\0';
8228 mem_size = atoi(size);
8233 debug_log("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
8234 if ( mem_size && param)
8237 data->mem_size = mem_size;
8238 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
8239 ret = MM_ERROR_NONE;
8245 int file_stat = MM_ERROR_NONE;
8247 file_stat = util_exist_file_path(uri);
8249 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8250 if (file_stat == MM_ERROR_NONE)
8252 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", uri);
8254 if ( util_is_sdp_file( (char*)uri ) )
8256 debug_log("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
8257 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8261 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8263 ret = MM_ERROR_NONE;
8265 else if (file_stat == MM_ERROR_PLAYER_PERMISSION_DENIED)
8267 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8271 debug_error ("invalid uri, could not play..\n");
8272 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8276 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE) {
8277 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
8278 } else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION){
8279 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
8282 /* dump parse result */
8283 secure_debug_warning("incomming uri : %s\n", uri);
8284 debug_log("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n",
8285 data->uri_type, data->mem, data->mem_size, data->urgent);
8292 gboolean _asm_postmsg(gpointer *data)
8294 mm_player_t* player = (mm_player_t*)data;
8295 MMMessageParamType msg = {0, };
8298 return_val_if_fail ( player, FALSE );
8299 debug_warning("get notified");
8301 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
8302 (player->cmd == MMPLAYER_COMMAND_UNREALIZE))
8304 debug_warning("dispatched");
8309 msg.union_type = MM_MSG_UNION_CODE;
8310 msg.code = player->sound_focus.focus_changed_msg;
8312 #if 0 // should remove
8313 if (player->sm.event_src == ASM_EVENT_SOURCE_RESUMABLE_CANCELED)
8315 /* fill the message with state of player */
8316 msg.state.current = MMPLAYER_CURRENT_STATE(player);
8317 MMPLAYER_POST_MSG( player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
8318 player->resumable_cancel_id = 0;
8323 MMPLAYER_POST_MSG( player, MM_MESSAGE_READY_TO_RESUME, &msg);
8324 player->resume_event_id = 0;
8327 debug_warning("dispatched");
8331 gboolean _asm_lazy_pause(gpointer *data)
8333 mm_player_t* player = (mm_player_t*)data;
8334 int ret = MM_ERROR_NONE;
8338 return_val_if_fail ( player, FALSE );
8340 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING)
8342 debug_log ("Ready to proceed lazy pause\n");
8343 ret = _mmplayer_pause((MMHandleType)player);
8344 if(MM_ERROR_NONE != ret)
8346 debug_error("MMPlayer pause failed in ASM callback lazy pause\n");
8351 debug_log ("Invalid state to proceed lazy pause\n");
8355 if (player->pipeline && player->pipeline->audiobin)
8356 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", 0, NULL);
8358 player->sound_focus.by_asm_cb = FALSE; //should be reset here
8366 __mmplayer_can_do_interrupt(mm_player_t *player)
8368 if (!player || !player->pipeline || !player->attrs)
8370 debug_warning("not initialized");
8374 if ((player->sound_focus.exit_cb) || (player->set_mode.pcm_extraction))
8376 debug_warning("leave from asm cb right now, %d, %d", player->sound_focus.exit_cb, player->set_mode.pcm_extraction);
8380 /* check if seeking */
8381 if (player->doing_seek)
8383 MMMessageParamType msg_param;
8384 memset (&msg_param, 0, sizeof(MMMessageParamType));
8385 msg_param.code = MM_ERROR_PLAYER_SEEK;
8386 player->doing_seek = FALSE;
8387 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8391 /* check other thread */
8392 if (!g_mutex_trylock(&player->cmd_lock))
8394 debug_warning("locked already, cmd state : %d", player->cmd);
8396 /* check application command */
8397 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)
8399 debug_warning("playing.. should wait cmd lock then, will be interrupted");
8400 g_mutex_lock(&player->cmd_lock);
8403 debug_warning("nothing to do");
8408 debug_warning("can interrupt immediately");
8419 /* if you want to enable USE_ASM, please check the history get the ASM cb code. */
8421 __mmplayer_convert_sound_focus_state(gboolean acquire, const char *reason_for_change, MMPlayerFocusChangedMsg *msg)
8423 int ret = MM_ERROR_NONE;
8424 MMPlayerFocusChangedMsg focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_UNKNOWN;
8426 if (strstr(reason_for_change, "alarm")) {
8427 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_ALARM;
8429 } else if (strstr(reason_for_change, "notification")) {
8430 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_NOTIFICATION;
8432 } else if (strstr(reason_for_change, "emergency")) {
8433 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_EMERGENCY;
8435 } else if (strstr(reason_for_change, "call-voice") ||
8436 strstr(reason_for_change, "call-video") ||
8437 strstr(reason_for_change, "voip") ||
8438 strstr(reason_for_change, "ringtone-voip") ||
8439 strstr(reason_for_change, "ringtone-call")) {
8440 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_CALL;
8442 } else if (strstr(reason_for_change, "media") ||
8443 strstr(reason_for_change, "radio") ||
8444 strstr(reason_for_change, "loopback") ||
8445 strstr(reason_for_change, "system") ||
8446 strstr(reason_for_change, "voice-information") ||
8447 strstr(reason_for_change, "voice-recognition")) {
8448 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_MEDIA;
8451 ret = MM_ERROR_INVALID_ARGUMENT;
8452 debug_warning("not supported reason(%s), err(0x%08x)", reason_for_change, ret);
8456 if (acquire && (focus_msg != MM_PLAYER_FOCUS_CHANGED_BY_MEDIA))
8459 focus_msg = MM_PLAYER_FOCUS_CHANGED_COMPLETED;
8462 debug_log("converted from reason(%s) to msg(%d)", reason_for_change, focus_msg);
8469 /* FIXME: will be updated with new funct */
8470 void __mmplayer_sound_focus_watch_callback(int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e focus_state,
8471 const char *reason_for_change, const char *additional_info, void *user_data)
8473 mm_player_t* player = (mm_player_t*) user_data;
8474 int result = MM_ERROR_NONE;
8475 MMPlayerFocusChangedMsg msg = MM_PLAYER_FOCUS_CHANGED_BY_UNKNOWN;
8477 debug_warning("focus watch notified");
8479 if (!__mmplayer_can_do_interrupt(player))
8481 debug_warning("no need to interrupt, so leave");
8485 if (player->sound_focus.session_flags & MM_SESSION_OPTION_UNINTERRUPTIBLE)
8487 debug_warning("flags is UNINTERRUPTIBLE. do nothing.");
8491 debug_warning("watch: state: %d, focus_type : %d, reason_for_change : %s",
8492 focus_state, focus_type, (reason_for_change?reason_for_change:"N/A"));
8494 player->sound_focus.cb_pending = TRUE;
8495 player->sound_focus.by_asm_cb = TRUE;
8497 if (focus_state == FOCUS_IS_ACQUIRED)
8499 debug_warning("watch: FOCUS_IS_ACQUIRED");
8500 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(FALSE, reason_for_change, &msg))
8502 player->sound_focus.focus_changed_msg = (int)msg;
8505 if (strstr(reason_for_change, "call") ||
8506 strstr(reason_for_change, "voip") || /* FIXME: to check */
8507 strstr(reason_for_change, "alarm") ||
8508 strstr(reason_for_change, "media"))
8510 if (!MMPLAYER_IS_RTSP_STREAMING(player))
8512 // hold 0.7 second to excute "fadedown mute" effect
8513 debug_warning ("do fade down->pause->undo fade down");
8515 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
8517 result = _mmplayer_pause((MMHandleType)player);
8518 if (result != MM_ERROR_NONE)
8520 debug_warning("fail to set Pause state by asm");
8523 __mmplayer_undo_sound_fadedown(player);
8527 /* rtsp should connect again in specific network becasue tcp session can't be kept any more */
8528 _mmplayer_unrealize((MMHandleType)player);
8533 debug_warning ("pause immediately");
8534 result = _mmplayer_pause((MMHandleType)player);
8535 if (result != MM_ERROR_NONE)
8537 debug_warning("fail to set Pause state by asm");
8542 else if (focus_state == FOCUS_IS_RELEASED)
8544 debug_warning("FOCUS_IS_RELEASED: Got msg from asm to resume");
8545 player->sound_focus.antishock = TRUE;
8546 player->sound_focus.by_asm_cb = FALSE;
8548 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(TRUE, reason_for_change, &msg))
8550 player->sound_focus.focus_changed_msg = (int)msg;
8553 //ASM server is single thread daemon. So use g_idle_add() to post resume msg
8554 player->resume_event_id = g_idle_add((GSourceFunc)_asm_postmsg, (gpointer)player);
8559 debug_warning("unknown focus state %d", focus_state);
8563 player->sound_focus.by_asm_cb = FALSE;
8564 player->sound_focus.cb_pending = FALSE;
8565 MMPLAYER_CMD_UNLOCK( player );
8568 debug_warning("dispatched");
8573 __mmplayer_sound_focus_callback(int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e focus_state,
8574 const char *reason_for_change, const char *additional_info, void *user_data)
8576 mm_player_t* player = (mm_player_t*) user_data;
8577 int result = MM_ERROR_NONE;
8578 gboolean lazy_pause = FALSE;
8579 MMPlayerFocusChangedMsg msg = MM_PLAYER_FOCUS_CHANGED_BY_UNKNOWN;
8581 debug_warning("get focus notified");
8583 if (!__mmplayer_can_do_interrupt(player))
8585 debug_warning("no need to interrupt, so leave");
8589 if (player->sound_focus.session_flags & MM_SESSION_OPTION_UNINTERRUPTIBLE)
8591 debug_warning("flags is UNINTERRUPTIBLE. do nothing.");
8595 debug_warning("state: %d, focus_type : %d, reason_for_change : %s",
8596 focus_state, focus_type, (reason_for_change?reason_for_change:"N/A"));
8598 player->sound_focus.cb_pending = TRUE;
8599 player->sound_focus.by_asm_cb = TRUE;
8600 // player->sound_focus.event_src = event_src;
8603 /* first, check event source */
8604 if(event_src == ASM_EVENT_SOURCE_EARJACK_UNPLUG)
8606 int stop_by_asm = 0;
8607 mm_attrs_get_int_by_name(player->attrs, "sound_stop_when_unplugged", &stop_by_asm);
8611 else if (event_src == ASM_EVENT_SOURCE_RESOURCE_CONFLICT)
8613 /* can use video overlay simultaneously */
8614 /* video resource conflict */
8615 if(player->pipeline->videobin)
8617 debug_log("video conflict but, can support multiple video");
8618 result = _mmplayer_pause((MMHandleType)player);
8619 cb_res = ASM_CB_RES_PAUSE;
8621 else if (player->pipeline->audiobin)
8623 debug_log("audio resource conflict");
8624 result = _mmplayer_pause((MMHandleType)player);
8625 if (result != MM_ERROR_NONE)
8627 debug_warning("fail to set pause by asm");
8629 cb_res = ASM_CB_RES_PAUSE;
8633 #if 0 // should remove
8634 else if (event_src == ASM_EVENT_SOURCE_RESUMABLE_CANCELED)
8636 debug_warning("Got msg from asm for resumable canceled.\n");
8637 player->sound_focus.antishock = TRUE;
8638 player->sound_focus.by_asm_cb = FALSE;
8640 player->resumable_cancel_id = g_idle_add((GSourceFunc)_asm_postmsg, (gpointer)player);
8641 cb_res = ASM_CB_RES_IGNORE;
8647 if (focus_state == FOCUS_IS_RELEASED)
8649 debug_warning("FOCUS_IS_RELEASED");
8651 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(FALSE, reason_for_change, &msg))
8653 player->sound_focus.focus_changed_msg = (int)msg;
8656 if (strstr(reason_for_change, "call") ||
8657 strstr(reason_for_change, "voip") || /* FIXME: to check */
8658 strstr(reason_for_change, "alarm") ||
8659 strstr(reason_for_change, "media"))
8661 if (!MMPLAYER_IS_RTSP_STREAMING(player))
8663 //hold 0.7 second to excute "fadedown mute" effect
8664 debug_warning ("do fade down->pause->undo fade down");
8666 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
8668 result = _mmplayer_pause((MMHandleType)player);
8669 if (result != MM_ERROR_NONE)
8671 debug_warning("fail to set Pause state by asm");
8674 __mmplayer_undo_sound_fadedown(player);
8678 /* rtsp should connect again in specific network becasue tcp session can't be kept any more */
8679 _mmplayer_unrealize((MMHandleType)player);
8683 #ifdef USE_LAZY_PAUSE // if enabled, should consider event id and context when removed
8684 else if(event_src == ASM_EVENT_SOURCE_OTHER_PLAYER_APP)
8686 lazy_pause = TRUE; // return as soon as possible, for fast start of other app
8688 if ( player->pipeline->audiobin && player->pipeline->audiobin[MMPLAYER_A_SINK].gst )
8689 g_object_set( player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "mute", 2, NULL);
8691 player->lazy_pause_event_id = g_timeout_add(LAZY_PAUSE_TIMEOUT_MSEC, (GSourceFunc)_asm_lazy_pause, (gpointer)player);
8692 debug_warning ("set lazy pause timer (id=[%d], timeout=[%d ms])", player->lazy_pause_event_id, LAZY_PAUSE_TIMEOUT_MSEC);
8698 debug_warning ("pause immediately");
8699 result = _mmplayer_pause((MMHandleType)player);
8700 if (result != MM_ERROR_NONE)
8702 debug_warning("fail to set Pause state by asm");
8707 else if (focus_state == FOCUS_IS_ACQUIRED)
8709 debug_warning("FOCUS_IS_ACQUIRED: Got msg from asm to resume");
8710 player->sound_focus.antishock = TRUE;
8711 player->sound_focus.by_asm_cb = FALSE;
8713 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(TRUE, reason_for_change, &msg))
8715 player->sound_focus.focus_changed_msg = (int)msg;
8718 //ASM server is single thread daemon. So use g_idle_add() to post resume msg
8719 player->resume_event_id = g_idle_add((GSourceFunc)_asm_postmsg, (gpointer)player);
8724 debug_warning("unknown focus state %d", focus_state);
8730 player->sound_focus.by_asm_cb = FALSE;
8732 player->sound_focus.cb_pending = FALSE;
8733 MMPLAYER_CMD_UNLOCK( player );
8736 debug_warning("dispatched");
8742 _mmplayer_create_player(MMHandleType handle) // @
8744 mm_player_t* player = MM_PLAYER_CAST(handle);
8748 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
8750 /* initialize player state */
8751 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
8752 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
8753 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
8754 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
8756 /* check current state */
8757 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL ( player, MMPLAYER_COMMAND_CREATE );
8759 /* construct attributes */
8760 player->attrs = _mmplayer_construct_attribute(handle);
8762 if ( !player->attrs )
8764 debug_error("Failed to construct attributes\n");
8768 /* initialize gstreamer with configured parameter */
8769 if ( ! __mmplayer_init_gstreamer(player) )
8771 debug_error("Initializing gstreamer failed\n");
8775 /* initialize factories if not using decodebin */
8776 if( player->factories == NULL )
8777 __mmplayer_init_factories(player);
8779 /* create lock. note that g_tread_init() has already called in gst_init() */
8780 g_mutex_init(&player->fsink_lock);
8782 /* create repeat mutex */
8783 g_mutex_init(&player->repeat_thread_mutex);
8785 /* create repeat cond */
8786 g_cond_init(&player->repeat_thread_cond);
8788 /* create repeat thread */
8789 player->repeat_thread =
8790 g_thread_try_new ("repeat_thread", __mmplayer_repeat_thread, (gpointer)player, NULL);
8793 /* create next play mutex */
8794 g_mutex_init(&player->next_play_thread_mutex);
8796 /* create next play cond */
8797 g_cond_init(&player->next_play_thread_cond);
8799 /* create next play thread */
8800 player->next_play_thread =
8801 g_thread_try_new ("next_play_thread", __mmplayer_next_play_thread, (gpointer)player, NULL);
8802 if ( ! player->next_play_thread )
8804 debug_error("failed to create next play thread");
8808 if ( MM_ERROR_NONE != _mmplayer_initialize_video_capture(player))
8810 debug_error("failed to initialize video capture\n");
8814 /* register to asm */
8815 if ( MM_ERROR_NONE != _mmplayer_sound_register(&player->sound_focus,
8816 (mm_sound_focus_changed_cb)__mmplayer_sound_focus_callback,
8817 (mm_sound_focus_changed_watch_cb)__mmplayer_sound_focus_watch_callback,
8821 /* NOTE : we are dealing it as an error since we cannot expect it's behavior */
8822 debug_error("failed to register asm server\n");
8823 return MM_ERROR_POLICY_INTERNAL;
8825 #if 0 //need to change and test
8826 /* to add active device callback */
8827 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))
8829 debug_error("failed mm_sound_add_device_information_changed_callback \n");
8832 if (MMPLAYER_IS_HTTP_PD(player))
8834 player->pd_downloader = NULL;
8835 player->pd_file_save_path = NULL;
8838 player->streaming_type = STREAMING_SERVICE_NONE;
8840 /* give default value of audio effect setting */
8841 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
8842 player->playback_rate = DEFAULT_PLAYBACK_RATE;
8844 player->play_subtitle = FALSE;
8845 player->use_textoverlay = FALSE;
8846 player->play_count = 0;
8847 player->use_decodebin = TRUE;
8848 player->ignore_asyncdone = FALSE;
8849 player->use_deinterleave = FALSE;
8850 player->max_audio_channels = 0;
8851 player->video_share_api_delta = 0;
8852 player->video_share_clock_delta = 0;
8853 player->has_closed_caption = FALSE;
8855 __mmplayer_post_proc_reset(player);
8857 if (player->ini.dump_element_keyword[0][0] == '\0')
8859 player->ini.set_dump_element_flag= FALSE;
8863 player->ini.set_dump_element_flag = TRUE;
8866 /* set player state to null */
8867 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8868 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_NULL );
8870 return MM_ERROR_NONE;
8874 g_mutex_clear(&player->fsink_lock );
8877 if ( player->repeat_thread )
8879 player->repeat_thread_exit = TRUE;
8880 g_cond_signal( &player->repeat_thread_cond );
8882 g_thread_join( player->repeat_thread );
8883 player->repeat_thread = NULL;
8885 g_mutex_clear(&player->repeat_thread_mutex );
8887 g_cond_clear (&player->repeat_thread_cond );
8889 /* clear repeat thread mutex/cond if still alive
8890 * this can happen if only thread creating has failed
8892 g_mutex_clear(&player->repeat_thread_mutex );
8893 g_cond_clear ( &player->repeat_thread_cond );
8895 /* free next play thread */
8896 if ( player->next_play_thread )
8898 player->next_play_thread_exit = TRUE;
8899 g_cond_signal( &player->next_play_thread_cond );
8901 g_thread_join( player->next_play_thread );
8902 player->next_play_thread = NULL;
8904 g_mutex_clear(&player->next_play_thread_mutex );
8906 g_cond_clear ( &player->next_play_thread_cond );
8908 /* clear next play thread mutex/cond if still alive
8909 * this can happen if only thread creating has failed
8911 g_mutex_clear(&player->next_play_thread_mutex );
8913 g_cond_clear ( &player->next_play_thread_cond );
8915 /* release attributes */
8916 _mmplayer_deconstruct_attribute(handle);
8920 return MM_ERROR_PLAYER_INTERNAL;
8924 __mmplayer_init_gstreamer(mm_player_t* player) // @
8926 static gboolean initialized = FALSE;
8927 static const int max_argc = 50;
8929 gchar** argv = NULL;
8930 gchar** argv2 = NULL;
8937 debug_log("gstreamer already initialized.\n");
8942 argc = malloc( sizeof(int) );
8943 argv = malloc( sizeof(gchar*) * max_argc );
8944 argv2 = malloc( sizeof(gchar*) * max_argc );
8946 if ( !argc || !argv || !argv2)
8949 memset( argv, 0, sizeof(gchar*) * max_argc );
8950 memset( argv2, 0, sizeof(gchar*) * max_argc );
8954 argv[0] = g_strdup( "mmplayer" );
8957 for ( i = 0; i < 5; i++ ) /* FIXIT : num of param is now fixed to 5. make it dynamic */
8959 if ( strlen( player->ini.gst_param[i] ) > 0 )
8961 argv[*argc] = g_strdup( player->ini.gst_param[i] );
8966 /* we would not do fork for scanning plugins */
8967 argv[*argc] = g_strdup("--gst-disable-registry-fork");
8970 /* check disable registry scan */
8971 if ( player->ini.skip_rescan )
8973 argv[*argc] = g_strdup("--gst-disable-registry-update");
8977 /* check disable segtrap */
8978 if ( player->ini.disable_segtrap )
8980 argv[*argc] = g_strdup("--gst-disable-segtrap");
8984 debug_log("initializing gstreamer with following parameter\n");
8985 debug_log("argc : %d\n", *argc);
8988 for ( i = 0; i < arg_count; i++ )
8991 debug_log("argv[%d] : %s\n", i, argv2[i]);
8995 /* initializing gstreamer */
8996 if ( ! gst_init_check (argc, &argv, &err))
8998 debug_error("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
9007 for ( i = 0; i < arg_count; i++ )
9009 //debug_log("release - argv[%d] : %s\n", i, argv2[i]);
9010 MMPLAYER_FREEIF( argv2[i] );
9013 MMPLAYER_FREEIF( argv );
9014 MMPLAYER_FREEIF( argv2 );
9015 MMPLAYER_FREEIF( argc );
9025 for ( i = 0; i < arg_count; i++ )
9027 debug_log("free[%d] : %s\n", i, argv2[i]);
9028 MMPLAYER_FREEIF( argv2[i] );
9031 MMPLAYER_FREEIF( argv );
9032 MMPLAYER_FREEIF( argv2 );
9033 MMPLAYER_FREEIF( argc );
9039 __mmplayer_destroy_streaming_ext(mm_player_t* player)
9041 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9043 if (player->pd_downloader)
9045 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
9046 MMPLAYER_FREEIF(player->pd_downloader);
9049 if (MMPLAYER_IS_HTTP_PD(player))
9051 _mmplayer_destroy_pd_downloader((MMHandleType)player);
9052 MMPLAYER_FREEIF(player->pd_file_save_path);
9055 return MM_ERROR_NONE;
9059 _mmplayer_destroy(MMHandleType handle) // @
9061 mm_player_t* player = MM_PLAYER_CAST(handle);
9065 /* check player handle */
9066 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9068 /* destroy can called at anytime */
9069 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL ( player, MMPLAYER_COMMAND_DESTROY );
9071 __mmplayer_destroy_streaming_ext(player);
9073 /* release repeat thread */
9074 if ( player->repeat_thread )
9076 player->repeat_thread_exit = TRUE;
9077 g_cond_signal( &player->repeat_thread_cond );
9079 debug_log("waitting for repeat thread exit\n");
9080 g_thread_join ( player->repeat_thread );
9081 g_mutex_clear(&player->repeat_thread_mutex );
9082 g_cond_clear (&player->repeat_thread_cond );
9083 debug_log("repeat thread released\n");
9086 /* release next play thread */
9087 if ( player->next_play_thread )
9089 player->next_play_thread_exit = TRUE;
9090 g_cond_signal( &player->next_play_thread_cond );
9092 debug_log("waitting for next play thread exit\n");
9093 g_thread_join ( player->next_play_thread );
9094 g_mutex_clear(&player->next_play_thread_mutex );
9095 g_cond_clear(&player->next_play_thread_cond );
9096 debug_log("next play thread released\n");
9099 _mmplayer_release_video_capture(player);
9101 /* flush any pending asm_cb */
9102 if (player->sound_focus.cb_pending)
9104 /* set a flag for make sure asm_cb to be returned immediately */
9105 debug_warning("asm cb has pending state");
9106 player->sound_focus.exit_cb = TRUE;
9108 /* make sure to release any pending asm_cb which locked by cmd_lock */
9109 MMPLAYER_CMD_UNLOCK(player);
9111 MMPLAYER_CMD_LOCK(player);
9115 if ( MM_ERROR_NONE != _mmplayer_sound_unregister(&player->sound_focus) )
9117 debug_error("failed to deregister asm server\n");
9120 #ifdef USE_LAZY_PAUSE
9121 if (player->lazy_pause_event_id)
9123 __mmplayer_remove_g_source_from_context(player->context.global_default, player->lazy_pause_event_id);
9124 player->lazy_pause_event_id = 0;
9128 if (player->resume_event_id)
9130 g_source_remove (player->resume_event_id);
9131 player->resume_event_id = 0;
9134 if (player->resumable_cancel_id)
9136 g_source_remove (player->resumable_cancel_id);
9137 player->resumable_cancel_id = 0;
9140 /* release pipeline */
9141 if ( MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline( player ) )
9143 debug_error("failed to destory pipeline\n");
9144 return MM_ERROR_PLAYER_INTERNAL;
9147 if (player->is_external_subtitle_present && player->subtitle_language_list)
9149 g_list_free (player->subtitle_language_list);
9150 player->subtitle_language_list = NULL;
9153 __mmplayer_release_dump_list (player->dump_list);
9155 /* release miscellaneous information.
9156 these info needs to be released after pipeline is destroyed. */
9157 __mmplayer_release_misc_post( player );
9159 /* release attributes */
9160 _mmplayer_deconstruct_attribute( handle );
9162 /* release factories */
9163 __mmplayer_release_factories( player );
9166 g_mutex_clear(&player->fsink_lock );
9168 g_mutex_clear(&player->msg_cb_lock );
9172 return MM_ERROR_NONE;
9176 __mmplayer_realize_streaming_ext(mm_player_t* player)
9178 int ret = MM_ERROR_NONE;
9181 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9183 if (MMPLAYER_IS_HTTP_PD(player))
9185 gboolean bret = FALSE;
9187 player->pd_downloader = _mmplayer_create_pd_downloader();
9188 if ( !player->pd_downloader )
9190 debug_error ("Unable to create PD Downloader...");
9191 ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
9194 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
9198 debug_error ("Unable to create PD Downloader...");
9199 ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
9208 _mmplayer_realize(MMHandleType hplayer) // @
9210 mm_player_t* player = (mm_player_t*)hplayer;
9213 int application_pid = -1;
9214 gboolean update_registry = FALSE;
9215 MMHandleType attrs = 0;
9216 int ret = MM_ERROR_NONE;
9220 /* check player handle */
9221 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED )
9223 /* check current state */
9224 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_REALIZE );
9226 attrs = MMPLAYER_GET_ATTRS(player);
9229 debug_error("fail to get attributes.\n");
9230 return MM_ERROR_PLAYER_INTERNAL;
9233 mm_attrs_get_int_by_name(attrs, "sound_application_pid", &application_pid );
9234 player->sound_focus.pid = application_pid;
9236 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
9237 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
9239 ret = __mmfplayer_parse_profile((const char*)uri, param, &player->profile);
9241 if (ret != MM_ERROR_NONE)
9243 debug_error("failed to parse profile\n");
9247 /* FIXIT : we can use thouse in player->profile directly */
9248 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM)
9250 player->mem_buf.buf = (char *)player->profile.mem;
9251 player->mem_buf.len = player->profile.mem_size;
9252 player->mem_buf.offset = 0;
9255 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_ES_BUFF)
9257 if (strstr(uri, "es_buff://push_mode"))
9259 player->es_player_push_mode = TRUE;
9263 player->es_player_push_mode = FALSE;
9267 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS)
9269 debug_warning("mms protocol is not supported format.\n");
9270 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
9273 if (MMPLAYER_IS_STREAMING(player))
9274 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
9276 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
9278 player->smooth_streaming = FALSE;
9279 player->videodec_linked = 0;
9280 player->videosink_linked = 0;
9281 player->audiodec_linked = 0;
9282 player->audiosink_linked = 0;
9283 player->textsink_linked = 0;
9284 player->is_external_subtitle_present = FALSE;
9285 /* set the subtitle ON default */
9286 player->is_subtitle_off = FALSE;
9288 /* registry should be updated for downloadable codec */
9289 mm_attrs_get_int_by_name(attrs, "profile_update_registry", &update_registry);
9291 if ( update_registry )
9293 debug_log("updating registry...\n");
9294 gst_update_registry();
9296 /* then we have to rebuild factories */
9297 __mmplayer_release_factories( player );
9298 __mmplayer_init_factories(player);
9301 /* realize pipeline */
9302 ret = __gst_realize( player );
9303 if ( ret != MM_ERROR_NONE )
9305 debug_error("fail to realize the player.\n");
9309 ret = __mmplayer_realize_streaming_ext(player);
9318 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
9321 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9323 /* destroy can called at anytime */
9324 if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player))
9326 _mmplayer_unrealize_pd_downloader ((MMHandleType)player);
9327 MMPLAYER_FREEIF(player->pd_downloader);
9331 return MM_ERROR_NONE;
9335 _mmplayer_unrealize(MMHandleType hplayer)
9337 mm_player_t* player = (mm_player_t*)hplayer;
9338 int ret = MM_ERROR_NONE;
9342 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED )
9344 /* check current state */
9345 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_UNREALIZE );
9347 __mmplayer_unrealize_streaming_ext(player);
9349 /* unrealize pipeline */
9350 ret = __gst_unrealize( player );
9352 /* set asm stop if success */
9353 if (MM_ERROR_NONE == ret)
9355 ret = _mmplayer_sound_release_focus(&player->sound_focus);
9356 if ( ret != MM_ERROR_NONE )
9358 debug_error("failed to release sound focus\n");
9364 debug_error("failed and don't change asm state to stop");
9373 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param) // @
9375 mm_player_t* player = (mm_player_t*)hplayer;
9377 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9379 return __gst_set_message_callback(player, callback, user_param);
9383 _mmplayer_get_state(MMHandleType hplayer, int* state) // @
9385 mm_player_t *player = (mm_player_t*)hplayer;
9387 return_val_if_fail(state, MM_ERROR_INVALID_ARGUMENT);
9389 *state = MMPLAYER_CURRENT_STATE(player);
9391 return MM_ERROR_NONE;
9396 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume) // @
9398 mm_player_t* player = (mm_player_t*) hplayer;
9399 GstElement* vol_element = NULL;
9404 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9406 debug_log("volume [L]=%f:[R]=%f\n",
9407 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
9409 /* invalid factor range or not */
9410 for ( i = 0; i < MM_VOLUME_CHANNEL_NUM; i++ )
9412 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
9413 debug_error("Invalid factor! (valid factor:0~1.0)\n");
9414 return MM_ERROR_INVALID_ARGUMENT;
9418 /* not support to set other value into each channel */
9419 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
9420 return MM_ERROR_INVALID_ARGUMENT;
9422 /* Save volume to handle. Currently the first array element will be saved. */
9423 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
9425 /* check pipeline handle */
9426 if ( ! player->pipeline || ! player->pipeline->audiobin )
9428 debug_log("audiobin is not created yet\n");
9429 debug_log("but, current stored volume will be set when it's created.\n");
9431 /* NOTE : stored volume will be used in create_audiobin
9432 * returning MM_ERROR_NONE here makes application to able to
9433 * set volume at anytime.
9435 return MM_ERROR_NONE;
9438 /* setting volume to volume element */
9439 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
9443 debug_log("volume is set [%f]\n", player->sound.volume);
9444 g_object_set(vol_element, "volume", player->sound.volume, NULL);
9449 return MM_ERROR_NONE;
9454 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
9456 mm_player_t* player = (mm_player_t*) hplayer;
9461 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9462 return_val_if_fail( volume, MM_ERROR_INVALID_ARGUMENT );
9464 /* returning stored volume */
9465 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
9466 volume->level[i] = player->sound.volume;
9470 return MM_ERROR_NONE;
9476 _mmplayer_set_mute(MMHandleType hplayer, int mute) // @
9478 mm_player_t* player = (mm_player_t*) hplayer;
9479 GstElement* vol_element = NULL;
9483 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9485 /* mute value shoud 0 or 1 */
9486 if ( mute != 0 && mute != 1 )
9488 debug_error("bad mute value\n");
9490 /* FIXIT : definitly, we need _BAD_PARAM error code */
9491 return MM_ERROR_INVALID_ARGUMENT;
9494 player->sound.mute = mute;
9496 /* just hold mute value if pipeline is not ready */
9497 if ( !player->pipeline || !player->pipeline->audiobin )
9499 debug_log("pipeline is not ready. holding mute value\n");
9500 return MM_ERROR_NONE;
9503 vol_element = player->pipeline->audiobin[MMPLAYER_A_SINK].gst;
9505 /* NOTE : volume will only created when the bt is enabled */
9508 debug_log("mute : %d\n", mute);
9509 g_object_set(vol_element, "mute", mute, NULL);
9513 debug_log("volume elemnet is not created. using volume in audiosink\n");
9518 return MM_ERROR_NONE;
9522 _mmplayer_get_mute(MMHandleType hplayer, int* pmute) // @
9524 mm_player_t* player = (mm_player_t*) hplayer;
9528 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9529 return_val_if_fail ( pmute, MM_ERROR_INVALID_ARGUMENT );
9531 /* just hold mute value if pipeline is not ready */
9532 if ( !player->pipeline || !player->pipeline->audiobin )
9534 debug_log("pipeline is not ready. returning stored value\n");
9535 *pmute = player->sound.mute;
9536 return MM_ERROR_NONE;
9539 *pmute = player->sound.mute;
9543 return MM_ERROR_NONE;
9547 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
9549 mm_player_t* player = (mm_player_t*) hplayer;
9553 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9555 player->video_stream_changed_cb = callback;
9556 player->video_stream_changed_cb_user_param = user_param;
9557 debug_log("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
9561 return MM_ERROR_NONE;
9565 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
9567 mm_player_t* player = (mm_player_t*) hplayer;
9571 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9573 player->audio_stream_changed_cb = callback;
9574 player->audio_stream_changed_cb_user_param = user_param;
9575 debug_log("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
9579 return MM_ERROR_NONE;
9583 _mmplayer_set_audiostream_cb_ex(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback_ex callback, void *user_param) // @
9585 mm_player_t* player = (mm_player_t*) hplayer;
9589 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9591 player->audio_stream_render_cb_ex = callback;
9592 player->audio_stream_cb_user_param = user_param;
9593 player->audio_stream_sink_sync = sync;
9594 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);
9598 return MM_ERROR_NONE;
9602 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param) // @
9604 mm_player_t* player = (mm_player_t*) hplayer;
9608 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9610 player->video_stream_cb = callback;
9611 player->video_stream_cb_user_param = user_param;
9612 player->use_video_stream = TRUE;
9613 debug_log("Stream cb Handle value is %p : %p\n", player, player->video_stream_cb);
9617 return MM_ERROR_NONE;
9621 _mmplayer_set_audiostream_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param) // @
9623 mm_player_t* player = (mm_player_t*) hplayer;
9627 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9629 player->audio_stream_cb = callback;
9630 player->audio_stream_cb_user_param = user_param;
9631 debug_log("Audio Stream cb Handle value is %p : %p\n", player, player->audio_stream_cb);
9635 return MM_ERROR_NONE;
9640 _mmplayer_set_prepare_buffering_time(MMHandleType hplayer, int second)
9642 mm_player_t* player = (mm_player_t*) hplayer;
9646 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9648 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL)
9649 return MM_ERROR_PLAYER_INVALID_STATE;
9651 debug_log("pre buffer size : %d sec\n", second);
9655 debug_error("bad size value\n");
9656 return MM_ERROR_INVALID_ARGUMENT;
9659 if (player->streamer == NULL)
9661 player->streamer = __mm_player_streaming_create();
9662 __mm_player_streaming_initialize(player->streamer);
9665 player->streamer->buffering_req.initial_second = second;
9669 return MM_ERROR_NONE;
9674 _mmplayer_set_runtime_buffering_mode(MMHandleType hplayer, MMPlayerBufferingMode mode, int second)
9676 mm_player_t* player = (mm_player_t*) hplayer;
9680 return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9682 debug_log("mode %d\n", mode);
9684 if ((mode < 0) || (mode > MM_PLAYER_BUFFERING_MODE_MAX) ||
9685 ((mode == MM_PLAYER_BUFFERING_MODE_FIXED) && (second <= 0)))
9686 return MM_ERROR_INVALID_ARGUMENT;
9688 if (player->streamer == NULL)
9690 player->streamer = __mm_player_streaming_create();
9691 __mm_player_streaming_initialize(player->streamer);
9694 player->streamer->buffering_req.mode = mode;
9697 ((mode == MM_PLAYER_BUFFERING_MODE_FIXED) ||
9698 (mode == MM_PLAYER_BUFFERING_MODE_ADAPTIVE)))
9699 player->streamer->buffering_req.runtime_second = second;
9703 return MM_ERROR_NONE;
9707 _mmplayer_set_videoframe_render_error_cb(MMHandleType hplayer, mm_player_video_frame_render_error_callback callback, void *user_param) // @
9709 mm_player_t* player = (mm_player_t*) hplayer;
9713 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9714 return_val_if_fail ( callback, MM_ERROR_INVALID_ARGUMENT );
9716 player->video_frame_render_error_cb = callback;
9717 player->video_frame_render_error_cb_user_param = user_param;
9719 debug_log("Video frame render error cb Handle value is %p : %p\n", player, player->video_frame_render_error_cb);
9723 return MM_ERROR_NONE;
9727 __mmplayer_start_streaming_ext(mm_player_t *player)
9729 gint ret = MM_ERROR_NONE;
9732 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9734 if (MMPLAYER_IS_HTTP_PD(player))
9736 if ( !player->pd_downloader )
9738 ret = __mmplayer_realize_streaming_ext(player);
9740 if ( ret != MM_ERROR_NONE)
9742 debug_error ("failed to realize streaming ext\n");
9747 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI)
9749 ret = _mmplayer_start_pd_downloader ((MMHandleType)player);
9752 debug_error ("ERROR while starting PD...\n");
9753 return MM_ERROR_PLAYER_NOT_INITIALIZED;
9755 ret = MM_ERROR_NONE;
9764 _mmplayer_start(MMHandleType hplayer) // @
9766 mm_player_t* player = (mm_player_t*) hplayer;
9767 gint ret = MM_ERROR_NONE;
9771 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9773 /* check current state */
9774 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_START );
9776 ret = _mmplayer_sound_acquire_focus(&player->sound_focus);
9777 if ( ret != MM_ERROR_NONE )
9779 debug_error("failed to acquire sound focus.\n");
9783 /* NOTE : we should check and create pipeline again if not created as we destroy
9784 * whole pipeline when stopping in streamming playback
9786 if ( ! player->pipeline )
9788 ret = __gst_realize( player );
9789 if ( MM_ERROR_NONE != ret )
9791 debug_error("failed to realize before starting. only in streamming\n");
9797 ret = __mmplayer_start_streaming_ext(player);
9798 if ( ret != MM_ERROR_NONE )
9800 debug_error("failed to start streaming ext \n");
9803 /* start pipeline */
9804 ret = __gst_start( player );
9805 if ( ret != MM_ERROR_NONE )
9807 debug_error("failed to start player.\n");
9815 /* NOTE: post "not supported codec message" to application
9816 * when one codec is not found during AUTOPLUGGING in MSL.
9817 * So, it's separated with error of __mmplayer_gst_callback().
9818 * And, if any codec is not found, don't send message here.
9819 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
9822 __mmplayer_handle_missed_plugin(mm_player_t* player)
9824 MMMessageParamType msg_param;
9825 memset (&msg_param, 0, sizeof(MMMessageParamType));
9826 gboolean post_msg_direct = FALSE;
9830 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9832 debug_log("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
9833 player->not_supported_codec, player->can_support_codec);
9835 if( player->not_found_demuxer )
9837 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9838 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
9840 MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param );
9841 MMPLAYER_FREEIF(msg_param.data);
9843 return MM_ERROR_NONE;
9846 if (player->not_supported_codec)
9848 if ( player->can_support_codec ) // There is one codec to play
9850 post_msg_direct = TRUE;
9854 if ( player->pipeline->audiobin ) // Some content has only PCM data in container.
9855 post_msg_direct = TRUE;
9858 if ( post_msg_direct )
9860 MMMessageParamType msg_param;
9861 memset (&msg_param, 0, sizeof(MMMessageParamType));
9863 if ( player->not_supported_codec == MISSING_PLUGIN_AUDIO )
9865 debug_warning("not found AUDIO codec, posting error code to application.\n");
9867 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9868 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9870 else if ( player->not_supported_codec == MISSING_PLUGIN_VIDEO )
9872 debug_warning("not found VIDEO codec, posting error code to application.\n");
9874 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
9875 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
9878 MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param );
9880 MMPLAYER_FREEIF(msg_param.data);
9882 return MM_ERROR_NONE;
9884 else // no any supported codec case
9886 debug_warning("not found any codec, posting error code to application.\n");
9888 if ( player->not_supported_codec == MISSING_PLUGIN_AUDIO )
9890 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9891 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9895 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9896 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
9899 MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param );
9901 MMPLAYER_FREEIF(msg_param.data);
9907 return MM_ERROR_NONE;
9910 static void __mmplayer_check_pipeline(mm_player_t* player)
9912 GstState element_state = GST_STATE_VOID_PENDING;
9913 GstState element_pending_state = GST_STATE_VOID_PENDING;
9915 int ret = MM_ERROR_NONE;
9917 if (player->gapless.reconfigure)
9919 debug_warning("pipeline is under construction.\n");
9921 MMPLAYER_PLAYBACK_LOCK(player);
9922 MMPLAYER_PLAYBACK_UNLOCK(player);
9924 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT ( player );
9926 /* wait for state transition */
9927 ret = gst_element_get_state( player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND );
9929 if ( ret == GST_STATE_CHANGE_FAILURE )
9931 debug_error("failed to change pipeline state within %d sec\n", timeout );
9936 /* NOTE : it should be able to call 'stop' anytime*/
9938 _mmplayer_stop(MMHandleType hplayer) // @
9940 mm_player_t* player = (mm_player_t*)hplayer;
9941 int ret = MM_ERROR_NONE;
9945 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9947 /* check current state */
9948 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_STOP );
9950 /* check pipline building state */
9951 __mmplayer_check_pipeline(player);
9952 player->gapless.start_time = 0;
9954 /* NOTE : application should not wait for EOS after calling STOP */
9955 __mmplayer_cancel_eos_timer( player );
9957 __mmplayer_unrealize_streaming_ext(player);
9960 player->doing_seek = FALSE;
9963 ret = __gst_stop( player );
9965 if ( ret != MM_ERROR_NONE )
9967 debug_error("failed to stop player.\n");
9976 _mmplayer_pause(MMHandleType hplayer) // @
9978 mm_player_t* player = (mm_player_t*)hplayer;
9979 gint64 pos_msec = 0;
9980 gboolean async = FALSE;
9981 gint ret = MM_ERROR_NONE;
9985 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9987 /* check current state */
9988 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_PAUSE );
9990 /* check pipline building state */
9991 __mmplayer_check_pipeline(player);
9993 switch (MMPLAYER_CURRENT_STATE(player))
9995 case MM_PLAYER_STATE_READY:
9997 /* check prepare async or not.
9998 * In the case of streaming playback, it's recommned to avoid blocking wait.
10000 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
10001 debug_log("prepare working mode : %s", (async ? "async" : "sync"));
10005 case MM_PLAYER_STATE_PLAYING:
10007 /* NOTE : store current point to overcome some bad operation
10008 * ( returning zero when getting current position in paused state) of some
10011 if ( !gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec))
10012 debug_warning("getting current position failed in paused\n");
10014 player->last_position = pos_msec;
10019 /* pause pipeline */
10020 ret = __gst_pause( player, async );
10022 if ( ret != MM_ERROR_NONE )
10024 debug_error("failed to pause player. ret : 0x%x\n", ret);
10033 _mmplayer_resume(MMHandleType hplayer)
10035 mm_player_t* player = (mm_player_t*)hplayer;
10036 int ret = MM_ERROR_NONE;
10037 gboolean async = FALSE;
10041 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
10043 ret = _mmplayer_sound_acquire_focus(&player->sound_focus);
10044 if ( ret != MM_ERROR_NONE )
10046 debug_error("failed to acquire sound focus.\n");
10050 /* check current state */
10051 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_RESUME );
10053 ret = __gst_resume( player, async );
10055 if ( ret != MM_ERROR_NONE )
10057 debug_error("failed to resume player.\n");
10066 __mmplayer_set_play_count(mm_player_t* player, gint count)
10068 MMHandleType attrs = 0;
10072 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
10074 attrs = MMPLAYER_GET_ATTRS(player);
10077 debug_error("fail to get attributes.\n");
10078 return MM_ERROR_PLAYER_INTERNAL;
10081 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
10082 if ( mmf_attrs_commit ( attrs ) ) /* return -1 if error */
10083 debug_error("failed to commit\n");
10087 return MM_ERROR_NONE;
10091 _mmplayer_activate_section_repeat(MMHandleType hplayer, unsigned long start, unsigned long end)
10093 mm_player_t* player = (mm_player_t*)hplayer;
10094 gint64 start_pos = 0;
10095 gint64 end_pos = 0;
10096 gint infinity = -1;
10100 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
10101 return_val_if_fail ( end <= GST_TIME_AS_MSECONDS(player->duration), MM_ERROR_INVALID_ARGUMENT );
10103 player->section_repeat = TRUE;
10104 player->section_repeat_start = start;
10105 player->section_repeat_end = end;
10107 start_pos = player->section_repeat_start * G_GINT64_CONSTANT(1000000);
10108 end_pos = player->section_repeat_end * G_GINT64_CONSTANT(1000000);
10110 __mmplayer_set_play_count( player, infinity );
10112 if ( (!__gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
10113 player->playback_rate,
10115 ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ),
10116 GST_SEEK_TYPE_SET, start_pos,
10117 GST_SEEK_TYPE_SET, end_pos)))
10119 debug_error("failed to activate section repeat\n");
10121 return MM_ERROR_PLAYER_SEEK;
10124 debug_log("succeeded to set section repeat from %d to %d\n",
10125 player->section_repeat_start, player->section_repeat_end);
10129 return MM_ERROR_NONE;
10133 __mmplayer_set_pcm_extraction(mm_player_t* player)
10135 gint64 start_nsec = 0;
10136 gint64 end_nsec = 0;
10137 gint64 dur_nsec = 0;
10138 gint64 dur_msec = 0;
10139 int required_start = 0;
10140 int required_end = 0;
10145 return_val_if_fail( player, FALSE );
10147 mm_attrs_multiple_get(player->attrs,
10149 "pcm_extraction_start_msec", &required_start,
10150 "pcm_extraction_end_msec", &required_end,
10153 debug_log("pcm extraction required position is from [%d] to [%d] (msec)\n", required_start, required_end);
10155 if (required_start == 0 && required_end == 0)
10157 debug_log("extracting entire stream");
10158 return MM_ERROR_NONE;
10160 else if (required_start < 0 || required_start > required_end || required_end < 0 )
10162 debug_log("invalid range for pcm extraction");
10163 return MM_ERROR_INVALID_ARGUMENT;
10167 ret = gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec);
10170 debug_error("failed to get duration");
10171 return MM_ERROR_PLAYER_INTERNAL;
10173 dur_msec = GST_TIME_AS_MSECONDS(dur_nsec);
10175 if (dur_msec < required_end) // FIXME
10177 debug_log("invalid end pos for pcm extraction");
10178 return MM_ERROR_INVALID_ARGUMENT;
10181 start_nsec = required_start * G_GINT64_CONSTANT(1000000);
10182 end_nsec = required_end * G_GINT64_CONSTANT(1000000);
10184 if ( (!__gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
10187 ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ),
10188 GST_SEEK_TYPE_SET, start_nsec,
10189 GST_SEEK_TYPE_SET, end_nsec)))
10191 debug_error("failed to seek for pcm extraction\n");
10193 return MM_ERROR_PLAYER_SEEK;
10196 debug_log("succeeded to set up segment extraction from [%llu] to [%llu] (nsec)\n", start_nsec, end_nsec);
10200 return MM_ERROR_NONE;
10204 _mmplayer_deactivate_section_repeat(MMHandleType hplayer)
10206 mm_player_t* player = (mm_player_t*)hplayer;
10207 gint64 cur_pos = 0;
10212 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
10214 player->section_repeat = FALSE;
10216 __mmplayer_set_play_count( player, onetime );
10218 gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_pos);
10220 if ( (!__gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
10223 ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ),
10224 GST_SEEK_TYPE_SET, cur_pos,
10225 GST_SEEK_TYPE_SET, player->duration )))
10227 debug_error("failed to deactivate section repeat\n");
10229 return MM_ERROR_PLAYER_SEEK;
10234 return MM_ERROR_NONE;
10238 _mmplayer_set_playspeed(MMHandleType hplayer, float rate)
10240 mm_player_t* player = (mm_player_t*)hplayer;
10241 gint64 pos_msec = 0;
10242 int ret = MM_ERROR_NONE;
10244 signed long long start = 0, stop = 0;
10245 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
10248 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
10249 return_val_if_fail ( !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API );
10251 /* The sound of video is not supported under 0.0 and over 2.0. */
10252 if(rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN)
10254 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
10257 _mmplayer_set_mute(hplayer, mute);
10259 if (player->playback_rate == rate)
10260 return MM_ERROR_NONE;
10262 /* If the position is reached at start potion during fast backward, EOS is posted.
10263 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
10265 player->playback_rate = rate;
10267 current_state = MMPLAYER_CURRENT_STATE(player);
10269 if ( current_state != MM_PLAYER_STATE_PAUSED )
10270 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
10272 debug_log ("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS (pos_msec), ret, current_state);
10274 if ( ( current_state == MM_PLAYER_STATE_PAUSED )
10276 //|| ( player->last_position != 0 && pos_msec == 0 ) )
10278 debug_warning("returning last point : %lld\n", player->last_position );
10279 pos_msec = player->last_position;
10286 stop = GST_CLOCK_TIME_NONE;
10290 start = GST_CLOCK_TIME_NONE;
10293 if ((!gst_element_seek (player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
10296 ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ),
10297 GST_SEEK_TYPE_SET, start,
10298 GST_SEEK_TYPE_SET, stop)))
10300 debug_error("failed to set speed playback\n");
10301 return MM_ERROR_PLAYER_SEEK;
10304 debug_log("succeeded to set speed playback as %0.1f\n", rate);
10308 return MM_ERROR_NONE;;
10312 _mmplayer_set_position(MMHandleType hplayer, int format, int position) // @
10314 mm_player_t* player = (mm_player_t*)hplayer;
10315 int ret = MM_ERROR_NONE;
10319 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
10321 ret = __gst_set_position ( player, format, (unsigned long)position, FALSE );
10329 _mmplayer_get_position(MMHandleType hplayer, int format, unsigned long *position) // @
10331 mm_player_t* player = (mm_player_t*)hplayer;
10332 int ret = MM_ERROR_NONE;
10334 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
10336 ret = __gst_get_position ( player, format, position );
10342 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos) // @
10344 mm_player_t* player = (mm_player_t*)hplayer;
10345 int ret = MM_ERROR_NONE;
10347 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
10349 ret = __gst_get_buffer_position ( player, format, start_pos, stop_pos );
10355 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position) // @
10357 mm_player_t* player = (mm_player_t*)hplayer;
10358 int ret = MM_ERROR_NONE;
10362 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
10364 ret = __gst_adjust_subtitle_position(player, format, position);
10371 _mmplayer_adjust_video_postion(MMHandleType hplayer, int offset) // @
10373 mm_player_t* player = (mm_player_t*)hplayer;
10374 int ret = MM_ERROR_NONE;
10378 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
10380 ret = __gst_adjust_video_position(player, offset);
10388 __mmplayer_is_midi_type( gchar* str_caps)
10390 if ( ( g_strrstr(str_caps, "audio/midi") ) ||
10391 ( g_strrstr(str_caps, "application/x-gst_ff-mmf") ) ||
10392 ( g_strrstr(str_caps, "application/x-smaf") ) ||
10393 ( g_strrstr(str_caps, "audio/x-imelody") ) ||
10394 ( g_strrstr(str_caps, "audio/mobile-xmf") ) ||
10395 ( g_strrstr(str_caps, "audio/xmf") ) ||
10396 ( g_strrstr(str_caps, "audio/mxmf") ) )
10398 debug_log("midi\n");
10407 __mmplayer_is_only_mp3_type (gchar *str_caps)
10409 if (g_strrstr(str_caps, "application/x-id3") ||
10410 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
10418 __mmplayer_set_audio_attrs (mm_player_t* player, GstCaps* caps)
10420 GstStructure* caps_structure = NULL;
10421 gint samplerate = 0;
10425 return_if_fail (player && caps);
10427 caps_structure = gst_caps_get_structure(caps, 0);
10429 /* set stream information */
10430 gst_structure_get_int (caps_structure, "rate", &samplerate);
10431 mm_attrs_set_int_by_name (player->attrs, "content_audio_samplerate", samplerate);
10433 gst_structure_get_int (caps_structure, "channels", &channels);
10434 mm_attrs_set_int_by_name (player->attrs, "content_audio_channels", channels);
10436 debug_log ("audio samplerate : %d channels : %d\n", samplerate, channels);
10440 __mmplayer_update_content_type_info(mm_player_t* player)
10443 return_if_fail( player && player->type);
10445 if (__mmplayer_is_midi_type(player->type))
10447 player->bypass_audio_effect = TRUE;
10449 else if (g_strrstr(player->type, "application/x-hls"))
10451 /* If it can't know exact type when it parses uri because of redirection case,
10452 * it will be fixed by typefinder or when doing autoplugging.
10454 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
10455 if (player->streamer)
10457 player->streamer->is_adaptive_streaming = TRUE;
10458 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
10459 player->streamer->buffering_req.runtime_second = 5;
10462 else if (g_strrstr(player->type, "application/dash+xml"))
10464 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
10471 __mmplayer_typefind_have_type( GstElement *tf, guint probability, // @
10472 GstCaps *caps, gpointer data)
10474 mm_player_t* player = (mm_player_t*)data;
10475 GstPad* pad = NULL;
10479 return_if_fail( player && tf && caps );
10481 /* store type string */
10482 MMPLAYER_FREEIF(player->type);
10483 player->type = gst_caps_to_string(caps);
10485 debug_log("meida type %s found, probability %d%% / %d\n", player->type, probability, gst_caps_get_size(caps));
10487 if ( (!MMPLAYER_IS_WFD_STREAMING( player )) &&
10488 (!MMPLAYER_IS_RTSP_STREAMING( player )) &&
10489 (g_strrstr(player->type, "audio/x-raw-int")))
10491 debug_error("not support media format\n");
10493 if (player->msg_posted == FALSE)
10495 MMMessageParamType msg_param;
10496 memset (&msg_param, 0, sizeof(MMMessageParamType));
10498 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
10499 MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param );
10501 /* don't post more if one was sent already */
10502 player->msg_posted = TRUE;
10507 __mmplayer_update_content_type_info(player);
10509 pad = gst_element_get_static_pad(tf, "src");
10512 debug_error("fail to get typefind src pad.\n");
10516 if (player->use_decodebin)
10518 if(!__mmplayer_try_to_plug_decodebin( player, pad, caps ))
10520 gboolean async = FALSE;
10521 debug_error("failed to autoplug %s\n", player->type);
10523 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
10525 if ( async && player->msg_posted == FALSE )
10527 __mmplayer_handle_missed_plugin( player );
10536 if ( ! __mmplayer_try_to_plug( player, pad, caps ) )
10538 gboolean async = FALSE;
10539 debug_error("failed to autoplug %s\n", player->type);
10541 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
10543 if ( async && player->msg_posted == FALSE )
10545 __mmplayer_handle_missed_plugin( player );
10551 /* finish autopluging if no dynamic pad waiting */
10552 if( ( ! player->have_dynamic_pad) && ( ! player->has_many_types) )
10554 if ( ! MMPLAYER_IS_RTSP_STREAMING( player ) )
10556 __mmplayer_pipeline_complete( NULL, (gpointer)player );
10562 gst_object_unref( GST_OBJECT(pad) );
10569 #ifdef _MM_PLAYER_ALP_PARSER
10570 void check_name (void *data, void *user_data)
10572 mm_player_t* player = user_data;
10574 if (g_strrstr((gchar*)data, "mpegaudioparse"))
10576 debug_log("mpegaudioparse - set alp-mp3dec\n");
10577 g_object_set(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "alp-mp3dec", TRUE, NULL);
10582 static GstElement *
10583 __mmplayer_create_decodebin (mm_player_t* player)
10585 GstElement *decodebin = NULL;
10589 /* create decodebin */
10590 decodebin = gst_element_factory_make("decodebin", NULL);
10594 debug_error("fail to create decodebin\n");
10598 /* raw pad handling signal */
10599 MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
10600 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
10602 /* no-more-pad pad handling signal */
10603 MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
10604 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), player);
10606 MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
10607 G_CALLBACK(__mmplayer_gst_decode_pad_removed), player);
10609 /* This signal is emitted when a pad for which there is no further possible
10610 decoding is added to the decodebin.*/
10611 MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
10612 G_CALLBACK(__mmplayer_gst_decode_unknown_type), player );
10614 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
10615 before looking for any elements that can handle that stream.*/
10616 MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
10617 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), player);
10619 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
10620 before looking for any elements that can handle that stream.*/
10621 MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
10622 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
10624 /* This signal is emitted once decodebin has finished decoding all the data.*/
10625 MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
10626 G_CALLBACK(__mmplayer_gst_decode_drained), player);
10628 /* This signal is emitted when a element is added to the bin.*/
10629 MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
10630 G_CALLBACK(__mmplayer_gst_element_added), player);
10637 __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
10639 MMPlayerGstElement* mainbin = NULL;
10640 GstElement* decodebin = NULL;
10641 GstElement* queue2 = NULL;
10642 GstPad* sinkpad = NULL;
10643 GstPad* qsrcpad= NULL;
10644 gchar *caps_str = NULL;
10645 gint64 dur_bytes = 0L;
10646 gchar* file_buffering_path = NULL;
10647 gboolean use_file_buffer = FALSE;
10649 guint max_buffer_size_bytes = 0;
10650 gdouble init_buffering_time = (gdouble)player->streamer->buffering_req.initial_second;
10653 return_val_if_fail (player && player->pipeline && player->pipeline->mainbin, FALSE);
10655 mainbin = player->pipeline->mainbin;
10657 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
10658 (MMPLAYER_IS_HTTP_STREAMING(player)))
10660 debug_log ("creating http streaming buffering queue (queue2)\n");
10662 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)
10664 debug_error ("MMPLAYER_M_MUXED_S_BUFFER is not null\n");
10668 queue2 = gst_element_factory_make ("queue2", "queue2");
10671 debug_error ("failed to create buffering queue element\n");
10675 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2))
10677 debug_error("failed to add buffering queue\n");
10681 sinkpad = gst_element_get_static_pad(queue2, "sink");
10682 qsrcpad = gst_element_get_static_pad(queue2, "src");
10684 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad))
10686 debug_error("failed to link buffering queue\n");
10690 // if ( !MMPLAYER_IS_HTTP_LIVE_STREAMING(player))
10692 if ( !gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
10693 debug_error("fail to get duration.\n");
10695 debug_log("dur_bytes = %lld\n", dur_bytes);
10699 use_file_buffer = MMPLAYER_USE_FILE_FOR_BUFFERING(player);
10700 file_buffering_path = g_strdup(player->ini.http_file_buffer_path);
10708 /* NOTE : we cannot get any duration info from ts container in case of streaming */
10709 // if(!g_strrstr(GST_ELEMENT_NAME(sinkelement), "mpegtsdemux"))
10710 if(!g_strrstr(player->type, "video/mpegts"))
10712 max_buffer_size_bytes = (use_file_buffer)?(player->ini.http_max_size_bytes):(5*1024*1024);
10713 debug_log("max_buffer_size_bytes = %d\n", max_buffer_size_bytes);
10715 __mm_player_streaming_set_queue2(player->streamer,
10718 max_buffer_size_bytes,
10719 player->ini.http_buffering_time,
10721 player->ini.http_buffering_limit, // no meaning
10723 file_buffering_path,
10724 (guint64)dur_bytes);
10727 MMPLAYER_FREEIF(file_buffering_path);
10728 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent (queue2))
10730 debug_error("failed to sync queue2 state with parent\n");
10736 gst_object_unref(GST_OBJECT(sinkpad));
10738 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
10739 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
10743 /* create decodebin */
10744 decodebin = __mmplayer_create_decodebin(player);
10748 debug_error("can not create autoplug element\n");
10752 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin))
10754 debug_error("failed to add decodebin\n");
10758 /* to force caps on the decodebin element and avoid reparsing stuff by
10759 * typefind. It also avoids a deadlock in the way typefind activates pads in
10760 * the state change */
10761 g_object_set (decodebin, "sink-caps", caps, NULL);
10763 sinkpad = gst_element_get_static_pad(decodebin, "sink");
10765 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad))
10767 debug_error("failed to link decodebin\n");
10771 gst_object_unref(GST_OBJECT(sinkpad));
10773 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
10774 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
10776 /* set decodebin property about buffer in streaming playback. *
10777 * in case of hls, it does not need to have big buffer *
10778 * because it is kind of adaptive streaming. */
10779 if ( ((!MMPLAYER_IS_HTTP_PD(player)) &&
10780 (MMPLAYER_IS_HTTP_STREAMING(player))) || MMPLAYER_IS_DASH_STREAMING (player))
10782 guint max_size_bytes = MAX_DECODEBIN_BUFFER_BYTES;
10783 guint64 max_size_time = MAX_DECODEBIN_BUFFER_TIME;
10784 init_buffering_time = (init_buffering_time != 0)?(init_buffering_time):(player->ini.http_buffering_time);
10786 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {
10787 max_size_bytes = MAX_DECODEBIN_ADAPTIVE_BUFFER_BYTES;
10788 max_size_time = MAX_DECODEBIN_ADAPTIVE_BUFFER_TIME;
10791 g_object_set (G_OBJECT(decodebin), "use-buffering", TRUE,
10792 "high-percent", (gint)player->ini.http_buffering_limit,
10793 "low-percent", 1, // 1%
10794 "max-size-bytes", max_size_bytes,
10795 "max-size-time", (guint64)(max_size_time * GST_SECOND),
10796 "max-size-buffers", 0, NULL); // disable or automatic
10799 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin))
10801 debug_error("failed to sync decodebin state with parent\n");
10811 MMPLAYER_FREEIF( caps_str );
10814 gst_object_unref(GST_OBJECT(sinkpad));
10818 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
10819 * You need to explicitly set elements to the NULL state before
10820 * dropping the final reference, to allow them to clean up.
10822 gst_element_set_state(queue2, GST_STATE_NULL);
10824 /* And, it still has a parent "player".
10825 * You need to let the parent manage the object instead of unreffing the object directly.
10827 gst_bin_remove (GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
10828 gst_object_unref (queue2);
10834 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
10835 * You need to explicitly set elements to the NULL state before
10836 * dropping the final reference, to allow them to clean up.
10838 gst_element_set_state(decodebin, GST_STATE_NULL);
10840 /* And, it still has a parent "player".
10841 * You need to let the parent manage the object instead of unreffing the object directly.
10844 gst_bin_remove (GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
10845 gst_object_unref (decodebin);
10852 /* it will return first created element */
10854 __mmplayer_try_to_plug(mm_player_t* player, GstPad *pad, const GstCaps *caps) // @
10856 MMPlayerGstElement* mainbin = NULL;
10857 const char* mime = NULL;
10858 const GList* item = NULL;
10859 const gchar* klass = NULL;
10860 GstCaps* res = NULL;
10861 gboolean skip = FALSE;
10862 GstPad* queue_pad = NULL;
10863 GstElement* queue = NULL;
10864 GstElement *element = NULL;
10868 return_val_if_fail( player && player->pipeline && player->pipeline->mainbin, FALSE );
10870 mainbin = player->pipeline->mainbin;
10872 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10874 /* return if we got raw output */
10875 if(g_str_has_prefix(mime, "video/x-raw") || g_str_has_prefix(mime, "audio/x-raw")
10876 || g_str_has_prefix(mime, "text/plain") ||g_str_has_prefix(mime, "text/x-pango-markup"))
10879 element = (GstElement*)gst_pad_get_parent(pad);
10880 /* NOTE : When no decoder has added during autoplugging. like a simple wave playback.
10881 * No queue will be added. I think it can caused breaking sound when playing raw audio
10882 * frames but there's no different. Decodebin also doesn't add with those wav fils.
10883 * Anyway, currentely raw-queue seems not necessary.
10886 /* NOTE : check if previously linked element is demuxer/depayloader/parse means no decoder
10887 * has linked. if so, we need to add queue for quality of output. note that
10888 * decodebin also has same problem.
10890 klass = gst_element_factory_get_metadata (gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
10892 /* add queue if needed */
10893 if( (g_strrstr(klass, "Demux") || g_strrstr(klass, "Depayloader")
10894 || g_strrstr(klass, "Parse")) && !g_str_has_prefix(mime, "text"))
10896 debug_log("adding raw queue\n");
10898 queue = gst_element_factory_make("queue", NULL);
10901 debug_warning("failed to create queue\n");
10906 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_READY) )
10908 debug_warning("failed to set state READY to queue\n");
10912 /* add to pipeline */
10913 if ( ! gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue) )
10915 debug_warning("failed to add queue\n");
10920 queue_pad = gst_element_get_static_pad(queue, "sink");
10922 if ( GST_PAD_LINK_OK != gst_pad_link(pad, queue_pad) )
10924 debug_warning("failed to link queue\n");
10927 gst_object_unref ( GST_OBJECT(queue_pad) );
10931 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_PAUSED) )
10933 debug_warning("failed to set state PAUSED to queue\n");
10937 /* replace given pad to queue:src */
10938 pad = gst_element_get_static_pad(queue, "src");
10941 debug_warning("failed to get pad from queue\n");
10946 /* check if player can do start continually */
10947 MMPLAYER_CHECK_CMD_IF_EXIT(player);
10949 if(__mmplayer_link_sink(player,pad))
10950 __mmplayer_gst_decode_callback(element, pad, player);
10952 gst_object_unref( GST_OBJECT(element));
10958 item = player->factories;
10959 for(; item != NULL ; item = item->next)
10961 GstElementFactory *factory = GST_ELEMENT_FACTORY(item->data);
10967 /* filtering exclude keyword */
10968 for ( idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++ )
10970 if ( g_strrstr(GST_OBJECT_NAME (factory),
10971 player->ini.exclude_element_keyword[idx] ) )
10973 debug_warning("skipping [%s] by exculde keyword [%s]\n",
10974 GST_OBJECT_NAME (factory),
10975 player->ini.exclude_element_keyword[idx] );
10982 if ( MMPLAYER_IS_RTSP_STREAMING(player) && g_strrstr(GST_OBJECT_NAME (factory), "omx_mpeg4dec"))
10984 // omx decoder can not support mpeg4video data partitioned
10985 // rtsp streaming didn't know mpeg4video data partitioned format
10986 // so, if rtsp playback, player will skip omx_mpeg4dec.
10987 debug_warning("skipping [%s] when rtsp streaming \n",
10988 GST_OBJECT_NAME (factory));
10993 if ( skip ) continue;
10995 /* check factory class for filtering */
10996 klass = gst_element_factory_get_metadata (GST_ELEMENT_FACTORY(factory), GST_ELEMENT_METADATA_KLASS);
10998 /*parsers are not required in case of external feeder*/
10999 if (g_strrstr(klass, "Codec/Parser") && MMPLAYER_IS_ES_BUFF_SRC(player))
11002 /* NOTE : msl don't need to use image plugins.
11003 * So, those plugins should be skipped for error handling.
11005 if ( g_strrstr(klass, "Codec/Decoder/Image") )
11007 debug_log("skipping [%s] by not required\n", GST_OBJECT_NAME (factory));
11011 /* check pad compatability */
11012 for(pads = gst_element_factory_get_static_pad_templates(factory);
11013 pads != NULL; pads=pads->next)
11015 GstStaticPadTemplate *temp1 = pads->data;
11016 GstCaps* static_caps = NULL;
11018 if( temp1->direction != GST_PAD_SINK
11019 || temp1->presence != GST_PAD_ALWAYS)
11022 if ( GST_IS_CAPS( &temp1->static_caps.caps) )
11024 /* using existing caps */
11025 static_caps = gst_caps_ref(temp1->static_caps.caps );
11030 static_caps = gst_caps_from_string ( temp1->static_caps.string );
11033 res = gst_caps_intersect((GstCaps*)caps, static_caps);
11034 gst_caps_unref( static_caps );
11035 static_caps = NULL;
11037 if( res && !gst_caps_is_empty(res) )
11039 GstElement *new_element;
11040 GList *elements = player->parsers;
11041 char *name_template = g_strdup(temp1->name_template);
11042 gchar *name_to_plug = GST_OBJECT_NAME(factory);
11043 gst_caps_unref(res);
11045 /* check ALP Codec can be used or not */
11046 if ((g_strrstr(klass, "Codec/Decoder/Audio")))
11048 /* consider mp3 audio only */
11049 if ( !MMPLAYER_IS_STREAMING(player) && __mmplayer_is_only_mp3_type(player->type) )
11051 /* try to use ALP decoder first instead of selected decoder */
11052 GstElement *element = NULL;
11053 GstElementFactory * element_facory;
11054 gchar *path = NULL;
11055 guint64 data_size = 0;
11056 #define MIN_THRESHOLD_SIZE 320 * 1024 // 320K
11059 mm_attrs_get_string_by_name(player->attrs, "profile_uri", &path);
11061 if (stat(path, &sb) == 0)
11063 data_size = (guint64)sb.st_size;
11065 debug_log("file size : %u", data_size);
11067 if (data_size > MIN_THRESHOLD_SIZE)
11069 debug_log("checking if ALP can be used or not");
11070 element = gst_element_factory_make("omx_mp3dec", "omx mp3 decoder");
11073 /* check availability because multi-instance is not supported */
11074 GstStateChangeReturn ret = gst_element_set_state(element, GST_STATE_READY);
11076 if (ret != GST_STATE_CHANGE_SUCCESS) // use just selected decoder
11078 gst_object_unref (element);
11080 else if (ret == GST_STATE_CHANGE_SUCCESS) // replace facotry to use omx
11083 gst_element_set_state(element, GST_STATE_NULL);
11084 gst_object_unref (element);
11086 element_facory = gst_element_factory_find("omx_mp3dec");
11087 /* replace, otherwise use selected thing instead */
11088 if (element_facory)
11090 factory = element_facory;
11091 name_to_plug = GST_OBJECT_NAME(factory);
11094 /* make parser alp mode */
11095 #ifdef _MM_PLAYER_ALP_PARSER
11096 g_list_foreach (player->parsers, check_name, player);
11103 else if ((g_strrstr(klass, "Codec/Decoder/Video")))
11105 if ( g_strrstr(GST_OBJECT_NAME(factory), "omx_") )
11107 char *env = getenv ("MM_PLAYER_HW_CODEC_DISABLE");
11110 if (strncasecmp(env, "yes", 3) == 0)
11112 debug_log("skipping [%s] by disabled\n", name_to_plug);
11113 MMPLAYER_FREEIF(name_template);
11120 debug_log("found %s to plug\n", name_to_plug);
11122 new_element = gst_element_factory_create(GST_ELEMENT_FACTORY(factory), NULL);
11123 if ( ! new_element )
11125 debug_error("failed to create element [%s]. continue with next.\n",
11126 GST_OBJECT_NAME (factory));
11128 MMPLAYER_FREEIF(name_template);
11133 /* check and skip it if it was already used. Otherwise, it can be an infinite loop
11134 * because parser can accept its own output as input.
11136 if (g_strrstr(klass, "Parser"))
11138 gchar *selected = NULL;
11140 for ( ; elements; elements = g_list_next(elements))
11142 gchar *element_name = elements->data;
11144 if (g_strrstr(element_name, name_to_plug))
11146 debug_log("but, %s already linked, so skipping it\n", name_to_plug);
11153 MMPLAYER_FREEIF(name_template);
11157 selected = g_strdup(name_to_plug);
11158 player->parsers = g_list_append(player->parsers, selected);
11161 /* store specific handles for futher control */
11162 if(g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse"))
11164 /* FIXIT : first value will be overwritten if there's more
11165 * than 1 demuxer/parser
11167 debug_log("plugged element is demuxer. take it\n");
11168 mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
11169 mainbin[MMPLAYER_M_DEMUX].gst = new_element;
11171 /*Added for multi audio support */
11172 if(g_strrstr(klass, "Demux"))
11174 mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
11175 mainbin[MMPLAYER_M_DEMUX_EX].gst = new_element;
11177 /* NOTE : workaround for bug in mpegtsdemux since doesn't emit
11178 no-more-pad signal. this may cause wrong content attributes at PAUSED state
11179 this code should be removed after mpegtsdemux is fixed */
11180 if ( g_strrstr(GST_OBJECT_NAME(factory), "mpegtsdemux") )
11182 debug_warning("force no-more-pad to TRUE since mpegtsdemux os not giving no-more-pad signal. content attributes may wrong");
11183 player->no_more_pad = TRUE;
11186 if (g_strrstr(name_to_plug, "asfdemux")) // to support trust-zone only
11188 g_object_set(mainbin[MMPLAYER_M_DEMUX_EX].gst, "file-location", player->profile.uri,NULL);
11191 else if(g_strrstr(klass, "Decoder") && __mmplayer_link_decoder(player,pad))
11193 if(mainbin[MMPLAYER_M_DEC1].gst == NULL)
11195 debug_log("plugged element is decoder. take it[MMPLAYER_M_DEC1]\n");
11196 mainbin[MMPLAYER_M_DEC1].id = MMPLAYER_M_DEC1;
11197 mainbin[MMPLAYER_M_DEC1].gst = new_element;
11199 else if(mainbin[MMPLAYER_M_DEC2].gst == NULL)
11201 debug_log("plugged element is decoder. take it[MMPLAYER_M_DEC2]\n");
11202 mainbin[MMPLAYER_M_DEC2].id = MMPLAYER_M_DEC2;
11203 mainbin[MMPLAYER_M_DEC2].gst = new_element;
11205 /* NOTE : IF one codec is found, add it to supported_codec and remove from
11206 * missing plugin. Both of them are used to check what's supported codec
11207 * before returning result of play start. And, missing plugin should be
11208 * updated here for multi track files.
11210 if(g_str_has_prefix(mime, "video"))
11212 GstPad *src_pad = NULL;
11213 GstPadTemplate *pad_templ = NULL;
11214 GstCaps *caps = NULL;
11215 gchar *caps_str = NULL;
11217 debug_log("found VIDEO decoder\n");
11218 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
11219 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
11221 src_pad = gst_element_get_static_pad (new_element, "src");
11222 pad_templ = gst_pad_get_pad_template (src_pad);
11223 caps = GST_PAD_TEMPLATE_CAPS(pad_templ);
11225 caps_str = gst_caps_to_string(caps);
11228 MMPLAYER_FREEIF( caps_str );
11229 gst_object_unref (src_pad);
11231 else if (g_str_has_prefix(mime, "audio"))
11233 debug_log("found AUDIO decoder\n");
11234 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
11235 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
11239 if ( ! __mmplayer_close_link(player, pad, new_element,
11240 name_template,gst_element_factory_get_static_pad_templates(factory)) )
11242 MMPLAYER_FREEIF(name_template);
11243 if (player->keep_detecting_vcodec)
11246 /* Link is failed even though a supportable codec is found. */
11247 __mmplayer_check_not_supported_codec(player, klass, mime);
11249 debug_error("failed to call _close_link\n");
11253 MMPLAYER_FREEIF(name_template);
11257 gst_caps_unref(res);
11262 /* There is no available codec. */
11263 __mmplayer_check_not_supported_codec(player, klass, mime);
11271 gst_object_unref( queue );
11274 gst_object_unref( queue_pad );
11277 gst_object_unref ( element );
11284 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
11288 return_val_if_fail(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
11289 return_val_if_fail ( mime, MM_ERROR_INVALID_ARGUMENT );
11291 debug_log("class : %s, mime : %s \n", factory_class, mime );
11293 /* add missing plugin */
11294 /* NOTE : msl should check missing plugin for image mime type.
11295 * Some motion jpeg clips can have playable audio track.
11296 * So, msl have to play audio after displaying popup written video format not supported.
11298 if ( !( player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst ) )
11300 if ( !( player->can_support_codec | player->videodec_linked | player->audiodec_linked ) )
11302 debug_log("not found demuxer\n");
11303 player->not_found_demuxer = TRUE;
11304 player->unlinked_demuxer_mime = g_strdup_printf ( "%s", mime );
11310 if( !g_strrstr(factory_class, "Demuxer"))
11312 if( ( g_str_has_prefix(mime, "video") ) ||( g_str_has_prefix(mime, "image") ) )
11314 debug_log("can support codec=%d, vdec_linked=%d, adec_linked=%d\n",
11315 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
11317 /* check that clip have multi tracks or not */
11318 if ( ( player->can_support_codec & FOUND_PLUGIN_VIDEO ) && ( player->videodec_linked ) )
11320 debug_log("video plugin is already linked\n");
11324 debug_warning("add VIDEO to missing plugin\n");
11325 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
11328 else if ( g_str_has_prefix(mime, "audio") )
11330 if ( ( player->can_support_codec & FOUND_PLUGIN_AUDIO ) && ( player->audiodec_linked ) )
11332 debug_log("audio plugin is already linked\n");
11336 debug_warning("add AUDIO to missing plugin\n");
11337 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
11345 return MM_ERROR_NONE;
11350 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
11352 mm_player_t* player = (mm_player_t*)data;
11356 return_if_fail( player );
11358 /* remove fakesink. */
11359 if ( !__mmplayer_gst_remove_fakesink( player,
11360 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]) )
11362 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
11363 * signaling mechanism ( pad-added, no-more-pad, new-decoded-pad ) from various
11364 * source element are not same. To overcome this situation, this function will called
11365 * several places and several times. Therefore, this is not an error case.
11370 debug_log("pipeline has completely constructed\n");
11372 if (( player->ini.async_start ) &&
11373 ( player->msg_posted == FALSE ) &&
11374 ( player->cmd >= MMPLAYER_COMMAND_START ))
11376 __mmplayer_handle_missed_plugin( player );
11379 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-complete" );
11383 __mmplayer_verify_next_play_path(mm_player_t *player)
11385 MMHandleType attrs = 0;
11386 MMPlayerParseProfile profile;
11387 gint uri_idx = 0, check_cnt = 0;
11389 gint mode = MM_PLAYER_PD_MODE_NONE;
11391 guint num_of_list = 0;
11395 debug_log("checking for gapless play");
11397 if (player->pipeline->textbin)
11399 debug_error("subtitle path is enabled. gapless play is not supported.\n");
11403 attrs = MMPLAYER_GET_ATTRS(player);
11406 debug_error("fail to get attributes.\n");
11410 /* seamless playback is supported in case of audio only */
11411 mm_attrs_get_int_by_name(attrs, "content_video_found", &mode);
11414 debug_log("video found");
11418 if (mm_attrs_get_int_by_name (attrs, "pd_mode", &mode) == MM_ERROR_NONE)
11422 debug_warning("pd mode\n");
11427 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
11429 debug_error("can not get play count\n");
11432 num_of_list = g_list_length(player->uri_info.uri_list);
11434 debug_log("repeat count = %d, num_of_list = %d\n", count, num_of_list);
11436 if ( num_of_list == 0 )
11438 if (mm_attrs_get_string_by_name(player->attrs, "profile_uri", &uri) != MM_ERROR_NONE)
11440 debug_error("can not get profile_uri\n");
11446 debug_error("uri list is empty.\n");
11450 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
11451 debug_log("add original path : %s ", uri);
11457 uri_idx = player->uri_info.uri_idx;
11463 if (check_cnt > num_of_list)
11465 debug_error("there is no valid uri.");
11469 debug_log("uri idx : %d / %d\n", uri_idx, num_of_list);
11471 if ( uri_idx < num_of_list-1 )
11477 if ((count <= 1) && (count != -1))
11479 debug_log("no repeat.");
11482 else if ( count > 1 ) /* decrease play count */
11484 /* we successeded to rewind. update play count and then wait for next EOS */
11487 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
11489 /* commit attribute */
11490 if ( mmf_attrs_commit ( attrs ) )
11492 debug_error("failed to commit attribute\n");
11496 /* count < 0 : repeat continually */
11500 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
11501 debug_log("uri idx : %d, uri = %s\n", uri_idx, uri);
11505 debug_warning("next uri does not exist\n");
11509 if (__mmfplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE)
11511 debug_error("failed to parse profile\n");
11515 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
11516 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP))
11518 debug_warning("uri type is not supported (%d).", profile.uri_type);
11525 player->uri_info.uri_idx = uri_idx;
11526 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
11529 if (mmf_attrs_commit(player->attrs))
11531 debug_error("failed to commit.\n");
11535 debug_log("next uri %s (%d)\n", uri, uri_idx);
11541 debug_error("unable to play next path. EOS will be posted soon.\n");
11546 __mmplayer_initialize_next_play(mm_player_t *player)
11552 player->smooth_streaming = FALSE;
11553 player->videodec_linked = 0;
11554 player->audiodec_linked = 0;
11555 player->videosink_linked = 0;
11556 player->audiosink_linked = 0;
11557 player->textsink_linked = 0;
11558 player->is_external_subtitle_present = FALSE;
11559 player->not_supported_codec = MISSING_PLUGIN_NONE;
11560 player->can_support_codec = FOUND_PLUGIN_NONE;
11561 player->pending_seek.is_pending = FALSE;
11562 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
11563 player->pending_seek.pos = 0;
11564 player->msg_posted = FALSE;
11565 player->has_many_types = FALSE;
11566 player->no_more_pad = FALSE;
11567 player->is_drm_file = FALSE;
11568 player->not_found_demuxer = 0;
11569 player->doing_seek = FALSE;
11570 player->max_audio_channels = 0;
11571 player->is_subtitle_force_drop = FALSE;
11572 player->play_subtitle = FALSE;
11573 player->use_textoverlay = FALSE;
11574 player->adjust_subtitle_pos = 0;
11576 player->updated_bitrate_count = 0;
11577 player->total_bitrate = 0;
11578 player->updated_maximum_bitrate_count = 0;
11579 player->total_maximum_bitrate = 0;
11581 _mmplayer_track_initialize(player);
11583 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++)
11585 player->bitrate[i] = 0;
11586 player->maximum_bitrate[i] = 0;
11589 if (player->v_stream_caps)
11591 gst_caps_unref(player->v_stream_caps);
11592 player->v_stream_caps = NULL;
11595 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
11596 mm_attrs_set_int_by_name(player->attrs, "content_audio_found", 0);
11598 /* clean found parsers */
11599 if (player->parsers)
11601 GList *parsers = player->parsers;
11602 for ( ;parsers ; parsers = g_list_next(parsers))
11604 gchar *name = parsers->data;
11605 MMPLAYER_FREEIF(name);
11607 g_list_free(player->parsers);
11608 player->parsers = NULL;
11611 /* clean found audio decoders */
11612 if (player->audio_decoders)
11614 GList *a_dec = player->audio_decoders;
11615 for ( ;a_dec ; a_dec = g_list_next(a_dec))
11617 gchar *name = a_dec->data;
11618 MMPLAYER_FREEIF(name);
11620 g_list_free(player->audio_decoders);
11621 player->audio_decoders = NULL;
11628 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
11630 MMPlayerGstElement *mainbin = NULL;
11631 MMMessageParamType msg_param = {0,};
11632 GstElement *element = NULL;
11633 MMHandleType attrs = 0;
11635 enum MainElementID elemId = MMPLAYER_M_NUM;
11639 if ((player == NULL) ||
11640 (player->pipeline == NULL) ||
11641 (player->pipeline->mainbin == NULL))
11643 debug_error("player is null.\n");
11647 mainbin = player->pipeline->mainbin;
11648 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
11650 attrs = MMPLAYER_GET_ATTRS(player);
11653 debug_error("fail to get attributes.\n");
11657 /* Initialize Player values */
11658 __mmplayer_initialize_next_play(player);
11660 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
11662 if (__mmfplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE)
11664 debug_error("failed to parse profile\n");
11665 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
11669 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
11670 (MMPLAYER_URL_HAS_HLS_SUFFIX(player)))
11672 debug_error("it's dash or hls. not support.");
11673 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
11678 switch ( player->profile.uri_type )
11681 case MM_PLAYER_URI_TYPE_FILE:
11683 debug_log("using filesrc for 'file://' handler.\n");
11685 element = gst_element_factory_make("filesrc", "source");
11689 debug_error("failed to create filesrc\n");
11693 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
11696 case MM_PLAYER_URI_TYPE_URL_HTTP:
11698 gchar *user_agent, *proxy, *cookies, **cookie_list;
11699 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
11700 user_agent = proxy = cookies = NULL;
11701 cookie_list = NULL;
11703 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
11706 debug_error("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
11709 debug_log("using http streamming source [%s].\n", player->ini.httpsrc_element);
11711 /* get attribute */
11712 mm_attrs_get_string_by_name ( attrs, "streaming_cookie", &cookies );
11713 mm_attrs_get_string_by_name ( attrs, "streaming_user_agent", &user_agent );
11714 mm_attrs_get_string_by_name ( attrs, "streaming_proxy", &proxy );
11715 mm_attrs_get_int_by_name ( attrs, "streaming_timeout", &http_timeout );
11717 if ((http_timeout == DEFAULT_HTTP_TIMEOUT) &&
11718 (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT))
11720 debug_log("get timeout from ini\n");
11721 http_timeout = player->ini.http_timeout;
11724 /* get attribute */
11725 secure_debug_log("location : %s\n", player->profile.uri);
11726 secure_debug_log("cookies : %s\n", cookies);
11727 secure_debug_log("proxy : %s\n", proxy);
11728 secure_debug_log("user_agent : %s\n", user_agent);
11729 debug_log("timeout : %d\n", http_timeout);
11731 /* setting property to streaming source */
11732 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
11733 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
11734 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
11736 /* check if prosy is vailid or not */
11737 if ( util_check_valid_url ( proxy ) )
11738 g_object_set(G_OBJECT(element), "proxy", proxy, NULL);
11739 /* parsing cookies */
11740 if ( ( cookie_list = util_get_cookie_list ((const char*)cookies) ) )
11741 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
11743 g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL);
11747 debug_error("not support uri type %d\n", player->profile.uri_type);
11753 debug_error("no source element was created.\n");
11757 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE)
11759 debug_error("failed to add source element to pipeline\n");
11760 gst_object_unref(GST_OBJECT(element));
11765 /* take source element */
11766 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
11767 mainbin[MMPLAYER_M_SRC].gst = element;
11771 if (MMPLAYER_IS_HTTP_STREAMING(player))
11773 if (player->streamer == NULL)
11775 player->streamer = __mm_player_streaming_create();
11776 __mm_player_streaming_initialize(player->streamer);
11779 elemId = MMPLAYER_M_TYPEFIND;
11780 element = gst_element_factory_make("typefind", "typefinder");
11781 MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
11782 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player );
11786 elemId = MMPLAYER_M_AUTOPLUG;
11787 element = __mmplayer_create_decodebin(player);
11790 /* check autoplug element is OK */
11793 debug_error("can not create element (%d)\n", elemId);
11797 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE)
11799 debug_error("failed to add sinkbin to pipeline\n");
11800 gst_object_unref(GST_OBJECT(element));
11805 mainbin[elemId].id = elemId;
11806 mainbin[elemId].gst = element;
11808 if ( gst_element_link (mainbin[MMPLAYER_M_SRC].gst, mainbin[elemId].gst) == FALSE )
11810 debug_error("Failed to link src - autoplug (or typefind)\n");
11814 if (gst_element_set_state (mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE)
11816 debug_error("Failed to change state of src element\n");
11820 if (!MMPLAYER_IS_HTTP_STREAMING(player))
11822 if (gst_element_set_state (mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE)
11824 debug_error("Failed to change state of decodebin\n");
11830 if (gst_element_set_state (mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE)
11832 debug_error("Failed to change state of src element\n");
11837 player->gapless.stream_changed = TRUE;
11838 player->gapless.running = TRUE;
11843 MMPLAYER_PLAYBACK_UNLOCK(player);
11845 if (!player->msg_posted)
11847 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
11848 player->msg_posted = TRUE;
11854 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
11856 mm_player_selector_t *selector = &player->selector[type];
11857 MMPlayerGstElement *sinkbin = NULL;
11858 enum MainElementID selectorId = MMPLAYER_M_NUM;
11859 enum MainElementID sinkId = MMPLAYER_M_NUM;
11860 GstPad *srcpad = NULL;
11861 GstPad *sinkpad = NULL;
11864 return_val_if_fail (player, FALSE);
11866 debug_log("type %d", type);
11870 case MM_PLAYER_TRACK_TYPE_AUDIO:
11871 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
11872 sinkId = MMPLAYER_A_BIN;
11873 sinkbin = player->pipeline->audiobin;
11875 case MM_PLAYER_TRACK_TYPE_TEXT:
11876 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
11877 sinkId = MMPLAYER_T_BIN;
11878 sinkbin = player->pipeline->textbin;
11881 debug_error("requested type is not supportable");
11886 if (player->pipeline->mainbin[selectorId].gst)
11890 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
11892 if (selector->event_probe_id != 0)
11893 gst_pad_remove_probe (srcpad, selector->event_probe_id);
11894 selector->event_probe_id = 0;
11896 if ((sinkbin) && (sinkbin[sinkId].gst))
11898 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
11900 if (srcpad && sinkpad)
11902 /* after getting drained signal there is no data flows, so no need to do pad_block */
11903 debug_log("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
11904 gst_pad_unlink (srcpad, sinkpad);
11907 gst_object_unref (sinkpad);
11910 gst_object_unref (srcpad);
11913 debug_log("selector release");
11915 /* release and unref requests pad from the selector */
11916 for (n = 0; n < selector->channels->len; n++)
11918 GstPad *sinkpad = g_ptr_array_index (selector->channels, n);
11919 gst_element_release_request_pad ((player->pipeline->mainbin[selectorId].gst), sinkpad);
11921 g_ptr_array_set_size (selector->channels, 0);
11923 gst_element_set_state (player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
11924 gst_bin_remove (GST_BIN_CAST (player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
11926 player->pipeline->mainbin[selectorId].gst = NULL;
11934 __mmplayer_deactivate_old_path(mm_player_t *player)
11937 return_if_fail ( player );
11939 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
11940 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT)))
11942 debug_error("deactivate selector error");
11946 _mmplayer_track_destroy(player);
11947 __mmplayer_release_signal_connection( player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG );
11949 if (player->streamer)
11951 __mm_player_streaming_deinitialize (player->streamer);
11952 __mm_player_streaming_destroy(player->streamer);
11953 player->streamer = NULL;
11956 MMPLAYER_PLAYBACK_LOCK(player);
11957 g_cond_signal( &player->next_play_thread_cond );
11964 if (!player->msg_posted)
11966 MMMessageParamType msg = {0,};
11969 msg.code = MM_ERROR_PLAYER_INTERNAL;
11970 debug_error("next_uri_play> deactivate error");
11972 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
11973 player->msg_posted = TRUE;
11978 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
11980 int result = MM_ERROR_NONE;
11981 mm_player_t* player = (mm_player_t*) hplayer;
11984 return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11986 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
11987 if (mmf_attrs_commit(player->attrs))
11989 debug_error("failed to commit the original uri.\n");
11990 result = MM_ERROR_PLAYER_INTERNAL;
11994 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
11996 debug_error("failed to add the original uri in the uri list.\n");
12004 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
12006 mm_player_t* player = (mm_player_t*) hplayer;
12007 guint num_of_list = 0;
12011 return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12012 return_val_if_fail (uri, MM_ERROR_INVALID_ARGUMENT);
12014 if (player->pipeline && player->pipeline->textbin)
12016 debug_error("subtitle path is enabled.\n");
12017 return MM_ERROR_PLAYER_INVALID_STATE;
12020 num_of_list = g_list_length(player->uri_info.uri_list);
12022 if (is_first_path == TRUE)
12024 if (num_of_list == 0)
12026 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
12027 debug_log("add original path : %s", uri);
12031 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
12032 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
12034 debug_log("change original path : %s", uri);
12039 if (num_of_list == 0)
12041 MMHandleType attrs = 0;
12042 char *original_uri = NULL;
12044 attrs = MMPLAYER_GET_ATTRS(player);
12047 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
12051 debug_error("there is no original uri.");
12052 return MM_ERROR_PLAYER_INVALID_STATE;
12055 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
12056 player->uri_info.uri_idx = 0;
12058 debug_log("add original path at first : %s (%d)", original_uri);
12062 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
12063 debug_log("add new path : %s (total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
12067 return MM_ERROR_NONE;
12070 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
12072 mm_player_t* player = (mm_player_t*) hplayer;
12073 char *next_uri = NULL;
12074 guint num_of_list = 0;
12077 return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12079 num_of_list = g_list_length(player->uri_info.uri_list);
12081 if (num_of_list > 0)
12083 gint uri_idx = player->uri_info.uri_idx;
12085 if ( uri_idx < num_of_list-1 )
12090 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
12091 debug_error("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
12093 *uri = g_strdup(next_uri);
12097 return MM_ERROR_NONE;
12101 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad,
12102 GstCaps *caps, gpointer data)
12104 mm_player_t* player = (mm_player_t*)data;
12105 const gchar* klass = NULL;
12106 const gchar* mime = NULL;
12107 gchar* caps_str = NULL;
12109 klass = gst_element_factory_get_metadata (gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
12110 mime = gst_structure_get_name (gst_caps_get_structure(caps, 0));
12111 caps_str = gst_caps_to_string(caps);
12113 debug_warning("unknown type of caps : %s from %s",
12114 caps_str, GST_ELEMENT_NAME (elem));
12116 MMPLAYER_FREEIF(caps_str);
12118 /* There is no available codec. */
12119 __mmplayer_check_not_supported_codec (player, klass, mime);
12123 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad,
12124 GstCaps * caps, gpointer data)
12126 mm_player_t* player = (mm_player_t*)data;
12127 const char* mime = NULL;
12128 gboolean ret = TRUE;
12130 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
12131 mime = gst_structure_get_name (gst_caps_get_structure(caps, 0));
12133 if (g_str_has_prefix(mime, "audio")) {
12134 GstStructure* caps_structure = NULL;
12135 gint samplerate = 0;
12137 gchar *caps_str = NULL;
12139 caps_structure = gst_caps_get_structure(caps, 0);
12140 gst_structure_get_int (caps_structure, "rate", &samplerate);
12141 gst_structure_get_int (caps_structure, "channels", &channels);
12143 if ( (channels > 0 && samplerate == 0)) {
12144 debug_log("exclude audio...");
12148 caps_str = gst_caps_to_string(caps);
12149 /* set it directly because not sent by TAG */
12150 if (g_strrstr(caps_str, "mobile-xmf")) {
12151 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
12153 MMPLAYER_FREEIF (caps_str);
12154 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
12155 debug_log("already video linked");
12158 debug_log("found new stream");
12165 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad,
12166 GstCaps* caps, GstElementFactory* factory, gpointer data)
12168 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
12169 We are defining our own and will be removed when it actually exposed */
12171 GST_AUTOPLUG_SELECT_TRY,
12172 GST_AUTOPLUG_SELECT_EXPOSE,
12173 GST_AUTOPLUG_SELECT_SKIP
12174 } GstAutoplugSelectResult;
12176 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
12177 mm_player_t* player = (mm_player_t*)data;
12179 gchar* factory_name = NULL;
12180 gchar* caps_str = NULL;
12181 const gchar* klass = NULL;
12184 factory_name = GST_OBJECT_NAME (factory);
12185 klass = gst_element_factory_get_metadata (factory, GST_ELEMENT_METADATA_KLASS);
12186 caps_str = gst_caps_to_string(caps);
12188 // debug_log("found new element [%s] to link for caps [%s]", factory_name, caps_str);
12189 debug_log("found new element [%s] to link", factory_name);
12191 /* store type string */
12192 if (player->type == NULL)
12194 player->type = gst_caps_to_string(caps);
12195 __mmplayer_update_content_type_info(player);
12198 /* To support evasimagesink, omx is excluded temporarily*/
12199 int surface_type = 0;
12200 mm_attrs_get_int_by_name(player->attrs, "display_surface_client_type", &surface_type);
12201 if (surface_type == MM_DISPLAY_SURFACE_NULL)
12202 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
12203 debug_log("check display surface type attribute: %d", surface_type);
12204 if (surface_type == MM_DISPLAY_SURFACE_EVAS && strstr(factory_name, "omx"))
12206 debug_warning("skipping [%s] for supporting evasimagesink temporarily.\n", factory_name);
12207 result = GST_AUTOPLUG_SELECT_SKIP;
12211 /* filtering exclude keyword */
12212 for ( idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++ )
12214 if ( strstr(factory_name, player->ini.exclude_element_keyword[idx] ) )
12216 debug_warning("skipping [%s] by exculde keyword [%s]\n",
12217 factory_name, player->ini.exclude_element_keyword[idx] );
12219 // NOTE : does we need to check n_value against the number of item selected?
12220 result = GST_AUTOPLUG_SELECT_SKIP;
12225 /* check factory class for filtering */
12226 /* NOTE : msl don't need to use image plugins.
12227 * So, those plugins should be skipped for error handling.
12229 if (g_strrstr(klass, "Codec/Decoder/Image"))
12231 debug_log("skipping [%s] by not required\n", factory_name);
12232 result = GST_AUTOPLUG_SELECT_SKIP;
12236 if ((MMPLAYER_IS_ES_BUFF_SRC(player)) &&
12237 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser"))))
12239 // TO CHECK : subtitle if needed, add subparse exception.
12240 debug_log("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
12241 result = GST_AUTOPLUG_SELECT_SKIP;
12245 if (g_strrstr(factory_name, "mpegpsdemux"))
12247 debug_log("skipping PS container - not support\n");
12248 result = GST_AUTOPLUG_SELECT_SKIP;
12252 if (g_strrstr(factory_name, SMOOTH_STREAMING_DEMUX))
12253 player->smooth_streaming = TRUE;
12255 /* check ALP Codec can be used or not */
12256 if ((g_strrstr(klass, "Codec/Decoder/Audio")))
12258 GstStructure* str = NULL;
12261 str = gst_caps_get_structure( caps, 0 );
12264 gst_structure_get_int (str, "channels", &channels);
12266 debug_log ("check audio ch : %d %d\n", player->max_audio_channels, channels);
12267 if (player->max_audio_channels < channels)
12269 player->max_audio_channels = channels;
12273 if (!player->audiodec_linked)
12275 /* set stream information */
12276 __mmplayer_set_audio_attrs (player, caps);
12279 else if ((g_strrstr(klass, "Codec/Decoder/Video")))
12281 if (g_strrstr(factory_name, "omx_"))
12283 char *env = getenv ("MM_PLAYER_HW_CODEC_DISABLE");
12286 if (strncasecmp(env, "yes", 3) == 0)
12288 debug_log ("skipping [%s] by disabled\n", factory_name);
12289 result = GST_AUTOPLUG_SELECT_SKIP;
12296 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
12297 (g_strrstr(klass, "Codec/Decoder/Video")))
12301 GstStructure *str = NULL;
12302 mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &stype);
12304 /* don't make video because of not required */
12305 if (stype == MM_DISPLAY_SURFACE_NULL)
12307 debug_log ("no video because it's not required. -> return expose");
12308 if (player->set_mode.media_packet_video_stream == FALSE)
12310 result = GST_AUTOPLUG_SELECT_EXPOSE;
12315 /* get w/h for omx state-tune */
12316 str = gst_caps_get_structure (caps, 0);
12317 gst_structure_get_int (str, "width", &width);
12320 if (player->v_stream_caps) {
12321 gst_caps_unref(player->v_stream_caps);
12322 player->v_stream_caps = NULL;
12325 player->v_stream_caps = gst_caps_copy(caps);
12326 debug_log ("take caps for video state tune");
12327 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
12331 if (g_strrstr(klass, "Decoder"))
12333 const char* mime = NULL;
12334 mime = gst_structure_get_name (gst_caps_get_structure(caps, 0));
12336 if (g_str_has_prefix(mime, "video"))
12338 // __mmplayer_check_video_zero_cpoy(player, factory);
12340 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
12341 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
12343 player->videodec_linked = 1;
12345 else if(g_str_has_prefix(mime, "audio"))
12347 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
12348 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
12350 player->audiodec_linked = 1;
12355 MMPLAYER_FREEIF(caps_str);
12362 static GValueArray*
12363 __mmplayer_gst_decode_autoplug_factories(GstElement *bin, GstPad* pad,
12364 GstCaps * caps, gpointer data)
12366 //mm_player_t* player = (mm_player_t*)data;
12368 debug_log("decodebin is requesting factories for caps [%s] from element[%s]",
12369 gst_caps_to_string(caps),
12370 GST_ELEMENT_NAME(GST_PAD_PARENT(pad)));
12377 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad,
12378 gpointer data) // @
12380 //mm_player_t* player = (mm_player_t*)data;
12381 GstCaps* caps = NULL;
12383 debug_log("[Decodebin2] pad-removed signal\n");
12385 caps = gst_pad_query_caps(new_pad, NULL);
12388 gchar* caps_str = NULL;
12389 caps_str = gst_caps_to_string(caps);
12391 debug_log("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem) );
12393 MMPLAYER_FREEIF(caps_str);
12398 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
12400 mm_player_t* player = (mm_player_t*)data;
12403 return_if_fail ( player );
12405 debug_log("__mmplayer_gst_decode_drained");
12407 if (player->use_deinterleave == TRUE)
12409 debug_log("group playing mode.");
12413 if (!g_mutex_trylock(&player->cmd_lock))
12415 debug_warning("Fail to get cmd lock");
12419 if (!__mmplayer_verify_next_play_path(player))
12421 debug_log("decoding is finished.");
12422 player->gapless.running = FALSE;
12423 player->gapless.start_time = 0;
12424 g_mutex_unlock(&player->cmd_lock);
12428 player->gapless.reconfigure = TRUE;
12430 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
12431 __mmplayer_deactivate_old_path(player);
12433 g_mutex_unlock(&player->cmd_lock);
12439 __mmplayer_gst_element_added (GstElement *bin, GstElement *element, gpointer data)
12441 mm_player_t* player = (mm_player_t*)data;
12442 const gchar* klass = NULL;
12443 gchar* factory_name = NULL;
12445 klass = gst_element_factory_get_metadata (gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
12446 factory_name = GST_OBJECT_NAME (gst_element_get_factory(element));
12448 debug_log("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
12450 if (__mmplayer_add_dump_buffer_probe(player, element))
12451 debug_log("add buffer probe");
12454 if (g_strrstr(klass, "Codec/Decoder/Audio"))
12456 gchar* selected = NULL;
12457 selected = g_strdup( GST_ELEMENT_NAME(element));
12458 player->audio_decoders = g_list_append (player->audio_decoders, selected);
12462 if (g_strrstr(klass, "Parser"))
12464 gchar* selected = NULL;
12466 selected = g_strdup (factory_name);
12467 player->parsers = g_list_append (player->parsers, selected);
12470 if ((g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) && !(g_strrstr(klass, "Adaptive")))
12472 /* FIXIT : first value will be overwritten if there's more
12473 * than 1 demuxer/parser
12476 //debug_log ("plugged element is demuxer. take it\n");
12477 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
12478 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
12480 /*Added for multi audio support */ // Q. del?
12481 if (g_strrstr(klass, "Demux"))
12483 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
12484 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].gst = element;
12488 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux"))
12490 int surface_type = 0;
12492 mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &surface_type);
12494 #if 0 // this is for 0.10 plugin with downstream modification
12495 /* playback protection if drm file */
12496 if (player->use_video_stream || surface_type == MM_DISPLAY_SURFACE_EVAS || surface_type == MM_DISPLAY_SURFACE_X_EXT)
12498 debug_log("playback can be protected if playready drm");
12499 g_object_set (G_OBJECT(element), "playback-protection", TRUE, NULL);
12504 // to support trust-zone only
12505 if (g_strrstr(factory_name, "asfdemux"))
12507 debug_log ("set file-location %s\n", player->profile.uri);
12508 g_object_set (G_OBJECT(element), "file-location", player->profile.uri, NULL);
12510 if (player->video_hub_download_mode == TRUE)
12512 g_object_set (G_OBJECT(element), "downloading-mode", player->video_hub_download_mode, NULL);
12515 else if (g_strrstr(factory_name, "legacyh264parse")) // SMOOTH_STREAMING_DEMUX
12517 debug_log ("[%s] output-format to legacyh264parse\n", SMOOTH_STREAMING_DEMUX);
12518 g_object_set (G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
12520 else if (g_strrstr(factory_name, "mpegaudioparse"))
12522 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
12523 (__mmplayer_is_only_mp3_type(player->type)))
12525 debug_log ("[mpegaudioparse] set streaming pull mode.");
12526 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
12529 else if (g_strrstr(factory_name, "omx"))
12531 if (g_strrstr(klass, "Codec/Decoder/Video"))
12533 gboolean ret = FALSE;
12535 if (player->v_stream_caps != NULL)
12537 GstPad *pad = gst_element_get_static_pad(element, "sink");
12541 ret = gst_pad_set_caps(pad, player->v_stream_caps);
12542 debug_log("found omx decoder, setting gst_pad_set_caps for omx (ret:%d)", ret);
12543 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
12544 gst_object_unref (pad);
12547 g_object_set (G_OBJECT(element), "state-tuning", TRUE, NULL);
12549 #ifdef _MM_PLAYER_ALP_PARSER
12550 if (g_strrstr(factory_name, "omx_mp3dec"))
12552 g_list_foreach (player->parsers, check_name, player);
12555 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
12558 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
12559 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue")))
12561 debug_log ("plugged element is multiqueue. take it\n");
12563 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
12564 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
12566 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
12567 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)))
12569 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
12570 __mm_player_streaming_set_multiqueue(player->streamer,
12573 player->ini.http_buffering_time,
12575 player->ini.http_buffering_limit);
12577 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
12581 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-added" );
12585 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player)
12588 return_val_if_fail ( player, FALSE );
12590 if ( MMPLAYER_IS_STREAMING(player) )
12593 /* This callback can be set to music player only. */
12594 if((player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO)
12596 debug_warning("audio callback is not supported for video");
12600 if (player->audio_stream_cb)
12603 GstPad *pad = NULL;
12605 pad = gst_element_get_static_pad (player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
12609 debug_error("failed to get sink pad from audiosink to probe data\n");
12612 player->audio_cb_probe_id = gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER,
12613 __mmplayer_audio_stream_probe, player, NULL);
12615 gst_object_unref (pad);
12622 debug_error("There is no audio callback to configure.\n");
12632 __mmplayer_init_factories(mm_player_t* player) // @
12634 return_if_fail ( player );
12636 player->factories = gst_registry_feature_filter(gst_registry_get(),
12637 (GstPluginFeatureFilter)__mmplayer_feature_filter, FALSE, NULL);
12638 player->factories = g_list_sort(player->factories, (GCompareFunc)util_factory_rank_compare);
12642 __mmplayer_release_factories(mm_player_t* player) // @
12645 return_if_fail ( player );
12647 if (player->factories)
12649 gst_plugin_feature_list_free (player->factories);
12650 player->factories = NULL;
12657 __mmplayer_release_misc(mm_player_t* player)
12660 gboolean cur_mode = player->set_mode.rich_audio;
12663 return_if_fail ( player );
12665 player->use_video_stream = FALSE;
12666 player->video_stream_cb = NULL;
12667 player->video_stream_cb_user_param = NULL;
12669 player->audio_stream_cb = NULL;
12670 player->audio_stream_render_cb_ex = NULL;
12671 player->audio_stream_cb_user_param = NULL;
12672 player->audio_stream_sink_sync = false;
12674 player->video_stream_changed_cb = NULL;
12675 player->video_stream_changed_cb_user_param = NULL;
12677 player->audio_stream_changed_cb = NULL;
12678 player->audio_stream_changed_cb_user_param = NULL;
12680 player->sent_bos = FALSE;
12681 player->playback_rate = DEFAULT_PLAYBACK_RATE;
12683 player->doing_seek = FALSE;
12685 player->updated_bitrate_count = 0;
12686 player->total_bitrate = 0;
12687 player->updated_maximum_bitrate_count = 0;
12688 player->total_maximum_bitrate = 0;
12690 player->not_found_demuxer = 0;
12692 player->last_position = 0;
12693 player->duration = 0;
12694 player->http_content_size = 0;
12695 player->not_supported_codec = MISSING_PLUGIN_NONE;
12696 player->can_support_codec = FOUND_PLUGIN_NONE;
12697 player->pending_seek.is_pending = FALSE;
12698 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
12699 player->pending_seek.pos = 0;
12700 player->msg_posted = FALSE;
12701 player->has_many_types = FALSE;
12702 player->is_drm_file = FALSE;
12703 player->max_audio_channels = 0;
12704 player->video_share_api_delta = 0;
12705 player->video_share_clock_delta = 0;
12706 player->sound_focus.keep_last_pos = FALSE;
12707 player->sound_focus.acquired = FALSE;
12708 player->is_subtitle_force_drop = FALSE;
12709 player->play_subtitle = FALSE;
12710 player->use_textoverlay = FALSE;
12711 player->adjust_subtitle_pos = 0;
12712 player->last_multiwin_status = FALSE;
12713 player->has_closed_caption = FALSE;
12714 player->set_mode.media_packet_video_stream = FALSE;
12715 memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
12717 player->set_mode.rich_audio = cur_mode;
12719 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++)
12721 player->bitrate[i] = 0;
12722 player->maximum_bitrate[i] = 0;
12725 /* remove media stream cb (appsrc cb) */
12726 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++)
12728 player->media_stream_buffer_status_cb[i] = NULL;
12729 player->media_stream_seek_data_cb[i] = NULL;
12732 /* free memory related to audio effect */
12733 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
12735 if (player->state_tune_caps)
12737 gst_caps_unref(player->state_tune_caps);
12738 player->state_tune_caps = NULL;
12741 if (player->video_cb_probe_id)
12743 GstPad *pad = NULL;
12745 pad = gst_element_get_static_pad (player->video_fakesink, "sink");
12748 debug_log("release video probe\n");
12750 /* release audio callback */
12751 gst_pad_remove_probe (pad, player->video_cb_probe_id);
12752 player->video_cb_probe_id = 0;
12753 player->video_stream_cb = NULL;
12754 player->video_stream_cb_user_param = NULL;
12762 __mmplayer_release_misc_post(mm_player_t* player)
12764 char *original_uri = NULL;
12767 /* player->pipeline is already released before. */
12769 return_if_fail ( player );
12771 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
12772 mm_attrs_set_int_by_name(player->attrs, "content_audio_found", 0);
12774 /* clean found parsers */
12775 if (player->parsers)
12777 GList *parsers = player->parsers;
12778 for ( ;parsers ; parsers = g_list_next(parsers))
12780 gchar *name = parsers->data;
12781 MMPLAYER_FREEIF(name);
12783 g_list_free(player->parsers);
12784 player->parsers = NULL;
12787 /* clean found audio decoders */
12788 if (player->audio_decoders)
12790 GList *a_dec = player->audio_decoders;
12791 for ( ;a_dec ; a_dec = g_list_next(a_dec))
12793 gchar *name = a_dec->data;
12794 MMPLAYER_FREEIF(name);
12796 g_list_free(player->audio_decoders);
12797 player->audio_decoders = NULL;
12800 /* clean the uri list except original uri */
12801 if (player->uri_info.uri_list)
12803 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
12807 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
12808 debug_log("restore original uri = %s\n", original_uri);
12810 if (mmf_attrs_commit(player->attrs))
12812 debug_error("failed to commit the original uri.\n");
12816 GList *uri_list = player->uri_info.uri_list;
12817 for ( ;uri_list ; uri_list = g_list_next(uri_list))
12819 gchar *uri = uri_list->data;
12820 MMPLAYER_FREEIF(uri);
12822 g_list_free(player->uri_info.uri_list);
12823 player->uri_info.uri_list = NULL;
12826 player->uri_info.uri_idx = 0;
12830 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name)
12832 GstElement *element = NULL;
12835 debug_log("creating %s to plug\n", name);
12837 element = gst_element_factory_make(name, NULL);
12840 debug_error("failed to create queue\n");
12844 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(element, GST_STATE_READY) )
12846 debug_error("failed to set state READY to %s\n", name);
12847 gst_object_unref (element);
12851 if ( ! gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), element))
12853 debug_error("failed to add %s\n", name);
12854 gst_object_unref (element);
12858 sinkpad = gst_element_get_static_pad(element, "sink");
12860 if ( GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad) )
12862 debug_error("failed to link %s\n", name);
12863 gst_object_unref (sinkpad);
12864 gst_object_unref (element);
12868 debug_log("linked %s to pipeline successfully\n", name);
12870 gst_object_unref (sinkpad);
12876 __mmplayer_close_link(mm_player_t* player, GstPad *srcpad, GstElement *sinkelement,
12877 const char *padname, const GList *templlist)
12879 GstPad *pad = NULL;
12880 gboolean has_dynamic_pads = FALSE;
12881 gboolean has_many_types = FALSE;
12882 const char *klass = NULL;
12883 GstStaticPadTemplate *padtemplate = NULL;
12884 GstElementFactory *factory = NULL;
12885 GstElement* queue = NULL;
12886 GstElement* parser = NULL;
12887 GstPad *pssrcpad = NULL;
12888 GstPad *qsrcpad = NULL, *qsinkpad = NULL;
12889 MMPlayerGstElement *mainbin = NULL;
12890 GstStructure* str = NULL;
12891 GstCaps* srccaps = NULL;
12892 GstState target_state = GST_STATE_READY;
12893 gboolean isvideo_decoder = FALSE;
12894 guint q_max_size_time = 0;
12898 return_val_if_fail ( player &&
12899 player->pipeline &&
12900 player->pipeline->mainbin,
12903 mainbin = player->pipeline->mainbin;
12905 debug_log("plugging pad %s:%s to newly create %s:%s\n",
12906 GST_ELEMENT_NAME( GST_PAD_PARENT ( srcpad ) ),
12907 GST_PAD_NAME( srcpad ),
12908 GST_ELEMENT_NAME( sinkelement ),
12911 factory = gst_element_get_factory(sinkelement);
12912 klass = gst_element_factory_get_metadata (factory, GST_ELEMENT_METADATA_KLASS);
12914 /* check if player can do start continually */
12915 MMPLAYER_CHECK_CMD_IF_EXIT(player);
12917 /* need it to warm up omx before linking to pipeline */
12918 if (g_strrstr(GST_ELEMENT_NAME( GST_PAD_PARENT ( srcpad ) ), "demux"))
12920 debug_log("get demux caps.\n");
12921 if (player->state_tune_caps)
12923 gst_caps_unref(player->state_tune_caps);
12924 player->state_tune_caps = NULL;
12926 player->state_tune_caps = gst_caps_copy(gst_pad_get_current_caps(srcpad));
12929 /* NOTE : OMX Codec can check if resource is available or not at this state. */
12930 if (g_strrstr(GST_ELEMENT_NAME(sinkelement), "omx"))
12932 if (player->state_tune_caps != NULL)
12934 debug_log("set demux's caps to omx codec if resource is available");
12935 if (gst_pad_set_caps(gst_element_get_static_pad(sinkelement, "sink"), player->state_tune_caps))
12937 target_state = GST_STATE_PAUSED;
12938 isvideo_decoder = TRUE;
12939 g_object_set(G_OBJECT(sinkelement), "state-tuning", TRUE, NULL);
12943 debug_warning("failed to set caps for state tuning");
12946 gst_caps_unref(player->state_tune_caps);
12947 player->state_tune_caps = NULL;
12950 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkelement, target_state) )
12952 debug_error("failed to set %d state to %s\n", target_state, GST_ELEMENT_NAME( sinkelement ));
12953 if (isvideo_decoder)
12955 gst_element_set_state(sinkelement, GST_STATE_NULL);
12956 gst_object_unref(G_OBJECT(sinkelement));
12957 player->keep_detecting_vcodec = TRUE;
12962 /* add to pipeline */
12963 if ( ! gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), sinkelement) )
12965 debug_error("failed to add %s to mainbin\n", GST_ELEMENT_NAME( sinkelement ));
12969 debug_log("element klass : %s\n", klass);
12971 /* added to support multi track files */
12972 /* only decoder case and any of the video/audio still need to link*/
12973 if(g_strrstr(klass, "Decoder") && __mmplayer_link_decoder(player,srcpad))
12975 gchar *name = g_strdup(GST_ELEMENT_NAME( GST_PAD_PARENT ( srcpad )));
12977 if (g_strrstr(name, "mpegtsdemux")|| g_strrstr(name, SMOOTH_STREAMING_DEMUX))
12979 gchar *src_demux_caps_str = NULL;
12980 gchar *needed_parser = NULL;
12981 GstCaps *src_demux_caps = NULL;
12982 gboolean smooth_streaming = FALSE;
12984 src_demux_caps = gst_pad_query_caps(srcpad, NULL);
12985 src_demux_caps_str = gst_caps_to_string(src_demux_caps);
12987 gst_caps_unref(src_demux_caps);
12989 if (g_strrstr(src_demux_caps_str, "video/x-h264"))
12991 if (g_strrstr(name, SMOOTH_STREAMING_DEMUX))
12993 needed_parser = g_strdup("legacyh264parse");
12994 smooth_streaming = TRUE;
12998 needed_parser = g_strdup("h264parse");
13001 else if (g_strrstr(src_demux_caps_str, "video/mpeg"))
13003 needed_parser = g_strdup("mpeg4videoparse");
13005 MMPLAYER_FREEIF(src_demux_caps_str);
13009 parser = __mmplayer_element_create_and_link(player, srcpad, needed_parser);
13010 MMPLAYER_FREEIF(needed_parser);
13014 debug_error("failed to create parser\n");
13018 if (smooth_streaming)
13020 g_object_set (parser, "output-format", 1, NULL); /* NALU/Byte Stream format */
13023 /* update srcpad if parser is created */
13024 pssrcpad = gst_element_get_static_pad(parser, "src");
13029 MMPLAYER_FREEIF(name);
13031 queue = __mmplayer_element_create_and_link(player, srcpad, "queue"); // parser - queue or demuxer - queue
13034 debug_error("failed to create queue\n");
13038 /* update srcpad to link with decoder */
13039 qsrcpad = gst_element_get_static_pad(queue, "src");
13042 q_max_size_time = GST_QUEUE_DEFAULT_TIME;
13044 /* assigning queue handle for futher manipulation purpose */
13045 /* FIXIT : make it some kind of list so that msl can support more then two stream (text, data, etc...) */
13046 if(mainbin[MMPLAYER_M_Q1].gst == NULL)
13048 mainbin[MMPLAYER_M_Q1].id = MMPLAYER_M_Q1;
13049 mainbin[MMPLAYER_M_Q1].gst = queue;
13051 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_SS)
13053 g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q1].gst), "max-size-time", 0 , NULL);
13054 g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q1].gst), "max-size-buffers", 2, NULL);
13055 g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q1].gst), "max-size-bytes", 0, NULL);
13059 if (!MMPLAYER_IS_RTSP_STREAMING(player))
13060 g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q1].gst), "max-size-time", q_max_size_time * GST_SECOND, NULL);
13063 else if(mainbin[MMPLAYER_M_Q2].gst == NULL)
13065 mainbin[MMPLAYER_M_Q2].id = MMPLAYER_M_Q2;
13066 mainbin[MMPLAYER_M_Q2].gst = queue;
13068 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_SS)
13070 g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q2].gst), "max-size-time", 0 , NULL);
13071 g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q2].gst), "max-size-buffers", 2, NULL);
13072 g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q2].gst), "max-size-bytes", 0, NULL);
13076 if (!MMPLAYER_IS_RTSP_STREAMING(player))
13077 g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q2].gst), "max-size-time", q_max_size_time * GST_SECOND, NULL);
13082 debug_error("Not supporting more then two elementary stream\n");
13086 pad = gst_element_get_static_pad(sinkelement, padname);
13090 debug_warning("failed to get pad(%s) from %s. retrying with [sink]\n",
13091 padname, GST_ELEMENT_NAME(sinkelement) );
13093 pad = gst_element_get_static_pad(sinkelement, "sink");
13096 debug_error("failed to get pad(sink) from %s. \n",
13097 GST_ELEMENT_NAME(sinkelement) );
13102 /* to check the video/audio type set the proper flag*/
13103 const gchar *mime_type = NULL;
13105 srccaps = gst_pad_query_caps(srcpad, NULL);
13109 str = gst_caps_get_structure( srccaps, 0 );
13113 mime_type = gst_structure_get_name(str);
13118 /* link queue and decoder. so, it will be queue - decoder. */
13119 if ( GST_PAD_LINK_OK != gst_pad_link(srcpad, pad) )
13121 gst_object_unref(GST_OBJECT(pad));
13122 debug_error("failed to link (%s) to pad(%s)\n", GST_ELEMENT_NAME( sinkelement ), padname );
13124 /* reconstitute supportable codec */
13125 if (strstr(mime_type, "video"))
13127 player->can_support_codec ^= FOUND_PLUGIN_VIDEO;
13129 else if (strstr(mime_type, "audio"))
13131 player->can_support_codec ^= FOUND_PLUGIN_AUDIO;
13136 if (strstr(mime_type, "video"))
13138 player->videodec_linked = 1;
13139 debug_msg("player->videodec_linked set to 1\n");
13142 else if (strstr(mime_type, "audio"))
13144 player->audiodec_linked = 1;
13145 debug_msg("player->auddiodec_linked set to 1\n");
13148 gst_object_unref(GST_OBJECT(pad));
13149 gst_caps_unref(GST_CAPS(srccaps));
13153 if ( !MMPLAYER_IS_HTTP_PD(player) )
13155 if( (g_strrstr(klass, "Demux") && !g_strrstr(klass, "Metadata")) || (g_strrstr(klass, "Parser") ) )
13157 if (MMPLAYER_IS_HTTP_STREAMING(player))
13159 gint64 dur_bytes = 0L;
13160 gchar *file_buffering_path = NULL;
13161 gboolean use_file_buffer = FALSE;
13163 if ( !mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)
13165 debug_log("creating http streaming buffering queue\n");
13167 queue = gst_element_factory_make("queue2", "queue2");
13170 debug_error ( "failed to create buffering queue element\n" );
13174 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_READY) )
13176 debug_error("failed to set state READY to buffering queue\n");
13180 if ( !gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue) )
13182 debug_error("failed to add buffering queue\n");
13186 qsinkpad = gst_element_get_static_pad(queue, "sink");
13187 qsrcpad = gst_element_get_static_pad(queue, "src");
13189 if ( GST_PAD_LINK_OK != gst_pad_link(srcpad, qsinkpad) )
13191 debug_error("failed to link buffering queue\n");
13197 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
13198 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue;
13200 if ( !MMPLAYER_IS_HTTP_LIVE_STREAMING(player))
13202 if ( !gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
13203 debug_error("fail to get duration.\n");
13207 use_file_buffer = MMPLAYER_USE_FILE_FOR_BUFFERING(player);
13208 file_buffering_path = g_strdup(player->ini.http_file_buffer_path);
13216 /* NOTE : we cannot get any duration info from ts container in case of streaming */
13217 if(!g_strrstr(GST_ELEMENT_NAME(sinkelement), "mpegtsdemux"))
13219 __mm_player_streaming_set_queue2(player->streamer,
13222 player->ini.http_max_size_bytes,
13223 player->ini.http_buffering_time,
13225 player->ini.http_buffering_limit,
13227 file_buffering_path,
13228 (guint64)dur_bytes);
13231 MMPLAYER_FREEIF(file_buffering_path);
13236 /* if it is not decoder or */
13237 /* in decoder case any of the video/audio still need to link*/
13238 if(!g_strrstr(klass, "Decoder"))
13241 pad = gst_element_get_static_pad(sinkelement, padname);
13244 debug_warning("failed to get pad(%s) from %s. retrying with [sink]\n",
13245 padname, GST_ELEMENT_NAME(sinkelement) );
13247 pad = gst_element_get_static_pad(sinkelement, "sink");
13251 debug_error("failed to get pad(sink) from %s. \n",
13252 GST_ELEMENT_NAME(sinkelement) );
13257 if ( GST_PAD_LINK_OK != gst_pad_link(srcpad, pad) )
13259 gst_object_unref(GST_OBJECT(pad));
13260 debug_error("failed to link (%s) to pad(%s)\n", GST_ELEMENT_NAME( sinkelement ), padname );
13264 gst_object_unref(GST_OBJECT(pad));
13267 for(;templlist != NULL; templlist = templlist->next)
13269 padtemplate = templlist->data;
13271 debug_log ("director = [%d], presence = [%d]\n", padtemplate->direction, padtemplate->presence);
13273 if( padtemplate->direction != GST_PAD_SRC ||
13274 padtemplate->presence == GST_PAD_REQUEST )
13277 switch(padtemplate->presence)
13279 case GST_PAD_ALWAYS:
13281 GstPad *srcpad = gst_element_get_static_pad(sinkelement, "src");
13282 GstCaps *caps = gst_pad_query_caps(srcpad, NULL);
13284 /* Check whether caps has many types */
13285 if ( !gst_caps_is_fixed(caps))
13287 debug_log ("always pad but, caps has many types");
13288 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
13289 has_many_types = TRUE;
13293 if ( ! __mmplayer_try_to_plug(player, srcpad, caps) )
13295 gst_object_unref(GST_OBJECT(srcpad));
13296 gst_caps_unref(GST_CAPS(caps));
13298 debug_error("failed to plug something after %s\n", GST_ELEMENT_NAME( sinkelement ));
13302 gst_caps_unref(GST_CAPS(caps));
13303 gst_object_unref(GST_OBJECT(srcpad));
13309 case GST_PAD_SOMETIMES:
13310 has_dynamic_pads = TRUE;
13318 /* check if player can do start continually */
13319 MMPLAYER_CHECK_CMD_IF_EXIT(player);
13321 if( has_dynamic_pads )
13323 player->have_dynamic_pad = TRUE;
13324 MMPLAYER_SIGNAL_CONNECT ( player, sinkelement, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
13325 G_CALLBACK(__mmplayer_add_new_pad), player);
13327 /* for streaming, more then one typefind will used for each elementary stream
13328 * so this doesn't mean the whole pipeline completion
13330 if ( ! MMPLAYER_IS_RTSP_STREAMING( player ) )
13332 MMPLAYER_SIGNAL_CONNECT( player, sinkelement, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
13333 G_CALLBACK(__mmplayer_pipeline_complete), player);
13337 if (has_many_types)
13339 GstPad *pad = NULL;
13341 player->has_many_types = has_many_types;
13343 pad = gst_element_get_static_pad(sinkelement, "src");
13344 MMPLAYER_SIGNAL_CONNECT (player, pad, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "notify::caps", G_CALLBACK(__mmplayer_add_new_caps), player);
13345 gst_object_unref (GST_OBJECT(pad));
13349 /* check if player can do start continually */
13350 MMPLAYER_CHECK_CMD_IF_EXIT(player);
13352 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkelement, GST_STATE_PAUSED) )
13354 debug_error("failed to set state PAUSED to %s\n", GST_ELEMENT_NAME( sinkelement ));
13360 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state (queue, GST_STATE_PAUSED) )
13362 debug_error("failed to set state PAUSED to queue\n");
13368 gst_object_unref (GST_OBJECT(qsrcpad));
13374 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state (parser, GST_STATE_PAUSED) )
13376 debug_error("failed to set state PAUSED to queue\n");
13382 gst_object_unref (GST_OBJECT(pssrcpad));
13394 gst_object_unref(GST_OBJECT(qsrcpad));
13396 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
13397 * You need to explicitly set elements to the NULL state before
13398 * dropping the final reference, to allow them to clean up.
13400 gst_element_set_state(queue, GST_STATE_NULL);
13401 /* And, it still has a parent "player".
13402 * You need to let the parent manage the object instead of unreffing the object directly.
13405 gst_bin_remove (GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue);
13406 //gst_object_unref( queue );
13410 gst_caps_unref(GST_CAPS(srccaps));
13415 static gboolean __mmplayer_feature_filter(GstPluginFeature *feature, gpointer data) // @
13417 const gchar *klass;
13418 //const gchar *name;
13420 /* we only care about element factories */
13421 if (!GST_IS_ELEMENT_FACTORY(feature))
13424 /* only parsers, demuxers and decoders */
13425 klass = gst_element_factory_get_metadata (GST_ELEMENT_FACTORY(feature), GST_ELEMENT_METADATA_KLASS);
13426 //name = gst_element_factory_get_longname(GST_ELEMENT_FACTORY(feature));
13428 if( g_strrstr(klass, "Demux") == NULL &&
13429 g_strrstr(klass, "Codec/Decoder") == NULL &&
13430 g_strrstr(klass, "Depayloader") == NULL &&
13431 g_strrstr(klass, "Parse") == NULL)
13439 static void __mmplayer_add_new_caps(GstPad* pad, GParamSpec* unused, gpointer data)
13441 mm_player_t* player = (mm_player_t*) data;
13442 GstCaps *caps = NULL;
13443 GstStructure *str = NULL;
13448 return_if_fail ( pad )
13449 return_if_fail ( unused )
13450 return_if_fail ( data )
13452 caps = gst_pad_query_caps(pad, NULL);
13456 str = gst_caps_get_structure(caps, 0);
13460 name = gst_structure_get_name(str);
13463 debug_log("name=%s\n", name);
13465 if ( ! __mmplayer_try_to_plug(player, pad, caps) )
13467 debug_error("failed to autoplug for type (%s)\n", name);
13468 gst_caps_unref(caps);
13472 gst_caps_unref(caps);
13474 __mmplayer_pipeline_complete( NULL, (gpointer)player );
13481 static void __mmplayer_set_unlinked_mime_type(mm_player_t* player, GstCaps *caps)
13485 const char *stream_type;
13486 gchar *version_field = NULL;
13490 return_if_fail ( player );
13491 return_if_fail ( caps );
13493 str = gst_caps_get_structure(caps, 0);
13497 stream_type = gst_structure_get_name(str);
13498 if ( !stream_type )
13502 /* set unlinked mime type for downloadable codec */
13503 if (g_str_has_prefix(stream_type, "video/"))
13505 if (g_str_has_prefix(stream_type, "video/mpeg"))
13507 gst_structure_get_int (str, MM_PLAYER_MPEG_VNAME, &version);
13508 version_field = MM_PLAYER_MPEG_VNAME;
13510 else if (g_str_has_prefix(stream_type, "video/x-wmv"))
13512 gst_structure_get_int (str, MM_PLAYER_WMV_VNAME, &version);
13513 version_field = MM_PLAYER_WMV_VNAME;
13516 else if (g_str_has_prefix(stream_type, "video/x-divx"))
13518 gst_structure_get_int (str, MM_PLAYER_DIVX_VNAME, &version);
13519 version_field = MM_PLAYER_DIVX_VNAME;
13524 player->unlinked_video_mime = g_strdup_printf("%s, %s=%d", stream_type, version_field, version);
13528 player->unlinked_video_mime = g_strdup_printf("%s", stream_type);
13531 else if (g_str_has_prefix(stream_type, "audio/"))
13533 if (g_str_has_prefix(stream_type, "audio/mpeg")) // mp3 or aac
13535 gst_structure_get_int (str, MM_PLAYER_MPEG_VNAME, &version);
13536 version_field = MM_PLAYER_MPEG_VNAME;
13538 else if (g_str_has_prefix(stream_type, "audio/x-wma"))
13540 gst_structure_get_int (str, MM_PLAYER_WMA_VNAME, &version);
13541 version_field = MM_PLAYER_WMA_VNAME;
13546 player->unlinked_audio_mime = g_strdup_printf("%s, %s=%d", stream_type, version_field, version);
13550 player->unlinked_audio_mime = g_strdup_printf("%s", stream_type);
13557 static void __mmplayer_add_new_pad(GstElement *element, GstPad *pad, gpointer data)
13559 mm_player_t* player = (mm_player_t*) data;
13560 GstCaps *caps = NULL;
13561 GstStructure *str = NULL;
13565 return_if_fail ( player );
13566 return_if_fail ( pad );
13568 GST_OBJECT_LOCK (pad);
13569 if ((caps = gst_pad_get_current_caps(pad)))
13570 gst_caps_ref(caps);
13571 GST_OBJECT_UNLOCK (pad);
13573 if ( NULL == caps )
13575 caps = gst_pad_query_caps(pad, NULL);
13576 if ( !caps ) return;
13579 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
13581 str = gst_caps_get_structure(caps, 0);
13585 name = gst_structure_get_name(str);
13589 player->num_dynamic_pad++;
13590 debug_log("stream count inc : %d\n", player->num_dynamic_pad);
13592 /* Note : If the stream is the subtitle, we try not to play it. Just close the demuxer subtitle pad.
13593 * If want to play it, remove this code.
13595 if (g_strrstr(name, "application"))
13597 if (g_strrstr(name, "x-id3") || g_strrstr(name, "x-apetag"))
13599 /* If id3/ape tag comes, keep going */
13600 debug_log("application mime exception : id3/ape tag");
13604 /* Otherwise, we assume that this stream is subtile. */
13605 debug_log(" application mime type pad is closed.");
13609 else if (g_strrstr(name, "audio"))
13611 gint samplerate = 0, channels = 0;
13613 if (player->audiodec_linked)
13615 gst_caps_unref(caps);
13616 debug_log("multi tracks. skip to plug");
13620 /* set stream information */
13621 /* if possible, set it here because the caps is not distrubed by resampler. */
13622 gst_structure_get_int (str, "rate", &samplerate);
13623 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
13625 gst_structure_get_int (str, "channels", &channels);
13626 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
13628 debug_log("audio samplerate : %d channels : %d", samplerate, channels);
13630 else if (g_strrstr(name, "video"))
13633 mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &stype);
13635 /* don't make video because of not required */
13636 if (stype == MM_DISPLAY_SURFACE_NULL)
13638 debug_log("no video because it's not required");
13642 player->v_stream_caps = gst_caps_copy(caps); //if needed, video caps is required when videobin is created
13645 if ( ! __mmplayer_try_to_plug(player, pad, caps) )
13647 debug_error("failed to autoplug for type (%s)", name);
13649 __mmplayer_set_unlinked_mime_type(player, caps);
13652 gst_caps_unref(caps);
13659 __mmplayer_check_subtitle( mm_player_t* player )
13661 MMHandleType attrs = 0;
13662 char *subtitle_uri = NULL;
13666 return_val_if_fail( player, FALSE );
13668 /* get subtitle attribute */
13669 attrs = MMPLAYER_GET_ATTRS(player);
13673 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
13674 if ( !subtitle_uri || !strlen(subtitle_uri))
13677 debug_log ("subtite uri is %s[%d]\n", subtitle_uri, strlen(subtitle_uri));
13678 player->is_external_subtitle_present = TRUE;
13686 __mmplayer_can_extract_pcm( mm_player_t* player )
13688 MMHandleType attrs = 0;
13689 gboolean is_drm = FALSE;
13690 gboolean sound_extraction = FALSE;
13692 return_val_if_fail ( player, FALSE );
13694 attrs = MMPLAYER_GET_ATTRS(player);
13697 debug_error("fail to get attributes.");
13701 /* check file is drm or not */
13702 if (g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), "is-drm"))
13703 g_object_get(G_OBJECT(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), "is-drm", &is_drm, NULL);
13705 /* get sound_extraction property */
13706 mm_attrs_get_int_by_name(attrs, "pcm_extraction", &sound_extraction);
13708 if ( ! sound_extraction || is_drm )
13710 debug_log("checking pcm extraction mode : %d, drm : %d", sound_extraction, is_drm);
13718 __mmplayer_handle_streaming_error ( mm_player_t* player, GstMessage * message )
13721 MMMessageParamType msg_param;
13722 gchar *msg_src_element = NULL;
13723 GstStructure *s = NULL;
13724 guint error_id = 0;
13725 gchar *error_string = NULL;
13729 return_val_if_fail ( player, FALSE );
13730 return_val_if_fail ( message, FALSE );
13732 s = malloc( sizeof(GstStructure) );
13733 memcpy ( s, gst_message_get_structure ( message ), sizeof(GstStructure));
13735 if ( !gst_structure_get_uint (s, "error_id", &error_id) )
13736 error_id = MMPLAYER_STREAMING_ERROR_NONE;
13738 switch ( error_id )
13740 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
13741 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
13743 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
13744 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
13746 case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
13747 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
13749 case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
13750 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
13752 case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
13753 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
13755 case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
13756 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
13758 case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
13759 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
13761 case MMPLAYER_STREAMING_ERROR_INVALID_URL:
13762 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
13764 case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
13765 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
13767 case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
13768 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
13770 case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
13771 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
13773 case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
13774 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
13776 case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
13777 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
13779 case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
13780 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
13782 case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
13783 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
13785 case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
13786 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
13788 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
13789 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
13791 case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
13792 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
13794 case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
13795 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
13797 case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
13798 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
13800 case MMPLAYER_STREAMING_ERROR_GONE:
13801 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
13803 case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
13804 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
13806 case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
13807 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
13809 case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
13810 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
13812 case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
13813 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
13815 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
13816 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
13818 case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
13819 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
13821 case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
13822 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
13824 case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
13825 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
13827 case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
13828 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
13830 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
13831 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
13833 case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
13834 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
13836 case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
13837 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
13839 case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
13840 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
13842 case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
13843 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
13845 case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
13846 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
13848 case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
13849 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
13851 case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
13852 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
13854 case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
13855 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
13857 case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
13858 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
13860 case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
13861 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
13863 case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
13864 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
13866 case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
13867 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
13869 case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
13870 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
13872 case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
13873 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
13877 MMPLAYER_FREEIF(s);
13878 return MM_ERROR_PLAYER_STREAMING_FAIL;
13882 error_string = g_strdup(gst_structure_get_string (s, "error_string"));
13883 if ( error_string )
13884 msg_param.data = (void *) error_string;
13886 if ( message->src )
13888 msg_src_element = GST_ELEMENT_NAME( GST_ELEMENT_CAST( message->src ) );
13890 debug_error("-Msg src : [%s] Code : [%x] Error : [%s] \n",
13891 msg_src_element, msg_param.code, (char*)msg_param.data );
13894 /* post error to application */
13895 if ( ! player->msg_posted )
13897 MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param );
13899 /* don't post more if one was sent already */
13900 player->msg_posted = TRUE;
13904 debug_log("skip error post because it's sent already.\n");
13907 MMPLAYER_FREEIF(s);
13909 g_free(error_string);
13916 __mmplayer_handle_eos_delay( mm_player_t* player, int delay_in_ms )
13918 return_if_fail( player );
13921 /* post now if delay is zero */
13922 if ( delay_in_ms == 0 || player->set_mode.pcm_extraction)
13924 debug_log("eos delay is zero. posting EOS now\n");
13925 MMPLAYER_POST_MSG( player, MM_MESSAGE_END_OF_STREAM, NULL );
13927 if ( player->set_mode.pcm_extraction )
13928 __mmplayer_cancel_eos_timer(player);
13933 /* cancel if existing */
13934 __mmplayer_cancel_eos_timer( player );
13936 /* init new timeout */
13937 /* NOTE : consider give high priority to this timer */
13938 debug_log("posting EOS message after [%d] msec\n", delay_in_ms);
13940 player->eos_timer = g_timeout_add( delay_in_ms,
13941 __mmplayer_eos_timer_cb, player );
13943 player->context.global_default = g_main_context_default ();
13944 debug_log("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
13946 /* check timer is valid. if not, send EOS now */
13947 if ( player->eos_timer == 0 )
13949 debug_warning("creating timer for delayed EOS has failed. sending EOS now\n");
13950 MMPLAYER_POST_MSG( player, MM_MESSAGE_END_OF_STREAM, NULL );
13955 __mmplayer_cancel_eos_timer( mm_player_t* player )
13957 return_if_fail( player );
13959 if ( player->eos_timer )
13961 debug_log("cancel eos timer");
13962 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
13963 player->eos_timer = 0;
13970 __mmplayer_eos_timer_cb(gpointer u_data)
13972 mm_player_t* player = NULL;
13973 player = (mm_player_t*) u_data;
13975 return_val_if_fail( player, FALSE );
13977 if ( player->play_count > 1 )
13979 gint ret_value = 0;
13980 ret_value = __gst_set_position( player, MM_PLAYER_POS_FORMAT_TIME, 0, TRUE);
13981 if (ret_value == MM_ERROR_NONE)
13983 MMHandleType attrs = 0;
13984 attrs = MMPLAYER_GET_ATTRS(player);
13986 /* we successeded to rewind. update play count and then wait for next EOS */
13987 player->play_count--;
13989 mm_attrs_set_int_by_name(attrs, "profile_play_count", player->play_count);
13990 mmf_attrs_commit ( attrs );
13994 debug_error("seeking to 0 failed in repeat play");
14000 MMPLAYER_POST_MSG( player, MM_MESSAGE_END_OF_STREAM, NULL );
14003 /* we are returning FALSE as we need only one posting */
14008 __mmplayer_link_decoder( mm_player_t* player, GstPad *srcpad)
14010 const gchar* name = NULL;
14011 GstStructure* str = NULL;
14012 GstCaps* srccaps = NULL;
14016 return_val_if_fail( player, FALSE );
14017 return_val_if_fail ( srcpad, FALSE );
14019 /* to check any of the decoder (video/audio) need to be linked to parser*/
14020 srccaps = gst_pad_query_caps( srcpad, NULL);
14024 str = gst_caps_get_structure( srccaps, 0 );
14028 name = gst_structure_get_name(str);
14032 if (strstr(name, "video"))
14034 if(player->videodec_linked)
14036 debug_msg("Video decoder already linked\n");
14040 if (strstr(name, "audio"))
14042 if(player->audiodec_linked)
14044 debug_msg("Audio decoder already linked\n");
14049 gst_caps_unref( srccaps );
14057 gst_caps_unref( srccaps );
14063 __mmplayer_link_sink( mm_player_t* player , GstPad *srcpad)
14065 const gchar* name = NULL;
14066 GstStructure* str = NULL;
14067 GstCaps* srccaps = NULL;
14071 return_val_if_fail ( player, FALSE );
14072 return_val_if_fail ( srcpad, FALSE );
14074 /* to check any of the decoder (video/audio) need to be linked to parser*/
14075 srccaps = gst_pad_query_caps( srcpad, NULL );
14079 str = gst_caps_get_structure( srccaps, 0 );
14083 name = gst_structure_get_name(str);
14087 if (strstr(name, "video"))
14089 if(player->videosink_linked)
14091 debug_msg("Video Sink already linked\n");
14095 if (strstr(name, "audio"))
14097 if(player->audiosink_linked)
14099 debug_msg("Audio Sink already linked\n");
14103 if (strstr(name, "text"))
14105 if(player->textsink_linked)
14107 debug_msg("Text Sink already linked\n");
14112 gst_caps_unref( srccaps );
14117 //return (!player->videosink_linked || !player->audiosink_linked);
14121 gst_caps_unref( srccaps );
14127 /* sending event to one of sinkelements */
14129 __gst_send_event_to_sink( mm_player_t* player, GstEvent* event )
14131 GstEvent * event2 = NULL;
14132 GList *sinks = NULL;
14133 gboolean res = FALSE;
14136 return_val_if_fail( player, FALSE );
14137 return_val_if_fail ( event, FALSE );
14139 if ( player->play_subtitle && !player->use_textoverlay)
14140 event2 = gst_event_copy((const GstEvent *)event);
14142 sinks = player->sink_elements;
14145 GstElement *sink = GST_ELEMENT_CAST (sinks->data);
14147 if (GST_IS_ELEMENT(sink))
14149 /* keep ref to the event */
14150 gst_event_ref (event);
14152 if ( (res = gst_element_send_event (sink, event)) )
14154 debug_log("sending event[%s] to sink element [%s] success!\n",
14155 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink) );
14157 /* rtsp case, asyn_done is not called after seek during pause state */
14158 if (MMPLAYER_IS_RTSP_STREAMING(player))
14160 if (strstr(GST_EVENT_TYPE_NAME(event), "seek"))
14162 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED)
14164 debug_log("RTSP seek completed, after pause state..\n");
14165 player->doing_seek = FALSE;
14166 MMPLAYER_POST_MSG ( player, MM_MESSAGE_SEEK_COMPLETED, NULL );
14172 if( MMPLAYER_IS_ES_BUFF_SRC(player))
14174 sinks = g_list_next (sinks);
14181 debug_log("sending event[%s] to sink element [%s] failed. try with next one.\n",
14182 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink) );
14185 sinks = g_list_next (sinks);
14190 request pad name = sink0;
14192 request pad name = sink1; // external
14195 /* Note : Textbin is not linked to the video or audio bin.
14196 * It needs to send the event to the text sink seperatelly.
14198 if ( player->play_subtitle && !player->use_textoverlay)
14200 GstElement *text_sink = GST_ELEMENT_CAST (player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
14202 if (GST_IS_ELEMENT(text_sink))
14204 /* keep ref to the event */
14205 gst_event_ref (event2);
14207 if ((res = gst_element_send_event (text_sink, event2)))
14209 debug_log("sending event[%s] to subtitle sink element [%s] success!\n",
14210 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink) );
14214 debug_error("sending event[%s] to subtitle sink element [%s] failed!\n",
14215 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink) );
14218 gst_event_unref (event2);
14222 gst_event_unref (event);
14230 __mmplayer_add_sink( mm_player_t* player, GstElement* sink )
14234 return_if_fail ( player );
14235 return_if_fail ( sink );
14237 player->sink_elements =
14238 g_list_append(player->sink_elements, sink);
14244 __mmplayer_del_sink( mm_player_t* player, GstElement* sink )
14248 return_if_fail ( player );
14249 return_if_fail ( sink );
14251 player->sink_elements =
14252 g_list_remove(player->sink_elements, sink);
14258 __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
14259 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
14260 gint64 cur, GstSeekType stop_type, gint64 stop )
14262 GstEvent* event = NULL;
14263 gboolean result = FALSE;
14267 return_val_if_fail( player, FALSE );
14269 __mmplayer_drop_subtitle(player, FALSE);
14271 event = gst_event_new_seek (rate, format, flags, cur_type,
14272 cur, stop_type, stop);
14274 result = __gst_send_event_to_sink( player, event );
14281 /* NOTE : be careful with calling this api. please refer to below glib comment
14282 * glib comment : Note that there is a bug in GObject that makes this function much
14283 * less useful than it might seem otherwise. Once gobject is disposed, the callback
14284 * will no longer be called, but, the signal handler is not currently disconnected.
14285 * If the instance is itself being freed at the same time than this doesn't matter,
14286 * since the signal will automatically be removed, but if instance persists,
14287 * then the signal handler will leak. You should not remove the signal yourself
14288 * because in a future versions of GObject, the handler will automatically be
14291 * It's possible to work around this problem in a way that will continue to work
14292 * with future versions of GObject by checking that the signal handler is still
14293 * connected before disconnected it:
14295 * if (g_signal_handler_is_connected (instance, id))
14296 * g_signal_handler_disconnect (instance, id);
14299 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
14301 GList* sig_list = NULL;
14302 MMPlayerSignalItem* item = NULL;
14306 return_if_fail( player );
14308 debug_log("release signals type : %d", type);
14310 if ((type < MM_PLAYER_SIGNAL_TYPE_AUTOPLUG) || (type >= MM_PLAYER_SIGNAL_TYPE_ALL))
14312 __mmplayer_release_signal_connection (player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
14313 __mmplayer_release_signal_connection (player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
14314 __mmplayer_release_signal_connection (player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
14315 __mmplayer_release_signal_connection (player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
14316 __mmplayer_release_signal_connection (player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
14320 sig_list = player->signals[type];
14322 for ( ; sig_list; sig_list = sig_list->next )
14324 item = sig_list->data;
14326 if ( item && item->obj && GST_IS_ELEMENT(item->obj) )
14328 if ( g_signal_handler_is_connected ( item->obj, item->sig ) )
14330 g_signal_handler_disconnect ( item->obj, item->sig );
14334 MMPLAYER_FREEIF( item );
14337 g_list_free ( player->signals[type] );
14338 player->signals[type] = NULL;
14345 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
14347 mm_player_t* player = 0;
14348 int prev_display_surface_type = 0;
14349 void *prev_display_overlay = NULL;
14350 const gchar *klass = NULL;
14351 gchar *cur_videosink_name = NULL;
14354 int num_of_dec = 2; /* DEC1, DEC2 */
14358 return_val_if_fail(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
14359 return_val_if_fail(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
14361 player = MM_PLAYER_CAST(handle);
14363 if (surface_type < MM_DISPLAY_SURFACE_X && surface_type >= MM_DISPLAY_SURFACE_NUM)
14365 debug_error("Not support this surface type(%d) for changing vidoesink", surface_type);
14367 return MM_ERROR_INVALID_ARGUMENT;
14370 /* load previous attributes */
14373 mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &prev_display_surface_type);
14374 mm_attrs_get_data_by_name (player->attrs, "display_overlay", &prev_display_overlay);
14375 debug_log("[0: X surface, 1: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
14376 if (prev_display_surface_type == surface_type)
14378 debug_log("incoming display surface type is same as previous one, do nothing..");
14380 return MM_ERROR_NONE;
14385 debug_error("failed to load attributes");
14387 return MM_ERROR_PLAYER_INTERNAL;
14390 /* check videosink element is created */
14391 if (!player->pipeline || !player->pipeline->videobin ||
14392 !player->pipeline->videobin[MMPLAYER_V_SINK].gst )
14394 debug_log("videosink element is not yet ready");
14396 /* videobin is not created yet, so we just set attributes related to display surface */
14397 debug_log("store display attribute for given surface type(%d)", surface_type);
14398 mm_attrs_set_int_by_name (player->attrs, "display_surface_type", surface_type);
14399 mm_attrs_set_data_by_name (player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
14400 if ( mmf_attrs_commit ( player->attrs ) )
14402 debug_error("failed to commit attribute");
14404 return MM_ERROR_PLAYER_INTERNAL;
14407 return MM_ERROR_NONE;
14411 /* get player command status */
14412 if ( !(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME || player->cmd == MMPLAYER_COMMAND_PAUSE) )
14414 debug_error("invalid player command status(%d), __mmplayer_do_change_videosink() is only available with START/RESUME/PAUSE command",player->cmd);
14416 return MM_ERROR_PLAYER_INVALID_STATE;
14419 /* get a current videosink name */
14420 cur_videosink_name = GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
14422 /* surface change */
14423 for ( i = 0 ; i < num_of_dec ; i++)
14425 if ( player->pipeline->mainbin &&
14426 player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst )
14428 GstElementFactory *decfactory;
14429 decfactory = gst_element_get_factory (player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst);
14431 klass = gst_element_factory_get_metadata (decfactory, GST_ELEMENT_METADATA_KLASS);
14432 if ((g_strrstr(klass, "Codec/Decoder/Video")))
14434 if ( !strncmp(cur_videosink_name, "x", 1) && (surface_type == MM_DISPLAY_SURFACE_EVAS) )
14436 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, player->ini.videosink_element_evas, surface_type, display_overlay);
14443 debug_warning("success to changing display surface(%d)",surface_type);
14445 return MM_ERROR_NONE;
14448 else if (!strncmp(cur_videosink_name, "evas", 4) && (surface_type == MM_DISPLAY_SURFACE_X) )
14450 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, player->ini.videosink_element_x, surface_type, display_overlay);
14457 debug_warning("success to changing display surface(%d)",surface_type);
14459 return MM_ERROR_NONE;
14464 debug_error("invalid incoming surface type(%d) and current videosink_name(%s) for changing display surface",surface_type, cur_videosink_name);
14465 ret = MM_ERROR_PLAYER_INTERNAL;
14474 /* rollback to previous attributes */
14475 mm_attrs_set_int_by_name (player->attrs, "display_surface_type", prev_display_surface_type);
14476 mm_attrs_set_data_by_name(player->attrs, "display_overlay", prev_display_overlay, sizeof(void*));
14477 if ( mmf_attrs_commit ( player->attrs ) )
14479 debug_error("failed to commit attributes to rollback");
14481 return MM_ERROR_PLAYER_INTERNAL;
14487 /* NOTE : It does not support some use cases, eg using colorspace converter */
14489 __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay)
14491 GstPad *src_pad_dec = NULL;
14492 GstPad *sink_pad_videosink = NULL;
14493 GstPad *sink_pad_videobin = NULL;
14494 GstClock *clock = NULL;
14495 MMPlayerStateType previous_state = MM_PLAYER_STATE_NUM;
14496 int ret = MM_ERROR_NONE;
14497 gboolean is_audiobin_created = TRUE;
14501 return_val_if_fail(player, MM_ERROR_COMMON_INVALID_ARGUMENT);
14502 return_val_if_fail(videosink_element, MM_ERROR_COMMON_INVALID_ARGUMENT);
14503 return_val_if_fail(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
14505 debug_log("video dec is found(idx:%d), we are going to change videosink to %s", dec_index, videosink_element);
14506 debug_log("surface type(%d), display overlay(%x)", surface_type, display_overlay);
14508 /* get information whether if audiobin is created */
14509 if ( !player->pipeline->audiobin ||
14510 !player->pipeline->audiobin[MMPLAYER_A_SINK].gst )
14512 debug_warning("audiobin is null, this video content may not have audio data");
14513 is_audiobin_created = FALSE;
14516 /* get current state of player */
14517 previous_state = MMPLAYER_CURRENT_STATE(player);
14518 debug_log("previous state(%d)", previous_state);
14521 /* get src pad of decoder and block it */
14522 src_pad_dec = gst_element_get_static_pad (GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), "src");
14525 debug_error("failed to get src pad from decode in mainbin");
14526 return MM_ERROR_PLAYER_INTERNAL;
14529 if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING)
14531 debug_warning("trying to block pad(video)");
14532 // if (!gst_pad_set_blocked (src_pad_dec, TRUE))
14533 gst_pad_add_probe(src_pad_dec, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
14537 debug_error("failed to set block pad(video)");
14538 return MM_ERROR_PLAYER_INTERNAL;
14540 debug_warning("pad is blocked(video)");
14544 /* no data flows, so no need to do pad_block */
14545 if (player->doing_seek) {
14546 debug_warning("not completed seek(%d), do nothing", player->doing_seek);
14548 debug_log("MM_PLAYER_STATE is not PLAYING now, skip pad-block(TRUE)");
14552 if (!gst_element_remove_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst,
14553 GST_PAD_CAST(GST_GHOST_PAD(player->ghost_pad_for_videobin))))
14555 debug_error("failed to remove previous ghost_pad for videobin");
14556 return MM_ERROR_PLAYER_INTERNAL;
14559 /* change state of videobin to NULL */
14560 debug_log("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_NULL);
14561 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_NULL);
14562 if (ret != GST_STATE_CHANGE_SUCCESS)
14564 debug_error("failed to change state of videobin to NULL");
14565 return MM_ERROR_PLAYER_INTERNAL;
14568 /* unlink between decoder and videobin and remove previous videosink from videobin */
14569 GST_ELEMENT_UNLINK(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst),GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst));
14570 if ( !gst_bin_remove (GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst)) )
14572 debug_error("failed to remove former videosink from videobin");
14573 return MM_ERROR_PLAYER_INTERNAL;
14576 __mmplayer_del_sink( player, player->pipeline->videobin[MMPLAYER_V_SINK].gst );
14578 /* create a new videosink and add it to videobin */
14579 player->pipeline->videobin[MMPLAYER_V_SINK].gst = gst_element_factory_make(videosink_element, videosink_element);
14580 gst_bin_add (GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst));
14581 __mmplayer_add_sink( player, player->pipeline->videobin[MMPLAYER_V_SINK].gst );
14582 g_object_set (G_OBJECT (player->pipeline->videobin[MMPLAYER_V_SINK].gst), "qos", TRUE, NULL);
14584 /* save attributes */
14587 /* set a new display surface type */
14588 mm_attrs_set_int_by_name (player->attrs, "display_surface_type", surface_type);
14589 /* set a new diplay overlay */
14590 switch (surface_type)
14592 case MM_DISPLAY_SURFACE_X:
14593 debug_log("save attributes related to display surface to X : xid = %d", *(int*)display_overlay);
14594 mm_attrs_set_data_by_name (player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
14596 case MM_DISPLAY_SURFACE_EVAS:
14597 debug_log("save attributes related to display surface to EVAS : evas image object = %x", display_overlay);
14598 mm_attrs_set_data_by_name (player->attrs, "display_overlay", display_overlay, sizeof(void*));
14601 debug_error("invalid type(%d) for changing display surface",surface_type);
14603 return MM_ERROR_INVALID_ARGUMENT;
14605 if ( mmf_attrs_commit ( player->attrs ) )
14607 debug_error("failed to commit");
14609 return MM_ERROR_PLAYER_INTERNAL;
14614 debug_error("player->attrs is null, failed to save attributes");
14616 return MM_ERROR_PLAYER_INTERNAL;
14619 /* update video param */
14620 if ( MM_ERROR_NONE != _mmplayer_update_video_param( player ) )
14622 debug_error("failed to update video param");
14623 return MM_ERROR_PLAYER_INTERNAL;
14626 /* change state of videobin to READY */
14627 debug_log("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_READY);
14628 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_READY);
14629 if (ret != GST_STATE_CHANGE_SUCCESS)
14631 debug_error("failed to change state of videobin to READY");
14632 return MM_ERROR_PLAYER_INTERNAL;
14635 /* change ghostpad */
14636 sink_pad_videosink = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "sink");
14637 if ( !sink_pad_videosink )
14639 debug_error("failed to get sink pad from videosink element");
14640 return MM_ERROR_PLAYER_INTERNAL;
14642 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", sink_pad_videosink);
14643 if (!gst_pad_set_active(player->ghost_pad_for_videobin, TRUE))
14645 debug_error("failed to set active to ghost_pad");
14646 return MM_ERROR_PLAYER_INTERNAL;
14648 if ( FALSE == gst_element_add_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin) )
14650 debug_error("failed to change ghostpad for videobin");
14651 return MM_ERROR_PLAYER_INTERNAL;
14653 gst_object_unref(sink_pad_videosink);
14655 /* link decoder with videobin */
14656 sink_pad_videobin = gst_element_get_static_pad( GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst), "sink");
14657 if ( !sink_pad_videobin )
14659 debug_error("failed to get sink pad from videobin");
14660 return MM_ERROR_PLAYER_INTERNAL;
14662 if ( GST_PAD_LINK_OK != GST_PAD_LINK(src_pad_dec, sink_pad_videobin) )
14664 debug_error("failed to link");
14665 return MM_ERROR_PLAYER_INTERNAL;
14667 gst_object_unref(sink_pad_videobin);
14669 /* clock setting for a new videosink plugin */
14670 /* NOTE : Below operation is needed, because a new videosink plugin doesn't have clock for basesink,
14671 so we set it from audiosink plugin or pipeline(system clock) */
14672 if (!is_audiobin_created)
14674 debug_warning("audiobin is not created, get clock from pipeline..");
14675 clock = GST_ELEMENT_CLOCK (player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
14679 clock = GST_ELEMENT_CLOCK (player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
14684 GstClockTime base_time;
14685 debug_log("set the clock to videosink");
14686 gst_element_set_clock (GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), clock);
14687 clock = GST_ELEMENT_CLOCK (player->pipeline->videobin[MMPLAYER_V_SINK].gst);
14690 debug_log("got clock of videosink");
14691 now = gst_clock_get_time ( clock );
14692 base_time = GST_ELEMENT_CAST (player->pipeline->videobin[MMPLAYER_V_SINK].gst)->base_time;
14693 debug_log ("at time %" GST_TIME_FORMAT ", base %"
14694 GST_TIME_FORMAT, GST_TIME_ARGS (now), GST_TIME_ARGS (base_time));
14698 debug_error("failed to get clock of videosink after setting clock");
14699 return MM_ERROR_PLAYER_INTERNAL;
14704 debug_warning("failed to get clock, maybe it is the time before first playing");
14707 if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING)
14709 /* change state of videobin to PAUSED */
14710 debug_log("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PLAYING);
14711 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PLAYING);
14712 if (ret != GST_STATE_CHANGE_FAILURE)
14714 debug_warning("change state of videobin to PLAYING, ret(%d)", ret);
14718 debug_error("failed to change state of videobin to PLAYING");
14719 return MM_ERROR_PLAYER_INTERNAL;
14722 /* release blocked and unref src pad of video decoder */
14724 if (!gst_pad_set_blocked (src_pad_dec, FALSE))
14726 debug_error("failed to set pad blocked FALSE(video)");
14727 return MM_ERROR_PLAYER_INTERNAL;
14730 debug_warning("pad is unblocked(video)");
14734 if (player->doing_seek) {
14735 debug_warning("not completed seek(%d)", player->doing_seek);
14737 /* change state of videobin to PAUSED */
14738 debug_log("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PAUSED);
14739 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PAUSED);
14740 if (ret != GST_STATE_CHANGE_FAILURE)
14742 debug_warning("change state of videobin to PAUSED, ret(%d)", ret);
14746 debug_error("failed to change state of videobin to PLAYING");
14747 return MM_ERROR_PLAYER_INTERNAL;
14750 /* already skipped pad block */
14751 debug_log("previous MM_PLAYER_STATE is not PLAYING, skip pad-block(FALSE)");
14754 /* do get/set position for new videosink plugin */
14756 unsigned long position = 0;
14757 gint64 pos_msec = 0;
14759 debug_log("do get/set position for new videosink plugin");
14760 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position ))
14762 debug_error("failed to get position");
14763 return MM_ERROR_PLAYER_INTERNAL;
14765 #ifdef SINKCHANGE_WITH_ACCURATE_SEEK
14766 /* accurate seek */
14767 if (__gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, position, TRUE ))
14769 debug_error("failed to set position");
14770 return MM_ERROR_PLAYER_INTERNAL;
14773 /* key unit seek */
14774 pos_msec = position * G_GINT64_CONSTANT(1000000);
14775 ret = __gst_seek ( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
14776 GST_FORMAT_TIME, ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT ),
14777 GST_SEEK_TYPE_SET, pos_msec,
14778 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE );
14781 debug_error("failed to set position");
14782 return MM_ERROR_PLAYER_INTERNAL;
14789 gst_object_unref (src_pad_dec);
14791 debug_log("success to change sink");
14795 return MM_ERROR_NONE;
14799 /* Note : if silent is true, then subtitle would not be displayed. :*/
14800 int _mmplayer_set_subtitle_silent (MMHandleType hplayer, int silent)
14802 mm_player_t* player = (mm_player_t*) hplayer;
14806 /* check player handle */
14807 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED );
14809 player->set_mode.subtitle_off = silent;
14811 debug_log("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
14815 return MM_ERROR_NONE;
14818 int _mmplayer_remove_audio_parser_decoder(mm_player_t* player,GstPad *inpad)
14820 int result = MM_ERROR_NONE;
14821 GstPad *peer = NULL,*pad = NULL;
14822 GstElement *Element = NULL;
14823 MMPlayerGstElement* mainbin = NULL;
14824 mainbin = player->pipeline->mainbin;
14827 if(!gst_pad_set_blocked(inpad,TRUE))
14829 result = MM_ERROR_PLAYER_INTERNAL;
14833 gst_pad_add_probe(inpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
14836 /*Getting pad connected to demuxer audio pad */
14837 peer = gst_pad_get_peer(inpad);
14838 /* Disconnecting Demuxer and its peer plugin [audio] */
14841 if(!gst_pad_unlink(inpad,peer))
14843 result = MM_ERROR_PLAYER_INTERNAL;
14849 result = MM_ERROR_PLAYER_INTERNAL;
14852 /*Removing elements between Demuxer and audiobin*/
14853 while(peer != NULL)
14855 gchar *Element_name = NULL;
14856 gchar *factory_name = NULL;
14857 GList *elements = NULL;
14858 GstElementFactory *factory = NULL;
14859 /*Getting peer element*/
14860 Element = gst_pad_get_parent_element(peer);
14861 if(Element == NULL)
14863 gst_object_unref(peer);
14864 result = MM_ERROR_PLAYER_INTERNAL;
14868 Element_name = gst_element_get_name(Element);
14869 factory = gst_element_get_factory(Element);
14870 /*checking the element is audio bin*/
14871 if(!strcmp(Element_name,"audiobin"))
14873 gst_object_unref(peer);
14874 result = MM_ERROR_NONE;
14875 g_free(Element_name);
14878 factory_name = GST_OBJECT_NAME(factory);
14879 pad = gst_element_get_static_pad(Element,"src");
14882 result = MM_ERROR_PLAYER_INTERNAL;
14883 g_free(Element_name);
14886 gst_object_unref(peer);
14887 peer = gst_pad_get_peer(pad);
14890 if(!gst_pad_unlink(pad,peer))
14892 gst_object_unref(peer);
14893 gst_object_unref(pad);
14894 result = MM_ERROR_PLAYER_INTERNAL;
14895 g_free(Element_name);
14899 elements = player->parsers;
14900 /* Removing the element form the list*/
14901 for ( ; elements; elements = g_list_next(elements))
14903 Element_name = elements->data;
14904 if(g_strrstr(Element_name,factory_name))
14906 player->parsers = g_list_remove(player->parsers,elements->data);
14909 gst_element_set_state(Element,GST_STATE_NULL);
14910 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst),Element);
14911 gst_object_unref(pad);
14912 if(Element == mainbin[MMPLAYER_M_Q1].gst)
14914 mainbin[MMPLAYER_M_Q1].gst = NULL;
14916 else if(Element == mainbin[MMPLAYER_M_Q2].gst)
14918 mainbin[MMPLAYER_M_Q2].gst = NULL;
14920 else if(Element == mainbin[MMPLAYER_M_DEC1].gst)
14922 mainbin[MMPLAYER_M_DEC1].gst = NULL;
14924 else if(Element == mainbin[MMPLAYER_M_DEC2].gst)
14926 mainbin[MMPLAYER_M_DEC2].gst = NULL;
14928 gst_object_unref(Element);
14934 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
14936 MMPlayerGstElement* mainbin = NULL;
14937 MMPlayerGstElement* textbin = NULL;
14938 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
14939 GstState current_state = GST_STATE_VOID_PENDING;
14940 GstState element_state = GST_STATE_VOID_PENDING;
14941 GstState element_pending_state = GST_STATE_VOID_PENDING;
14943 GstEvent *event = NULL;
14944 int result = MM_ERROR_NONE;
14946 GstClock *curr_clock = NULL;
14947 GstClockTime base_time, start_time, curr_time;
14952 /* check player handle */
14953 return_val_if_fail ( player && player->pipeline , MM_ERROR_PLAYER_NOT_INITIALIZED);
14955 if (!(player->pipeline->mainbin) || !(player->pipeline->textbin))
14957 debug_error("Pipeline is not in proper state\n");
14958 result = MM_ERROR_PLAYER_NOT_INITIALIZED;
14962 mainbin = player->pipeline->mainbin;
14963 textbin = player->pipeline->textbin;
14965 current_state = GST_STATE (mainbin[MMPLAYER_M_PIPE].gst);
14967 // sync clock with current pipeline
14968 curr_clock = GST_ELEMENT_CLOCK (player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
14969 curr_time = gst_clock_get_time (curr_clock);
14971 base_time = gst_element_get_base_time (GST_ELEMENT_CAST (player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
14972 start_time = gst_element_get_start_time (GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
14974 debug_log ("base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
14975 GST_TIME_ARGS (base_time), GST_TIME_ARGS (start_time), GST_TIME_ARGS (curr_time));
14977 if (current_state > GST_STATE_READY)
14979 // sync state with current pipeline
14980 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
14981 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
14982 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
14984 ret = gst_element_get_state (mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
14985 if ( GST_STATE_CHANGE_FAILURE == ret )
14987 debug_error("fail to state change.\n");
14991 gst_element_set_base_time (textbin[MMPLAYER_T_BIN].gst, base_time);
14992 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
14996 gst_element_set_clock (textbin[MMPLAYER_T_BIN].gst, curr_clock);
14997 gst_object_unref (curr_clock);
15000 // seek to current position
15001 if (!gst_element_query_position (mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time))
15003 result = MM_ERROR_PLAYER_INVALID_STATE;
15004 debug_error("gst_element_query_position failed, invalid state\n");
15008 debug_log("seek time = %lld\n", time);
15009 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);
15012 __gst_send_event_to_sink(player, event);
15016 result = MM_ERROR_PLAYER_INTERNAL;
15017 debug_error("gst_event_new_seek failed\n");
15021 // sync state with current pipeline
15022 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
15023 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
15024 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
15031 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
15033 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
15034 GstState current_state = GST_STATE_VOID_PENDING;
15036 MMHandleType attrs = 0;
15037 MMPlayerGstElement* mainbin = NULL;
15038 MMPlayerGstElement* textbin = NULL;
15040 gchar* subtitle_uri = NULL;
15041 int result = MM_ERROR_NONE;
15042 const gchar *charset = NULL;
15046 /* check player handle */
15047 return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
15048 return_val_if_fail( filepath, MM_ERROR_COMMON_INVALID_ARGUMENT );
15050 if (!(player->pipeline) || !(player->pipeline->mainbin))
15052 result = MM_ERROR_PLAYER_INVALID_STATE;
15053 debug_error("Pipeline is not in proper state\n");
15057 mainbin = player->pipeline->mainbin;
15058 textbin = player->pipeline->textbin;
15060 current_state = GST_STATE (mainbin[MMPLAYER_M_PIPE].gst);
15061 if (current_state < GST_STATE_READY)
15063 result = MM_ERROR_PLAYER_INVALID_STATE;
15064 debug_error("Pipeline is not in proper state\n");
15068 attrs = MMPLAYER_GET_ATTRS(player);
15071 debug_error("cannot get content attribute\n");
15072 result = MM_ERROR_PLAYER_INTERNAL;
15076 mm_attrs_get_string_by_name (attrs, "subtitle_uri", &subtitle_uri);
15077 if (!subtitle_uri || strlen(subtitle_uri) < 1)
15079 debug_error("subtitle uri is not proper filepath\n");
15080 result = MM_ERROR_PLAYER_INVALID_URI;
15084 debug_log("old subtitle file path is [%s]\n", subtitle_uri);
15085 debug_log("new subtitle file path is [%s]\n", filepath);
15087 if (!strcmp (filepath, subtitle_uri))
15089 debug_log("No need to swtich subtitle, as input filepath is same as current filepath\n");
15094 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
15095 if (mmf_attrs_commit(player->attrs))
15097 debug_error("failed to commit.\n");
15102 //gst_pad_set_blocked_async(src-srcpad, TRUE)
15104 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
15105 if (ret != GST_STATE_CHANGE_SUCCESS)
15107 debug_error("failed to change state of textbin to READY");
15108 result = MM_ERROR_PLAYER_INTERNAL;
15112 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
15113 if (ret != GST_STATE_CHANGE_SUCCESS)
15115 debug_error("failed to change state of subparse to READY");
15116 result = MM_ERROR_PLAYER_INTERNAL;
15120 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
15121 if (ret != GST_STATE_CHANGE_SUCCESS)
15123 debug_error("failed to change state of filesrc to READY");
15124 result = MM_ERROR_PLAYER_INTERNAL;
15128 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
15130 charset = util_get_charset(filepath);
15133 debug_log ("detected charset is %s\n", charset );
15134 g_object_set (G_OBJECT (mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
15137 result = _mmplayer_sync_subtitle_pipeline(player);
15144 /* API to switch between external subtitles */
15145 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
15147 int result = MM_ERROR_NONE;
15148 mm_player_t* player = (mm_player_t*)hplayer;
15152 /* check player handle */
15153 return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
15155 if (!player->pipeline) // IDLE state
15157 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
15158 if (mmf_attrs_commit(player->attrs))
15160 debug_error("failed to commit.\n");
15161 result= MM_ERROR_PLAYER_INTERNAL;
15164 else // curr state <> IDLE (READY, PAUSE, PLAYING..)
15166 if ( filepath == NULL )
15167 return MM_ERROR_COMMON_INVALID_ARGUMENT;
15169 if (!__mmplayer_check_subtitle(player))
15171 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
15172 if (mmf_attrs_commit(player->attrs))
15174 debug_error("failed to commit.\n");
15175 result = MM_ERROR_PLAYER_INTERNAL;
15178 if ( MM_ERROR_NONE != __mmplayer_gst_create_subtitle_src(player) )
15179 debug_error("fail to create subtitle src\n");
15181 result = _mmplayer_sync_subtitle_pipeline(player);
15185 result = __mmplayer_change_external_subtitle_language(player, filepath);
15194 __mmplayer_change_selector_pad (mm_player_t* player, MMPlayerTrackType type, int index)
15196 int result = MM_ERROR_NONE;
15197 gchar* change_pad_name = NULL;
15198 GstPad* sinkpad = NULL;
15199 MMPlayerGstElement* mainbin = NULL;
15200 enum MainElementID elemId = MMPLAYER_M_NUM;
15201 GstCaps* caps = NULL;
15202 gint total_track_num = 0;
15206 return_val_if_fail (player && player->pipeline && player->pipeline->mainbin,
15207 MM_ERROR_PLAYER_NOT_INITIALIZED);
15209 debug_log ("Change Track(%d) to %d\n", type, index);
15211 mainbin = player->pipeline->mainbin;
15213 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
15215 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
15217 else if (type == MM_PLAYER_TRACK_TYPE_TEXT)
15219 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
15223 debug_error ("Track Type Error\n");
15227 if (mainbin[elemId].gst == NULL)
15229 result = MM_ERROR_PLAYER_NO_OP;
15230 debug_log ("Req track doesn't exist\n");
15234 total_track_num = player->selector[type].total_track_num;
15235 if (total_track_num <= 0)
15237 result = MM_ERROR_PLAYER_NO_OP;
15238 debug_log ("Language list is not available \n");
15242 if ((index < 0) || (index >= total_track_num))
15244 result = MM_ERROR_INVALID_ARGUMENT;
15245 debug_log ("Not a proper index : %d \n", index);
15249 /*To get the new pad from the selector*/
15250 change_pad_name = g_strdup_printf ("sink_%u", index);
15251 if (change_pad_name == NULL)
15253 result = MM_ERROR_PLAYER_INTERNAL;
15254 debug_log ("Pad does not exists\n");
15258 debug_log ("new active pad name: %s\n", change_pad_name);
15260 sinkpad = gst_element_get_static_pad (mainbin[elemId].gst, change_pad_name);
15261 if (sinkpad == NULL)
15263 debug_log ("sinkpad is NULL");
15264 result = MM_ERROR_PLAYER_INTERNAL;
15268 debug_log ("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
15269 g_object_set (mainbin[elemId].gst, "active-pad", sinkpad, NULL);
15271 caps = gst_pad_get_current_caps(sinkpad);
15272 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
15275 gst_object_unref (sinkpad);
15277 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
15279 __mmplayer_set_audio_attrs (player, caps);
15284 MMPLAYER_FREEIF(change_pad_name);
15288 int _mmplayer_change_track_language (MMHandleType hplayer, MMPlayerTrackType type, int index)
15290 int result = MM_ERROR_NONE;
15291 mm_player_t* player = NULL;
15292 MMPlayerGstElement* mainbin = NULL;
15294 gint current_active_index = 0;
15296 GstState current_state = GST_STATE_VOID_PENDING;
15297 GstEvent* event = NULL;
15302 player = (mm_player_t*)hplayer;
15303 return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED);
15305 if (!player->pipeline)
15307 debug_error ("Track %d pre setting -> %d\n", type, index);
15309 player->selector[type].active_pad_index = index;
15313 mainbin = player->pipeline->mainbin;
15315 current_active_index = player->selector[type].active_pad_index;
15317 /*If index is same as running index no need to change the pad*/
15318 if (current_active_index == index)
15323 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time))
15325 result = MM_ERROR_PLAYER_INVALID_STATE;
15329 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
15330 if (current_state < GST_STATE_PAUSED)
15332 result = MM_ERROR_PLAYER_INVALID_STATE;
15333 debug_warning ("Pipeline not in porper state\n");
15337 result = __mmplayer_change_selector_pad(player, type, index);
15338 if (result != MM_ERROR_NONE)
15340 debug_error ("change selector pad error\n");
15344 player->selector[type].active_pad_index = index;
15346 if (current_state == GST_STATE_PLAYING)
15348 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);
15351 __gst_send_event_to_sink (player, event);
15355 result = MM_ERROR_PLAYER_INTERNAL;
15364 int _mmplayer_get_subtitle_silent (MMHandleType hplayer, int* silent)
15366 mm_player_t* player = (mm_player_t*) hplayer;
15370 /* check player handle */
15371 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED );
15373 *silent = player->set_mode.subtitle_off;
15375 debug_log("subtitle is %s.\n", silent ? "ON" : "OFF");
15379 return MM_ERROR_NONE;
15383 __is_es_buff_src( mm_player_t* player )
15385 return_val_if_fail ( player, FALSE );
15387 return ( player->profile.uri_type == MM_PLAYER_URI_TYPE_ES_BUFF) ? TRUE : FALSE;
15391 __has_suffix(mm_player_t* player, const gchar* suffix)
15393 return_val_if_fail( player, FALSE );
15394 return_val_if_fail( suffix, FALSE );
15396 gboolean ret = FALSE;
15397 gchar* t_url = g_ascii_strdown(player->profile.uri, -1);
15398 gchar* t_suffix = g_ascii_strdown(suffix, -1);
15400 if ( g_str_has_suffix(player->profile.uri, suffix) )
15405 MMPLAYER_FREEIF(t_url);
15406 MMPLAYER_FREEIF(t_suffix);
15412 _mmplayer_set_display_zoom(MMHandleType hplayer, float level, int x, int y)
15414 mm_player_t* player = (mm_player_t*) hplayer;
15416 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
15418 MMPLAYER_VIDEO_SINK_CHECK(player);
15420 debug_log("setting display zoom level = %f, offset = %d, %d", level, x, y);
15422 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "zoom", level, "zoom-pos-x", x, "zoom-pos-y", y, NULL);
15424 return MM_ERROR_NONE;
15427 _mmplayer_get_display_zoom(MMHandleType hplayer, float *level, int *x, int *y)
15430 mm_player_t* player = (mm_player_t*) hplayer;
15431 float _level = 0.0;
15435 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
15437 MMPLAYER_VIDEO_SINK_CHECK(player);
15439 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "zoom", &_level, "zoom-pos-x", &_x, "zoom-pos-y", &_y, NULL);
15441 debug_log("display zoom level = %f, start off x = %d, y = %d", _level, _x, _y);
15447 return MM_ERROR_NONE;
15451 _mmplayer_set_video_hub_download_mode(MMHandleType hplayer, bool mode)
15453 mm_player_t* player = (mm_player_t*) hplayer;
15455 return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED);
15457 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL)
15459 MMPLAYER_PRINT_STATE(player);
15460 debug_error("wrong-state : can't set the download mode to parse");
15461 return MM_ERROR_PLAYER_INVALID_STATE;
15464 debug_log("set video hub download mode to %s", (mode)?"ON":"OFF");
15465 player->video_hub_download_mode = mode;
15467 return MM_ERROR_NONE;
15471 _mmplayer_enable_sync_handler(MMHandleType hplayer, bool enable)
15473 mm_player_t* player = (mm_player_t*) hplayer;
15475 return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED);
15477 debug_log("enable sync handler : %s", (enable)?"ON":"OFF");
15478 player->sync_handler = enable;
15480 return MM_ERROR_NONE;
15484 _mmplayer_set_video_share_master_clock( MMHandleType hplayer,
15486 long long clock_delta,
15487 long long video_time,
15488 long long media_clock,
15489 long long audio_time)
15491 mm_player_t* player = (mm_player_t*) hplayer;
15492 MMPlayerGstElement* mainbin = NULL;
15493 GstClockTime start_time_audio = 0, start_time_video = 0;
15494 GstClockTimeDiff base_time = 0, new_base_time = 0;
15495 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
15496 gint64 api_delta = 0;
15497 gint64 position = 0, position_delta = 0;
15498 gint64 adj_base_time = 0;
15499 GstClock *curr_clock = NULL;
15500 GstClockTime curr_time = 0;
15501 gboolean query_ret = TRUE;
15502 int result = MM_ERROR_NONE;
15506 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
15507 return_val_if_fail ( player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
15508 return_val_if_fail ( player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
15510 // debug_log("in(us) : %lld, %lld, %lld, %lld, %lld", clock, clock_delta, video_time, media_clock, audio_time);
15512 if ((video_time < 0) || (player->doing_seek))
15514 debug_log("skip setting master clock. %lld", video_time);
15518 mainbin = player->pipeline->mainbin;
15520 curr_clock = gst_pipeline_get_clock (GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
15521 curr_time = gst_clock_get_time (curr_clock);
15523 current_state = MMPLAYER_CURRENT_STATE(player);
15525 if ( current_state == MM_PLAYER_STATE_PLAYING )
15526 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
15528 if ( ( current_state != MM_PLAYER_STATE_PLAYING ) ||
15531 position = player->last_position;
15532 debug_log ("query fail. %lld", position);
15535 clock*= GST_USECOND;
15536 clock_delta *= GST_USECOND;
15538 api_delta = clock - curr_time;
15539 if ((player->video_share_api_delta == 0 ) || (player->video_share_api_delta > api_delta))
15541 player->video_share_api_delta = api_delta;
15545 clock_delta += (api_delta - player->video_share_api_delta);
15548 if ((player->video_share_clock_delta == 0 ) || (player->video_share_clock_delta > clock_delta))
15550 player->video_share_clock_delta = (gint64)clock_delta;
15552 position_delta = (position/GST_USECOND) - video_time;
15553 position_delta *= GST_USECOND;
15555 adj_base_time = position_delta;
15556 debug_log ("video_share_clock_delta = %lld, adj = %lld", player->video_share_clock_delta, adj_base_time);
15561 gint64 new_play_time = 0;
15562 gint64 network_delay =0;
15564 video_time *= GST_USECOND;
15566 network_delay = clock_delta - player->video_share_clock_delta;
15567 new_play_time = video_time + network_delay;
15569 adj_base_time = position - new_play_time;
15571 debug_log ("%lld(delay) = %lld - %lld / %lld(adj) = %lld(slave_pos) - %lld(master_pos) - %lld(delay)",
15572 network_delay, clock_delta, player->video_share_clock_delta, adj_base_time, position, video_time, network_delay);
15575 /* Adjust Current Stream Time with base_time of sink
15576 * 1. Set Start time to CLOCK NONE, to control the base time by MSL
15577 * 2. Set new base time
15578 * if adj_base_time is positive value, the stream time will be decreased.
15579 * 3. If seek event is occurred, the start time will be reset. */
15580 if ((player->pipeline->audiobin) &&
15581 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst))
15583 start_time_audio = gst_element_get_start_time (player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
15585 if (start_time_audio != GST_CLOCK_TIME_NONE)
15587 debug_log ("audio sink : gst_element_set_start_time -> NONE");
15588 gst_element_set_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, GST_CLOCK_TIME_NONE);
15591 base_time = gst_element_get_base_time (player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
15594 if ((player->pipeline->videobin) &&
15595 (player->pipeline->videobin[MMPLAYER_V_SINK].gst))
15597 start_time_video = gst_element_get_start_time (player->pipeline->videobin[MMPLAYER_V_SINK].gst);
15599 if (start_time_video != GST_CLOCK_TIME_NONE)
15601 debug_log ("video sink : gst_element_set_start_time -> NONE");
15602 gst_element_set_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst, GST_CLOCK_TIME_NONE);
15605 // if videobin exist, get base_time from videobin.
15606 base_time = gst_element_get_base_time (player->pipeline->videobin[MMPLAYER_V_SINK].gst);
15609 new_base_time = base_time + adj_base_time;
15611 if ((player->pipeline->audiobin) &&
15612 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst))
15613 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), (GstClockTime)new_base_time);
15615 if ((player->pipeline->videobin) &&
15616 (player->pipeline->videobin[MMPLAYER_V_SINK].gst))
15617 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), (GstClockTime)new_base_time);
15626 _mmplayer_get_video_share_master_clock( MMHandleType hplayer,
15627 long long *video_time,
15628 long long *media_clock,
15629 long long *audio_time)
15631 mm_player_t* player = (mm_player_t*) hplayer;
15632 MMPlayerGstElement* mainbin = NULL;
15633 GstClock *curr_clock = NULL;
15634 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
15635 gint64 position = 0;
15636 gboolean query_ret = TRUE;
15640 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
15641 return_val_if_fail ( player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
15642 return_val_if_fail ( player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
15644 return_val_if_fail ( video_time, MM_ERROR_COMMON_INVALID_ARGUMENT );
15645 return_val_if_fail ( media_clock, MM_ERROR_COMMON_INVALID_ARGUMENT );
15646 return_val_if_fail ( audio_time, MM_ERROR_COMMON_INVALID_ARGUMENT );
15648 mainbin = player->pipeline->mainbin;
15650 curr_clock = gst_pipeline_get_clock (GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
15652 current_state = MMPLAYER_CURRENT_STATE(player);
15654 if ( current_state != MM_PLAYER_STATE_PAUSED )
15655 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
15657 if ( ( current_state == MM_PLAYER_STATE_PAUSED ) ||
15660 position = player->last_position;
15663 *media_clock = *video_time = *audio_time = (position/GST_USECOND);
15665 debug_log("media_clock: %lld, video_time: %lld (us)", *media_clock, *video_time);
15668 gst_object_unref (curr_clock);
15672 return MM_ERROR_NONE;
15676 _mmplayer_get_video_rotate_angle(MMHandleType hplayer, int *angle)
15678 mm_player_t* player = (mm_player_t*) hplayer;
15683 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
15684 return_val_if_fail ( angle, MM_ERROR_COMMON_INVALID_ARGUMENT );
15686 if (player->v_stream_caps)
15688 GstStructure *str = NULL;
15690 str = gst_caps_get_structure (player->v_stream_caps, 0);
15691 if ( !gst_structure_get_int (str, "orientation", &org_angle))
15693 debug_log ("missing 'orientation' field in video caps");
15697 debug_log("orientation: %d", org_angle);
15698 *angle = org_angle;
15701 return MM_ERROR_NONE;
15705 __mmplayer_is_streaming(mm_player_t* player)
15707 gboolean result = FALSE;
15711 return_val_if_fail (player, FALSE);
15712 result = __is_streaming (player) ;
15719 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
15721 return_val_if_fail (player, FALSE);
15722 return_val_if_fail (element, FALSE);
15724 gchar *factory_name = GST_OBJECT_NAME (gst_element_get_factory(element));
15725 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
15729 for ( idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++ )
15731 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx]))
15733 debug_log("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
15734 mm_player_dump_t *dump_s;
15735 dump_s = g_malloc (sizeof(mm_player_dump_t));
15737 if (dump_s == NULL)
15739 debug_error ("malloc fail");
15743 dump_s->dump_element_file = NULL;
15744 dump_s->dump_pad = NULL;
15745 dump_s->dump_pad = gst_element_get_static_pad (element, "sink");
15747 if (dump_s->dump_pad)
15749 memset (dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
15750 sprintf (dump_file_name, "%s/%s_sink_pad.dump", player->ini.dump_element_path, player->ini.dump_element_keyword[idx]);
15751 dump_s->dump_element_file = fopen(dump_file_name,"w+");
15752 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);
15753 /* add list for removed buffer probe and close FILE */
15754 player->dump_list = g_list_append (player->dump_list, dump_s);
15755 debug_log ("%s sink pad added buffer probe for dump", factory_name);
15762 debug_error ("failed to get %s sink pad added", factory_name);
15771 static GstPadProbeReturn
15772 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
15774 FILE *dump_data = (FILE *) u_data;
15775 // int written = 0;
15776 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
15777 GstMapInfo probe_info = GST_MAP_INFO_INIT;
15779 return_val_if_fail ( dump_data, FALSE );
15781 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
15783 // debug_log ("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS( GST_BUFFER_TIMESTAMP(buffer)));
15785 fwrite ( probe_info.data, 1, probe_info.size , dump_data);
15787 return GST_PAD_PROBE_OK;
15791 __mmplayer_release_dump_list (GList *dump_list)
15795 GList *d_list = dump_list;
15796 for ( ;d_list ; d_list = g_list_next(d_list))
15798 mm_player_dump_t *dump_s = d_list->data;
15799 if (dump_s->dump_pad)
15801 if (dump_s->probe_handle_id)
15803 gst_pad_remove_probe (dump_s->dump_pad, dump_s->probe_handle_id);
15807 if (dump_s->dump_element_file)
15809 fclose(dump_s->dump_element_file);
15810 dump_s->dump_element_file = NULL;
15812 MMPLAYER_FREEIF(dump_s);
15814 g_list_free(dump_list);
15820 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
15822 mm_player_t* player = (mm_player_t*) hplayer;
15826 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
15827 return_val_if_fail ( exist, MM_ERROR_INVALID_ARGUMENT );
15829 *exist = player->has_closed_caption;
15833 return MM_ERROR_NONE;
15837 _mmplayer_enable_media_packet_video_stream(MMHandleType hplayer, bool enable)
15839 mm_player_t* player = (mm_player_t*) hplayer;
15843 return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED);
15844 return_val_if_fail (enable == TRUE || enable == FALSE, MM_ERROR_INVALID_ARGUMENT);
15846 player->bufmgr = tbm_bufmgr_init(-1);
15848 tbm_bufmgr_deinit(player->bufmgr);
15849 player->bufmgr = NULL;
15852 player->set_mode.media_packet_video_stream = enable;
15856 return MM_ERROR_NONE;
15859 void * _mm_player_media_packet_video_stream_internal_buffer_ref(void *buffer)
15863 /* increase ref count of gst buffer */
15865 ret = gst_buffer_ref((GstBuffer *)buffer);
15871 void _mm_player_media_packet_video_stream_internal_buffer_unref(void *buffer)
15875 gst_buffer_unref((GstBuffer *)buffer);
15882 __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data)
15884 mm_player_t *player = (mm_player_t*)user_data;
15885 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
15887 return_if_fail ( player );
15889 debug_msg("app-src: feed audio\n");
15891 if (player->media_stream_buffer_status_cb[type])
15893 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, player->buffer_cb_user_param);
15898 __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data)
15900 mm_player_t *player = (mm_player_t*)user_data;
15901 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
15903 return_if_fail ( player );
15905 debug_msg("app-src: feed video\n");
15907 if (player->media_stream_buffer_status_cb[type])
15909 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, player->buffer_cb_user_param);
15914 __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data)
15916 mm_player_t *player = (mm_player_t*)user_data;
15917 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
15919 return_if_fail ( player );
15921 debug_msg("app-src: feed subtitle\n");
15923 if (player->media_stream_buffer_status_cb[type])
15925 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, player->buffer_cb_user_param);
15930 __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data)
15932 mm_player_t *player = (mm_player_t*)user_data;
15933 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
15935 return_if_fail ( player );
15937 debug_msg("app-src: audio buffer is full.\n");
15939 if (player->media_stream_buffer_status_cb[type])
15941 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, player->buffer_cb_user_param);
15946 __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data)
15948 mm_player_t *player = (mm_player_t*)user_data;
15949 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
15951 return_if_fail ( player );
15953 debug_msg("app-src: video buffer is full.\n");
15955 if (player->media_stream_buffer_status_cb[type])
15957 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, player->buffer_cb_user_param);
15962 __gst_seek_audio_data (GstElement * appsrc, guint64 position, gpointer user_data)
15964 mm_player_t *player = (mm_player_t*)user_data;
15965 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
15967 return_val_if_fail( player, FALSE );
15969 debug_log("app-src: seek audio data\n");
15971 if (player->media_stream_seek_data_cb[type])
15973 player->media_stream_seek_data_cb[type](type, position, player->buffer_cb_user_param);
15980 __gst_seek_video_data (GstElement * appsrc, guint64 position, gpointer user_data)
15982 mm_player_t *player = (mm_player_t*)user_data;
15983 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
15985 return_val_if_fail( player, FALSE );
15987 debug_log("app-src: seek video data\n");
15989 if (player->media_stream_seek_data_cb[type])
15991 player->media_stream_seek_data_cb[type](type, position, player->buffer_cb_user_param);
15998 __gst_seek_subtitle_data (GstElement * appsrc, guint64 position, gpointer user_data)
16000 mm_player_t *player = (mm_player_t*)user_data;
16001 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
16003 return_val_if_fail( player, FALSE );
16005 debug_log("app-src: seek subtitle data\n");
16007 if (player->media_stream_seek_data_cb[type])
16009 player->media_stream_seek_data_cb[type](type, position, player->buffer_cb_user_param);
16016 _mmplayer_set_pcm_spec(MMHandleType hplayer, int samplerate, int channel)
16018 mm_player_t* player = (mm_player_t*) hplayer;
16022 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
16024 player->pcm_samplerate = samplerate;
16025 player->pcm_channel = channel;
16028 return MM_ERROR_NONE;
16031 int _mmplayer_get_raw_video_caps(mm_player_t *player, char **caps)
16033 GstCaps *v_caps = NULL;
16034 GstPad *pad = NULL;
16038 if(!player->videosink_linked) {
16039 debug_log("No video sink");
16040 return MM_ERROR_NONE;
16042 mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &stype);
16044 if (stype == MM_DISPLAY_SURFACE_NULL) {
16045 debug_log("Display type is NULL");
16046 if(!player->video_fakesink) {
16047 debug_error("No fakesink");
16048 return MM_ERROR_PLAYER_INVALID_STATE;
16050 gst = player->video_fakesink;
16053 if ( !player->pipeline || !player->pipeline->videobin ||
16054 !player->pipeline->videobin[MMPLAYER_V_SINK].gst ) {
16055 debug_error("No video pipeline");
16056 return MM_ERROR_PLAYER_INVALID_STATE;
16058 gst = player->pipeline->videobin[MMPLAYER_V_SINK].gst;
16060 pad = gst_element_get_static_pad(gst, "sink");
16062 debug_error("static pad is NULL");
16063 return MM_ERROR_PLAYER_INVALID_STATE;
16065 v_caps = gst_pad_get_current_caps(pad);
16066 gst_object_unref( pad );
16069 debug_error("fail to get caps");
16070 return MM_ERROR_PLAYER_INVALID_STATE;
16073 *caps = gst_caps_to_string(v_caps);
16075 gst_caps_unref(v_caps);
16077 return MM_ERROR_NONE;