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_sound_focus.h>
49 #include "mm_player_priv.h"
50 #include "mm_player_ini.h"
51 #include "mm_player_attrs.h"
52 #include "mm_player_capture.h"
53 #include "mm_player_utils.h"
54 #include "mm_player_tracks.h"
56 /*===========================================================================================
58 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
60 ========================================================================================== */
62 /*---------------------------------------------------------------------------
63 | GLOBAL CONSTANT DEFINITIONS: |
64 ---------------------------------------------------------------------------*/
66 /*---------------------------------------------------------------------------
67 | IMPORTED VARIABLE DECLARATIONS: |
68 ---------------------------------------------------------------------------*/
70 /*---------------------------------------------------------------------------
71 | IMPORTED FUNCTION DECLARATIONS: |
72 ---------------------------------------------------------------------------*/
74 /*---------------------------------------------------------------------------
76 ---------------------------------------------------------------------------*/
77 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
78 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
80 #define MM_VOLUME_FACTOR_DEFAULT 1.0
81 #define MM_VOLUME_FACTOR_MIN 0
82 #define MM_VOLUME_FACTOR_MAX 1.0
84 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 700000 // 700 msec
86 #define MM_PLAYER_MPEG_VNAME "mpegversion"
87 #define MM_PLAYER_DIVX_VNAME "divxversion"
88 #define MM_PLAYER_WMV_VNAME "wmvversion"
89 #define MM_PLAYER_WMA_VNAME "wmaversion"
91 #define DEFAULT_PLAYBACK_RATE 1.0
92 #define PLAYBACK_RATE_EX_AUDIO_MIN 0.5
93 #define PLAYBACK_RATE_EX_AUDIO_MAX 2.0
94 #define PLAYBACK_RATE_EX_VIDEO_MIN 0.5
95 #define PLAYBACK_RATE_EX_VIDEO_MAX 1.5
97 #define GST_QUEUE_DEFAULT_TIME 4
98 #define GST_QUEUE_HLS_TIME 8
100 #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) )
101 #define MM_PLAYER_NAME "mmplayer"
103 /*---------------------------------------------------------------------------
104 | LOCAL CONSTANT DEFINITIONS: |
105 ---------------------------------------------------------------------------*/
107 /*---------------------------------------------------------------------------
108 | LOCAL DATA TYPE DEFINITIONS: |
109 ---------------------------------------------------------------------------*/
111 /*---------------------------------------------------------------------------
112 | GLOBAL VARIABLE DEFINITIONS: |
113 ---------------------------------------------------------------------------*/
115 /*---------------------------------------------------------------------------
116 | LOCAL VARIABLE DEFINITIONS: |
117 ---------------------------------------------------------------------------*/
119 /*---------------------------------------------------------------------------
120 | LOCAL FUNCTION PROTOTYPES: |
121 ---------------------------------------------------------------------------*/
122 static int __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps *caps, MMDisplaySurfaceType surface_type);
123 static int __mmplayer_gst_create_audio_pipeline(mm_player_t* player);
124 static int __mmplayer_gst_create_text_pipeline(mm_player_t* player);
125 static int __mmplayer_gst_create_subtitle_src(mm_player_t* player);
126 static int __mmplayer_gst_create_pipeline(mm_player_t* player);
127 static int __mmplayer_gst_destroy_pipeline(mm_player_t* player);
128 static int __mmplayer_gst_element_link_bucket(GList* element_bucket);
130 static GstPadProbeReturn __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data);
131 static void __mmplayer_gst_decode_pad_added(GstElement* elem, GstPad* pad, gpointer data);
132 static void __mmplayer_gst_decode_no_more_pads(GstElement* elem, gpointer data);
133 static void __mmplayer_gst_decode_callback(GstElement *decodebin, GstPad *pad, gpointer data);
134 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad, GstCaps *caps, gpointer data);
135 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad, GstCaps * caps, gpointer data);
136 static gint __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad, GstCaps * caps, GstElementFactory* factory, gpointer data);
137 //static GValueArray* __mmplayer_gst_decode_autoplug_factories(GstElement *bin, GstPad* pad, GstCaps * caps, gpointer data);
138 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad, gpointer data);
139 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
140 static void __mmplayer_gst_element_added(GstElement* bin, GstElement* element, gpointer data);
141 static GstElement * __mmplayer_create_decodebin(mm_player_t* player);
142 static gboolean __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps);
144 static void __mmplayer_typefind_have_type( GstElement *tf, guint probability, GstCaps *caps, gpointer data);
145 static gboolean __mmplayer_try_to_plug(mm_player_t* player, GstPad *pad, const GstCaps *caps);
146 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
147 static gboolean __mmplayer_is_midi_type(gchar* str_caps);
148 static gboolean __mmplayer_is_only_mp3_type (gchar *str_caps);
149 static void __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps);
150 //static void __mmplayer_check_video_zero_cpoy(mm_player_t* player, GstElementFactory* factory);
152 static gboolean __mmplayer_close_link(mm_player_t* player, GstPad *srcpad, GstElement *sinkelement, const char *padname, const GList *templlist);
153 static gboolean __mmplayer_feature_filter(GstPluginFeature *feature, gpointer data);
154 static void __mmplayer_add_new_pad(GstElement *element, GstPad *pad, gpointer data);
156 static void __mmplayer_gst_rtp_no_more_pads (GstElement *element, gpointer data);
157 //static void __mmplayer_gst_wfd_dynamic_pad (GstElement *element, GstPad *pad, gpointer data);
158 static void __mmplayer_gst_rtp_dynamic_pad (GstElement *element, GstPad *pad, gpointer data);
159 static gboolean __mmplayer_get_stream_service_type( mm_player_t* player );
160 static gboolean __mmplayer_update_subtitle( GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
163 static void __mmplayer_init_factories(mm_player_t* player);
164 static void __mmplayer_release_factories(mm_player_t* player);
165 static void __mmplayer_release_misc(mm_player_t* player);
166 static void __mmplayer_release_misc_post(mm_player_t* player);
167 static gboolean __mmplayer_init_gstreamer(mm_player_t* player);
168 static GstBusSyncReply __mmplayer_bus_sync_callback (GstBus * bus, GstMessage * message, gpointer data);
169 static gboolean __mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data);
171 static gboolean __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage *msg);
172 static gboolean __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg);
174 int __mmplayer_switch_audio_sink (mm_player_t* player);
175 static gboolean __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink);
176 static GstPadProbeReturn __mmplayer_audio_stream_probe (GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
177 static GstPadProbeReturn __mmplayer_video_stream_probe (GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
178 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe (GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
179 static int __mmplayer_change_selector_pad (mm_player_t* player, MMPlayerTrackType type, int index);
181 static gboolean __mmplayer_check_subtitle( mm_player_t* player );
182 static gboolean __mmplayer_handle_streaming_error ( mm_player_t* player, GstMessage * message );
183 static void __mmplayer_handle_eos_delay( mm_player_t* player, int delay_in_ms );
184 static void __mmplayer_cancel_eos_timer( mm_player_t* player );
185 static gboolean __mmplayer_eos_timer_cb(gpointer u_data);
186 static gboolean __mmplayer_link_decoder( mm_player_t* player,GstPad *srcpad);
187 static gboolean __mmplayer_link_sink( mm_player_t* player,GstPad *srcpad);
188 static int __mmplayer_handle_missed_plugin(mm_player_t* player);
189 static int __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime);
190 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player);
191 static void __mmplayer_add_sink( mm_player_t* player, GstElement* sink);
192 static void __mmplayer_del_sink( mm_player_t* player, GstElement* sink);
193 static void __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type);
194 static gpointer __mmplayer_next_play_thread(gpointer data);
195 static gpointer __mmplayer_repeat_thread(gpointer data);
196 static gboolean _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag);
199 static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element);
200 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
201 static void __mmplayer_release_dump_list (GList *dump_list);
203 static int __gst_realize(mm_player_t* player);
204 static int __gst_unrealize(mm_player_t* player);
205 static int __gst_start(mm_player_t* player);
206 static int __gst_stop(mm_player_t* player);
207 static int __gst_pause(mm_player_t* player, gboolean async);
208 static int __gst_resume(mm_player_t* player, gboolean async);
209 static gboolean __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
210 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
211 gint64 cur, GstSeekType stop_type, gint64 stop );
212 static int __gst_pending_seek ( mm_player_t* player );
214 static int __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called);
215 static int __gst_get_position(mm_player_t* player, int format, unsigned long *position);
216 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos);
217 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position);
218 static int __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param);
220 static gboolean __gst_send_event_to_sink( mm_player_t* player, GstEvent* event );
222 static int __mmplayer_set_pcm_extraction(mm_player_t* player);
223 static gboolean __mmplayer_can_extract_pcm( mm_player_t* player );
226 static void __mmplayer_do_sound_fadedown(mm_player_t* player, unsigned int time);
227 static void __mmplayer_undo_sound_fadedown(mm_player_t* player);
229 static void __mmplayer_add_new_caps(GstPad* pad, GParamSpec* unused, gpointer data);
230 static void __mmplayer_set_unlinked_mime_type(mm_player_t* player, GstCaps *caps);
233 static gboolean __is_es_buff_src(mm_player_t* player);
234 static gboolean __has_suffix(mm_player_t * player, const gchar * suffix);
236 static int __mmplayer_realize_streaming_ext(mm_player_t* player);
237 static int __mmplayer_unrealize_streaming_ext(mm_player_t *player);
238 static int __mmplayer_start_streaming_ext(mm_player_t *player);
239 static int __mmplayer_destroy_streaming_ext(mm_player_t* player);
240 static int __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay);
242 static gboolean __mmplayer_verify_next_play_path(mm_player_t *player);
243 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
244 static void __mmplayer_check_pipeline(mm_player_t* player);
245 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
246 static void __mmplayer_deactivate_old_path(mm_player_t *player);
247 #if 0 // We'll need this in future.
248 static int __mmplayer_gst_switching_element(mm_player_t *player, GstElement *search_from, const gchar *removal_name, const gchar *new_element_name);
251 static void __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg);
252 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name);
253 static gboolean __mmplayer_can_do_interrupt(mm_player_t *player);
255 /* device change post proc */
256 void __mmplayer_device_change_post_process(gpointer user);
257 void __mmplayer_set_required_cb_score(mm_player_t* player, guint score);
258 void __mmplayer_inc_cb_score(mm_player_t* player);
259 void __mmplayer_post_proc_reset(mm_player_t* player);
260 void __mmplayer_device_change_trigger_post_process(mm_player_t* player);
261 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player);
262 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name);
263 static void __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data);
264 static void __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data);
265 static void __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data);
266 static void __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data);
267 static void __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data);
268 static gboolean __gst_seek_audio_data (GstElement * appsrc, guint64 position, gpointer user_data);
269 static gboolean __gst_seek_video_data (GstElement * appsrc, guint64 position, gpointer user_data);
270 static gboolean __gst_seek_subtitle_data (GstElement * appsrc, guint64 position, gpointer user_data);
271 /*===========================================================================================
273 | FUNCTION DEFINITIONS |
275 ========================================================================================== */
279 print_tag (const GstTagList * list, const gchar * tag, gpointer unused)
283 count = gst_tag_list_get_tag_size (list, tag);
285 debug_log("count = %d", count);
287 for (i = 0; i < count; i++) {
290 if (gst_tag_get_type (tag) == G_TYPE_STRING) {
291 if (!gst_tag_list_get_string_index (list, tag, i, &str))
292 g_assert_not_reached ();
295 g_strdup_value_contents (gst_tag_list_get_value_index (list, tag, i));
299 g_print (" %15s: %s\n", gst_tag_get_nick (tag), str);
301 g_print (" : %s\n", str);
310 __mmplayer_videostream_cb(GstElement *element, void *data,
311 int width, int height, gpointer user_data) // @
313 mm_player_t* player = (mm_player_t*)user_data;
315 return_if_fail ( player );
319 if (player->is_drm_file)
321 MMMessageParamType msg_param = { 0, };
322 debug_warning("not supported in drm file");
323 msg_param.code = MM_ERROR_PLAYER_DRM_OUTPUT_PROTECTION;
324 MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param );
326 else if ( !player->set_mode.media_packet_video_stream && player->video_stream_cb)
328 MMPlayerVideoStreamDataType stream;
330 /* clear stream data structure */
331 memset(&stream, 0x0, sizeof(MMPlayerVideoStreamDataType));
333 stream.data[0] = data;
334 stream.length_total = width * height * 4; // for rgb 32bit
335 stream.height = height;
336 stream.width = width;
337 player->video_stream_cb(&stream, player->video_stream_cb_user_param);
344 __mmplayer_videoframe_render_error_cb(GstElement *element, void *error_id, gpointer data)
346 mm_player_t* player = (mm_player_t*)data;
348 return_if_fail ( player );
352 if (player->video_frame_render_error_cb )
356 int surface_type = 0;
357 mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &surface_type);
358 switch (surface_type)
360 case MM_DISPLAY_SURFACE_X_EXT:
361 player->video_frame_render_error_cb((unsigned int*)error_id, player->video_frame_render_error_cb_user_param);
362 debug_log("display surface type(X_EXT) : render error callback(%p) is finished", player->video_frame_render_error_cb);
365 debug_error("video_frame_render_error_cb was set, but this surface type(%d) is not supported", surface_type);
371 debug_error("could not get surface type");
376 debug_warning("video_frame_render_error_cb was not set");
383 __mmplayer_device_change_post_process(gpointer user)
385 mm_player_t* player = (mm_player_t*)user;
386 unsigned long position = 0;
387 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
388 MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
393 ! player->pipeline ||
394 ! player->pipeline->mainbin ||
395 ! player->pipeline->mainbin[MMPLAYER_M_PIPE].gst )
400 current_state = MMPLAYER_CURRENT_STATE(player);
401 pending_state = MMPLAYER_PENDING_STATE(player);
403 if (player->post_proc.need_pause_and_resume)
405 debug_log("pausing");
406 if ((pending_state == MM_PLAYER_STATE_PLAYING) ||
407 ((pending_state == MM_PLAYER_STATE_NONE) && (current_state != MM_PLAYER_STATE_PAUSED)))
408 gst_element_set_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED);
411 /* seek should be done within pause and resume */
412 if (player->post_proc.need_seek)
414 debug_log("seeking");
415 __gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position);
416 debug_log(">> seek to current position = %ld ms", position);
417 __gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, position, TRUE);
420 if (player->post_proc.need_pause_and_resume)
422 debug_log("resuming");
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_PLAYING);
429 if (player->post_proc.need_async)
431 debug_log("setting async");
433 /* TODO : need some comment here */
434 if (player->pipeline->textbin && player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst)
435 g_object_set (G_OBJECT (player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst), "async", TRUE, NULL);
440 __mmplayer_post_proc_reset(player);
444 void __mmplayer_set_required_cb_score(mm_player_t* player, guint score)
446 return_if_fail(player);
447 player->post_proc.required_cb_score = score;
448 debug_log("set required score to : %d", score);
451 void __mmplayer_inc_cb_score(mm_player_t* player)
453 return_if_fail(player);
454 player->post_proc.cb_score++;
455 debug_log("post proc cb score increased to %d", player->post_proc.cb_score);
458 void __mmplayer_post_proc_reset(mm_player_t* player)
460 return_if_fail(player);
462 /* check if already triggered */
463 if (player->post_proc.id)
465 /* TODO : need to consider multiple main context. !!!! */
466 if (FALSE == g_source_remove(player->post_proc.id) )
468 debug_error("failed to remove exist post_proc item");
470 player->post_proc.id = 0;
473 memset(&player->post_proc, 0, sizeof(mm_player_post_proc_t));
475 /* set default required cb score 1 as only audio device has changed in this case.
476 if display status is changed with audio device, required cb score is set 2 in display status callback.
477 this logic bases on the assumption which audio device callback is called after calling display status callback. */
478 player->post_proc.required_cb_score = 1;
482 __mmplayer_device_change_trigger_post_process(mm_player_t* player)
484 return_if_fail(player);
487 if ( player->post_proc.cb_score < player->post_proc.required_cb_score )
489 /* wait for next turn */
490 debug_log("wait for next turn. required cb score : %d current score : %d\n",
491 player->post_proc.required_cb_score, player->post_proc.cb_score);
495 /* check if already triggered */
496 if (player->post_proc.id)
498 /* TODO : need to consider multiple main context. !!!! */
499 if (FALSE == g_source_remove(player->post_proc.id) )
501 debug_error("failed to remove exist post_proc item");
503 player->post_proc.id = 0;
506 player->post_proc.id = g_idle_add((GSourceFunc)__mmplayer_device_change_post_process, (gpointer)player);
509 /* NOTE : Sound module has different latency according to output device So,
510 * synchronization problem can be happened whenever device is changed.
511 * To avoid this issue, we do reset avsystem or seek as workaroud.
514 __mmplayer_sound_device_info_changed_cb_func (MMSoundDevice_t device_h, int changed_info_type, void *user_data)
517 mm_sound_device_type_e device_type;
518 mm_player_t* player = (mm_player_t*) user_data;
520 return_if_fail( player );
522 debug_warning("device_info_changed_cb is called, device_h[0x%x], changed_info_type[%d]\n", device_h, changed_info_type);
524 __mmplayer_inc_cb_score(player);
526 /* get device type with device_h*/
527 ret = mm_sound_get_device_type(device_h, &device_type);
529 debug_error("failed to mm_sound_get_device_type()\n");
532 /* do pause and resume only if video is playing */
533 if ( player->videodec_linked && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING )
537 case MM_SOUND_DEVICE_TYPE_BLUETOOTH:
538 case MM_SOUND_DEVICE_TYPE_AUDIOJACK:
539 case MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER:
540 case MM_SOUND_DEVICE_TYPE_HDMI:
541 case MM_SOUND_DEVICE_TYPE_MIRRORING:
543 player->post_proc.need_pause_and_resume = TRUE;
548 debug_log("do nothing");
551 debug_warning("dispatched");
553 __mmplayer_device_change_trigger_post_process(player);
556 /* This function should be called after the pipeline goes PAUSED or higher
559 _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag) // @
561 static gboolean has_duration = FALSE;
562 static gboolean has_video_attrs = FALSE;
563 static gboolean has_audio_attrs = FALSE;
564 static gboolean has_bitrate = FALSE;
565 gboolean missing_only = FALSE;
566 gboolean all = FALSE;
568 GstStructure* p = NULL;
569 MMHandleType attrs = 0;
571 gint stream_service_type = STREAMING_SERVICE_NONE;
576 return_val_if_fail ( player, FALSE );
578 /* check player state here */
579 if ( MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
580 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING )
582 /* give warning now only */
583 debug_warning("be careful. content attributes may not available in this state ");
586 /* get content attribute first */
587 attrs = MMPLAYER_GET_ATTRS(player);
590 debug_error("cannot get content attribute");
594 /* get update flag */
596 if ( flag & ATTR_MISSING_ONLY )
599 debug_log("updating missed attr only");
602 if ( flag & ATTR_ALL )
605 has_duration = FALSE;
606 has_video_attrs = FALSE;
607 has_audio_attrs = FALSE;
610 debug_log("updating all attrs");
613 if ( missing_only && all )
615 debug_warning("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
616 missing_only = FALSE;
619 if ( (flag & ATTR_DURATION) || (!has_duration && missing_only) || all )
621 debug_log("try to update duration");
622 has_duration = FALSE;
624 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec ))
626 player->duration = dur_nsec;
627 debug_warning("duration : %lld msec", GST_TIME_AS_MSECONDS(dur_nsec));
630 /* try to get streaming service type */
631 stream_service_type = __mmplayer_get_stream_service_type( player );
632 mm_attrs_set_int_by_name ( attrs, "streaming_type", stream_service_type );
634 /* check duration is OK */
635 if ( dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING( player ) )
637 /* FIXIT : find another way to get duration here. */
638 debug_error("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
643 mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(dur_nsec));
648 if ( (flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all )
650 /* update audio params
651 NOTE : We need original audio params and it can be only obtained from src pad of audio
652 decoder. Below code only valid when we are not using 'resampler' just before
655 debug_log("try to update audio attrs");
656 has_audio_attrs = FALSE;
658 if ( player->pipeline->audiobin &&
659 player->pipeline->audiobin[MMPLAYER_A_SINK].gst )
661 GstCaps *caps_a = NULL;
663 gint samplerate = 0, channels = 0;
665 pad = gst_element_get_static_pad(
666 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink" );
670 caps_a = gst_pad_get_current_caps( pad );
674 p = gst_caps_get_structure (caps_a, 0);
676 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
678 gst_structure_get_int (p, "rate", &samplerate);
679 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
681 gst_structure_get_int (p, "channels", &channels);
682 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
684 secure_debug_log("samplerate : %d channels : %d", samplerate, channels);
686 gst_caps_unref( caps_a );
689 has_audio_attrs = TRUE;
693 debug_warning("not ready to get audio caps");
696 gst_object_unref( pad );
700 debug_warning("failed to get pad from audiosink");
705 if ( (flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all )
707 debug_log("try to update video attrs");
708 has_video_attrs = FALSE;
710 if ( player->pipeline->videobin &&
711 player->pipeline->videobin[MMPLAYER_V_SINK].gst )
713 GstCaps *caps_v = NULL;
718 pad = gst_element_get_static_pad( player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink" );
721 caps_v = gst_pad_get_current_caps( pad );
723 /* Use v_stream_caps, if fail to get video_sink sink pad*/
724 if (!caps_v && player->v_stream_caps)
726 caps_v = player->v_stream_caps;
727 gst_caps_ref(caps_v);
732 p = gst_caps_get_structure (caps_v, 0);
733 gst_structure_get_int (p, "width", &width);
734 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
736 gst_structure_get_int (p, "height", &height);
737 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
739 gst_structure_get_fraction (p, "framerate", &tmpNu, &tmpDe);
741 secure_debug_log("width : %d height : %d", width, height );
743 gst_caps_unref( caps_v );
748 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
749 secure_debug_log("fps : %d", tmpNu / tmpDe);
752 has_video_attrs = TRUE;
756 debug_log("no negitiated caps from videosink");
758 gst_object_unref( pad );
763 debug_log("no videosink sink pad");
769 if ( (flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all )
773 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
774 if (player->duration)
776 guint64 data_size = 0;
778 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO))
780 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
782 if (stat(path, &sb) == 0)
784 data_size = (guint64)sb.st_size;
787 else if (MMPLAYER_IS_HTTP_STREAMING(player))
789 data_size = player->http_content_size;
791 debug_log("try to update bitrate : data_size = %lld", data_size);
796 guint64 msec_dur = 0;
798 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
799 bitrate = data_size * 8 * 1000 / msec_dur;
800 secure_debug_log("file size : %u, video bitrate = %llu", data_size, bitrate);
801 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
806 if (MMPLAYER_IS_RTSP_STREAMING(player))
808 if(player->total_bitrate)
810 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
818 if ( mmf_attrs_commit ( attrs ) )
820 debug_error("failed to update attributes\n");
829 static gboolean __mmplayer_get_stream_service_type( mm_player_t* player )
831 gint streaming_type = STREAMING_SERVICE_NONE;
835 return_val_if_fail ( player &&
837 player->pipeline->mainbin &&
838 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
841 /* streaming service type if streaming */
842 if ( ! MMPLAYER_IS_STREAMING(player) )
843 return STREAMING_SERVICE_NONE;
845 if (MMPLAYER_IS_HTTP_STREAMING(player))
847 streaming_type = (player->duration == 0) ?
848 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
851 switch ( streaming_type )
853 case STREAMING_SERVICE_LIVE:
854 debug_log("it's live streaming");
856 case STREAMING_SERVICE_VOD:
857 debug_log("it's vod streaming");
859 case STREAMING_SERVICE_NONE:
860 debug_error("should not get here");
863 debug_error("should not get here");
866 player->streaming_type = streaming_type;
869 return streaming_type;
873 /* this function sets the player state and also report
874 * it to applicaton by calling callback function
877 __mmplayer_set_state(mm_player_t* player, int state) // @
879 MMMessageParamType msg = {0, };
880 int sound_result = MM_ERROR_NONE;
881 gboolean post_bos = FALSE;
882 gboolean interrupted_by_asm = FALSE;
883 int ret = MM_ERROR_NONE;
885 return_val_if_fail ( player, FALSE );
887 if ( MMPLAYER_CURRENT_STATE(player) == state )
889 debug_warning("already same state(%s)\n", MMPLAYER_STATE_GET_NAME(state));
890 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
894 /* update player states */
895 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
896 MMPLAYER_CURRENT_STATE(player) = state;
898 /* FIXIT : it's better to do like below code
899 if ( MMPLAYER_CURRENT_STATE(player) == MMPLAYER_TARGET_STATE(player) )
900 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
901 and add more code to handling PENDING_STATE.
903 if ( MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player) )
904 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
907 MMPLAYER_PRINT_STATE(player);
909 /* do some FSM stuffs before posting new state to application */
910 interrupted_by_asm = player->sound_focus.by_asm_cb;
912 switch ( MMPLAYER_CURRENT_STATE(player) )
914 case MM_PLAYER_STATE_NULL:
915 case MM_PLAYER_STATE_READY:
917 if (player->cmd == MMPLAYER_COMMAND_STOP)
919 sound_result = _mmplayer_sound_release_focus(&player->sound_focus);
920 if ( sound_result != MM_ERROR_NONE )
922 debug_error("failed to release sound focus\n");
923 return MM_ERROR_POLICY_INTERNAL;
929 case MM_PLAYER_STATE_PAUSED:
931 if ( ! player->sent_bos )
934 #define MMPLAYER_MAX_SOUND_PRIORITY 3
936 /* it's first time to update all content attrs. */
937 _mmplayer_update_content_attrs( player, ATTR_ALL );
938 /* set max sound priority to keep own sound and not to mute other's one */
939 mm_attrs_get_int_by_name(player->attrs, "content_video_found", &found);
942 mm_attrs_get_int_by_name(player->attrs, "content_audio_found", &found);
945 debug_log("set max audio priority");
946 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "priority", MMPLAYER_MAX_SOUND_PRIORITY, NULL);
952 /* add audio callback probe if condition is satisfied */
953 if ( ! player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
955 __mmplayer_configure_audio_callback(player);
956 /* FIXIT : handle return value */
959 if (!MMPLAYER_IS_STREAMING(player) || (player->streamer && !player->streamer->is_buffering))
961 sound_result = _mmplayer_sound_release_focus(&player->sound_focus);
962 if ( sound_result != MM_ERROR_NONE )
964 debug_error("failed to release sound focus\n");
965 return MM_ERROR_POLICY_INTERNAL;
971 case MM_PLAYER_STATE_PLAYING:
973 /* try to get content metadata */
974 if ( ! player->sent_bos )
976 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
977 * c-api since c-api doesn't use _start() anymore. It may not work propery with
978 * legacy mmfw-player api */
979 _mmplayer_update_content_attrs( player, ATTR_MISSING_ONLY);
982 if ( (player->cmd == MMPLAYER_COMMAND_START) || (player->cmd == MMPLAYER_COMMAND_RESUME) )
984 if (!player->sent_bos)
986 __mmplayer_handle_missed_plugin ( player );
988 sound_result = _mmplayer_sound_acquire_focus(&player->sound_focus);
989 if (sound_result != MM_ERROR_NONE)
991 // FIXME : need to check history
992 if (player->pipeline->videobin)
994 MMMessageParamType msg = {0, };
996 debug_error("failed to go ahead because of video conflict\n");
998 msg.union_type = MM_MSG_UNION_CODE;
999 msg.code = MM_ERROR_POLICY_INTERRUPTED;
1000 MMPLAYER_POST_MSG( player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
1002 _mmplayer_unrealize((MMHandleType)player);
1006 debug_error("failed to play by sound focus error : 0x%X\n", sound_result);
1007 _mmplayer_pause((MMHandleType)player);
1008 return sound_result;
1011 return MM_ERROR_POLICY_INTERNAL;
1015 if ( player->resumed_by_rewind && player->playback_rate < 0.0 )
1017 /* initialize because auto resume is done well. */
1018 player->resumed_by_rewind = FALSE;
1019 player->playback_rate = 1.0;
1022 if ( !player->sent_bos )
1024 /* check audio codec field is set or not
1025 * we can get it from typefinder or codec's caps.
1027 gchar *audio_codec = NULL;
1028 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
1030 /* The codec format can't be sent for audio only case like amr, mid etc.
1031 * Because, parser don't make related TAG.
1032 * So, if it's not set yet, fill it with found data.
1034 if ( ! audio_codec )
1036 if ( g_strrstr(player->type, "audio/midi"))
1038 audio_codec = g_strdup("MIDI");
1041 else if ( g_strrstr(player->type, "audio/x-amr"))
1043 audio_codec = g_strdup("AMR");
1045 else if ( g_strrstr(player->type, "audio/mpeg") && !g_strrstr(player->type, "mpegversion=(int)1"))
1047 audio_codec = g_strdup("AAC");
1051 audio_codec = g_strdup("unknown");
1053 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
1055 MMPLAYER_FREEIF(audio_codec);
1056 mmf_attrs_commit(player->attrs);
1057 debug_log("set audio codec type with caps\n");
1065 case MM_PLAYER_STATE_NONE:
1067 debug_warning("invalid target state, there is nothing to do.\n");
1072 /* post message to application */
1073 if (MMPLAYER_TARGET_STATE(player) == state)
1075 /* fill the message with state of player */
1076 msg.state.previous = MMPLAYER_PREV_STATE(player);
1077 msg.state.current = MMPLAYER_CURRENT_STATE(player);
1079 debug_log ("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
1081 /* state changed by asm callback */
1082 if ( interrupted_by_asm )
1084 msg.union_type = MM_MSG_UNION_CODE;
1085 msg.code = player->sound_focus.focus_changed_msg; /* FIXME: player.c convert function have to be modified. */
1086 MMPLAYER_POST_MSG( player, MM_MESSAGE_STATE_INTERRUPTED, &msg );
1088 /* state changed by usecase */
1091 MMPLAYER_POST_MSG( player, MM_MESSAGE_STATE_CHANGED, &msg );
1096 debug_log ("intermediate state, do nothing.\n");
1097 MMPLAYER_PRINT_STATE(player);
1103 MMPLAYER_POST_MSG ( player, MM_MESSAGE_BEGIN_OF_STREAM, NULL );
1104 player->sent_bos = TRUE;
1110 static gpointer __mmplayer_next_play_thread(gpointer data)
1112 mm_player_t* player = (mm_player_t*) data;
1113 MMPlayerGstElement *mainbin = NULL;
1115 return_val_if_fail ( player, NULL );
1117 g_mutex_lock(&player->next_play_thread_mutex);
1118 while ( ! player->next_play_thread_exit )
1120 debug_log("next play thread started. waiting for signal.\n");
1121 g_cond_wait(&player->next_play_thread_cond, &player->next_play_thread_mutex );
1123 debug_log("reconfigure pipeline for gapless play.\n");
1125 if ( player->next_play_thread_exit )
1127 if(player->gapless.reconfigure)
1129 player->gapless.reconfigure = false;
1130 MMPLAYER_PLAYBACK_UNLOCK(player);
1132 debug_log("exiting gapless play thread\n");
1136 mainbin = player->pipeline->mainbin;
1138 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
1139 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
1140 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
1141 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
1142 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
1144 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
1146 g_mutex_unlock(&player->next_play_thread_mutex);
1151 static gpointer __mmplayer_repeat_thread(gpointer data)
1153 mm_player_t* player = (mm_player_t*) data;
1154 gboolean ret_value = FALSE;
1155 MMHandleType attrs = 0;
1158 return_val_if_fail ( player, NULL );
1160 g_mutex_lock(&player->repeat_thread_mutex);
1161 while ( ! player->repeat_thread_exit )
1163 debug_log("repeat thread started. waiting for signal.\n");
1164 g_cond_wait(&player->repeat_thread_cond, &player->repeat_thread_mutex );
1166 if ( player->repeat_thread_exit )
1168 debug_log("exiting repeat thread\n");
1174 g_mutex_lock(&player->cmd_lock);
1176 attrs = MMPLAYER_GET_ATTRS(player);
1178 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
1180 debug_error("can not get play count\n");
1184 if ( player->section_repeat )
1186 ret_value = _mmplayer_activate_section_repeat((MMHandleType)player, player->section_repeat_start, player->section_repeat_end);
1190 if ( player->playback_rate < 0.0 )
1192 player->resumed_by_rewind = TRUE;
1193 _mmplayer_set_mute((MMHandleType)player, 0);
1194 MMPLAYER_POST_MSG( player, MM_MESSAGE_RESUMED_BY_REW, NULL );
1197 ret_value = __gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
1198 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET,
1199 0, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
1202 player->sent_bos = FALSE;
1207 debug_error("failed to set position to zero for rewind\n");
1211 /* decrease play count */
1214 /* we successeded to rewind. update play count and then wait for next EOS */
1217 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
1219 /* commit attribute */
1220 if ( mmf_attrs_commit ( attrs ) )
1222 debug_error("failed to commit attribute\n");
1227 g_mutex_unlock(&player->cmd_lock);
1230 g_mutex_unlock(&player->repeat_thread_mutex);
1235 __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg)
1237 MMHandleType attrs = 0;
1238 guint64 data_size = 0;
1240 unsigned long pos_msec = 0;
1243 return_if_fail( player && player->pipeline && player->pipeline->mainbin);
1245 __gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &pos_msec); // update last_position
1247 attrs = MMPLAYER_GET_ATTRS(player);
1250 debug_error("fail to get attributes.\n");
1254 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO))
1256 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
1258 if (stat(path, &sb) == 0)
1260 data_size = (guint64)sb.st_size;
1263 else if (MMPLAYER_IS_HTTP_STREAMING(player))
1265 data_size = player->http_content_size;
1268 __mm_player_streaming_buffering( player->streamer,
1271 player->last_position,
1274 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
1280 __mmplayer_handle_buffering_message ( mm_player_t* player )
1282 int ret = MM_ERROR_NONE;
1283 MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
1284 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
1285 MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
1286 MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
1288 MMPLAYER_CMD_LOCK( player );
1290 if( !player || !player->streamer || MMPLAYER_IS_LIVE_STREAMING(player))
1292 ret = MM_ERROR_PLAYER_INVALID_STATE;
1296 prev_state = MMPLAYER_PREV_STATE(player);
1297 current_state = MMPLAYER_CURRENT_STATE(player);
1298 target_state = MMPLAYER_TARGET_STATE(player);
1299 pending_state = MMPLAYER_PENDING_STATE(player);
1301 debug_log( "player state : prev %s, current %s, pending %s, target %s, buffering %d",
1302 MMPLAYER_STATE_GET_NAME(prev_state),
1303 MMPLAYER_STATE_GET_NAME(current_state),
1304 MMPLAYER_STATE_GET_NAME(pending_state),
1305 MMPLAYER_STATE_GET_NAME(target_state),
1306 player->streamer->is_buffering);
1308 if ( !player->streamer->is_buffering )
1310 /* NOTE : if buffering has done, player has to go to target state. */
1311 switch ( target_state )
1313 case MM_PLAYER_STATE_PAUSED :
1315 switch ( pending_state )
1317 case MM_PLAYER_STATE_PLAYING:
1319 __gst_pause ( player, TRUE );
1323 case MM_PLAYER_STATE_PAUSED:
1325 debug_log("player is already going to paused state, there is nothing to do.\n");
1329 case MM_PLAYER_STATE_NONE:
1330 case MM_PLAYER_STATE_NULL:
1331 case MM_PLAYER_STATE_READY:
1334 debug_warning("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state) );
1341 case MM_PLAYER_STATE_PLAYING :
1343 switch ( pending_state )
1345 case MM_PLAYER_STATE_NONE:
1347 if (current_state != MM_PLAYER_STATE_PLAYING)
1348 __gst_resume ( player, TRUE );
1352 case MM_PLAYER_STATE_PAUSED:
1354 /* NOTE: It should be worked as asynchronously.
1355 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
1357 __gst_resume ( player, TRUE );
1361 case MM_PLAYER_STATE_PLAYING:
1363 debug_log("player is already going to playing state, there is nothing to do.\n");
1367 case MM_PLAYER_STATE_NULL:
1368 case MM_PLAYER_STATE_READY:
1371 debug_warning("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state) );
1378 case MM_PLAYER_STATE_NULL :
1379 case MM_PLAYER_STATE_READY :
1380 case MM_PLAYER_STATE_NONE :
1383 debug_warning("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state) );
1390 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1391 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
1393 switch ( pending_state )
1395 case MM_PLAYER_STATE_NONE:
1397 if (current_state != MM_PLAYER_STATE_PAUSED)
1399 debug_log("set pause state during buffering\n");
1400 __gst_pause ( player, TRUE );
1402 // to cover the weak-signal environment.
1403 if (MMPLAYER_IS_RTSP_STREAMING(player))
1405 unsigned long position = 0;
1406 gint64 pos_msec = 0;
1408 debug_log("[RTSP] seek to the buffering start point\n");
1410 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position ))
1412 debug_error("failed to get position\n");
1417 pos_msec = position * G_GINT64_CONSTANT(1000000);
1419 __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
1420 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET,
1421 pos_msec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
1427 case MM_PLAYER_STATE_PLAYING:
1429 __gst_pause ( player, TRUE );
1433 case MM_PLAYER_STATE_PAUSED:
1438 case MM_PLAYER_STATE_NULL:
1439 case MM_PLAYER_STATE_READY:
1442 debug_warning("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state) );
1449 MMPLAYER_CMD_UNLOCK( player );
1454 __mmplayer_drop_subtitle(mm_player_t* player, gboolean is_drop)
1456 MMPlayerGstElement *textbin;
1459 return_if_fail ( player &&
1461 player->pipeline->textbin);
1463 return_if_fail (player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1465 textbin = player->pipeline->textbin;
1469 debug_log("Drop subtitle text after getting EOS\n");
1471 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", FALSE, NULL);
1472 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
1474 player->is_subtitle_force_drop = TRUE;
1478 if (player->is_subtitle_force_drop == TRUE)
1480 debug_log("Enable subtitle data path without drop\n");
1482 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
1483 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", TRUE, NULL);
1485 debug_log ("non-connected with external display");
1487 player->is_subtitle_force_drop = FALSE;
1493 __mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data) // @
1495 mm_player_t* player = (mm_player_t*) data;
1496 gboolean ret = TRUE;
1497 static gboolean async_done = FALSE;
1499 return_val_if_fail ( player, FALSE );
1500 return_val_if_fail ( msg && GST_IS_MESSAGE(msg), FALSE );
1502 switch ( GST_MESSAGE_TYPE( msg ) )
1504 case GST_MESSAGE_UNKNOWN:
1505 debug_log("unknown message received\n");
1508 case GST_MESSAGE_EOS:
1510 MMHandleType attrs = 0;
1513 debug_log("GST_MESSAGE_EOS received\n");
1515 /* NOTE : EOS event is comming multiple time. watch out it */
1516 /* check state. we only process EOS when pipeline state goes to PLAYING */
1517 if ( ! (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) )
1519 debug_log("EOS received on non-playing state. ignoring it\n");
1523 __mmplayer_drop_subtitle(player, TRUE);
1525 if ( (player->audio_stream_cb) && (player->set_mode.pcm_extraction) && (!player->audio_stream_render_cb_ex))
1529 pad = gst_element_get_static_pad (player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
1531 debug_log("release audio callback\n");
1533 /* release audio callback */
1534 gst_pad_remove_probe (pad, player->audio_cb_probe_id);
1535 player->audio_cb_probe_id = 0;
1536 /* audio callback should be free because it can be called even though probe remove.*/
1537 player->audio_stream_cb = NULL;
1538 player->audio_stream_cb_user_param = NULL;
1542 /* rewind if repeat count is greater then zero */
1543 /* get play count */
1544 attrs = MMPLAYER_GET_ATTRS(player);
1548 gboolean smooth_repeat = FALSE;
1550 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1551 mm_attrs_get_int_by_name(attrs, "profile_smooth_repeat", &smooth_repeat);
1553 player->play_count = count;
1555 debug_log("remaining play count: %d, playback rate: %f\n", count, player->playback_rate);
1557 if ( count > 1 || count == -1 || player->playback_rate < 0.0 ) /* default value is 1 */
1559 if ( smooth_repeat )
1561 debug_log("smooth repeat enabled. seeking operation will be excuted in new thread\n");
1563 g_cond_signal( &player->repeat_thread_cond );
1571 if ( player->section_repeat )
1573 ret_value = _mmplayer_activate_section_repeat((MMHandleType)player, player->section_repeat_start, player->section_repeat_end);
1577 if ( player->playback_rate < 0.0 )
1579 player->resumed_by_rewind = TRUE;
1580 _mmplayer_set_mute((MMHandleType)player, 0);
1581 MMPLAYER_POST_MSG( player, MM_MESSAGE_RESUMED_BY_REW, NULL );
1584 __mmplayer_handle_eos_delay( player, player->ini.delay_before_repeat );
1587 player->sent_bos = FALSE;
1590 if ( MM_ERROR_NONE != ret_value )
1592 debug_error("failed to set position to zero for rewind\n");
1595 /* not posting eos when repeating */
1601 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-eos" );
1603 /* post eos message to application */
1604 __mmplayer_handle_eos_delay( player, player->ini.eos_delay );
1606 /* reset last position */
1607 player->last_position = 0;
1611 case GST_MESSAGE_ERROR:
1613 GError *error = NULL;
1614 gchar* debug = NULL;
1616 /* generating debug info before returning error */
1617 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-error" );
1619 /* get error code */
1620 gst_message_parse_error( msg, &error, &debug );
1622 if ( gst_structure_has_name ( gst_message_get_structure(msg), "streaming_error" ) )
1624 /* Note : the streaming error from the streaming source is handled
1625 * using __mmplayer_handle_streaming_error.
1627 __mmplayer_handle_streaming_error ( player, msg );
1629 /* dump state of all element */
1630 __mmplayer_dump_pipeline_state( player );
1634 /* traslate gst error code to msl error code. then post it
1635 * to application if needed
1637 __mmplayer_handle_gst_error( player, msg, error );
1641 debug_error ("error debug : %s", debug);
1646 if (MMPLAYER_IS_HTTP_PD(player))
1648 _mmplayer_unrealize_pd_downloader ((MMHandleType)player);
1651 MMPLAYER_FREEIF( debug );
1652 g_error_free( error );
1656 case GST_MESSAGE_WARNING:
1659 GError* error = NULL;
1661 gst_message_parse_warning(msg, &error, &debug);
1663 debug_log("warning : %s\n", error->message);
1664 debug_log("debug : %s\n", debug);
1666 MMPLAYER_POST_MSG( player, MM_MESSAGE_WARNING, NULL );
1668 MMPLAYER_FREEIF( debug );
1669 g_error_free( error );
1673 case GST_MESSAGE_TAG:
1675 debug_log("GST_MESSAGE_TAG\n");
1676 if ( ! __mmplayer_gst_extract_tag_from_msg( player, msg ) )
1678 debug_warning("failed to extract tags from gstmessage\n");
1683 case GST_MESSAGE_BUFFERING:
1685 MMMessageParamType msg_param = {0, };
1687 if (!MMPLAYER_IS_STREAMING(player))
1690 /* ignore the prev buffering message */
1691 if ((player->streamer) && (player->streamer->is_buffering == FALSE) && (player->streamer->is_buffering_done == TRUE))
1693 gint buffer_percent = 0;
1695 gst_message_parse_buffering (msg, &buffer_percent);
1697 if (buffer_percent == MAX_BUFFER_PERCENT)
1699 debug_log ("Ignored all the previous buffering msg! (got %d%%)\n", buffer_percent);
1700 player->streamer->is_buffering_done = FALSE;
1706 __mmplayer_update_buffer_setting(player, msg);
1708 if(__mmplayer_handle_buffering_message ( player ) == MM_ERROR_NONE) {
1710 msg_param.connection.buffering = player->streamer->buffering_percent;
1711 MMPLAYER_POST_MSG ( player, MM_MESSAGE_BUFFERING, &msg_param );
1712 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1713 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT))
1715 if (player->doing_seek)
1717 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED)
1719 player->doing_seek = FALSE;
1720 MMPLAYER_POST_MSG ( player, MM_MESSAGE_SEEK_COMPLETED, NULL );
1722 else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING)
1732 case GST_MESSAGE_STATE_CHANGED:
1734 MMPlayerGstElement *mainbin;
1735 const GValue *voldstate, *vnewstate, *vpending;
1736 GstState oldstate, newstate, pending;
1738 if ( ! ( player->pipeline && player->pipeline->mainbin ) )
1740 debug_error("player pipeline handle is null");
1744 mainbin = player->pipeline->mainbin;
1746 /* we only handle messages from pipeline */
1747 if( msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst )
1750 /* get state info from msg */
1751 voldstate = gst_structure_get_value (gst_message_get_structure(msg), "old-state");
1752 vnewstate = gst_structure_get_value (gst_message_get_structure(msg), "new-state");
1753 vpending = gst_structure_get_value (gst_message_get_structure(msg), "pending-state");
1755 oldstate = (GstState)voldstate->data[0].v_int;
1756 newstate = (GstState)vnewstate->data[0].v_int;
1757 pending = (GstState)vpending->data[0].v_int;
1759 debug_log("state changed [%s] : %s ---> %s final : %s\n",
1760 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1761 gst_element_state_get_name( (GstState)oldstate ),
1762 gst_element_state_get_name( (GstState)newstate ),
1763 gst_element_state_get_name( (GstState)pending ) );
1765 if (oldstate == newstate)
1767 debug_log("pipeline reports state transition to old state");
1773 case GST_STATE_VOID_PENDING:
1776 case GST_STATE_NULL:
1779 case GST_STATE_READY:
1782 case GST_STATE_PAUSED:
1784 gboolean prepare_async = FALSE;
1785 gboolean is_drm = FALSE;
1787 if ( ! player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
1788 __mmplayer_configure_audio_callback(player);
1790 if ( ! player->sent_bos && oldstate == GST_STATE_READY) // managed prepare async case
1792 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1793 debug_log("checking prepare mode for async transition - %d", prepare_async);
1796 if ( MMPLAYER_IS_STREAMING(player) || prepare_async )
1798 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_PAUSED );
1800 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1802 __mm_player_streaming_set_content_bitrate(player->streamer,
1803 player->total_maximum_bitrate, player->total_bitrate);
1807 /* NOTE : should consider streaming case */
1808 /* check if drm file */
1809 if ((player->pipeline->mainbin[MMPLAYER_M_SRC].gst) &&
1810 (g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), "is-drm")))
1812 g_object_get(G_OBJECT(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), "is-drm", &is_drm, NULL);
1816 player->is_drm_file = TRUE;
1822 case GST_STATE_PLAYING:
1824 /* for audio tunning */
1826 if (player->can_support_codec == 0x03) {
1828 mm_attrs_get_int_by_name(player->attrs, "sound_volume_type", &volume_type);
1829 volume_type |= MM_SOUND_VOLUME_GAIN_VIDEO;
1830 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "volumetype", volume_type, NULL);
1833 if ( MMPLAYER_IS_STREAMING(player) ) // managed prepare async case when buffering is completed
1835 // pending state should be reset oyherwise, it's still playing even though it's resumed after bufferging.
1836 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1837 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1839 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_PLAYING);
1843 if (player->gapless.stream_changed)
1845 _mmplayer_update_content_attrs(player, ATTR_ALL);
1848 if (player->doing_seek && async_done)
1850 player->doing_seek = FALSE;
1852 MMPLAYER_POST_MSG ( player, MM_MESSAGE_SEEK_COMPLETED, NULL );
1863 case GST_MESSAGE_CLOCK_LOST:
1865 GstClock *clock = NULL;
1866 gboolean need_new_clock = FALSE;
1868 gst_message_parse_clock_lost (msg, &clock);
1869 debug_log("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME (clock) : "NULL"));
1871 if (!player->videodec_linked)
1873 need_new_clock = TRUE;
1875 else if (!player->ini.use_system_clock)
1877 need_new_clock = TRUE;
1880 if (need_new_clock) {
1881 debug_log ("Provide clock is TRUE, do pause->resume\n");
1882 __gst_pause(player, FALSE);
1883 __gst_resume(player, FALSE);
1888 case GST_MESSAGE_NEW_CLOCK:
1890 GstClock *clock = NULL;
1891 gst_message_parse_new_clock (msg, &clock);
1892 debug_log("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME (clock) : "NULL"));
1896 case GST_MESSAGE_ELEMENT:
1898 const gchar *structure_name;
1900 MMHandleType attrs = 0;
1902 attrs = MMPLAYER_GET_ATTRS(player);
1905 debug_error("cannot get content attribute");
1910 if(gst_message_get_structure(msg) == NULL)
1913 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1914 if(!strcmp(structure_name, "Language_list"))
1916 const GValue *lang_list = NULL;
1917 lang_list = gst_structure_get_value (gst_message_get_structure(msg), "lang_list");
1918 if(lang_list != NULL)
1920 count = g_list_length((GList *)g_value_get_pointer (lang_list));
1922 debug_log("Total audio tracks (from parser) = %d \n",count);
1926 if (!strcmp (structure_name, "Ext_Sub_Language_List"))
1928 const GValue *lang_list = NULL;
1929 MMPlayerLangStruct *temp = NULL;
1931 lang_list = gst_structure_get_value (gst_message_get_structure(msg), "lang_list");
1932 if (lang_list != NULL)
1934 count = g_list_length ((GList *)g_value_get_pointer (lang_list));
1937 player->subtitle_language_list = (GList *)g_value_get_pointer (lang_list);
1938 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)count);
1939 if (mmf_attrs_commit (attrs))
1940 debug_error("failed to commit.\n");
1941 debug_log("Total subtitle tracks = %d \n", count);
1945 temp = g_list_nth_data (player->subtitle_language_list, count - 1);
1946 debug_log ("value of lang_key is %s and lang_code is %s",
1947 temp->language_key, temp->language_code);
1953 /* custom message */
1954 if (!strcmp (structure_name, "audio_codec_not_supported")) {
1955 MMMessageParamType msg_param = {0,};
1956 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1957 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1962 case GST_MESSAGE_DURATION_CHANGED:
1964 debug_log("GST_MESSAGE_DURATION_CHANGED\n");
1965 ret = __mmplayer_gst_handle_duration(player, msg);
1968 debug_warning("failed to update duration");
1974 case GST_MESSAGE_ASYNC_START:
1976 debug_log("GST_MESSAGE_ASYNC_START : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1980 case GST_MESSAGE_ASYNC_DONE:
1982 debug_log("GST_MESSAGE_ASYNC_DONE : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1984 /* we only handle messages from pipeline */
1985 if( msg->src != (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst )
1988 if (player->doing_seek)
1990 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED)
1992 player->doing_seek = FALSE;
1993 MMPLAYER_POST_MSG ( player, MM_MESSAGE_SEEK_COMPLETED, NULL );
1995 else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING)
1997 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1998 (player->streamer) &&
1999 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
2000 (player->streamer->is_buffering == FALSE))
2002 GstQuery *query = NULL;
2003 gboolean busy = FALSE;
2006 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer)
2008 query = gst_query_new_buffering ( GST_FORMAT_PERCENT );
2009 if ( gst_element_query (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query ) )
2011 gst_query_parse_buffering_percent ( query, &busy, &percent);
2013 gst_query_unref (query);
2015 debug_log("buffered percent(%s): %d\n",
2016 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
2021 player->streamer->is_buffering = FALSE;
2022 __mmplayer_handle_buffering_message(player);
2032 #if 0 /* delete unnecessary logs */
2033 case GST_MESSAGE_REQUEST_STATE: debug_log("GST_MESSAGE_REQUEST_STATE\n"); break;
2034 case GST_MESSAGE_STEP_START: debug_log("GST_MESSAGE_STEP_START\n"); break;
2035 case GST_MESSAGE_QOS: debug_log("GST_MESSAGE_QOS\n"); break;
2036 case GST_MESSAGE_PROGRESS: debug_log("GST_MESSAGE_PROGRESS\n"); break;
2037 case GST_MESSAGE_ANY: debug_log("GST_MESSAGE_ANY\n"); break;
2038 case GST_MESSAGE_INFO: debug_log("GST_MESSAGE_STATE_DIRTY\n"); break;
2039 case GST_MESSAGE_STATE_DIRTY: debug_log("GST_MESSAGE_STATE_DIRTY\n"); break;
2040 case GST_MESSAGE_STEP_DONE: debug_log("GST_MESSAGE_STEP_DONE\n"); break;
2041 case GST_MESSAGE_CLOCK_PROVIDE: debug_log("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
2042 case GST_MESSAGE_STRUCTURE_CHANGE: debug_log("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
2043 case GST_MESSAGE_STREAM_STATUS: debug_log("GST_MESSAGE_STREAM_STATUS\n"); break;
2044 case GST_MESSAGE_APPLICATION: debug_log("GST_MESSAGE_APPLICATION\n"); break;
2045 case GST_MESSAGE_SEGMENT_START: debug_log("GST_MESSAGE_SEGMENT_START\n"); break;
2046 case GST_MESSAGE_SEGMENT_DONE: debug_log("GST_MESSAGE_SEGMENT_DONE\n"); break;
2047 case GST_MESSAGE_LATENCY: debug_log("GST_MESSAGE_LATENCY\n"); break;
2054 /* FIXIT : this cause so many warnings/errors from glib/gstreamer. we should not call it since
2055 * gst_element_post_message api takes ownership of the message.
2057 //gst_message_unref( msg );
2063 __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg)
2069 return_val_if_fail(player, FALSE);
2070 return_val_if_fail(msg, FALSE);
2072 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
2073 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst))
2075 debug_log("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
2077 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes))
2079 debug_log("data total size of http content: %lld", bytes);
2080 player->http_content_size = bytes;
2085 /* handling audio clip which has vbr. means duration is keep changing */
2086 _mmplayer_update_content_attrs (player, ATTR_DURATION );
2096 __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg) // @
2099 /* macro for better code readability */
2100 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
2101 if (gst_tag_list_get_string(tag_list, gsttag, &string)) \
2103 if (string != NULL)\
2105 secure_debug_log ( "update tag string : %s\n", string); \
2106 mm_attrs_set_string_by_name(attribute, playertag, string); \
2112 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
2113 GstSample *sample = NULL;\
2114 if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample))\
2116 GstMapInfo info = GST_MAP_INFO_INIT;\
2117 buffer = gst_sample_get_buffer(sample);\
2118 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)){\
2119 debug_log("failed to get image data from tag");\
2122 secure_debug_log ( "update album cover data : %p, size : %d\n", info.data, info.size);\
2123 MMPLAYER_FREEIF(player->album_art); \
2124 player->album_art = (gchar *)g_malloc(info.size); \
2125 if (player->album_art) \
2127 memcpy(player->album_art, info.data, info.size); \
2128 mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size); \
2129 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) \
2131 msg_param.data = (void *)player->album_art; \
2132 msg_param.size = info.size; \
2133 MMPLAYER_POST_MSG (player, MM_MESSAGE_IMAGE_BUFFER, &msg_param); \
2134 secure_debug_log ( "post message image buffer data : %p, size : %d\n", info.data, info.size); \
2137 gst_buffer_unmap(buffer, &info); \
2140 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
2141 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint))\
2145 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) \
2147 if (player->updated_bitrate_count == 0) \
2148 mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
2149 if (player->updated_bitrate_count<MM_PLAYER_STREAM_COUNT_MAX) \
2151 player->bitrate[player->updated_bitrate_count] = v_uint;\
2152 player->total_bitrate += player->bitrate[player->updated_maximum_bitrate_count]; \
2153 player->updated_bitrate_count++; \
2154 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate);\
2155 secure_debug_log ( "update bitrate %d[bps] of stream #%d.\n", v_uint, player->updated_bitrate_count);\
2158 else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) \
2160 if (player->updated_maximum_bitrate_count<MM_PLAYER_STREAM_COUNT_MAX) \
2162 player->maximum_bitrate[player->updated_maximum_bitrate_count] = v_uint;\
2163 player->total_maximum_bitrate += player->maximum_bitrate[player->updated_maximum_bitrate_count]; \
2164 player->updated_maximum_bitrate_count++; \
2165 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate); \
2166 secure_debug_log ( "update maximum bitrate %d[bps] of stream #%d\n", v_uint, player->updated_maximum_bitrate_count);\
2171 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
2177 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
2178 if (gst_tag_list_get_date(tag_list, gsttag, &date))\
2182 string = g_strdup_printf("%d", g_date_get_year(date));\
2183 mm_attrs_set_string_by_name(attribute, playertag, string);\
2184 secure_debug_log ( "metainfo year : %s\n", string);\
2185 MMPLAYER_FREEIF(string);\
2190 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
2191 if(gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64))\
2195 /* FIXIT : don't know how to store date */\
2201 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
2202 if(gst_tag_list_get_double(tag_list, gsttag, &v_double))\
2206 /* FIXIT : don't know how to store date */\
2212 /* function start */
2213 GstTagList* tag_list = NULL;
2215 MMHandleType attrs = 0;
2217 char *string = NULL;
2221 GstBuffer *buffer = NULL;
2223 MMMessageParamType msg_param = {0, };
2225 /* currently not used. but those are needed for above macro */
2226 //guint64 v_uint64 = 0;
2227 //gdouble v_double = 0;
2229 return_val_if_fail( player && msg, FALSE );
2231 attrs = MMPLAYER_GET_ATTRS(player);
2233 return_val_if_fail( attrs, FALSE );
2235 /* get tag list from gst message */
2236 gst_message_parse_tag(msg, &tag_list);
2238 /* store tags to player attributes */
2239 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
2240 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
2241 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
2242 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
2243 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
2244 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
2245 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
2246 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
2247 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
2248 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
2249 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
2250 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
2251 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
2252 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
2253 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
2254 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
2255 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
2256 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
2257 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
2258 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
2259 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
2260 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
2261 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
2262 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
2263 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
2264 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
2265 /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
2266 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
2267 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
2268 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
2269 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
2270 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
2271 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
2272 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
2273 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
2274 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
2275 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
2276 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
2277 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
2278 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
2279 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
2280 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
2281 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
2282 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
2283 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
2284 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation");
2286 if ( mmf_attrs_commit ( attrs ) )
2287 debug_error("failed to commit.\n");
2289 gst_tag_list_free(tag_list);
2295 __mmplayer_gst_rtp_no_more_pads (GstElement *element, gpointer data) // @
2297 mm_player_t* player = (mm_player_t*) data;
2301 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2302 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2303 * num_dynamic_pad. and this is no-more-pad situation which means mo more pad will be added.
2304 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2306 * [1] audio and video will be dumped with filesink.
2307 * [2] autoplugging is done by just using pad caps.
2308 * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2309 * and the video will be dumped via filesink.
2311 if ( player->num_dynamic_pad == 0 )
2313 debug_log("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
2315 if ( ! __mmplayer_gst_remove_fakesink( player,
2316 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]) )
2318 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
2319 * signaling mechanism ( pad-added, no-more-pad, new-decoded-pad ) from various
2320 * source element are not same. To overcome this situation, this function will called
2321 * several places and several times. Therefore, this is not an error case.
2327 /* create dot before error-return. for debugging */
2328 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-no-more-pad" );
2330 player->no_more_pad = TRUE;
2336 __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink) // @
2338 GstElement* parent = NULL;
2340 return_val_if_fail(player && player->pipeline, FALSE);
2342 /* if we have no fakesink. this meas we are using decodebin which doesn'
2343 t need to add extra fakesink */
2344 return_val_if_fail(fakesink, TRUE);
2347 g_mutex_lock(&player->fsink_lock );
2349 if ( ! fakesink->gst )
2354 /* get parent of fakesink */
2355 parent = (GstElement*)gst_object_get_parent( (GstObject*)fakesink->gst );
2358 debug_log("fakesink already removed\n");
2362 gst_element_set_locked_state( fakesink->gst, TRUE );
2364 /* setting the state to NULL never returns async
2365 * so no need to wait for completion of state transiton
2367 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state (fakesink->gst, GST_STATE_NULL) )
2369 debug_error("fakesink state change failure!\n");
2371 /* FIXIT : should I return here? or try to proceed to next? */
2375 /* remove fakesink from it's parent */
2376 if ( ! gst_bin_remove( GST_BIN( parent ), fakesink->gst ) )
2378 debug_error("failed to remove fakesink\n");
2380 gst_object_unref( parent );
2385 gst_object_unref( parent );
2387 debug_log("state-holder removed\n");
2389 gst_element_set_locked_state( fakesink->gst, FALSE );
2391 g_mutex_unlock( &player->fsink_lock );
2395 if ( fakesink->gst )
2397 gst_element_set_locked_state( fakesink->gst, FALSE );
2400 g_mutex_unlock( &player->fsink_lock );
2406 __mmplayer_gst_rtp_dynamic_pad (GstElement *element, GstPad *pad, gpointer data) // @
2408 GstPad *sinkpad = NULL;
2409 GstCaps* caps = NULL;
2410 GstElement* new_element = NULL;
2411 GstStructure* str = NULL;
2412 const gchar* name = NULL;
2414 mm_player_t* player = (mm_player_t*) data;
2418 return_if_fail( element && pad );
2419 return_if_fail( player &&
2421 player->pipeline->mainbin );
2424 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2425 * num_dynamic_pad will decreased after creating a sinkbin.
2427 player->num_dynamic_pad++;
2428 debug_log("stream count inc : %d\n", player->num_dynamic_pad);
2430 caps = gst_pad_query_caps( pad, NULL );
2432 MMPLAYER_CHECK_NULL( caps );
2434 /* clear previous result*/
2435 player->have_dynamic_pad = FALSE;
2437 str = gst_caps_get_structure(caps, 0);
2441 debug_error ("cannot get structure from caps.\n");
2445 name = gst_structure_get_name (str);
2448 debug_error ("cannot get mimetype from structure.\n");
2452 if (strstr(name, "video"))
2455 mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &stype);
2457 if (stype == MM_DISPLAY_SURFACE_NULL)
2459 if (player->v_stream_caps)
2461 gst_caps_unref(player->v_stream_caps);
2462 player->v_stream_caps = NULL;
2465 new_element = gst_element_factory_make("fakesink", NULL);
2466 player->num_dynamic_pad--;
2471 /* clear previous result*/
2472 player->have_dynamic_pad = FALSE;
2474 if ( !__mmplayer_try_to_plug_decodebin(player, pad, caps))
2476 debug_error("failed to autoplug for caps");
2480 /* check if there's dynamic pad*/
2481 if( player->have_dynamic_pad )
2483 debug_error("using pad caps assums there's no dynamic pad !\n");
2487 gst_caps_unref( caps );
2492 /* excute new_element if created*/
2495 debug_log("adding new element to pipeline\n");
2497 /* set state to READY before add to bin */
2498 MMPLAYER_ELEMENT_SET_STATE( new_element, GST_STATE_READY );
2500 /* add new element to the pipeline */
2501 if ( FALSE == gst_bin_add( GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element) )
2503 debug_error("failed to add autoplug element to bin\n");
2507 /* get pad from element */
2508 sinkpad = gst_element_get_static_pad ( GST_ELEMENT(new_element), "sink" );
2511 debug_error("failed to get sinkpad from autoplug element\n");
2516 if ( GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad) )
2518 debug_error("failed to link autoplug element\n");
2522 gst_object_unref (sinkpad);
2525 /* run. setting PLAYING here since streamming source is live source */
2526 MMPLAYER_ELEMENT_SET_STATE( new_element, GST_STATE_PLAYING );
2533 STATE_CHANGE_FAILED:
2535 /* FIXIT : take care if new_element has already added to pipeline */
2537 gst_object_unref(GST_OBJECT(new_element));
2540 gst_object_unref(GST_OBJECT(sinkpad));
2543 gst_object_unref(GST_OBJECT(caps));
2545 /* FIXIT : how to inform this error to MSL ????? */
2546 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2547 * then post an error to application
2553 /* FIXIT : check indent */
2556 __mmplayer_gst_wfd_dynamic_pad (GstElement *element, GstPad *pad, gpointer data) // @
2558 GstPad *sinkpad = NULL;
2559 GstCaps* caps = NULL;
2560 GstElement* new_element = NULL;
2561 enum MainElementID element_id = MMPLAYER_M_NUM;
2563 mm_player_t* player = (mm_player_t*) data;
2567 return_if_fail( element && pad );
2568 return_if_fail( player &&
2570 player->pipeline->mainbin );
2572 debug_log("stream count inc : %d\n", player->num_dynamic_pad);
2575 debug_log("using pad caps to autopluging instead of doing typefind\n");
2576 caps = gst_pad_query_caps( pad );
2577 MMPLAYER_CHECK_NULL( caps );
2578 /* clear previous result*/
2579 player->have_dynamic_pad = FALSE;
2580 new_element = gst_element_factory_make("rtpmp2tdepay", "wfd_rtp_depay");
2583 debug_error ( "failed to create wfd rtp depay element\n" );
2586 MMPLAYER_ELEMENT_SET_STATE( new_element, GST_STATE_READY );
2587 /* add new element to the pipeline */
2588 if ( FALSE == gst_bin_add( GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element) )
2590 debug_log("failed to add autoplug element to bin\n");
2593 /* get pad from element */
2594 sinkpad = gst_element_get_static_pad ( GST_ELEMENT(new_element), "sink" );
2597 debug_log("failed to get sinkpad from autoplug element\n");
2601 if ( GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad) )
2603 debug_log("failed to link autoplug element\n");
2606 gst_object_unref (sinkpad);
2608 pad = gst_element_get_static_pad ( GST_ELEMENT(new_element), "src" );
2609 caps = gst_pad_query_caps( pad );
2610 MMPLAYER_CHECK_NULL( caps );
2611 MMPLAYER_ELEMENT_SET_STATE( new_element, GST_STATE_PLAYING );
2612 /* create typefind */
2613 new_element = gst_element_factory_make( "typefind", NULL );
2614 if ( ! new_element )
2616 debug_log("failed to create typefind\n");
2620 MMPLAYER_SIGNAL_CONNECT( player,
2621 G_OBJECT(new_element),
2622 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG,
2624 G_CALLBACK(__mmplayer_typefind_have_type),
2627 player->have_dynamic_pad = FALSE;
2630 /* excute new_element if created*/
2633 debug_log("adding new element to pipeline\n");
2635 /* set state to READY before add to bin */
2636 MMPLAYER_ELEMENT_SET_STATE( new_element, GST_STATE_READY );
2638 /* add new element to the pipeline */
2639 if ( FALSE == gst_bin_add( GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element) )
2641 debug_log("failed to add autoplug element to bin\n");
2645 /* get pad from element */
2646 sinkpad = gst_element_get_static_pad ( GST_ELEMENT(new_element), "sink" );
2649 debug_log("failed to get sinkpad from autoplug element\n");
2654 if ( GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad) )
2656 debug_log("failed to link autoplug element\n");
2660 gst_object_unref (sinkpad);
2663 /* run. setting PLAYING here since streamming source is live source */
2664 MMPLAYER_ELEMENT_SET_STATE( new_element, GST_STATE_PLAYING );
2667 /* store handle to futher manipulation */
2668 player->pipeline->mainbin[element_id].id = element_id;
2669 player->pipeline->mainbin[element_id].gst = new_element;
2675 STATE_CHANGE_FAILED:
2677 /* FIXIT : take care if new_element has already added to pipeline */
2679 gst_object_unref(GST_OBJECT(new_element));
2682 gst_object_unref(GST_OBJECT(sinkpad));
2685 gst_object_unref(GST_OBJECT(caps));
2687 /* FIXIT : how to inform this error to MSL ????? */
2688 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2689 * then post an error to application
2694 static GstPadProbeReturn
2695 __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data)
2697 debug_log ("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
2698 return GST_PAD_PROBE_OK;
2701 static GstPadProbeReturn
2702 __mmplayer_audio_data_probe (GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
2704 mm_player_t* player = (mm_player_t*) u_data;
2705 GstBuffer *pad_buffer = gst_pad_probe_info_get_buffer(info);
2707 /* TO_CHECK: performance */
2708 return_val_if_fail (player && GST_IS_BUFFER(pad_buffer), GST_PAD_PROBE_OK);
2710 if (GST_BUFFER_PTS_IS_VALID(pad_buffer) && GST_BUFFER_DURATION_IS_VALID(pad_buffer))
2711 player->gapless.next_pts = GST_BUFFER_PTS(pad_buffer) + GST_BUFFER_DURATION(pad_buffer);
2713 return GST_PAD_PROBE_OK;
2716 static GstPadProbeReturn
2717 __mmplayer_gst_selector_event_probe (GstPad * pad, GstPadProbeInfo * info, gpointer data)
2719 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
2720 GstEvent *event = GST_PAD_PROBE_INFO_DATA (info);
2721 mm_player_t* player = (mm_player_t*)data;
2723 switch (GST_EVENT_TYPE (event)) {
2724 case GST_EVENT_STREAM_START:
2726 case GST_EVENT_SEGMENT: {
2730 if (!player->gapless.running)
2733 if (player->gapless.stream_changed) {
2734 player->gapless.start_time += player->gapless.next_pts;
2735 player->gapless.stream_changed = FALSE;
2738 debug_log ("event: %" GST_PTR_FORMAT, event);
2739 gst_event_copy_segment (event, &segment);
2741 if (segment.format == GST_FORMAT_TIME)
2743 segment.base = player->gapless.start_time;
2744 debug_log ("base of segment: %" GST_TIME_FORMAT, GST_TIME_ARGS (segment.base));
2746 tmpev = gst_event_new_segment (&segment);
2747 gst_event_set_seqnum (tmpev, gst_event_get_seqnum (event));
2748 gst_event_unref (event);
2749 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2760 __mmplayer_gst_decode_pad_added (GstElement *elem, GstPad *pad, gpointer data)
2762 mm_player_t* player = NULL;
2763 GstElement* pipeline = NULL;
2764 GstElement* selector = NULL;
2765 GstElement* fakesink = NULL;
2766 GstCaps* caps = NULL;
2767 GstStructure* str = NULL;
2768 const gchar* name = NULL;
2769 GstPad* sinkpad = NULL;
2770 GstPad* srcpad = NULL;
2771 gboolean first_track = FALSE;
2773 enum MainElementID elemId = MMPLAYER_M_NUM;
2774 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2777 player = (mm_player_t*)data;
2779 return_if_fail (elem && pad);
2780 return_if_fail (player && player->pipeline && player->pipeline->mainbin);
2782 //debug_log ("pad-added signal handling\n");
2784 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
2786 /* get mimetype from caps */
2787 caps = gst_pad_query_caps (pad, NULL);
2790 debug_error ("cannot get caps from pad.\n");
2794 str = gst_caps_get_structure (caps, 0);
2797 debug_error ("cannot get structure from caps.\n");
2801 name = gst_structure_get_name (str);
2804 debug_error ("cannot get mimetype from structure.\n");
2808 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2809 //debug_log ("detected mimetype : %s\n", name);
2811 if (strstr(name, "video"))
2814 mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &stype);
2816 /* don't make video because of not required, and not support multiple track */
2817 if (stype == MM_DISPLAY_SURFACE_NULL)
2819 debug_log ("no video sink by null surface or multiple track");
2820 gchar *caps_str = gst_caps_to_string(caps);
2821 if (strstr(caps_str, "ST12") || strstr(caps_str, "SN12"))
2823 player->set_mode.video_zc = TRUE;
2825 MMPLAYER_FREEIF( caps_str );
2827 if (player->v_stream_caps)
2829 gst_caps_unref(player->v_stream_caps);
2830 player->v_stream_caps = NULL;
2833 debug_log ("create fakesink instead of videobin");
2836 fakesink = gst_element_factory_make ("fakesink", NULL);
2837 if (fakesink == NULL)
2839 debug_error ("ERROR : fakesink create error\n");
2843 player->video_fakesink = fakesink;
2845 gst_bin_add (GST_BIN(pipeline), fakesink);
2848 sinkpad = gst_element_get_static_pad (fakesink, "sink");
2850 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad))
2852 debug_warning ("failed to link fakesink\n");
2853 gst_object_unref (GST_OBJECT(fakesink));
2857 if (player->set_mode.media_packet_video_stream)
2858 player->video_cb_probe_id = gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_BUFFER, __mmplayer_video_stream_probe, player, NULL);
2860 g_object_set (G_OBJECT (fakesink), "async", TRUE, NULL);
2861 g_object_set (G_OBJECT (fakesink), "sync", TRUE, NULL);
2862 gst_element_set_state (fakesink, GST_STATE_PAUSED);
2866 __mmplayer_gst_decode_callback (elem, pad, player);
2870 if (strstr(name, "audio"))
2872 gint samplerate = 0;
2875 if (MMPLAYER_IS_ES_BUFF_SRC(player))
2877 __mmplayer_gst_decode_callback (elem, pad, player);
2881 debug_log ("audio selector \n");
2882 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
2883 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2885 gst_structure_get_int (str, "rate", &samplerate);
2886 gst_structure_get_int (str, "channels", &channels);
2888 if ((channels > 0 && samplerate == 0)) {//exclude audio decoding
2890 fakesink = gst_element_factory_make ("fakesink", NULL);
2891 if (fakesink == NULL)
2893 debug_error ("ERROR : fakesink create error\n");
2897 gst_bin_add (GST_BIN(pipeline), fakesink);
2900 sinkpad = gst_element_get_static_pad (fakesink, "sink");
2902 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad))
2904 debug_warning ("failed to link fakesink\n");
2905 gst_object_unref (GST_OBJECT(fakesink));
2909 g_object_set (G_OBJECT (fakesink), "async", TRUE, NULL);
2910 g_object_set (G_OBJECT (fakesink), "sync", TRUE, NULL);
2911 gst_element_set_state (fakesink, GST_STATE_PAUSED);
2916 else if (strstr(name, "text"))
2918 debug_log ("text selector \n");
2919 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
2920 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
2924 debug_error ("wrong elem id \n");
2929 if(strstr(name, "video"))
2932 selector = player->pipeline->mainbin[elemId].gst;
2934 if (selector == NULL)
2936 selector = gst_element_factory_make ("input-selector", NULL);
2937 debug_log ("Creating input-selector\n");
2938 if (selector == NULL)
2940 debug_error ("ERROR : input-selector create error\n");
2943 g_object_set (selector, "sync-streams", TRUE, NULL);
2945 player->pipeline->mainbin[elemId].id = elemId;
2946 player->pipeline->mainbin[elemId].gst = selector;
2949 // player->selector[stream_type].active_pad_index = DEFAULT_TRACK; // default
2951 srcpad = gst_element_get_static_pad (selector, "src");
2953 debug_log ("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2954 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
2955 __mmplayer_gst_selector_blocked, NULL, NULL);
2956 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
2957 __mmplayer_gst_selector_event_probe, player, NULL);
2959 gst_element_set_state (selector, GST_STATE_PAUSED);
2960 gst_bin_add (GST_BIN(pipeline), selector);
2964 debug_log ("input-selector is already created.\n");
2965 selector = player->pipeline->mainbin[elemId].gst;
2969 debug_log ("Calling request pad with selector %p \n", selector);
2970 sinkpad = gst_element_get_request_pad (selector, "sink_%u");
2972 debug_log ("got pad %s:%s from selector", GST_DEBUG_PAD_NAME (sinkpad));
2974 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad))
2976 debug_warning ("failed to link selector\n");
2977 gst_object_unref (GST_OBJECT(selector));
2983 debug_log ("this is first track --> active track \n");
2984 g_object_set (selector, "active-pad", sinkpad, NULL);
2987 _mmplayer_track_update_info(player, stream_type, sinkpad);
2995 gst_caps_unref (caps);
3000 gst_object_unref (GST_OBJECT(sinkpad));
3006 gst_object_unref (GST_OBJECT(srcpad));
3013 static void __mmplayer_handle_text_decode_path(mm_player_t* player, GstElement* text_selector)
3015 GstPad* srcpad = NULL;
3016 MMHandleType attrs = 0;
3017 gint active_index = 0;
3019 // [link] input-selector :: textbin
3020 srcpad = gst_element_get_static_pad (text_selector, "src");
3023 debug_error("failed to get srcpad from selector\n");
3027 debug_log ("got pad %s:%s from text selector\n", GST_DEBUG_PAD_NAME(srcpad));
3029 active_index = player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index;
3030 if ((active_index != DEFAULT_TRACK) &&
3031 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_TEXT, active_index) != MM_ERROR_NONE))
3033 debug_warning("failed to change text track\n");
3034 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index = DEFAULT_TRACK;
3037 player->no_more_pad = TRUE;
3038 __mmplayer_gst_decode_callback (text_selector, srcpad, player);
3040 debug_log ("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3041 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id)
3043 gst_pad_remove_probe (srcpad, player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id);
3044 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id = 0;
3047 debug_log("Total text tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
3049 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
3050 player->has_closed_caption = TRUE;
3052 attrs = MMPLAYER_GET_ATTRS(player);
3055 mm_attrs_set_int_by_name(attrs, "content_text_track_num",(gint)player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
3056 if (mmf_attrs_commit (attrs))
3057 debug_error("failed to commit.\n");
3061 debug_error("cannot get content attribute");
3066 gst_object_unref ( GST_OBJECT(srcpad) );
3071 int _mmplayer_gst_set_audio_channel(MMHandleType hplayer, MMPlayerAudioChannel ch_idx)
3073 int result = MM_ERROR_NONE;
3075 mm_player_t* player = (mm_player_t*)hplayer;
3076 MMPlayerGstElement* mainbin = NULL;
3077 gchar* change_pad_name = NULL;
3078 GstPad* sinkpad = NULL;
3079 GstCaps* caps = NULL;
3083 return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3085 debug_log ("Change Audio mode to %d\n", ch_idx);
3086 player->use_deinterleave = TRUE;
3088 if ((!player->pipeline) || (!player->pipeline->mainbin))
3090 debug_log ("pre setting : %d\n", ch_idx);
3092 player->audio_mode.active_pad_index = ch_idx;
3096 mainbin = player->pipeline->mainbin;
3098 if (mainbin[MMPLAYER_M_A_SELECTOR].gst == NULL)
3100 if (player->max_audio_channels < 2)
3102 debug_log ("mono channel track only\n");
3106 debug_warning ("selector doesn't exist\n");
3107 return result; /* keep playing */
3110 debug_log ("total_ch_num : %d\n", player->audio_mode.total_track_num);
3112 if (player->audio_mode.total_track_num < 2)
3114 debug_warning ("there is no another audio path\n");
3115 return result; /* keep playing */
3118 if ((ch_idx < 0) || (ch_idx >= player->audio_mode.total_track_num))
3120 debug_warning ("Not a proper ch_idx : %d \n", ch_idx);
3121 return result; /* keep playing */
3124 /*To get the new pad from the selector*/
3125 change_pad_name = g_strdup_printf ("sink%d", ch_idx);
3126 if (change_pad_name == NULL)
3128 debug_warning ("Pad does not exists\n");
3129 goto ERROR; /* keep playing */
3132 debug_log ("new active pad name: %s\n", change_pad_name);
3134 sinkpad = gst_element_get_static_pad (mainbin[MMPLAYER_M_A_SELECTOR].gst, change_pad_name);
3135 if (sinkpad == NULL)
3137 //result = MM_ERROR_PLAYER_INTERNAL;
3138 goto ERROR; /* keep playing */
3141 debug_log ("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
3142 g_object_set (mainbin[MMPLAYER_M_A_SELECTOR].gst, "active-pad", sinkpad, NULL);
3144 caps = gst_pad_get_current_caps(sinkpad);
3145 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
3147 __mmplayer_set_audio_attrs (player, caps);
3148 player->audio_mode.active_pad_index = ch_idx;
3153 gst_object_unref (sinkpad);
3155 MMPLAYER_FREEIF(change_pad_name);
3164 __mmplayer_gst_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
3166 mm_player_t* player = (mm_player_t*)data;
3167 GstElement* selector = NULL;
3168 GstElement* queue = NULL;
3170 GstPad* srcpad = NULL;
3171 GstPad* sinkpad = NULL;
3172 gchar* caps_str= NULL;
3175 return_if_fail (player && player->pipeline && player->pipeline->mainbin);
3177 caps_str = gst_caps_to_string(gst_pad_get_current_caps(pad));
3178 debug_log ("deinterleave new caps : %s\n", caps_str);
3179 MMPLAYER_FREEIF(caps_str);
3181 if ((queue = __mmplayer_element_create_and_link(player, pad, "queue")) == NULL)
3183 debug_error ("ERROR : queue create error\n");
3187 g_object_set(G_OBJECT(queue),
3188 "max-size-buffers", 10,
3189 "max-size-bytes", 0,
3190 "max-size-time", (guint64)0,
3193 selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
3197 debug_error("there is no audio channel selector.\n");
3201 srcpad = gst_element_get_static_pad (queue, "src");
3202 sinkpad = gst_element_get_request_pad (selector, "sink_%u");
3204 debug_log ("link (%s:%s - %s:%s)\n", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
3206 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad))
3208 debug_warning ("failed to link deinterleave - selector\n");
3212 gst_element_set_state (queue, GST_STATE_PAUSED);
3213 player->audio_mode.total_track_num++;
3219 gst_object_unref ( GST_OBJECT(srcpad) );
3225 gst_object_unref ( GST_OBJECT(sinkpad) );
3234 __mmplayer_gst_deinterleave_no_more_pads (GstElement *elem, gpointer data)
3236 mm_player_t* player = NULL;
3237 GstElement* selector = NULL;
3238 GstPad* sinkpad = NULL;
3239 gint active_index = 0;
3240 gchar* change_pad_name = NULL;
3241 GstCaps* caps = NULL; // no need to unref
3242 gint default_audio_ch = 0;
3245 player = (mm_player_t*) data;
3247 selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
3251 debug_error("there is no audio channel selector.\n");
3255 active_index = player->audio_mode.active_pad_index;
3257 if (active_index != default_audio_ch)
3259 gint audio_ch = default_audio_ch;
3261 /*To get the new pad from the selector*/
3262 change_pad_name = g_strdup_printf ("sink%d", active_index);
3263 if (change_pad_name != NULL)
3265 sinkpad = gst_element_get_static_pad (selector, change_pad_name);
3266 if (sinkpad != NULL)
3268 debug_log ("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
3269 g_object_set (selector, "active-pad", sinkpad, NULL);
3271 audio_ch = active_index;
3273 caps = gst_pad_get_current_caps(sinkpad);
3274 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
3276 __mmplayer_set_audio_attrs (player, caps);
3280 player->audio_mode.active_pad_index = audio_ch;
3281 debug_log("audio LR info (0:stereo) = %d\n", player->audio_mode.active_pad_index);
3287 gst_object_unref (sinkpad);
3294 __mmplayer_gst_build_deinterleave_path (GstElement *elem, GstPad *pad, gpointer data)
3296 mm_player_t* player = NULL;
3297 MMPlayerGstElement *mainbin = NULL;
3299 GstElement* tee = NULL;
3300 GstElement* stereo_queue = NULL;
3301 GstElement* mono_queue = NULL;
3302 GstElement* conv = NULL;
3303 GstElement* filter = NULL;
3304 GstElement* deinterleave = NULL;
3305 GstElement* selector = NULL;
3307 GstPad* srcpad = NULL;
3308 GstPad* selector_srcpad = NULL;
3309 GstPad* sinkpad = NULL;
3310 GstCaps* caps = NULL;
3311 gulong block_id = 0;
3316 player = (mm_player_t*) data;
3318 return_if_fail( elem && pad );
3319 return_if_fail( player && player->pipeline && player->pipeline->mainbin );
3321 mainbin = player->pipeline->mainbin;
3324 if ((tee = __mmplayer_element_create_and_link(player, pad, "tee")) == NULL)
3326 debug_error ("ERROR : tee create error\n");
3330 mainbin[MMPLAYER_M_A_TEE].id = MMPLAYER_M_A_TEE;
3331 mainbin[MMPLAYER_M_A_TEE].gst = tee;
3333 gst_element_set_state (tee, GST_STATE_PAUSED);
3336 srcpad = gst_element_get_request_pad (tee, "src_%u");
3337 if ((stereo_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL)
3339 debug_error ("ERROR : stereo queue create error\n");
3343 g_object_set(G_OBJECT(stereo_queue),
3344 "max-size-buffers", 10,
3345 "max-size-bytes", 0,
3346 "max-size-time", (guint64)0,
3349 player->pipeline->mainbin[MMPLAYER_M_A_Q1].id = MMPLAYER_M_A_Q1;
3350 player->pipeline->mainbin[MMPLAYER_M_A_Q1].gst = stereo_queue;
3354 gst_object_unref (GST_OBJECT(srcpad));
3358 srcpad = gst_element_get_request_pad (tee, "src_%u");
3360 if ((mono_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL)
3362 debug_error ("ERROR : mono queue create error\n");
3366 g_object_set(G_OBJECT(mono_queue),
3367 "max-size-buffers", 10,
3368 "max-size-bytes", 0,
3369 "max-size-time", (guint64)0,
3372 player->pipeline->mainbin[MMPLAYER_M_A_Q2].id = MMPLAYER_M_A_Q2;
3373 player->pipeline->mainbin[MMPLAYER_M_A_Q2].gst = mono_queue;
3375 gst_element_set_state (stereo_queue, GST_STATE_PAUSED);
3376 gst_element_set_state (mono_queue, GST_STATE_PAUSED);
3379 srcpad = gst_element_get_static_pad (mono_queue, "src");
3380 if ((conv = __mmplayer_element_create_and_link(player, srcpad, "audioconvert")) == NULL)
3382 debug_error ("ERROR : audioconvert create error\n");
3386 player->pipeline->mainbin[MMPLAYER_M_A_CONV].id = MMPLAYER_M_A_CONV;
3387 player->pipeline->mainbin[MMPLAYER_M_A_CONV].gst = conv;
3392 gst_object_unref (GST_OBJECT(srcpad));
3395 srcpad = gst_element_get_static_pad (conv, "src");
3397 if ((filter = __mmplayer_element_create_and_link(player, srcpad, "capsfilter")) == NULL)
3399 debug_error ("ERROR : capsfilter create error\n");
3403 player->pipeline->mainbin[MMPLAYER_M_A_FILTER].id = MMPLAYER_M_A_FILTER;
3404 player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst = filter;
3406 caps = gst_caps_from_string( "audio/x-raw-int, "
3407 "width = (int) 16, "
3408 "depth = (int) 16, "
3409 "channels = (int) 2");
3411 g_object_set (GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst), "caps", caps, NULL );
3412 gst_caps_unref( caps );
3414 gst_element_set_state (conv, GST_STATE_PAUSED);
3415 gst_element_set_state (filter, GST_STATE_PAUSED);
3420 gst_object_unref (GST_OBJECT(srcpad));
3423 srcpad = gst_element_get_static_pad (filter, "src");
3425 if ((deinterleave = __mmplayer_element_create_and_link(player, srcpad, "deinterleave")) == NULL)
3427 debug_error ("ERROR : deinterleave create error\n");
3431 g_object_set (deinterleave, "keep-positions", TRUE, NULL);
3433 MMPLAYER_SIGNAL_CONNECT (player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
3434 G_CALLBACK (__mmplayer_gst_deinterleave_pad_added), player);
3436 MMPLAYER_SIGNAL_CONNECT (player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
3437 G_CALLBACK (__mmplayer_gst_deinterleave_no_more_pads), player);
3439 player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].id = MMPLAYER_M_A_DEINTERLEAVE;
3440 player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].gst = deinterleave;
3443 selector = gst_element_factory_make ("input-selector", "audio-channel-selector");
3444 if (selector == NULL)
3446 debug_error ("ERROR : audio-selector create error\n");
3450 g_object_set (selector, "sync-streams", TRUE, NULL);
3451 gst_bin_add (GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), selector);
3453 player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].id = MMPLAYER_M_A_SELECTOR;
3454 player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst = selector;
3456 selector_srcpad = gst_element_get_static_pad (selector, "src");
3458 debug_log ("blocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3460 gst_pad_add_probe(selector_srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
3461 __mmplayer_gst_selector_blocked, NULL, NULL);
3465 gst_object_unref (GST_OBJECT(srcpad));
3469 srcpad = gst_element_get_static_pad(stereo_queue, "src");
3470 sinkpad = gst_element_get_request_pad (selector, "sink_%u");
3472 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad))
3474 debug_warning ("failed to link queue_stereo - selector\n");
3478 player->audio_mode.total_track_num++;
3480 g_object_set (selector, "active-pad", sinkpad, NULL);
3481 gst_element_set_state (deinterleave, GST_STATE_PAUSED);
3482 gst_element_set_state (selector, GST_STATE_PAUSED);
3484 __mmplayer_gst_decode_callback (selector, selector_srcpad, player);
3488 debug_log ("unblocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3491 gst_pad_remove_probe (selector_srcpad, block_id);
3497 gst_object_unref (GST_OBJECT(sinkpad));
3503 gst_object_unref (GST_OBJECT(srcpad));
3507 if (selector_srcpad)
3509 gst_object_unref (GST_OBJECT(selector_srcpad));
3510 selector_srcpad = NULL;
3518 __mmplayer_gst_decode_no_more_pads (GstElement *elem, gpointer data)
3520 mm_player_t* player = NULL;
3521 GstPad* srcpad = NULL;
3522 GstElement* audio_selector = NULL;
3523 GstElement* text_selector = NULL;
3524 MMHandleType attrs = 0;
3525 gint active_index = 0;
3526 gint64 dur_bytes = 0L;
3528 player = (mm_player_t*) data;
3530 debug_log("no-more-pad signal handling\n");
3532 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
3533 (player->cmd == MMPLAYER_COMMAND_UNREALIZE))
3535 debug_warning("no need to go more");
3537 if (player->gapless.reconfigure)
3539 player->gapless.reconfigure = FALSE;
3540 MMPLAYER_PLAYBACK_UNLOCK(player);
3546 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
3547 (MMPLAYER_IS_HTTP_STREAMING(player)) &&
3548 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
3549 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst))
3551 #define ESTIMATED_BUFFER_UNIT (1*1024*1024)
3553 if (NULL == player->streamer)
3555 debug_warning("invalid state for buffering");
3559 gdouble init_buffering_time = (gdouble)player->streamer->buffering_req.initial_second;
3560 guint buffer_bytes = init_buffering_time * ESTIMATED_BUFFER_UNIT;
3562 buffer_bytes = MAX(buffer_bytes, player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffering_bytes);
3563 debug_log("[Decodebin2] set use-buffering on Q2 (pre buffer time: %d sec, buffer size : %d)\n", (gint)init_buffering_time, buffer_bytes);
3565 init_buffering_time = (init_buffering_time != 0)?(init_buffering_time):(player->ini.http_buffering_time);
3567 if ( !gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
3568 debug_error("fail to get duration.\n");
3570 // enable use-buffering on queue2 instead of multiqueue (ex)audio only streaming
3571 // use file information was already set on Q2 when it was created.
3572 __mm_player_streaming_set_queue2(player->streamer,
3573 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
3574 TRUE, // use_buffering
3576 init_buffering_time,
3578 player->ini.http_buffering_limit, // high percent
3581 ((dur_bytes>0)?((guint64)dur_bytes):0));
3583 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
3584 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3587 active_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
3588 if ((active_index != DEFAULT_TRACK) &&
3589 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_AUDIO, active_index) != MM_ERROR_NONE))
3591 debug_warning("failed to change audio track\n");
3592 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index = DEFAULT_TRACK;
3595 // [link] input-selector :: audiobin
3596 srcpad = gst_element_get_static_pad (audio_selector, "src");
3599 debug_error("failed to get srcpad from selector\n");
3603 debug_log ("got pad %s:%s from selector\n", GST_DEBUG_PAD_NAME(srcpad));
3605 player->no_more_pad = TRUE;
3607 if ((player->use_deinterleave == TRUE) && (player->max_audio_channels >= 2))
3609 debug_log ("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3610 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id)
3612 gst_pad_remove_probe (srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3613 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3616 __mmplayer_gst_build_deinterleave_path(audio_selector, srcpad, player);
3620 __mmplayer_gst_decode_callback (audio_selector, srcpad, player);
3622 debug_log ("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3623 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id)
3625 gst_pad_remove_probe (srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3626 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3630 debug_log("Total audio tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3632 attrs = MMPLAYER_GET_ATTRS(player);
3635 mm_attrs_set_int_by_name(attrs, "content_audio_track_num",(gint)player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3636 if (mmf_attrs_commit (attrs))
3637 debug_error("failed to commit.\n");
3641 debug_error("cannot get content attribute");
3646 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst))
3648 debug_log ("There is no audio track : remove audiobin");
3650 __mmplayer_release_signal_connection( player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN );
3651 __mmplayer_del_sink ( player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst );
3653 MMPLAYER_RELEASE_ELEMENT ( player, player->pipeline->audiobin, MMPLAYER_A_BIN );
3654 MMPLAYER_FREEIF ( player->pipeline->audiobin )
3657 if (player->num_dynamic_pad == 0)
3659 __mmplayer_pipeline_complete (NULL, player);
3664 if (!MMPLAYER_IS_ES_BUFF_SRC(player))
3668 __mmplayer_handle_text_decode_path(player, text_selector);
3677 gst_object_unref ( GST_OBJECT(srcpad) );
3681 if (player->gapless.reconfigure)
3683 player->gapless.reconfigure = FALSE;
3684 MMPLAYER_PLAYBACK_UNLOCK(player);
3689 __mmplayer_gst_decode_callback(GstElement *elem, GstPad *pad, gpointer data) // @
3691 mm_player_t* player = NULL;
3692 MMHandleType attrs = 0;
3693 GstElement* pipeline = NULL;
3694 GstCaps* caps = NULL;
3695 gchar* caps_str = NULL;
3696 GstStructure* str = NULL;
3697 const gchar* name = NULL;
3698 GstPad* sinkpad = NULL;
3699 GstElement* sinkbin = NULL;
3700 gboolean reusing = FALSE;
3701 GstElement *text_selector = NULL;
3704 player = (mm_player_t*) data;
3706 return_if_fail( elem && pad );
3707 return_if_fail(player && player->pipeline && player->pipeline->mainbin);
3709 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
3711 attrs = MMPLAYER_GET_ATTRS(player);
3714 debug_error("cannot get content attribute\n");
3718 /* get mimetype from caps */
3719 caps = gst_pad_query_caps( pad, NULL );
3722 debug_error("cannot get caps from pad.\n");
3725 caps_str = gst_caps_to_string(caps);
3727 str = gst_caps_get_structure( caps, 0 );
3730 debug_error("cannot get structure from caps.\n");
3734 name = gst_structure_get_name(str);
3737 debug_error("cannot get mimetype from structure.\n");
3741 //debug_log("detected mimetype : %s\n", name);
3743 if (strstr(name, "audio"))
3745 if (player->pipeline->audiobin == NULL)
3747 if (MM_ERROR_NONE != __mmplayer_gst_create_audio_pipeline(player))
3749 debug_error("failed to create audiobin. continuing without audio\n");
3753 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3754 debug_log("creating audiosink bin success\n");
3759 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3760 debug_log("reusing audiobin\n");
3761 _mmplayer_update_content_attrs( player, ATTR_AUDIO);
3764 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num <= 0) // should not update if content have multi audio tracks
3765 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 1);
3767 player->audiosink_linked = 1;
3769 sinkpad = gst_element_get_static_pad( GST_ELEMENT(sinkbin), "sink" );
3772 debug_error("failed to get pad from sinkbin\n");
3776 else if (strstr(name, "video"))
3778 if (strstr(caps_str, "ST12") || strstr(caps_str, "SN12"))
3780 player->set_mode.video_zc = TRUE;
3783 if (player->pipeline->videobin == NULL)
3785 /* NOTE : not make videobin because application dose not want to play it even though file has video stream. */
3786 /* get video surface type */
3787 int surface_type = 0;
3788 mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &surface_type);
3790 if (surface_type == MM_DISPLAY_SURFACE_NULL)
3792 debug_log("not make videobin because it dose not want\n");
3796 if (MM_ERROR_NONE != __mmplayer_gst_create_video_pipeline(player, caps, surface_type) )
3798 debug_error("failed to create videobin. continuing without video\n");
3802 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3803 debug_log("creating videosink bin success\n");
3808 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3809 debug_log("re-using videobin\n");
3810 _mmplayer_update_content_attrs( player, ATTR_VIDEO);
3813 /* FIXIT : track number shouldn't be hardcoded */
3814 mm_attrs_set_int_by_name(attrs, "content_video_track_num", 1);
3815 player->videosink_linked = 1;
3817 /* NOTE : intermediate code before doing H/W subtitle compositon */
3818 if ( player->use_textoverlay && player->play_subtitle )
3820 debug_log("using textoverlay for external subtitle");
3821 /* check text bin has created well */
3822 if ( player->pipeline && player->pipeline->textbin )
3824 /* get sinkpad from textoverlay */
3825 sinkpad = gst_element_get_static_pad(
3826 GST_ELEMENT(player->pipeline->textbin[MMPLAYER_T_BIN].gst),
3830 debug_error("failed to get sink pad from textoverlay");
3834 /* link new pad with textoverlay first */
3835 if ( GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad) )
3837 debug_error("failed to get pad from sinkbin\n");
3841 gst_object_unref(sinkpad);
3844 /* alright, override pad to textbin.src for futher link */
3845 pad = gst_element_get_static_pad(
3846 GST_ELEMENT(player->pipeline->textbin[MMPLAYER_T_BIN].gst),
3850 debug_error("failed to get sink pad from textoverlay");
3856 debug_error("should not reach here.");
3861 sinkpad = gst_element_get_static_pad( GST_ELEMENT(sinkbin), "sink" );
3864 debug_error("failed to get pad from sinkbin\n");
3868 else if (strstr(name, "text"))
3870 if (player->pipeline->textbin == NULL)
3872 MMPlayerGstElement* mainbin = NULL;
3874 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player))
3876 debug_error("failed to create textbin. continuing without text\n");
3880 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3881 debug_log("creating textsink bin success\n");
3883 /* FIXIT : track number shouldn't be hardcoded */
3884 mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1);
3886 player->textsink_linked = 1;
3887 debug_msg("player->textsink_linked set to 1\n");
3889 sinkpad = gst_element_get_static_pad( GST_ELEMENT(sinkbin), "text_sink" );
3892 debug_error("failed to get pad from sinkbin\n");
3896 mainbin = player->pipeline->mainbin;
3898 if (!mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst)
3900 /* input selector */
3901 text_selector = gst_element_factory_make("input-selector", "subtitle_inselector");
3902 if ( !text_selector )
3904 debug_error ( "failed to create subtitle input selector element\n" );
3907 g_object_set (text_selector, "sync-streams", TRUE, NULL);
3909 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].id = MMPLAYER_M_T_INPUT_SELECTOR;
3910 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst = text_selector;
3913 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state (text_selector, GST_STATE_READY))
3915 debug_error("failed to set state(READY) to sinkbin\n");
3919 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), text_selector))
3921 debug_warning("failed to add subtitle input selector\n");
3925 debug_log ("created element input-selector");
3930 debug_log ("already having subtitle input selector");
3931 text_selector = mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3937 if (!player->textsink_linked)
3939 debug_log("re-using textbin\n");
3942 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3944 player->textsink_linked = 1;
3945 debug_msg("player->textsink_linked set to 1\n");
3949 debug_log("ignoring internal subtutle since external subtitle is available");
3955 debug_warning("unknown type of elementary stream! ignoring it...\n");
3964 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state( sinkbin, GST_STATE_READY ) )
3966 debug_error("failed to set state(READY) to sinkbin\n");
3970 /* Added for multi audio support to avoid adding audio bin again*/
3972 if ( FALSE == gst_bin_add( GST_BIN(pipeline), sinkbin ) )
3974 debug_error("failed to add sinkbin to pipeline\n");
3980 if (GST_PAD_LINK_OK != GST_PAD_LINK (pad, sinkpad))
3982 debug_error("failed to get pad from sinkbin\n");
3989 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state (sinkbin, GST_STATE_PAUSED))
3991 debug_error("failed to set state(PAUSED) to sinkbin\n");
3997 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state (text_selector, GST_STATE_PAUSED))
3999 debug_error("failed to set state(PAUSED) to sinkbin\n");
4005 gst_object_unref (sinkpad);
4009 debug_log ("linking sink bin success\n");
4011 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
4012 * streaming task. if the task blocked, then buffer will not flow to the next element
4013 * ( autoplugging element ). so this is special hack for streaming. please try to remove it
4015 /* dec stream count. we can remove fakesink if it's zero */
4016 if (player->num_dynamic_pad)
4017 player->num_dynamic_pad--;
4019 debug_log ("no more pads: %d stream count dec : %d (num of dynamic pad)\n", player->no_more_pad, player->num_dynamic_pad);
4021 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
4023 __mmplayer_pipeline_complete (NULL, player);
4026 /* FIXIT : please leave a note why this code is needed */
4027 if(MMPLAYER_IS_WFD_STREAMING( player ))
4029 player->no_more_pad = TRUE;
4034 MMPLAYER_FREEIF(caps_str);
4037 gst_caps_unref( caps );
4040 gst_object_unref(GST_OBJECT(sinkpad));
4042 /* flusing out new attributes */
4043 if ( mmf_attrs_commit ( attrs ) )
4045 debug_error("failed to comit attributes\n");
4052 __mmplayer_gst_element_link_bucket(GList* element_bucket) // @
4054 GList* bucket = element_bucket;
4055 MMPlayerGstElement* element = NULL;
4056 MMPlayerGstElement* prv_element = NULL;
4057 gint successful_link_count = 0;
4061 return_val_if_fail(element_bucket, -1);
4063 prv_element = (MMPlayerGstElement*)bucket->data;
4064 bucket = bucket->next;
4066 for ( ; bucket; bucket = bucket->next )
4068 element = (MMPlayerGstElement*)bucket->data;
4070 if ( element && element->gst )
4072 /* If next element is audio appsrc then make a seprate audio pipeline */
4073 if (!strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),"audio_appsrc") ||
4074 !strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),"subtitle_appsrc"))
4076 prv_element = element;
4080 if ( GST_ELEMENT_LINK(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst)) )
4082 debug_log("linking [%s] to [%s] success\n",
4083 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4084 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)) );
4085 successful_link_count ++;
4089 debug_log("linking [%s] to [%s] failed\n",
4090 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4091 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)) );
4096 prv_element = element;
4101 return successful_link_count;
4105 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket) // @
4107 GList* bucket = element_bucket;
4108 MMPlayerGstElement* element = NULL;
4109 int successful_add_count = 0;
4113 return_val_if_fail(element_bucket, 0);
4114 return_val_if_fail(bin, 0);
4116 for ( ; bucket; bucket = bucket->next )
4118 element = (MMPlayerGstElement*)bucket->data;
4120 if ( element && element->gst )
4122 if( !gst_bin_add(bin, GST_ELEMENT(element->gst)) )
4124 debug_log("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed\n",
4125 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
4126 GST_ELEMENT_NAME(GST_ELEMENT(bin) ) );
4129 successful_add_count ++;
4135 return successful_add_count;
4138 static void __mmplayer_gst_caps_notify_cb (GstPad * pad, GParamSpec * unused, gpointer data)
4140 mm_player_t* player = (mm_player_t*) data;
4141 GstCaps *caps = NULL;
4142 GstStructure *str = NULL;
4147 return_if_fail ( pad )
4148 return_if_fail ( unused )
4149 return_if_fail ( data )
4151 caps = gst_pad_get_current_caps( pad );
4157 str = gst_caps_get_structure(caps, 0);
4163 name = gst_structure_get_name(str);
4169 debug_log("name = %s\n", name);
4171 if (strstr(name, "audio"))
4173 _mmplayer_update_content_attrs (player, ATTR_AUDIO);
4175 if (player->audio_stream_changed_cb)
4177 debug_error("call the audio stream changed cb\n");
4178 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
4181 else if (strstr(name, "video"))
4183 _mmplayer_update_content_attrs (player, ATTR_VIDEO);
4185 if (player->video_stream_changed_cb)
4187 debug_error("call the video stream changed cb\n");
4188 player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
4198 gst_caps_unref(caps);
4208 * This function is to create audio pipeline for playing.
4210 * @param player [in] handle of player
4212 * @return This function returns zero on success.
4214 * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_pipeline
4216 #define MMPLAYER_CREATEONLY_ELEMENT(x_bin, x_id, x_factory, x_name) \
4217 x_bin[x_id].id = x_id;\
4218 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4219 if ( ! x_bin[x_id].gst )\
4221 debug_error("failed to create %s \n", x_factory);\
4225 #define MMPLAYER_CREATE_ELEMENT_ADD_BIN(x_bin, x_id, x_factory, x_name, y_bin, x_player) \
4226 x_bin[x_id].id = x_id;\
4227 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4228 if ( ! x_bin[x_id].gst )\
4230 debug_error("failed to create %s \n", x_factory);\
4235 if (x_player->ini.set_dump_element_flag)\
4236 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
4238 if( !gst_bin_add(GST_BIN(y_bin), GST_ELEMENT(x_bin[x_id].gst)))\
4240 debug_log("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed\n",\
4241 GST_ELEMENT_NAME(GST_ELEMENT(x_bin[x_id].gst)),\
4242 GST_ELEMENT_NAME(GST_ELEMENT(y_bin) ) );\
4246 /* macro for code readability. just for sinkbin-creation functions */
4247 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
4250 x_bin[x_id].id = x_id;\
4251 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4252 if ( ! x_bin[x_id].gst )\
4254 debug_error("failed to create %s \n", x_factory);\
4259 if (x_player->ini.set_dump_element_flag)\
4260 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
4262 if ( x_add_bucket )\
4263 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
4267 __mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4269 mm_player_t* player = (mm_player_t*) data;
4274 gint endianness = 0;
4275 guint64 channel_mask = 0;
4277 MMPlayerAudioStreamDataType audio_stream = { 0, };
4278 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4281 return_if_fail(player->audio_stream_render_cb_ex);
4283 debug_log ("__mmplayer_audio_stream_decoded_render_cb new pad: %s", GST_PAD_NAME (pad));
4285 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4286 audio_stream.data = mapinfo.data;
4287 audio_stream.data_size = mapinfo.size;
4289 GstCaps *caps = gst_pad_get_current_caps( pad );
4290 GstStructure *structure = gst_caps_get_structure (caps, 0);
4292 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
4293 gst_structure_get_int (structure, "rate", &rate);
4294 gst_structure_get_int (structure, "channels", &channel);
4295 gst_structure_get_int (structure, "depth", &depth);
4296 gst_structure_get_int (structure, "endianness", &endianness);
4297 gst_structure_get (structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
4299 gst_caps_unref(GST_CAPS(caps));
4301 audio_stream.bitrate = rate;
4302 audio_stream.channel = channel;
4303 audio_stream.depth = depth;
4304 audio_stream.is_little_endian = (endianness == 1234 ? 1 : 0);
4305 audio_stream.channel_mask = channel_mask;
4306 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);
4307 player->audio_stream_render_cb_ex(&audio_stream, player->audio_stream_cb_user_param);
4308 gst_buffer_unmap(buffer, &mapinfo);
4314 __mmplayer_gst_audio_deinterleave_pad_added (GstElement *elem, GstPad *pad, gpointer data)
4316 mm_player_t* player = (mm_player_t*)data;
4317 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4318 GstPad* sinkpad = NULL;
4319 GstElement *queue = NULL, *sink = NULL;
4322 return_if_fail (player && player->pipeline && player->pipeline->mainbin);
4324 queue = gst_element_factory_make ("queue", NULL);
4327 debug_log ("fail make queue\n");
4331 sink = gst_element_factory_make ("fakesink", NULL);
4334 debug_log ("fail make fakesink\n");
4338 gst_bin_add_many (GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
4340 if (!gst_element_link_pads_full (queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING))
4342 debug_warning("failed to link queue & sink\n");
4346 sinkpad = gst_element_get_static_pad (queue, "sink");
4348 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad))
4350 debug_warning ("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad));
4354 debug_error("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync);
4356 gst_object_unref (sinkpad);
4357 g_object_set (sink, "sync", player->audio_stream_sink_sync, NULL);
4358 g_object_set (sink, "signal-handoffs", TRUE, NULL);
4360 gst_element_set_state (sink, GST_STATE_PAUSED);
4361 gst_element_set_state (queue, GST_STATE_PAUSED);
4363 MMPLAYER_SIGNAL_CONNECT( player,
4365 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4367 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
4374 debug_error("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n");
4377 gst_object_unref(GST_OBJECT(queue));
4382 gst_object_unref(GST_OBJECT(sink));
4387 gst_object_unref ( GST_OBJECT(sinkpad) );
4394 void __mmplayer_gst_set_audiosink_property(mm_player_t* player, MMHandleType attrs)
4396 #define MAX_PROPS_LEN 64
4397 gint volume_type = 0;
4398 gint latency_mode = 0;
4399 gchar *stream_type = NULL;
4400 gchar *latency = NULL;
4402 gchar stream_props[MAX_PROPS_LEN] = {0,};
4403 GstStructure *props = NULL;
4406 * It should be set after player creation through attribute.
4407 * But, it can not be changed during playing.
4410 mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
4411 mm_attrs_get_string_by_name (attrs, "sound_stream_type", &stream_type );
4415 debug_error("stream_type is null.\n");
4419 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d", stream_type, stream_id);
4420 props = gst_structure_from_string(stream_props, NULL);
4421 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
4422 debug_log("stream_id[%d], stream_type[%s], result[%s].\n", stream_id, stream_type, stream_props);
4425 mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
4426 mm_attrs_get_int_by_name(attrs, "sound_volume_type", &volume_type);
4428 switch (latency_mode)
4430 case AUDIO_LATENCY_MODE_LOW:
4431 latency = g_strndup("low", 3);
4433 case AUDIO_LATENCY_MODE_MID:
4434 latency = g_strndup("mid", 3);
4436 case AUDIO_LATENCY_MODE_HIGH:
4437 latency = g_strndup("high", 4);
4441 /* hook sound_type if emergency case */
4442 if (player->sound_focus.focus_changed_msg == MM_PLAYER_FOCUS_CHANGED_BY_EMERGENCY)
4444 debug_log ("emergency session, hook sound_type from [%d] to [%d]\n", volume_type, MM_SOUND_VOLUME_TYPE_EMERGENCY);
4445 volume_type = MM_SOUND_VOLUME_TYPE_EMERGENCY;
4447 #if 0 //need to check
4448 if (player->sound_focus.user_route_policy != 0)
4450 route_path = player->sound_focus.user_route_policy;
4453 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
4454 "latency", latency_mode,
4457 debug_log("audiosink property status...volume type:%d, user-route=%d, latency=%d \n",
4458 volume_type, route_path, latency_mode);
4463 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
4467 debug_log("audiosink property - volume type=%d, latency=%s \n",
4468 volume_type, latency);
4476 __mmplayer_gst_create_audio_pipeline(mm_player_t* player)
4478 MMPlayerGstElement* first_element = NULL;
4479 MMPlayerGstElement* audiobin = NULL;
4480 MMHandleType attrs = 0;
4482 GstPad *ghostpad = NULL;
4483 GList* element_bucket = NULL;
4484 gboolean link_audio_sink_now = TRUE;
4489 return_val_if_fail( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
4492 audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
4495 debug_error("failed to allocate memory for audiobin\n");
4496 return MM_ERROR_PLAYER_NO_FREE_SPACE;
4499 attrs = MMPLAYER_GET_ATTRS(player);
4502 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
4503 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
4504 if ( !audiobin[MMPLAYER_A_BIN].gst )
4506 debug_error("failed to create audiobin\n");
4511 player->pipeline->audiobin = audiobin;
4513 player->set_mode.pcm_extraction = __mmplayer_can_extract_pcm(player);
4515 /* Adding audiotp plugin for reverse trickplay feature */
4516 // MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TP, "audiotp", "audio trickplay", TRUE, player);
4519 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
4522 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", TRUE, player);
4524 if (player->set_mode.pcm_extraction) // pcm extraction only and no sound output
4526 if(player->audio_stream_render_cb_ex)
4528 char *caps_str = NULL;
4529 GstCaps* caps = NULL;
4530 gchar *format = NULL;
4533 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4535 mm_attrs_get_string_by_name (player->attrs, "pcm_audioformat", &format );
4537 debug_log("contents : format: %s samplerate : %d pcm_channel: %d", format, player->pcm_samplerate, player->pcm_channel);
4539 caps = gst_caps_new_simple ("audio/x-raw",
4540 "format", G_TYPE_STRING, format,
4541 "rate", G_TYPE_INT, player->pcm_samplerate,
4542 "channels", G_TYPE_INT, player->pcm_channel,
4544 caps_str = gst_caps_to_string(caps);
4545 debug_log("new caps : %s\n", caps_str);
4547 g_object_set (GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL );
4550 gst_caps_unref( caps );
4551 MMPLAYER_FREEIF( caps_str );
4553 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
4555 g_object_set (G_OBJECT (audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
4556 /* raw pad handling signal */
4557 MMPLAYER_SIGNAL_CONNECT( player,
4558 (audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
4559 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
4560 G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), player);
4564 int dst_samplerate = 0;
4565 int dst_channels = 0;
4567 char *caps_str = NULL;
4568 GstCaps* caps = NULL;
4570 /* get conf. values */
4571 mm_attrs_multiple_get(player->attrs,
4573 "pcm_extraction_samplerate", &dst_samplerate,
4574 "pcm_extraction_channels", &dst_channels,
4575 "pcm_extraction_depth", &dst_depth,
4579 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4580 caps = gst_caps_new_simple ("audio/x-raw",
4581 "rate", G_TYPE_INT, dst_samplerate,
4582 "channels", G_TYPE_INT, dst_channels,
4583 "depth", G_TYPE_INT, dst_depth,
4585 caps_str = gst_caps_to_string(caps);
4586 debug_log("new caps : %s\n", caps_str);
4588 g_object_set (GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL );
4591 gst_caps_unref( caps );
4592 MMPLAYER_FREEIF( caps_str );
4595 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "fakesink", TRUE, player);
4598 g_object_set (G_OBJECT (audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL);
4601 else // normal playback
4603 //GstCaps* caps = NULL;
4606 /* for logical volume control */
4607 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
4608 g_object_set(G_OBJECT (audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
4610 if (player->sound.mute)
4612 debug_log("mute enabled\n");
4613 g_object_set(G_OBJECT (audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
4618 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE, player);
4619 caps = gst_caps_from_string( "audio/x-raw-int, "
4620 "endianness = (int) LITTLE_ENDIAN, "
4621 "signed = (boolean) true, "
4622 "width = (int) 16, "
4623 "depth = (int) 16" );
4624 g_object_set (GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL );
4625 gst_caps_unref( caps );
4628 /* chech if multi-chennels */
4629 if (player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)
4631 GstPad *srcpad = NULL;
4632 GstCaps *caps = NULL;
4634 if ((srcpad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "src")))
4636 if ((caps = gst_pad_query_caps(srcpad, NULL)))
4638 //MMPLAYER_LOG_GST_CAPS_TYPE(caps);
4639 GstStructure *str = gst_caps_get_structure(caps, 0);
4641 gst_structure_get_int (str, "channels", &channels);
4642 gst_caps_unref(caps);
4644 gst_object_unref(srcpad);
4648 /* audio effect element. if audio effect is enabled */
4649 if ( (strcmp(player->ini.audioeffect_element, ""))
4651 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom))
4653 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
4655 debug_log("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
4657 if ( (!player->bypass_audio_effect)
4658 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom) )
4660 if ( MM_AUDIO_EFFECT_TYPE_CUSTOM == player->audio_effect_info.effect_type )
4662 if (!_mmplayer_audio_effect_custom_apply(player))
4664 debug_msg("apply audio effect(custom) setting success\n");
4669 if ( (strcmp(player->ini.audioeffect_element_custom, ""))
4670 && (player->set_mode.rich_audio) )
4672 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
4675 if (!MMPLAYER_IS_RTSP_STREAMING(player))
4677 if (player->set_mode.rich_audio && channels <= 2)
4678 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VSP, "audiovsp", "x-speed", TRUE, player);
4681 /* create audio sink */
4682 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", link_audio_sink_now, player);
4685 g_object_set (G_OBJECT (audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
4686 g_object_set (G_OBJECT (audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
4688 if (player->videodec_linked && player->ini.use_system_clock)
4690 debug_log("system clock will be used.\n");
4691 g_object_set (G_OBJECT (audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
4694 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
4695 __mmplayer_gst_set_audiosink_property(player, attrs);
4698 if (audiobin[MMPLAYER_A_SINK].gst)
4700 GstPad *sink_pad = NULL;
4701 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
4702 MMPLAYER_SIGNAL_CONNECT (player, sink_pad, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4703 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
4704 gst_object_unref (GST_OBJECT(sink_pad));
4707 __mmplayer_add_sink( player, audiobin[MMPLAYER_A_SINK].gst );
4709 /* adding created elements to bin */
4710 debug_log("adding created elements to bin\n");
4711 if( !__mmplayer_gst_element_add_bucket_to_bin( GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket ))
4713 debug_error("failed to add elements\n");
4717 /* linking elements in the bucket by added order. */
4718 debug_log("Linking elements in the bucket by added order.\n");
4719 if ( __mmplayer_gst_element_link_bucket(element_bucket) == -1 )
4721 debug_error("failed to link elements\n");
4725 /* get first element's sinkpad for creating ghostpad */
4726 first_element = (MMPlayerGstElement *)element_bucket->data;
4728 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
4731 debug_error("failed to get pad from first element of audiobin\n");
4735 ghostpad = gst_ghost_pad_new("sink", pad);
4738 debug_error("failed to create ghostpad\n");
4742 if ( FALSE == gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad) )
4744 debug_error("failed to add ghostpad to audiobin\n");
4748 player->gapless.audio_data_probe_id = gst_pad_add_probe(ghostpad, GST_PAD_PROBE_TYPE_BUFFER,
4749 __mmplayer_audio_data_probe, player, NULL);
4751 gst_object_unref(pad);
4753 g_list_free(element_bucket);
4755 mm_attrs_set_int_by_name(attrs, "content_audio_found", TRUE);
4759 return MM_ERROR_NONE;
4763 debug_log("ERROR : releasing audiobin\n");
4766 gst_object_unref(GST_OBJECT(pad));
4769 gst_object_unref(GST_OBJECT(ghostpad));
4771 g_list_free( element_bucket );
4773 /* release element which are not added to bin */
4774 for ( i = 1; i < MMPLAYER_A_NUM; i++ ) /* NOTE : skip bin */
4776 if ( audiobin[i].gst )
4778 GstObject* parent = NULL;
4779 parent = gst_element_get_parent( audiobin[i].gst );
4783 gst_object_unref(GST_OBJECT(audiobin[i].gst));
4784 audiobin[i].gst = NULL;
4788 gst_object_unref(GST_OBJECT(parent));
4793 /* release audiobin with it's childs */
4794 if ( audiobin[MMPLAYER_A_BIN].gst )
4796 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
4799 MMPLAYER_FREEIF( audiobin );
4801 player->pipeline->audiobin = NULL;
4803 return MM_ERROR_PLAYER_INTERNAL;
4806 static GstPadProbeReturn
4807 __mmplayer_audio_stream_probe (GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4809 mm_player_t* player = (mm_player_t*) u_data;
4810 GstBuffer *pad_buffer = gst_pad_probe_info_get_buffer(info);
4811 GstMapInfo probe_info = GST_MAP_INFO_INIT;
4813 gst_buffer_map(pad_buffer, &probe_info, GST_MAP_READ);
4815 if (player->audio_stream_cb && probe_info.size && probe_info.data)
4816 player->audio_stream_cb((void *)probe_info.data, probe_info.size, player->audio_stream_cb_user_param);
4818 return GST_PAD_PROBE_OK;
4821 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
4823 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
4826 static GstPadProbeReturn
4827 __mmplayer_video_stream_probe (GstPad *pad, GstPadProbeInfo *info, gpointer user_data)
4829 GstCaps *caps = NULL;
4830 MMPlayerVideoStreamDataType stream;
4831 MMVideoBuffer *video_buffer = NULL;
4832 GstMemory *dataBlock = NULL;
4833 GstMemory *metaBlock = NULL;
4834 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4835 GstStructure *structure = NULL;
4836 const gchar *string_format = NULL;
4837 unsigned int fourcc = 0;
4838 mm_player_t* player = (mm_player_t*)user_data;
4839 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
4841 return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
4842 return_val_if_fail(gst_buffer_n_memory(buffer) , GST_PAD_PROBE_DROP);
4844 caps = gst_pad_get_current_caps(pad);
4846 debug_error( "Caps is NULL." );
4847 return GST_PAD_PROBE_OK;
4850 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
4852 /* clear stream data structure */
4853 memset(&stream, 0x0, sizeof(MMPlayerVideoStreamDataType));
4855 structure = gst_caps_get_structure( caps, 0 );
4856 gst_structure_get_int(structure, "width", &(stream.width));
4857 gst_structure_get_int(structure, "height", &(stream.height));
4858 string_format = gst_structure_get_string(structure, "format");
4860 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
4862 stream.format = util_get_pixtype(fourcc);
4863 gst_caps_unref( caps );
4867 debug_log( "Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
4868 GST_BUFFER_DATA(buffer), stream.width, stream.height, stream.format );
4871 if (stream.width == 0 || stream.height == 0 || stream.format == MM_PIXEL_FORMAT_INVALID) {
4872 debug_error("Wrong condition!!");
4876 /* set size and timestamp */
4877 dataBlock = gst_buffer_peek_memory(buffer, 0);
4878 stream.length_total = gst_memory_get_sizes(dataBlock, NULL, NULL);
4879 stream.timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/1000000); /* nano sec -> mili sec */
4881 /* check zero-copy */
4882 if (player->set_mode.video_zc &&
4883 player->set_mode.media_packet_video_stream &&
4884 gst_buffer_n_memory(buffer) > 1) {
4885 metaBlock = gst_buffer_peek_memory(buffer, 1);
4886 gst_memory_map(metaBlock, &mapinfo, GST_MAP_READ);
4887 video_buffer = (MMVideoBuffer *)mapinfo.data;
4892 if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
4893 /* copy pointer of tbm bo, stride, elevation */
4894 memcpy(stream.bo, video_buffer->handle.bo,
4895 sizeof(void *) * MM_VIDEO_BUFFER_PLANE_MAX);
4897 else if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_PHYSICAL_ADDRESS) {
4898 memcpy(stream.data, video_buffer->data,
4899 sizeof(void *) * MM_VIDEO_BUFFER_PLANE_MAX);
4901 memcpy(stream.stride, video_buffer->stride_width,
4902 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
4903 memcpy(stream.elevation, video_buffer->stride_height,
4904 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
4905 /* set gst buffer */
4906 stream.internal_buffer = buffer;
4908 tbm_bo_handle thandle;
4909 int stride = ((stream.width + 3) & (~3));
4910 int elevation = stream.height;
4911 int size = stride * elevation * 3 / 2;
4913 gst_ret = gst_memory_map(dataBlock, &mapinfo, GST_MAP_READWRITE);
4915 debug_error("fail to gst_memory_map");
4916 return GST_PAD_PROBE_OK;
4919 stream.stride[0] = stride;
4920 stream.elevation[0] = elevation;
4921 if(stream.format == MM_PIXEL_FORMAT_I420) {
4922 stream.stride[1] = stream.stride[2] = stride / 2;
4923 stream.elevation[1] = stream.elevation[2] = elevation / 2;
4926 debug_error("Not support format %d", stream.format);
4927 gst_memory_unmap(dataBlock, &mapinfo);
4928 return GST_PAD_PROBE_OK;
4931 stream.bo[0] = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
4933 debug_error("Fail to tbm_bo_alloc!!");
4934 gst_memory_unmap(dataBlock, &mapinfo);
4935 return GST_PAD_PROBE_OK;
4937 thandle = tbm_bo_map(stream.bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
4938 if(thandle.ptr && mapinfo.data)
4939 memcpy(thandle.ptr, mapinfo.data, size);
4941 debug_error("data pointer is wrong. dest : %p, src : %p",
4942 thandle.ptr, mapinfo.data);
4944 tbm_bo_unmap(stream.bo[0]);
4947 if (player->video_stream_cb) {
4948 player->video_stream_cb(&stream, player->video_stream_cb_user_param);
4952 gst_memory_unmap(metaBlock, &mapinfo);
4954 gst_memory_unmap(dataBlock, &mapinfo);
4955 tbm_bo_unref(stream.bo[0]);
4958 return GST_PAD_PROBE_OK;
4962 __mmplayer_gst_create_video_filters(mm_player_t* player, GList** bucket, gboolean use_video_stream)
4964 gchar* video_csc = "videoconvert"; // default colorspace converter
4965 GList* element_bucket = *bucket;
4967 return_val_if_fail(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4971 if (!player->set_mode.media_packet_video_stream && use_video_stream)
4973 if (player->set_mode.video_zc && strlen(player->ini.videoconverter_element) > 0)
4975 video_csc = player->ini.videoconverter_element;
4978 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
4979 debug_log("using video converter: %s", video_csc);
4981 if ( !player->set_mode.video_zc)
4983 gint width = 0; //width of video
4984 gint height = 0; //height of video
4985 GstCaps* video_caps = NULL;
4986 GstStructure *structure = NULL;
4988 /* rotator, scaler and capsfilter */
4989 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
4990 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_SCALE, "videoscale", "video scaler", TRUE, player);
4991 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CAPS, "capsfilter", "videocapsfilter", TRUE, player);
4993 /* get video stream caps parsed by demuxer */
4995 mm_attrs_get_int_by_name(player->attrs, "display_width", &width);
4998 structure = gst_structure_new("video/x-raw", "width", G_TYPE_INT, width, NULL);
5000 mm_attrs_get_int_by_name(player->attrs, "display_height", &height);
5002 if(structure && height) {
5003 gst_structure_set (structure, "height", G_TYPE_INT, height, NULL);
5005 video_caps = gst_caps_new_full(structure, NULL);
5006 g_object_set (GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_CAPS].gst), "caps", video_caps, NULL );
5007 MMPLAYER_LOG_GST_CAPS_TYPE(video_caps);
5008 gst_caps_unref(video_caps);
5011 debug_error("fail to set capsfilter %p, width %d, height %d", structure, width, height);
5014 gst_structure_free(structure);
5020 MMDisplaySurfaceType surface_type = MM_DISPLAY_SURFACE_NULL;
5021 mm_attrs_get_int_by_name (player->attrs, "display_surface_type", (int *)&surface_type);
5023 if (player->set_mode.video_zc)
5025 if ( (surface_type == MM_DISPLAY_SURFACE_EVAS) && ( !strcmp(player->ini.videosink_element_evas, "evasimagesink")) )
5027 video_csc = player->ini.videoconverter_element;
5035 if (video_csc && (strcmp(video_csc, "")))
5037 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
5038 debug_log("using video converter: %s", video_csc);
5041 /* set video rotator */
5042 if ( !player->set_mode.video_zc )
5043 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
5046 #if !defined(__arm__)
5047 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_SCALE, "videoscale", "videoscaler", TRUE, player);
5051 *bucket = element_bucket;
5053 return MM_ERROR_NONE;
5058 return MM_ERROR_PLAYER_INTERNAL;
5062 * This function is to create video pipeline.
5064 * @param player [in] handle of player
5065 * caps [in] src caps of decoder
5066 * surface_type [in] surface type for video rendering
5068 * @return This function returns zero on success.
5070 * @see __mmplayer_gst_create_audio_pipeline, __mmplayer_gst_create_midi_pipeline
5074 * - x surface (arm/x86) : xvimagesink
5075 * - evas surface (arm) : evaspixmapsink
5076 * fimcconvert ! evasimagesink
5077 * - evas surface (x86) : videoconvertor ! videoflip ! evasimagesink
5080 __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
5084 GList*element_bucket = NULL;
5085 MMPlayerGstElement* first_element = NULL;
5086 MMPlayerGstElement* videobin = NULL;
5087 gchar *videosink_element = NULL;
5091 return_val_if_fail(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5094 videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
5097 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5100 player->pipeline->videobin = videobin;
5102 attrs = MMPLAYER_GET_ATTRS(player);
5105 debug_error("cannot get content attribute");
5106 return MM_ERROR_PLAYER_INTERNAL;
5110 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
5111 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
5112 if ( !videobin[MMPLAYER_V_BIN].gst )
5114 debug_error("failed to create videobin");
5118 if( player->use_video_stream ) // video stream callback, so send raw video data to application
5120 debug_log("using memsink\n");
5122 if ( __mmplayer_gst_create_video_filters(player, &element_bucket, TRUE) != MM_ERROR_NONE)
5125 /* finally, create video sink. output will be BGRA8888. */
5126 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, "avsysmemsink", "videosink", TRUE, player);
5128 MMPLAYER_SIGNAL_CONNECT( player,
5129 videobin[MMPLAYER_V_SINK].gst,
5130 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5132 G_CALLBACK(__mmplayer_videostream_cb),
5135 else // render video data using sink plugin like xvimagesink
5137 if ( __mmplayer_gst_create_video_filters(player, &element_bucket, FALSE) != MM_ERROR_NONE)
5140 /* set video sink */
5141 switch (surface_type)
5143 case MM_DISPLAY_SURFACE_X:
5144 if (strlen(player->ini.videosink_element_x) > 0)
5145 videosink_element = player->ini.videosink_element_x;
5149 case MM_DISPLAY_SURFACE_EVAS:
5150 if (strlen(player->ini.videosink_element_evas) > 0)
5151 videosink_element = player->ini.videosink_element_evas;
5155 case MM_DISPLAY_SURFACE_X_EXT:
5157 void *pixmap_id_cb = NULL;
5158 mm_attrs_get_data_by_name(attrs, "display_overlay", &pixmap_id_cb);
5159 if (pixmap_id_cb) /* this is used for the videoTextue(canvasTexture) overlay */
5161 videosink_element = player->ini.videosink_element_x;
5165 debug_error("something wrong.. callback function for getting pixmap id is null");
5170 case MM_DISPLAY_SURFACE_NULL:
5171 if (strlen(player->ini.videosink_element_fake) > 0)
5172 videosink_element = player->ini.videosink_element_fake;
5176 case MM_DISPLAY_SURFACE_REMOTE:
5177 if (strlen(player->ini.videosink_element_remote) > 0)
5178 videosink_element = player->ini.videosink_element_remote;
5183 debug_error("unidentified surface type");
5187 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_element, videosink_element, TRUE, player);
5188 debug_log("selected videosink name: %s", videosink_element);
5190 /* additional setting for sink plug-in */
5191 switch (surface_type) {
5192 case MM_DISPLAY_SURFACE_X_EXT:
5193 MMPLAYER_SIGNAL_CONNECT( player,
5194 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
5195 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5196 "frame-render-error",
5197 G_CALLBACK(__mmplayer_videoframe_render_error_cb),
5199 debug_log("videoTexture usage, connect a signal handler for pixmap rendering error");
5201 case MM_DISPLAY_SURFACE_REMOTE:
5203 char *stream_path = NULL;
5204 /* viceo_zc is the result of check ST12/SN12 */
5205 bool use_tbm = player->set_mode.video_zc;
5206 int attr_ret = mm_attrs_get_string_by_name (
5207 attrs, "shm_stream_path", &stream_path );
5208 if(attr_ret == MM_ERROR_NONE && stream_path) {
5209 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5210 "socket-path", stream_path,
5211 "wait-for-connection", FALSE,
5216 debug_log("set path \"%s\" for shmsink", stream_path);
5218 debug_error("Not set attribute of shm_stream_path");
5228 if (_mmplayer_update_video_param(player) != MM_ERROR_NONE)
5231 if (videobin[MMPLAYER_V_SINK].gst)
5233 GstPad *sink_pad = NULL;
5234 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
5237 MMPLAYER_SIGNAL_CONNECT (player, sink_pad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5238 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
5239 gst_object_unref (GST_OBJECT(sink_pad));
5243 debug_warning("failed to get sink pad from videosink\n");
5247 /* store it as it's sink element */
5248 __mmplayer_add_sink( player, videobin[MMPLAYER_V_SINK].gst );
5250 /* adding created elements to bin */
5251 if( ! __mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket) )
5253 debug_error("failed to add elements\n");
5257 /* Linking elements in the bucket by added order */
5258 if ( __mmplayer_gst_element_link_bucket(element_bucket) == -1 )
5260 debug_error("failed to link elements\n");
5264 /* get first element's sinkpad for creating ghostpad */
5265 first_element = (MMPlayerGstElement *)element_bucket->data;
5266 if ( !first_element )
5268 debug_error("failed to get first element from bucket\n");
5272 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
5275 debug_error("failed to get pad from first element\n");
5279 /* create ghostpad */
5280 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
5281 if ( FALSE == gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin) )
5283 debug_error("failed to add ghostpad to videobin\n");
5286 gst_object_unref(pad);
5288 /* done. free allocated variables */
5289 g_list_free(element_bucket);
5291 mm_attrs_set_int_by_name(attrs, "content_video_found", TRUE);
5293 if(surface_type == MM_DISPLAY_SURFACE_REMOTE &&
5294 MMPLAYER_IS_HTTP_PD(player) )
5296 MMMessageParamType msg = {0, };
5297 msg.data = gst_caps_to_string(caps);
5298 MMPLAYER_POST_MSG ( player, MM_MESSAGE_VIDEO_BIN_CREATED, &msg );
5303 return MM_ERROR_NONE;
5306 debug_error("ERROR : releasing videobin\n");
5308 g_list_free( element_bucket );
5311 gst_object_unref(GST_OBJECT(pad));
5313 /* release videobin with it's childs */
5314 if ( videobin[MMPLAYER_V_BIN].gst )
5316 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
5320 MMPLAYER_FREEIF( videobin );
5322 player->pipeline->videobin = NULL;
5324 return MM_ERROR_PLAYER_INTERNAL;
5327 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
5329 GList *element_bucket = NULL;
5330 MMPlayerGstElement *textbin = player->pipeline->textbin;
5332 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
5333 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
5334 g_object_set (G_OBJECT (textbin[MMPLAYER_T_IDENTITY].gst),
5335 "signal-handoffs", FALSE,
5338 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
5339 MMPLAYER_SIGNAL_CONNECT( player,
5340 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
5341 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
5343 G_CALLBACK(__mmplayer_update_subtitle),
5346 g_object_set (G_OBJECT (textbin[MMPLAYER_T_FAKE_SINK].gst), "async", TRUE, NULL);
5347 g_object_set (G_OBJECT (textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE, NULL);
5348 g_object_set (G_OBJECT (textbin[MMPLAYER_T_FAKE_SINK].gst), "signal-handoffs", TRUE, NULL);
5350 if (!player->play_subtitle)
5352 debug_log ("add textbin sink as sink element of whole pipeline.\n");
5353 __mmplayer_add_sink (player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
5356 /* adding created elements to bin */
5357 debug_log("adding created elements to bin\n");
5358 if( !__mmplayer_gst_element_add_bucket_to_bin( GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket ))
5360 debug_error("failed to add elements\n");
5364 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
5365 GST_OBJECT_FLAG_UNSET (textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
5366 GST_OBJECT_FLAG_UNSET (textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
5368 /* linking elements in the bucket by added order. */
5369 debug_log("Linking elements in the bucket by added order.\n");
5370 if ( __mmplayer_gst_element_link_bucket(element_bucket) == -1 )
5372 debug_error("failed to link elements\n");
5376 /* done. free allocated variables */
5377 g_list_free(element_bucket);
5379 if (textbin[MMPLAYER_T_QUEUE].gst)
5382 GstPad *ghostpad = NULL;
5384 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
5387 debug_error("failed to get video pad of textbin\n");
5388 return MM_ERROR_PLAYER_INTERNAL;
5391 ghostpad = gst_ghost_pad_new("text_sink", pad);
5392 gst_object_unref(pad);
5396 debug_error("failed to create ghostpad of textbin\n");
5400 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad))
5402 debug_error("failed to add ghostpad to textbin\n");
5407 return MM_ERROR_NONE;
5410 g_list_free(element_bucket);
5412 return MM_ERROR_PLAYER_INTERNAL;
5415 static int __mmplayer_gst_create_text_pipeline(mm_player_t* player)
5417 MMPlayerGstElement *textbin = NULL;
5418 GList *element_bucket = NULL;
5423 return_val_if_fail( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
5426 textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
5429 debug_error("failed to allocate memory for textbin\n");
5430 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5434 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
5435 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
5436 if ( !textbin[MMPLAYER_T_BIN].gst )
5438 debug_error("failed to create textbin\n");
5443 player->pipeline->textbin = textbin;
5446 if (player->use_textoverlay)
5448 debug_log ("use textoverlay for displaying \n");
5450 MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_QUEUE, "queue", "text_t_queue", textbin[MMPLAYER_T_BIN].gst, player);
5452 MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_VIDEO_QUEUE, "queue", "text_v_queue", textbin[MMPLAYER_T_BIN].gst, player);
5454 MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_VIDEO_CONVERTER, "fimcconvert", "text_v_converter", textbin[MMPLAYER_T_BIN].gst, player);
5456 MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_OVERLAY, "textoverlay", "text_overlay", textbin[MMPLAYER_T_BIN].gst, player);
5458 if (!gst_element_link_pads (textbin[MMPLAYER_T_VIDEO_QUEUE].gst, "src", textbin[MMPLAYER_T_VIDEO_CONVERTER].gst, "sink"))
5460 debug_error("failed to link queue and converter\n");
5464 if (!gst_element_link_pads (textbin[MMPLAYER_T_VIDEO_CONVERTER].gst, "src", textbin[MMPLAYER_T_OVERLAY].gst, "video_sink"))
5466 debug_error("failed to link queue and textoverlay\n");
5470 if (!gst_element_link_pads (textbin[MMPLAYER_T_QUEUE].gst, "src", textbin[MMPLAYER_T_OVERLAY].gst, "text_sink"))
5472 debug_error("failed to link queue and textoverlay\n");
5478 int surface_type = 0;
5480 debug_log ("use subtitle message for displaying \n");
5482 mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &surface_type);
5484 switch(surface_type)
5486 case MM_DISPLAY_SURFACE_X:
5487 case MM_DISPLAY_SURFACE_EVAS:
5488 case MM_DISPLAY_SURFACE_GL:
5489 case MM_DISPLAY_SURFACE_NULL:
5490 case MM_DISPLAY_SURFACE_X_EXT:
5491 case MM_DISPLAY_SURFACE_REMOTE:
5492 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE)
5494 debug_error("failed to make plain text elements\n");
5506 return MM_ERROR_NONE;
5510 debug_log("ERROR : releasing textbin\n");
5512 g_list_free( element_bucket );
5514 /* release element which are not added to bin */
5515 for ( i = 1; i < MMPLAYER_T_NUM; i++ ) /* NOTE : skip bin */
5517 if ( textbin[i].gst )
5519 GstObject* parent = NULL;
5520 parent = gst_element_get_parent( textbin[i].gst );
5524 gst_object_unref(GST_OBJECT(textbin[i].gst));
5525 textbin[i].gst = NULL;
5529 gst_object_unref(GST_OBJECT(parent));
5534 /* release textbin with it's childs */
5535 if ( textbin[MMPLAYER_T_BIN].gst )
5537 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5540 MMPLAYER_FREEIF( textbin );
5542 player->pipeline->textbin = NULL;
5544 return MM_ERROR_PLAYER_INTERNAL;
5549 __mmplayer_gst_create_subtitle_src(mm_player_t* player)
5551 MMPlayerGstElement* mainbin = NULL;
5552 MMHandleType attrs = 0;
5553 GstElement *subsrc = NULL;
5554 GstElement *subparse = NULL;
5555 gchar *subtitle_uri =NULL;
5556 const gchar *charset = NULL;
5562 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5564 mainbin = player->pipeline->mainbin;
5566 attrs = MMPLAYER_GET_ATTRS(player);
5569 debug_error("cannot get content attribute\n");
5570 return MM_ERROR_PLAYER_INTERNAL;
5573 mm_attrs_get_string_by_name ( attrs, "subtitle_uri", &subtitle_uri );
5574 if ( !subtitle_uri || strlen(subtitle_uri) < 1)
5576 debug_error("subtitle uri is not proper filepath.\n");
5577 return MM_ERROR_PLAYER_INVALID_URI;
5579 debug_log("subtitle file path is [%s].\n", subtitle_uri);
5582 /* create the subtitle source */
5583 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
5586 debug_error ( "failed to create filesrc element\n" );
5589 g_object_set(G_OBJECT (subsrc), "location", subtitle_uri, NULL);
5591 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
5592 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
5594 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc))
5596 debug_warning("failed to add queue\n");
5601 subparse = gst_element_factory_make("subparse", "subtitle_parser");
5604 debug_error ( "failed to create subparse element\n" );
5608 charset = util_get_charset(subtitle_uri);
5611 debug_log ("detected charset is %s\n", charset );
5612 g_object_set (G_OBJECT (subparse), "subtitle-encoding", charset, NULL);
5615 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
5616 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
5618 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse))
5620 debug_warning("failed to add subparse\n");
5624 if (!gst_element_link_pads (subsrc, "src", subparse, "sink"))
5626 debug_warning("failed to link subsrc and subparse\n");
5630 player->play_subtitle = TRUE;
5631 player->adjust_subtitle_pos = 0;
5633 debug_log ("play subtitle using subtitle file\n");
5635 if (player->pipeline->textbin == NULL)
5637 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player))
5639 debug_error("failed to create textbin. continuing without text\n");
5643 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(player->pipeline->textbin[MMPLAYER_T_BIN].gst)))
5645 debug_warning("failed to add textbin\n");
5649 debug_log ("link text input selector and textbin ghost pad");
5651 player->textsink_linked = 1;
5652 player->external_text_idx = 0;
5653 debug_msg("player->textsink_linked set to 1\n");
5657 debug_log("text bin has been created. reuse it.");
5658 player->external_text_idx = 1;
5661 if (!gst_element_link_pads (subparse, "src", player->pipeline->textbin[MMPLAYER_T_BIN].gst, "text_sink"))
5663 debug_warning("failed to link subparse and textbin\n");
5667 pad = gst_element_get_static_pad (player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
5671 debug_error("failed to get sink pad from textsink to probe data");
5672 return MM_ERROR_PLAYER_INTERNAL;
5675 gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER,
5676 __mmplayer_subtitle_adjust_position_probe, player, NULL);
5678 gst_object_unref(pad);
5681 /* create dot. for debugging */
5682 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-with-subtitle" );
5685 return MM_ERROR_NONE;
5688 player->textsink_linked = 0;
5689 return MM_ERROR_PLAYER_INTERNAL;
5693 __mmplayer_update_subtitle( GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5695 mm_player_t* player = (mm_player_t*) data;
5696 MMMessageParamType msg = {0, };
5697 GstClockTime duration = 0;
5698 gpointer text = NULL;
5699 guint text_size = 0;
5700 gboolean ret = TRUE;
5701 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5705 return_val_if_fail ( player, FALSE );
5706 return_val_if_fail ( buffer, FALSE );
5708 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
5709 text = g_memdup(mapinfo.data, mapinfo.size);
5710 text_size = mapinfo.size;
5711 duration = GST_BUFFER_DURATION(buffer);
5714 if ( player->set_mode.subtitle_off )
5716 debug_log("subtitle is OFF.\n" );
5720 if ( !text || (text_size == 0))
5722 debug_log("There is no subtitle to be displayed.\n" );
5726 msg.data = (void *) text;
5727 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
5729 debug_log("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data );
5731 MMPLAYER_POST_MSG( player, MM_MESSAGE_UPDATE_SUBTITLE, &msg );
5732 gst_buffer_unmap(buffer, &mapinfo);
5739 static GstPadProbeReturn
5740 __mmplayer_subtitle_adjust_position_probe (GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
5743 mm_player_t *player = (mm_player_t *) u_data;
5744 GstClockTime cur_timestamp = 0;
5745 gint64 adjusted_timestamp = 0;
5746 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
5748 return_val_if_fail ( player, FALSE );
5750 if ( player->set_mode.subtitle_off )
5752 debug_log("subtitle is OFF.\n" );
5756 if (player->adjust_subtitle_pos == 0 )
5758 debug_log("nothing to do");
5762 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
5763 adjusted_timestamp = (gint64) cur_timestamp + ((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
5765 if ( adjusted_timestamp < 0)
5767 debug_log("adjusted_timestamp under zero");
5772 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
5773 debug_log("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
5774 GST_TIME_ARGS(cur_timestamp),
5775 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
5777 return GST_PAD_PROBE_OK;
5779 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
5783 /* check player and subtitlebin are created */
5784 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
5785 return_val_if_fail ( player->play_subtitle, MM_ERROR_NOT_SUPPORT_API );
5789 debug_log ("nothing to do\n");
5791 return MM_ERROR_NONE;
5796 case MM_PLAYER_POS_FORMAT_TIME:
5798 /* check current postion */
5799 player->adjust_subtitle_pos = position;
5801 debug_log("save adjust_subtitle_pos in player") ;
5807 debug_warning("invalid format.\n");
5809 return MM_ERROR_INVALID_ARGUMENT;
5815 return MM_ERROR_NONE;
5817 static int __gst_adjust_video_position(mm_player_t* player, int offset)
5820 debug_log("adjusting video_pos in player") ;
5821 int current_pos = 0;
5822 /* check player and videobin are created */
5823 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
5824 if ( !player->pipeline->videobin ||
5825 !player->pipeline->videobin[MMPLAYER_V_SINK].gst )
5827 debug_log("no video pipeline or sink is there");
5828 return MM_ERROR_PLAYER_INVALID_STATE ;
5832 debug_log ("nothing to do\n");
5834 return MM_ERROR_NONE;
5836 if(__gst_get_position ( player, MM_PLAYER_POS_FORMAT_TIME, (unsigned long*)¤t_pos ) != MM_ERROR_NONE )
5838 debug_log("failed to get current position");
5839 return MM_ERROR_PLAYER_INTERNAL;
5841 if ( (current_pos - offset ) < GST_TIME_AS_MSECONDS(player->duration) )
5843 debug_log("enter video delay is valid");
5846 debug_log("enter video delay is crossing content boundary");
5847 return MM_ERROR_INVALID_ARGUMENT ;
5849 g_object_set (G_OBJECT (player->pipeline->videobin[MMPLAYER_V_SINK].gst),"ts-offset",((gint64) offset * G_GINT64_CONSTANT(1000000)),NULL);
5850 debug_log("video delay has been done");
5853 return MM_ERROR_NONE;
5857 __gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data) // @
5859 GstElement *appsrc = element;
5860 tBuffer *buf = (tBuffer *)user_data;
5861 GstBuffer *buffer = NULL;
5862 GstFlowReturn ret = GST_FLOW_OK;
5865 return_if_fail ( element );
5866 return_if_fail ( buf );
5868 buffer = gst_buffer_new ();
5870 if (buf->offset >= buf->len)
5872 debug_log("call eos appsrc\n");
5873 g_signal_emit_by_name (appsrc, "end-of-stream", &ret);
5877 if ( buf->len - buf->offset < size)
5879 len = buf->len - buf->offset + buf->offset;
5882 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));
5883 GST_BUFFER_OFFSET(buffer) = buf->offset;
5884 GST_BUFFER_OFFSET_END(buffer) = buf->offset + len;
5886 //debug_log("feed buffer %p, offset %u-%u length %u\n", buffer, buf->offset, buf->len,len);
5887 g_signal_emit_by_name (appsrc, "push-buffer", buffer, &ret);
5893 __gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data) // @
5895 tBuffer *buf = (tBuffer *)user_data;
5897 return_val_if_fail ( buf, FALSE );
5899 buf->offset = (int)size;
5905 __gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data) // @
5907 mm_player_t *player = (mm_player_t*)user_data;
5908 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
5910 return_if_fail ( player );
5912 debug_msg("app-src: feed data\n");
5914 if (player->media_stream_buffer_status_cb[type])
5915 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, player->buffer_cb_user_param);
5919 __gst_appsrc_seek_data(GstElement *element, guint64 offset, gpointer user_data) // @
5921 mm_player_t *player = (mm_player_t*)user_data;
5922 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
5924 return_val_if_fail ( player, FALSE );
5926 debug_msg("app-src: seek data\n");
5928 if(player->media_stream_seek_data_cb[type])
5929 player->media_stream_seek_data_cb[type](type, offset, player->buffer_cb_user_param);
5936 __gst_appsrc_enough_data(GstElement *element, gpointer user_data) // @
5938 mm_player_t *player = (mm_player_t*)user_data;
5939 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
5941 return_val_if_fail ( player, FALSE );
5943 debug_msg("app-src: enough data:%p\n", player->media_stream_buffer_status_cb[type]);
5945 if (player->media_stream_buffer_status_cb[type])
5946 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, player->buffer_cb_user_param);
5952 _mmplayer_push_buffer(MMHandleType hplayer, unsigned char *buf, int size) // @
5954 mm_player_t* player = (mm_player_t*)hplayer;
5955 GstBuffer *buffer = NULL;
5956 GstFlowReturn gst_ret = GST_FLOW_OK;
5957 int ret = MM_ERROR_NONE;
5962 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
5964 /* check current state */
5965 // MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_START );
5968 /* NOTE : we should check and create pipeline again if not created as we destroy
5969 * whole pipeline when stopping in streamming playback
5971 if ( ! player->pipeline )
5973 if ( MM_ERROR_NONE != __gst_realize( player ) )
5975 debug_error("failed to realize before starting. only in streamming\n");
5976 return MM_ERROR_PLAYER_INTERNAL;
5980 debug_msg("app-src: pushing data\n");
5984 debug_error("buf is null\n");
5985 return MM_ERROR_NONE;
5988 buffer = gst_buffer_new ();
5992 debug_log("call eos appsrc\n");
5993 g_signal_emit_by_name (player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "end-of-stream", &gst_ret);
5994 return MM_ERROR_NONE;
5997 //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));
5999 debug_log("feed buffer %p, length %u\n", buf, size);
6000 g_signal_emit_by_name (player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "push-buffer", buffer, &gst_ret);
6007 static GstBusSyncReply
6008 __mmplayer_bus_sync_callback (GstBus * bus, GstMessage * message, gpointer data)
6010 mm_player_t *player = (mm_player_t *)data;
6011 GstBusSyncReply reply = GST_BUS_DROP;
6013 if ( ! ( player->pipeline && player->pipeline->mainbin ) )
6015 debug_error("player pipeline handle is null");
6016 return GST_BUS_PASS;
6019 if (!__mmplayer_check_useful_message(player, message))
6021 gst_message_unref (message);
6022 return GST_BUS_DROP;
6025 switch (GST_MESSAGE_TYPE (message))
6027 case GST_MESSAGE_STATE_CHANGED:
6028 /* post directly for fast launch */
6029 if (player->sync_handler) {
6030 __mmplayer_gst_callback(NULL, message, player);
6031 reply = GST_BUS_DROP;
6034 reply = GST_BUS_PASS;
6037 case GST_MESSAGE_TAG:
6038 __mmplayer_gst_extract_tag_from_msg(player, message);
6042 GstTagList *tags = NULL;
6044 gst_message_parse_tag (message, &tags);
6046 debug_error("TAGS received from element \"%s\".\n",
6047 GST_STR_NULL (GST_ELEMENT_NAME (GST_MESSAGE_SRC (message))));
6049 gst_tag_list_foreach (tags, print_tag, NULL);
6050 gst_tag_list_free (tags);
6058 case GST_MESSAGE_DURATION_CHANGED:
6059 __mmplayer_gst_handle_duration(player, message);
6061 case GST_MESSAGE_ASYNC_DONE:
6062 /* NOTE:Don't call gst_callback directly
6063 * because previous frame can be showed even though this message is received for seek.
6066 reply = GST_BUS_PASS;
6070 if (reply == GST_BUS_DROP)
6071 gst_message_unref (message);
6077 __mmplayer_gst_create_decoder ( mm_player_t *player,
6078 MMPlayerTrackType track,
6080 enum MainElementID elemId,
6083 gboolean ret = TRUE;
6084 GstPad *sinkpad = NULL;
6088 return_val_if_fail( player &&
6090 player->pipeline->mainbin, FALSE);
6091 return_val_if_fail((track == MM_PLAYER_TRACK_TYPE_AUDIO || track == MM_PLAYER_TRACK_TYPE_VIDEO), FALSE);
6092 return_val_if_fail(srcpad, FALSE);
6093 return_val_if_fail((player->pipeline->mainbin[elemId].gst == NULL), FALSE);
6095 GstElement *decodebin = NULL;
6096 GstCaps *dec_caps = NULL;
6098 /* create decodebin */
6099 decodebin = gst_element_factory_make("decodebin", name);
6103 debug_error("error : fail to create decodebin for %d decoder\n", track);
6108 /* raw pad handling signal */
6109 MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6110 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
6112 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6113 before looking for any elements that can handle that stream.*/
6114 MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6115 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
6117 /* This signal is emitted when a element is added to the bin.*/
6118 MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6119 G_CALLBACK(__mmplayer_gst_element_added), player);
6121 if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), decodebin))
6123 debug_error("failed to add new decodebin\n");
6128 dec_caps = gst_pad_query_caps (srcpad, NULL);
6131 //debug_log ("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
6132 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
6133 gst_caps_unref(dec_caps);
6136 player->pipeline->mainbin[elemId].id = elemId;
6137 player->pipeline->mainbin[elemId].gst = decodebin;
6139 sinkpad = gst_element_get_static_pad (decodebin, "sink");
6141 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad))
6143 debug_warning ("failed to link [%s:%s] to decoder\n", GST_DEBUG_PAD_NAME(srcpad));
6144 gst_object_unref (GST_OBJECT(decodebin));
6147 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent (decodebin))
6149 debug_error("failed to sync second level decodebin state with parent\n");
6152 debug_log("Total num of %d tracks = %d \n", track, player->selector[track].total_track_num);
6157 gst_object_unref ( GST_OBJECT(sinkpad) );
6166 * This function is to create audio or video pipeline for playing.
6168 * @param player [in] handle of player
6170 * @return This function returns zero on success.
6175 __mmplayer_gst_create_pipeline(mm_player_t* player) // @
6178 MMPlayerGstElement *mainbin = NULL;
6179 MMHandleType attrs = 0;
6180 GstElement* element = NULL;
6181 GstElement* elem_src_audio = NULL;
6182 GstElement* elem_src_subtitle = NULL;
6183 GstElement* es_video_queue = NULL;
6184 GstElement* es_audio_queue = NULL;
6185 GstElement* es_subtitle_queue = NULL;
6186 GList* element_bucket = NULL;
6187 gboolean need_state_holder = TRUE;
6189 #ifdef SW_CODEC_ONLY
6190 int surface_type = 0;
6194 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6196 /* get profile attribute */
6197 attrs = MMPLAYER_GET_ATTRS(player);
6200 debug_error("cannot get content attribute\n");
6204 /* create pipeline handles */
6205 if ( player->pipeline )
6207 debug_warning("pipeline should be released before create new one\n");
6211 player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0( sizeof(MMPlayerGstPipelineInfo) );
6212 if (player->pipeline == NULL)
6215 memset( player->pipeline, 0, sizeof(MMPlayerGstPipelineInfo) );
6218 /* create mainbin */
6219 mainbin = (MMPlayerGstElement*) g_malloc0( sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM );
6220 if (mainbin == NULL)
6223 memset( mainbin, 0, sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
6225 /* create pipeline */
6226 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
6227 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
6228 if ( ! mainbin[MMPLAYER_M_PIPE].gst )
6230 debug_error("failed to create pipeline\n");
6233 player->demux_pad_index = 0;
6234 player->subtitle_language_list = NULL;
6236 player->is_subtitle_force_drop = FALSE;
6237 player->last_multiwin_status = FALSE;
6239 _mmplayer_track_initialize(player);
6241 /* create source element */
6242 switch ( player->profile.uri_type )
6244 /* rtsp streamming */
6245 case MM_PLAYER_URI_TYPE_URL_RTSP:
6247 gint network_bandwidth;
6248 gchar *user_agent, *wap_profile;
6250 element = gst_element_factory_make("rtspsrc", "rtsp source");
6254 debug_error("failed to create streaming source element\n");
6259 network_bandwidth = 0;
6260 user_agent = wap_profile = NULL;
6263 mm_attrs_get_string_by_name ( attrs, "streaming_user_agent", &user_agent );
6264 mm_attrs_get_string_by_name ( attrs,"streaming_wap_profile", &wap_profile );
6265 mm_attrs_get_int_by_name ( attrs, "streaming_network_bandwidth", &network_bandwidth );
6267 secure_debug_log("user_agent : %s\n", user_agent);
6268 secure_debug_log("wap_profile : %s\n", wap_profile);
6270 /* setting property to streaming source */
6271 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6273 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6275 g_object_set(G_OBJECT(element), "wap_profile", wap_profile, NULL);
6277 MMPLAYER_SIGNAL_CONNECT ( player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6278 G_CALLBACK (__mmplayer_gst_rtp_dynamic_pad), player );
6279 MMPLAYER_SIGNAL_CONNECT ( player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6280 G_CALLBACK (__mmplayer_gst_rtp_no_more_pads), player );
6282 player->use_decodebin = FALSE;
6287 case MM_PLAYER_URI_TYPE_URL_HTTP:
6289 gchar *user_agent, *proxy, *cookies, **cookie_list;
6290 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6291 user_agent = proxy = cookies = NULL;
6293 gint mode = MM_PLAYER_PD_MODE_NONE;
6295 mm_attrs_get_int_by_name ( attrs, "pd_mode", &mode );
6297 player->pd_mode = mode;
6299 debug_log("http playback, PD mode : %d\n", player->pd_mode);
6301 if ( ! MMPLAYER_IS_HTTP_PD(player) )
6303 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
6306 debug_error("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
6309 debug_log("using http streamming source [%s].\n", player->ini.httpsrc_element);
6312 mm_attrs_get_string_by_name ( attrs, "streaming_cookie", &cookies );
6313 mm_attrs_get_string_by_name ( attrs, "streaming_user_agent", &user_agent );
6314 mm_attrs_get_string_by_name ( attrs, "streaming_proxy", &proxy );
6315 mm_attrs_get_int_by_name ( attrs, "streaming_timeout", &http_timeout );
6317 if ((http_timeout == DEFAULT_HTTP_TIMEOUT) &&
6318 (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT))
6320 debug_log("get timeout from ini\n");
6321 http_timeout = player->ini.http_timeout;
6325 secure_debug_log("location : %s\n", player->profile.uri);
6326 secure_debug_log("cookies : %s\n", cookies);
6327 secure_debug_log("proxy : %s\n", proxy);
6328 secure_debug_log("user_agent : %s\n", user_agent);
6329 debug_log("timeout : %d\n", http_timeout);
6331 /* setting property to streaming source */
6332 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6333 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6334 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
6336 /* check if prosy is vailid or not */
6337 if ( util_check_valid_url ( proxy ) )
6338 g_object_set(G_OBJECT(element), "proxy", proxy, NULL);
6339 /* parsing cookies */
6340 if ( ( cookie_list = util_get_cookie_list ((const char*)cookies) ) )
6341 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
6343 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6345 if ( MMPLAYER_URL_HAS_DASH_SUFFIX(player) )
6347 debug_warning("it's dash. and it's still experimental feature.");
6350 else // progressive download
6352 gchar* location = NULL;
6354 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
6358 mm_attrs_get_string_by_name ( attrs, "pd_location", &path );
6360 MMPLAYER_FREEIF(player->pd_file_save_path);
6362 debug_log("PD Location : %s\n", path);
6366 player->pd_file_save_path = g_strdup(path);
6370 debug_error("can't find pd location so, it should be set \n");
6371 return MM_ERROR_PLAYER_FILE_NOT_FOUND;
6375 element = gst_element_factory_make("pdpushsrc", "PD pushsrc");
6378 debug_error("failed to create PD push source element[%s].\n", "pdpushsrc");
6382 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
6383 g_object_set(G_OBJECT(element), "location", player->pd_file_save_path, NULL);
6385 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6387 g_object_get(element, "location", &location, NULL);
6388 debug_log("PD_LOCATION [%s].\n", location);
6396 case MM_PLAYER_URI_TYPE_FILE:
6399 debug_log("using filesrc for 'file://' handler.\n");
6401 element = gst_element_factory_make("filesrc", "source");
6405 debug_error("failed to create filesrc\n");
6409 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
6410 //g_object_set(G_OBJECT(element), "use-mmap", TRUE, NULL);
6414 case MM_PLAYER_URI_TYPE_SS:
6416 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6417 element = gst_element_factory_make("souphttpsrc", "http streaming source");
6420 debug_error("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
6424 mm_attrs_get_int_by_name ( attrs, "streaming_timeout", &http_timeout );
6426 if ((http_timeout == DEFAULT_HTTP_TIMEOUT) &&
6427 (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT))
6429 debug_log("get timeout from ini\n");
6430 http_timeout = player->ini.http_timeout;
6433 /* setting property to streaming source */
6434 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6435 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6440 case MM_PLAYER_URI_TYPE_BUFF:
6442 guint64 stream_type = GST_APP_STREAM_TYPE_STREAM;
6444 debug_log("mem src is selected\n");
6446 element = gst_element_factory_make("appsrc", "buff-source");
6449 debug_error("failed to create appsrc element\n");
6453 g_object_set( element, "stream-type", stream_type, NULL );
6454 //g_object_set( element, "size", player->mem_buf.len, NULL );
6455 //g_object_set( element, "blocksize", (guint64)20480, NULL );
6457 MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6458 G_CALLBACK(__gst_appsrc_seek_data), player);
6459 MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6460 G_CALLBACK(__gst_appsrc_feed_data), player);
6461 MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6462 G_CALLBACK(__gst_appsrc_enough_data), player);
6465 case MM_PLAYER_URI_TYPE_ES_BUFF:
6467 debug_log("es buff src is selected\n");
6469 if (player->v_stream_caps)
6471 element = gst_element_factory_make("appsrc", "video_appsrc");
6474 debug_critical("failed to create video app source element[appsrc].\n" );
6478 if ( player->a_stream_caps )
6480 elem_src_audio = gst_element_factory_make("appsrc", "audio_appsrc");
6481 if ( !elem_src_audio )
6483 debug_critical("failed to create audio app source element[appsrc].\n" );
6488 else if ( player->a_stream_caps )
6490 /* no video, only audio pipeline*/
6491 element = gst_element_factory_make("appsrc", "audio_appsrc");
6494 debug_critical("failed to create audio app source element[appsrc].\n" );
6499 if ( player->s_stream_caps )
6501 elem_src_subtitle = gst_element_factory_make("appsrc", "subtitle_appsrc");
6502 if ( !elem_src_subtitle )
6504 debug_critical("failed to create subtitle app source element[appsrc].\n" );
6509 debug_log("setting app sources properties.\n");
6510 debug_log("location : %s\n", player->profile.uri);
6512 if ( player->v_stream_caps && element )
6514 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6515 "blocksize", (guint)1048576, /* size of many video frames are larger than default blocksize as 4096 */
6516 "caps", player->v_stream_caps, NULL);
6518 if ( player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6519 g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6520 if ( player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6521 g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6523 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6524 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6525 MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6526 G_CALLBACK(__gst_seek_video_data), player);
6528 if (player->a_stream_caps && elem_src_audio)
6530 g_object_set(G_OBJECT(elem_src_audio), "format", GST_FORMAT_TIME,
6531 "caps", player->a_stream_caps, NULL);
6533 if ( player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6534 g_object_set(G_OBJECT(elem_src_audio), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6535 if ( player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6536 g_object_set(G_OBJECT(elem_src_audio), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6538 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6539 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_audio), GST_APP_STREAM_TYPE_SEEKABLE);
6540 MMPLAYER_SIGNAL_CONNECT( player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6541 G_CALLBACK(__gst_seek_audio_data), player);
6544 else if (player->a_stream_caps && element)
6546 g_object_set(G_OBJECT(element), "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(element), "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(element), "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(element), GST_APP_STREAM_TYPE_SEEKABLE);
6556 MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6557 G_CALLBACK(__gst_seek_audio_data), player);
6560 if (player->s_stream_caps && elem_src_subtitle)
6562 g_object_set(G_OBJECT(elem_src_subtitle), "format", GST_FORMAT_TIME,
6563 "caps", player->s_stream_caps, NULL);
6565 if ( player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6566 g_object_set(G_OBJECT(elem_src_subtitle), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6567 if ( player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6568 g_object_set(G_OBJECT(elem_src_subtitle), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6570 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_subtitle), GST_APP_STREAM_TYPE_SEEKABLE);
6572 MMPLAYER_SIGNAL_CONNECT( player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6573 G_CALLBACK(__gst_seek_subtitle_data), player);
6576 if (player->v_stream_caps && element)
6578 MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6579 G_CALLBACK(__gst_appsrc_feed_video_data), player);
6580 MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6581 G_CALLBACK(__gst_appsrc_enough_video_data), player);
6583 if (player->a_stream_caps && elem_src_audio)
6585 MMPLAYER_SIGNAL_CONNECT( player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6586 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6587 MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6588 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6591 else if (player->a_stream_caps && element)
6593 MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6594 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6595 MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6596 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6599 if (player->s_stream_caps && elem_src_subtitle)
6601 MMPLAYER_SIGNAL_CONNECT( player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6602 G_CALLBACK(__gst_appsrc_feed_subtitle_data), player);
6605 need_state_holder = FALSE;
6609 case MM_PLAYER_URI_TYPE_MEM:
6611 guint64 stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
6613 debug_log("mem src is selected\n");
6615 element = gst_element_factory_make("appsrc", "mem-source");
6618 debug_error("failed to create appsrc element\n");
6622 g_object_set( element, "stream-type", stream_type, NULL );
6623 g_object_set( element, "size", player->mem_buf.len, NULL );
6624 g_object_set( element, "blocksize", (guint64)20480, NULL );
6626 MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6627 G_CALLBACK(__gst_appsrc_seek_data_mem), &player->mem_buf );
6628 MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6629 G_CALLBACK(__gst_appsrc_feed_data_mem), &player->mem_buf );
6632 case MM_PLAYER_URI_TYPE_URL:
6635 case MM_PLAYER_URI_TYPE_TEMP:
6638 case MM_PLAYER_URI_TYPE_NONE:
6643 /* check source element is OK */
6646 debug_error("no source element was created.\n");
6650 /* take source element */
6651 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6652 mainbin[MMPLAYER_M_SRC].gst = element;
6653 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
6655 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL))
6657 player->streamer = __mm_player_streaming_create();
6658 __mm_player_streaming_initialize(player->streamer);
6661 if ( MMPLAYER_IS_HTTP_PD(player) )
6663 gdouble pre_buffering_time = (gdouble)player->streamer->buffering_req.initial_second;
6665 debug_log ("Picked queue2 element(pre buffer : %d sec)....\n", pre_buffering_time);
6666 element = gst_element_factory_make("queue2", "queue2");
6669 debug_error ( "failed to create http streaming buffer element\n" );
6674 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6675 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element;
6676 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]);
6678 pre_buffering_time = (pre_buffering_time > 0)?(pre_buffering_time):(player->ini.http_buffering_time);
6680 __mm_player_streaming_set_queue2(player->streamer,
6683 player->ini.http_max_size_bytes,
6686 player->ini.http_buffering_limit,
6691 if (MMPLAYER_IS_ES_BUFF_SRC(player))
6693 if (player->v_stream_caps)
6695 es_video_queue = gst_element_factory_make("queue2", "video_queue");
6696 if (!es_video_queue)
6698 debug_error ("create es_video_queue for es player failed\n");
6701 mainbin[MMPLAYER_M_V_BUFFER].id = MMPLAYER_M_V_BUFFER;
6702 mainbin[MMPLAYER_M_V_BUFFER].gst = es_video_queue;
6703 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_V_BUFFER]);
6705 /* Adding audio appsrc to bucket */
6706 if (player->a_stream_caps && elem_src_audio)
6708 mainbin[MMPLAYER_M_2ND_SRC].id = MMPLAYER_M_2ND_SRC;
6709 mainbin[MMPLAYER_M_2ND_SRC].gst = elem_src_audio;
6710 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_2ND_SRC]);
6712 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6713 if (!es_audio_queue)
6715 debug_error ("create es_audio_queue for es player failed\n");
6718 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6719 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6720 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6723 /* Only audio stream, no video */
6724 else if (player->a_stream_caps)
6726 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6727 if (!es_audio_queue)
6729 debug_error ("create es_audio_queue for es player failed\n");
6732 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6733 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6734 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6737 if (player->s_stream_caps && elem_src_subtitle)
6739 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
6740 mainbin[MMPLAYER_M_SUBSRC].gst = elem_src_subtitle;
6741 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SUBSRC]);
6743 es_subtitle_queue = gst_element_factory_make("queue2", "subtitle_queue");
6744 if (!es_subtitle_queue)
6746 debug_error ("create es_subtitle_queue for es player failed\n");
6749 mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_V_BUFFER;
6750 mainbin[MMPLAYER_M_S_BUFFER].gst = es_subtitle_queue;
6751 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_S_BUFFER]);
6755 /* create autoplugging element if src element is not a rtsp src */
6756 if ((player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_RTSP) &&
6757 (player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_WFD) &&
6758 (player->profile.uri_type != MM_PLAYER_URI_TYPE_ES_BUFF))
6761 enum MainElementID elemId = MMPLAYER_M_NUM;
6763 if ((player->use_decodebin) &&
6764 ((MMPLAYER_IS_HTTP_PD(player)) ||
6765 (!MMPLAYER_IS_HTTP_STREAMING(player))))
6767 elemId = MMPLAYER_M_AUTOPLUG;
6768 element = __mmplayer_create_decodebin(player);
6769 need_state_holder = FALSE;
6773 elemId = MMPLAYER_M_TYPEFIND;
6774 element = gst_element_factory_make("typefind", "typefinder");
6775 MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
6776 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player );
6780 /* check autoplug element is OK */
6783 debug_error("can not create element (%d)\n", elemId);
6787 mainbin[elemId].id = elemId;
6788 mainbin[elemId].gst = element;
6790 element_bucket = g_list_append(element_bucket, &mainbin[elemId]);
6793 /* add elements to pipeline */
6794 if( !__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket))
6796 debug_error("Failed to add elements to pipeline\n");
6801 /* linking elements in the bucket by added order. */
6802 if ( __mmplayer_gst_element_link_bucket(element_bucket) == -1 )
6804 debug_error("Failed to link some elements\n");
6809 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
6810 if ( need_state_holder )
6813 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
6814 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make ("fakesink", "state-holder");
6816 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
6818 debug_error ("fakesink element could not be created\n");
6821 GST_OBJECT_FLAG_UNSET (mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
6823 /* take ownership of fakesink. we are reusing it */
6824 gst_object_ref( mainbin[MMPLAYER_M_SRC_FAKESINK].gst );
6827 if ( FALSE == gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst),
6828 mainbin[MMPLAYER_M_SRC_FAKESINK].gst) )
6830 debug_error("failed to add fakesink to bin\n");
6835 /* now we have completed mainbin. take it */
6836 player->pipeline->mainbin = mainbin;
6838 if (MMPLAYER_IS_ES_BUFF_SRC(player))
6840 GstPad *srcpad = NULL;
6842 if (mainbin[MMPLAYER_M_V_BUFFER].gst)
6844 srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_V_BUFFER].gst, "src");
6847 __mmplayer_gst_create_decoder ( player,
6848 MM_PLAYER_TRACK_TYPE_VIDEO,
6850 MMPLAYER_M_AUTOPLUG_V_DEC,
6853 gst_object_unref ( GST_OBJECT(srcpad) );
6858 if ((player->a_stream_caps) && (mainbin[MMPLAYER_M_A_BUFFER].gst))
6860 srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_A_BUFFER].gst, "src");
6863 __mmplayer_gst_create_decoder ( player,
6864 MM_PLAYER_TRACK_TYPE_AUDIO,
6866 MMPLAYER_M_AUTOPLUG_A_DEC,
6869 gst_object_unref ( GST_OBJECT(srcpad) );
6874 if (mainbin[MMPLAYER_M_S_BUFFER].gst)
6876 __mmplayer_try_to_plug_decodebin(player, gst_element_get_static_pad(mainbin[MMPLAYER_M_S_BUFFER].gst, "src"), player->s_stream_caps);
6880 /* connect bus callback */
6881 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6884 debug_error ("cannot get bus from pipeline.\n");
6888 player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_callback, player);
6890 player->context.thread_default = g_main_context_get_thread_default();
6892 if (NULL == player->context.thread_default)
6894 player->context.thread_default = g_main_context_default();
6895 debug_log("thread-default context is the global default context");
6897 debug_warning("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
6899 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
6900 if ( __mmplayer_check_subtitle ( player ) )
6902 if ( MM_ERROR_NONE != __mmplayer_gst_create_subtitle_src(player) )
6903 debug_error("fail to create subtitle src\n");
6906 /* set sync handler to get tag synchronously */
6907 gst_bus_set_sync_handler(bus, __mmplayer_bus_sync_callback, player, NULL);
6910 gst_object_unref(GST_OBJECT(bus));
6911 g_list_free(element_bucket);
6915 return MM_ERROR_NONE;
6919 __mmplayer_gst_destroy_pipeline(player);
6920 g_list_free(element_bucket);
6922 /* release element which are not added to bin */
6923 for ( i = 1; i < MMPLAYER_M_NUM; i++ ) /* NOTE : skip pipeline */
6925 if ( mainbin[i].gst )
6927 GstObject* parent = NULL;
6928 parent = gst_element_get_parent( mainbin[i].gst );
6932 gst_object_unref(GST_OBJECT(mainbin[i].gst));
6933 mainbin[i].gst = NULL;
6937 gst_object_unref(GST_OBJECT(parent));
6942 /* release pipeline with it's childs */
6943 if ( mainbin[MMPLAYER_M_PIPE].gst )
6945 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
6948 MMPLAYER_FREEIF( player->pipeline );
6949 MMPLAYER_FREEIF( mainbin );
6951 return MM_ERROR_PLAYER_INTERNAL;
6955 __mmplayer_reset_gapless_state(mm_player_t* player)
6958 return_if_fail(player
6960 && player->pipeline->audiobin
6961 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
6963 if (player->gapless.audio_data_probe_id != 0)
6966 sinkpad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_BIN].gst, "sink");
6967 gst_pad_remove_probe (sinkpad, player->gapless.audio_data_probe_id);
6968 gst_object_unref (sinkpad);
6970 memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
6977 __mmplayer_gst_destroy_pipeline(mm_player_t* player) // @
6980 int ret = MM_ERROR_NONE;
6984 return_val_if_fail ( player, MM_ERROR_INVALID_HANDLE );
6986 /* cleanup stuffs */
6987 MMPLAYER_FREEIF(player->type);
6988 player->have_dynamic_pad = FALSE;
6989 player->no_more_pad = FALSE;
6990 player->num_dynamic_pad = 0;
6991 player->demux_pad_index = 0;
6992 player->subtitle_language_list = NULL;
6993 player->use_deinterleave = FALSE;
6994 player->max_audio_channels = 0;
6995 player->video_share_api_delta = 0;
6996 player->video_share_clock_delta = 0;
6997 player->video_hub_download_mode = 0;
6998 __mmplayer_reset_gapless_state(player);
6999 __mmplayer_post_proc_reset(player);
7001 if (player->streamer)
7003 __mm_player_streaming_deinitialize (player->streamer);
7004 __mm_player_streaming_destroy(player->streamer);
7005 player->streamer = NULL;
7008 /* cleanup unlinked mime type */
7009 MMPLAYER_FREEIF(player->unlinked_audio_mime);
7010 MMPLAYER_FREEIF(player->unlinked_video_mime);
7011 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
7013 /* cleanup running stuffs */
7014 __mmplayer_cancel_eos_timer( player );
7015 #if 0 //need to change and test
7016 /* remove sound cb */
7017 if ( MM_ERROR_NONE != mm_sound_remove_device_information_changed_callback())
7019 debug_error("failed to mm_sound_remove_device_information_changed_callback()");
7022 /* cleanup gst stuffs */
7023 if ( player->pipeline )
7025 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
7026 GstTagList* tag_list = player->pipeline->tag_list;
7028 /* first we need to disconnect all signal hander */
7029 __mmplayer_release_signal_connection( player, MM_PLAYER_SIGNAL_TYPE_ALL );
7031 /* disconnecting bus watch */
7032 if ( player->bus_watcher )
7033 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
7034 player->bus_watcher = 0;
7038 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
7039 MMPlayerGstElement* videobin = player->pipeline->videobin;
7040 MMPlayerGstElement* textbin = player->pipeline->textbin;
7041 GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE (mainbin[MMPLAYER_M_PIPE].gst));
7042 gst_bus_set_sync_handler (bus, NULL, NULL, NULL);
7043 gst_object_unref(bus);
7045 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7046 ret = __mmplayer_gst_set_state ( player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout );
7047 if ( ret != MM_ERROR_NONE )
7049 debug_error("fail to change state to NULL\n");
7050 return MM_ERROR_PLAYER_INTERNAL;
7053 debug_warning("succeeded in chaning state to NULL\n");
7055 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
7058 if ( mainbin[MMPLAYER_M_SRC_FAKESINK].gst )
7059 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
7061 /* free avsysaudiosink
7062 avsysaudiosink should be unref when destory pipeline just after start play with BT.
7063 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
7065 MMPLAYER_FREEIF( audiobin );
7066 MMPLAYER_FREEIF( videobin );
7067 MMPLAYER_FREEIF( textbin );
7068 MMPLAYER_FREEIF( mainbin );
7072 gst_tag_list_free(tag_list);
7074 MMPLAYER_FREEIF( player->pipeline );
7076 MMPLAYER_FREEIF(player->album_art);
7078 if (player->v_stream_caps)
7080 gst_caps_unref(player->v_stream_caps);
7081 player->v_stream_caps = NULL;
7083 if (player->a_stream_caps)
7085 gst_caps_unref(player->a_stream_caps);
7086 player->a_stream_caps = NULL;
7088 if (player->s_stream_caps)
7090 gst_caps_unref(player->s_stream_caps);
7091 player->s_stream_caps = NULL;
7093 _mmplayer_track_destroy(player);
7095 if ( player->sink_elements )
7096 g_list_free ( player->sink_elements );
7097 player->sink_elements = NULL;
7099 debug_warning("finished destroy pipeline\n");
7106 static int __gst_realize(mm_player_t* player) // @
7109 int ret = MM_ERROR_NONE;
7113 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7115 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7117 ret = __mmplayer_gst_create_pipeline(player);
7120 debug_error("failed to create pipeline\n");
7124 /* set pipeline state to READY */
7125 /* NOTE : state change to READY must be performed sync. */
7126 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7127 ret = __mmplayer_gst_set_state(player,
7128 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
7130 if ( ret != MM_ERROR_NONE )
7132 /* return error if failed to set state */
7133 debug_error("failed to set READY state");
7138 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_READY );
7141 /* create dot before error-return. for debugging */
7142 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-realize" );
7149 static int __gst_unrealize(mm_player_t* player) // @
7151 int ret = MM_ERROR_NONE;
7155 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7157 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
7158 MMPLAYER_PRINT_STATE(player);
7160 /* release miscellaneous information */
7161 __mmplayer_release_misc( player );
7163 /* destroy pipeline */
7164 ret = __mmplayer_gst_destroy_pipeline( player );
7165 if ( ret != MM_ERROR_NONE )
7167 debug_error("failed to destory pipeline\n");
7171 /* release miscellaneous information.
7172 these info needs to be released after pipeline is destroyed. */
7173 __mmplayer_release_misc_post( player );
7175 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_NULL );
7182 static int __gst_pending_seek ( mm_player_t* player )
7184 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7185 int ret = MM_ERROR_NONE;
7189 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
7191 if ( !player->pending_seek.is_pending )
7193 debug_log("pending seek is not reserved. nothing to do.\n" );
7197 /* check player state if player could pending seek or not. */
7198 current_state = MMPLAYER_CURRENT_STATE(player);
7200 if ( current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING )
7202 debug_warning("try to pending seek in %s state, try next time. \n",
7203 MMPLAYER_STATE_GET_NAME(current_state));
7207 debug_log("trying to play from (%lu) pending position\n", player->pending_seek.pos);
7209 ret = __gst_set_position ( player, player->pending_seek.format, player->pending_seek.pos, FALSE );
7211 if ( MM_ERROR_NONE != ret )
7212 debug_error("failed to seek pending postion. just keep staying current position.\n");
7214 player->pending_seek.is_pending = FALSE;
7221 static int __gst_start(mm_player_t* player) // @
7223 gboolean sound_extraction = 0;
7224 int ret = MM_ERROR_NONE;
7225 gboolean async = FALSE;
7229 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
7231 /* get sound_extraction property */
7232 mm_attrs_get_int_by_name(player->attrs, "pcm_extraction", &sound_extraction);
7234 /* NOTE : if SetPosition was called before Start. do it now */
7235 /* streaming doesn't support it. so it should be always sync */
7236 /* !! create one more api to check if there is pending seek rather than checking variables */
7237 if ( (player->pending_seek.is_pending || sound_extraction) && !MMPLAYER_IS_STREAMING(player))
7239 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
7240 ret = __gst_pause(player, FALSE);
7241 if ( ret != MM_ERROR_NONE )
7243 debug_error("failed to set state to PAUSED for pending seek\n");
7247 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
7249 if ( sound_extraction )
7251 debug_log("setting pcm extraction\n");
7253 ret = __mmplayer_set_pcm_extraction(player);
7254 if ( MM_ERROR_NONE != ret )
7256 debug_warning("failed to set pcm extraction\n");
7262 if ( MM_ERROR_NONE != __gst_pending_seek(player) )
7264 debug_warning("failed to seek pending postion. starting from the begin of content.\n");
7269 debug_log("current state before doing transition");
7270 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7271 MMPLAYER_PRINT_STATE(player);
7273 /* set pipeline state to PLAYING */
7274 if (player->es_player_push_mode)
7278 /* set pipeline state to PLAYING */
7279 ret = __mmplayer_gst_set_state(player,
7280 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player) );
7282 if (ret == MM_ERROR_NONE)
7284 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7288 debug_error("failed to set state to PLAYING");
7292 /* generating debug info before returning error */
7293 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-start" );
7300 static void __mmplayer_do_sound_fadedown(mm_player_t* player, unsigned int time)
7304 return_if_fail(player
7306 && player->pipeline->audiobin
7307 && player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
7309 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", 2, NULL);
7316 static void __mmplayer_undo_sound_fadedown(mm_player_t* player)
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", 0, NULL);
7330 static int __gst_stop(mm_player_t* player) // @
7332 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
7333 MMHandleType attrs = 0;
7334 gboolean fadedown = FALSE;
7335 gboolean rewind = FALSE;
7337 int ret = MM_ERROR_NONE;
7339 gboolean async = FALSE;
7343 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7344 return_val_if_fail ( player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7346 debug_log("current state before doing transition");
7347 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7348 MMPLAYER_PRINT_STATE(player);
7350 attrs = MMPLAYER_GET_ATTRS(player);
7353 debug_error("cannot get content attribute\n");
7354 return MM_ERROR_PLAYER_INTERNAL;
7357 mm_attrs_get_int_by_name(attrs, "sound_fadedown", &fadedown);
7359 /* enable fadedown */
7360 if (fadedown || player->sound_focus.by_asm_cb)
7361 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
7363 /* Just set state to PAUESED and the rewind. it's usual player behavior. */
7364 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT ( player );
7366 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_BUFF ||
7367 player->profile.uri_type == MM_PLAYER_URI_TYPE_HLS)
7369 state = GST_STATE_READY;
7373 state = GST_STATE_PAUSED;
7375 if ( ! MMPLAYER_IS_STREAMING(player) ||
7376 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked)) {
7381 if (player->es_player_push_mode)
7386 ret = __mmplayer_gst_set_state( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, state, async, timeout );
7388 /* disable fadeout */
7389 if (fadedown || player->sound_focus.by_asm_cb)
7390 __mmplayer_undo_sound_fadedown(player);
7392 /* return if set_state has failed */
7393 if ( ret != MM_ERROR_NONE )
7395 debug_error("failed to set state.\n");
7402 if ( ! __gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7403 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
7404 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE) )
7406 debug_warning("failed to rewind\n");
7407 ret = MM_ERROR_PLAYER_SEEK;
7412 player->sent_bos = FALSE;
7414 if (player->es_player_push_mode) //for cloudgame
7419 /* wait for seek to complete */
7420 change_ret = gst_element_get_state (player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
7421 if ( change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL )
7423 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_READY );
7427 debug_error("fail to stop player.\n");
7428 ret = MM_ERROR_PLAYER_INTERNAL;
7429 __mmplayer_dump_pipeline_state(player);
7432 /* generate dot file if enabled */
7433 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-stop" );
7440 int __gst_pause(mm_player_t* player, gboolean async) // @
7442 int ret = MM_ERROR_NONE;
7446 return_val_if_fail(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7447 return_val_if_fail(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7449 debug_log("current state before doing transition");
7450 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
7451 MMPLAYER_PRINT_STATE(player);
7453 /* set pipeline status to PAUSED */
7454 player->ignore_asyncdone = TRUE;
7456 ret = __mmplayer_gst_set_state(player,
7457 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7459 player->ignore_asyncdone = FALSE;
7461 if ( FALSE == async )
7463 if ( ret != MM_ERROR_NONE )
7465 GstMessage *msg = NULL;
7466 GTimer *timer = NULL;
7467 gdouble MAX_TIMEOUT_SEC = 3;
7469 debug_error("failed to set state to PAUSED");
7471 timer = g_timer_new();
7472 g_timer_start(timer);
7474 GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7475 gboolean got_msg = FALSE;
7476 /* check if gst error posted or not */
7479 msg = gst_bus_timed_pop(bus, GST_SECOND /2);
7482 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR)
7484 GError *error = NULL;
7486 /* parse error code */
7487 gst_message_parse_error(msg, &error, NULL);
7489 if ( gst_structure_has_name ( gst_message_get_structure(msg), "streaming_error" ) )
7491 /* Note : the streaming error from the streaming source is handled
7492 * using __mmplayer_handle_streaming_error.
7494 __mmplayer_handle_streaming_error ( player, msg );
7499 debug_error("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
7501 if (error->domain == GST_STREAM_ERROR)
7503 ret = __gst_handle_stream_error( player, error, msg );
7505 else if (error->domain == GST_RESOURCE_ERROR)
7507 ret = __gst_handle_resource_error( player, error->code );
7509 else if (error->domain == GST_LIBRARY_ERROR)
7511 ret = __gst_handle_library_error( player, error->code );
7513 else if (error->domain == GST_CORE_ERROR)
7515 ret = __gst_handle_core_error( player, error->code );
7520 player->msg_posted = TRUE;
7522 gst_message_unref(msg);
7524 } while (!got_msg && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
7526 gst_object_unref(bus);
7527 g_timer_stop (timer);
7528 g_timer_destroy (timer);
7532 else if ( (!player->pipeline->videobin) && (!player->pipeline->audiobin) )
7534 if (MMPLAYER_IS_RTSP_STREAMING(player))
7536 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
7538 else if ( ret== MM_ERROR_NONE)
7540 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_PAUSED );
7544 /* generate dot file before returning error */
7545 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-pause" );
7552 int __gst_resume(mm_player_t* player, gboolean async) // @
7554 int ret = MM_ERROR_NONE;
7559 return_val_if_fail(player && player->pipeline,
7560 MM_ERROR_PLAYER_NOT_INITIALIZED);
7562 debug_log("current state before doing transition");
7563 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7564 MMPLAYER_PRINT_STATE(player);
7566 /* generate dot file before returning error */
7567 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-resume" );
7570 debug_log("do async state transition to PLAYING.\n");
7572 /* set pipeline state to PLAYING */
7573 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7575 ret = __mmplayer_gst_set_state(player,
7576 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout );
7577 if (ret != MM_ERROR_NONE)
7579 debug_error("failed to set state to PLAYING\n");
7586 // MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_PLAYING );
7587 debug_log("update state machine to %d\n", MM_PLAYER_STATE_PLAYING);
7588 ret = __mmplayer_set_state(player, MM_PLAYER_STATE_PLAYING);
7592 /* generate dot file before returning error */
7593 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-resume" );
7601 __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called) // @
7603 unsigned long dur_msec = 0;
7604 gint64 dur_nsec = 0;
7605 gint64 pos_nsec = 0;
7606 gboolean ret = TRUE;
7607 gboolean accurated = FALSE;
7608 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
7611 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
7612 return_val_if_fail ( !MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP );
7614 if ( MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
7615 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED )
7618 if( !MMPLAYER_IS_ES_BUFF_SRC(player) )
7620 /* check duration */
7621 /* NOTE : duration cannot be zero except live streaming.
7622 * Since some element could have some timing problemn with quering duration, try again.
7624 if ( !player->duration )
7626 if ( !gst_element_query_duration( player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec ))
7630 player->duration = dur_nsec;
7633 if ( player->duration )
7635 dur_msec = GST_TIME_AS_MSECONDS(player->duration);
7639 debug_error("could not get the duration. fail to seek.\n");
7643 debug_log("playback rate: %f\n", player->playback_rate);
7645 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
7648 seek_flags |= GST_SEEK_FLAG_ACCURATE;
7652 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
7658 case MM_PLAYER_POS_FORMAT_TIME:
7660 if( !MMPLAYER_IS_ES_BUFF_SRC(player) )
7662 /* check position is valid or not */
7663 if ( position > dur_msec )
7666 debug_log("seeking to (%lu) msec, duration is %d msec\n", position, dur_msec);
7668 if ( player->doing_seek )
7670 debug_log("not completed seek");
7671 return MM_ERROR_PLAYER_DOING_SEEK;
7675 if ( !internal_called )
7676 player->doing_seek = TRUE;
7678 pos_nsec = position * G_GINT64_CONSTANT(1000000);
7680 if ((MMPLAYER_IS_HTTP_STREAMING(player)) && (!player->videodec_linked))
7682 gint64 cur_time = 0;
7684 /* get current position */
7685 gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_time);
7688 GstEvent *event = gst_event_new_seek (1.0,
7690 (GstSeekFlags)GST_SEEK_FLAG_FLUSH,
7691 GST_SEEK_TYPE_SET, cur_time,
7692 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7694 __gst_send_event_to_sink(player, event);
7697 __gst_pause( player, FALSE );
7700 ret = __gst_seek ( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7701 GST_FORMAT_TIME, seek_flags,
7702 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE );
7705 debug_error("failed to set position. dur[%lu] pos[%lu] pos_msec[%llu]\n", dur_msec, position, pos_nsec);
7711 case MM_PLAYER_POS_FORMAT_PERCENT:
7713 debug_log("seeking to (%lu)%% \n", position);
7715 if (player->doing_seek)
7717 debug_log("not completed seek");
7718 return MM_ERROR_PLAYER_DOING_SEEK;
7721 if ( !internal_called)
7722 player->doing_seek = TRUE;
7724 /* FIXIT : why don't we use 'GST_FORMAT_PERCENT' */
7725 pos_nsec = (gint64) ( ( position * player->duration ) / 100 );
7726 ret = __gst_seek ( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7727 GST_FORMAT_TIME, seek_flags,
7728 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE );
7731 debug_error("failed to set position. dur[%lud] pos[%lud] pos_msec[%"G_GUINT64_FORMAT"]\n", dur_msec, position, pos_nsec);
7742 /* NOTE : store last seeking point to overcome some bad operation
7743 * ( returning zero when getting current position ) of some elements
7745 player->last_position = pos_nsec;
7747 /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
7748 if ( player->playback_rate > 1.0 )
7749 _mmplayer_set_playspeed ( (MMHandleType)player, player->playback_rate );
7752 return MM_ERROR_NONE;
7755 player->pending_seek.is_pending = TRUE;
7756 player->pending_seek.format = format;
7757 player->pending_seek.pos = position;
7759 debug_warning("player current-state : %s, pending-state : %s, just preserve pending position(%lu).\n",
7760 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)), MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)), player->pending_seek.pos);
7762 return MM_ERROR_NONE;
7765 debug_error("invalid arguments, position : %ld dur : %ld format : %d \n", position, dur_msec, format);
7766 return MM_ERROR_INVALID_ARGUMENT;
7769 player->doing_seek = FALSE;
7770 return MM_ERROR_PLAYER_SEEK;
7773 #define TRICKPLAY_OFFSET GST_MSECOND
7776 __gst_get_position(mm_player_t* player, int format, unsigned long* position) // @
7778 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7779 gint64 pos_msec = 0;
7780 gboolean ret = TRUE;
7782 return_val_if_fail( player && position && player->pipeline && player->pipeline->mainbin,
7783 MM_ERROR_PLAYER_NOT_INITIALIZED );
7785 current_state = MMPLAYER_CURRENT_STATE(player);
7787 /* NOTE : query position except paused state to overcome some bad operation
7788 * please refer to below comments in details
7790 if ( current_state != MM_PLAYER_STATE_PAUSED )
7792 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
7795 /* NOTE : get last point to overcome some bad operation of some elements
7796 * ( returning zero when getting current position in paused state
7797 * and when failed to get postion during seeking
7799 if ( ( current_state == MM_PLAYER_STATE_PAUSED )
7801 //|| ( player->last_position != 0 && pos_msec == 0 ) )
7803 debug_log ("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS (pos_msec), ret, current_state);
7805 if(player->playback_rate < 0.0)
7806 pos_msec = player->last_position - TRICKPLAY_OFFSET;
7808 pos_msec = player->last_position;
7811 pos_msec = player->last_position;
7813 player->last_position = pos_msec;
7815 debug_log("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_msec));
7820 if (player->duration > 0 && pos_msec > player->duration) {
7821 pos_msec = player->duration;
7824 if (player->sound_focus.keep_last_pos) {
7825 debug_log("return last pos as stop by asm, %"GST_TIME_FORMAT, GST_TIME_ARGS(player->last_position));
7826 pos_msec = player->last_position;
7829 player->last_position = pos_msec;
7834 case MM_PLAYER_POS_FORMAT_TIME:
7835 *position = GST_TIME_AS_MSECONDS(pos_msec);
7838 case MM_PLAYER_POS_FORMAT_PERCENT:
7843 dur = player->duration / GST_SECOND;
7846 debug_log ("duration is [%d], so returning position 0\n",dur);
7851 pos = pos_msec / GST_SECOND;
7852 *position = pos * 100 / dur;
7857 return MM_ERROR_PLAYER_INTERNAL;
7860 return MM_ERROR_NONE;
7864 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
7866 #define STREAMING_IS_FINISHED 0
7867 #define BUFFERING_MAX_PER 100
7869 GstQuery *query = NULL;
7871 return_val_if_fail( player &&
7873 player->pipeline->mainbin,
7874 MM_ERROR_PLAYER_NOT_INITIALIZED );
7876 return_val_if_fail( start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT );
7878 if (!MMPLAYER_IS_HTTP_STREAMING ( player ))
7880 /* and rtsp is not ready yet. */
7881 debug_warning ( "it's only used for http streaming case.\n" );
7882 return MM_ERROR_NONE;
7890 case MM_PLAYER_POS_FORMAT_PERCENT :
7892 gint start_per = -1, stop_per = -1;
7893 gint64 buffered_total = 0;
7895 unsigned long position = 0;
7896 guint curr_size_bytes = 0;
7897 gint64 buffering_left = -1;
7898 gint buffered_sec = -1;
7900 gint64 content_duration = player->duration;
7901 guint64 content_size = player->http_content_size;
7903 if (content_duration > 0)
7905 if (!__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position))
7907 debug_log ("[Time] pos %d ms / dur %d sec / %lld bytes", position, (guint)(content_duration/GST_SECOND), content_size);
7908 start_per = 100 * (position*GST_MSECOND) / content_duration;
7910 /* buffered size info from multiqueue */
7911 if (player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst)
7913 g_object_get(G_OBJECT(player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst), "curr-size-bytes", &curr_size_bytes, NULL);
7914 debug_log ("[MQ] curr_size_bytes = %d", curr_size_bytes);
7916 buffered_total += curr_size_bytes;
7919 /* buffered size info from queue2 */
7920 if (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)
7922 query = gst_query_new_buffering ( GST_FORMAT_BYTES );
7923 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query))
7925 GstBufferingMode mode;
7926 gint byte_in_rate = 0, byte_out_rate = 0;
7927 gint64 start_byte = 0, stop_byte = 0;
7928 guint num_of_ranges = 0;
7931 num_of_ranges = gst_query_get_n_buffering_ranges(query);
7932 for ( idx=0 ; idx<num_of_ranges ; idx++ )
7934 gst_query_parse_nth_buffering_range (query, idx, &start_byte, &stop_byte);
7935 debug_log ("[Q2][range %d] %lld ~ %lld\n", idx, start_byte, stop_byte);
7937 buffered_total += (stop_byte - start_byte);
7940 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, &buffering_left);
7941 debug_log ("[Q2] in_rate %d, out_rate %d, left %lld\n", byte_in_rate, byte_out_rate, buffering_left);
7943 gst_query_unref (query);
7946 if (buffering_left == STREAMING_IS_FINISHED)
7948 stop_per = BUFFERING_MAX_PER;
7952 guint dur_sec = (guint)(content_duration/GST_SECOND);
7953 guint avg_byterate = (dur_sec>0)?((guint)(content_size/dur_sec)):(0);
7955 if (avg_byterate > 0)
7956 buffered_sec = (gint)(buffered_total/avg_byterate);
7957 else if (player->total_maximum_bitrate > 0)
7958 buffered_sec = (gint)(GET_BIT_FROM_BYTE(buffered_total)/(gint64)player->total_maximum_bitrate);
7959 else if (player->total_bitrate > 0)
7960 buffered_sec = (gint)(GET_BIT_FROM_BYTE(buffered_total)/(gint64)player->total_bitrate);
7962 if ((buffered_sec >= 0) && (dur_sec > 0))
7963 stop_per = start_per + (100 * buffered_sec / dur_sec);
7966 debug_log ("[Buffered Total] %lld bytes, %d sec, per %d~%d\n", buffered_total, buffered_sec, start_per, stop_per);
7970 if (((buffered_total == 0) || (start_per < 0) || (stop_per < 0)) &&
7971 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst))
7973 query = gst_query_new_buffering ( GST_FORMAT_PERCENT );
7974 if ( gst_element_query ( player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query ) )
7977 gint64 range_start_per = -1, range_stop_per = -1;
7979 gst_query_parse_buffering_range ( query, &format, &range_start_per, &range_stop_per, NULL );
7981 debug_log ("[Q2] range start %" G_GINT64_FORMAT " ~ stop %" G_GINT64_FORMAT "\n", range_start_per , range_stop_per);
7983 if (range_start_per != -1)
7984 start_per = (gint)(100 * range_start_per / GST_FORMAT_PERCENT_MAX);
7986 if (range_stop_per != -1)
7987 stop_per = (gint)(100 * range_stop_per / GST_FORMAT_PERCENT_MAX);
7989 gst_query_unref (query);
7993 *start_pos = (start_per < 100)?(start_per):(100);
7998 *stop_pos = (stop_per < 100)?(stop_per):(100);
8004 case MM_PLAYER_POS_FORMAT_TIME :
8005 debug_warning ( "Time format is not supported yet.\n" );
8012 debug_log("current buffer position : %lu~%lu \n", *start_pos, *stop_pos );
8014 return MM_ERROR_NONE;
8018 __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param) // @
8024 debug_warning("set_message_callback is called with invalid player handle\n");
8025 return MM_ERROR_PLAYER_NOT_INITIALIZED;
8028 player->msg_cb = callback;
8029 player->msg_cb_param = user_param;
8031 debug_log("msg_cb : %p msg_cb_param : %p\n", callback, user_param);
8035 return MM_ERROR_NONE;
8038 static int __mmfplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data) // @
8040 int ret = MM_ERROR_PLAYER_INVALID_URI;
8045 return_val_if_fail ( uri , FALSE);
8046 return_val_if_fail ( data , FALSE);
8047 return_val_if_fail ( ( strlen(uri) <= MM_MAX_URL_LEN ), FALSE );
8049 memset(data, 0, sizeof(MMPlayerParseProfile));
8051 if ((path = strstr(uri, "file://")))
8053 int file_stat = MM_ERROR_NONE;
8055 file_stat = util_exist_file_path(path + 7);
8057 if (file_stat == MM_ERROR_NONE)
8059 strncpy(data->uri, path, MM_MAX_URL_LEN-1);
8061 if ( util_is_sdp_file ( path ) )
8063 debug_log("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
8064 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8068 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8070 ret = MM_ERROR_NONE;
8072 else if (file_stat == MM_ERROR_PLAYER_PERMISSION_DENIED)
8074 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8078 debug_warning("could access %s.\n", path);
8081 else if ((path = strstr(uri, "es_buff://")))
8085 strcpy(data->uri, uri);
8086 data->uri_type = MM_PLAYER_URI_TYPE_ES_BUFF;
8087 ret = MM_ERROR_NONE;
8090 else if ((path = strstr(uri, "buff://")))
8092 data->uri_type = MM_PLAYER_URI_TYPE_BUFF;
8093 ret = MM_ERROR_NONE;
8095 else if ((path = strstr(uri, "rtsp://")))
8098 if((path = strstr(uri, "/wfd1.0/"))) {
8099 strcpy(data->uri, uri);
8100 data->uri_type = MM_PLAYER_URI_TYPE_URL_WFD;
8101 ret = MM_ERROR_NONE;
8102 debug_log("uri is actually a wfd client path. giving it to wfdrtspsrc\n");
8105 strcpy(data->uri, uri);
8106 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8107 ret = MM_ERROR_NONE;
8111 else if ((path = strstr(uri, "http://")))
8114 strcpy(data->uri, uri);
8116 if (g_str_has_suffix (g_ascii_strdown(uri, strlen(uri)), ".ism/manifest") ||
8117 g_str_has_suffix (g_ascii_strdown(uri, strlen(uri)), ".isml/manifest"))
8119 data->uri_type = MM_PLAYER_URI_TYPE_SS;
8122 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
8124 ret = MM_ERROR_NONE;
8127 else if ((path = strstr(uri, "https://")))
8130 strcpy(data->uri, uri);
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;
8138 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
8140 ret = MM_ERROR_NONE;
8143 else if ((path = strstr(uri, "rtspu://")))
8146 strcpy(data->uri, uri);
8147 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8148 ret = MM_ERROR_NONE;
8151 else if ((path = strstr(uri, "rtspr://")))
8153 strcpy(data->uri, path);
8154 char *separater =strstr(path, "*");
8158 char *urgent = separater + strlen("*");
8160 if ((urgent_len = strlen(urgent))) {
8161 data->uri[strlen(path) - urgent_len - strlen("*")] = '\0';
8162 strcpy(data->urgent, urgent);
8163 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8164 ret = MM_ERROR_NONE;
8168 else if ((path = strstr(uri, "mms://")))
8171 strcpy(data->uri, uri);
8172 data->uri_type = MM_PLAYER_URI_TYPE_URL_MMS;
8173 ret = MM_ERROR_NONE;
8176 else if ((path = strstr(uri, "mem://")))
8180 char *buffer = NULL;
8181 char *seperator = strchr(path, ',');
8182 char ext[100] = {0,}, size[100] = {0,};
8185 if ((buffer = strstr(path, "ext="))) {
8186 buffer += strlen("ext=");
8188 if (strlen(buffer)) {
8189 strcpy(ext, buffer);
8191 if ((seperator = strchr(ext, ','))
8192 || (seperator = strchr(ext, ' '))
8193 || (seperator = strchr(ext, '\0'))) {
8194 seperator[0] = '\0';
8199 if ((buffer = strstr(path, "size="))) {
8200 buffer += strlen("size=");
8202 if (strlen(buffer) > 0) {
8203 strcpy(size, buffer);
8205 if ((seperator = strchr(size, ','))
8206 || (seperator = strchr(size, ' '))
8207 || (seperator = strchr(size, '\0'))) {
8208 seperator[0] = '\0';
8211 mem_size = atoi(size);
8216 debug_log("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
8217 if ( mem_size && param)
8220 data->mem_size = mem_size;
8221 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
8222 ret = MM_ERROR_NONE;
8228 int file_stat = MM_ERROR_NONE;
8230 file_stat = util_exist_file_path(uri);
8232 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8233 if (file_stat == MM_ERROR_NONE)
8235 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", uri);
8237 if ( util_is_sdp_file( (char*)uri ) )
8239 debug_log("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
8240 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8244 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8246 ret = MM_ERROR_NONE;
8248 else if (file_stat == MM_ERROR_PLAYER_PERMISSION_DENIED)
8250 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8254 debug_error ("invalid uri, could not play..\n");
8255 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8259 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE) {
8260 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
8261 } else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION){
8262 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
8265 /* dump parse result */
8266 secure_debug_warning("incomming uri : %s\n", uri);
8267 debug_log("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n",
8268 data->uri_type, data->mem, data->mem_size, data->urgent);
8275 gboolean _asm_postmsg(gpointer *data)
8277 mm_player_t* player = (mm_player_t*)data;
8278 MMMessageParamType msg = {0, };
8281 return_val_if_fail ( player, FALSE );
8282 debug_warning("get notified");
8284 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
8285 (player->cmd == MMPLAYER_COMMAND_UNREALIZE))
8287 debug_warning("dispatched");
8292 msg.union_type = MM_MSG_UNION_CODE;
8293 msg.code = player->sound_focus.focus_changed_msg;
8295 #if 0 // should remove
8296 if (player->sm.event_src == ASM_EVENT_SOURCE_RESUMABLE_CANCELED)
8298 /* fill the message with state of player */
8299 msg.state.current = MMPLAYER_CURRENT_STATE(player);
8300 MMPLAYER_POST_MSG( player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
8301 player->resumable_cancel_id = 0;
8306 MMPLAYER_POST_MSG( player, MM_MESSAGE_READY_TO_RESUME, &msg);
8307 player->resume_event_id = 0;
8310 debug_warning("dispatched");
8314 gboolean _asm_lazy_pause(gpointer *data)
8316 mm_player_t* player = (mm_player_t*)data;
8317 int ret = MM_ERROR_NONE;
8321 return_val_if_fail ( player, FALSE );
8323 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING)
8325 debug_log ("Ready to proceed lazy pause\n");
8326 ret = _mmplayer_pause((MMHandleType)player);
8327 if(MM_ERROR_NONE != ret)
8329 debug_error("MMPlayer pause failed in ASM callback lazy pause\n");
8334 debug_log ("Invalid state to proceed lazy pause\n");
8338 if (player->pipeline && player->pipeline->audiobin)
8339 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", 0, NULL);
8341 player->sound_focus.by_asm_cb = FALSE; //should be reset here
8349 __mmplayer_can_do_interrupt(mm_player_t *player)
8351 if (!player || !player->pipeline || !player->attrs)
8353 debug_warning("not initialized");
8357 if ((player->sound_focus.exit_cb) || (player->set_mode.pcm_extraction))
8359 debug_warning("leave from asm cb right now, %d, %d", player->sound_focus.exit_cb, player->set_mode.pcm_extraction);
8363 /* check if seeking */
8364 if (player->doing_seek)
8366 MMMessageParamType msg_param;
8367 memset (&msg_param, 0, sizeof(MMMessageParamType));
8368 msg_param.code = MM_ERROR_PLAYER_SEEK;
8369 player->doing_seek = FALSE;
8370 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8374 /* check other thread */
8375 if (!g_mutex_trylock(&player->cmd_lock))
8377 debug_warning("locked already, cmd state : %d", player->cmd);
8379 /* check application command */
8380 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)
8382 debug_warning("playing.. should wait cmd lock then, will be interrupted");
8383 g_mutex_lock(&player->cmd_lock);
8386 debug_warning("nothing to do");
8391 debug_warning("can interrupt immediately");
8402 /* if you want to enable USE_ASM, please check the history get the ASM cb code. */
8404 __mmplayer_convert_sound_focus_state(gboolean acquire, const char *reason_for_change, MMPlayerFocusChangedMsg *msg)
8406 int ret = MM_ERROR_NONE;
8407 MMPlayerFocusChangedMsg focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_UNKNOWN;
8409 if (strstr(reason_for_change, "alarm")) {
8410 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_ALARM;
8412 } else if (strstr(reason_for_change, "notification")) {
8413 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_NOTIFICATION;
8415 } else if (strstr(reason_for_change, "emergency")) {
8416 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_EMERGENCY;
8418 } else if (strstr(reason_for_change, "call-voice") ||
8419 strstr(reason_for_change, "call-video") ||
8420 strstr(reason_for_change, "voip") ||
8421 strstr(reason_for_change, "ringtone-voip") ||
8422 strstr(reason_for_change, "ringtone-call")) {
8423 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_CALL;
8425 } else if (strstr(reason_for_change, "media") ||
8426 strstr(reason_for_change, "radio") ||
8427 strstr(reason_for_change, "loopback") ||
8428 strstr(reason_for_change, "system") ||
8429 strstr(reason_for_change, "voice-information") ||
8430 strstr(reason_for_change, "voice-recognition")) {
8431 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_MEDIA;
8434 ret = MM_ERROR_INVALID_ARGUMENT;
8435 debug_warning("not supported reason(%s), err(0x%08x)", reason_for_change, ret);
8439 if (acquire && (focus_msg != MM_PLAYER_FOCUS_CHANGED_BY_MEDIA))
8442 focus_msg = MM_PLAYER_FOCUS_CHANGED_COMPLETED;
8445 debug_log("converted from reason(%s) to msg(%d)", reason_for_change, focus_msg);
8452 /* FIXME: will be updated with new funct */
8453 void __mmplayer_sound_focus_watch_callback(int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e focus_state,
8454 const char *reason_for_change, const char *additional_info, void *user_data)
8456 mm_player_t* player = (mm_player_t*) user_data;
8457 int result = MM_ERROR_NONE;
8458 MMPlayerFocusChangedMsg msg = MM_PLAYER_FOCUS_CHANGED_BY_UNKNOWN;
8460 debug_warning("focus watch notified");
8462 if (!__mmplayer_can_do_interrupt(player))
8464 debug_warning("no need to interrupt, so leave");
8468 if (player->sound_focus.session_flags & MM_SESSION_OPTION_UNINTERRUPTIBLE)
8470 debug_warning("flags is UNINTERRUPTIBLE. do nothing.");
8474 debug_warning("watch: state: %d, focus_type : %d, reason_for_change : %s",
8475 focus_state, focus_type, (reason_for_change?reason_for_change:"N/A"));
8477 player->sound_focus.cb_pending = TRUE;
8478 player->sound_focus.by_asm_cb = TRUE;
8480 if (focus_state == FOCUS_IS_ACQUIRED)
8482 debug_warning("watch: FOCUS_IS_ACQUIRED");
8483 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(FALSE, reason_for_change, &msg))
8485 player->sound_focus.focus_changed_msg = (int)msg;
8488 if (strstr(reason_for_change, "call") ||
8489 strstr(reason_for_change, "voip") || /* FIXME: to check */
8490 strstr(reason_for_change, "alarm") ||
8491 strstr(reason_for_change, "media"))
8493 if (!MMPLAYER_IS_RTSP_STREAMING(player))
8495 // hold 0.7 second to excute "fadedown mute" effect
8496 debug_warning ("do fade down->pause->undo fade down");
8498 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
8500 result = _mmplayer_pause((MMHandleType)player);
8501 if (result != MM_ERROR_NONE)
8503 debug_warning("fail to set Pause state by asm");
8506 __mmplayer_undo_sound_fadedown(player);
8510 /* rtsp should connect again in specific network becasue tcp session can't be kept any more */
8511 _mmplayer_unrealize((MMHandleType)player);
8516 debug_warning ("pause immediately");
8517 result = _mmplayer_pause((MMHandleType)player);
8518 if (result != MM_ERROR_NONE)
8520 debug_warning("fail to set Pause state by asm");
8525 else if (focus_state == FOCUS_IS_RELEASED)
8527 debug_warning("FOCUS_IS_RELEASED: Got msg from asm to resume");
8528 player->sound_focus.antishock = TRUE;
8529 player->sound_focus.by_asm_cb = FALSE;
8531 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(TRUE, reason_for_change, &msg))
8533 player->sound_focus.focus_changed_msg = (int)msg;
8536 //ASM server is single thread daemon. So use g_idle_add() to post resume msg
8537 player->resume_event_id = g_idle_add((GSourceFunc)_asm_postmsg, (gpointer)player);
8542 debug_warning("unknown focus state %d", focus_state);
8546 player->sound_focus.by_asm_cb = FALSE;
8547 player->sound_focus.cb_pending = FALSE;
8548 MMPLAYER_CMD_UNLOCK( player );
8551 debug_warning("dispatched");
8556 __mmplayer_sound_focus_callback(int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e focus_state,
8557 const char *reason_for_change, const char *additional_info, void *user_data)
8559 mm_player_t* player = (mm_player_t*) user_data;
8560 int result = MM_ERROR_NONE;
8561 gboolean lazy_pause = FALSE;
8562 MMPlayerFocusChangedMsg msg = MM_PLAYER_FOCUS_CHANGED_BY_UNKNOWN;
8564 debug_warning("get focus notified");
8566 if (!__mmplayer_can_do_interrupt(player))
8568 debug_warning("no need to interrupt, so leave");
8572 if (player->sound_focus.session_flags & MM_SESSION_OPTION_UNINTERRUPTIBLE)
8574 debug_warning("flags is UNINTERRUPTIBLE. do nothing.");
8578 debug_warning("state: %d, focus_type : %d, reason_for_change : %s",
8579 focus_state, focus_type, (reason_for_change?reason_for_change:"N/A"));
8581 player->sound_focus.cb_pending = TRUE;
8582 player->sound_focus.by_asm_cb = TRUE;
8583 // player->sound_focus.event_src = event_src;
8586 /* first, check event source */
8587 if(event_src == ASM_EVENT_SOURCE_EARJACK_UNPLUG)
8589 int stop_by_asm = 0;
8590 mm_attrs_get_int_by_name(player->attrs, "sound_stop_when_unplugged", &stop_by_asm);
8594 else if (event_src == ASM_EVENT_SOURCE_RESOURCE_CONFLICT)
8596 /* can use video overlay simultaneously */
8597 /* video resource conflict */
8598 if(player->pipeline->videobin)
8600 debug_log("video conflict but, can support multiple video");
8601 result = _mmplayer_pause((MMHandleType)player);
8602 cb_res = ASM_CB_RES_PAUSE;
8604 else if (player->pipeline->audiobin)
8606 debug_log("audio resource conflict");
8607 result = _mmplayer_pause((MMHandleType)player);
8608 if (result != MM_ERROR_NONE)
8610 debug_warning("fail to set pause by asm");
8612 cb_res = ASM_CB_RES_PAUSE;
8616 #if 0 // should remove
8617 else if (event_src == ASM_EVENT_SOURCE_RESUMABLE_CANCELED)
8619 debug_warning("Got msg from asm for resumable canceled.\n");
8620 player->sound_focus.antishock = TRUE;
8621 player->sound_focus.by_asm_cb = FALSE;
8623 player->resumable_cancel_id = g_idle_add((GSourceFunc)_asm_postmsg, (gpointer)player);
8624 cb_res = ASM_CB_RES_IGNORE;
8630 if (focus_state == FOCUS_IS_RELEASED)
8632 debug_warning("FOCUS_IS_RELEASED");
8634 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(FALSE, reason_for_change, &msg))
8636 player->sound_focus.focus_changed_msg = (int)msg;
8639 if (strstr(reason_for_change, "call") ||
8640 strstr(reason_for_change, "voip") || /* FIXME: to check */
8641 strstr(reason_for_change, "alarm") ||
8642 strstr(reason_for_change, "media"))
8644 if (!MMPLAYER_IS_RTSP_STREAMING(player))
8646 //hold 0.7 second to excute "fadedown mute" effect
8647 debug_warning ("do fade down->pause->undo fade down");
8649 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
8651 result = _mmplayer_pause((MMHandleType)player);
8652 if (result != MM_ERROR_NONE)
8654 debug_warning("fail to set Pause state by asm");
8657 __mmplayer_undo_sound_fadedown(player);
8661 /* rtsp should connect again in specific network becasue tcp session can't be kept any more */
8662 _mmplayer_unrealize((MMHandleType)player);
8667 debug_warning ("pause immediately");
8668 result = _mmplayer_pause((MMHandleType)player);
8669 if (result != MM_ERROR_NONE)
8671 debug_warning("fail to set Pause state by asm");
8676 else if (focus_state == FOCUS_IS_ACQUIRED)
8678 debug_warning("FOCUS_IS_ACQUIRED: Got msg from asm to resume");
8679 player->sound_focus.antishock = TRUE;
8680 player->sound_focus.by_asm_cb = FALSE;
8682 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(TRUE, reason_for_change, &msg))
8684 player->sound_focus.focus_changed_msg = (int)msg;
8687 //ASM server is single thread daemon. So use g_idle_add() to post resume msg
8688 player->resume_event_id = g_idle_add((GSourceFunc)_asm_postmsg, (gpointer)player);
8693 debug_warning("unknown focus state %d", focus_state);
8699 player->sound_focus.by_asm_cb = FALSE;
8701 player->sound_focus.cb_pending = FALSE;
8702 MMPLAYER_CMD_UNLOCK( player );
8705 debug_warning("dispatched");
8711 _mmplayer_create_player(MMHandleType handle) // @
8713 mm_player_t* player = MM_PLAYER_CAST(handle);
8717 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
8719 /* initialize player state */
8720 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
8721 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
8722 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
8723 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
8725 /* check current state */
8726 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL ( player, MMPLAYER_COMMAND_CREATE );
8728 /* construct attributes */
8729 player->attrs = _mmplayer_construct_attribute(handle);
8731 if ( !player->attrs )
8733 debug_error("Failed to construct attributes\n");
8737 /* initialize gstreamer with configured parameter */
8738 if ( ! __mmplayer_init_gstreamer(player) )
8740 debug_error("Initializing gstreamer failed\n");
8744 /* initialize factories if not using decodebin */
8745 if( player->factories == NULL )
8746 __mmplayer_init_factories(player);
8748 /* create lock. note that g_tread_init() has already called in gst_init() */
8749 g_mutex_init(&player->fsink_lock);
8751 /* create repeat mutex */
8752 g_mutex_init(&player->repeat_thread_mutex);
8754 /* create repeat cond */
8755 g_cond_init(&player->repeat_thread_cond);
8757 /* create repeat thread */
8758 player->repeat_thread =
8759 g_thread_try_new ("repeat_thread", __mmplayer_repeat_thread, (gpointer)player, NULL);
8762 /* create next play mutex */
8763 g_mutex_init(&player->next_play_thread_mutex);
8765 /* create next play cond */
8766 g_cond_init(&player->next_play_thread_cond);
8768 /* create next play thread */
8769 player->next_play_thread =
8770 g_thread_try_new ("next_play_thread", __mmplayer_next_play_thread, (gpointer)player, NULL);
8771 if ( ! player->next_play_thread )
8773 debug_error("failed to create next play thread");
8777 if ( MM_ERROR_NONE != _mmplayer_initialize_video_capture(player))
8779 debug_error("failed to initialize video capture\n");
8783 /* register to asm */
8784 if ( MM_ERROR_NONE != _mmplayer_sound_register(&player->sound_focus,
8785 (mm_sound_focus_changed_cb)__mmplayer_sound_focus_callback,
8786 (mm_sound_focus_changed_watch_cb)__mmplayer_sound_focus_watch_callback,
8790 /* NOTE : we are dealing it as an error since we cannot expect it's behavior */
8791 debug_error("failed to register asm server\n");
8792 return MM_ERROR_POLICY_INTERNAL;
8794 #if 0 //need to change and test
8795 /* to add active device callback */
8796 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))
8798 debug_error("failed mm_sound_add_device_information_changed_callback \n");
8801 if (MMPLAYER_IS_HTTP_PD(player))
8803 player->pd_downloader = NULL;
8804 player->pd_file_save_path = NULL;
8807 player->streaming_type = STREAMING_SERVICE_NONE;
8809 /* give default value of audio effect setting */
8810 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
8811 player->playback_rate = DEFAULT_PLAYBACK_RATE;
8813 player->play_subtitle = FALSE;
8814 player->use_textoverlay = FALSE;
8815 player->play_count = 0;
8816 player->use_decodebin = TRUE;
8817 player->ignore_asyncdone = FALSE;
8818 player->use_deinterleave = FALSE;
8819 player->max_audio_channels = 0;
8820 player->video_share_api_delta = 0;
8821 player->video_share_clock_delta = 0;
8822 player->has_closed_caption = FALSE;
8824 __mmplayer_post_proc_reset(player);
8826 if (player->ini.dump_element_keyword[0][0] == '\0')
8828 player->ini.set_dump_element_flag= FALSE;
8832 player->ini.set_dump_element_flag = TRUE;
8835 /* set player state to null */
8836 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8837 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_NULL );
8839 return MM_ERROR_NONE;
8843 g_mutex_clear(&player->fsink_lock );
8846 if ( player->repeat_thread )
8848 player->repeat_thread_exit = TRUE;
8849 g_cond_signal( &player->repeat_thread_cond );
8851 g_thread_join( player->repeat_thread );
8852 player->repeat_thread = NULL;
8854 g_mutex_clear(&player->repeat_thread_mutex );
8856 g_cond_clear (&player->repeat_thread_cond );
8858 /* clear repeat thread mutex/cond if still alive
8859 * this can happen if only thread creating has failed
8861 g_mutex_clear(&player->repeat_thread_mutex );
8862 g_cond_clear ( &player->repeat_thread_cond );
8864 /* free next play thread */
8865 if ( player->next_play_thread )
8867 player->next_play_thread_exit = TRUE;
8868 g_cond_signal( &player->next_play_thread_cond );
8870 g_thread_join( player->next_play_thread );
8871 player->next_play_thread = NULL;
8873 g_mutex_clear(&player->next_play_thread_mutex );
8875 g_cond_clear ( &player->next_play_thread_cond );
8877 /* clear next play thread mutex/cond if still alive
8878 * this can happen if only thread creating has failed
8880 g_mutex_clear(&player->next_play_thread_mutex );
8882 g_cond_clear ( &player->next_play_thread_cond );
8884 /* release attributes */
8885 _mmplayer_deconstruct_attribute(handle);
8889 return MM_ERROR_PLAYER_INTERNAL;
8893 __mmplayer_init_gstreamer(mm_player_t* player) // @
8895 static gboolean initialized = FALSE;
8896 static const int max_argc = 50;
8898 gchar** argv = NULL;
8899 gchar** argv2 = NULL;
8906 debug_log("gstreamer already initialized.\n");
8911 argc = malloc( sizeof(int) );
8912 argv = malloc( sizeof(gchar*) * max_argc );
8913 argv2 = malloc( sizeof(gchar*) * max_argc );
8915 if ( !argc || !argv || !argv2)
8918 memset( argv, 0, sizeof(gchar*) * max_argc );
8919 memset( argv2, 0, sizeof(gchar*) * max_argc );
8923 argv[0] = g_strdup( "mmplayer" );
8926 for ( i = 0; i < 5; i++ ) /* FIXIT : num of param is now fixed to 5. make it dynamic */
8928 if ( strlen( player->ini.gst_param[i] ) > 0 )
8930 argv[*argc] = g_strdup( player->ini.gst_param[i] );
8935 /* we would not do fork for scanning plugins */
8936 argv[*argc] = g_strdup("--gst-disable-registry-fork");
8939 /* check disable registry scan */
8940 if ( player->ini.skip_rescan )
8942 argv[*argc] = g_strdup("--gst-disable-registry-update");
8946 /* check disable segtrap */
8947 if ( player->ini.disable_segtrap )
8949 argv[*argc] = g_strdup("--gst-disable-segtrap");
8953 debug_log("initializing gstreamer with following parameter\n");
8954 debug_log("argc : %d\n", *argc);
8957 for ( i = 0; i < arg_count; i++ )
8960 debug_log("argv[%d] : %s\n", i, argv2[i]);
8964 /* initializing gstreamer */
8965 if ( ! gst_init_check (argc, &argv, &err))
8967 debug_error("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
8976 for ( i = 0; i < arg_count; i++ )
8978 //debug_log("release - argv[%d] : %s\n", i, argv2[i]);
8979 MMPLAYER_FREEIF( argv2[i] );
8982 MMPLAYER_FREEIF( argv );
8983 MMPLAYER_FREEIF( argv2 );
8984 MMPLAYER_FREEIF( argc );
8994 for ( i = 0; i < arg_count; i++ )
8996 debug_log("free[%d] : %s\n", i, argv2[i]);
8997 MMPLAYER_FREEIF( argv2[i] );
9000 MMPLAYER_FREEIF( argv );
9001 MMPLAYER_FREEIF( argv2 );
9002 MMPLAYER_FREEIF( argc );
9008 __mmplayer_destroy_streaming_ext(mm_player_t* player)
9010 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9012 if (player->pd_downloader)
9014 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
9015 MMPLAYER_FREEIF(player->pd_downloader);
9018 if (MMPLAYER_IS_HTTP_PD(player))
9020 _mmplayer_destroy_pd_downloader((MMHandleType)player);
9021 MMPLAYER_FREEIF(player->pd_file_save_path);
9024 return MM_ERROR_NONE;
9028 _mmplayer_destroy(MMHandleType handle) // @
9030 mm_player_t* player = MM_PLAYER_CAST(handle);
9034 /* check player handle */
9035 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9037 /* destroy can called at anytime */
9038 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL ( player, MMPLAYER_COMMAND_DESTROY );
9040 __mmplayer_destroy_streaming_ext(player);
9042 /* release repeat thread */
9043 if ( player->repeat_thread )
9045 player->repeat_thread_exit = TRUE;
9046 g_cond_signal( &player->repeat_thread_cond );
9048 debug_log("waitting for repeat thread exit\n");
9049 g_thread_join ( player->repeat_thread );
9050 g_mutex_clear(&player->repeat_thread_mutex );
9051 g_cond_clear (&player->repeat_thread_cond );
9052 debug_log("repeat thread released\n");
9055 /* release next play thread */
9056 if ( player->next_play_thread )
9058 player->next_play_thread_exit = TRUE;
9059 g_cond_signal( &player->next_play_thread_cond );
9061 debug_log("waitting for next play thread exit\n");
9062 g_thread_join ( player->next_play_thread );
9063 g_mutex_clear(&player->next_play_thread_mutex );
9064 g_cond_clear(&player->next_play_thread_cond );
9065 debug_log("next play thread released\n");
9068 _mmplayer_release_video_capture(player);
9070 /* flush any pending asm_cb */
9071 if (player->sound_focus.cb_pending)
9073 /* set a flag for make sure asm_cb to be returned immediately */
9074 debug_warning("asm cb has pending state");
9075 player->sound_focus.exit_cb = TRUE;
9077 /* make sure to release any pending asm_cb which locked by cmd_lock */
9078 MMPLAYER_CMD_UNLOCK(player);
9080 MMPLAYER_CMD_LOCK(player);
9084 if ( MM_ERROR_NONE != _mmplayer_sound_unregister(&player->sound_focus) )
9086 debug_error("failed to deregister asm server\n");
9089 #ifdef USE_LAZY_PAUSE
9090 if (player->lazy_pause_event_id)
9092 __mmplayer_remove_g_source_from_context(player->context.global_default, player->lazy_pause_event_id);
9093 player->lazy_pause_event_id = 0;
9097 if (player->resume_event_id)
9099 g_source_remove (player->resume_event_id);
9100 player->resume_event_id = 0;
9103 if (player->resumable_cancel_id)
9105 g_source_remove (player->resumable_cancel_id);
9106 player->resumable_cancel_id = 0;
9109 /* release pipeline */
9110 if ( MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline( player ) )
9112 debug_error("failed to destory pipeline\n");
9113 return MM_ERROR_PLAYER_INTERNAL;
9116 if (player->is_external_subtitle_present && player->subtitle_language_list)
9118 g_list_free (player->subtitle_language_list);
9119 player->subtitle_language_list = NULL;
9122 __mmplayer_release_dump_list (player->dump_list);
9124 /* release miscellaneous information.
9125 these info needs to be released after pipeline is destroyed. */
9126 __mmplayer_release_misc_post( player );
9128 /* release attributes */
9129 _mmplayer_deconstruct_attribute( handle );
9131 /* release factories */
9132 __mmplayer_release_factories( player );
9135 g_mutex_clear(&player->fsink_lock );
9137 g_mutex_clear(&player->msg_cb_lock );
9141 return MM_ERROR_NONE;
9145 __mmplayer_realize_streaming_ext(mm_player_t* player)
9147 int ret = MM_ERROR_NONE;
9150 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9152 if (MMPLAYER_IS_HTTP_PD(player))
9154 gboolean bret = FALSE;
9156 player->pd_downloader = _mmplayer_create_pd_downloader();
9157 if ( !player->pd_downloader )
9159 debug_error ("Unable to create PD Downloader...");
9160 ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
9163 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
9167 debug_error ("Unable to create PD Downloader...");
9168 ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
9177 _mmplayer_realize(MMHandleType hplayer) // @
9179 mm_player_t* player = (mm_player_t*)hplayer;
9182 int application_pid = -1;
9183 gboolean update_registry = FALSE;
9184 MMHandleType attrs = 0;
9185 int ret = MM_ERROR_NONE;
9189 /* check player handle */
9190 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED )
9192 /* check current state */
9193 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_REALIZE );
9195 attrs = MMPLAYER_GET_ATTRS(player);
9198 debug_error("fail to get attributes.\n");
9199 return MM_ERROR_PLAYER_INTERNAL;
9202 mm_attrs_get_int_by_name(attrs, "sound_application_pid", &application_pid );
9203 player->sound_focus.pid = application_pid;
9205 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
9206 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
9208 ret = __mmfplayer_parse_profile((const char*)uri, param, &player->profile);
9210 if (ret != MM_ERROR_NONE)
9212 debug_error("failed to parse profile\n");
9216 /* FIXIT : we can use thouse in player->profile directly */
9217 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM)
9219 player->mem_buf.buf = (char *)player->profile.mem;
9220 player->mem_buf.len = player->profile.mem_size;
9221 player->mem_buf.offset = 0;
9224 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_ES_BUFF)
9226 if (strstr(uri, "es_buff://push_mode"))
9228 player->es_player_push_mode = TRUE;
9232 player->es_player_push_mode = FALSE;
9236 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS)
9238 debug_warning("mms protocol is not supported format.\n");
9239 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
9242 if (MMPLAYER_IS_STREAMING(player))
9243 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
9245 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
9247 player->smooth_streaming = FALSE;
9248 player->videodec_linked = 0;
9249 player->videosink_linked = 0;
9250 player->audiodec_linked = 0;
9251 player->audiosink_linked = 0;
9252 player->textsink_linked = 0;
9253 player->is_external_subtitle_present = FALSE;
9254 /* set the subtitle ON default */
9255 player->is_subtitle_off = FALSE;
9257 /* registry should be updated for downloadable codec */
9258 mm_attrs_get_int_by_name(attrs, "profile_update_registry", &update_registry);
9260 if ( update_registry )
9262 debug_log("updating registry...\n");
9263 gst_update_registry();
9265 /* then we have to rebuild factories */
9266 __mmplayer_release_factories( player );
9267 __mmplayer_init_factories(player);
9270 /* realize pipeline */
9271 ret = __gst_realize( player );
9272 if ( ret != MM_ERROR_NONE )
9274 debug_error("fail to realize the player.\n");
9278 ret = __mmplayer_realize_streaming_ext(player);
9287 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
9290 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9292 /* destroy can called at anytime */
9293 if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player))
9295 _mmplayer_unrealize_pd_downloader ((MMHandleType)player);
9296 MMPLAYER_FREEIF(player->pd_downloader);
9300 return MM_ERROR_NONE;
9304 _mmplayer_unrealize(MMHandleType hplayer)
9306 mm_player_t* player = (mm_player_t*)hplayer;
9307 int ret = MM_ERROR_NONE;
9311 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED )
9313 /* check current state */
9314 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_UNREALIZE );
9316 __mmplayer_unrealize_streaming_ext(player);
9318 /* unrealize pipeline */
9319 ret = __gst_unrealize( player );
9321 /* set asm stop if success */
9322 if (MM_ERROR_NONE == ret)
9324 ret = _mmplayer_sound_release_focus(&player->sound_focus);
9325 if ( ret != MM_ERROR_NONE )
9327 debug_error("failed to release sound focus\n");
9333 debug_error("failed and don't change asm state to stop");
9342 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param) // @
9344 mm_player_t* player = (mm_player_t*)hplayer;
9346 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9348 return __gst_set_message_callback(player, callback, user_param);
9352 _mmplayer_get_state(MMHandleType hplayer, int* state) // @
9354 mm_player_t *player = (mm_player_t*)hplayer;
9356 return_val_if_fail(state, MM_ERROR_INVALID_ARGUMENT);
9358 *state = MMPLAYER_CURRENT_STATE(player);
9360 return MM_ERROR_NONE;
9365 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume) // @
9367 mm_player_t* player = (mm_player_t*) hplayer;
9368 GstElement* vol_element = NULL;
9373 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9375 debug_log("volume [L]=%f:[R]=%f\n",
9376 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
9378 /* invalid factor range or not */
9379 for ( i = 0; i < MM_VOLUME_CHANNEL_NUM; i++ )
9381 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
9382 debug_error("Invalid factor! (valid factor:0~1.0)\n");
9383 return MM_ERROR_INVALID_ARGUMENT;
9387 /* not support to set other value into each channel */
9388 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
9389 return MM_ERROR_INVALID_ARGUMENT;
9391 /* Save volume to handle. Currently the first array element will be saved. */
9392 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
9394 /* check pipeline handle */
9395 if ( ! player->pipeline || ! player->pipeline->audiobin )
9397 debug_log("audiobin is not created yet\n");
9398 debug_log("but, current stored volume will be set when it's created.\n");
9400 /* NOTE : stored volume will be used in create_audiobin
9401 * returning MM_ERROR_NONE here makes application to able to
9402 * set volume at anytime.
9404 return MM_ERROR_NONE;
9407 /* setting volume to volume element */
9408 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
9412 debug_log("volume is set [%f]\n", player->sound.volume);
9413 g_object_set(vol_element, "volume", player->sound.volume, NULL);
9418 return MM_ERROR_NONE;
9423 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
9425 mm_player_t* player = (mm_player_t*) hplayer;
9430 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9431 return_val_if_fail( volume, MM_ERROR_INVALID_ARGUMENT );
9433 /* returning stored volume */
9434 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
9435 volume->level[i] = player->sound.volume;
9439 return MM_ERROR_NONE;
9445 _mmplayer_set_mute(MMHandleType hplayer, int mute) // @
9447 mm_player_t* player = (mm_player_t*) hplayer;
9448 GstElement* vol_element = NULL;
9452 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9454 /* mute value shoud 0 or 1 */
9455 if ( mute != 0 && mute != 1 )
9457 debug_error("bad mute value\n");
9459 /* FIXIT : definitly, we need _BAD_PARAM error code */
9460 return MM_ERROR_INVALID_ARGUMENT;
9463 player->sound.mute = mute;
9465 /* just hold mute value if pipeline is not ready */
9466 if ( !player->pipeline || !player->pipeline->audiobin )
9468 debug_log("pipeline is not ready. holding mute value\n");
9469 return MM_ERROR_NONE;
9472 vol_element = player->pipeline->audiobin[MMPLAYER_A_SINK].gst;
9474 /* NOTE : volume will only created when the bt is enabled */
9477 debug_log("mute : %d\n", mute);
9478 g_object_set(vol_element, "mute", mute, NULL);
9482 debug_log("volume elemnet is not created. using volume in audiosink\n");
9487 return MM_ERROR_NONE;
9491 _mmplayer_get_mute(MMHandleType hplayer, int* pmute) // @
9493 mm_player_t* player = (mm_player_t*) hplayer;
9497 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9498 return_val_if_fail ( pmute, MM_ERROR_INVALID_ARGUMENT );
9500 /* just hold mute value if pipeline is not ready */
9501 if ( !player->pipeline || !player->pipeline->audiobin )
9503 debug_log("pipeline is not ready. returning stored value\n");
9504 *pmute = player->sound.mute;
9505 return MM_ERROR_NONE;
9508 *pmute = player->sound.mute;
9512 return MM_ERROR_NONE;
9516 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
9518 mm_player_t* player = (mm_player_t*) hplayer;
9522 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9524 player->video_stream_changed_cb = callback;
9525 player->video_stream_changed_cb_user_param = user_param;
9526 debug_log("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
9530 return MM_ERROR_NONE;
9534 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
9536 mm_player_t* player = (mm_player_t*) hplayer;
9540 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9542 player->audio_stream_changed_cb = callback;
9543 player->audio_stream_changed_cb_user_param = user_param;
9544 debug_log("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
9548 return MM_ERROR_NONE;
9552 _mmplayer_set_audiostream_cb_ex(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback_ex callback, void *user_param) // @
9554 mm_player_t* player = (mm_player_t*) hplayer;
9558 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9560 player->audio_stream_render_cb_ex = callback;
9561 player->audio_stream_cb_user_param = user_param;
9562 player->audio_stream_sink_sync = sync;
9563 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);
9567 return MM_ERROR_NONE;
9571 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param) // @
9573 mm_player_t* player = (mm_player_t*) hplayer;
9577 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9579 player->video_stream_cb = callback;
9580 player->video_stream_cb_user_param = user_param;
9581 player->use_video_stream = TRUE;
9582 debug_log("Stream cb Handle value is %p : %p\n", player, player->video_stream_cb);
9586 return MM_ERROR_NONE;
9590 _mmplayer_set_audiostream_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param) // @
9592 mm_player_t* player = (mm_player_t*) hplayer;
9596 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9598 player->audio_stream_cb = callback;
9599 player->audio_stream_cb_user_param = user_param;
9600 debug_log("Audio Stream cb Handle value is %p : %p\n", player, player->audio_stream_cb);
9604 return MM_ERROR_NONE;
9609 _mmplayer_set_prepare_buffering_time(MMHandleType hplayer, int second)
9611 mm_player_t* player = (mm_player_t*) hplayer;
9615 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9617 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL)
9618 return MM_ERROR_PLAYER_INVALID_STATE;
9620 debug_log("pre buffer size : %d sec\n", second);
9624 debug_error("bad size value\n");
9625 return MM_ERROR_INVALID_ARGUMENT;
9628 if (player->streamer == NULL)
9630 player->streamer = __mm_player_streaming_create();
9631 __mm_player_streaming_initialize(player->streamer);
9634 player->streamer->buffering_req.initial_second = second;
9638 return MM_ERROR_NONE;
9643 _mmplayer_set_runtime_buffering_mode(MMHandleType hplayer, MMPlayerBufferingMode mode, int second)
9645 mm_player_t* player = (mm_player_t*) hplayer;
9649 return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9651 debug_log("mode %d\n", mode);
9653 if ((mode < 0) || (mode > MM_PLAYER_BUFFERING_MODE_MAX) ||
9654 ((mode == MM_PLAYER_BUFFERING_MODE_FIXED) && (second <= 0)))
9655 return MM_ERROR_INVALID_ARGUMENT;
9657 if (player->streamer == NULL)
9659 player->streamer = __mm_player_streaming_create();
9660 __mm_player_streaming_initialize(player->streamer);
9663 player->streamer->buffering_req.mode = mode;
9666 ((mode == MM_PLAYER_BUFFERING_MODE_FIXED) ||
9667 (mode == MM_PLAYER_BUFFERING_MODE_ADAPTIVE)))
9668 player->streamer->buffering_req.runtime_second = second;
9672 return MM_ERROR_NONE;
9676 _mmplayer_set_videoframe_render_error_cb(MMHandleType hplayer, mm_player_video_frame_render_error_callback callback, void *user_param) // @
9678 mm_player_t* player = (mm_player_t*) hplayer;
9682 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9683 return_val_if_fail ( callback, MM_ERROR_INVALID_ARGUMENT );
9685 player->video_frame_render_error_cb = callback;
9686 player->video_frame_render_error_cb_user_param = user_param;
9688 debug_log("Video frame render error cb Handle value is %p : %p\n", player, player->video_frame_render_error_cb);
9692 return MM_ERROR_NONE;
9696 __mmplayer_start_streaming_ext(mm_player_t *player)
9698 gint ret = MM_ERROR_NONE;
9701 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9703 if (MMPLAYER_IS_HTTP_PD(player))
9705 if ( !player->pd_downloader )
9707 ret = __mmplayer_realize_streaming_ext(player);
9709 if ( ret != MM_ERROR_NONE)
9711 debug_error ("failed to realize streaming ext\n");
9716 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI)
9718 ret = _mmplayer_start_pd_downloader ((MMHandleType)player);
9721 debug_error ("ERROR while starting PD...\n");
9722 return MM_ERROR_PLAYER_NOT_INITIALIZED;
9724 ret = MM_ERROR_NONE;
9733 _mmplayer_start(MMHandleType hplayer) // @
9735 mm_player_t* player = (mm_player_t*) hplayer;
9736 gint ret = MM_ERROR_NONE;
9740 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9742 /* check current state */
9743 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_START );
9745 ret = _mmplayer_sound_acquire_focus(&player->sound_focus);
9746 if ( ret != MM_ERROR_NONE )
9748 debug_error("failed to acquire sound focus.\n");
9752 /* NOTE : we should check and create pipeline again if not created as we destroy
9753 * whole pipeline when stopping in streamming playback
9755 if ( ! player->pipeline )
9757 ret = __gst_realize( player );
9758 if ( MM_ERROR_NONE != ret )
9760 debug_error("failed to realize before starting. only in streamming\n");
9766 ret = __mmplayer_start_streaming_ext(player);
9767 if ( ret != MM_ERROR_NONE )
9769 debug_error("failed to start streaming ext \n");
9772 /* start pipeline */
9773 ret = __gst_start( player );
9774 if ( ret != MM_ERROR_NONE )
9776 debug_error("failed to start player.\n");
9784 /* NOTE: post "not supported codec message" to application
9785 * when one codec is not found during AUTOPLUGGING in MSL.
9786 * So, it's separated with error of __mmplayer_gst_callback().
9787 * And, if any codec is not found, don't send message here.
9788 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
9791 __mmplayer_handle_missed_plugin(mm_player_t* player)
9793 MMMessageParamType msg_param;
9794 memset (&msg_param, 0, sizeof(MMMessageParamType));
9795 gboolean post_msg_direct = FALSE;
9799 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9801 debug_log("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
9802 player->not_supported_codec, player->can_support_codec);
9804 if( player->not_found_demuxer )
9806 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9807 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
9809 MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param );
9810 MMPLAYER_FREEIF(msg_param.data);
9812 return MM_ERROR_NONE;
9815 if (player->not_supported_codec)
9817 if ( player->can_support_codec ) // There is one codec to play
9819 post_msg_direct = TRUE;
9823 if ( player->pipeline->audiobin ) // Some content has only PCM data in container.
9824 post_msg_direct = TRUE;
9827 if ( post_msg_direct )
9829 MMMessageParamType msg_param;
9830 memset (&msg_param, 0, sizeof(MMMessageParamType));
9832 if ( player->not_supported_codec == MISSING_PLUGIN_AUDIO )
9834 debug_warning("not found AUDIO codec, posting error code to application.\n");
9836 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9837 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9839 else if ( player->not_supported_codec == MISSING_PLUGIN_VIDEO )
9841 debug_warning("not found VIDEO codec, posting error code to application.\n");
9843 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
9844 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
9847 MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param );
9849 MMPLAYER_FREEIF(msg_param.data);
9851 return MM_ERROR_NONE;
9853 else // no any supported codec case
9855 debug_warning("not found any codec, posting error code to application.\n");
9857 if ( player->not_supported_codec == MISSING_PLUGIN_AUDIO )
9859 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9860 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9864 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9865 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
9868 MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param );
9870 MMPLAYER_FREEIF(msg_param.data);
9876 return MM_ERROR_NONE;
9879 static void __mmplayer_check_pipeline(mm_player_t* player)
9881 GstState element_state = GST_STATE_VOID_PENDING;
9882 GstState element_pending_state = GST_STATE_VOID_PENDING;
9884 int ret = MM_ERROR_NONE;
9886 if (player->gapless.reconfigure)
9888 debug_warning("pipeline is under construction.\n");
9890 MMPLAYER_PLAYBACK_LOCK(player);
9891 MMPLAYER_PLAYBACK_UNLOCK(player);
9893 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT ( player );
9895 /* wait for state transition */
9896 ret = gst_element_get_state( player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND );
9898 if ( ret == GST_STATE_CHANGE_FAILURE )
9900 debug_error("failed to change pipeline state within %d sec\n", timeout );
9905 /* NOTE : it should be able to call 'stop' anytime*/
9907 _mmplayer_stop(MMHandleType hplayer) // @
9909 mm_player_t* player = (mm_player_t*)hplayer;
9910 int ret = MM_ERROR_NONE;
9914 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9916 /* check current state */
9917 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_STOP );
9919 /* check pipline building state */
9920 __mmplayer_check_pipeline(player);
9921 player->gapless.start_time = 0;
9923 /* NOTE : application should not wait for EOS after calling STOP */
9924 __mmplayer_cancel_eos_timer( player );
9926 __mmplayer_unrealize_streaming_ext(player);
9929 player->doing_seek = FALSE;
9932 ret = __gst_stop( player );
9934 if ( ret != MM_ERROR_NONE )
9936 debug_error("failed to stop player.\n");
9945 _mmplayer_pause(MMHandleType hplayer) // @
9947 mm_player_t* player = (mm_player_t*)hplayer;
9948 gint64 pos_msec = 0;
9949 gboolean async = FALSE;
9950 gint ret = MM_ERROR_NONE;
9954 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9956 /* check current state */
9957 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_PAUSE );
9959 /* check pipline building state */
9960 __mmplayer_check_pipeline(player);
9962 switch (MMPLAYER_CURRENT_STATE(player))
9964 case MM_PLAYER_STATE_READY:
9966 /* check prepare async or not.
9967 * In the case of streaming playback, it's recommned to avoid blocking wait.
9969 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9970 debug_log("prepare working mode : %s", (async ? "async" : "sync"));
9974 case MM_PLAYER_STATE_PLAYING:
9976 /* NOTE : store current point to overcome some bad operation
9977 * ( returning zero when getting current position in paused state) of some
9980 if ( !gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec))
9981 debug_warning("getting current position failed in paused\n");
9983 player->last_position = pos_msec;
9988 /* pause pipeline */
9989 ret = __gst_pause( player, async );
9991 if ( ret != MM_ERROR_NONE )
9993 debug_error("failed to pause player. ret : 0x%x\n", ret);
10002 _mmplayer_resume(MMHandleType hplayer)
10004 mm_player_t* player = (mm_player_t*)hplayer;
10005 int ret = MM_ERROR_NONE;
10006 gboolean async = FALSE;
10010 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
10012 ret = _mmplayer_sound_acquire_focus(&player->sound_focus);
10013 if ( ret != MM_ERROR_NONE )
10015 debug_error("failed to acquire sound focus.\n");
10019 /* check current state */
10020 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_RESUME );
10022 ret = __gst_resume( player, async );
10024 if ( ret != MM_ERROR_NONE )
10026 debug_error("failed to resume player.\n");
10035 __mmplayer_set_play_count(mm_player_t* player, gint count)
10037 MMHandleType attrs = 0;
10041 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
10043 attrs = MMPLAYER_GET_ATTRS(player);
10046 debug_error("fail to get attributes.\n");
10047 return MM_ERROR_PLAYER_INTERNAL;
10050 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
10051 if ( mmf_attrs_commit ( attrs ) ) /* return -1 if error */
10052 debug_error("failed to commit\n");
10056 return MM_ERROR_NONE;
10060 _mmplayer_activate_section_repeat(MMHandleType hplayer, unsigned long start, unsigned long end)
10062 mm_player_t* player = (mm_player_t*)hplayer;
10063 gint64 start_pos = 0;
10064 gint64 end_pos = 0;
10065 gint infinity = -1;
10069 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
10070 return_val_if_fail ( end <= GST_TIME_AS_MSECONDS(player->duration), MM_ERROR_INVALID_ARGUMENT );
10072 player->section_repeat = TRUE;
10073 player->section_repeat_start = start;
10074 player->section_repeat_end = end;
10076 start_pos = player->section_repeat_start * G_GINT64_CONSTANT(1000000);
10077 end_pos = player->section_repeat_end * G_GINT64_CONSTANT(1000000);
10079 __mmplayer_set_play_count( player, infinity );
10081 if ( (!__gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
10082 player->playback_rate,
10084 ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ),
10085 GST_SEEK_TYPE_SET, start_pos,
10086 GST_SEEK_TYPE_SET, end_pos)))
10088 debug_error("failed to activate section repeat\n");
10090 return MM_ERROR_PLAYER_SEEK;
10093 debug_log("succeeded to set section repeat from %d to %d\n",
10094 player->section_repeat_start, player->section_repeat_end);
10098 return MM_ERROR_NONE;
10102 __mmplayer_set_pcm_extraction(mm_player_t* player)
10104 gint64 start_nsec = 0;
10105 gint64 end_nsec = 0;
10106 gint64 dur_nsec = 0;
10107 gint64 dur_msec = 0;
10108 int required_start = 0;
10109 int required_end = 0;
10114 return_val_if_fail( player, FALSE );
10116 mm_attrs_multiple_get(player->attrs,
10118 "pcm_extraction_start_msec", &required_start,
10119 "pcm_extraction_end_msec", &required_end,
10122 debug_log("pcm extraction required position is from [%d] to [%d] (msec)\n", required_start, required_end);
10124 if (required_start == 0 && required_end == 0)
10126 debug_log("extracting entire stream");
10127 return MM_ERROR_NONE;
10129 else if (required_start < 0 || required_start > required_end || required_end < 0 )
10131 debug_log("invalid range for pcm extraction");
10132 return MM_ERROR_INVALID_ARGUMENT;
10136 ret = gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec);
10139 debug_error("failed to get duration");
10140 return MM_ERROR_PLAYER_INTERNAL;
10142 dur_msec = GST_TIME_AS_MSECONDS(dur_nsec);
10144 if (dur_msec < required_end) // FIXME
10146 debug_log("invalid end pos for pcm extraction");
10147 return MM_ERROR_INVALID_ARGUMENT;
10150 start_nsec = required_start * G_GINT64_CONSTANT(1000000);
10151 end_nsec = required_end * G_GINT64_CONSTANT(1000000);
10153 if ( (!__gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
10156 ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ),
10157 GST_SEEK_TYPE_SET, start_nsec,
10158 GST_SEEK_TYPE_SET, end_nsec)))
10160 debug_error("failed to seek for pcm extraction\n");
10162 return MM_ERROR_PLAYER_SEEK;
10165 debug_log("succeeded to set up segment extraction from [%llu] to [%llu] (nsec)\n", start_nsec, end_nsec);
10169 return MM_ERROR_NONE;
10173 _mmplayer_deactivate_section_repeat(MMHandleType hplayer)
10175 mm_player_t* player = (mm_player_t*)hplayer;
10176 gint64 cur_pos = 0;
10181 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
10183 player->section_repeat = FALSE;
10185 __mmplayer_set_play_count( player, onetime );
10187 gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_pos);
10189 if ( (!__gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
10192 ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ),
10193 GST_SEEK_TYPE_SET, cur_pos,
10194 GST_SEEK_TYPE_SET, player->duration )))
10196 debug_error("failed to deactivate section repeat\n");
10198 return MM_ERROR_PLAYER_SEEK;
10203 return MM_ERROR_NONE;
10207 _mmplayer_set_playspeed(MMHandleType hplayer, float rate)
10209 mm_player_t* player = (mm_player_t*)hplayer;
10210 gint64 pos_msec = 0;
10211 int ret = MM_ERROR_NONE;
10213 signed long long start = 0, stop = 0;
10214 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
10217 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
10218 return_val_if_fail ( !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API );
10220 /* The sound of video is not supported under 0.0 and over 2.0. */
10221 if(rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN)
10223 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
10226 _mmplayer_set_mute(hplayer, mute);
10228 if (player->playback_rate == rate)
10229 return MM_ERROR_NONE;
10231 /* If the position is reached at start potion during fast backward, EOS is posted.
10232 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
10234 player->playback_rate = rate;
10236 current_state = MMPLAYER_CURRENT_STATE(player);
10238 if ( current_state != MM_PLAYER_STATE_PAUSED )
10239 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
10241 debug_log ("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS (pos_msec), ret, current_state);
10243 if ( ( current_state == MM_PLAYER_STATE_PAUSED )
10245 //|| ( player->last_position != 0 && pos_msec == 0 ) )
10247 debug_warning("returning last point : %lld\n", player->last_position );
10248 pos_msec = player->last_position;
10255 stop = GST_CLOCK_TIME_NONE;
10259 start = GST_CLOCK_TIME_NONE;
10262 if ((!gst_element_seek (player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
10265 ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ),
10266 GST_SEEK_TYPE_SET, start,
10267 GST_SEEK_TYPE_SET, stop)))
10269 debug_error("failed to set speed playback\n");
10270 return MM_ERROR_PLAYER_SEEK;
10273 debug_log("succeeded to set speed playback as %0.1f\n", rate);
10277 return MM_ERROR_NONE;;
10281 _mmplayer_set_position(MMHandleType hplayer, int format, int position) // @
10283 mm_player_t* player = (mm_player_t*)hplayer;
10284 int ret = MM_ERROR_NONE;
10288 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
10290 ret = __gst_set_position ( player, format, (unsigned long)position, FALSE );
10298 _mmplayer_get_position(MMHandleType hplayer, int format, unsigned long *position) // @
10300 mm_player_t* player = (mm_player_t*)hplayer;
10301 int ret = MM_ERROR_NONE;
10303 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
10305 ret = __gst_get_position ( player, format, position );
10311 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos) // @
10313 mm_player_t* player = (mm_player_t*)hplayer;
10314 int ret = MM_ERROR_NONE;
10316 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
10318 ret = __gst_get_buffer_position ( player, format, start_pos, stop_pos );
10324 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position) // @
10326 mm_player_t* player = (mm_player_t*)hplayer;
10327 int ret = MM_ERROR_NONE;
10331 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
10333 ret = __gst_adjust_subtitle_position(player, format, position);
10340 _mmplayer_adjust_video_postion(MMHandleType hplayer, int offset) // @
10342 mm_player_t* player = (mm_player_t*)hplayer;
10343 int ret = MM_ERROR_NONE;
10347 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
10349 ret = __gst_adjust_video_position(player, offset);
10357 __mmplayer_is_midi_type( gchar* str_caps)
10359 if ( ( g_strrstr(str_caps, "audio/midi") ) ||
10360 ( g_strrstr(str_caps, "application/x-gst_ff-mmf") ) ||
10361 ( g_strrstr(str_caps, "application/x-smaf") ) ||
10362 ( g_strrstr(str_caps, "audio/x-imelody") ) ||
10363 ( g_strrstr(str_caps, "audio/mobile-xmf") ) ||
10364 ( g_strrstr(str_caps, "audio/xmf") ) ||
10365 ( g_strrstr(str_caps, "audio/mxmf") ) )
10367 debug_log("midi\n");
10376 __mmplayer_is_only_mp3_type (gchar *str_caps)
10378 if (g_strrstr(str_caps, "application/x-id3") ||
10379 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
10387 __mmplayer_set_audio_attrs (mm_player_t* player, GstCaps* caps)
10389 GstStructure* caps_structure = NULL;
10390 gint samplerate = 0;
10394 return_if_fail (player && caps);
10396 caps_structure = gst_caps_get_structure(caps, 0);
10398 /* set stream information */
10399 gst_structure_get_int (caps_structure, "rate", &samplerate);
10400 mm_attrs_set_int_by_name (player->attrs, "content_audio_samplerate", samplerate);
10402 gst_structure_get_int (caps_structure, "channels", &channels);
10403 mm_attrs_set_int_by_name (player->attrs, "content_audio_channels", channels);
10405 debug_log ("audio samplerate : %d channels : %d\n", samplerate, channels);
10409 __mmplayer_update_content_type_info(mm_player_t* player)
10412 return_if_fail( player && player->type);
10414 if (__mmplayer_is_midi_type(player->type))
10416 player->bypass_audio_effect = TRUE;
10418 else if (g_strrstr(player->type, "application/x-hls"))
10420 /* If it can't know exact type when it parses uri because of redirection case,
10421 * it will be fixed by typefinder or when doing autoplugging.
10423 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
10424 if (player->streamer)
10426 player->streamer->is_adaptive_streaming = TRUE;
10427 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
10428 player->streamer->buffering_req.runtime_second = 5;
10431 else if (g_strrstr(player->type, "application/dash+xml"))
10433 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
10440 __mmplayer_typefind_have_type( GstElement *tf, guint probability, // @
10441 GstCaps *caps, gpointer data)
10443 mm_player_t* player = (mm_player_t*)data;
10444 GstPad* pad = NULL;
10448 return_if_fail( player && tf && caps );
10450 /* store type string */
10451 MMPLAYER_FREEIF(player->type);
10452 player->type = gst_caps_to_string(caps);
10454 debug_log("meida type %s found, probability %d%% / %d\n", player->type, probability, gst_caps_get_size(caps));
10456 if ( (!MMPLAYER_IS_WFD_STREAMING( player )) &&
10457 (!MMPLAYER_IS_RTSP_STREAMING( player )) &&
10458 (g_strrstr(player->type, "audio/x-raw-int")))
10460 debug_error("not support media format\n");
10462 if (player->msg_posted == FALSE)
10464 MMMessageParamType msg_param;
10465 memset (&msg_param, 0, sizeof(MMMessageParamType));
10467 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
10468 MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param );
10470 /* don't post more if one was sent already */
10471 player->msg_posted = TRUE;
10476 __mmplayer_update_content_type_info(player);
10478 pad = gst_element_get_static_pad(tf, "src");
10481 debug_error("fail to get typefind src pad.\n");
10485 if (player->use_decodebin)
10487 if(!__mmplayer_try_to_plug_decodebin( player, pad, caps ))
10489 gboolean async = FALSE;
10490 debug_error("failed to autoplug %s\n", player->type);
10492 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
10494 if ( async && player->msg_posted == FALSE )
10496 __mmplayer_handle_missed_plugin( player );
10505 if ( ! __mmplayer_try_to_plug( player, pad, caps ) )
10507 gboolean async = FALSE;
10508 debug_error("failed to autoplug %s\n", player->type);
10510 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
10512 if ( async && player->msg_posted == FALSE )
10514 __mmplayer_handle_missed_plugin( player );
10520 /* finish autopluging if no dynamic pad waiting */
10521 if( ( ! player->have_dynamic_pad) && ( ! player->has_many_types) )
10523 if ( ! MMPLAYER_IS_RTSP_STREAMING( player ) )
10525 __mmplayer_pipeline_complete( NULL, (gpointer)player );
10531 gst_object_unref( GST_OBJECT(pad) );
10538 #ifdef _MM_PLAYER_ALP_PARSER
10539 void check_name (void *data, void *user_data)
10541 mm_player_t* player = user_data;
10543 if (g_strrstr((gchar*)data, "mpegaudioparse"))
10545 debug_log("mpegaudioparse - set alp-mp3dec\n");
10546 g_object_set(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "alp-mp3dec", TRUE, NULL);
10551 static GstElement *
10552 __mmplayer_create_decodebin (mm_player_t* player)
10554 GstElement *decodebin = NULL;
10558 /* create decodebin */
10559 decodebin = gst_element_factory_make("decodebin", NULL);
10563 debug_error("fail to create decodebin\n");
10567 /* raw pad handling signal */
10568 MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
10569 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
10571 /* no-more-pad pad handling signal */
10572 MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
10573 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), player);
10575 MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
10576 G_CALLBACK(__mmplayer_gst_decode_pad_removed), player);
10578 /* This signal is emitted when a pad for which there is no further possible
10579 decoding is added to the decodebin.*/
10580 MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
10581 G_CALLBACK(__mmplayer_gst_decode_unknown_type), player );
10583 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
10584 before looking for any elements that can handle that stream.*/
10585 MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
10586 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), player);
10588 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
10589 before looking for any elements that can handle that stream.*/
10590 MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
10591 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
10593 /* This signal is emitted once decodebin has finished decoding all the data.*/
10594 MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
10595 G_CALLBACK(__mmplayer_gst_decode_drained), player);
10597 /* This signal is emitted when a element is added to the bin.*/
10598 MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
10599 G_CALLBACK(__mmplayer_gst_element_added), player);
10606 __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
10608 MMPlayerGstElement* mainbin = NULL;
10609 GstElement* decodebin = NULL;
10610 GstElement* queue2 = NULL;
10611 GstPad* sinkpad = NULL;
10612 GstPad* qsrcpad= NULL;
10613 gchar *caps_str = NULL;
10614 gint64 dur_bytes = 0L;
10615 gchar* file_buffering_path = NULL;
10616 gboolean use_file_buffer = FALSE;
10618 guint max_buffer_size_bytes = 0;
10619 gdouble init_buffering_time = (gdouble)player->streamer->buffering_req.initial_second;
10622 return_val_if_fail (player && player->pipeline && player->pipeline->mainbin, FALSE);
10624 mainbin = player->pipeline->mainbin;
10626 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
10627 (MMPLAYER_IS_HTTP_STREAMING(player)))
10629 debug_log ("creating http streaming buffering queue (queue2)\n");
10631 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)
10633 debug_error ("MMPLAYER_M_MUXED_S_BUFFER is not null\n");
10637 queue2 = gst_element_factory_make ("queue2", "queue2");
10640 debug_error ("failed to create buffering queue element\n");
10644 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2))
10646 debug_error("failed to add buffering queue\n");
10650 sinkpad = gst_element_get_static_pad(queue2, "sink");
10651 qsrcpad = gst_element_get_static_pad(queue2, "src");
10653 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad))
10655 debug_error("failed to link buffering queue\n");
10659 // if ( !MMPLAYER_IS_HTTP_LIVE_STREAMING(player))
10661 if ( !gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
10662 debug_error("fail to get duration.\n");
10664 debug_log("dur_bytes = %lld\n", dur_bytes);
10668 use_file_buffer = MMPLAYER_USE_FILE_FOR_BUFFERING(player);
10669 file_buffering_path = g_strdup(player->ini.http_file_buffer_path);
10677 /* NOTE : we cannot get any duration info from ts container in case of streaming */
10678 // if(!g_strrstr(GST_ELEMENT_NAME(sinkelement), "mpegtsdemux"))
10679 if(!g_strrstr(player->type, "video/mpegts"))
10681 max_buffer_size_bytes = (use_file_buffer)?(player->ini.http_max_size_bytes):(5*1024*1024);
10682 debug_log("max_buffer_size_bytes = %d\n", max_buffer_size_bytes);
10684 __mm_player_streaming_set_queue2(player->streamer,
10687 max_buffer_size_bytes,
10688 player->ini.http_buffering_time,
10690 player->ini.http_buffering_limit, // no meaning
10692 file_buffering_path,
10693 (guint64)dur_bytes);
10696 MMPLAYER_FREEIF(file_buffering_path);
10697 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent (queue2))
10699 debug_error("failed to sync queue2 state with parent\n");
10705 gst_object_unref(GST_OBJECT(sinkpad));
10707 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
10708 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
10712 /* create decodebin */
10713 decodebin = __mmplayer_create_decodebin(player);
10717 debug_error("can not create autoplug element\n");
10721 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin))
10723 debug_error("failed to add decodebin\n");
10727 /* to force caps on the decodebin element and avoid reparsing stuff by
10728 * typefind. It also avoids a deadlock in the way typefind activates pads in
10729 * the state change */
10730 g_object_set (decodebin, "sink-caps", caps, NULL);
10732 sinkpad = gst_element_get_static_pad(decodebin, "sink");
10734 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad))
10736 debug_error("failed to link decodebin\n");
10740 gst_object_unref(GST_OBJECT(sinkpad));
10742 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
10743 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
10745 /* set decodebin property about buffer in streaming playback. *
10746 * in case of hls, it does not need to have big buffer *
10747 * because it is kind of adaptive streaming. */
10748 if ( ((!MMPLAYER_IS_HTTP_PD(player)) &&
10749 (MMPLAYER_IS_HTTP_STREAMING(player))) || MMPLAYER_IS_DASH_STREAMING (player))
10751 guint max_size_bytes = MAX_DECODEBIN_BUFFER_BYTES;
10752 guint64 max_size_time = MAX_DECODEBIN_BUFFER_TIME;
10753 init_buffering_time = (init_buffering_time != 0)?(init_buffering_time):(player->ini.http_buffering_time);
10755 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {
10756 max_size_bytes = MAX_DECODEBIN_ADAPTIVE_BUFFER_BYTES;
10757 max_size_time = MAX_DECODEBIN_ADAPTIVE_BUFFER_TIME;
10760 g_object_set (G_OBJECT(decodebin), "use-buffering", TRUE,
10761 "high-percent", (gint)player->ini.http_buffering_limit,
10762 "low-percent", 1, // 1%
10763 "max-size-bytes", max_size_bytes,
10764 "max-size-time", (guint64)(max_size_time * GST_SECOND),
10765 "max-size-buffers", 0, NULL); // disable or automatic
10768 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin))
10770 debug_error("failed to sync decodebin state with parent\n");
10780 MMPLAYER_FREEIF( caps_str );
10783 gst_object_unref(GST_OBJECT(sinkpad));
10787 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
10788 * You need to explicitly set elements to the NULL state before
10789 * dropping the final reference, to allow them to clean up.
10791 gst_element_set_state(queue2, GST_STATE_NULL);
10793 /* And, it still has a parent "player".
10794 * You need to let the parent manage the object instead of unreffing the object directly.
10796 gst_bin_remove (GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
10797 gst_object_unref (queue2);
10803 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
10804 * You need to explicitly set elements to the NULL state before
10805 * dropping the final reference, to allow them to clean up.
10807 gst_element_set_state(decodebin, GST_STATE_NULL);
10809 /* And, it still has a parent "player".
10810 * You need to let the parent manage the object instead of unreffing the object directly.
10813 gst_bin_remove (GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
10814 gst_object_unref (decodebin);
10821 /* it will return first created element */
10823 __mmplayer_try_to_plug(mm_player_t* player, GstPad *pad, const GstCaps *caps) // @
10825 MMPlayerGstElement* mainbin = NULL;
10826 const char* mime = NULL;
10827 const GList* item = NULL;
10828 const gchar* klass = NULL;
10829 GstCaps* res = NULL;
10830 gboolean skip = FALSE;
10831 GstPad* queue_pad = NULL;
10832 GstElement* queue = NULL;
10833 GstElement *element = NULL;
10837 return_val_if_fail( player && player->pipeline && player->pipeline->mainbin, FALSE );
10839 mainbin = player->pipeline->mainbin;
10841 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10843 /* return if we got raw output */
10844 if(g_str_has_prefix(mime, "video/x-raw") || g_str_has_prefix(mime, "audio/x-raw")
10845 || g_str_has_prefix(mime, "text/plain") ||g_str_has_prefix(mime, "text/x-pango-markup"))
10848 element = (GstElement*)gst_pad_get_parent(pad);
10849 /* NOTE : When no decoder has added during autoplugging. like a simple wave playback.
10850 * No queue will be added. I think it can caused breaking sound when playing raw audio
10851 * frames but there's no different. Decodebin also doesn't add with those wav fils.
10852 * Anyway, currentely raw-queue seems not necessary.
10855 /* NOTE : check if previously linked element is demuxer/depayloader/parse means no decoder
10856 * has linked. if so, we need to add queue for quality of output. note that
10857 * decodebin also has same problem.
10859 klass = gst_element_factory_get_metadata (gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
10861 /* add queue if needed */
10862 if( (g_strrstr(klass, "Demux") || g_strrstr(klass, "Depayloader")
10863 || g_strrstr(klass, "Parse")) && !g_str_has_prefix(mime, "text"))
10865 debug_log("adding raw queue\n");
10867 queue = gst_element_factory_make("queue", NULL);
10870 debug_warning("failed to create queue\n");
10875 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_READY) )
10877 debug_warning("failed to set state READY to queue\n");
10881 /* add to pipeline */
10882 if ( ! gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue) )
10884 debug_warning("failed to add queue\n");
10889 queue_pad = gst_element_get_static_pad(queue, "sink");
10891 if ( GST_PAD_LINK_OK != gst_pad_link(pad, queue_pad) )
10893 debug_warning("failed to link queue\n");
10896 gst_object_unref ( GST_OBJECT(queue_pad) );
10900 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_PAUSED) )
10902 debug_warning("failed to set state PAUSED to queue\n");
10906 /* replace given pad to queue:src */
10907 pad = gst_element_get_static_pad(queue, "src");
10910 debug_warning("failed to get pad from queue\n");
10915 /* check if player can do start continually */
10916 MMPLAYER_CHECK_CMD_IF_EXIT(player);
10918 if(__mmplayer_link_sink(player,pad))
10919 __mmplayer_gst_decode_callback(element, pad, player);
10921 gst_object_unref( GST_OBJECT(element));
10927 item = player->factories;
10928 for(; item != NULL ; item = item->next)
10930 GstElementFactory *factory = GST_ELEMENT_FACTORY(item->data);
10936 /* filtering exclude keyword */
10937 for ( idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++ )
10939 if ( g_strrstr(GST_OBJECT_NAME (factory),
10940 player->ini.exclude_element_keyword[idx] ) )
10942 debug_warning("skipping [%s] by exculde keyword [%s]\n",
10943 GST_OBJECT_NAME (factory),
10944 player->ini.exclude_element_keyword[idx] );
10951 if ( MMPLAYER_IS_RTSP_STREAMING(player) && g_strrstr(GST_OBJECT_NAME (factory), "omx_mpeg4dec"))
10953 // omx decoder can not support mpeg4video data partitioned
10954 // rtsp streaming didn't know mpeg4video data partitioned format
10955 // so, if rtsp playback, player will skip omx_mpeg4dec.
10956 debug_warning("skipping [%s] when rtsp streaming \n",
10957 GST_OBJECT_NAME (factory));
10962 if ( skip ) continue;
10964 /* check factory class for filtering */
10965 klass = gst_element_factory_get_metadata (GST_ELEMENT_FACTORY(factory), GST_ELEMENT_METADATA_KLASS);
10967 /*parsers are not required in case of external feeder*/
10968 if (g_strrstr(klass, "Codec/Parser") && MMPLAYER_IS_ES_BUFF_SRC(player))
10971 /* NOTE : msl don't need to use image plugins.
10972 * So, those plugins should be skipped for error handling.
10974 if ( g_strrstr(klass, "Codec/Decoder/Image") )
10976 debug_log("skipping [%s] by not required\n", GST_OBJECT_NAME (factory));
10980 /* check pad compatability */
10981 for(pads = gst_element_factory_get_static_pad_templates(factory);
10982 pads != NULL; pads=pads->next)
10984 GstStaticPadTemplate *temp1 = pads->data;
10985 GstCaps* static_caps = NULL;
10987 if( temp1->direction != GST_PAD_SINK
10988 || temp1->presence != GST_PAD_ALWAYS)
10991 if ( GST_IS_CAPS( &temp1->static_caps.caps) )
10993 /* using existing caps */
10994 static_caps = gst_caps_ref(temp1->static_caps.caps );
10999 static_caps = gst_caps_from_string ( temp1->static_caps.string );
11002 res = gst_caps_intersect((GstCaps*)caps, static_caps);
11003 gst_caps_unref( static_caps );
11004 static_caps = NULL;
11006 if( res && !gst_caps_is_empty(res) )
11008 GstElement *new_element;
11009 GList *elements = player->parsers;
11010 char *name_template = g_strdup(temp1->name_template);
11011 gchar *name_to_plug = GST_OBJECT_NAME(factory);
11012 gst_caps_unref(res);
11014 /* check ALP Codec can be used or not */
11015 if ((g_strrstr(klass, "Codec/Decoder/Audio")))
11017 /* consider mp3 audio only */
11018 if ( !MMPLAYER_IS_STREAMING(player) && __mmplayer_is_only_mp3_type(player->type) )
11020 /* try to use ALP decoder first instead of selected decoder */
11021 GstElement *element = NULL;
11022 GstElementFactory * element_facory;
11023 gchar *path = NULL;
11024 guint64 data_size = 0;
11025 #define MIN_THRESHOLD_SIZE 320 * 1024 // 320K
11028 mm_attrs_get_string_by_name(player->attrs, "profile_uri", &path);
11030 if (stat(path, &sb) == 0)
11032 data_size = (guint64)sb.st_size;
11034 debug_log("file size : %u", data_size);
11036 if (data_size > MIN_THRESHOLD_SIZE)
11038 debug_log("checking if ALP can be used or not");
11039 element = gst_element_factory_make("omx_mp3dec", "omx mp3 decoder");
11042 /* check availability because multi-instance is not supported */
11043 GstStateChangeReturn ret = gst_element_set_state(element, GST_STATE_READY);
11045 if (ret != GST_STATE_CHANGE_SUCCESS) // use just selected decoder
11047 gst_object_unref (element);
11049 else if (ret == GST_STATE_CHANGE_SUCCESS) // replace facotry to use omx
11052 gst_element_set_state(element, GST_STATE_NULL);
11053 gst_object_unref (element);
11055 element_facory = gst_element_factory_find("omx_mp3dec");
11056 /* replace, otherwise use selected thing instead */
11057 if (element_facory)
11059 factory = element_facory;
11060 name_to_plug = GST_OBJECT_NAME(factory);
11063 /* make parser alp mode */
11064 #ifdef _MM_PLAYER_ALP_PARSER
11065 g_list_foreach (player->parsers, check_name, player);
11072 else if ((g_strrstr(klass, "Codec/Decoder/Video")))
11074 if ( g_strrstr(GST_OBJECT_NAME(factory), "omx_") )
11076 char *env = getenv ("MM_PLAYER_HW_CODEC_DISABLE");
11079 if (strncasecmp(env, "yes", 3) == 0)
11081 debug_log("skipping [%s] by disabled\n", name_to_plug);
11082 MMPLAYER_FREEIF(name_template);
11089 debug_log("found %s to plug\n", name_to_plug);
11091 new_element = gst_element_factory_create(GST_ELEMENT_FACTORY(factory), NULL);
11092 if ( ! new_element )
11094 debug_error("failed to create element [%s]. continue with next.\n",
11095 GST_OBJECT_NAME (factory));
11097 MMPLAYER_FREEIF(name_template);
11102 /* check and skip it if it was already used. Otherwise, it can be an infinite loop
11103 * because parser can accept its own output as input.
11105 if (g_strrstr(klass, "Parser"))
11107 gchar *selected = NULL;
11109 for ( ; elements; elements = g_list_next(elements))
11111 gchar *element_name = elements->data;
11113 if (g_strrstr(element_name, name_to_plug))
11115 debug_log("but, %s already linked, so skipping it\n", name_to_plug);
11122 MMPLAYER_FREEIF(name_template);
11126 selected = g_strdup(name_to_plug);
11127 player->parsers = g_list_append(player->parsers, selected);
11130 /* store specific handles for futher control */
11131 if(g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse"))
11133 /* FIXIT : first value will be overwritten if there's more
11134 * than 1 demuxer/parser
11136 debug_log("plugged element is demuxer. take it\n");
11137 mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
11138 mainbin[MMPLAYER_M_DEMUX].gst = new_element;
11140 /*Added for multi audio support */
11141 if(g_strrstr(klass, "Demux"))
11143 mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
11144 mainbin[MMPLAYER_M_DEMUX_EX].gst = new_element;
11146 /* NOTE : workaround for bug in mpegtsdemux since doesn't emit
11147 no-more-pad signal. this may cause wrong content attributes at PAUSED state
11148 this code should be removed after mpegtsdemux is fixed */
11149 if ( g_strrstr(GST_OBJECT_NAME(factory), "mpegtsdemux") )
11151 debug_warning("force no-more-pad to TRUE since mpegtsdemux os not giving no-more-pad signal. content attributes may wrong");
11152 player->no_more_pad = TRUE;
11155 if (g_strrstr(name_to_plug, "asfdemux")) // to support trust-zone only
11157 g_object_set(mainbin[MMPLAYER_M_DEMUX_EX].gst, "file-location", player->profile.uri,NULL);
11160 else if(g_strrstr(klass, "Decoder") && __mmplayer_link_decoder(player,pad))
11162 if(mainbin[MMPLAYER_M_DEC1].gst == NULL)
11164 debug_log("plugged element is decoder. take it[MMPLAYER_M_DEC1]\n");
11165 mainbin[MMPLAYER_M_DEC1].id = MMPLAYER_M_DEC1;
11166 mainbin[MMPLAYER_M_DEC1].gst = new_element;
11168 else if(mainbin[MMPLAYER_M_DEC2].gst == NULL)
11170 debug_log("plugged element is decoder. take it[MMPLAYER_M_DEC2]\n");
11171 mainbin[MMPLAYER_M_DEC2].id = MMPLAYER_M_DEC2;
11172 mainbin[MMPLAYER_M_DEC2].gst = new_element;
11174 /* NOTE : IF one codec is found, add it to supported_codec and remove from
11175 * missing plugin. Both of them are used to check what's supported codec
11176 * before returning result of play start. And, missing plugin should be
11177 * updated here for multi track files.
11179 if(g_str_has_prefix(mime, "video"))
11181 GstPad *src_pad = NULL;
11182 GstPadTemplate *pad_templ = NULL;
11183 GstCaps *caps = NULL;
11184 gchar *caps_str = NULL;
11186 debug_log("found VIDEO decoder\n");
11187 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
11188 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
11190 src_pad = gst_element_get_static_pad (new_element, "src");
11191 pad_templ = gst_pad_get_pad_template (src_pad);
11192 caps = GST_PAD_TEMPLATE_CAPS(pad_templ);
11194 caps_str = gst_caps_to_string(caps);
11197 MMPLAYER_FREEIF( caps_str );
11198 gst_object_unref (src_pad);
11200 else if (g_str_has_prefix(mime, "audio"))
11202 debug_log("found AUDIO decoder\n");
11203 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
11204 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
11208 if ( ! __mmplayer_close_link(player, pad, new_element,
11209 name_template,gst_element_factory_get_static_pad_templates(factory)) )
11211 MMPLAYER_FREEIF(name_template);
11212 if (player->keep_detecting_vcodec)
11215 /* Link is failed even though a supportable codec is found. */
11216 __mmplayer_check_not_supported_codec(player, klass, mime);
11218 debug_error("failed to call _close_link\n");
11222 MMPLAYER_FREEIF(name_template);
11226 gst_caps_unref(res);
11231 /* There is no available codec. */
11232 __mmplayer_check_not_supported_codec(player, klass, mime);
11240 gst_object_unref( queue );
11243 gst_object_unref( queue_pad );
11246 gst_object_unref ( element );
11253 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
11257 return_val_if_fail(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
11258 return_val_if_fail ( mime, MM_ERROR_INVALID_ARGUMENT );
11260 debug_log("class : %s, mime : %s \n", factory_class, mime );
11262 /* add missing plugin */
11263 /* NOTE : msl should check missing plugin for image mime type.
11264 * Some motion jpeg clips can have playable audio track.
11265 * So, msl have to play audio after displaying popup written video format not supported.
11267 if ( !( player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst ) )
11269 if ( !( player->can_support_codec | player->videodec_linked | player->audiodec_linked ) )
11271 debug_log("not found demuxer\n");
11272 player->not_found_demuxer = TRUE;
11273 player->unlinked_demuxer_mime = g_strdup_printf ( "%s", mime );
11279 if( !g_strrstr(factory_class, "Demuxer"))
11281 if( ( g_str_has_prefix(mime, "video") ) ||( g_str_has_prefix(mime, "image") ) )
11283 debug_log("can support codec=%d, vdec_linked=%d, adec_linked=%d\n",
11284 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
11286 /* check that clip have multi tracks or not */
11287 if ( ( player->can_support_codec & FOUND_PLUGIN_VIDEO ) && ( player->videodec_linked ) )
11289 debug_log("video plugin is already linked\n");
11293 debug_warning("add VIDEO to missing plugin\n");
11294 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
11297 else if ( g_str_has_prefix(mime, "audio") )
11299 if ( ( player->can_support_codec & FOUND_PLUGIN_AUDIO ) && ( player->audiodec_linked ) )
11301 debug_log("audio plugin is already linked\n");
11305 debug_warning("add AUDIO to missing plugin\n");
11306 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
11314 return MM_ERROR_NONE;
11319 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
11321 mm_player_t* player = (mm_player_t*)data;
11325 return_if_fail( player );
11327 /* remove fakesink. */
11328 if ( !__mmplayer_gst_remove_fakesink( player,
11329 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]) )
11331 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
11332 * signaling mechanism ( pad-added, no-more-pad, new-decoded-pad ) from various
11333 * source element are not same. To overcome this situation, this function will called
11334 * several places and several times. Therefore, this is not an error case.
11339 debug_log("pipeline has completely constructed\n");
11341 if (( player->ini.async_start ) &&
11342 ( player->msg_posted == FALSE ) &&
11343 ( player->cmd >= MMPLAYER_COMMAND_START ))
11345 __mmplayer_handle_missed_plugin( player );
11348 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-complete" );
11352 __mmplayer_verify_next_play_path(mm_player_t *player)
11354 MMHandleType attrs = 0;
11355 MMPlayerParseProfile profile;
11356 gint uri_idx = 0, check_cnt = 0;
11358 gint mode = MM_PLAYER_PD_MODE_NONE;
11360 guint num_of_list = 0;
11364 debug_log("checking for gapless play");
11366 if (player->pipeline->textbin)
11368 debug_error("subtitle path is enabled. gapless play is not supported.\n");
11372 attrs = MMPLAYER_GET_ATTRS(player);
11375 debug_error("fail to get attributes.\n");
11379 /* seamless playback is supported in case of audio only */
11380 mm_attrs_get_int_by_name(attrs, "content_video_found", &mode);
11383 debug_log("video found");
11387 if (mm_attrs_get_int_by_name (attrs, "pd_mode", &mode) == MM_ERROR_NONE)
11391 debug_warning("pd mode\n");
11396 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
11398 debug_error("can not get play count\n");
11401 num_of_list = g_list_length(player->uri_info.uri_list);
11403 debug_log("repeat count = %d, num_of_list = %d\n", count, num_of_list);
11405 if ( num_of_list == 0 )
11407 if (mm_attrs_get_string_by_name(player->attrs, "profile_uri", &uri) != MM_ERROR_NONE)
11409 debug_error("can not get profile_uri\n");
11415 debug_error("uri list is empty.\n");
11419 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
11420 debug_log("add original path : %s ", uri);
11426 uri_idx = player->uri_info.uri_idx;
11432 if (check_cnt > num_of_list)
11434 debug_error("there is no valid uri.");
11438 debug_log("uri idx : %d / %d\n", uri_idx, num_of_list);
11440 if ( uri_idx < num_of_list-1 )
11446 if ((count <= 1) && (count != -1))
11448 debug_log("no repeat.");
11451 else if ( count > 1 ) /* decrease play count */
11453 /* we successeded to rewind. update play count and then wait for next EOS */
11456 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
11458 /* commit attribute */
11459 if ( mmf_attrs_commit ( attrs ) )
11461 debug_error("failed to commit attribute\n");
11465 /* count < 0 : repeat continually */
11469 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
11470 debug_log("uri idx : %d, uri = %s\n", uri_idx, uri);
11474 debug_warning("next uri does not exist\n");
11478 if (__mmfplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE)
11480 debug_error("failed to parse profile\n");
11484 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
11485 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP))
11487 debug_warning("uri type is not supported (%d).", profile.uri_type);
11494 player->uri_info.uri_idx = uri_idx;
11495 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
11498 if (mmf_attrs_commit(player->attrs))
11500 debug_error("failed to commit.\n");
11504 debug_log("next uri %s (%d)\n", uri, uri_idx);
11510 debug_error("unable to play next path. EOS will be posted soon.\n");
11515 __mmplayer_initialize_next_play(mm_player_t *player)
11521 player->smooth_streaming = FALSE;
11522 player->videodec_linked = 0;
11523 player->audiodec_linked = 0;
11524 player->videosink_linked = 0;
11525 player->audiosink_linked = 0;
11526 player->textsink_linked = 0;
11527 player->is_external_subtitle_present = FALSE;
11528 player->not_supported_codec = MISSING_PLUGIN_NONE;
11529 player->can_support_codec = FOUND_PLUGIN_NONE;
11530 player->pending_seek.is_pending = FALSE;
11531 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
11532 player->pending_seek.pos = 0;
11533 player->msg_posted = FALSE;
11534 player->has_many_types = FALSE;
11535 player->no_more_pad = FALSE;
11536 player->is_drm_file = FALSE;
11537 player->not_found_demuxer = 0;
11538 player->doing_seek = FALSE;
11539 player->max_audio_channels = 0;
11540 player->is_subtitle_force_drop = FALSE;
11541 player->play_subtitle = FALSE;
11542 player->use_textoverlay = FALSE;
11543 player->adjust_subtitle_pos = 0;
11545 player->updated_bitrate_count = 0;
11546 player->total_bitrate = 0;
11547 player->updated_maximum_bitrate_count = 0;
11548 player->total_maximum_bitrate = 0;
11550 _mmplayer_track_initialize(player);
11552 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++)
11554 player->bitrate[i] = 0;
11555 player->maximum_bitrate[i] = 0;
11558 if (player->v_stream_caps)
11560 gst_caps_unref(player->v_stream_caps);
11561 player->v_stream_caps = NULL;
11564 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
11565 mm_attrs_set_int_by_name(player->attrs, "content_audio_found", 0);
11567 /* clean found parsers */
11568 if (player->parsers)
11570 GList *parsers = player->parsers;
11571 for ( ;parsers ; parsers = g_list_next(parsers))
11573 gchar *name = parsers->data;
11574 MMPLAYER_FREEIF(name);
11576 g_list_free(player->parsers);
11577 player->parsers = NULL;
11580 /* clean found audio decoders */
11581 if (player->audio_decoders)
11583 GList *a_dec = player->audio_decoders;
11584 for ( ;a_dec ; a_dec = g_list_next(a_dec))
11586 gchar *name = a_dec->data;
11587 MMPLAYER_FREEIF(name);
11589 g_list_free(player->audio_decoders);
11590 player->audio_decoders = NULL;
11597 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
11599 MMPlayerGstElement *mainbin = NULL;
11600 MMMessageParamType msg_param = {0,};
11601 GstElement *element = NULL;
11602 MMHandleType attrs = 0;
11604 enum MainElementID elemId = MMPLAYER_M_NUM;
11608 if ((player == NULL) ||
11609 (player->pipeline == NULL) ||
11610 (player->pipeline->mainbin == NULL))
11612 debug_error("player is null.\n");
11616 mainbin = player->pipeline->mainbin;
11617 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
11619 attrs = MMPLAYER_GET_ATTRS(player);
11622 debug_error("fail to get attributes.\n");
11626 /* Initialize Player values */
11627 __mmplayer_initialize_next_play(player);
11629 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
11631 if (__mmfplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE)
11633 debug_error("failed to parse profile\n");
11634 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
11638 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
11639 (MMPLAYER_URL_HAS_HLS_SUFFIX(player)))
11641 debug_error("it's dash or hls. not support.");
11642 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
11647 switch ( player->profile.uri_type )
11650 case MM_PLAYER_URI_TYPE_FILE:
11652 debug_log("using filesrc for 'file://' handler.\n");
11654 element = gst_element_factory_make("filesrc", "source");
11658 debug_error("failed to create filesrc\n");
11662 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
11665 case MM_PLAYER_URI_TYPE_URL_HTTP:
11667 gchar *user_agent, *proxy, *cookies, **cookie_list;
11668 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
11669 user_agent = proxy = cookies = NULL;
11670 cookie_list = NULL;
11672 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
11675 debug_error("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
11678 debug_log("using http streamming source [%s].\n", player->ini.httpsrc_element);
11680 /* get attribute */
11681 mm_attrs_get_string_by_name ( attrs, "streaming_cookie", &cookies );
11682 mm_attrs_get_string_by_name ( attrs, "streaming_user_agent", &user_agent );
11683 mm_attrs_get_string_by_name ( attrs, "streaming_proxy", &proxy );
11684 mm_attrs_get_int_by_name ( attrs, "streaming_timeout", &http_timeout );
11686 if ((http_timeout == DEFAULT_HTTP_TIMEOUT) &&
11687 (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT))
11689 debug_log("get timeout from ini\n");
11690 http_timeout = player->ini.http_timeout;
11693 /* get attribute */
11694 secure_debug_log("location : %s\n", player->profile.uri);
11695 secure_debug_log("cookies : %s\n", cookies);
11696 secure_debug_log("proxy : %s\n", proxy);
11697 secure_debug_log("user_agent : %s\n", user_agent);
11698 debug_log("timeout : %d\n", http_timeout);
11700 /* setting property to streaming source */
11701 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
11702 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
11703 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
11705 /* check if prosy is vailid or not */
11706 if ( util_check_valid_url ( proxy ) )
11707 g_object_set(G_OBJECT(element), "proxy", proxy, NULL);
11708 /* parsing cookies */
11709 if ( ( cookie_list = util_get_cookie_list ((const char*)cookies) ) )
11710 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
11712 g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL);
11716 debug_error("not support uri type %d\n", player->profile.uri_type);
11722 debug_error("no source element was created.\n");
11726 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE)
11728 debug_error("failed to add source element to pipeline\n");
11729 gst_object_unref(GST_OBJECT(element));
11734 /* take source element */
11735 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
11736 mainbin[MMPLAYER_M_SRC].gst = element;
11740 if (MMPLAYER_IS_HTTP_STREAMING(player))
11742 if (player->streamer == NULL)
11744 player->streamer = __mm_player_streaming_create();
11745 __mm_player_streaming_initialize(player->streamer);
11748 elemId = MMPLAYER_M_TYPEFIND;
11749 element = gst_element_factory_make("typefind", "typefinder");
11750 MMPLAYER_SIGNAL_CONNECT( player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
11751 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player );
11755 elemId = MMPLAYER_M_AUTOPLUG;
11756 element = __mmplayer_create_decodebin(player);
11759 /* check autoplug element is OK */
11762 debug_error("can not create element (%d)\n", elemId);
11766 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE)
11768 debug_error("failed to add sinkbin to pipeline\n");
11769 gst_object_unref(GST_OBJECT(element));
11774 mainbin[elemId].id = elemId;
11775 mainbin[elemId].gst = element;
11777 if ( gst_element_link (mainbin[MMPLAYER_M_SRC].gst, mainbin[elemId].gst) == FALSE )
11779 debug_error("Failed to link src - autoplug (or typefind)\n");
11783 if (gst_element_set_state (mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE)
11785 debug_error("Failed to change state of src element\n");
11789 if (!MMPLAYER_IS_HTTP_STREAMING(player))
11791 if (gst_element_set_state (mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE)
11793 debug_error("Failed to change state of decodebin\n");
11799 if (gst_element_set_state (mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE)
11801 debug_error("Failed to change state of src element\n");
11806 player->gapless.stream_changed = TRUE;
11807 player->gapless.running = TRUE;
11812 MMPLAYER_PLAYBACK_UNLOCK(player);
11814 if (!player->msg_posted)
11816 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
11817 player->msg_posted = TRUE;
11823 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
11825 mm_player_selector_t *selector = &player->selector[type];
11826 MMPlayerGstElement *sinkbin = NULL;
11827 enum MainElementID selectorId = MMPLAYER_M_NUM;
11828 enum MainElementID sinkId = MMPLAYER_M_NUM;
11829 GstPad *srcpad = NULL;
11830 GstPad *sinkpad = NULL;
11833 return_val_if_fail (player, FALSE);
11835 debug_log("type %d", type);
11839 case MM_PLAYER_TRACK_TYPE_AUDIO:
11840 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
11841 sinkId = MMPLAYER_A_BIN;
11842 sinkbin = player->pipeline->audiobin;
11844 case MM_PLAYER_TRACK_TYPE_TEXT:
11845 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
11846 sinkId = MMPLAYER_T_BIN;
11847 sinkbin = player->pipeline->textbin;
11850 debug_error("requested type is not supportable");
11855 if (player->pipeline->mainbin[selectorId].gst)
11859 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
11861 if (selector->event_probe_id != 0)
11862 gst_pad_remove_probe (srcpad, selector->event_probe_id);
11863 selector->event_probe_id = 0;
11865 if ((sinkbin) && (sinkbin[sinkId].gst))
11867 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
11869 if (srcpad && sinkpad)
11871 /* after getting drained signal there is no data flows, so no need to do pad_block */
11872 debug_log("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
11873 gst_pad_unlink (srcpad, sinkpad);
11876 gst_object_unref (sinkpad);
11879 gst_object_unref (srcpad);
11882 debug_log("selector release");
11884 /* release and unref requests pad from the selector */
11885 for (n = 0; n < selector->channels->len; n++)
11887 GstPad *sinkpad = g_ptr_array_index (selector->channels, n);
11888 gst_element_release_request_pad ((player->pipeline->mainbin[selectorId].gst), sinkpad);
11890 g_ptr_array_set_size (selector->channels, 0);
11892 gst_element_set_state (player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
11893 gst_bin_remove (GST_BIN_CAST (player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
11895 player->pipeline->mainbin[selectorId].gst = NULL;
11903 __mmplayer_deactivate_old_path(mm_player_t *player)
11906 return_if_fail ( player );
11908 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
11909 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT)))
11911 debug_error("deactivate selector error");
11915 _mmplayer_track_destroy(player);
11916 __mmplayer_release_signal_connection( player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG );
11918 if (player->streamer)
11920 __mm_player_streaming_deinitialize (player->streamer);
11921 __mm_player_streaming_destroy(player->streamer);
11922 player->streamer = NULL;
11925 MMPLAYER_PLAYBACK_LOCK(player);
11926 g_cond_signal( &player->next_play_thread_cond );
11933 if (!player->msg_posted)
11935 MMMessageParamType msg = {0,};
11938 msg.code = MM_ERROR_PLAYER_INTERNAL;
11939 debug_error("next_uri_play> deactivate error");
11941 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
11942 player->msg_posted = TRUE;
11947 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
11949 int result = MM_ERROR_NONE;
11950 mm_player_t* player = (mm_player_t*) hplayer;
11953 return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11955 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
11956 if (mmf_attrs_commit(player->attrs))
11958 debug_error("failed to commit the original uri.\n");
11959 result = MM_ERROR_PLAYER_INTERNAL;
11963 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
11965 debug_error("failed to add the original uri in the uri list.\n");
11973 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
11975 mm_player_t* player = (mm_player_t*) hplayer;
11976 guint num_of_list = 0;
11980 return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11981 return_val_if_fail (uri, MM_ERROR_INVALID_ARGUMENT);
11983 if (player->pipeline && player->pipeline->textbin)
11985 debug_error("subtitle path is enabled.\n");
11986 return MM_ERROR_PLAYER_INVALID_STATE;
11989 num_of_list = g_list_length(player->uri_info.uri_list);
11991 if (is_first_path == TRUE)
11993 if (num_of_list == 0)
11995 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
11996 debug_log("add original path : %s", uri);
12000 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
12001 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
12003 debug_log("change original path : %s", uri);
12008 if (num_of_list == 0)
12010 MMHandleType attrs = 0;
12011 char *original_uri = NULL;
12013 attrs = MMPLAYER_GET_ATTRS(player);
12016 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
12020 debug_error("there is no original uri.");
12021 return MM_ERROR_PLAYER_INVALID_STATE;
12024 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
12025 player->uri_info.uri_idx = 0;
12027 debug_log("add original path at first : %s (%d)", original_uri);
12031 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
12032 debug_log("add new path : %s (total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
12036 return MM_ERROR_NONE;
12039 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
12041 mm_player_t* player = (mm_player_t*) hplayer;
12042 char *next_uri = NULL;
12043 guint num_of_list = 0;
12046 return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12048 num_of_list = g_list_length(player->uri_info.uri_list);
12050 if (num_of_list > 0)
12052 gint uri_idx = player->uri_info.uri_idx;
12054 if ( uri_idx < num_of_list-1 )
12059 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
12060 debug_error("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
12062 *uri = g_strdup(next_uri);
12066 return MM_ERROR_NONE;
12070 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad,
12071 GstCaps *caps, gpointer data)
12073 mm_player_t* player = (mm_player_t*)data;
12074 const gchar* klass = NULL;
12075 const gchar* mime = NULL;
12076 gchar* caps_str = NULL;
12078 klass = gst_element_factory_get_metadata (gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
12079 mime = gst_structure_get_name (gst_caps_get_structure(caps, 0));
12080 caps_str = gst_caps_to_string(caps);
12082 debug_warning("unknown type of caps : %s from %s",
12083 caps_str, GST_ELEMENT_NAME (elem));
12085 MMPLAYER_FREEIF(caps_str);
12087 /* There is no available codec. */
12088 __mmplayer_check_not_supported_codec (player, klass, mime);
12092 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad,
12093 GstCaps * caps, gpointer data)
12095 mm_player_t* player = (mm_player_t*)data;
12096 const char* mime = NULL;
12097 gboolean ret = TRUE;
12099 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
12100 mime = gst_structure_get_name (gst_caps_get_structure(caps, 0));
12102 if (g_str_has_prefix(mime, "audio")) {
12103 GstStructure* caps_structure = NULL;
12104 gint samplerate = 0;
12106 gchar *caps_str = NULL;
12108 caps_structure = gst_caps_get_structure(caps, 0);
12109 gst_structure_get_int (caps_structure, "rate", &samplerate);
12110 gst_structure_get_int (caps_structure, "channels", &channels);
12112 if ( (channels > 0 && samplerate == 0)) {
12113 debug_log("exclude audio...");
12117 caps_str = gst_caps_to_string(caps);
12118 /* set it directly because not sent by TAG */
12119 if (g_strrstr(caps_str, "mobile-xmf")) {
12120 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
12122 MMPLAYER_FREEIF (caps_str);
12123 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
12124 debug_log("already video linked");
12127 debug_log("found new stream");
12134 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad,
12135 GstCaps* caps, GstElementFactory* factory, gpointer data)
12137 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
12138 We are defining our own and will be removed when it actually exposed */
12140 GST_AUTOPLUG_SELECT_TRY,
12141 GST_AUTOPLUG_SELECT_EXPOSE,
12142 GST_AUTOPLUG_SELECT_SKIP
12143 } GstAutoplugSelectResult;
12145 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
12146 mm_player_t* player = (mm_player_t*)data;
12148 gchar* factory_name = NULL;
12149 gchar* caps_str = NULL;
12150 const gchar* klass = NULL;
12153 factory_name = GST_OBJECT_NAME (factory);
12154 klass = gst_element_factory_get_metadata (factory, GST_ELEMENT_METADATA_KLASS);
12155 caps_str = gst_caps_to_string(caps);
12157 // debug_log("found new element [%s] to link for caps [%s]", factory_name, caps_str);
12158 debug_log("found new element [%s] to link", factory_name);
12160 /* store type string */
12161 if (player->type == NULL)
12163 player->type = gst_caps_to_string(caps);
12164 __mmplayer_update_content_type_info(player);
12167 /* To support evasimagesink, omx is excluded temporarily*/
12168 int surface_type = 0;
12169 mm_attrs_get_int_by_name(player->attrs, "display_surface_client_type", &surface_type);
12170 if (surface_type == MM_DISPLAY_SURFACE_NULL)
12171 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
12172 debug_log("check display surface type attribute: %d", surface_type);
12173 if (surface_type == MM_DISPLAY_SURFACE_EVAS && strstr(factory_name, "omx"))
12175 debug_warning("skipping [%s] for supporting evasimagesink temporarily.\n", factory_name);
12176 result = GST_AUTOPLUG_SELECT_SKIP;
12180 /* filtering exclude keyword */
12181 for ( idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++ )
12183 if ( strstr(factory_name, player->ini.exclude_element_keyword[idx] ) )
12185 debug_warning("skipping [%s] by exculde keyword [%s]\n",
12186 factory_name, player->ini.exclude_element_keyword[idx] );
12188 // NOTE : does we need to check n_value against the number of item selected?
12189 result = GST_AUTOPLUG_SELECT_SKIP;
12194 /* check factory class for filtering */
12195 /* NOTE : msl don't need to use image plugins.
12196 * So, those plugins should be skipped for error handling.
12198 if (g_strrstr(klass, "Codec/Decoder/Image"))
12200 debug_log("skipping [%s] by not required\n", factory_name);
12201 result = GST_AUTOPLUG_SELECT_SKIP;
12205 if ((MMPLAYER_IS_ES_BUFF_SRC(player)) &&
12206 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser"))))
12208 // TO CHECK : subtitle if needed, add subparse exception.
12209 debug_log("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
12210 result = GST_AUTOPLUG_SELECT_SKIP;
12214 if (g_strrstr(factory_name, "mpegpsdemux"))
12216 debug_log("skipping PS container - not support\n");
12217 result = GST_AUTOPLUG_SELECT_SKIP;
12221 if (g_strrstr(factory_name, "mssdemux"))
12222 player->smooth_streaming = TRUE;
12224 /* check ALP Codec can be used or not */
12225 if ((g_strrstr(klass, "Codec/Decoder/Audio")))
12227 GstStructure* str = NULL;
12230 str = gst_caps_get_structure( caps, 0 );
12233 gst_structure_get_int (str, "channels", &channels);
12235 debug_log ("check audio ch : %d %d\n", player->max_audio_channels, channels);
12236 if (player->max_audio_channels < channels)
12238 player->max_audio_channels = channels;
12242 if (!player->audiodec_linked)
12244 /* set stream information */
12245 __mmplayer_set_audio_attrs (player, caps);
12248 else if ((g_strrstr(klass, "Codec/Decoder/Video")))
12250 if (g_strrstr(factory_name, "omx_"))
12252 char *env = getenv ("MM_PLAYER_HW_CODEC_DISABLE");
12255 if (strncasecmp(env, "yes", 3) == 0)
12257 debug_log ("skipping [%s] by disabled\n", factory_name);
12258 result = GST_AUTOPLUG_SELECT_SKIP;
12265 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
12266 (g_strrstr(klass, "Codec/Decoder/Video")))
12270 GstStructure *str = NULL;
12271 mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &stype);
12273 /* don't make video because of not required */
12274 if (stype == MM_DISPLAY_SURFACE_NULL)
12276 debug_log ("no video because it's not required. -> return expose");
12277 if (player->set_mode.media_packet_video_stream == FALSE)
12279 result = GST_AUTOPLUG_SELECT_EXPOSE;
12284 /* get w/h for omx state-tune */
12285 str = gst_caps_get_structure (caps, 0);
12286 gst_structure_get_int (str, "width", &width);
12289 if (player->v_stream_caps) {
12290 gst_caps_unref(player->v_stream_caps);
12291 player->v_stream_caps = NULL;
12294 player->v_stream_caps = gst_caps_copy(caps);
12295 debug_log ("take caps for video state tune");
12296 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
12300 if (g_strrstr(klass, "Decoder"))
12302 const char* mime = NULL;
12303 mime = gst_structure_get_name (gst_caps_get_structure(caps, 0));
12305 if (g_str_has_prefix(mime, "video"))
12307 // __mmplayer_check_video_zero_cpoy(player, factory);
12309 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
12310 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
12312 player->videodec_linked = 1;
12314 else if(g_str_has_prefix(mime, "audio"))
12316 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
12317 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
12319 player->audiodec_linked = 1;
12324 MMPLAYER_FREEIF(caps_str);
12331 static GValueArray*
12332 __mmplayer_gst_decode_autoplug_factories(GstElement *bin, GstPad* pad,
12333 GstCaps * caps, gpointer data)
12335 //mm_player_t* player = (mm_player_t*)data;
12337 debug_log("decodebin is requesting factories for caps [%s] from element[%s]",
12338 gst_caps_to_string(caps),
12339 GST_ELEMENT_NAME(GST_PAD_PARENT(pad)));
12346 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad,
12347 gpointer data) // @
12349 //mm_player_t* player = (mm_player_t*)data;
12350 GstCaps* caps = NULL;
12352 debug_log("[Decodebin2] pad-removed signal\n");
12354 caps = gst_pad_query_caps(new_pad, NULL);
12357 gchar* caps_str = NULL;
12358 caps_str = gst_caps_to_string(caps);
12360 debug_log("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem) );
12362 MMPLAYER_FREEIF(caps_str);
12367 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
12369 mm_player_t* player = (mm_player_t*)data;
12372 return_if_fail ( player );
12374 debug_log("__mmplayer_gst_decode_drained");
12376 if (player->use_deinterleave == TRUE)
12378 debug_log("group playing mode.");
12382 if (!g_mutex_trylock(&player->cmd_lock))
12384 debug_warning("Fail to get cmd lock");
12388 if (!__mmplayer_verify_next_play_path(player))
12390 debug_log("decoding is finished.");
12391 player->gapless.running = FALSE;
12392 player->gapless.start_time = 0;
12393 g_mutex_unlock(&player->cmd_lock);
12397 player->gapless.reconfigure = TRUE;
12399 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
12400 __mmplayer_deactivate_old_path(player);
12402 g_mutex_unlock(&player->cmd_lock);
12408 __mmplayer_gst_element_added (GstElement *bin, GstElement *element, gpointer data)
12410 mm_player_t* player = (mm_player_t*)data;
12411 const gchar* klass = NULL;
12412 gchar* factory_name = NULL;
12414 klass = gst_element_factory_get_metadata (gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
12415 factory_name = GST_OBJECT_NAME (gst_element_get_factory(element));
12417 debug_log("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
12419 if (__mmplayer_add_dump_buffer_probe(player, element))
12420 debug_log("add buffer probe");
12423 if (g_strrstr(klass, "Codec/Decoder/Audio"))
12425 gchar* selected = NULL;
12426 selected = g_strdup( GST_ELEMENT_NAME(element));
12427 player->audio_decoders = g_list_append (player->audio_decoders, selected);
12431 if (g_strrstr(klass, "Parser"))
12433 gchar* selected = NULL;
12435 selected = g_strdup (factory_name);
12436 player->parsers = g_list_append (player->parsers, selected);
12439 if ((g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) && !(g_strrstr(klass, "Adaptive")))
12441 /* FIXIT : first value will be overwritten if there's more
12442 * than 1 demuxer/parser
12445 //debug_log ("plugged element is demuxer. take it\n");
12446 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
12447 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
12449 /*Added for multi audio support */ // Q. del?
12450 if (g_strrstr(klass, "Demux"))
12452 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
12453 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].gst = element;
12457 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux"))
12459 int surface_type = 0;
12461 mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &surface_type);
12463 #if 0 // this is for 0.10 plugin with downstream modification
12464 /* playback protection if drm file */
12465 if (player->use_video_stream || surface_type == MM_DISPLAY_SURFACE_EVAS || surface_type == MM_DISPLAY_SURFACE_X_EXT)
12467 debug_log("playback can be protected if playready drm");
12468 g_object_set (G_OBJECT(element), "playback-protection", TRUE, NULL);
12473 // to support trust-zone only
12474 if (g_strrstr(factory_name, "asfdemux"))
12476 debug_log ("set file-location %s\n", player->profile.uri);
12477 g_object_set (G_OBJECT(element), "file-location", player->profile.uri, NULL);
12479 if (player->video_hub_download_mode == TRUE)
12481 g_object_set (G_OBJECT(element), "downloading-mode", player->video_hub_download_mode, NULL);
12484 else if (g_strrstr(factory_name, "legacyh264parse"))
12486 debug_log ("[%s] output-format to legacyh264parse\n", "mssdemux");
12487 g_object_set (G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
12489 else if (g_strrstr(factory_name, "mpegaudioparse"))
12491 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
12492 (__mmplayer_is_only_mp3_type(player->type)))
12494 debug_log ("[mpegaudioparse] set streaming pull mode.");
12495 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
12498 else if (g_strrstr(factory_name, "omx"))
12500 if (g_strrstr(klass, "Codec/Decoder/Video"))
12502 gboolean ret = FALSE;
12504 if (player->v_stream_caps != NULL)
12506 GstPad *pad = gst_element_get_static_pad(element, "sink");
12510 ret = gst_pad_set_caps(pad, player->v_stream_caps);
12511 debug_log("found omx decoder, setting gst_pad_set_caps for omx (ret:%d)", ret);
12512 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
12513 gst_object_unref (pad);
12516 g_object_set (G_OBJECT(element), "state-tuning", TRUE, NULL);
12518 #ifdef _MM_PLAYER_ALP_PARSER
12519 if (g_strrstr(factory_name, "omx_mp3dec"))
12521 g_list_foreach (player->parsers, check_name, player);
12524 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
12527 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
12528 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue")))
12530 debug_log ("plugged element is multiqueue. take it\n");
12532 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
12533 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
12535 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
12536 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)))
12538 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
12539 __mm_player_streaming_set_multiqueue(player->streamer,
12542 player->ini.http_buffering_time,
12544 player->ini.http_buffering_limit);
12546 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
12550 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-added" );
12554 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player)
12557 return_val_if_fail ( player, FALSE );
12559 if ( MMPLAYER_IS_STREAMING(player) )
12562 /* This callback can be set to music player only. */
12563 if((player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO)
12565 debug_warning("audio callback is not supported for video");
12569 if (player->audio_stream_cb)
12572 GstPad *pad = NULL;
12574 pad = gst_element_get_static_pad (player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
12578 debug_error("failed to get sink pad from audiosink to probe data\n");
12581 player->audio_cb_probe_id = gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER,
12582 __mmplayer_audio_stream_probe, player, NULL);
12584 gst_object_unref (pad);
12591 debug_error("There is no audio callback to configure.\n");
12601 __mmplayer_init_factories(mm_player_t* player) // @
12603 return_if_fail ( player );
12605 player->factories = gst_registry_feature_filter(gst_registry_get(),
12606 (GstPluginFeatureFilter)__mmplayer_feature_filter, FALSE, NULL);
12607 player->factories = g_list_sort(player->factories, (GCompareFunc)util_factory_rank_compare);
12611 __mmplayer_release_factories(mm_player_t* player) // @
12614 return_if_fail ( player );
12616 if (player->factories)
12618 gst_plugin_feature_list_free (player->factories);
12619 player->factories = NULL;
12626 __mmplayer_release_misc(mm_player_t* player)
12629 gboolean cur_mode = player->set_mode.rich_audio;
12632 return_if_fail ( player );
12634 player->use_video_stream = FALSE;
12635 player->video_stream_cb = NULL;
12636 player->video_stream_cb_user_param = NULL;
12638 player->audio_stream_cb = NULL;
12639 player->audio_stream_render_cb_ex = NULL;
12640 player->audio_stream_cb_user_param = NULL;
12641 player->audio_stream_sink_sync = false;
12643 player->video_stream_changed_cb = NULL;
12644 player->video_stream_changed_cb_user_param = NULL;
12646 player->audio_stream_changed_cb = NULL;
12647 player->audio_stream_changed_cb_user_param = NULL;
12649 player->sent_bos = FALSE;
12650 player->playback_rate = DEFAULT_PLAYBACK_RATE;
12652 player->doing_seek = FALSE;
12654 player->updated_bitrate_count = 0;
12655 player->total_bitrate = 0;
12656 player->updated_maximum_bitrate_count = 0;
12657 player->total_maximum_bitrate = 0;
12659 player->not_found_demuxer = 0;
12661 player->last_position = 0;
12662 player->duration = 0;
12663 player->http_content_size = 0;
12664 player->not_supported_codec = MISSING_PLUGIN_NONE;
12665 player->can_support_codec = FOUND_PLUGIN_NONE;
12666 player->pending_seek.is_pending = FALSE;
12667 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
12668 player->pending_seek.pos = 0;
12669 player->msg_posted = FALSE;
12670 player->has_many_types = FALSE;
12671 player->is_drm_file = FALSE;
12672 player->max_audio_channels = 0;
12673 player->video_share_api_delta = 0;
12674 player->video_share_clock_delta = 0;
12675 player->sound_focus.keep_last_pos = FALSE;
12676 player->sound_focus.acquired = FALSE;
12677 player->is_subtitle_force_drop = FALSE;
12678 player->play_subtitle = FALSE;
12679 player->use_textoverlay = FALSE;
12680 player->adjust_subtitle_pos = 0;
12681 player->last_multiwin_status = FALSE;
12682 player->has_closed_caption = FALSE;
12683 player->set_mode.media_packet_video_stream = FALSE;
12684 memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
12686 player->set_mode.rich_audio = cur_mode;
12688 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++)
12690 player->bitrate[i] = 0;
12691 player->maximum_bitrate[i] = 0;
12694 /* remove media stream cb (appsrc cb) */
12695 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++)
12697 player->media_stream_buffer_status_cb[i] = NULL;
12698 player->media_stream_seek_data_cb[i] = NULL;
12701 /* free memory related to audio effect */
12702 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
12704 if (player->state_tune_caps)
12706 gst_caps_unref(player->state_tune_caps);
12707 player->state_tune_caps = NULL;
12710 if (player->video_cb_probe_id)
12712 GstPad *pad = NULL;
12714 pad = gst_element_get_static_pad (player->video_fakesink, "sink");
12717 debug_log("release video probe\n");
12719 /* release audio callback */
12720 gst_pad_remove_probe (pad, player->video_cb_probe_id);
12721 player->video_cb_probe_id = 0;
12722 player->video_stream_cb = NULL;
12723 player->video_stream_cb_user_param = NULL;
12731 __mmplayer_release_misc_post(mm_player_t* player)
12733 char *original_uri = NULL;
12736 /* player->pipeline is already released before. */
12738 return_if_fail ( player );
12740 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
12741 mm_attrs_set_int_by_name(player->attrs, "content_audio_found", 0);
12743 /* clean found parsers */
12744 if (player->parsers)
12746 GList *parsers = player->parsers;
12747 for ( ;parsers ; parsers = g_list_next(parsers))
12749 gchar *name = parsers->data;
12750 MMPLAYER_FREEIF(name);
12752 g_list_free(player->parsers);
12753 player->parsers = NULL;
12756 /* clean found audio decoders */
12757 if (player->audio_decoders)
12759 GList *a_dec = player->audio_decoders;
12760 for ( ;a_dec ; a_dec = g_list_next(a_dec))
12762 gchar *name = a_dec->data;
12763 MMPLAYER_FREEIF(name);
12765 g_list_free(player->audio_decoders);
12766 player->audio_decoders = NULL;
12769 /* clean the uri list except original uri */
12770 if (player->uri_info.uri_list)
12772 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
12776 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
12777 debug_log("restore original uri = %s\n", original_uri);
12779 if (mmf_attrs_commit(player->attrs))
12781 debug_error("failed to commit the original uri.\n");
12785 GList *uri_list = player->uri_info.uri_list;
12786 for ( ;uri_list ; uri_list = g_list_next(uri_list))
12788 gchar *uri = uri_list->data;
12789 MMPLAYER_FREEIF(uri);
12791 g_list_free(player->uri_info.uri_list);
12792 player->uri_info.uri_list = NULL;
12795 player->uri_info.uri_idx = 0;
12799 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name)
12801 GstElement *element = NULL;
12804 debug_log("creating %s to plug\n", name);
12806 element = gst_element_factory_make(name, NULL);
12809 debug_error("failed to create queue\n");
12813 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(element, GST_STATE_READY) )
12815 debug_error("failed to set state READY to %s\n", name);
12816 gst_object_unref (element);
12820 if ( ! gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), element))
12822 debug_error("failed to add %s\n", name);
12823 gst_object_unref (element);
12827 sinkpad = gst_element_get_static_pad(element, "sink");
12829 if ( GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad) )
12831 debug_error("failed to link %s\n", name);
12832 gst_object_unref (sinkpad);
12833 gst_object_unref (element);
12837 debug_log("linked %s to pipeline successfully\n", name);
12839 gst_object_unref (sinkpad);
12845 __mmplayer_close_link(mm_player_t* player, GstPad *srcpad, GstElement *sinkelement,
12846 const char *padname, const GList *templlist)
12848 GstPad *pad = NULL;
12849 gboolean has_dynamic_pads = FALSE;
12850 gboolean has_many_types = FALSE;
12851 const char *klass = NULL;
12852 GstStaticPadTemplate *padtemplate = NULL;
12853 GstElementFactory *factory = NULL;
12854 GstElement* queue = NULL;
12855 GstElement* parser = NULL;
12856 GstPad *pssrcpad = NULL;
12857 GstPad *qsrcpad = NULL, *qsinkpad = NULL;
12858 MMPlayerGstElement *mainbin = NULL;
12859 GstStructure* str = NULL;
12860 GstCaps* srccaps = NULL;
12861 GstState target_state = GST_STATE_READY;
12862 gboolean isvideo_decoder = FALSE;
12863 guint q_max_size_time = 0;
12867 return_val_if_fail ( player &&
12868 player->pipeline &&
12869 player->pipeline->mainbin,
12872 mainbin = player->pipeline->mainbin;
12874 debug_log("plugging pad %s:%s to newly create %s:%s\n",
12875 GST_ELEMENT_NAME( GST_PAD_PARENT ( srcpad ) ),
12876 GST_PAD_NAME( srcpad ),
12877 GST_ELEMENT_NAME( sinkelement ),
12880 factory = gst_element_get_factory(sinkelement);
12881 klass = gst_element_factory_get_metadata (factory, GST_ELEMENT_METADATA_KLASS);
12883 /* check if player can do start continually */
12884 MMPLAYER_CHECK_CMD_IF_EXIT(player);
12886 /* need it to warm up omx before linking to pipeline */
12887 if (g_strrstr(GST_ELEMENT_NAME( GST_PAD_PARENT ( srcpad ) ), "demux"))
12889 debug_log("get demux caps.\n");
12890 if (player->state_tune_caps)
12892 gst_caps_unref(player->state_tune_caps);
12893 player->state_tune_caps = NULL;
12895 player->state_tune_caps = gst_caps_copy(gst_pad_get_current_caps(srcpad));
12898 /* NOTE : OMX Codec can check if resource is available or not at this state. */
12899 if (g_strrstr(GST_ELEMENT_NAME(sinkelement), "omx"))
12901 if (player->state_tune_caps != NULL)
12903 debug_log("set demux's caps to omx codec if resource is available");
12904 if (gst_pad_set_caps(gst_element_get_static_pad(sinkelement, "sink"), player->state_tune_caps))
12906 target_state = GST_STATE_PAUSED;
12907 isvideo_decoder = TRUE;
12908 g_object_set(G_OBJECT(sinkelement), "state-tuning", TRUE, NULL);
12912 debug_warning("failed to set caps for state tuning");
12915 gst_caps_unref(player->state_tune_caps);
12916 player->state_tune_caps = NULL;
12919 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkelement, target_state) )
12921 debug_error("failed to set %d state to %s\n", target_state, GST_ELEMENT_NAME( sinkelement ));
12922 if (isvideo_decoder)
12924 gst_element_set_state(sinkelement, GST_STATE_NULL);
12925 gst_object_unref(G_OBJECT(sinkelement));
12926 player->keep_detecting_vcodec = TRUE;
12931 /* add to pipeline */
12932 if ( ! gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), sinkelement) )
12934 debug_error("failed to add %s to mainbin\n", GST_ELEMENT_NAME( sinkelement ));
12938 debug_log("element klass : %s\n", klass);
12940 /* added to support multi track files */
12941 /* only decoder case and any of the video/audio still need to link*/
12942 if(g_strrstr(klass, "Decoder") && __mmplayer_link_decoder(player,srcpad))
12944 gchar *name = g_strdup(GST_ELEMENT_NAME( GST_PAD_PARENT ( srcpad )));
12946 if (g_strrstr(name, "mpegtsdemux")|| g_strrstr(name, "mssdemux"))
12948 gchar *src_demux_caps_str = NULL;
12949 gchar *needed_parser = NULL;
12950 GstCaps *src_demux_caps = NULL;
12951 gboolean smooth_streaming = FALSE;
12953 src_demux_caps = gst_pad_query_caps(srcpad, NULL);
12954 src_demux_caps_str = gst_caps_to_string(src_demux_caps);
12956 gst_caps_unref(src_demux_caps);
12958 if (g_strrstr(src_demux_caps_str, "video/x-h264"))
12960 if (g_strrstr(name, "mssdemux"))
12962 needed_parser = g_strdup("legacyh264parse");
12963 smooth_streaming = TRUE;
12967 needed_parser = g_strdup("h264parse");
12970 else if (g_strrstr(src_demux_caps_str, "video/mpeg"))
12972 needed_parser = g_strdup("mpeg4videoparse");
12974 MMPLAYER_FREEIF(src_demux_caps_str);
12978 parser = __mmplayer_element_create_and_link(player, srcpad, needed_parser);
12979 MMPLAYER_FREEIF(needed_parser);
12983 debug_error("failed to create parser\n");
12987 if (smooth_streaming)
12989 g_object_set (parser, "output-format", 1, NULL); /* NALU/Byte Stream format */
12992 /* update srcpad if parser is created */
12993 pssrcpad = gst_element_get_static_pad(parser, "src");
12998 MMPLAYER_FREEIF(name);
13000 queue = __mmplayer_element_create_and_link(player, srcpad, "queue"); // parser - queue or demuxer - queue
13003 debug_error("failed to create queue\n");
13007 /* update srcpad to link with decoder */
13008 qsrcpad = gst_element_get_static_pad(queue, "src");
13011 q_max_size_time = GST_QUEUE_DEFAULT_TIME;
13013 /* assigning queue handle for futher manipulation purpose */
13014 /* FIXIT : make it some kind of list so that msl can support more then two stream (text, data, etc...) */
13015 if(mainbin[MMPLAYER_M_Q1].gst == NULL)
13017 mainbin[MMPLAYER_M_Q1].id = MMPLAYER_M_Q1;
13018 mainbin[MMPLAYER_M_Q1].gst = queue;
13020 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_SS)
13022 g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q1].gst), "max-size-time", 0 , NULL);
13023 g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q1].gst), "max-size-buffers", 2, NULL);
13024 g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q1].gst), "max-size-bytes", 0, NULL);
13028 if (!MMPLAYER_IS_RTSP_STREAMING(player))
13029 g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q1].gst), "max-size-time", q_max_size_time * GST_SECOND, NULL);
13032 else if(mainbin[MMPLAYER_M_Q2].gst == NULL)
13034 mainbin[MMPLAYER_M_Q2].id = MMPLAYER_M_Q2;
13035 mainbin[MMPLAYER_M_Q2].gst = queue;
13037 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_SS)
13039 g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q2].gst), "max-size-time", 0 , NULL);
13040 g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q2].gst), "max-size-buffers", 2, NULL);
13041 g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q2].gst), "max-size-bytes", 0, NULL);
13045 if (!MMPLAYER_IS_RTSP_STREAMING(player))
13046 g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q2].gst), "max-size-time", q_max_size_time * GST_SECOND, NULL);
13051 debug_error("Not supporting more then two elementary stream\n");
13055 pad = gst_element_get_static_pad(sinkelement, padname);
13059 debug_warning("failed to get pad(%s) from %s. retrying with [sink]\n",
13060 padname, GST_ELEMENT_NAME(sinkelement) );
13062 pad = gst_element_get_static_pad(sinkelement, "sink");
13065 debug_error("failed to get pad(sink) from %s. \n",
13066 GST_ELEMENT_NAME(sinkelement) );
13071 /* to check the video/audio type set the proper flag*/
13072 const gchar *mime_type = NULL;
13074 srccaps = gst_pad_query_caps(srcpad, NULL);
13078 str = gst_caps_get_structure( srccaps, 0 );
13082 mime_type = gst_structure_get_name(str);
13087 /* link queue and decoder. so, it will be queue - decoder. */
13088 if ( GST_PAD_LINK_OK != gst_pad_link(srcpad, pad) )
13090 gst_object_unref(GST_OBJECT(pad));
13091 debug_error("failed to link (%s) to pad(%s)\n", GST_ELEMENT_NAME( sinkelement ), padname );
13093 /* reconstitute supportable codec */
13094 if (strstr(mime_type, "video"))
13096 player->can_support_codec ^= FOUND_PLUGIN_VIDEO;
13098 else if (strstr(mime_type, "audio"))
13100 player->can_support_codec ^= FOUND_PLUGIN_AUDIO;
13105 if (strstr(mime_type, "video"))
13107 player->videodec_linked = 1;
13108 debug_msg("player->videodec_linked set to 1\n");
13111 else if (strstr(mime_type, "audio"))
13113 player->audiodec_linked = 1;
13114 debug_msg("player->auddiodec_linked set to 1\n");
13117 gst_object_unref(GST_OBJECT(pad));
13118 gst_caps_unref(GST_CAPS(srccaps));
13122 if ( !MMPLAYER_IS_HTTP_PD(player) )
13124 if( (g_strrstr(klass, "Demux") && !g_strrstr(klass, "Metadata")) || (g_strrstr(klass, "Parser") ) )
13126 if (MMPLAYER_IS_HTTP_STREAMING(player))
13128 gint64 dur_bytes = 0L;
13129 gchar *file_buffering_path = NULL;
13130 gboolean use_file_buffer = FALSE;
13132 if ( !mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)
13134 debug_log("creating http streaming buffering queue\n");
13136 queue = gst_element_factory_make("queue2", "queue2");
13139 debug_error ( "failed to create buffering queue element\n" );
13143 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_READY) )
13145 debug_error("failed to set state READY to buffering queue\n");
13149 if ( !gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue) )
13151 debug_error("failed to add buffering queue\n");
13155 qsinkpad = gst_element_get_static_pad(queue, "sink");
13156 qsrcpad = gst_element_get_static_pad(queue, "src");
13158 if ( GST_PAD_LINK_OK != gst_pad_link(srcpad, qsinkpad) )
13160 debug_error("failed to link buffering queue\n");
13166 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
13167 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue;
13169 if ( !MMPLAYER_IS_HTTP_LIVE_STREAMING(player))
13171 if ( !gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
13172 debug_error("fail to get duration.\n");
13176 use_file_buffer = MMPLAYER_USE_FILE_FOR_BUFFERING(player);
13177 file_buffering_path = g_strdup(player->ini.http_file_buffer_path);
13185 /* NOTE : we cannot get any duration info from ts container in case of streaming */
13186 if(!g_strrstr(GST_ELEMENT_NAME(sinkelement), "mpegtsdemux"))
13188 __mm_player_streaming_set_queue2(player->streamer,
13191 player->ini.http_max_size_bytes,
13192 player->ini.http_buffering_time,
13194 player->ini.http_buffering_limit,
13196 file_buffering_path,
13197 (guint64)dur_bytes);
13200 MMPLAYER_FREEIF(file_buffering_path);
13205 /* if it is not decoder or */
13206 /* in decoder case any of the video/audio still need to link*/
13207 if(!g_strrstr(klass, "Decoder"))
13210 pad = gst_element_get_static_pad(sinkelement, padname);
13213 debug_warning("failed to get pad(%s) from %s. retrying with [sink]\n",
13214 padname, GST_ELEMENT_NAME(sinkelement) );
13216 pad = gst_element_get_static_pad(sinkelement, "sink");
13220 debug_error("failed to get pad(sink) from %s. \n",
13221 GST_ELEMENT_NAME(sinkelement) );
13226 if ( GST_PAD_LINK_OK != gst_pad_link(srcpad, pad) )
13228 gst_object_unref(GST_OBJECT(pad));
13229 debug_error("failed to link (%s) to pad(%s)\n", GST_ELEMENT_NAME( sinkelement ), padname );
13233 gst_object_unref(GST_OBJECT(pad));
13236 for(;templlist != NULL; templlist = templlist->next)
13238 padtemplate = templlist->data;
13240 debug_log ("director = [%d], presence = [%d]\n", padtemplate->direction, padtemplate->presence);
13242 if( padtemplate->direction != GST_PAD_SRC ||
13243 padtemplate->presence == GST_PAD_REQUEST )
13246 switch(padtemplate->presence)
13248 case GST_PAD_ALWAYS:
13250 GstPad *srcpad = gst_element_get_static_pad(sinkelement, "src");
13251 GstCaps *caps = gst_pad_query_caps(srcpad, NULL);
13253 /* Check whether caps has many types */
13254 if ( !gst_caps_is_fixed(caps))
13256 debug_log ("always pad but, caps has many types");
13257 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
13258 has_many_types = TRUE;
13262 if ( ! __mmplayer_try_to_plug(player, srcpad, caps) )
13264 gst_object_unref(GST_OBJECT(srcpad));
13265 gst_caps_unref(GST_CAPS(caps));
13267 debug_error("failed to plug something after %s\n", GST_ELEMENT_NAME( sinkelement ));
13271 gst_caps_unref(GST_CAPS(caps));
13272 gst_object_unref(GST_OBJECT(srcpad));
13278 case GST_PAD_SOMETIMES:
13279 has_dynamic_pads = TRUE;
13287 /* check if player can do start continually */
13288 MMPLAYER_CHECK_CMD_IF_EXIT(player);
13290 if( has_dynamic_pads )
13292 player->have_dynamic_pad = TRUE;
13293 MMPLAYER_SIGNAL_CONNECT ( player, sinkelement, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
13294 G_CALLBACK(__mmplayer_add_new_pad), player);
13296 /* for streaming, more then one typefind will used for each elementary stream
13297 * so this doesn't mean the whole pipeline completion
13299 if ( ! MMPLAYER_IS_RTSP_STREAMING( player ) )
13301 MMPLAYER_SIGNAL_CONNECT( player, sinkelement, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
13302 G_CALLBACK(__mmplayer_pipeline_complete), player);
13306 if (has_many_types)
13308 GstPad *pad = NULL;
13310 player->has_many_types = has_many_types;
13312 pad = gst_element_get_static_pad(sinkelement, "src");
13313 MMPLAYER_SIGNAL_CONNECT (player, pad, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "notify::caps", G_CALLBACK(__mmplayer_add_new_caps), player);
13314 gst_object_unref (GST_OBJECT(pad));
13318 /* check if player can do start continually */
13319 MMPLAYER_CHECK_CMD_IF_EXIT(player);
13321 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkelement, GST_STATE_PAUSED) )
13323 debug_error("failed to set state PAUSED to %s\n", GST_ELEMENT_NAME( sinkelement ));
13329 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state (queue, GST_STATE_PAUSED) )
13331 debug_error("failed to set state PAUSED to queue\n");
13337 gst_object_unref (GST_OBJECT(qsrcpad));
13343 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state (parser, GST_STATE_PAUSED) )
13345 debug_error("failed to set state PAUSED to queue\n");
13351 gst_object_unref (GST_OBJECT(pssrcpad));
13363 gst_object_unref(GST_OBJECT(qsrcpad));
13365 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
13366 * You need to explicitly set elements to the NULL state before
13367 * dropping the final reference, to allow them to clean up.
13369 gst_element_set_state(queue, GST_STATE_NULL);
13370 /* And, it still has a parent "player".
13371 * You need to let the parent manage the object instead of unreffing the object directly.
13374 gst_bin_remove (GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue);
13375 //gst_object_unref( queue );
13379 gst_caps_unref(GST_CAPS(srccaps));
13384 static gboolean __mmplayer_feature_filter(GstPluginFeature *feature, gpointer data) // @
13386 const gchar *klass;
13387 //const gchar *name;
13389 /* we only care about element factories */
13390 if (!GST_IS_ELEMENT_FACTORY(feature))
13393 /* only parsers, demuxers and decoders */
13394 klass = gst_element_factory_get_metadata (GST_ELEMENT_FACTORY(feature), GST_ELEMENT_METADATA_KLASS);
13395 //name = gst_element_factory_get_longname(GST_ELEMENT_FACTORY(feature));
13397 if( g_strrstr(klass, "Demux") == NULL &&
13398 g_strrstr(klass, "Codec/Decoder") == NULL &&
13399 g_strrstr(klass, "Depayloader") == NULL &&
13400 g_strrstr(klass, "Parse") == NULL)
13408 static void __mmplayer_add_new_caps(GstPad* pad, GParamSpec* unused, gpointer data)
13410 mm_player_t* player = (mm_player_t*) data;
13411 GstCaps *caps = NULL;
13412 GstStructure *str = NULL;
13417 return_if_fail ( pad )
13418 return_if_fail ( unused )
13419 return_if_fail ( data )
13421 caps = gst_pad_query_caps(pad, NULL);
13425 str = gst_caps_get_structure(caps, 0);
13429 name = gst_structure_get_name(str);
13432 debug_log("name=%s\n", name);
13434 if ( ! __mmplayer_try_to_plug(player, pad, caps) )
13436 debug_error("failed to autoplug for type (%s)\n", name);
13437 gst_caps_unref(caps);
13441 gst_caps_unref(caps);
13443 __mmplayer_pipeline_complete( NULL, (gpointer)player );
13450 static void __mmplayer_set_unlinked_mime_type(mm_player_t* player, GstCaps *caps)
13454 const char *stream_type;
13455 gchar *version_field = NULL;
13459 return_if_fail ( player );
13460 return_if_fail ( caps );
13462 str = gst_caps_get_structure(caps, 0);
13466 stream_type = gst_structure_get_name(str);
13467 if ( !stream_type )
13471 /* set unlinked mime type for downloadable codec */
13472 if (g_str_has_prefix(stream_type, "video/"))
13474 if (g_str_has_prefix(stream_type, "video/mpeg"))
13476 gst_structure_get_int (str, MM_PLAYER_MPEG_VNAME, &version);
13477 version_field = MM_PLAYER_MPEG_VNAME;
13479 else if (g_str_has_prefix(stream_type, "video/x-wmv"))
13481 gst_structure_get_int (str, MM_PLAYER_WMV_VNAME, &version);
13482 version_field = MM_PLAYER_WMV_VNAME;
13485 else if (g_str_has_prefix(stream_type, "video/x-divx"))
13487 gst_structure_get_int (str, MM_PLAYER_DIVX_VNAME, &version);
13488 version_field = MM_PLAYER_DIVX_VNAME;
13493 player->unlinked_video_mime = g_strdup_printf("%s, %s=%d", stream_type, version_field, version);
13497 player->unlinked_video_mime = g_strdup_printf("%s", stream_type);
13500 else if (g_str_has_prefix(stream_type, "audio/"))
13502 if (g_str_has_prefix(stream_type, "audio/mpeg")) // mp3 or aac
13504 gst_structure_get_int (str, MM_PLAYER_MPEG_VNAME, &version);
13505 version_field = MM_PLAYER_MPEG_VNAME;
13507 else if (g_str_has_prefix(stream_type, "audio/x-wma"))
13509 gst_structure_get_int (str, MM_PLAYER_WMA_VNAME, &version);
13510 version_field = MM_PLAYER_WMA_VNAME;
13515 player->unlinked_audio_mime = g_strdup_printf("%s, %s=%d", stream_type, version_field, version);
13519 player->unlinked_audio_mime = g_strdup_printf("%s", stream_type);
13526 static void __mmplayer_add_new_pad(GstElement *element, GstPad *pad, gpointer data)
13528 mm_player_t* player = (mm_player_t*) data;
13529 GstCaps *caps = NULL;
13530 GstStructure *str = NULL;
13534 return_if_fail ( player );
13535 return_if_fail ( pad );
13537 GST_OBJECT_LOCK (pad);
13538 if ((caps = gst_pad_get_current_caps(pad)))
13539 gst_caps_ref(caps);
13540 GST_OBJECT_UNLOCK (pad);
13542 if ( NULL == caps )
13544 caps = gst_pad_query_caps(pad, NULL);
13545 if ( !caps ) return;
13548 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
13550 str = gst_caps_get_structure(caps, 0);
13554 name = gst_structure_get_name(str);
13558 player->num_dynamic_pad++;
13559 debug_log("stream count inc : %d\n", player->num_dynamic_pad);
13561 /* Note : If the stream is the subtitle, we try not to play it. Just close the demuxer subtitle pad.
13562 * If want to play it, remove this code.
13564 if (g_strrstr(name, "application"))
13566 if (g_strrstr(name, "x-id3") || g_strrstr(name, "x-apetag"))
13568 /* If id3/ape tag comes, keep going */
13569 debug_log("application mime exception : id3/ape tag");
13573 /* Otherwise, we assume that this stream is subtile. */
13574 debug_log(" application mime type pad is closed.");
13578 else if (g_strrstr(name, "audio"))
13580 gint samplerate = 0, channels = 0;
13582 if (player->audiodec_linked)
13584 gst_caps_unref(caps);
13585 debug_log("multi tracks. skip to plug");
13589 /* set stream information */
13590 /* if possible, set it here because the caps is not distrubed by resampler. */
13591 gst_structure_get_int (str, "rate", &samplerate);
13592 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
13594 gst_structure_get_int (str, "channels", &channels);
13595 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
13597 debug_log("audio samplerate : %d channels : %d", samplerate, channels);
13599 else if (g_strrstr(name, "video"))
13602 mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &stype);
13604 /* don't make video because of not required */
13605 if (stype == MM_DISPLAY_SURFACE_NULL)
13607 debug_log("no video because it's not required");
13611 player->v_stream_caps = gst_caps_copy(caps); //if needed, video caps is required when videobin is created
13614 if ( ! __mmplayer_try_to_plug(player, pad, caps) )
13616 debug_error("failed to autoplug for type (%s)", name);
13618 __mmplayer_set_unlinked_mime_type(player, caps);
13621 gst_caps_unref(caps);
13628 __mmplayer_check_subtitle( mm_player_t* player )
13630 MMHandleType attrs = 0;
13631 char *subtitle_uri = NULL;
13635 return_val_if_fail( player, FALSE );
13637 /* get subtitle attribute */
13638 attrs = MMPLAYER_GET_ATTRS(player);
13642 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
13643 if ( !subtitle_uri || !strlen(subtitle_uri))
13646 debug_log ("subtite uri is %s[%d]\n", subtitle_uri, strlen(subtitle_uri));
13647 player->is_external_subtitle_present = TRUE;
13655 __mmplayer_can_extract_pcm( mm_player_t* player )
13657 MMHandleType attrs = 0;
13658 gboolean is_drm = FALSE;
13659 gboolean sound_extraction = FALSE;
13661 return_val_if_fail ( player, FALSE );
13663 attrs = MMPLAYER_GET_ATTRS(player);
13666 debug_error("fail to get attributes.");
13670 /* check file is drm or not */
13671 if (g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), "is-drm"))
13672 g_object_get(G_OBJECT(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), "is-drm", &is_drm, NULL);
13674 /* get sound_extraction property */
13675 mm_attrs_get_int_by_name(attrs, "pcm_extraction", &sound_extraction);
13677 if ( ! sound_extraction || is_drm )
13679 debug_log("checking pcm extraction mode : %d, drm : %d", sound_extraction, is_drm);
13687 __mmplayer_handle_streaming_error ( mm_player_t* player, GstMessage * message )
13690 MMMessageParamType msg_param;
13691 gchar *msg_src_element = NULL;
13692 GstStructure *s = NULL;
13693 guint error_id = 0;
13694 gchar *error_string = NULL;
13698 return_val_if_fail ( player, FALSE );
13699 return_val_if_fail ( message, FALSE );
13701 s = malloc( sizeof(GstStructure) );
13702 memcpy ( s, gst_message_get_structure ( message ), sizeof(GstStructure));
13704 if ( !gst_structure_get_uint (s, "error_id", &error_id) )
13705 error_id = MMPLAYER_STREAMING_ERROR_NONE;
13707 switch ( error_id )
13709 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
13710 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
13712 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
13713 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
13715 case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
13716 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
13718 case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
13719 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
13721 case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
13722 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
13724 case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
13725 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
13727 case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
13728 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
13730 case MMPLAYER_STREAMING_ERROR_INVALID_URL:
13731 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
13733 case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
13734 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
13736 case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
13737 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
13739 case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
13740 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
13742 case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
13743 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
13745 case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
13746 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
13748 case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
13749 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
13751 case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
13752 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
13754 case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
13755 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
13757 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
13758 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
13760 case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
13761 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
13763 case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
13764 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
13766 case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
13767 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
13769 case MMPLAYER_STREAMING_ERROR_GONE:
13770 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
13772 case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
13773 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
13775 case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
13776 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
13778 case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
13779 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
13781 case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
13782 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
13784 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
13785 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
13787 case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
13788 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
13790 case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
13791 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
13793 case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
13794 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
13796 case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
13797 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
13799 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
13800 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
13802 case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
13803 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
13805 case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
13806 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
13808 case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
13809 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
13811 case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
13812 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
13814 case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
13815 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
13817 case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
13818 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
13820 case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
13821 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
13823 case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
13824 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
13826 case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
13827 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
13829 case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
13830 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
13832 case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
13833 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
13835 case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
13836 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
13838 case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
13839 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
13841 case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
13842 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
13846 MMPLAYER_FREEIF(s);
13847 return MM_ERROR_PLAYER_STREAMING_FAIL;
13851 error_string = g_strdup(gst_structure_get_string (s, "error_string"));
13852 if ( error_string )
13853 msg_param.data = (void *) error_string;
13855 if ( message->src )
13857 msg_src_element = GST_ELEMENT_NAME( GST_ELEMENT_CAST( message->src ) );
13859 debug_error("-Msg src : [%s] Code : [%x] Error : [%s] \n",
13860 msg_src_element, msg_param.code, (char*)msg_param.data );
13863 /* post error to application */
13864 if ( ! player->msg_posted )
13866 MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param );
13868 /* don't post more if one was sent already */
13869 player->msg_posted = TRUE;
13873 debug_log("skip error post because it's sent already.\n");
13876 MMPLAYER_FREEIF(s);
13878 g_free(error_string);
13885 __mmplayer_handle_eos_delay( mm_player_t* player, int delay_in_ms )
13887 return_if_fail( player );
13890 /* post now if delay is zero */
13891 if ( delay_in_ms == 0 || player->set_mode.pcm_extraction)
13893 debug_log("eos delay is zero. posting EOS now\n");
13894 MMPLAYER_POST_MSG( player, MM_MESSAGE_END_OF_STREAM, NULL );
13896 if ( player->set_mode.pcm_extraction )
13897 __mmplayer_cancel_eos_timer(player);
13902 /* cancel if existing */
13903 __mmplayer_cancel_eos_timer( player );
13905 /* init new timeout */
13906 /* NOTE : consider give high priority to this timer */
13907 debug_log("posting EOS message after [%d] msec\n", delay_in_ms);
13909 player->eos_timer = g_timeout_add( delay_in_ms,
13910 __mmplayer_eos_timer_cb, player );
13912 player->context.global_default = g_main_context_default ();
13913 debug_log("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
13915 /* check timer is valid. if not, send EOS now */
13916 if ( player->eos_timer == 0 )
13918 debug_warning("creating timer for delayed EOS has failed. sending EOS now\n");
13919 MMPLAYER_POST_MSG( player, MM_MESSAGE_END_OF_STREAM, NULL );
13924 __mmplayer_cancel_eos_timer( mm_player_t* player )
13926 return_if_fail( player );
13928 if ( player->eos_timer )
13930 debug_log("cancel eos timer");
13931 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
13932 player->eos_timer = 0;
13939 __mmplayer_eos_timer_cb(gpointer u_data)
13941 mm_player_t* player = NULL;
13942 player = (mm_player_t*) u_data;
13944 return_val_if_fail( player, FALSE );
13946 if ( player->play_count > 1 )
13948 gint ret_value = 0;
13949 ret_value = __gst_set_position( player, MM_PLAYER_POS_FORMAT_TIME, 0, TRUE);
13950 if (ret_value == MM_ERROR_NONE)
13952 MMHandleType attrs = 0;
13953 attrs = MMPLAYER_GET_ATTRS(player);
13955 /* we successeded to rewind. update play count and then wait for next EOS */
13956 player->play_count--;
13958 mm_attrs_set_int_by_name(attrs, "profile_play_count", player->play_count);
13959 mmf_attrs_commit ( attrs );
13963 debug_error("seeking to 0 failed in repeat play");
13969 MMPLAYER_POST_MSG( player, MM_MESSAGE_END_OF_STREAM, NULL );
13972 /* we are returning FALSE as we need only one posting */
13977 __mmplayer_link_decoder( mm_player_t* player, GstPad *srcpad)
13979 const gchar* name = NULL;
13980 GstStructure* str = NULL;
13981 GstCaps* srccaps = NULL;
13985 return_val_if_fail( player, FALSE );
13986 return_val_if_fail ( srcpad, FALSE );
13988 /* to check any of the decoder (video/audio) need to be linked to parser*/
13989 srccaps = gst_pad_query_caps( srcpad, NULL);
13993 str = gst_caps_get_structure( srccaps, 0 );
13997 name = gst_structure_get_name(str);
14001 if (strstr(name, "video"))
14003 if(player->videodec_linked)
14005 debug_msg("Video decoder already linked\n");
14009 if (strstr(name, "audio"))
14011 if(player->audiodec_linked)
14013 debug_msg("Audio decoder already linked\n");
14018 gst_caps_unref( srccaps );
14026 gst_caps_unref( srccaps );
14032 __mmplayer_link_sink( mm_player_t* player , GstPad *srcpad)
14034 const gchar* name = NULL;
14035 GstStructure* str = NULL;
14036 GstCaps* srccaps = NULL;
14040 return_val_if_fail ( player, FALSE );
14041 return_val_if_fail ( srcpad, FALSE );
14043 /* to check any of the decoder (video/audio) need to be linked to parser*/
14044 srccaps = gst_pad_query_caps( srcpad, NULL );
14048 str = gst_caps_get_structure( srccaps, 0 );
14052 name = gst_structure_get_name(str);
14056 if (strstr(name, "video"))
14058 if(player->videosink_linked)
14060 debug_msg("Video Sink already linked\n");
14064 if (strstr(name, "audio"))
14066 if(player->audiosink_linked)
14068 debug_msg("Audio Sink already linked\n");
14072 if (strstr(name, "text"))
14074 if(player->textsink_linked)
14076 debug_msg("Text Sink already linked\n");
14081 gst_caps_unref( srccaps );
14086 //return (!player->videosink_linked || !player->audiosink_linked);
14090 gst_caps_unref( srccaps );
14096 /* sending event to one of sinkelements */
14098 __gst_send_event_to_sink( mm_player_t* player, GstEvent* event )
14100 GstEvent * event2 = NULL;
14101 GList *sinks = NULL;
14102 gboolean res = FALSE;
14105 return_val_if_fail( player, FALSE );
14106 return_val_if_fail ( event, FALSE );
14108 if ( player->play_subtitle && !player->use_textoverlay)
14109 event2 = gst_event_copy((const GstEvent *)event);
14111 sinks = player->sink_elements;
14114 GstElement *sink = GST_ELEMENT_CAST (sinks->data);
14116 if (GST_IS_ELEMENT(sink))
14118 /* keep ref to the event */
14119 gst_event_ref (event);
14121 if ( (res = gst_element_send_event (sink, event)) )
14123 debug_log("sending event[%s] to sink element [%s] success!\n",
14124 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink) );
14126 /* rtsp case, asyn_done is not called after seek during pause state */
14127 if (MMPLAYER_IS_RTSP_STREAMING(player))
14129 if (strstr(GST_EVENT_TYPE_NAME(event), "seek"))
14131 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED)
14133 debug_log("RTSP seek completed, after pause state..\n");
14134 player->doing_seek = FALSE;
14135 MMPLAYER_POST_MSG ( player, MM_MESSAGE_SEEK_COMPLETED, NULL );
14141 if( MMPLAYER_IS_ES_BUFF_SRC(player))
14143 sinks = g_list_next (sinks);
14150 debug_log("sending event[%s] to sink element [%s] failed. try with next one.\n",
14151 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink) );
14154 sinks = g_list_next (sinks);
14159 request pad name = sink0;
14161 request pad name = sink1; // external
14164 /* Note : Textbin is not linked to the video or audio bin.
14165 * It needs to send the event to the text sink seperatelly.
14167 if ( player->play_subtitle && !player->use_textoverlay)
14169 GstElement *text_sink = GST_ELEMENT_CAST (player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
14171 if (GST_IS_ELEMENT(text_sink))
14173 /* keep ref to the event */
14174 gst_event_ref (event2);
14176 if ((res = gst_element_send_event (text_sink, event2)))
14178 debug_log("sending event[%s] to subtitle sink element [%s] success!\n",
14179 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink) );
14183 debug_error("sending event[%s] to subtitle sink element [%s] failed!\n",
14184 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink) );
14187 gst_event_unref (event2);
14191 gst_event_unref (event);
14199 __mmplayer_add_sink( mm_player_t* player, GstElement* sink )
14203 return_if_fail ( player );
14204 return_if_fail ( sink );
14206 player->sink_elements =
14207 g_list_append(player->sink_elements, sink);
14213 __mmplayer_del_sink( mm_player_t* player, GstElement* sink )
14217 return_if_fail ( player );
14218 return_if_fail ( sink );
14220 player->sink_elements =
14221 g_list_remove(player->sink_elements, sink);
14227 __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
14228 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
14229 gint64 cur, GstSeekType stop_type, gint64 stop )
14231 GstEvent* event = NULL;
14232 gboolean result = FALSE;
14236 return_val_if_fail( player, FALSE );
14238 __mmplayer_drop_subtitle(player, FALSE);
14240 event = gst_event_new_seek (rate, format, flags, cur_type,
14241 cur, stop_type, stop);
14243 result = __gst_send_event_to_sink( player, event );
14250 /* NOTE : be careful with calling this api. please refer to below glib comment
14251 * glib comment : Note that there is a bug in GObject that makes this function much
14252 * less useful than it might seem otherwise. Once gobject is disposed, the callback
14253 * will no longer be called, but, the signal handler is not currently disconnected.
14254 * If the instance is itself being freed at the same time than this doesn't matter,
14255 * since the signal will automatically be removed, but if instance persists,
14256 * then the signal handler will leak. You should not remove the signal yourself
14257 * because in a future versions of GObject, the handler will automatically be
14260 * It's possible to work around this problem in a way that will continue to work
14261 * with future versions of GObject by checking that the signal handler is still
14262 * connected before disconnected it:
14264 * if (g_signal_handler_is_connected (instance, id))
14265 * g_signal_handler_disconnect (instance, id);
14268 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
14270 GList* sig_list = NULL;
14271 MMPlayerSignalItem* item = NULL;
14275 return_if_fail( player );
14277 debug_log("release signals type : %d", type);
14279 if ((type < MM_PLAYER_SIGNAL_TYPE_AUTOPLUG) || (type >= MM_PLAYER_SIGNAL_TYPE_ALL))
14281 __mmplayer_release_signal_connection (player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
14282 __mmplayer_release_signal_connection (player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
14283 __mmplayer_release_signal_connection (player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
14284 __mmplayer_release_signal_connection (player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
14285 __mmplayer_release_signal_connection (player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
14289 sig_list = player->signals[type];
14291 for ( ; sig_list; sig_list = sig_list->next )
14293 item = sig_list->data;
14295 if ( item && item->obj && GST_IS_ELEMENT(item->obj) )
14297 if ( g_signal_handler_is_connected ( item->obj, item->sig ) )
14299 g_signal_handler_disconnect ( item->obj, item->sig );
14303 MMPLAYER_FREEIF( item );
14306 g_list_free ( player->signals[type] );
14307 player->signals[type] = NULL;
14314 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
14316 mm_player_t* player = 0;
14317 int prev_display_surface_type = 0;
14318 void *prev_display_overlay = NULL;
14319 const gchar *klass = NULL;
14320 gchar *cur_videosink_name = NULL;
14323 int num_of_dec = 2; /* DEC1, DEC2 */
14327 return_val_if_fail(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
14328 return_val_if_fail(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
14330 player = MM_PLAYER_CAST(handle);
14332 if (surface_type < MM_DISPLAY_SURFACE_X && surface_type >= MM_DISPLAY_SURFACE_NUM)
14334 debug_error("Not support this surface type(%d) for changing vidoesink", surface_type);
14336 return MM_ERROR_INVALID_ARGUMENT;
14339 /* load previous attributes */
14342 mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &prev_display_surface_type);
14343 mm_attrs_get_data_by_name (player->attrs, "display_overlay", &prev_display_overlay);
14344 debug_log("[0: X surface, 1: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
14345 if (prev_display_surface_type == surface_type)
14347 debug_log("incoming display surface type is same as previous one, do nothing..");
14349 return MM_ERROR_NONE;
14354 debug_error("failed to load attributes");
14356 return MM_ERROR_PLAYER_INTERNAL;
14359 /* check videosink element is created */
14360 if (!player->pipeline || !player->pipeline->videobin ||
14361 !player->pipeline->videobin[MMPLAYER_V_SINK].gst )
14363 debug_log("videosink element is not yet ready");
14365 /* videobin is not created yet, so we just set attributes related to display surface */
14366 debug_log("store display attribute for given surface type(%d)", surface_type);
14367 mm_attrs_set_int_by_name (player->attrs, "display_surface_type", surface_type);
14368 mm_attrs_set_data_by_name (player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
14369 if ( mmf_attrs_commit ( player->attrs ) )
14371 debug_error("failed to commit attribute");
14373 return MM_ERROR_PLAYER_INTERNAL;
14376 return MM_ERROR_NONE;
14380 /* get player command status */
14381 if ( !(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME || player->cmd == MMPLAYER_COMMAND_PAUSE) )
14383 debug_error("invalid player command status(%d), __mmplayer_do_change_videosink() is only available with START/RESUME/PAUSE command",player->cmd);
14385 return MM_ERROR_PLAYER_INVALID_STATE;
14388 /* get a current videosink name */
14389 cur_videosink_name = GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
14391 /* surface change */
14392 for ( i = 0 ; i < num_of_dec ; i++)
14394 if ( player->pipeline->mainbin &&
14395 player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst )
14397 GstElementFactory *decfactory;
14398 decfactory = gst_element_get_factory (player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst);
14400 klass = gst_element_factory_get_metadata (decfactory, GST_ELEMENT_METADATA_KLASS);
14401 if ((g_strrstr(klass, "Codec/Decoder/Video")))
14403 if ( !strncmp(cur_videosink_name, "x", 1) && (surface_type == MM_DISPLAY_SURFACE_EVAS) )
14405 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, player->ini.videosink_element_evas, surface_type, display_overlay);
14412 debug_warning("success to changing display surface(%d)",surface_type);
14414 return MM_ERROR_NONE;
14417 else if (!strncmp(cur_videosink_name, "evas", 4) && (surface_type == MM_DISPLAY_SURFACE_X) )
14419 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, player->ini.videosink_element_x, surface_type, display_overlay);
14426 debug_warning("success to changing display surface(%d)",surface_type);
14428 return MM_ERROR_NONE;
14433 debug_error("invalid incoming surface type(%d) and current videosink_name(%s) for changing display surface",surface_type, cur_videosink_name);
14434 ret = MM_ERROR_PLAYER_INTERNAL;
14443 /* rollback to previous attributes */
14444 mm_attrs_set_int_by_name (player->attrs, "display_surface_type", prev_display_surface_type);
14445 mm_attrs_set_data_by_name(player->attrs, "display_overlay", prev_display_overlay, sizeof(void*));
14446 if ( mmf_attrs_commit ( player->attrs ) )
14448 debug_error("failed to commit attributes to rollback");
14450 return MM_ERROR_PLAYER_INTERNAL;
14456 /* NOTE : It does not support some use cases, eg using colorspace converter */
14458 __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay)
14460 GstPad *src_pad_dec = NULL;
14461 GstPad *sink_pad_videosink = NULL;
14462 GstPad *sink_pad_videobin = NULL;
14463 GstClock *clock = NULL;
14464 MMPlayerStateType previous_state = MM_PLAYER_STATE_NUM;
14465 int ret = MM_ERROR_NONE;
14466 gboolean is_audiobin_created = TRUE;
14470 return_val_if_fail(player, MM_ERROR_COMMON_INVALID_ARGUMENT);
14471 return_val_if_fail(videosink_element, MM_ERROR_COMMON_INVALID_ARGUMENT);
14472 return_val_if_fail(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
14474 debug_log("video dec is found(idx:%d), we are going to change videosink to %s", dec_index, videosink_element);
14475 debug_log("surface type(%d), display overlay(%x)", surface_type, display_overlay);
14477 /* get information whether if audiobin is created */
14478 if ( !player->pipeline->audiobin ||
14479 !player->pipeline->audiobin[MMPLAYER_A_SINK].gst )
14481 debug_warning("audiobin is null, this video content may not have audio data");
14482 is_audiobin_created = FALSE;
14485 /* get current state of player */
14486 previous_state = MMPLAYER_CURRENT_STATE(player);
14487 debug_log("previous state(%d)", previous_state);
14490 /* get src pad of decoder and block it */
14491 src_pad_dec = gst_element_get_static_pad (GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), "src");
14494 debug_error("failed to get src pad from decode in mainbin");
14495 return MM_ERROR_PLAYER_INTERNAL;
14498 if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING)
14500 debug_warning("trying to block pad(video)");
14501 // if (!gst_pad_set_blocked (src_pad_dec, TRUE))
14502 gst_pad_add_probe(src_pad_dec, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
14506 debug_error("failed to set block pad(video)");
14507 return MM_ERROR_PLAYER_INTERNAL;
14509 debug_warning("pad is blocked(video)");
14513 /* no data flows, so no need to do pad_block */
14514 if (player->doing_seek) {
14515 debug_warning("not completed seek(%d), do nothing", player->doing_seek);
14517 debug_log("MM_PLAYER_STATE is not PLAYING now, skip pad-block(TRUE)");
14521 if (!gst_element_remove_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst,
14522 GST_PAD_CAST(GST_GHOST_PAD(player->ghost_pad_for_videobin))))
14524 debug_error("failed to remove previous ghost_pad for videobin");
14525 return MM_ERROR_PLAYER_INTERNAL;
14528 /* change state of videobin to NULL */
14529 debug_log("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_NULL);
14530 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_NULL);
14531 if (ret != GST_STATE_CHANGE_SUCCESS)
14533 debug_error("failed to change state of videobin to NULL");
14534 return MM_ERROR_PLAYER_INTERNAL;
14537 /* unlink between decoder and videobin and remove previous videosink from videobin */
14538 GST_ELEMENT_UNLINK(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst),GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst));
14539 if ( !gst_bin_remove (GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst)) )
14541 debug_error("failed to remove former videosink from videobin");
14542 return MM_ERROR_PLAYER_INTERNAL;
14545 __mmplayer_del_sink( player, player->pipeline->videobin[MMPLAYER_V_SINK].gst );
14547 /* create a new videosink and add it to videobin */
14548 player->pipeline->videobin[MMPLAYER_V_SINK].gst = gst_element_factory_make(videosink_element, videosink_element);
14549 gst_bin_add (GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst));
14550 __mmplayer_add_sink( player, player->pipeline->videobin[MMPLAYER_V_SINK].gst );
14551 g_object_set (G_OBJECT (player->pipeline->videobin[MMPLAYER_V_SINK].gst), "qos", TRUE, NULL);
14553 /* save attributes */
14556 /* set a new display surface type */
14557 mm_attrs_set_int_by_name (player->attrs, "display_surface_type", surface_type);
14558 /* set a new diplay overlay */
14559 switch (surface_type)
14561 case MM_DISPLAY_SURFACE_X:
14562 debug_log("save attributes related to display surface to X : xid = %d", *(int*)display_overlay);
14563 mm_attrs_set_data_by_name (player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
14565 case MM_DISPLAY_SURFACE_EVAS:
14566 debug_log("save attributes related to display surface to EVAS : evas image object = %x", display_overlay);
14567 mm_attrs_set_data_by_name (player->attrs, "display_overlay", display_overlay, sizeof(void*));
14570 debug_error("invalid type(%d) for changing display surface",surface_type);
14572 return MM_ERROR_INVALID_ARGUMENT;
14574 if ( mmf_attrs_commit ( player->attrs ) )
14576 debug_error("failed to commit");
14578 return MM_ERROR_PLAYER_INTERNAL;
14583 debug_error("player->attrs is null, failed to save attributes");
14585 return MM_ERROR_PLAYER_INTERNAL;
14588 /* update video param */
14589 if ( MM_ERROR_NONE != _mmplayer_update_video_param( player ) )
14591 debug_error("failed to update video param");
14592 return MM_ERROR_PLAYER_INTERNAL;
14595 /* change state of videobin to READY */
14596 debug_log("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_READY);
14597 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_READY);
14598 if (ret != GST_STATE_CHANGE_SUCCESS)
14600 debug_error("failed to change state of videobin to READY");
14601 return MM_ERROR_PLAYER_INTERNAL;
14604 /* change ghostpad */
14605 sink_pad_videosink = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "sink");
14606 if ( !sink_pad_videosink )
14608 debug_error("failed to get sink pad from videosink element");
14609 return MM_ERROR_PLAYER_INTERNAL;
14611 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", sink_pad_videosink);
14612 if (!gst_pad_set_active(player->ghost_pad_for_videobin, TRUE))
14614 debug_error("failed to set active to ghost_pad");
14615 return MM_ERROR_PLAYER_INTERNAL;
14617 if ( FALSE == gst_element_add_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin) )
14619 debug_error("failed to change ghostpad for videobin");
14620 return MM_ERROR_PLAYER_INTERNAL;
14622 gst_object_unref(sink_pad_videosink);
14624 /* link decoder with videobin */
14625 sink_pad_videobin = gst_element_get_static_pad( GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst), "sink");
14626 if ( !sink_pad_videobin )
14628 debug_error("failed to get sink pad from videobin");
14629 return MM_ERROR_PLAYER_INTERNAL;
14631 if ( GST_PAD_LINK_OK != GST_PAD_LINK(src_pad_dec, sink_pad_videobin) )
14633 debug_error("failed to link");
14634 return MM_ERROR_PLAYER_INTERNAL;
14636 gst_object_unref(sink_pad_videobin);
14638 /* clock setting for a new videosink plugin */
14639 /* NOTE : Below operation is needed, because a new videosink plugin doesn't have clock for basesink,
14640 so we set it from audiosink plugin or pipeline(system clock) */
14641 if (!is_audiobin_created)
14643 debug_warning("audiobin is not created, get clock from pipeline..");
14644 clock = GST_ELEMENT_CLOCK (player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
14648 clock = GST_ELEMENT_CLOCK (player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
14653 GstClockTime base_time;
14654 debug_log("set the clock to videosink");
14655 gst_element_set_clock (GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), clock);
14656 clock = GST_ELEMENT_CLOCK (player->pipeline->videobin[MMPLAYER_V_SINK].gst);
14659 debug_log("got clock of videosink");
14660 now = gst_clock_get_time ( clock );
14661 base_time = GST_ELEMENT_CAST (player->pipeline->videobin[MMPLAYER_V_SINK].gst)->base_time;
14662 debug_log ("at time %" GST_TIME_FORMAT ", base %"
14663 GST_TIME_FORMAT, GST_TIME_ARGS (now), GST_TIME_ARGS (base_time));
14667 debug_error("failed to get clock of videosink after setting clock");
14668 return MM_ERROR_PLAYER_INTERNAL;
14673 debug_warning("failed to get clock, maybe it is the time before first playing");
14676 if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING)
14678 /* change state of videobin to PAUSED */
14679 debug_log("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PLAYING);
14680 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PLAYING);
14681 if (ret != GST_STATE_CHANGE_FAILURE)
14683 debug_warning("change state of videobin to PLAYING, ret(%d)", ret);
14687 debug_error("failed to change state of videobin to PLAYING");
14688 return MM_ERROR_PLAYER_INTERNAL;
14691 /* release blocked and unref src pad of video decoder */
14693 if (!gst_pad_set_blocked (src_pad_dec, FALSE))
14695 debug_error("failed to set pad blocked FALSE(video)");
14696 return MM_ERROR_PLAYER_INTERNAL;
14699 debug_warning("pad is unblocked(video)");
14703 if (player->doing_seek) {
14704 debug_warning("not completed seek(%d)", player->doing_seek);
14706 /* change state of videobin to PAUSED */
14707 debug_log("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PAUSED);
14708 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PAUSED);
14709 if (ret != GST_STATE_CHANGE_FAILURE)
14711 debug_warning("change state of videobin to PAUSED, ret(%d)", ret);
14715 debug_error("failed to change state of videobin to PLAYING");
14716 return MM_ERROR_PLAYER_INTERNAL;
14719 /* already skipped pad block */
14720 debug_log("previous MM_PLAYER_STATE is not PLAYING, skip pad-block(FALSE)");
14723 /* do get/set position for new videosink plugin */
14725 unsigned long position = 0;
14726 gint64 pos_msec = 0;
14728 debug_log("do get/set position for new videosink plugin");
14729 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position ))
14731 debug_error("failed to get position");
14732 return MM_ERROR_PLAYER_INTERNAL;
14734 #ifdef SINKCHANGE_WITH_ACCURATE_SEEK
14735 /* accurate seek */
14736 if (__gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, position, TRUE ))
14738 debug_error("failed to set position");
14739 return MM_ERROR_PLAYER_INTERNAL;
14742 /* key unit seek */
14743 pos_msec = position * G_GINT64_CONSTANT(1000000);
14744 ret = __gst_seek ( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
14745 GST_FORMAT_TIME, ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT ),
14746 GST_SEEK_TYPE_SET, pos_msec,
14747 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE );
14750 debug_error("failed to set position");
14751 return MM_ERROR_PLAYER_INTERNAL;
14758 gst_object_unref (src_pad_dec);
14760 debug_log("success to change sink");
14764 return MM_ERROR_NONE;
14768 /* Note : if silent is true, then subtitle would not be displayed. :*/
14769 int _mmplayer_set_subtitle_silent (MMHandleType hplayer, int silent)
14771 mm_player_t* player = (mm_player_t*) hplayer;
14775 /* check player handle */
14776 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED );
14778 player->set_mode.subtitle_off = silent;
14780 debug_log("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
14784 return MM_ERROR_NONE;
14787 int _mmplayer_remove_audio_parser_decoder(mm_player_t* player,GstPad *inpad)
14789 int result = MM_ERROR_NONE;
14790 GstPad *peer = NULL,*pad = NULL;
14791 GstElement *Element = NULL;
14792 MMPlayerGstElement* mainbin = NULL;
14793 mainbin = player->pipeline->mainbin;
14796 if(!gst_pad_set_blocked(inpad,TRUE))
14798 result = MM_ERROR_PLAYER_INTERNAL;
14802 gst_pad_add_probe(inpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
14805 /*Getting pad connected to demuxer audio pad */
14806 peer = gst_pad_get_peer(inpad);
14807 /* Disconnecting Demuxer and its peer plugin [audio] */
14810 if(!gst_pad_unlink(inpad,peer))
14812 result = MM_ERROR_PLAYER_INTERNAL;
14818 result = MM_ERROR_PLAYER_INTERNAL;
14821 /*Removing elements between Demuxer and audiobin*/
14822 while(peer != NULL)
14824 gchar *Element_name = NULL;
14825 gchar *factory_name = NULL;
14826 GList *elements = NULL;
14827 GstElementFactory *factory = NULL;
14828 /*Getting peer element*/
14829 Element = gst_pad_get_parent_element(peer);
14830 if(Element == NULL)
14832 gst_object_unref(peer);
14833 result = MM_ERROR_PLAYER_INTERNAL;
14837 Element_name = gst_element_get_name(Element);
14838 factory = gst_element_get_factory(Element);
14839 /*checking the element is audio bin*/
14840 if(!strcmp(Element_name,"audiobin"))
14842 gst_object_unref(peer);
14843 result = MM_ERROR_NONE;
14844 g_free(Element_name);
14847 factory_name = GST_OBJECT_NAME(factory);
14848 pad = gst_element_get_static_pad(Element,"src");
14851 result = MM_ERROR_PLAYER_INTERNAL;
14852 g_free(Element_name);
14855 gst_object_unref(peer);
14856 peer = gst_pad_get_peer(pad);
14859 if(!gst_pad_unlink(pad,peer))
14861 gst_object_unref(peer);
14862 gst_object_unref(pad);
14863 result = MM_ERROR_PLAYER_INTERNAL;
14864 g_free(Element_name);
14868 elements = player->parsers;
14869 /* Removing the element form the list*/
14870 for ( ; elements; elements = g_list_next(elements))
14872 Element_name = elements->data;
14873 if(g_strrstr(Element_name,factory_name))
14875 player->parsers = g_list_remove(player->parsers,elements->data);
14878 gst_element_set_state(Element,GST_STATE_NULL);
14879 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst),Element);
14880 gst_object_unref(pad);
14881 if(Element == mainbin[MMPLAYER_M_Q1].gst)
14883 mainbin[MMPLAYER_M_Q1].gst = NULL;
14885 else if(Element == mainbin[MMPLAYER_M_Q2].gst)
14887 mainbin[MMPLAYER_M_Q2].gst = NULL;
14889 else if(Element == mainbin[MMPLAYER_M_DEC1].gst)
14891 mainbin[MMPLAYER_M_DEC1].gst = NULL;
14893 else if(Element == mainbin[MMPLAYER_M_DEC2].gst)
14895 mainbin[MMPLAYER_M_DEC2].gst = NULL;
14897 gst_object_unref(Element);
14903 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
14905 MMPlayerGstElement* mainbin = NULL;
14906 MMPlayerGstElement* textbin = NULL;
14907 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
14908 GstState current_state = GST_STATE_VOID_PENDING;
14909 GstState element_state = GST_STATE_VOID_PENDING;
14910 GstState element_pending_state = GST_STATE_VOID_PENDING;
14912 GstEvent *event = NULL;
14913 int result = MM_ERROR_NONE;
14915 GstClock *curr_clock = NULL;
14916 GstClockTime base_time, start_time, curr_time;
14921 /* check player handle */
14922 return_val_if_fail ( player && player->pipeline , MM_ERROR_PLAYER_NOT_INITIALIZED);
14924 if (!(player->pipeline->mainbin) || !(player->pipeline->textbin))
14926 debug_error("Pipeline is not in proper state\n");
14927 result = MM_ERROR_PLAYER_NOT_INITIALIZED;
14931 mainbin = player->pipeline->mainbin;
14932 textbin = player->pipeline->textbin;
14934 current_state = GST_STATE (mainbin[MMPLAYER_M_PIPE].gst);
14936 // sync clock with current pipeline
14937 curr_clock = GST_ELEMENT_CLOCK (player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
14938 curr_time = gst_clock_get_time (curr_clock);
14940 base_time = gst_element_get_base_time (GST_ELEMENT_CAST (player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
14941 start_time = gst_element_get_start_time (GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
14943 debug_log ("base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
14944 GST_TIME_ARGS (base_time), GST_TIME_ARGS (start_time), GST_TIME_ARGS (curr_time));
14946 if (current_state > GST_STATE_READY)
14948 // sync state with current pipeline
14949 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
14950 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
14951 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
14953 ret = gst_element_get_state (mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
14954 if ( GST_STATE_CHANGE_FAILURE == ret )
14956 debug_error("fail to state change.\n");
14960 gst_element_set_base_time (textbin[MMPLAYER_T_BIN].gst, base_time);
14961 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
14965 gst_element_set_clock (textbin[MMPLAYER_T_BIN].gst, curr_clock);
14966 gst_object_unref (curr_clock);
14969 // seek to current position
14970 if (!gst_element_query_position (mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time))
14972 result = MM_ERROR_PLAYER_INVALID_STATE;
14973 debug_error("gst_element_query_position failed, invalid state\n");
14977 debug_log("seek time = %lld\n", time);
14978 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);
14981 __gst_send_event_to_sink(player, event);
14985 result = MM_ERROR_PLAYER_INTERNAL;
14986 debug_error("gst_event_new_seek failed\n");
14990 // sync state with current pipeline
14991 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
14992 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
14993 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
15000 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
15002 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
15003 GstState current_state = GST_STATE_VOID_PENDING;
15005 MMHandleType attrs = 0;
15006 MMPlayerGstElement* mainbin = NULL;
15007 MMPlayerGstElement* textbin = NULL;
15009 gchar* subtitle_uri = NULL;
15010 int result = MM_ERROR_NONE;
15011 const gchar *charset = NULL;
15015 /* check player handle */
15016 return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
15017 return_val_if_fail( filepath, MM_ERROR_COMMON_INVALID_ARGUMENT );
15019 if (!(player->pipeline) || !(player->pipeline->mainbin))
15021 result = MM_ERROR_PLAYER_INVALID_STATE;
15022 debug_error("Pipeline is not in proper state\n");
15026 mainbin = player->pipeline->mainbin;
15027 textbin = player->pipeline->textbin;
15029 current_state = GST_STATE (mainbin[MMPLAYER_M_PIPE].gst);
15030 if (current_state < GST_STATE_READY)
15032 result = MM_ERROR_PLAYER_INVALID_STATE;
15033 debug_error("Pipeline is not in proper state\n");
15037 attrs = MMPLAYER_GET_ATTRS(player);
15040 debug_error("cannot get content attribute\n");
15041 result = MM_ERROR_PLAYER_INTERNAL;
15045 mm_attrs_get_string_by_name (attrs, "subtitle_uri", &subtitle_uri);
15046 if (!subtitle_uri || strlen(subtitle_uri) < 1)
15048 debug_error("subtitle uri is not proper filepath\n");
15049 result = MM_ERROR_PLAYER_INVALID_URI;
15053 debug_log("old subtitle file path is [%s]\n", subtitle_uri);
15054 debug_log("new subtitle file path is [%s]\n", filepath);
15056 if (!strcmp (filepath, subtitle_uri))
15058 debug_log("No need to swtich subtitle, as input filepath is same as current filepath\n");
15063 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
15064 if (mmf_attrs_commit(player->attrs))
15066 debug_error("failed to commit.\n");
15071 //gst_pad_set_blocked_async(src-srcpad, TRUE)
15073 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
15074 if (ret != GST_STATE_CHANGE_SUCCESS)
15076 debug_error("failed to change state of textbin to READY");
15077 result = MM_ERROR_PLAYER_INTERNAL;
15081 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
15082 if (ret != GST_STATE_CHANGE_SUCCESS)
15084 debug_error("failed to change state of subparse to READY");
15085 result = MM_ERROR_PLAYER_INTERNAL;
15089 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
15090 if (ret != GST_STATE_CHANGE_SUCCESS)
15092 debug_error("failed to change state of filesrc to READY");
15093 result = MM_ERROR_PLAYER_INTERNAL;
15097 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
15099 charset = util_get_charset(filepath);
15102 debug_log ("detected charset is %s\n", charset );
15103 g_object_set (G_OBJECT (mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
15106 result = _mmplayer_sync_subtitle_pipeline(player);
15113 /* API to switch between external subtitles */
15114 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
15116 int result = MM_ERROR_NONE;
15117 mm_player_t* player = (mm_player_t*)hplayer;
15121 /* check player handle */
15122 return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
15124 if (!player->pipeline) // IDLE state
15126 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
15127 if (mmf_attrs_commit(player->attrs))
15129 debug_error("failed to commit.\n");
15130 result= MM_ERROR_PLAYER_INTERNAL;
15133 else // curr state <> IDLE (READY, PAUSE, PLAYING..)
15135 if ( filepath == NULL )
15136 return MM_ERROR_COMMON_INVALID_ARGUMENT;
15138 if (!__mmplayer_check_subtitle(player))
15140 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
15141 if (mmf_attrs_commit(player->attrs))
15143 debug_error("failed to commit.\n");
15144 result = MM_ERROR_PLAYER_INTERNAL;
15147 if ( MM_ERROR_NONE != __mmplayer_gst_create_subtitle_src(player) )
15148 debug_error("fail to create subtitle src\n");
15150 result = _mmplayer_sync_subtitle_pipeline(player);
15154 result = __mmplayer_change_external_subtitle_language(player, filepath);
15163 __mmplayer_change_selector_pad (mm_player_t* player, MMPlayerTrackType type, int index)
15165 int result = MM_ERROR_NONE;
15166 gchar* change_pad_name = NULL;
15167 GstPad* sinkpad = NULL;
15168 MMPlayerGstElement* mainbin = NULL;
15169 enum MainElementID elemId = MMPLAYER_M_NUM;
15170 GstCaps* caps = NULL;
15171 gint total_track_num = 0;
15175 return_val_if_fail (player && player->pipeline && player->pipeline->mainbin,
15176 MM_ERROR_PLAYER_NOT_INITIALIZED);
15178 debug_log ("Change Track(%d) to %d\n", type, index);
15180 mainbin = player->pipeline->mainbin;
15182 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
15184 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
15186 else if (type == MM_PLAYER_TRACK_TYPE_TEXT)
15188 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
15192 debug_error ("Track Type Error\n");
15196 if (mainbin[elemId].gst == NULL)
15198 result = MM_ERROR_PLAYER_NO_OP;
15199 debug_log ("Req track doesn't exist\n");
15203 total_track_num = player->selector[type].total_track_num;
15204 if (total_track_num <= 0)
15206 result = MM_ERROR_PLAYER_NO_OP;
15207 debug_log ("Language list is not available \n");
15211 if ((index < 0) || (index >= total_track_num))
15213 result = MM_ERROR_INVALID_ARGUMENT;
15214 debug_log ("Not a proper index : %d \n", index);
15218 /*To get the new pad from the selector*/
15219 change_pad_name = g_strdup_printf ("sink_%u", index);
15220 if (change_pad_name == NULL)
15222 result = MM_ERROR_PLAYER_INTERNAL;
15223 debug_log ("Pad does not exists\n");
15227 debug_log ("new active pad name: %s\n", change_pad_name);
15229 sinkpad = gst_element_get_static_pad (mainbin[elemId].gst, change_pad_name);
15230 if (sinkpad == NULL)
15232 debug_log ("sinkpad is NULL");
15233 result = MM_ERROR_PLAYER_INTERNAL;
15237 debug_log ("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
15238 g_object_set (mainbin[elemId].gst, "active-pad", sinkpad, NULL);
15240 caps = gst_pad_get_current_caps(sinkpad);
15241 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
15244 gst_object_unref (sinkpad);
15246 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
15248 __mmplayer_set_audio_attrs (player, caps);
15253 MMPLAYER_FREEIF(change_pad_name);
15257 int _mmplayer_change_track_language (MMHandleType hplayer, MMPlayerTrackType type, int index)
15259 int result = MM_ERROR_NONE;
15260 mm_player_t* player = NULL;
15261 MMPlayerGstElement* mainbin = NULL;
15263 gint current_active_index = 0;
15265 GstState current_state = GST_STATE_VOID_PENDING;
15266 GstEvent* event = NULL;
15271 player = (mm_player_t*)hplayer;
15272 return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED);
15274 if (!player->pipeline)
15276 debug_error ("Track %d pre setting -> %d\n", type, index);
15278 player->selector[type].active_pad_index = index;
15282 mainbin = player->pipeline->mainbin;
15284 current_active_index = player->selector[type].active_pad_index;
15286 /*If index is same as running index no need to change the pad*/
15287 if (current_active_index == index)
15292 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time))
15294 result = MM_ERROR_PLAYER_INVALID_STATE;
15298 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
15299 if (current_state < GST_STATE_PAUSED)
15301 result = MM_ERROR_PLAYER_INVALID_STATE;
15302 debug_warning ("Pipeline not in porper state\n");
15306 result = __mmplayer_change_selector_pad(player, type, index);
15307 if (result != MM_ERROR_NONE)
15309 debug_error ("change selector pad error\n");
15313 player->selector[type].active_pad_index = index;
15315 if (current_state == GST_STATE_PLAYING)
15317 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);
15320 __gst_send_event_to_sink (player, event);
15324 result = MM_ERROR_PLAYER_INTERNAL;
15333 int _mmplayer_get_subtitle_silent (MMHandleType hplayer, int* silent)
15335 mm_player_t* player = (mm_player_t*) hplayer;
15339 /* check player handle */
15340 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED );
15342 *silent = player->set_mode.subtitle_off;
15344 debug_log("subtitle is %s.\n", silent ? "ON" : "OFF");
15348 return MM_ERROR_NONE;
15352 __is_es_buff_src( mm_player_t* player )
15354 return_val_if_fail ( player, FALSE );
15356 return ( player->profile.uri_type == MM_PLAYER_URI_TYPE_ES_BUFF) ? TRUE : FALSE;
15360 __has_suffix(mm_player_t* player, const gchar* suffix)
15362 return_val_if_fail( player, FALSE );
15363 return_val_if_fail( suffix, FALSE );
15365 gboolean ret = FALSE;
15366 gchar* t_url = g_ascii_strdown(player->profile.uri, -1);
15367 gchar* t_suffix = g_ascii_strdown(suffix, -1);
15369 if ( g_str_has_suffix(player->profile.uri, suffix) )
15374 MMPLAYER_FREEIF(t_url);
15375 MMPLAYER_FREEIF(t_suffix);
15381 _mmplayer_set_display_zoom(MMHandleType hplayer, float level, int x, int y)
15383 mm_player_t* player = (mm_player_t*) hplayer;
15385 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
15387 MMPLAYER_VIDEO_SINK_CHECK(player);
15389 debug_log("setting display zoom level = %f, offset = %d, %d", level, x, y);
15391 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "zoom", level, "zoom-pos-x", x, "zoom-pos-y", y, NULL);
15393 return MM_ERROR_NONE;
15396 _mmplayer_get_display_zoom(MMHandleType hplayer, float *level, int *x, int *y)
15399 mm_player_t* player = (mm_player_t*) hplayer;
15400 float _level = 0.0;
15404 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
15406 MMPLAYER_VIDEO_SINK_CHECK(player);
15408 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "zoom", &_level, "zoom-pos-x", &_x, "zoom-pos-y", &_y, NULL);
15410 debug_log("display zoom level = %f, start off x = %d, y = %d", _level, _x, _y);
15416 return MM_ERROR_NONE;
15420 _mmplayer_set_video_hub_download_mode(MMHandleType hplayer, bool mode)
15422 mm_player_t* player = (mm_player_t*) hplayer;
15424 return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED);
15426 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL)
15428 MMPLAYER_PRINT_STATE(player);
15429 debug_error("wrong-state : can't set the download mode to parse");
15430 return MM_ERROR_PLAYER_INVALID_STATE;
15433 debug_log("set video hub download mode to %s", (mode)?"ON":"OFF");
15434 player->video_hub_download_mode = mode;
15436 return MM_ERROR_NONE;
15440 _mmplayer_enable_sync_handler(MMHandleType hplayer, bool enable)
15442 mm_player_t* player = (mm_player_t*) hplayer;
15444 return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED);
15446 debug_log("enable sync handler : %s", (enable)?"ON":"OFF");
15447 player->sync_handler = enable;
15449 return MM_ERROR_NONE;
15453 _mmplayer_set_video_share_master_clock( MMHandleType hplayer,
15455 long long clock_delta,
15456 long long video_time,
15457 long long media_clock,
15458 long long audio_time)
15460 mm_player_t* player = (mm_player_t*) hplayer;
15461 MMPlayerGstElement* mainbin = NULL;
15462 GstClockTime start_time_audio = 0, start_time_video = 0;
15463 GstClockTimeDiff base_time = 0, new_base_time = 0;
15464 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
15465 gint64 api_delta = 0;
15466 gint64 position = 0, position_delta = 0;
15467 gint64 adj_base_time = 0;
15468 GstClock *curr_clock = NULL;
15469 GstClockTime curr_time = 0;
15470 gboolean query_ret = TRUE;
15471 int result = MM_ERROR_NONE;
15475 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
15476 return_val_if_fail ( player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
15477 return_val_if_fail ( player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
15479 // debug_log("in(us) : %lld, %lld, %lld, %lld, %lld", clock, clock_delta, video_time, media_clock, audio_time);
15481 if ((video_time < 0) || (player->doing_seek))
15483 debug_log("skip setting master clock. %lld", video_time);
15487 mainbin = player->pipeline->mainbin;
15489 curr_clock = gst_pipeline_get_clock (GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
15490 curr_time = gst_clock_get_time (curr_clock);
15492 current_state = MMPLAYER_CURRENT_STATE(player);
15494 if ( current_state == MM_PLAYER_STATE_PLAYING )
15495 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
15497 if ( ( current_state != MM_PLAYER_STATE_PLAYING ) ||
15500 position = player->last_position;
15501 debug_log ("query fail. %lld", position);
15504 clock*= GST_USECOND;
15505 clock_delta *= GST_USECOND;
15507 api_delta = clock - curr_time;
15508 if ((player->video_share_api_delta == 0 ) || (player->video_share_api_delta > api_delta))
15510 player->video_share_api_delta = api_delta;
15514 clock_delta += (api_delta - player->video_share_api_delta);
15517 if ((player->video_share_clock_delta == 0 ) || (player->video_share_clock_delta > clock_delta))
15519 player->video_share_clock_delta = (gint64)clock_delta;
15521 position_delta = (position/GST_USECOND) - video_time;
15522 position_delta *= GST_USECOND;
15524 adj_base_time = position_delta;
15525 debug_log ("video_share_clock_delta = %lld, adj = %lld", player->video_share_clock_delta, adj_base_time);
15530 gint64 new_play_time = 0;
15531 gint64 network_delay =0;
15533 video_time *= GST_USECOND;
15535 network_delay = clock_delta - player->video_share_clock_delta;
15536 new_play_time = video_time + network_delay;
15538 adj_base_time = position - new_play_time;
15540 debug_log ("%lld(delay) = %lld - %lld / %lld(adj) = %lld(slave_pos) - %lld(master_pos) - %lld(delay)",
15541 network_delay, clock_delta, player->video_share_clock_delta, adj_base_time, position, video_time, network_delay);
15544 /* Adjust Current Stream Time with base_time of sink
15545 * 1. Set Start time to CLOCK NONE, to control the base time by MSL
15546 * 2. Set new base time
15547 * if adj_base_time is positive value, the stream time will be decreased.
15548 * 3. If seek event is occurred, the start time will be reset. */
15549 if ((player->pipeline->audiobin) &&
15550 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst))
15552 start_time_audio = gst_element_get_start_time (player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
15554 if (start_time_audio != GST_CLOCK_TIME_NONE)
15556 debug_log ("audio sink : gst_element_set_start_time -> NONE");
15557 gst_element_set_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, GST_CLOCK_TIME_NONE);
15560 base_time = gst_element_get_base_time (player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
15563 if ((player->pipeline->videobin) &&
15564 (player->pipeline->videobin[MMPLAYER_V_SINK].gst))
15566 start_time_video = gst_element_get_start_time (player->pipeline->videobin[MMPLAYER_V_SINK].gst);
15568 if (start_time_video != GST_CLOCK_TIME_NONE)
15570 debug_log ("video sink : gst_element_set_start_time -> NONE");
15571 gst_element_set_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst, GST_CLOCK_TIME_NONE);
15574 // if videobin exist, get base_time from videobin.
15575 base_time = gst_element_get_base_time (player->pipeline->videobin[MMPLAYER_V_SINK].gst);
15578 new_base_time = base_time + adj_base_time;
15580 if ((player->pipeline->audiobin) &&
15581 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst))
15582 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), (GstClockTime)new_base_time);
15584 if ((player->pipeline->videobin) &&
15585 (player->pipeline->videobin[MMPLAYER_V_SINK].gst))
15586 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), (GstClockTime)new_base_time);
15595 _mmplayer_get_video_share_master_clock( MMHandleType hplayer,
15596 long long *video_time,
15597 long long *media_clock,
15598 long long *audio_time)
15600 mm_player_t* player = (mm_player_t*) hplayer;
15601 MMPlayerGstElement* mainbin = NULL;
15602 GstClock *curr_clock = NULL;
15603 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
15604 gint64 position = 0;
15605 gboolean query_ret = TRUE;
15609 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
15610 return_val_if_fail ( player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
15611 return_val_if_fail ( player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
15613 return_val_if_fail ( video_time, MM_ERROR_COMMON_INVALID_ARGUMENT );
15614 return_val_if_fail ( media_clock, MM_ERROR_COMMON_INVALID_ARGUMENT );
15615 return_val_if_fail ( audio_time, MM_ERROR_COMMON_INVALID_ARGUMENT );
15617 mainbin = player->pipeline->mainbin;
15619 curr_clock = gst_pipeline_get_clock (GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
15621 current_state = MMPLAYER_CURRENT_STATE(player);
15623 if ( current_state != MM_PLAYER_STATE_PAUSED )
15624 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
15626 if ( ( current_state == MM_PLAYER_STATE_PAUSED ) ||
15629 position = player->last_position;
15632 *media_clock = *video_time = *audio_time = (position/GST_USECOND);
15634 debug_log("media_clock: %lld, video_time: %lld (us)", *media_clock, *video_time);
15637 gst_object_unref (curr_clock);
15641 return MM_ERROR_NONE;
15645 _mmplayer_get_video_rotate_angle(MMHandleType hplayer, int *angle)
15647 mm_player_t* player = (mm_player_t*) hplayer;
15652 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
15653 return_val_if_fail ( angle, MM_ERROR_COMMON_INVALID_ARGUMENT );
15655 if (player->v_stream_caps)
15657 GstStructure *str = NULL;
15659 str = gst_caps_get_structure (player->v_stream_caps, 0);
15660 if ( !gst_structure_get_int (str, "orientation", &org_angle))
15662 debug_log ("missing 'orientation' field in video caps");
15666 debug_log("orientation: %d", org_angle);
15667 *angle = org_angle;
15670 return MM_ERROR_NONE;
15674 __mmplayer_is_streaming(mm_player_t* player)
15676 gboolean result = FALSE;
15680 return_val_if_fail (player, FALSE);
15681 result = __is_streaming (player) ;
15688 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
15690 return_val_if_fail (player, FALSE);
15691 return_val_if_fail (element, FALSE);
15693 gchar *factory_name = GST_OBJECT_NAME (gst_element_get_factory(element));
15694 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
15698 for ( idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++ )
15700 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx]))
15702 debug_log("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
15703 mm_player_dump_t *dump_s;
15704 dump_s = g_malloc (sizeof(mm_player_dump_t));
15706 if (dump_s == NULL)
15708 debug_error ("malloc fail");
15712 dump_s->dump_element_file = NULL;
15713 dump_s->dump_pad = NULL;
15714 dump_s->dump_pad = gst_element_get_static_pad (element, "sink");
15716 if (dump_s->dump_pad)
15718 memset (dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
15719 sprintf (dump_file_name, "%s/%s_sink_pad.dump", player->ini.dump_element_path, player->ini.dump_element_keyword[idx]);
15720 dump_s->dump_element_file = fopen(dump_file_name,"w+");
15721 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);
15722 /* add list for removed buffer probe and close FILE */
15723 player->dump_list = g_list_append (player->dump_list, dump_s);
15724 debug_log ("%s sink pad added buffer probe for dump", factory_name);
15731 debug_error ("failed to get %s sink pad added", factory_name);
15740 static GstPadProbeReturn
15741 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
15743 FILE *dump_data = (FILE *) u_data;
15744 // int written = 0;
15745 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
15746 GstMapInfo probe_info = GST_MAP_INFO_INIT;
15748 return_val_if_fail ( dump_data, FALSE );
15750 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
15752 // debug_log ("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS( GST_BUFFER_TIMESTAMP(buffer)));
15754 fwrite ( probe_info.data, 1, probe_info.size , dump_data);
15756 return GST_PAD_PROBE_OK;
15760 __mmplayer_release_dump_list (GList *dump_list)
15764 GList *d_list = dump_list;
15765 for ( ;d_list ; d_list = g_list_next(d_list))
15767 mm_player_dump_t *dump_s = d_list->data;
15768 if (dump_s->dump_pad)
15770 if (dump_s->probe_handle_id)
15772 gst_pad_remove_probe (dump_s->dump_pad, dump_s->probe_handle_id);
15776 if (dump_s->dump_element_file)
15778 fclose(dump_s->dump_element_file);
15779 dump_s->dump_element_file = NULL;
15781 MMPLAYER_FREEIF(dump_s);
15783 g_list_free(dump_list);
15789 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
15791 mm_player_t* player = (mm_player_t*) hplayer;
15795 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
15796 return_val_if_fail ( exist, MM_ERROR_INVALID_ARGUMENT );
15798 *exist = player->has_closed_caption;
15802 return MM_ERROR_NONE;
15806 _mmplayer_enable_media_packet_video_stream(MMHandleType hplayer, bool enable)
15808 mm_player_t* player = (mm_player_t*) hplayer;
15812 return_val_if_fail (player, MM_ERROR_PLAYER_NOT_INITIALIZED);
15813 return_val_if_fail (enable == TRUE || enable == FALSE, MM_ERROR_INVALID_ARGUMENT);
15815 player->bufmgr = tbm_bufmgr_init(-1);
15817 tbm_bufmgr_deinit(player->bufmgr);
15818 player->bufmgr = NULL;
15821 player->set_mode.media_packet_video_stream = enable;
15825 return MM_ERROR_NONE;
15828 void * _mm_player_media_packet_video_stream_internal_buffer_ref(void *buffer)
15832 /* increase ref count of gst buffer */
15834 ret = gst_buffer_ref((GstBuffer *)buffer);
15840 void _mm_player_media_packet_video_stream_internal_buffer_unref(void *buffer)
15844 gst_buffer_unref((GstBuffer *)buffer);
15851 __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data)
15853 mm_player_t *player = (mm_player_t*)user_data;
15854 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
15856 return_if_fail ( player );
15858 debug_msg("app-src: feed audio\n");
15860 if (player->media_stream_buffer_status_cb[type])
15862 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, player->buffer_cb_user_param);
15867 __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data)
15869 mm_player_t *player = (mm_player_t*)user_data;
15870 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
15872 return_if_fail ( player );
15874 debug_msg("app-src: feed video\n");
15876 if (player->media_stream_buffer_status_cb[type])
15878 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, player->buffer_cb_user_param);
15883 __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data)
15885 mm_player_t *player = (mm_player_t*)user_data;
15886 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
15888 return_if_fail ( player );
15890 debug_msg("app-src: feed subtitle\n");
15892 if (player->media_stream_buffer_status_cb[type])
15894 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, player->buffer_cb_user_param);
15899 __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data)
15901 mm_player_t *player = (mm_player_t*)user_data;
15902 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
15904 return_if_fail ( player );
15906 debug_msg("app-src: audio buffer is full.\n");
15908 if (player->media_stream_buffer_status_cb[type])
15910 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, player->buffer_cb_user_param);
15915 __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data)
15917 mm_player_t *player = (mm_player_t*)user_data;
15918 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
15920 return_if_fail ( player );
15922 debug_msg("app-src: video buffer is full.\n");
15924 if (player->media_stream_buffer_status_cb[type])
15926 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, player->buffer_cb_user_param);
15931 __gst_seek_audio_data (GstElement * appsrc, guint64 position, gpointer user_data)
15933 mm_player_t *player = (mm_player_t*)user_data;
15934 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
15936 return_val_if_fail( player, FALSE );
15938 debug_log("app-src: seek audio data\n");
15940 if (player->media_stream_seek_data_cb[type])
15942 player->media_stream_seek_data_cb[type](type, position, player->buffer_cb_user_param);
15949 __gst_seek_video_data (GstElement * appsrc, guint64 position, gpointer user_data)
15951 mm_player_t *player = (mm_player_t*)user_data;
15952 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
15954 return_val_if_fail( player, FALSE );
15956 debug_log("app-src: seek video data\n");
15958 if (player->media_stream_seek_data_cb[type])
15960 player->media_stream_seek_data_cb[type](type, position, player->buffer_cb_user_param);
15967 __gst_seek_subtitle_data (GstElement * appsrc, guint64 position, gpointer user_data)
15969 mm_player_t *player = (mm_player_t*)user_data;
15970 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
15972 return_val_if_fail( player, FALSE );
15974 debug_log("app-src: seek subtitle data\n");
15976 if (player->media_stream_seek_data_cb[type])
15978 player->media_stream_seek_data_cb[type](type, position, player->buffer_cb_user_param);
15985 _mmplayer_set_pcm_spec(MMHandleType hplayer, int samplerate, int channel)
15987 mm_player_t* player = (mm_player_t*) hplayer;
15991 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
15993 player->pcm_samplerate = samplerate;
15994 player->pcm_channel = channel;
15997 return MM_ERROR_NONE;
16000 int _mmplayer_get_raw_video_caps(mm_player_t *player, char **caps)
16002 GstCaps *v_caps = NULL;
16003 GstPad *pad = NULL;
16007 if(!player->videosink_linked) {
16008 debug_log("No video sink");
16009 return MM_ERROR_NONE;
16011 mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &stype);
16013 if (stype == MM_DISPLAY_SURFACE_NULL) {
16014 debug_log("Display type is NULL");
16015 if(!player->video_fakesink) {
16016 debug_error("No fakesink");
16017 return MM_ERROR_PLAYER_INVALID_STATE;
16019 gst = player->video_fakesink;
16022 if ( !player->pipeline || !player->pipeline->videobin ||
16023 !player->pipeline->videobin[MMPLAYER_V_SINK].gst ) {
16024 debug_error("No video pipeline");
16025 return MM_ERROR_PLAYER_INVALID_STATE;
16027 gst = player->pipeline->videobin[MMPLAYER_V_SINK].gst;
16029 pad = gst_element_get_static_pad(gst, "sink");
16031 debug_error("static pad is NULL");
16032 return MM_ERROR_PLAYER_INVALID_STATE;
16034 v_caps = gst_pad_get_current_caps(pad);
16035 gst_object_unref( pad );
16038 debug_error("fail to get caps");
16039 return MM_ERROR_PLAYER_INVALID_STATE;
16042 *caps = gst_caps_to_string(v_caps);
16044 gst_caps_unref(v_caps);
16046 return MM_ERROR_NONE;