[v0.6.27] Change FADEOUT_TIME_DEFAULT value to 0
[platform/core/multimedia/libmm-player.git] / src / mm_player_priv.c
1 /*
2  * libmm-player
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
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>
8  *
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
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
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.
20  *
21  */
22
23 /*===========================================================================================
24 |                                                                                                                                                                                       |
25 |  INCLUDE FILES                                                                                                                                                        |
26 |                                                                                                                                                                                       |
27 ========================================================================================== */
28 #include <glib.h>
29 #include <gst/gst.h>
30 #include <gst/app/gstappsrc.h>
31 #include <gst/video/videooverlay.h>
32 #include <gst/wayland/wayland.h>
33 #include <gst/audio/gstaudiobasesink.h>
34 #include <unistd.h>
35 #include <sys/stat.h>
36 #include <string.h>
37 #include <sys/time.h>
38 #include <stdlib.h>
39 #include <dlog.h>
40
41 #include <mm_error.h>
42 #include <mm_attrs.h>
43 #include <mm_attrs_private.h>
44 #include <mm_sound.h>
45 #include <mm_sound_focus.h>
46
47 #include "mm_player_priv.h"
48 #include "mm_player_ini.h"
49 #include "mm_player_attrs.h"
50 #include "mm_player_capture.h"
51 #include "mm_player_utils.h"
52 #include "mm_player_tracks.h"
53
54 #include <system_info.h>
55
56 /*===========================================================================================
57 |                                                                                                                                                                                       |
58 |  LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE                                                                                        |
59 |                                                                                                                                                                                       |
60 ========================================================================================== */
61
62 /*---------------------------------------------------------------------------
63 |    GLOBAL CONSTANT DEFINITIONS:                                                                                       |
64 ---------------------------------------------------------------------------*/
65
66 /*---------------------------------------------------------------------------
67 |    IMPORTED VARIABLE DECLARATIONS:                                                                            |
68 ---------------------------------------------------------------------------*/
69
70 /*---------------------------------------------------------------------------
71 |    IMPORTED FUNCTION DECLARATIONS:                                                                            |
72 ---------------------------------------------------------------------------*/
73
74 /*---------------------------------------------------------------------------
75 |    LOCAL #defines:                                                                                                            |
76 ---------------------------------------------------------------------------*/
77 #define TRICK_PLAY_MUTE_THRESHOLD_MAX   2.0
78 #define TRICK_PLAY_MUTE_THRESHOLD_MIN   0.0
79
80 #define MM_VOLUME_FACTOR_DEFAULT                1.0
81 #define MM_VOLUME_FACTOR_MIN                    0
82 #define MM_VOLUME_FACTOR_MAX                    1.0
83
84 /* Don't need to sleep for sound fadeout
85  * fadeout related fucntion will be deleted(Deprecated)
86  */
87 #define MM_PLAYER_FADEOUT_TIME_DEFAULT  0
88
89 #define MM_PLAYER_MPEG_VNAME                    "mpegversion"
90 #define MM_PLAYER_DIVX_VNAME                    "divxversion"
91 #define MM_PLAYER_WMV_VNAME                             "wmvversion"
92 #define MM_PLAYER_WMA_VNAME                             "wmaversion"
93
94 #define DEFAULT_PLAYBACK_RATE                   1.0
95 #define PLAYBACK_RATE_EX_AUDIO_MIN              0.5
96 #define PLAYBACK_RATE_EX_AUDIO_MAX              2.0
97 #define PLAYBACK_RATE_EX_VIDEO_MIN              0.5
98 #define PLAYBACK_RATE_EX_VIDEO_MAX              1.5
99 #define DEFAULT_NUM_OF_V_OUT_BUFFER             3
100
101 #define GST_QUEUE_DEFAULT_TIME                  4
102 #define GST_QUEUE_HLS_TIME                              8
103
104 #define MMPLAYER_USE_FILE_FOR_BUFFERING(player) \
105         (((player)->profile.uri_type != MM_PLAYER_URI_TYPE_HLS) && \
106         (player->ini.http_use_file_buffer) && \
107         (player->http_file_buffering_path) && \
108         (strlen(player->http_file_buffering_path) > 0))
109 #define MM_PLAYER_NAME  "mmplayer"
110
111 #define PLAYER_DISPLAY_MODE_DST_ROI             5
112
113 /*---------------------------------------------------------------------------
114 |    LOCAL CONSTANT DEFINITIONS:                                                                                        |
115 ---------------------------------------------------------------------------*/
116
117 /*---------------------------------------------------------------------------
118 |    LOCAL DATA TYPE DEFINITIONS:                                                                                       |
119 ---------------------------------------------------------------------------*/
120
121 /*---------------------------------------------------------------------------
122 |    GLOBAL VARIABLE DEFINITIONS:                                                                                       |
123 ---------------------------------------------------------------------------*/
124
125 /*---------------------------------------------------------------------------
126 |    LOCAL VARIABLE DEFINITIONS:                                                                                        |
127 ---------------------------------------------------------------------------*/
128
129 /*---------------------------------------------------------------------------
130 |    LOCAL FUNCTION PROTOTYPES:                                                                                         |
131 ---------------------------------------------------------------------------*/
132 static int              __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps *caps, MMDisplaySurfaceType surface_type);
133 static int              __mmplayer_gst_create_audio_pipeline(mm_player_t* player);
134 static int              __mmplayer_gst_create_text_pipeline(mm_player_t* player);
135 static int              __mmplayer_gst_create_subtitle_src(mm_player_t* player);
136 static int              __mmplayer_gst_create_pipeline(mm_player_t* player);
137 static int              __mmplayer_gst_destroy_pipeline(mm_player_t* player);
138 static int              __mmplayer_gst_element_link_bucket(GList* element_bucket);
139
140 static GstPadProbeReturn        __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data);
141 static void             __mmplayer_gst_decode_pad_added(GstElement* elem, GstPad* pad, gpointer data);
142 static void             __mmplayer_gst_decode_no_more_pads(GstElement* elem, gpointer data);
143 static void             __mmplayer_gst_decode_callback(GstElement *decodebin, GstPad *pad, gpointer data);
144 static void             __mmplayer_gst_decode_unknown_type(GstElement *elem,  GstPad* pad, GstCaps *caps, gpointer data);
145 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin,  GstPad* pad, GstCaps * caps,  gpointer data);
146 static gint             __mmplayer_gst_decode_autoplug_select(GstElement *bin,  GstPad* pad, GstCaps * caps, GstElementFactory* factory, gpointer data);
147 //static GValueArray* __mmplayer_gst_decode_autoplug_factories(GstElement *bin,  GstPad* pad, GstCaps * caps,  gpointer data);
148 static void __mmplayer_gst_decode_pad_removed(GstElement *elem,  GstPad* new_pad, gpointer data);
149 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
150 static void     __mmplayer_gst_element_added(GstElement* bin, GstElement* element, gpointer data);
151 static GstElement * __mmplayer_create_decodebin(mm_player_t* player);
152 static gboolean __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps);
153
154 static void     __mmplayer_typefind_have_type(GstElement *tf, guint probability, GstCaps *caps, gpointer data);
155 static gboolean __mmplayer_try_to_plug(mm_player_t* player, GstPad *pad, const GstCaps *caps);
156 static void     __mmplayer_pipeline_complete(GstElement *decodebin,  gpointer data);
157 static gboolean __mmplayer_is_midi_type(gchar* str_caps);
158 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
159 static void     __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps);
160 //static void   __mmplayer_check_video_zero_cpoy(mm_player_t* player, GstElementFactory* factory);
161
162 static gboolean __mmplayer_close_link(mm_player_t* player, GstPad *srcpad, GstElement *sinkelement, const char *padname, const GList *templlist);
163 static gboolean __mmplayer_feature_filter(GstPluginFeature *feature, gpointer data);
164 static void             __mmplayer_add_new_pad(GstElement *element, GstPad *pad, gpointer data);
165
166 static void             __mmplayer_gst_rtp_no_more_pads(GstElement *element,  gpointer data);
167 //static void    __mmplayer_gst_wfd_dynamic_pad(GstElement *element, GstPad *pad, gpointer data);
168 static void             __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data);
169 static gboolean __mmplayer_get_stream_service_type(mm_player_t* player);
170 static gboolean __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
171
172
173 static void             __mmplayer_init_factories(mm_player_t* player);
174 static void             __mmplayer_release_factories(mm_player_t* player);
175 static void             __mmplayer_release_misc(mm_player_t* player);
176 static void             __mmplayer_release_misc_post(mm_player_t* player);
177 static gboolean __mmplayer_init_gstreamer(mm_player_t* player);
178 static GstBusSyncReply __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data);
179 static gboolean __mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data);
180
181 static gboolean __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage *msg);
182 static gboolean      __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg);
183
184 int             __mmplayer_switch_audio_sink(mm_player_t* player);
185 static gboolean __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink);
186 static GstPadProbeReturn __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
187 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
188 static void __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
189 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
190 static int __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index);
191
192 static gboolean __mmplayer_check_subtitle(mm_player_t* player);
193 static gboolean __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message);
194 static void             __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms);
195 static void             __mmplayer_cancel_eos_timer(mm_player_t* player);
196 static gboolean __mmplayer_eos_timer_cb(gpointer u_data);
197 static gboolean __mmplayer_link_decoder(mm_player_t* player, GstPad *srcpad);
198 static gboolean __mmplayer_link_sink(mm_player_t* player, GstPad *srcpad);
199 static int              __mmplayer_handle_missed_plugin(mm_player_t* player);
200 static int              __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime);
201 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player);
202 static void             __mmplayer_add_sink(mm_player_t* player, GstElement* sink);
203 static void             __mmplayer_del_sink(mm_player_t* player, GstElement* sink);
204 static void             __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type);
205 static gpointer __mmplayer_next_play_thread(gpointer data);
206 static gpointer __mmplayer_repeat_thread(gpointer data);
207 static gboolean _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag);
208
209
210 static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element);
211 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad,  GstPadProbeInfo *info, gpointer u_data);
212 static void __mmplayer_release_dump_list(GList *dump_list);
213
214 static int              __gst_realize(mm_player_t* player);
215 static int              __gst_unrealize(mm_player_t* player);
216 static int              __gst_start(mm_player_t* player);
217 static int              __gst_stop(mm_player_t* player);
218 static int              __gst_pause(mm_player_t* player, gboolean async);
219 static int              __gst_resume(mm_player_t* player, gboolean async);
220 static gboolean __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
221                                         GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
222                                         gint64 cur, GstSeekType stop_type, gint64 stop);
223 static int __gst_pending_seek(mm_player_t* player);
224
225 static int              __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called);
226 static int              __gst_get_position(mm_player_t* player, int format, unsigned long *position);
227 static int              __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos);
228 static int              __gst_adjust_subtitle_position(mm_player_t* player, int format, int position);
229 static int              __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param);
230
231 static gboolean __gst_send_event_to_sink(mm_player_t* player, GstEvent* event);
232
233 static int __mmplayer_set_pcm_extraction(mm_player_t* player);
234 static gboolean __mmplayer_can_extract_pcm(mm_player_t* player);
235
236 /*fadeout */
237 static void __mmplayer_do_sound_fadedown(mm_player_t* player, unsigned int time);
238 static void __mmplayer_undo_sound_fadedown(mm_player_t* player);
239
240 static void     __mmplayer_add_new_caps(GstPad* pad, GParamSpec* unused, gpointer data);
241 static void __mmplayer_set_unlinked_mime_type(mm_player_t* player, GstCaps *caps);
242
243 /* util */
244 static gboolean __is_ms_buff_src(mm_player_t* player);
245 static gboolean __has_suffix(mm_player_t * player, const gchar * suffix);
246
247 static int __mmplayer_realize_streaming_ext(mm_player_t* player);
248 static int __mmplayer_unrealize_streaming_ext(mm_player_t *player);
249 static int __mmplayer_start_streaming_ext(mm_player_t *player);
250 static int __mmplayer_destroy_streaming_ext(mm_player_t* player);
251 static int __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay);
252
253 static gboolean __mmplayer_verify_next_play_path(mm_player_t *player);
254 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
255 static void __mmplayer_check_pipeline(mm_player_t* player);
256 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
257 static void __mmplayer_deactivate_old_path(mm_player_t *player);
258 #if 0 // We'll need this in future.
259 static int __mmplayer_gst_switching_element(mm_player_t *player, GstElement *search_from, const gchar *removal_name, const gchar *new_element_name);
260 #endif
261
262 static void __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg);
263 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name);
264
265 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player);
266 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name);
267 static void             __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data);
268 static void             __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data);
269 static void     __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data);
270 static void             __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data);
271 static void             __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data);
272 static gboolean __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data);
273 static gboolean __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data);
274 static gboolean __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data);
275 static void             __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data);
276 static void             __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all);
277 static void             __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer);
278
279 /*===========================================================================================
280 |                                                                                                                                                                                       |
281 |  FUNCTION DEFINITIONS                                                                                                                                         |
282 |                                                                                                                                                                                       |
283 ========================================================================================== */
284
285 #if 0 //debug
286 static void
287 print_tag(const GstTagList * list, const gchar * tag, gpointer unused)
288 {
289         gint i, count;
290
291         count = gst_tag_list_get_tag_size(list, tag);
292
293         LOGD("count = %d", count);
294
295         for (i = 0; i < count; i++) {
296                 gchar *str;
297
298                 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
299                         if (!gst_tag_list_get_string_index(list, tag, i, &str))
300                                 g_assert_not_reached();
301                 } else
302                         str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
303
304                 if (i == 0)
305                         g_print("  %15s: %s\n", gst_tag_get_nick(tag), str);
306                 else
307                         g_print("                 : %s\n", str);
308
309                 g_free(str);
310         }
311 }
312 #endif
313
314 /* This function should be called after the pipeline goes PAUSED or higher
315 state. */
316 gboolean
317 _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag) // @
318 {
319         static gboolean has_duration = FALSE;
320         static gboolean has_video_attrs = FALSE;
321         static gboolean has_audio_attrs = FALSE;
322         static gboolean has_bitrate = FALSE;
323         gboolean missing_only = FALSE;
324         gboolean all = FALSE;
325         gint64 dur_nsec = 0;
326         GstStructure* p = NULL;
327         MMHandleType attrs = 0;
328         gchar *path = NULL;
329         gint stream_service_type = STREAMING_SERVICE_NONE;
330         struct stat sb;
331
332         MMPLAYER_FENTER();
333
334         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
335
336         /* check player state here */
337         if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
338                 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
339                 /* give warning now only */
340                 LOGW("be careful. content attributes may not available in this state ");
341         }
342
343         /* get content attribute first */
344         attrs = MMPLAYER_GET_ATTRS(player);
345         if (!attrs) {
346                 LOGE("cannot get content attribute");
347                 return FALSE;
348         }
349
350         /* get update flag */
351
352         if (flag & ATTR_MISSING_ONLY) {
353                 missing_only = TRUE;
354                 LOGD("updating missed attr only");
355         }
356
357         if (flag & ATTR_ALL) {
358                 all = TRUE;
359                 has_duration = FALSE;
360                 has_video_attrs = FALSE;
361                 has_audio_attrs = FALSE;
362                 has_bitrate = FALSE;
363
364                 LOGD("updating all attrs");
365         }
366
367         if (missing_only && all) {
368                 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
369                 missing_only = FALSE;
370         }
371
372         if ((flag & ATTR_DURATION) ||   (!has_duration && missing_only) || all) {
373                 LOGD("try to update duration");
374                 has_duration = FALSE;
375
376                 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
377                         player->duration = dur_nsec;
378                         LOGW("duration : %lld msec", GST_TIME_AS_MSECONDS(dur_nsec));
379                 }
380
381                 if (player->duration < 0) {
382                         LOGW("duration : %lld is Non-Initialized !!! \n",player->duration);
383                         player->duration = 0;
384                 }
385
386                 /* try to get streaming service type */
387                 stream_service_type = __mmplayer_get_stream_service_type(player);
388                 mm_attrs_set_int_by_name(attrs, "streaming_type", stream_service_type);
389
390                 /* check duration is OK */
391                 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player)) {
392                         /* FIXIT : find another way to get duration here. */
393                         LOGE("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
394                 } else {
395                         /*update duration */
396                         mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(dur_nsec));
397                         has_duration = TRUE;
398                 }
399         }
400
401         if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all) {
402                 /* update audio params
403                 NOTE : We need original audio params and it can be only obtained from src pad of audio
404                 decoder. Below code only valid when we are not using 'resampler' just before
405                 'audioconverter'. */
406
407                 LOGD("try to update audio attrs");
408                 has_audio_attrs = FALSE;
409
410                 if (player->pipeline->audiobin &&
411                          player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
412                         GstCaps *caps_a = NULL;
413                         GstPad* pad = NULL;
414                         gint samplerate = 0, channels = 0;
415
416                         pad = gst_element_get_static_pad(
417                                         player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
418
419                         if (pad) {
420                                 caps_a = gst_pad_get_current_caps(pad);
421
422                                 if (caps_a) {
423                                         p = gst_caps_get_structure(caps_a, 0);
424
425                                         mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
426
427                                         gst_structure_get_int(p, "rate", &samplerate);
428                                         mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
429
430                                         gst_structure_get_int(p, "channels", &channels);
431                                         mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
432
433                                         SECURE_LOGD("samplerate : %d    channels : %d", samplerate, channels);
434
435                                         gst_caps_unref(caps_a);
436                                         caps_a = NULL;
437
438                                         has_audio_attrs = TRUE;
439                                 } else
440                                         LOGW("not ready to get audio caps");
441
442                                 gst_object_unref(pad);
443                         } else
444                                 LOGW("failed to get pad from audiosink");
445                 }
446         }
447
448         if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all) {
449                 LOGD("try to update video attrs");
450                 has_video_attrs = FALSE;
451
452                 if (player->pipeline->videobin &&
453                          player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
454                         GstCaps *caps_v = NULL;
455                         GstPad* pad = NULL;
456                         gint tmpNu, tmpDe;
457                         gint width, height;
458
459                         pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
460                         if (pad) {
461                                 caps_v = gst_pad_get_current_caps(pad);
462
463                                 /* Use v_stream_caps, if fail to get video_sink sink pad*/
464                                 if (!caps_v && player->v_stream_caps) {
465                                         caps_v = player->v_stream_caps;
466                                         gst_caps_ref(caps_v);
467                                 }
468
469                                 if (caps_v) {
470                                         p = gst_caps_get_structure(caps_v, 0);
471                                         gst_structure_get_int(p, "width", &width);
472                                         mm_attrs_set_int_by_name(attrs, "content_video_width", width);
473
474                                         gst_structure_get_int(p, "height", &height);
475                                         mm_attrs_set_int_by_name(attrs, "content_video_height", height);
476
477                                         gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
478
479                                         SECURE_LOGD("width : %d     height : %d", width, height);
480
481                                         gst_caps_unref(caps_v);
482                                         caps_v = NULL;
483
484                                         if (tmpDe > 0) {
485                                                 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
486                                                 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
487                                         }
488
489                                         has_video_attrs = TRUE;
490                                 } else
491                                         LOGD("no negitiated caps from videosink");
492                                 gst_object_unref(pad);
493                                 pad = NULL;
494                         } else
495                                 LOGD("no videosink sink pad");
496                 }
497         }
498
499
500         if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all) {
501                 has_bitrate = FALSE;
502
503                 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
504                 if (player->duration) {
505                         guint64 data_size = 0;
506
507                         if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
508                                 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
509
510                                 if (stat(path, &sb) == 0)
511                                         data_size = (guint64)sb.st_size;
512                         } else if (MMPLAYER_IS_HTTP_STREAMING(player))
513                                 data_size = player->http_content_size;
514                         LOGD("try to update bitrate : data_size = %lld", data_size);
515
516                         if (data_size) {
517                                 guint64 bitrate = 0;
518                                 guint64 msec_dur = 0;
519
520                                 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
521                                 bitrate = data_size * 8 * 1000 / msec_dur;
522                                 SECURE_LOGD("file size : %u, video bitrate = %llu", data_size, bitrate);
523                                 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
524
525                                 has_bitrate = TRUE;
526                         }
527
528                         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
529                                 if (player->total_bitrate) {
530                                         mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
531                                         has_bitrate = TRUE;
532                                 }
533                         }
534                 }
535         }
536
537         /* validate all */
538         if (mmf_attrs_commit(attrs)) {
539                 LOGE("failed to update attributes\n");
540                 return FALSE;
541         }
542
543         MMPLAYER_FLEAVE();
544
545         return TRUE;
546 }
547
548 static gboolean __mmplayer_get_stream_service_type(mm_player_t* player)
549 {
550         gint streaming_type = STREAMING_SERVICE_NONE;
551
552         MMPLAYER_FENTER();
553
554         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
555                         player->pipeline &&
556                         player->pipeline->mainbin &&
557                         player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
558                         FALSE);
559
560         /* streaming service type if streaming */
561         if (!MMPLAYER_IS_STREAMING(player))
562                 return STREAMING_SERVICE_NONE;
563
564         if (MMPLAYER_IS_HTTP_STREAMING(player))
565                 streaming_type = (player->duration == 0) ?
566                         STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
567
568         switch (streaming_type) {
569         case STREAMING_SERVICE_LIVE:
570                 LOGD("it's live streaming");
571                 break;
572         case STREAMING_SERVICE_VOD:
573                 LOGD("it's vod streaming");
574                 break;
575         default:
576                 LOGE("should not get here");
577         }
578
579         player->streaming_type = streaming_type;
580         MMPLAYER_FLEAVE();
581
582         return streaming_type;
583 }
584
585
586 /* this function sets the player state and also report
587  * it to applicaton by calling callback function
588  */
589 int
590 __mmplayer_set_state(mm_player_t* player, int state) // @
591 {
592         MMMessageParamType msg = {0, };
593         int sound_result = MM_ERROR_NONE;
594         gboolean post_bos = FALSE;
595         gboolean interrupted_by_focus = FALSE;
596         gboolean interrupted_by_resource = FALSE;
597         int ret = MM_ERROR_NONE;
598
599         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
600
601         if (MMPLAYER_CURRENT_STATE(player) == state) {
602                 LOGW("already same state(%s)\n", MMPLAYER_STATE_GET_NAME(state));
603                 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
604                 return ret;
605         }
606
607         /* update player states */
608         MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
609         MMPLAYER_CURRENT_STATE(player) = state;
610
611         /* FIXIT : it's better to do like below code
612         if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_TARGET_STATE(player))
613                         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
614         and add more code to handling PENDING_STATE.
615         */
616         if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
617                 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
618
619         /* print state */
620         MMPLAYER_PRINT_STATE(player);
621
622         /* do some FSM stuffs before posting new state to application  */
623         interrupted_by_focus = player->sound_focus.by_asm_cb;
624         interrupted_by_resource = player->resource_manager.by_rm_cb;
625
626         switch (MMPLAYER_CURRENT_STATE(player)) {
627         case MM_PLAYER_STATE_NULL:
628         case MM_PLAYER_STATE_READY:
629                 {
630                         if (player->cmd == MMPLAYER_COMMAND_STOP) {
631                                 sound_result = _mmplayer_sound_release_focus(&player->sound_focus);
632                                 if (sound_result != MM_ERROR_NONE) {
633                                         LOGE("failed to release sound focus\n");
634                                         return MM_ERROR_POLICY_INTERNAL;
635                                 }
636                         }
637                 }
638                 break;
639
640         case MM_PLAYER_STATE_PAUSED:
641                 {
642                          if (!player->sent_bos) {
643                                 int found = 0;
644                                 #define MMPLAYER_MAX_SOUND_PRIORITY     3
645
646                                 /* rtsp case, get content attrs by GstMessage */
647                                 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
648                                         /* it's first time to update all content attrs. */
649                                         _mmplayer_update_content_attrs( player, ATTR_ALL );
650                                 }
651
652                                 /* set max sound priority to keep own sound and not to mute other's one */
653                                 mm_attrs_get_int_by_name(player->attrs, "content_video_found", &found);
654                                 if (found) {
655                                         mm_attrs_get_int_by_name(player->attrs, "content_audio_found", &found);
656                                         if (found) {
657                                                 LOGD("set max audio priority");
658                                                 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "priority", MMPLAYER_MAX_SOUND_PRIORITY, NULL);
659                                         }
660                                 }
661
662                          }
663
664                         /* add audio callback probe if condition is satisfied */
665                         if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
666                                 __mmplayer_configure_audio_callback(player);
667                                 /* FIXIT : handle return value */
668
669                         if (!MMPLAYER_IS_STREAMING(player) || (player->streamer && !player->streamer->is_buffering)) {
670                                 sound_result = _mmplayer_sound_release_focus(&player->sound_focus);
671                                 if (sound_result != MM_ERROR_NONE) {
672                                         LOGE("failed to release sound focus\n");
673                                         return MM_ERROR_POLICY_INTERNAL;
674                                 }
675                         }
676                 }
677                 break;
678
679         case MM_PLAYER_STATE_PLAYING:
680                 {
681                         /* try to get content metadata */
682                         if (!player->sent_bos) {
683                                 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
684                                  * c-api since c-api doesn't use _start() anymore. It may not work propery with
685                                  * legacy mmfw-player api */
686                                 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
687                         }
688
689                         if ((player->cmd == MMPLAYER_COMMAND_START) || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
690                                 if (!player->sent_bos)
691                                         __mmplayer_handle_missed_plugin(player);
692                                 sound_result = _mmplayer_sound_acquire_focus(&player->sound_focus);
693                                 if (sound_result != MM_ERROR_NONE) {
694                                         // FIXME : need to check history
695                                         if (player->pipeline->videobin) {
696                                                 MMMessageParamType msg = {0, };
697
698                                                 LOGE("failed to go ahead because of video conflict\n");
699
700                                                 msg.union_type = MM_MSG_UNION_CODE;
701                                                 msg.code = MM_ERROR_POLICY_INTERRUPTED;
702                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
703
704                                                 _mmplayer_unrealize((MMHandleType)player);
705                                         } else {
706                                                 LOGE("failed to play by sound focus error : 0x%X\n", sound_result);
707                                                 _mmplayer_pause((MMHandleType)player);
708                                                 return sound_result;
709                                         }
710
711                                         return MM_ERROR_POLICY_INTERNAL;
712                                 }
713                         }
714
715                         if (player->resumed_by_rewind && player->playback_rate < 0.0) {
716                                 /* initialize because auto resume is done well. */
717                                 player->resumed_by_rewind = FALSE;
718                                 player->playback_rate = 1.0;
719                         }
720
721                         if (!player->sent_bos) {
722                                 /* check audio codec field is set or not
723                                  * we can get it from typefinder or codec's caps.
724                                  */
725                                 gchar *audio_codec = NULL;
726                                 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
727
728                                 /* The codec format can't be sent for audio only case like amr, mid etc.
729                                  * Because, parser don't make related TAG.
730                                  * So, if it's not set yet, fill it with found data.
731                                  */
732                                 if (!audio_codec) {
733                                         if (g_strrstr(player->type, "audio/midi"))
734                                                 audio_codec = g_strdup("MIDI");
735                                         else if (g_strrstr(player->type, "audio/x-amr"))
736                                                 audio_codec = g_strdup("AMR");
737                                         else if (g_strrstr(player->type, "audio/mpeg") && !g_strrstr(player->type, "mpegversion= (int)1"))
738                                                 audio_codec = g_strdup("AAC");
739                                         else
740                                                 audio_codec = g_strdup("unknown");
741                                         mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
742
743                                         MMPLAYER_FREEIF(audio_codec);
744                                         mmf_attrs_commit(player->attrs);
745                                         LOGD("set audio codec type with caps\n");
746                                 }
747
748                                 post_bos = TRUE;
749                         }
750                 }
751                 break;
752
753         case MM_PLAYER_STATE_NONE:
754         default:
755                 LOGW("invalid target state, there is nothing to do.\n");
756                 break;
757         }
758
759
760         /* post message to application */
761         if (MMPLAYER_TARGET_STATE(player) == state) {
762                 /* fill the message with state of player */
763                 msg.state.previous = MMPLAYER_PREV_STATE(player);
764                 msg.state.current = MMPLAYER_CURRENT_STATE(player);
765
766                 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
767
768                 /* state changed by focus or resource callback */
769                 if (interrupted_by_focus || interrupted_by_resource) {
770                         msg.union_type = MM_MSG_UNION_CODE;
771                         if (interrupted_by_focus)
772                                 msg.code = player->sound_focus.focus_changed_msg;
773                         else if (interrupted_by_resource)
774                                 msg.code = MM_PLAYER_FOCUS_CHANGED_BY_RESOURCE_CONFLICT;
775                         MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
776                 } else /* state changed by usecase */
777                         MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
778         } else {
779                 LOGD("intermediate state, do nothing.\n");
780                 MMPLAYER_PRINT_STATE(player);
781                 return ret;
782         }
783
784         if (post_bos) {
785                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
786                 player->sent_bos = TRUE;
787         }
788
789         return ret;
790 }
791
792 static gpointer __mmplayer_next_play_thread(gpointer data)
793 {
794         mm_player_t* player = (mm_player_t*) data;
795         MMPlayerGstElement *mainbin = NULL;
796
797         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
798
799         MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
800         while (!player->next_play_thread_exit) {
801                 LOGD("next play thread started. waiting for signal.\n");
802                 MMPLAYER_NEXT_PLAY_THREAD_WAIT(player);
803
804                 LOGD("reconfigure pipeline for gapless play.\n");
805
806                 if (player->next_play_thread_exit) {
807                         if (player->gapless.reconfigure) {
808                                 player->gapless.reconfigure = false;
809                                 MMPLAYER_PLAYBACK_UNLOCK(player);
810                         }
811                         LOGD("exiting gapless play thread\n");
812                         break;
813                 }
814
815                 mainbin = player->pipeline->mainbin;
816
817                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
818                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
819                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
820                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
821                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
822
823                 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
824         }
825         MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
826
827         return NULL;
828 }
829
830 static gpointer __mmplayer_repeat_thread(gpointer data)
831 {
832         mm_player_t* player = (mm_player_t*) data;
833         gboolean ret_value = FALSE;
834         MMHandleType attrs = 0;
835         gint count = 0;
836
837         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
838
839         MMPLAYER_REPEAT_THREAD_LOCK(player);
840         while (!player->repeat_thread_exit) {
841                 LOGD("repeat thread started. waiting for signal.\n");
842                 MMPLAYER_REPEAT_THREAD_WAIT(player);
843
844                 if (player->repeat_thread_exit) {
845                         LOGD("exiting repeat thread\n");
846                         break;
847                 }
848
849
850                 /* lock */
851                 MMPLAYER_CMD_LOCK(player);
852
853                 attrs = MMPLAYER_GET_ATTRS(player);
854
855                 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE) {
856                         LOGE("can not get play count\n");
857                         MMPLAYER_CMD_UNLOCK(player);
858                         break;
859                 }
860
861                 if (player->section_repeat) {
862                         ret_value = _mmplayer_activate_section_repeat((MMHandleType)player, player->section_repeat_start, player->section_repeat_end);
863                 } else {
864                         if (player->playback_rate < 0.0) {
865                                 player->resumed_by_rewind = TRUE;
866                                 _mmplayer_set_mute((MMHandleType)player, 0);
867                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
868                         }
869
870                         ret_value = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
871                                 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET,
872                                 0, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
873
874                         /* initialize */
875                         player->sent_bos = FALSE;
876                 }
877
878                 if (!ret_value) {
879                         LOGE("failed to set position to zero for rewind\n");
880                         MMPLAYER_CMD_UNLOCK(player);
881                         continue;
882                 }
883
884                 /* decrease play count */
885                 if (count > 1) {
886                         /* we successeded to rewind. update play count and then wait for next EOS */
887                         count--;
888
889                         mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
890
891                         /* commit attribute */
892                         if (mmf_attrs_commit(attrs))
893                                 LOGE("failed to commit attribute\n");
894                 }
895
896                 /* unlock */
897                 MMPLAYER_CMD_UNLOCK(player);
898         }
899
900         MMPLAYER_REPEAT_THREAD_UNLOCK(player);
901         return NULL;
902 }
903
904 static void
905 __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg)
906 {
907         MMHandleType attrs = 0;
908         guint64 data_size = 0;
909         gchar* path = NULL;
910         unsigned long pos_msec = 0;
911         struct stat sb;
912
913         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
914
915         __gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &pos_msec);       // update last_position
916
917         attrs = MMPLAYER_GET_ATTRS(player);
918         if (!attrs) {
919                 LOGE("fail to get attributes.\n");
920                 return;
921         }
922
923         if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
924                 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
925
926                 if (stat(path, &sb) == 0)
927                         data_size = (guint64)sb.st_size;
928         } else if (MMPLAYER_IS_HTTP_STREAMING(player))
929                 data_size = player->http_content_size;
930
931         __mm_player_streaming_buffering(player->streamer,
932                                                                                 buffering_msg,
933                                                                                 data_size,
934                                                                                 player->last_position,
935                                                                                 player->duration);
936
937         __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
938
939         return;
940 }
941
942 static int
943 __mmplayer_handle_buffering_message(mm_player_t* player)
944 {
945         int ret = MM_ERROR_NONE;
946         MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
947         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
948         MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
949         MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
950
951         if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
952                 LOGW("do nothing for buffering msg\n");
953                 ret = MM_ERROR_PLAYER_INVALID_STATE;
954                 goto exit;
955         }
956
957         prev_state = MMPLAYER_PREV_STATE(player);
958         current_state = MMPLAYER_CURRENT_STATE(player);
959         target_state = MMPLAYER_TARGET_STATE(player);
960         pending_state = MMPLAYER_PENDING_STATE(player);
961
962         LOGD("player state : prev %s, current %s, pending %s, target %s, buffering %d",
963                 MMPLAYER_STATE_GET_NAME(prev_state),
964                 MMPLAYER_STATE_GET_NAME(current_state),
965                 MMPLAYER_STATE_GET_NAME(pending_state),
966                 MMPLAYER_STATE_GET_NAME(target_state),
967                 player->streamer->is_buffering);
968
969         if (!player->streamer->is_buffering) {
970                 /* NOTE : if buffering has done, player has to go to target state. */
971                 switch (target_state) {
972                 case MM_PLAYER_STATE_PAUSED:
973                         {
974                                 switch (pending_state) {
975                                 case MM_PLAYER_STATE_PLAYING:
976                                         __gst_pause(player, TRUE);
977                                         break;
978
979                                 case MM_PLAYER_STATE_PAUSED:
980                                         LOGD("player is already going to paused state, there is nothing to do.\n");
981                                         break;
982
983                                 case MM_PLAYER_STATE_NONE:
984                                 case MM_PLAYER_STATE_NULL:
985                                 case MM_PLAYER_STATE_READY:
986                                 default:
987                                         LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
988                                         break;
989                                 }
990                         }
991                         break;
992
993                 case MM_PLAYER_STATE_PLAYING:
994                         {
995                                 switch (pending_state) {
996                                 case MM_PLAYER_STATE_NONE:
997                                         {
998                                                 if (current_state != MM_PLAYER_STATE_PLAYING)
999                                                         __gst_resume(player, TRUE);
1000                                         }
1001                                         break;
1002
1003                                 case MM_PLAYER_STATE_PAUSED:
1004                                         /* NOTE: It should be worked as asynchronously.
1005                                          * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
1006                                          */
1007                                         __gst_resume(player, TRUE);
1008                                         break;
1009
1010                                 case MM_PLAYER_STATE_PLAYING:
1011                                         LOGD("player is already going to playing state, there is nothing to do.\n");
1012                                         break;
1013
1014                                 case MM_PLAYER_STATE_NULL:
1015                                 case MM_PLAYER_STATE_READY:
1016                                 default:
1017                                         LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1018                                         break;
1019                                 }
1020                         }
1021                         break;
1022
1023                 case MM_PLAYER_STATE_NULL:
1024                 case MM_PLAYER_STATE_READY:
1025                 case MM_PLAYER_STATE_NONE:
1026                 default:
1027                         LOGW("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state));
1028                         break;
1029                 }
1030         } else {
1031                 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1032                  *      it's for stopping the pipeline clock to prevent dropping the data in sink element.
1033                  */
1034                 switch (pending_state) {
1035                 case MM_PLAYER_STATE_NONE:
1036                         {
1037                                 if (current_state != MM_PLAYER_STATE_PAUSED) {
1038                                         /* rtsp streaming pause makes rtsp server stop sending data. */
1039                                         if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1040                                                 LOGD("set pause state during buffering\n");
1041                                                 __gst_pause( player, TRUE );
1042                                         }
1043                                 }
1044                         }
1045                         break;
1046
1047                 case MM_PLAYER_STATE_PLAYING:
1048                         /* rtsp streaming pause makes rtsp server stop sending data. */
1049                         if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1050                                 __gst_pause ( player, TRUE );
1051                         }
1052                         break;
1053
1054                 case MM_PLAYER_STATE_PAUSED:
1055                         break;
1056
1057                 case MM_PLAYER_STATE_NULL:
1058                 case MM_PLAYER_STATE_READY:
1059                 default:
1060                         LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1061                         break;
1062                 }
1063         }
1064
1065 exit:
1066         return ret;
1067 }
1068
1069 static void
1070 __mmplayer_drop_subtitle(mm_player_t* player, gboolean is_drop)
1071 {
1072         MMPlayerGstElement *textbin;
1073         MMPLAYER_FENTER();
1074
1075         MMPLAYER_RETURN_IF_FAIL(player &&
1076                                         player->pipeline &&
1077                                         player->pipeline->textbin);
1078
1079         MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1080
1081         textbin = player->pipeline->textbin;
1082
1083         if (is_drop) {
1084                 LOGD("Drop subtitle text after getting EOS\n");
1085
1086                 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", FALSE, NULL);
1087                 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
1088
1089                 player->is_subtitle_force_drop = TRUE;
1090         } else {
1091                 if (player->is_subtitle_force_drop == TRUE) {
1092                         LOGD("Enable subtitle data path without drop\n");
1093
1094                         g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
1095                         g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", TRUE, NULL);
1096
1097                         LOGD("non-connected with external display");
1098
1099                         player->is_subtitle_force_drop = FALSE;
1100                 }
1101         }
1102 }
1103
1104 static gboolean
1105 __mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data) // @
1106 {
1107         mm_player_t* player = (mm_player_t*) data;
1108         gboolean ret = TRUE;
1109         static gboolean async_done = FALSE;
1110
1111         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1112         MMPLAYER_RETURN_VAL_IF_FAIL(msg && GST_IS_MESSAGE(msg), FALSE);
1113
1114         switch (GST_MESSAGE_TYPE(msg)) {
1115         case GST_MESSAGE_UNKNOWN:
1116                 LOGD("unknown message received\n");
1117                 break;
1118
1119         case GST_MESSAGE_EOS:
1120                 {
1121                         MMHandleType attrs = 0;
1122                         gint count = 0;
1123
1124                         LOGD("GST_MESSAGE_EOS received\n");
1125
1126                         /* NOTE : EOS event is comming multiple time. watch out it */
1127                         /* check state. we only process EOS when pipeline state goes to PLAYING */
1128                         if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1129                                 LOGD("EOS received on non-playing state. ignoring it\n");
1130                                 break;
1131                         }
1132
1133                         if (player->pipeline) {
1134                                 if (player->pipeline->textbin)
1135                                         __mmplayer_drop_subtitle(player, TRUE);
1136
1137                                 if ((player->audio_stream_cb) && (player->set_mode.pcm_extraction) && (!player->audio_stream_render_cb_ex)) {
1138                                         GstPad *pad = NULL;
1139
1140                                         pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
1141
1142                                         LOGD("release audio callback\n");
1143
1144                                         /* release audio callback */
1145                                         gst_pad_remove_probe(pad, player->audio_cb_probe_id);
1146                                         player->audio_cb_probe_id = 0;
1147                                         /* audio callback should be free because it can be called even though probe remove.*/
1148                                         player->audio_stream_cb = NULL;
1149                                         player->audio_stream_cb_user_param = NULL;
1150
1151                                 }
1152                         }
1153                         if ((player->audio_stream_render_cb_ex) && (!player->audio_stream_sink_sync))
1154                                 __mmplayer_audio_stream_clear_buffer(player, TRUE);
1155
1156                         /* rewind if repeat count is greater then zero */
1157                         /* get play count */
1158                         attrs = MMPLAYER_GET_ATTRS(player);
1159
1160                         if (attrs) {
1161                                 gboolean smooth_repeat = FALSE;
1162
1163                                 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1164                                 mm_attrs_get_int_by_name(attrs, "profile_smooth_repeat", &smooth_repeat);
1165
1166                                 player->play_count = count;
1167
1168                                 LOGD("remaining play count: %d, playback rate: %f\n", count, player->playback_rate);
1169
1170                                 if (count > 1 || count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1171                                         if (smooth_repeat) {
1172                                                 LOGD("smooth repeat enabled. seeking operation will be excuted in new thread\n");
1173
1174                                                 MMPLAYER_REPEAT_THREAD_SIGNAL(player);
1175
1176                                                 break;
1177                                         } else {
1178                                                 gint ret_value = 0;
1179
1180                                                 if (player->section_repeat) {
1181                                                         ret_value = _mmplayer_activate_section_repeat((MMHandleType)player, player->section_repeat_start, player->section_repeat_end);
1182                                                 } else {
1183                                                         if (player->playback_rate < 0.0) {
1184                                                                 player->resumed_by_rewind = TRUE;
1185                                                                 _mmplayer_set_mute((MMHandleType)player, 0);
1186                                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1187                                                         }
1188
1189                                                         __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1190
1191                                                         /* initialize */
1192                                                         player->sent_bos = FALSE;
1193                                                 }
1194
1195                                                 if (MM_ERROR_NONE != ret_value)
1196                                                         LOGE("failed to set position to zero for rewind\n");
1197
1198                                                 /* not posting eos when repeating */
1199                                                 break;
1200                                         }
1201                                 }
1202                         }
1203
1204                         if (player->pipeline)
1205                                 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1206
1207                         /* post eos message to application */
1208                         __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1209
1210                         /* reset last position */
1211                         player->last_position = 0;
1212                 }
1213                 break;
1214
1215         case GST_MESSAGE_ERROR:
1216                 {
1217                         GError *error = NULL;
1218                         gchar* debug = NULL;
1219
1220                         /* generating debug info before returning error */
1221                         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1222
1223                         /* get error code */
1224                         gst_message_parse_error(msg, &error, &debug);
1225
1226                         if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1227                                 /* Note : the streaming error from the streaming source is handled
1228                                  *   using __mmplayer_handle_streaming_error.
1229                                  */
1230                                 __mmplayer_handle_streaming_error(player, msg);
1231
1232                                 /* dump state of all element */
1233                                 __mmplayer_dump_pipeline_state(player);
1234                         } else {
1235                                 /* traslate gst error code to msl error code. then post it
1236                                  * to application if needed
1237                                  */
1238                                 __mmplayer_handle_gst_error(player, msg, error);
1239
1240                                 if (debug)
1241                                         LOGE("error debug : %s", debug);
1242                         }
1243
1244                         if (MMPLAYER_IS_HTTP_PD(player))
1245                                 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
1246
1247                         MMPLAYER_FREEIF(debug);
1248                         g_error_free(error);
1249                 }
1250                 break;
1251
1252         case GST_MESSAGE_WARNING:
1253                 {
1254                         char* debug = NULL;
1255                         GError* error = NULL;
1256
1257                         gst_message_parse_warning(msg, &error, &debug);
1258
1259                         LOGD("warning : %s\n", error->message);
1260                         LOGD("debug : %s\n", debug);
1261
1262                         MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1263
1264                         MMPLAYER_FREEIF(debug);
1265                         g_error_free(error);
1266                 }
1267                 break;
1268
1269         case GST_MESSAGE_TAG:
1270                 {
1271                         LOGD("GST_MESSAGE_TAG\n");
1272                         if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1273                                 LOGW("failed to extract tags from gstmessage\n");
1274                 }
1275                 break;
1276
1277         case GST_MESSAGE_BUFFERING:
1278                 {
1279                         MMMessageParamType msg_param = {0, };
1280                         int bRet = MM_ERROR_NONE;
1281
1282                         if (!MMPLAYER_IS_STREAMING(player))
1283                                 break;
1284
1285                         /* ignore the prev buffering message */
1286                         if ((player->streamer) && (player->streamer->is_buffering == FALSE) && (player->streamer->is_buffering_done == TRUE)) {
1287                                 gint buffer_percent = 0;
1288
1289                                 gst_message_parse_buffering(msg, &buffer_percent);
1290
1291                                 if (buffer_percent == MAX_BUFFER_PERCENT) {
1292                                         LOGD("Ignored all the previous buffering msg!(got %d%%)\n", buffer_percent);
1293                                         player->streamer->is_buffering_done = FALSE;
1294                                 }
1295
1296                                 break;
1297                         }
1298
1299                         MMPLAYER_CMD_LOCK(player);
1300                         __mmplayer_update_buffer_setting(player, msg);
1301
1302                         bRet = __mmplayer_handle_buffering_message(player);
1303
1304                         if (bRet == MM_ERROR_NONE) {
1305                                 msg_param.connection.buffering = player->streamer->buffering_percent;
1306                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1307
1308                                 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1309                                         player->pending_resume &&
1310                                         (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1311
1312                                         player->is_external_subtitle_added_now = FALSE;
1313                                         player->pending_resume = FALSE;
1314                                         _mmplayer_resume((MMHandleType)player);
1315                                 }
1316
1317                                 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1318                                         (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1319
1320                                         if (player->doing_seek) {
1321                                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1322                                                         player->doing_seek = FALSE;
1323                                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1324                                                 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1325                                                         async_done = TRUE;
1326                                                 }
1327                                         }
1328                                 }
1329                         } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1330                                 if (!player->streamer) {
1331                                         LOGW("player->streamer is NULL, so discarding the buffering percent update\n");
1332                                         MMPLAYER_CMD_UNLOCK(player);
1333                                         break;
1334                                 }
1335
1336                                 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1337
1338                                         LOGD("player->last_position=%lld , player->streamer->buffering_percent=%d \n",
1339                                                         GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1340
1341                                         if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1342                                                 msg_param.connection.buffering = player->streamer->buffering_percent;
1343                                                 MMPLAYER_POST_MSG( player, MM_MESSAGE_BUFFERING, &msg_param );
1344                                         } else {
1345                                                 LOGD("Not updating Buffering Message for Live RTSP case !!!\n");
1346                                         }
1347                                 } else {
1348                                         msg_param.connection.buffering = player->streamer->buffering_percent;
1349                                         MMPLAYER_POST_MSG( player, MM_MESSAGE_BUFFERING, &msg_param );
1350                                 }
1351                         }
1352                         MMPLAYER_CMD_UNLOCK(player);
1353                 }
1354                 break;
1355
1356         case GST_MESSAGE_STATE_CHANGED:
1357                 {
1358                         MMPlayerGstElement *mainbin;
1359                         const GValue *voldstate, *vnewstate, *vpending;
1360                         GstState oldstate = GST_STATE_NULL;
1361                         GstState newstate = GST_STATE_NULL;
1362                         GstState pending = GST_STATE_NULL;
1363
1364                         if (!(player->pipeline && player->pipeline->mainbin)) {
1365                                 LOGE("player pipeline handle is null");
1366                                 break;
1367                         }
1368
1369                         mainbin = player->pipeline->mainbin;
1370
1371                         /* we only handle messages from pipeline */
1372                         if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1373                                 break;
1374
1375                         /* get state info from msg */
1376                         voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1377                         vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1378                         vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1379
1380                         if (!voldstate || !vnewstate) {
1381                                 LOGE("received msg has wrong format.");
1382                                 break;
1383                         }
1384
1385                         oldstate = (GstState)voldstate->data[0].v_int;
1386                         newstate = (GstState)vnewstate->data[0].v_int;
1387                         if (vpending)
1388                                 pending = (GstState)vpending->data[0].v_int;
1389
1390                         LOGD("state changed [%s] : %s ---> %s     final : %s\n",
1391                                 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1392                                 gst_element_state_get_name((GstState)oldstate),
1393                                 gst_element_state_get_name((GstState)newstate),
1394                                 gst_element_state_get_name((GstState)pending));
1395
1396                         if (newstate == GST_STATE_PLAYING) {
1397                                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1398
1399                                         int retVal = MM_ERROR_NONE;
1400                                         LOGD("trying to play from (%lu) pending position\n", player->pending_seek.pos);
1401
1402                                         retVal = __gst_set_position( player, player->pending_seek.format, player->pending_seek.pos, TRUE );
1403
1404                                         if (MM_ERROR_NONE != retVal)
1405                                                 LOGE("failed to seek pending postion. just keep staying current position.\n");
1406
1407                                         player->pending_seek.is_pending = FALSE;
1408                                 }
1409                         }
1410
1411                         if (oldstate == newstate) {
1412                                 LOGD("pipeline reports state transition to old state");
1413                                 break;
1414                         }
1415
1416                         switch (newstate) {
1417                         case GST_STATE_VOID_PENDING:
1418                                 break;
1419
1420                         case GST_STATE_NULL:
1421                                 break;
1422
1423                         case GST_STATE_READY:
1424                                 break;
1425
1426                         case GST_STATE_PAUSED:
1427                                 {
1428                                         gboolean prepare_async = FALSE;
1429
1430                                         if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
1431                                                 __mmplayer_configure_audio_callback(player);
1432
1433                                         if (!player->sent_bos && oldstate == GST_STATE_READY) {
1434                                                 // managed prepare async case
1435                                                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1436                                                 LOGD("checking prepare mode for async transition - %d", prepare_async);
1437                                         }
1438
1439                                         if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1440                                                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1441
1442                                                 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1443                                                         __mm_player_streaming_set_content_bitrate(player->streamer,
1444                                                                 player->total_maximum_bitrate, player->total_bitrate);
1445                                         }
1446                                 }
1447                                 break;
1448
1449                         case GST_STATE_PLAYING:
1450                                 {
1451                                         if (MMPLAYER_IS_STREAMING(player)) {
1452                                                 // managed prepare async case when buffering is completed
1453                                                 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1454                                                 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1455                                                         (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1456                                                         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1457
1458                                                 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1459
1460                                                         LOGD("Current Buffering Percent = %d",player->streamer->buffering_percent);
1461                                                         if (player->streamer->buffering_percent < 100) {
1462
1463                                                                 MMMessageParamType msg_param = {0, };
1464                                                                 LOGW("Posting Buffering Completed Message to Application !!!");
1465
1466                                                                 msg_param.connection.buffering = 100;
1467                                                                 MMPLAYER_POST_MSG ( player, MM_MESSAGE_BUFFERING, &msg_param );
1468                                                         }
1469                                                 }
1470                                         }
1471
1472                                         if (player->gapless.stream_changed) {
1473                                                 _mmplayer_update_content_attrs(player, ATTR_ALL);
1474                                                 player->gapless.stream_changed = FALSE;
1475                                         }
1476
1477                                         if (player->doing_seek && async_done) {
1478                                                 player->doing_seek = FALSE;
1479                                                 async_done = FALSE;
1480                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1481                                         }
1482                                 }
1483                                 break;
1484
1485                         default:
1486                                 break;
1487                         }
1488                 }
1489                 break;
1490
1491         case GST_MESSAGE_CLOCK_LOST:
1492                         {
1493                                 GstClock *clock = NULL;
1494                                 gboolean need_new_clock = FALSE;
1495
1496                                 gst_message_parse_clock_lost(msg, &clock);
1497                                 LOGD("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1498
1499                                 if (!player->videodec_linked)
1500                                         need_new_clock = TRUE;
1501                                 else if (!player->ini.use_system_clock)
1502                                         need_new_clock = TRUE;
1503
1504                                 if (need_new_clock) {
1505                                         LOGD("Provide clock is TRUE, do pause->resume\n");
1506                                         __gst_pause(player, FALSE);
1507                                         __gst_resume(player, FALSE);
1508                                 }
1509                         }
1510                         break;
1511
1512         case GST_MESSAGE_NEW_CLOCK:
1513                         {
1514                                 GstClock *clock = NULL;
1515                                 gst_message_parse_new_clock(msg, &clock);
1516                                 LOGD("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1517                         }
1518                         break;
1519
1520         case GST_MESSAGE_ELEMENT:
1521                         {
1522                                 const gchar *structure_name;
1523                                 gint count = 0;
1524                                 MMHandleType attrs = 0;
1525
1526                                 attrs = MMPLAYER_GET_ATTRS(player);
1527                                 if (!attrs) {
1528                                         LOGE("cannot get content attribute");
1529                                         ret = FALSE;
1530                                         break;
1531                                 }
1532
1533                                 if (gst_message_get_structure(msg) == NULL)
1534                                         break;
1535
1536                                 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1537                                 if (!structure_name)
1538                                         break;
1539
1540                                 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1541                                         gint num_buffers = 0;
1542                                         gint extra_num_buffers = 0;
1543
1544                                         if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1545                                                 player->video_num_buffers = num_buffers;
1546                                                 LOGD("video_num_buffers : %d", player->video_num_buffers);
1547                                         }
1548
1549                                         if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1550                                                 player->video_extra_num_buffers = extra_num_buffers;
1551                                                 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1552                                         }
1553                                         break;
1554                                 }
1555
1556                                 if (!strcmp(structure_name, "Language_list")) {
1557                                         const GValue *lang_list = NULL;
1558                                         lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1559                                         if (lang_list != NULL) {
1560                                                 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1561                                                 if (count > 1)
1562                                                         LOGD("Total audio tracks(from parser) = %d \n", count);
1563                                         }
1564                                 }
1565
1566                                 if (!strcmp(structure_name, "Ext_Sub_Language_List")) {
1567                                         const GValue *lang_list = NULL;
1568                                         MMPlayerLangStruct *temp = NULL;
1569
1570                                         lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1571                                         if (lang_list != NULL) {
1572                                                 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1573                                                 if (count) {
1574                                                         player->subtitle_language_list = (GList *)g_value_get_pointer(lang_list);
1575                                                         mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)count);
1576                                                         if (mmf_attrs_commit(attrs))
1577                                                           LOGE("failed to commit.\n");
1578                                                         LOGD("Total subtitle tracks = %d \n", count);
1579                                                 }
1580                                                 while (count) {
1581                                                         temp = g_list_nth_data(player->subtitle_language_list, count - 1);
1582                                                         if (temp)
1583                                                                 LOGD("value of lang_key is %s and lang_code is %s",
1584                                                                                         temp->language_key, temp->language_code);
1585                                                         count--;
1586                                                 }
1587                                         }
1588                                 }
1589
1590                                 /* custom message */
1591                                 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1592                                         MMMessageParamType msg_param = {0,};
1593                                         msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1594                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1595                                 }
1596
1597                                 /* custom message for RTSP attribute :
1598                                     RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1599                                     sdp which has contents info is received when rtsp connection is opened.
1600                                     extract duration ,codec info , resolution from sdp and get it by GstMessage */
1601                                 if (!strcmp(structure_name, "rtspsrc_properties")) {
1602
1603                                         gchar           *audio_codec = NULL;
1604                                         gchar           *video_codec = NULL;
1605                                         gchar           *video_frame_size = NULL;
1606
1607                                         gst_structure_get(gst_message_get_structure(msg), "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1608                                         LOGD("rtsp duration : %lld msec", GST_TIME_AS_MSECONDS(player->duration));
1609                                         __mmplayer_get_stream_service_type(player);
1610                                         mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(player->duration));
1611
1612                                         gst_structure_get(gst_message_get_structure(msg), "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1613                                         LOGD("rtsp_audio_codec : %s", audio_codec);
1614                                         if (audio_codec)
1615                                                 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
1616
1617                                         gst_structure_get(gst_message_get_structure(msg), "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1618                                         LOGD("rtsp_video_codec : %s", video_codec);
1619                                         if (video_codec)
1620                                                 mm_attrs_set_string_by_name(player->attrs, "content_video_codec", video_codec);
1621
1622                                         gst_structure_get(gst_message_get_structure(msg), "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1623                                         LOGD("rtsp_video_frame_size : %s", video_frame_size);
1624                                         if (video_frame_size) {
1625
1626                                                 char *seperator = strchr(video_frame_size, '-');
1627                                                 if (seperator) {
1628
1629                                                         char video_width[10]={0,};
1630                                                         int frame_size_len = strlen(video_frame_size);
1631                                                         int separtor_len = strlen(seperator);
1632
1633                                                         strncpy(video_width,video_frame_size,(frame_size_len-separtor_len));
1634                                                         mm_attrs_set_int_by_name(attrs, "content_video_width", atoi(video_width));
1635
1636                                                         seperator++;
1637                                                         mm_attrs_set_int_by_name(attrs, "content_video_height", atoi(seperator));
1638                                                 }
1639                                         }
1640
1641                                         if (mmf_attrs_commit(attrs))
1642                                                 LOGE("failed to commit.\n");
1643                                 }
1644                         }
1645                         break;
1646
1647         case GST_MESSAGE_DURATION_CHANGED:
1648                 {
1649                         LOGD("GST_MESSAGE_DURATION_CHANGED\n");
1650                         ret = __mmplayer_gst_handle_duration(player, msg);
1651                         if (!ret)
1652                                 LOGW("failed to update duration");
1653                 }
1654
1655                 break;
1656
1657         case GST_MESSAGE_ASYNC_START:
1658                         LOGD("GST_MESSAGE_ASYNC_START : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1659                 break;
1660
1661         case GST_MESSAGE_ASYNC_DONE:
1662                 {
1663                         LOGD("GST_MESSAGE_ASYNC_DONE : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1664
1665                         /* we only handle messages from pipeline */
1666                         if (msg->src != (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst)
1667                                 break;
1668
1669                         if (player->doing_seek) {
1670                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1671                                         player->doing_seek = FALSE;
1672                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1673                                 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1674                                         if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1675                                                 (player->streamer) &&
1676                                                 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1677                                                 (player->streamer->is_buffering == FALSE)) {
1678                                                 GstQuery *query = NULL;
1679                                                 gboolean busy = FALSE;
1680                                                 gint percent = 0;
1681
1682                                                 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1683                                                         query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1684                                                         if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1685                                                                 gst_query_parse_buffering_percent(query, &busy, &percent);
1686                                                         gst_query_unref(query);
1687
1688                                                         LOGD("buffered percent(%s): %d\n",
1689                                                                 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1690                                                 }
1691
1692                                                 if (percent >= 100) {
1693                                                         player->streamer->is_buffering = FALSE;
1694                                                         __mmplayer_handle_buffering_message(player);
1695                                                 }
1696                                         }
1697
1698                                         async_done = TRUE;
1699                                 }
1700                         }
1701                 }
1702                 break;
1703
1704         #if 0 /* delete unnecessary logs */
1705         case GST_MESSAGE_REQUEST_STATE:         LOGD("GST_MESSAGE_REQUEST_STATE\n"); break;
1706         case GST_MESSAGE_STEP_START:            LOGD("GST_MESSAGE_STEP_START\n"); break;
1707         case GST_MESSAGE_QOS:                           LOGD("GST_MESSAGE_QOS\n"); break;
1708         case GST_MESSAGE_PROGRESS:                      LOGD("GST_MESSAGE_PROGRESS\n"); break;
1709         case GST_MESSAGE_ANY:                           LOGD("GST_MESSAGE_ANY\n"); break;
1710         case GST_MESSAGE_INFO:                          LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1711         case GST_MESSAGE_STATE_DIRTY:           LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1712         case GST_MESSAGE_STEP_DONE:                     LOGD("GST_MESSAGE_STEP_DONE\n"); break;
1713         case GST_MESSAGE_CLOCK_PROVIDE:         LOGD("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
1714         case GST_MESSAGE_STRUCTURE_CHANGE:      LOGD("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
1715         case GST_MESSAGE_STREAM_STATUS:         LOGD("GST_MESSAGE_STREAM_STATUS\n"); break;
1716         case GST_MESSAGE_APPLICATION:           LOGD("GST_MESSAGE_APPLICATION\n"); break;
1717         case GST_MESSAGE_SEGMENT_START:         LOGD("GST_MESSAGE_SEGMENT_START\n"); break;
1718         case GST_MESSAGE_SEGMENT_DONE:          LOGD("GST_MESSAGE_SEGMENT_DONE\n"); break;
1719         case GST_MESSAGE_LATENCY:                               LOGD("GST_MESSAGE_LATENCY\n"); break;
1720         #endif
1721
1722         default:
1723                 break;
1724         }
1725
1726         /* FIXIT : this cause so many warnings/errors from glib/gstreamer. we should not call it since
1727          * gst_element_post_message api takes ownership of the message.
1728          */
1729         //gst_message_unref(msg);
1730
1731         return ret;
1732 }
1733
1734 static gboolean
1735 __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg)
1736 {
1737         gint64 bytes = 0;
1738
1739         MMPLAYER_FENTER();
1740
1741         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1742         MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1743
1744         if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1745                 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1746                 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1747
1748                 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1749                         LOGD("data total size of http content: %lld", bytes);
1750                         player->http_content_size = (bytes > 0) ? (bytes) : (0);
1751                 }
1752         } else
1753                 /* handling audio clip which has vbr. means duration is keep changing */
1754                 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1755
1756         MMPLAYER_FLEAVE();
1757
1758         return TRUE;
1759 }
1760
1761
1762 static gboolean
1763 __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg) // @
1764 {
1765
1766 /* macro for better code readability */
1767 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
1768 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
1769         if (string != NULL) {\
1770                 SECURE_LOGD("update tag string : %s\n", string); \
1771                 mm_attrs_set_string_by_name(attribute, playertag, string); \
1772                 g_free(string);\
1773                 string = NULL;\
1774         } \
1775 }
1776
1777 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
1778 GstSample *sample = NULL;\
1779 if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
1780         GstMapInfo info = GST_MAP_INFO_INIT;\
1781         buffer = gst_sample_get_buffer(sample);\
1782         if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
1783                 LOGD("failed to get image data from tag");\
1784                 return FALSE;\
1785         } \
1786         SECURE_LOGD("update album cover data : %p, size : %d\n", info.data, info.size);\
1787         MMPLAYER_FREEIF(player->album_art);\
1788         player->album_art = (gchar *)g_malloc(info.size);\
1789         if (player->album_art) {\
1790                 memcpy(player->album_art, info.data, info.size);\
1791                 mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size);\
1792                 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
1793                         msg_param.data = (void *)player->album_art;\
1794                         msg_param.size = info.size;\
1795                         MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
1796                         SECURE_LOGD("post message image buffer data : %p, size : %d\n", info.data, info.size);\
1797                 } \
1798         } \
1799         gst_buffer_unmap(buffer, &info);\
1800 }
1801
1802 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
1803 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) {\
1804         if (v_uint) {\
1805                 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) {\
1806                         if (player->updated_bitrate_count == 0) \
1807                                 mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
1808                         if (player->updated_bitrate_count < MM_PLAYER_STREAM_COUNT_MAX) {\
1809                                 player->bitrate[player->updated_bitrate_count] = v_uint;\
1810                                 player->total_bitrate += player->bitrate[player->updated_maximum_bitrate_count]; \
1811                                 player->updated_bitrate_count++; \
1812                                 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate);\
1813                                 SECURE_LOGD("update bitrate %d[bps] of stream #%d.\n", v_uint, player->updated_bitrate_count);\
1814                         } \
1815                 } \
1816                 else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) {\
1817                         if (player->updated_maximum_bitrate_count < MM_PLAYER_STREAM_COUNT_MAX) {\
1818                                 player->maximum_bitrate[player->updated_maximum_bitrate_count] = v_uint;\
1819                                 player->total_maximum_bitrate += player->maximum_bitrate[player->updated_maximum_bitrate_count]; \
1820                                 player->updated_maximum_bitrate_count++; \
1821                                 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate); \
1822                                 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d\n", v_uint, player->updated_maximum_bitrate_count);\
1823                         } \
1824                 } else\
1825                         mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
1826                 v_uint = 0;\
1827         } \
1828 }
1829
1830 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
1831 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
1832         if (date != NULL) {\
1833                 string = g_strdup_printf("%d", g_date_get_year(date));\
1834                 mm_attrs_set_string_by_name(attribute, playertag, string);\
1835                 SECURE_LOGD("metainfo year : %s\n", string);\
1836                 MMPLAYER_FREEIF(string);\
1837                 g_date_free(date);\
1838         } \
1839 }
1840
1841 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, attribute, playertag) \
1842 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
1843         if (datetime != NULL) {\
1844                 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
1845                 mm_attrs_set_string_by_name(attribute, playertag, string);\
1846                 SECURE_LOGD("metainfo year : %s\n", string);\
1847                 MMPLAYER_FREEIF(string);\
1848                 gst_date_time_unref(datetime);\
1849         } \
1850 }
1851
1852 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
1853 if (gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64)) {\
1854         if (v_uint64) {\
1855                 /* FIXIT : don't know how to store date */\
1856                 g_assert(1);\
1857                 v_uint64 = 0;\
1858         } \
1859 }
1860
1861 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
1862 if (gst_tag_list_get_double(tag_list, gsttag, &v_double)) {\
1863         if (v_double) {\
1864                 /* FIXIT : don't know how to store date */\
1865                 g_assert(1);\
1866                 v_double = 0;\
1867         } \
1868 }
1869
1870         /* function start */
1871         GstTagList* tag_list = NULL;
1872
1873         MMHandleType attrs = 0;
1874
1875         char *string = NULL;
1876         guint v_uint = 0;
1877         GDate *date = NULL;
1878         GstDateTime *datetime = NULL;
1879         /* album cover */
1880         GstBuffer *buffer = NULL;
1881         gint index = 0;
1882         MMMessageParamType msg_param = {0, };
1883
1884         /* currently not used. but those are needed for above macro */
1885         //guint64 v_uint64 = 0;
1886         //gdouble v_double = 0;
1887
1888         MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
1889
1890         attrs = MMPLAYER_GET_ATTRS(player);
1891
1892         MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE);
1893
1894         /* get tag list from gst message */
1895         gst_message_parse_tag(msg, &tag_list);
1896
1897         /* store tags to player attributes */
1898         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
1899         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
1900         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
1901         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
1902         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
1903         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
1904         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
1905         MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
1906         MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, attrs, "tag_date");
1907         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
1908         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
1909         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
1910         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
1911         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
1912         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
1913         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
1914         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
1915         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
1916         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
1917         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
1918         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
1919         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
1920         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
1921         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
1922         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
1923         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
1924         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
1925         /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
1926         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
1927         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
1928         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
1929         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
1930         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
1931         MMPLAYER_UPDATE_TAG_LOCK(player);
1932         MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
1933         MMPLAYER_UPDATE_TAG_UNLOCK(player);
1934         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
1935         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
1936         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
1937         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
1938         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
1939         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
1940         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
1941         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
1942         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
1943         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
1944         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
1945         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
1946         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation");
1947
1948         if (mmf_attrs_commit(attrs))
1949                 LOGE("failed to commit.\n");
1950
1951         gst_tag_list_free(tag_list);
1952
1953         return TRUE;
1954 }
1955
1956 static void
1957 __mmplayer_gst_rtp_no_more_pads(GstElement *element,  gpointer data)  // @
1958 {
1959         mm_player_t* player = (mm_player_t*) data;
1960
1961         MMPLAYER_FENTER();
1962
1963         /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
1964           * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
1965           * num_dynamic_pad. and this is no-more-pad situation which means mo more pad will be added.
1966           * So we can say this. if num_dynamic_pad is zero, it must be one of followings
1967
1968           * [1] audio and video will be dumped with filesink.
1969           * [2] autoplugging is done by just using pad caps.
1970           * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
1971           * and the video will be dumped via filesink.
1972           */
1973         if (player->num_dynamic_pad == 0) {
1974                 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
1975
1976                 if (!__mmplayer_gst_remove_fakesink(player,
1977                         &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
1978                         /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
1979                          * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
1980                          * source element are not same. To overcome this situation, this function will called
1981                          * several places and several times. Therefore, this is not an error case.
1982                          */
1983                         return;
1984         }
1985
1986         /* create dot before error-return. for debugging */
1987         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
1988
1989         player->no_more_pad = TRUE;
1990
1991         MMPLAYER_FLEAVE();
1992 }
1993
1994 static gboolean
1995 __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink) // @
1996 {
1997         GstElement* parent = NULL;
1998
1999         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
2000
2001         /* if we have no fakesink. this meas we are using decodebin which doesn'
2002         t need to add extra fakesink */
2003         MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
2004
2005         /* lock */
2006         MMPLAYER_FSINK_LOCK(player);
2007
2008         if (!fakesink->gst)
2009                 goto ERROR;
2010
2011         /* get parent of fakesink */
2012         parent = (GstElement*)gst_object_get_parent((GstObject*)fakesink->gst);
2013         if (!parent) {
2014                 LOGD("fakesink already removed\n");
2015                 goto ERROR;
2016         }
2017
2018         gst_element_set_locked_state(fakesink->gst, TRUE);
2019
2020         /* setting the state to NULL never returns async
2021          * so no need to wait for completion of state transiton
2022          */
2023         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
2024                 LOGE("fakesink state change failure!\n");
2025                 /* FIXIT : should I return here? or try to proceed to next? */
2026                 /* return FALSE; */
2027
2028         /* remove fakesink from it's parent */
2029         if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
2030                 LOGE("failed to remove fakesink\n");
2031
2032                 gst_object_unref(parent);
2033
2034                 goto ERROR;
2035         }
2036
2037         gst_object_unref(parent);
2038
2039         LOGD("state-holder removed\n");
2040
2041         gst_element_set_locked_state(fakesink->gst, FALSE);
2042
2043         MMPLAYER_FSINK_UNLOCK(player);
2044         return TRUE;
2045
2046 ERROR:
2047         if (fakesink->gst)
2048                 gst_element_set_locked_state(fakesink->gst, FALSE);
2049
2050         MMPLAYER_FSINK_UNLOCK(player);
2051         return FALSE;
2052 }
2053
2054
2055 static void
2056 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data) // @
2057 {
2058         GstPad *sinkpad = NULL;
2059         GstCaps* caps = NULL;
2060         GstElement* new_element = NULL;
2061         GstStructure* str = NULL;
2062         const gchar* name = NULL;
2063
2064         mm_player_t* player = (mm_player_t*) data;
2065
2066         MMPLAYER_FENTER();
2067
2068         MMPLAYER_RETURN_IF_FAIL(element && pad);
2069         MMPLAYER_RETURN_IF_FAIL(player &&
2070                                         player->pipeline &&
2071                                         player->pipeline->mainbin);
2072
2073
2074         /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2075          * num_dynamic_pad will decreased after creating a sinkbin.
2076          */
2077         player->num_dynamic_pad++;
2078         LOGD("stream count inc : %d\n", player->num_dynamic_pad);
2079
2080         caps = gst_pad_query_caps(pad, NULL);
2081
2082         MMPLAYER_CHECK_NULL(caps);
2083
2084         /* clear  previous result*/
2085         player->have_dynamic_pad = FALSE;
2086
2087         str = gst_caps_get_structure(caps, 0);
2088
2089         if (!str) {
2090                 LOGE("cannot get structure from caps.\n");
2091                 goto ERROR;
2092         }
2093
2094         name = gst_structure_get_name(str);
2095         if (!name) {
2096                 LOGE("cannot get mimetype from structure.\n");
2097                 goto ERROR;
2098         }
2099
2100         if (strstr(name, "video")) {
2101                 gint stype = 0;
2102                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2103
2104                 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
2105                         if (player->v_stream_caps) {
2106                                 gst_caps_unref(player->v_stream_caps);
2107                                 player->v_stream_caps = NULL;
2108                         }
2109
2110                         new_element = gst_element_factory_make("fakesink", NULL);
2111                         player->num_dynamic_pad--;
2112                         goto NEW_ELEMENT;
2113                 }
2114         }
2115
2116         /* clear  previous result*/
2117         player->have_dynamic_pad = FALSE;
2118
2119         if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
2120                 LOGE("failed to autoplug for caps");
2121                 goto ERROR;
2122         }
2123
2124         /* check if there's dynamic pad*/
2125         if (player->have_dynamic_pad) {
2126                 LOGE("using pad caps assums there's no dynamic pad !\n");
2127                 goto ERROR;
2128         }
2129
2130         gst_caps_unref(caps);
2131         caps = NULL;
2132
2133 NEW_ELEMENT:
2134
2135         /* excute new_element if created*/
2136         if (new_element) {
2137                 LOGD("adding new element to pipeline\n");
2138
2139                 /* set state to READY before add to bin */
2140                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2141
2142                 /* add new element to the pipeline */
2143                 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2144                         LOGE("failed to add autoplug element to bin\n");
2145                         goto ERROR;
2146                 }
2147
2148                 /* get pad from element */
2149                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2150                 if (!sinkpad) {
2151                         LOGE("failed to get sinkpad from autoplug element\n");
2152                         goto ERROR;
2153                 }
2154
2155                 /* link it */
2156                 if (GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad)) {
2157                         LOGE("failed to link autoplug element\n");
2158                         goto ERROR;
2159                 }
2160
2161                 gst_object_unref(sinkpad);
2162                 sinkpad = NULL;
2163
2164                 /* run. setting PLAYING here since streamming source is live source */
2165                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2166         }
2167
2168         MMPLAYER_FLEAVE();
2169
2170         return;
2171
2172 STATE_CHANGE_FAILED:
2173 ERROR:
2174         /* FIXIT : take care if new_element has already added to pipeline */
2175         if (new_element)
2176                 gst_object_unref(GST_OBJECT(new_element));
2177
2178         if (sinkpad)
2179                 gst_object_unref(GST_OBJECT(sinkpad));
2180
2181         if (caps)
2182                 gst_object_unref(GST_OBJECT(caps));
2183
2184         /* FIXIT : how to inform this error to MSL ????? */
2185         /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2186          * then post an error to application
2187          */
2188 }
2189
2190
2191
2192 /* FIXIT : check indent */
2193 #if 0
2194 static void
2195 __mmplayer_gst_wfd_dynamic_pad(GstElement *element, GstPad *pad, gpointer data) // @
2196 {
2197         GstPad *sinkpad = NULL;
2198         GstCaps* caps = NULL;
2199         GstElement* new_element = NULL;
2200         enum MainElementID element_id = MMPLAYER_M_NUM;
2201
2202         mm_player_t* player = (mm_player_t*) data;
2203
2204         MMPLAYER_FENTER();
2205
2206         MMPLAYER_RETURN_IF_FAIL(element && pad);
2207         MMPLAYER_RETURN_IF_FAIL(player &&
2208                 player->pipeline &&
2209                 player->pipeline->mainbin);
2210
2211         LOGD("stream count inc : %d\n", player->num_dynamic_pad);
2212
2213         {
2214                 LOGD("using pad caps to autopluging instead of doing typefind\n");
2215                 caps = gst_pad_query_caps(pad);
2216                 MMPLAYER_CHECK_NULL(caps);
2217                 /* clear  previous result*/
2218                 player->have_dynamic_pad = FALSE;
2219                 new_element = gst_element_factory_make("rtpmp2tdepay", "wfd_rtp_depay");
2220                 if (!new_element) {
2221                         LOGE("failed to create wfd rtp depay element\n");
2222                         goto ERROR;
2223                 }
2224                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2225                 /* add new element to the pipeline */
2226                 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2227                         LOGD("failed to add autoplug element to bin\n");
2228                         goto ERROR;
2229                 }
2230                 /* get pad from element */
2231                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2232                 if (!sinkpad) {
2233                         LOGD("failed to get sinkpad from autoplug element\n");
2234                         goto ERROR;
2235                 }
2236                 /* link it */
2237                 if (GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad)) {
2238                         LOGD("failed to link autoplug element\n");
2239                         goto ERROR;
2240                 }
2241                 gst_object_unref(sinkpad);
2242                 sinkpad = NULL;
2243                 pad = gst_element_get_static_pad(GST_ELEMENT(new_element), "src");
2244                 caps = gst_pad_query_caps(pad);
2245                 MMPLAYER_CHECK_NULL(caps);
2246                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2247                 /* create typefind */
2248                 new_element = gst_element_factory_make("typefind", NULL);
2249                 if (!new_element) {
2250                         LOGD("failed to create typefind\n");
2251                         goto ERROR;
2252                 }
2253
2254                 MMPLAYER_SIGNAL_CONNECT(player,
2255                         G_OBJECT(new_element),
2256                         MM_PLAYER_SIGNAL_TYPE_AUTOPLUG,
2257                         "have-type",
2258                         G_CALLBACK(__mmplayer_typefind_have_type),
2259                         (gpointer)player);
2260
2261                 player->have_dynamic_pad = FALSE;
2262         }
2263
2264         /* excute new_element if created*/
2265         if (new_element) {
2266                 LOGD("adding new element to pipeline\n");
2267
2268                 /* set state to READY before add to bin */
2269                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2270
2271                 /* add new element to the pipeline */
2272                 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2273                         LOGD("failed to add autoplug element to bin\n");
2274                         goto ERROR;
2275                 }
2276
2277                 /* get pad from element */
2278                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2279                 if (!sinkpad) {
2280                         LOGD("failed to get sinkpad from autoplug element\n");
2281                         goto ERROR;
2282                 }
2283
2284                 /* link it */
2285                 if (GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad)) {
2286                         LOGD("failed to link autoplug element\n");
2287                         goto ERROR;
2288                 }
2289
2290                 gst_object_unref(sinkpad);
2291                 sinkpad = NULL;
2292
2293                 /* run. setting PLAYING here since streamming source is live source */
2294                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2295         }
2296
2297         /* store handle to futher manipulation */
2298         player->pipeline->mainbin[element_id].id = element_id;
2299         player->pipeline->mainbin[element_id].gst = new_element;
2300
2301         MMPLAYER_FLEAVE();
2302
2303         return;
2304
2305 STATE_CHANGE_FAILED:
2306 ERROR:
2307         /* FIXIT : take care if new_element has already added to pipeline */
2308         if (new_element)
2309                 gst_object_unref(GST_OBJECT(new_element));
2310
2311         if (sinkpad)
2312                 gst_object_unref(GST_OBJECT(sinkpad));
2313
2314         if (caps)
2315                 gst_object_unref(GST_OBJECT(caps));
2316
2317         /* FIXIT : how to inform this error to MSL ????? */
2318         /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2319          * then post an error to application
2320          */
2321 }
2322 #endif
2323
2324 static GstPadProbeReturn
2325 __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data)
2326 {
2327         LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
2328         return GST_PAD_PROBE_OK;
2329 }
2330
2331 static GstPadProbeReturn
2332 __mmplayer_gst_selector_event_probe(GstPad * pad, GstPadProbeInfo * info, gpointer data)
2333 {
2334         GstPadProbeReturn ret = GST_PAD_PROBE_OK;
2335         GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
2336         mm_player_t* player = (mm_player_t*)data;
2337         GstCaps* caps = NULL;
2338         GstStructure* str = NULL;
2339         const gchar* name = NULL;
2340         MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2341
2342
2343         if (GST_EVENT_IS_DOWNSTREAM(event)) {
2344                 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
2345                         GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
2346                         GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
2347                         GST_EVENT_TYPE(event) != GST_EVENT_EOS)
2348                         return ret;
2349         } else if (GST_EVENT_IS_UPSTREAM(event)) {
2350                 if (GST_EVENT_TYPE(event) != GST_EVENT_QOS)
2351                         return ret;
2352         }
2353
2354         caps = gst_pad_query_caps(pad, NULL);
2355         if (!caps) {
2356                 LOGE("failed to get caps from pad[%s:%s]", GST_DEBUG_PAD_NAME(pad));
2357                 goto ERROR;
2358         }
2359
2360         str = gst_caps_get_structure(caps, 0);
2361         if (!str) {
2362                 LOGE("failed to get structure from caps");
2363                 goto ERROR;
2364         }
2365
2366         name = gst_structure_get_name(str);
2367         if (!name) {
2368                 LOGE("failed to get name from str");
2369                 goto ERROR;
2370         }
2371
2372         if (strstr(name, "audio")) {
2373                 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2374         } else if (strstr(name, "video")) {
2375                 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2376         } else {
2377                 /* text track is not supportable */
2378                 LOGE("invalid name %s", name);
2379                 goto ERROR;
2380         }
2381
2382         switch (GST_EVENT_TYPE(event)) {
2383         case GST_EVENT_EOS:
2384                 {
2385                         /* in case of gapless, drop eos event not to send it to sink */
2386                         if (player->gapless.reconfigure && !player->msg_posted) {
2387                                 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
2388                                 ret = GST_PAD_PROBE_DROP;
2389                         }
2390                         break;
2391                 }
2392         case GST_EVENT_STREAM_START:
2393                 {
2394                         gint64 stop_running_time = 0;
2395                         gint64 position_running_time = 0;
2396                         gint64 position = 0;
2397                         gint idx = 0;
2398
2399                         for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
2400                                 if ((player->gapless.update_segment[idx] == TRUE) ||
2401                                         !(player->selector[idx].event_probe_id)) {
2402                                         /* LOGW("[%d] skip", idx); */
2403                                         continue;
2404                                 }
2405
2406                                 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
2407                                         stop_running_time =
2408                                                 gst_segment_to_running_time(&player->gapless.segment[idx],
2409                                                                 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
2410                                 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
2411                                         stop_running_time =
2412                                                 gst_segment_to_running_time(&player->gapless.segment[idx],
2413                                                                 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
2414                                 } else {
2415                                         LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
2416                                         stop_running_time =
2417                                                 gst_segment_to_running_time(&player->gapless.segment[idx],
2418                                                                 GST_FORMAT_TIME, player->duration);
2419                                 }
2420
2421                                 position_running_time =
2422                                         gst_segment_to_running_time(&player->gapless.segment[idx],
2423                                         GST_FORMAT_TIME, player->gapless.segment[idx].position);
2424
2425                                 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
2426                                         GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
2427                                         idx,
2428                                         GST_TIME_ARGS(stop_running_time),
2429                                         GST_TIME_ARGS(position_running_time),
2430                                         GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
2431                                         GST_FORMAT_TIME, player->gapless.segment[idx].start)));
2432
2433                                 position_running_time = MAX(position_running_time, stop_running_time);
2434                                 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
2435                                                                                                 GST_FORMAT_TIME, player->gapless.segment[idx].start);
2436                                 position_running_time = MAX(0, position_running_time);
2437                                 position = MAX(position, position_running_time);
2438                         }
2439
2440                         if (position != 0) {
2441                                 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2442                                         stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
2443                                         GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
2444
2445                                 player->gapless.start_time[stream_type] += position;
2446                         }
2447                         break;
2448                 }
2449         case GST_EVENT_FLUSH_STOP:
2450                 {
2451                         LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
2452                         gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
2453                         player->gapless.start_time[stream_type] = 0;
2454                         break;
2455                 }
2456         case GST_EVENT_SEGMENT:
2457                 {
2458                         GstSegment segment;
2459                         GstEvent *tmpev;
2460
2461                         LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
2462                         gst_event_copy_segment(event, &segment);
2463
2464                         if (segment.format == GST_FORMAT_TIME) {
2465                                 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
2466                                          ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
2467                                          ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
2468                                         GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
2469                                         GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
2470                                         GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
2471
2472                                 /* keep the all the segment ev to cover the seeking */
2473                                 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
2474                                 player->gapless.update_segment[stream_type] = TRUE;
2475
2476                                 if (!player->gapless.running)
2477                                         break;
2478
2479                                 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
2480
2481                                 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
2482
2483                                 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
2484                                 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
2485                                 gst_event_unref(event);
2486                                 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2487                         }
2488                         break;
2489                 }
2490         case GST_EVENT_QOS:
2491                 {
2492                         gdouble proportion = 0.0;
2493                         GstClockTimeDiff diff = 0;
2494                         GstClockTime timestamp = 0;
2495                         gint64 running_time_diff = -1;
2496                         GstQOSType type = 0;
2497                         GstEvent *tmpev = NULL;
2498
2499                         running_time_diff = player->gapless.segment[stream_type].base;
2500
2501                         if (running_time_diff <= 0) /* don't need to adjust */
2502                                 break;
2503
2504                         gst_event_parse_qos(event, &type, &proportion, &diff, &timestamp);
2505                         gst_event_unref(event);
2506
2507                         if (timestamp < running_time_diff) {
2508                                 LOGW("QOS event from previous group");
2509                                 ret = GST_PAD_PROBE_DROP;
2510                                 break;
2511                         }
2512
2513                         LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
2514                                  " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
2515                                                 stream_type, GST_TIME_ARGS(timestamp),
2516                                                 GST_TIME_ARGS(running_time_diff),
2517                                                 GST_TIME_ARGS(timestamp - running_time_diff));
2518
2519                         timestamp -= running_time_diff;
2520
2521                         /* That case is invalid for QoS events */
2522                         if (diff < 0 && -diff > timestamp) {
2523                                 LOGW("QOS event from previous group");
2524                                 ret = GST_PAD_PROBE_DROP;
2525                                 break;
2526                         }
2527
2528                         tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
2529                         GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2530
2531                         break;
2532                 }
2533         default:
2534                 break;
2535         }
2536
2537 ERROR:
2538         if (caps)
2539                 gst_caps_unref(caps);
2540         return ret;
2541 }
2542
2543 static void
2544 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2545 {
2546         mm_player_t* player = NULL;
2547         GstElement* pipeline = NULL;
2548         GstElement* selector = NULL;
2549         GstElement* fakesink = NULL;
2550         GstCaps* caps = NULL;
2551         GstStructure* str = NULL;
2552         const gchar* name = NULL;
2553         GstPad* sinkpad = NULL;
2554         GstPad* srcpad = NULL;
2555         gboolean first_track = FALSE;
2556
2557         enum MainElementID elemId = MMPLAYER_M_NUM;
2558         MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2559
2560         /* check handles */
2561         player = (mm_player_t*)data;
2562
2563         MMPLAYER_RETURN_IF_FAIL(elem && pad);
2564         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2565
2566         //LOGD("pad-added signal handling\n");
2567
2568         pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
2569
2570         /* get mimetype from caps */
2571         caps = gst_pad_query_caps(pad, NULL);
2572         if (!caps) {
2573                 LOGE("cannot get caps from pad.\n");
2574                 goto ERROR;
2575         }
2576
2577         str = gst_caps_get_structure(caps, 0);
2578         if (!str) {
2579                 LOGE("cannot get structure from caps.\n");
2580                 goto ERROR;
2581         }
2582
2583         name = gst_structure_get_name(str);
2584         if (!name) {
2585                 LOGE("cannot get mimetype from structure.\n");
2586                 goto ERROR;
2587         }
2588
2589         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2590         //LOGD("detected mimetype : %s\n", name);
2591
2592         if (strstr(name, "video")) {
2593                 gint stype = 0;
2594                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2595
2596                 /* don't make video because of not required, and not support multiple track */
2597                 if (stype == MM_DISPLAY_SURFACE_NULL) {
2598                         LOGD("no video sink by null surface");
2599                         MMPlayerResourceState resource_state = RESOURCE_STATE_NONE;
2600                         if (_mmplayer_resource_manager_get_state(&player->resource_manager, &resource_state)
2601                                         == MM_ERROR_NONE) {
2602                                 /* acquire resources for video playing */
2603                                 if (resource_state == RESOURCE_STATE_PREPARED) {
2604                                         if (_mmplayer_resource_manager_acquire(&player->resource_manager)
2605                                                         != MM_ERROR_NONE) {
2606                                                 LOGE("could not acquire resources for video playing\n");
2607                                                 _mmplayer_resource_manager_unprepare(&player->resource_manager);
2608                                                 goto ERROR;
2609                                         }
2610                                 }
2611                         }
2612
2613                         gchar *caps_str = gst_caps_to_string(caps);
2614                         if (strstr(caps_str, "ST12") || strstr(caps_str, "SN12"))
2615                                 player->set_mode.video_zc = TRUE;
2616
2617                         MMPLAYER_FREEIF(caps_str);
2618
2619                         if (player->v_stream_caps) {
2620                                 gst_caps_unref(player->v_stream_caps);
2621                                 player->v_stream_caps = NULL;
2622                         }
2623
2624                         LOGD("create fakesink instead of videobin");
2625
2626                         /* fake sink */
2627                         fakesink = gst_element_factory_make("fakesink", NULL);
2628                         if (fakesink == NULL) {
2629                                 LOGE("ERROR : fakesink create error\n");
2630                                 goto ERROR;
2631                         }
2632
2633                         if (player->ini.set_dump_element_flag)
2634                                 __mmplayer_add_dump_buffer_probe(player, fakesink);
2635
2636                         player->video_fakesink = fakesink;
2637
2638                         /* store it as it's sink element */
2639                         __mmplayer_add_sink(player, player->video_fakesink);
2640
2641                         gst_bin_add(GST_BIN(pipeline), fakesink);
2642
2643                         // link
2644                         sinkpad = gst_element_get_static_pad(fakesink, "sink");
2645
2646                         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2647                                 LOGW("failed to link fakesink\n");
2648                                 gst_object_unref(GST_OBJECT(fakesink));
2649                                 goto ERROR;
2650                         }
2651
2652                         if (stype == MM_DISPLAY_SURFACE_REMOTE) {
2653                                 MMPLAYER_SIGNAL_CONNECT(player, sinkpad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2654                                                 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
2655                         }
2656
2657                         if (player->set_mode.media_packet_video_stream) {
2658                                 g_object_set(G_OBJECT(fakesink), "signal-handoffs", TRUE, NULL);
2659
2660                                 MMPLAYER_SIGNAL_CONNECT(player,
2661                                                                                 G_OBJECT(fakesink),
2662                                                                                 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2663                                                                                 "handoff",
2664                                                                                 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
2665                                                                                 (gpointer)player);
2666
2667                                 MMPLAYER_SIGNAL_CONNECT(player,
2668                                                                                 G_OBJECT(fakesink),
2669                                                                                 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2670                                                                                 "preroll-handoff",
2671                                                                                 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
2672                                                                                 (gpointer)player);
2673                         }
2674
2675                         g_object_set(G_OBJECT(fakesink), "async", TRUE, "sync", TRUE, NULL);
2676                         gst_element_set_state(fakesink, GST_STATE_PAUSED);
2677                         goto DONE;
2678                 }
2679
2680                 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2681                         __mmplayer_gst_decode_callback(elem, pad, player);
2682                         return;
2683                 }
2684
2685                 LOGD("video selector \n");
2686                 elemId = MMPLAYER_M_V_INPUT_SELECTOR;
2687                 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2688         } else {
2689                 if (strstr(name, "audio")) {
2690                         gint samplerate = 0;
2691                         gint channels = 0;
2692
2693                         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2694                                 __mmplayer_gst_decode_callback(elem, pad, player);
2695                                 return;
2696                         }
2697
2698                         LOGD("audio selector \n");
2699                         elemId = MMPLAYER_M_A_INPUT_SELECTOR;
2700                         stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2701
2702                         gst_structure_get_int(str, "rate", &samplerate);
2703                         gst_structure_get_int(str, "channels", &channels);
2704
2705                         if ((channels > 0 && samplerate == 0)) {//exclude audio decoding
2706                                 /* fake sink */
2707                                 fakesink = gst_element_factory_make("fakesink", NULL);
2708                                 if (fakesink == NULL) {
2709                                         LOGE("ERROR : fakesink create error\n");
2710                                         goto ERROR;
2711                                 }
2712
2713                                 gst_bin_add(GST_BIN(pipeline), fakesink);
2714
2715                                 /* link */
2716                                 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2717
2718                                 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2719                                         LOGW("failed to link fakesink\n");
2720                                         gst_object_unref(GST_OBJECT(fakesink));
2721                                         goto ERROR;
2722                                 }
2723
2724                                 g_object_set(G_OBJECT(fakesink), "async", TRUE, NULL);
2725                                 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
2726                                 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2727
2728                                 goto DONE;
2729                         }
2730                 } else if (strstr(name, "text")) {
2731                         LOGD("text selector \n");
2732                         elemId = MMPLAYER_M_T_INPUT_SELECTOR;
2733                         stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
2734                 } else {
2735                         LOGE("wrong elem id \n");
2736                         goto ERROR;
2737                 }
2738         }
2739
2740         selector = player->pipeline->mainbin[elemId].gst;
2741         if (selector == NULL) {
2742                 selector = gst_element_factory_make("input-selector", NULL);
2743                 LOGD("Creating input-selector\n");
2744                 if (selector == NULL) {
2745                         LOGE("ERROR : input-selector create error\n");
2746                         goto ERROR;
2747                 }
2748                 g_object_set(selector, "sync-streams", TRUE, NULL);
2749
2750                 player->pipeline->mainbin[elemId].id = elemId;
2751                 player->pipeline->mainbin[elemId].gst = selector;
2752
2753                 first_track = TRUE;
2754                 // player->selector[stream_type].active_pad_index = DEFAULT_TRACK;      // default
2755
2756                 srcpad = gst_element_get_static_pad(selector, "src");
2757
2758                 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2759                 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
2760                         __mmplayer_gst_selector_blocked, NULL, NULL);
2761                 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
2762                         __mmplayer_gst_selector_event_probe, player, NULL);
2763
2764                 gst_element_set_state(selector, GST_STATE_PAUSED);
2765                 gst_bin_add(GST_BIN(pipeline), selector);
2766         } else
2767                 LOGD("input-selector is already created.\n");
2768
2769         // link
2770         LOGD("Calling request pad with selector %p \n", selector);
2771         sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2772
2773         LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(sinkpad));
2774
2775         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2776                 LOGW("failed to link selector\n");
2777                 gst_object_unref(GST_OBJECT(selector));
2778                 goto ERROR;
2779         }
2780
2781         if (first_track) {
2782                 LOGD("this is first track --> active track \n");
2783                 g_object_set(selector, "active-pad", sinkpad, NULL);
2784         }
2785
2786         _mmplayer_track_update_info(player, stream_type, sinkpad);
2787
2788
2789 DONE:
2790 ERROR:
2791
2792         if (caps)
2793                 gst_caps_unref(caps);
2794
2795         if (sinkpad) {
2796                 gst_object_unref(GST_OBJECT(sinkpad));
2797                 sinkpad = NULL;
2798         }
2799
2800         if (srcpad) {
2801                 gst_object_unref(GST_OBJECT(srcpad));
2802                 srcpad = NULL;
2803         }
2804
2805         return;
2806 }
2807
2808 static void __mmplayer_handle_text_decode_path(mm_player_t* player, GstElement* text_selector)
2809 {
2810         GstPad* srcpad = NULL;
2811         MMHandleType attrs = 0;
2812         gint active_index = 0;
2813
2814         // [link] input-selector :: textbin
2815         srcpad = gst_element_get_static_pad(text_selector, "src");
2816         if (!srcpad) {
2817                 LOGE("failed to get srcpad from selector\n");
2818                 return;
2819         }
2820
2821         LOGD("got pad %s:%s from text selector\n", GST_DEBUG_PAD_NAME(srcpad));
2822
2823         active_index = player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index;
2824         if ((active_index != DEFAULT_TRACK) &&
2825                 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_TEXT, active_index) != MM_ERROR_NONE)) {
2826                 LOGW("failed to change text track\n");
2827                 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index = DEFAULT_TRACK;
2828         }
2829
2830         player->no_more_pad = TRUE;
2831         __mmplayer_gst_decode_callback(text_selector, srcpad, player);
2832
2833         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2834         if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id) {
2835                 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id);
2836                 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id = 0;
2837         }
2838
2839         LOGD("Total text tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2840
2841         if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
2842                 player->has_closed_caption = TRUE;
2843
2844         attrs = MMPLAYER_GET_ATTRS(player);
2845         if (attrs) {
2846                 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2847                 if (mmf_attrs_commit(attrs))
2848                         LOGE("failed to commit.\n");
2849         } else
2850                 LOGE("cannot get content attribute");
2851
2852         if (srcpad) {
2853                 gst_object_unref(GST_OBJECT(srcpad));
2854                 srcpad = NULL;
2855         }
2856 }
2857
2858 int _mmplayer_gst_set_audio_channel(MMHandleType hplayer, MMPlayerAudioChannel ch_idx)
2859 {
2860         int result = MM_ERROR_NONE;
2861
2862         mm_player_t* player = (mm_player_t*)hplayer;
2863         MMPlayerGstElement* mainbin = NULL;
2864         gchar* change_pad_name = NULL;
2865         GstPad* sinkpad = NULL;
2866         GstCaps* caps = NULL;
2867
2868         MMPLAYER_FENTER();
2869
2870         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
2871
2872         LOGD("Change Audio mode to %d\n", ch_idx);
2873         player->use_deinterleave = TRUE;
2874
2875         if ((!player->pipeline) || (!player->pipeline->mainbin)) {
2876                 LOGD("pre setting : %d\n", ch_idx);
2877
2878                 player->audio_mode.active_pad_index = ch_idx;
2879                 return result;
2880         }
2881
2882         mainbin = player->pipeline->mainbin;
2883
2884         if (mainbin[MMPLAYER_M_A_SELECTOR].gst == NULL) {
2885                 if (player->max_audio_channels < 2) {
2886                         LOGD("mono channel track only\n");
2887                         return result;
2888                 }
2889
2890                 LOGW("selector doesn't exist\n");
2891                 return result;  /* keep playing */
2892         }
2893
2894         LOGD("total_ch_num : %d\n", player->audio_mode.total_track_num);
2895
2896         if (player->audio_mode.total_track_num < 2) {
2897                 LOGW("there is no another audio path\n");
2898                 return result;  /* keep playing */
2899         }
2900
2901         if ((ch_idx < 0) || (ch_idx >= player->audio_mode.total_track_num)) {
2902                 LOGW("Not a proper ch_idx : %d \n", ch_idx);
2903                 return result;  /* keep playing */
2904         }
2905
2906         /*To get the new pad from the selector*/
2907         change_pad_name = g_strdup_printf("sink%d", ch_idx);
2908         if (change_pad_name == NULL) {
2909                 LOGW("Pad does not exists\n");
2910                 goto ERROR;     /* keep playing */
2911         }
2912
2913         LOGD("new active pad name: %s\n", change_pad_name);
2914
2915         sinkpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_A_SELECTOR].gst, change_pad_name);
2916         if (sinkpad == NULL)
2917                 //result = MM_ERROR_PLAYER_INTERNAL;
2918                 goto ERROR;     /* keep playing */
2919
2920         LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
2921         g_object_set(mainbin[MMPLAYER_M_A_SELECTOR].gst, "active-pad", sinkpad, NULL);
2922
2923         caps = gst_pad_get_current_caps(sinkpad);
2924         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2925
2926         __mmplayer_set_audio_attrs(player, caps);
2927         player->audio_mode.active_pad_index = ch_idx;
2928
2929 ERROR:
2930
2931         if (sinkpad)
2932                 gst_object_unref(sinkpad);
2933
2934         MMPLAYER_FREEIF(change_pad_name);
2935
2936         MMPLAYER_FLEAVE();
2937         return result;
2938 }
2939
2940
2941
2942 static void
2943 __mmplayer_gst_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2944 {
2945         mm_player_t* player = (mm_player_t*)data;
2946         GstElement* selector = NULL;
2947         GstElement* queue = NULL;
2948
2949         GstPad* srcpad = NULL;
2950         GstPad* sinkpad = NULL;
2951         gchar* caps_str = NULL;
2952
2953         MMPLAYER_FENTER();
2954         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2955
2956         caps_str = gst_caps_to_string(gst_pad_get_current_caps(pad));
2957         LOGD("deinterleave new caps : %s\n", caps_str);
2958         MMPLAYER_FREEIF(caps_str);
2959
2960         if ((queue = __mmplayer_element_create_and_link(player, pad, "queue")) == NULL) {
2961                 LOGE("ERROR : queue create error\n");
2962                 goto ERROR;
2963         }
2964
2965         g_object_set(G_OBJECT(queue),
2966                                 "max-size-buffers", 10,
2967                                 "max-size-bytes", 0,
2968                                 "max-size-time", (guint64)0,
2969                                 NULL);
2970
2971         selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2972
2973         if (!selector) {
2974                 LOGE("there is no audio channel selector.\n");
2975                 goto ERROR;
2976         }
2977
2978         srcpad = gst_element_get_static_pad(queue, "src");
2979         sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2980
2981         LOGD("link(%s:%s - %s:%s)\n", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
2982
2983         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
2984                 LOGW("failed to link deinterleave - selector\n");
2985                 goto ERROR;
2986         }
2987
2988         gst_element_set_state(queue, GST_STATE_PAUSED);
2989         player->audio_mode.total_track_num++;
2990
2991 ERROR:
2992
2993         if (srcpad) {
2994                 gst_object_unref(GST_OBJECT(srcpad));
2995                 srcpad = NULL;
2996         }
2997
2998         if (sinkpad) {
2999                 gst_object_unref(GST_OBJECT(sinkpad));
3000                 sinkpad = NULL;
3001         }
3002
3003         MMPLAYER_FLEAVE();
3004         return;
3005 }
3006
3007 static void
3008 __mmplayer_gst_deinterleave_no_more_pads(GstElement *elem, gpointer data)
3009 {
3010         mm_player_t* player = NULL;
3011         GstElement* selector = NULL;
3012         GstPad* sinkpad = NULL;
3013         gint active_index = 0;
3014         gchar* change_pad_name = NULL;
3015         GstCaps* caps = NULL;   // no need to unref
3016         gint default_audio_ch = 0;
3017
3018         MMPLAYER_FENTER();
3019         player = (mm_player_t*) data;
3020
3021         selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
3022
3023         if (!selector) {
3024                 LOGE("there is no audio channel selector.\n");
3025                 goto ERROR;
3026         }
3027
3028         active_index = player->audio_mode.active_pad_index;
3029
3030         if (active_index != default_audio_ch) {
3031                 gint audio_ch = default_audio_ch;
3032
3033                 /*To get the new pad from the selector*/
3034                 change_pad_name = g_strdup_printf("sink%d", active_index);
3035                 if (change_pad_name != NULL) {
3036                         sinkpad = gst_element_get_static_pad(selector, change_pad_name);
3037                         if (sinkpad != NULL) {
3038                                 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
3039                                 g_object_set(selector, "active-pad", sinkpad, NULL);
3040
3041                                 audio_ch = active_index;
3042
3043                                 caps = gst_pad_get_current_caps(sinkpad);
3044                                 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
3045
3046                                 __mmplayer_set_audio_attrs(player, caps);
3047                         }
3048                         MMPLAYER_FREEIF(change_pad_name);
3049                 }
3050
3051                 player->audio_mode.active_pad_index = audio_ch;
3052                 LOGD("audio LR info(0:stereo) = %d\n", player->audio_mode.active_pad_index);
3053         }
3054
3055 ERROR:
3056
3057         if (sinkpad)
3058                 gst_object_unref(sinkpad);
3059
3060         MMPLAYER_FLEAVE();
3061         return;
3062 }
3063
3064 static void
3065 __mmplayer_gst_build_deinterleave_path(GstElement *elem, GstPad *pad, gpointer data)
3066 {
3067         mm_player_t* player = NULL;
3068         MMPlayerGstElement *mainbin = NULL;
3069
3070         GstElement* tee = NULL;
3071         GstElement* stereo_queue = NULL;
3072         GstElement* mono_queue = NULL;
3073         GstElement* conv = NULL;
3074         GstElement* filter = NULL;
3075         GstElement* deinterleave = NULL;
3076         GstElement* selector = NULL;
3077
3078         GstPad* srcpad = NULL;
3079         GstPad* selector_srcpad = NULL;
3080         GstPad* sinkpad = NULL;
3081         GstCaps* caps = NULL;
3082         gulong block_id = 0;
3083
3084         MMPLAYER_FENTER();
3085
3086         /* check handles */
3087         player = (mm_player_t*) data;
3088
3089         MMPLAYER_RETURN_IF_FAIL(elem && pad);
3090         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3091
3092         mainbin = player->pipeline->mainbin;
3093
3094         /* tee */
3095         if ((tee = __mmplayer_element_create_and_link(player, pad, "tee")) == NULL) {
3096                 LOGE("ERROR : tee create error\n");
3097                 goto ERROR;
3098         }
3099
3100         mainbin[MMPLAYER_M_A_TEE].id = MMPLAYER_M_A_TEE;
3101         mainbin[MMPLAYER_M_A_TEE].gst = tee;
3102
3103         gst_element_set_state(tee, GST_STATE_PAUSED);
3104
3105         /* queue */
3106         srcpad = gst_element_get_request_pad(tee, "src_%u");
3107         if ((stereo_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
3108                 LOGE("ERROR : stereo queue create error\n");
3109                 goto ERROR;
3110         }
3111
3112         g_object_set(G_OBJECT(stereo_queue),
3113                                 "max-size-buffers", 10,
3114                                 "max-size-bytes", 0,
3115                                 "max-size-time", (guint64)0,
3116                                 NULL);
3117
3118         player->pipeline->mainbin[MMPLAYER_M_A_Q1].id = MMPLAYER_M_A_Q1;
3119         player->pipeline->mainbin[MMPLAYER_M_A_Q1].gst = stereo_queue;
3120
3121         if (srcpad) {
3122                 gst_object_unref(GST_OBJECT(srcpad));
3123                 srcpad = NULL;
3124         }
3125
3126         srcpad = gst_element_get_request_pad(tee, "src_%u");
3127
3128         if ((mono_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
3129                 LOGE("ERROR : mono queue create error\n");
3130                 goto ERROR;
3131         }
3132
3133         g_object_set(G_OBJECT(mono_queue),
3134                                 "max-size-buffers", 10,
3135                                 "max-size-bytes", 0,
3136                                 "max-size-time", (guint64)0,
3137                                 NULL);
3138
3139         player->pipeline->mainbin[MMPLAYER_M_A_Q2].id = MMPLAYER_M_A_Q2;
3140         player->pipeline->mainbin[MMPLAYER_M_A_Q2].gst = mono_queue;
3141
3142         gst_element_set_state(stereo_queue, GST_STATE_PAUSED);
3143         gst_element_set_state(mono_queue, GST_STATE_PAUSED);
3144
3145         /* audioconvert */
3146         srcpad = gst_element_get_static_pad(mono_queue, "src");
3147         if ((conv = __mmplayer_element_create_and_link(player, srcpad, "audioconvert")) == NULL) {
3148                 LOGE("ERROR : audioconvert create error\n");
3149                 goto ERROR;
3150         }
3151
3152         player->pipeline->mainbin[MMPLAYER_M_A_CONV].id = MMPLAYER_M_A_CONV;
3153         player->pipeline->mainbin[MMPLAYER_M_A_CONV].gst = conv;
3154
3155         /* caps filter */
3156         if (srcpad) {
3157                 gst_object_unref(GST_OBJECT(srcpad));
3158                 srcpad = NULL;
3159         }
3160         srcpad = gst_element_get_static_pad(conv, "src");
3161
3162         if ((filter = __mmplayer_element_create_and_link(player, srcpad, "capsfilter")) == NULL) {
3163                 LOGE("ERROR : capsfilter create error\n");
3164                 goto ERROR;
3165         }
3166
3167         player->pipeline->mainbin[MMPLAYER_M_A_FILTER].id = MMPLAYER_M_A_FILTER;
3168         player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst = filter;
3169
3170         caps = gst_caps_from_string("audio/x-raw-int, "
3171                                 "width = (int) 16, "
3172                                 "depth = (int) 16, "
3173                                 "channels = (int) 2");
3174
3175         g_object_set(GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst), "caps", caps, NULL);
3176         gst_caps_unref(caps);
3177
3178         gst_element_set_state(conv, GST_STATE_PAUSED);
3179         gst_element_set_state(filter, GST_STATE_PAUSED);
3180
3181         /* deinterleave */
3182         if (srcpad) {
3183                 gst_object_unref(GST_OBJECT(srcpad));
3184                 srcpad = NULL;
3185         }
3186         srcpad = gst_element_get_static_pad(filter, "src");
3187
3188         if ((deinterleave = __mmplayer_element_create_and_link(player, srcpad, "deinterleave")) == NULL) {
3189                 LOGE("ERROR : deinterleave create error\n");
3190                 goto ERROR;
3191         }
3192
3193         g_object_set(deinterleave, "keep-positions", TRUE, NULL);
3194
3195         MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
3196                                                         G_CALLBACK(__mmplayer_gst_deinterleave_pad_added), player);
3197
3198         MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
3199                                                         G_CALLBACK(__mmplayer_gst_deinterleave_no_more_pads), player);
3200
3201         player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].id = MMPLAYER_M_A_DEINTERLEAVE;
3202         player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].gst = deinterleave;
3203
3204         /* selector */
3205         selector = gst_element_factory_make("input-selector", "audio-channel-selector");
3206         if (selector == NULL) {
3207                 LOGE("ERROR : audio-selector create error\n");
3208                 goto ERROR;
3209         }
3210
3211         g_object_set(selector, "sync-streams", TRUE, NULL);
3212         gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), selector);
3213
3214         player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].id = MMPLAYER_M_A_SELECTOR;
3215         player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst = selector;
3216
3217         selector_srcpad = gst_element_get_static_pad(selector, "src");
3218
3219         LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3220         block_id =
3221                 gst_pad_add_probe(selector_srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
3222                         __mmplayer_gst_selector_blocked, NULL, NULL);
3223
3224         if (srcpad) {
3225                 gst_object_unref(GST_OBJECT(srcpad));
3226                 srcpad = NULL;
3227         }
3228
3229         srcpad = gst_element_get_static_pad(stereo_queue, "src");
3230         sinkpad = gst_element_get_request_pad(selector, "sink_%u");
3231
3232         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
3233                 LOGW("failed to link queue_stereo - selector\n");
3234                 goto ERROR;
3235         }
3236
3237         player->audio_mode.total_track_num++;
3238
3239         g_object_set(selector, "active-pad", sinkpad, NULL);
3240         gst_element_set_state(deinterleave, GST_STATE_PAUSED);
3241         gst_element_set_state(selector, GST_STATE_PAUSED);
3242
3243         __mmplayer_gst_decode_callback(selector, selector_srcpad, player);
3244
3245 ERROR:
3246
3247         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3248         if (block_id != 0) {
3249                 gst_pad_remove_probe(selector_srcpad, block_id);
3250                 block_id = 0;
3251         }
3252
3253         if (sinkpad) {
3254                 gst_object_unref(GST_OBJECT(sinkpad));
3255                 sinkpad = NULL;
3256         }
3257
3258         if (srcpad) {
3259                 gst_object_unref(GST_OBJECT(srcpad));
3260                 srcpad = NULL;
3261         }
3262
3263         if (selector_srcpad) {
3264                 gst_object_unref(GST_OBJECT(selector_srcpad));
3265                 selector_srcpad = NULL;
3266         }
3267
3268         MMPLAYER_FLEAVE();
3269         return;
3270 }
3271
3272 static void
3273 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
3274 {
3275         mm_player_t* player = NULL;
3276         GstPad* srcpad = NULL;
3277         GstElement* video_selector = NULL;
3278         GstElement* audio_selector = NULL;
3279         GstElement* text_selector = NULL;
3280         MMHandleType attrs = 0;
3281         gint active_index = 0;
3282         gint64 dur_bytes = 0L;
3283
3284         player = (mm_player_t*) data;
3285
3286         LOGD("no-more-pad signal handling\n");
3287
3288         if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
3289                 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
3290                 LOGW("no need to go more");
3291
3292                 if (player->gapless.reconfigure) {
3293                         player->gapless.reconfigure = FALSE;
3294                         MMPLAYER_PLAYBACK_UNLOCK(player);
3295                 }
3296
3297                 return;
3298         }
3299
3300         if ((!MMPLAYER_IS_HTTP_PD(player)) &&
3301                 (MMPLAYER_IS_HTTP_STREAMING(player)) &&
3302                 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
3303                 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
3304                 #define ESTIMATED_BUFFER_UNIT (1*1024*1024)
3305
3306                 if (NULL == player->streamer) {
3307                         LOGW("invalid state for buffering");
3308                         goto ERROR;
3309                 }
3310
3311                 gdouble init_buffering_time = (gdouble)player->streamer->buffering_req.initial_second;
3312                 guint buffer_bytes = init_buffering_time * ESTIMATED_BUFFER_UNIT;
3313
3314                 buffer_bytes = MAX(buffer_bytes, player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffering_bytes);
3315                 LOGD("[Decodebin2] set use-buffering on Q2(pre buffer time: %d sec, buffer size : %d)\n", (gint)init_buffering_time, buffer_bytes);
3316
3317                 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
3318
3319                 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
3320                         LOGE("fail to get duration.\n");
3321
3322                 // enable use-buffering on queue2 instead of multiqueue(ex)audio only streaming
3323                 // use file information was already set on Q2 when it was created.
3324                 __mm_player_streaming_set_queue2(player->streamer,
3325                                                 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
3326                                                 TRUE,                                                           // use_buffering
3327                                                 buffer_bytes,
3328                                                 init_buffering_time,
3329                                                 1.0,                                                            // low percent
3330                                                 player->ini.http_buffering_limit,       // high percent
3331                                                 MUXED_BUFFER_TYPE_MEM_QUEUE,
3332                                                 NULL,
3333                                                 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
3334         }
3335
3336         video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
3337         audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
3338         text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3339         if (video_selector) {
3340                 // [link] input-selector :: videobin
3341                 srcpad = gst_element_get_static_pad(video_selector, "src");
3342                 if (!srcpad) {
3343                         LOGE("failed to get srcpad from video selector\n");
3344                         goto ERROR;
3345                 }
3346
3347                 LOGD("got pad %s:%s from video selector\n", GST_DEBUG_PAD_NAME(srcpad));
3348                 if (!text_selector && !audio_selector)
3349                         player->no_more_pad = TRUE;
3350
3351                 __mmplayer_gst_decode_callback(video_selector, srcpad, player);
3352
3353                 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3354                 if (player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id) {
3355                         gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id);
3356                         player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id = 0;
3357                 }
3358         }
3359
3360         if (audio_selector) {
3361                 active_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
3362                 if ((active_index != DEFAULT_TRACK) &&
3363                         (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_AUDIO, active_index) != MM_ERROR_NONE)) {
3364                         LOGW("failed to change audio track\n");
3365                         player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index = DEFAULT_TRACK;
3366                 }
3367
3368                 // [link] input-selector :: audiobin
3369                 srcpad = gst_element_get_static_pad(audio_selector, "src");
3370                 if (!srcpad) {
3371                         LOGE("failed to get srcpad from selector\n");
3372                         goto ERROR;
3373                 }
3374
3375                 LOGD("got pad %s:%s from selector\n", GST_DEBUG_PAD_NAME(srcpad));
3376                 if (!text_selector)
3377                         player->no_more_pad = TRUE;
3378
3379                 if ((player->use_deinterleave == TRUE) && (player->max_audio_channels >= 2)) {
3380                         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3381                         if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3382                                 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3383                                 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3384                         }
3385
3386                         __mmplayer_gst_build_deinterleave_path(audio_selector, srcpad, player);
3387                 } else {
3388                         __mmplayer_gst_decode_callback(audio_selector, srcpad, player);
3389
3390                         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3391                         if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3392                                 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3393                                 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3394                         }
3395                 }
3396
3397                 LOGD("Total audio tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3398
3399                 attrs = MMPLAYER_GET_ATTRS(player);
3400                 if (attrs) {
3401                         mm_attrs_set_int_by_name(attrs, "content_audio_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3402                         if (mmf_attrs_commit(attrs))
3403                                 LOGE("failed to commit.\n");
3404                 } else
3405                         LOGE("cannot get content attribute");
3406         } else {
3407                 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
3408                         LOGD("There is no audio track : remove audiobin");
3409
3410                         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
3411                         __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
3412
3413                         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
3414                         MMPLAYER_FREEIF(player->pipeline->audiobin)
3415                 }
3416
3417                 if (player->num_dynamic_pad == 0)
3418                         __mmplayer_pipeline_complete(NULL, player);
3419         }
3420
3421         if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
3422                 if (text_selector)
3423                         __mmplayer_handle_text_decode_path(player, text_selector);
3424         }
3425
3426         MMPLAYER_FLEAVE();
3427
3428 ERROR:
3429         if (srcpad) {
3430                 gst_object_unref(GST_OBJECT(srcpad));
3431                 srcpad = NULL;
3432         }
3433
3434         if (player->gapless.reconfigure) {
3435                 player->gapless.reconfigure = FALSE;
3436                 MMPLAYER_PLAYBACK_UNLOCK(player);
3437         }
3438 }
3439
3440 static void
3441 __mmplayer_gst_decode_callback(GstElement *elem, GstPad *pad, gpointer data) // @
3442 {
3443         mm_player_t* player = NULL;
3444         MMHandleType attrs = 0;
3445         GstElement* pipeline = NULL;
3446         GstCaps* caps = NULL;
3447         gchar* caps_str = NULL;
3448         GstStructure* str = NULL;
3449         const gchar* name = NULL;
3450         GstPad* sinkpad = NULL;
3451         GstElement* sinkbin = NULL;
3452         gboolean reusing = FALSE;
3453         GstElement *text_selector = NULL;
3454         MMPlayerResourceState resource_state = RESOURCE_STATE_NONE;
3455
3456         /* check handles */
3457         player = (mm_player_t*) data;
3458
3459         MMPLAYER_RETURN_IF_FAIL(elem && pad);
3460         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3461
3462         pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
3463
3464         attrs = MMPLAYER_GET_ATTRS(player);
3465         if (!attrs) {
3466                 LOGE("cannot get content attribute\n");
3467                 goto ERROR;
3468         }
3469
3470         /* get mimetype from caps */
3471         caps = gst_pad_query_caps(pad, NULL);
3472         if (!caps) {
3473                 LOGE("cannot get caps from pad.\n");
3474                 goto ERROR;
3475         }
3476         caps_str = gst_caps_to_string(caps);
3477
3478         str = gst_caps_get_structure(caps, 0);
3479         if (!str) {
3480                 LOGE("cannot get structure from caps.\n");
3481                 goto ERROR;
3482         }
3483
3484         name = gst_structure_get_name(str);
3485         if (!name) {
3486                 LOGE("cannot get mimetype from structure.\n");
3487                 goto ERROR;
3488         }
3489
3490         //LOGD("detected mimetype : %s\n", name);
3491
3492         if (strstr(name, "audio")) {
3493                 if (player->pipeline->audiobin == NULL) {
3494                         if (MM_ERROR_NONE !=  __mmplayer_gst_create_audio_pipeline(player)) {
3495                                 LOGE("failed to create audiobin. continuing without audio\n");
3496                                 goto ERROR;
3497                         }
3498
3499                         sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3500                         LOGD("creating audiosink bin success\n");
3501                 } else {
3502                         reusing = TRUE;
3503                         sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3504                         LOGD("reusing audiobin\n");
3505                         _mmplayer_update_content_attrs(player, ATTR_AUDIO);
3506                 }
3507
3508                 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num <= 0) // should not update if content have multi audio tracks
3509                         mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 1);
3510
3511                 player->audiosink_linked  = 1;
3512
3513                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3514                 if (!sinkpad) {
3515                         LOGE("failed to get pad from sinkbin\n");
3516                         goto ERROR;
3517                 }
3518         } else if (strstr(name, "video")) {
3519                 if (strstr(caps_str, "ST12") || strstr(caps_str, "SN12"))
3520                         player->set_mode.video_zc = TRUE;
3521
3522                 if (player->pipeline->videobin == NULL) {
3523                         /* NOTE : not make videobin because application dose not want to play it even though file has video stream. */
3524                         /* get video surface type */
3525                         int surface_type = 0;
3526                         mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3527                         LOGD("display_surface_type(%d)\n", surface_type);
3528
3529                         if (surface_type == MM_DISPLAY_SURFACE_NULL) {
3530                                 LOGD("not make videobin because it dose not want\n");
3531                                 goto ERROR;
3532                         }
3533
3534                         if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3535                                 if (_mmplayer_resource_manager_get_state(&player->resource_manager, &resource_state) == MM_ERROR_NONE) {
3536                                         /* prepare resource manager for video overlay */
3537                                         if (resource_state >= RESOURCE_STATE_INITIALIZED) {
3538                                                 if (_mmplayer_resource_manager_prepare(&player->resource_manager, RESOURCE_TYPE_VIDEO_OVERLAY)
3539                                                         != MM_ERROR_NONE) {
3540                                                         LOGE("could not prepare for video_overlay resource\n");
3541                                                         goto ERROR;
3542                                                 }
3543                                         }
3544                                 }
3545                         }
3546
3547                         if (_mmplayer_resource_manager_get_state(&player->resource_manager, &resource_state)
3548                                 == MM_ERROR_NONE) {
3549                                 /* acquire resources for video playing */
3550                                 if (resource_state == RESOURCE_STATE_PREPARED) {
3551                                         if (_mmplayer_resource_manager_acquire(&player->resource_manager)
3552                                                 != MM_ERROR_NONE) {
3553                                                 LOGE("could not acquire resources for video playing\n");
3554                                                 _mmplayer_resource_manager_unprepare(&player->resource_manager);
3555                                                 goto ERROR;
3556                                         }
3557                                 }
3558                         }
3559
3560                         if (MM_ERROR_NONE !=  __mmplayer_gst_create_video_pipeline(player, caps, surface_type)) {
3561                                 LOGE("failed to create videobin. continuing without video\n");
3562                                 goto ERROR;
3563                         }
3564
3565                         sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3566                         LOGD("creating videosink bin success\n");
3567                 } else {
3568                         reusing = TRUE;
3569                         sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3570                         LOGD("re-using videobin\n");
3571                         _mmplayer_update_content_attrs(player, ATTR_VIDEO);
3572                 }
3573
3574                 /* FIXIT : track number shouldn't be hardcoded */
3575                 mm_attrs_set_int_by_name(attrs, "content_video_track_num", 1);
3576                 player->videosink_linked  = 1;
3577
3578                 /* NOTE : intermediate code before doing H/W subtitle compositon */
3579                 if (player->use_textoverlay && player->play_subtitle) {
3580                         LOGD("using textoverlay for external subtitle");
3581                         /* check text bin has created well */
3582                         if (player->pipeline && player->pipeline->textbin) {
3583                                 /* get sinkpad from textoverlay */
3584                                 sinkpad = gst_element_get_static_pad(
3585                                         GST_ELEMENT(player->pipeline->textbin[MMPLAYER_T_BIN].gst),
3586                                         "video_sink");
3587                                 if (!sinkpad) {
3588                                         LOGE("failed to get sink pad from textoverlay");
3589                                         goto ERROR;
3590                                 }
3591
3592                                 /* link new pad with textoverlay first */
3593                                 if (GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad)) {
3594                                         LOGE("failed to get pad from sinkbin\n");
3595                                         goto ERROR;
3596                                 }
3597
3598                                 gst_object_unref(sinkpad);
3599                                 sinkpad = NULL;
3600
3601                                 /* alright, override pad to textbin.src for futher link */
3602                                 pad = gst_element_get_static_pad(
3603                                         GST_ELEMENT(player->pipeline->textbin[MMPLAYER_T_BIN].gst),
3604                                         "src");
3605                                 if (!pad) {
3606                                         LOGE("failed to get sink pad from textoverlay");
3607                                         goto ERROR;
3608                                 }
3609                         } else {
3610                                 LOGE("should not reach here.");
3611                                 goto ERROR;
3612                         }
3613                 }
3614
3615                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3616                 if (!sinkpad) {
3617                         LOGE("failed to get pad from sinkbin\n");
3618                         goto ERROR;
3619                 }
3620         } else if (strstr(name, "text")) {
3621                 if (player->pipeline->textbin == NULL) {
3622                         MMPlayerGstElement* mainbin = NULL;
3623
3624                         if (MM_ERROR_NONE !=  __mmplayer_gst_create_text_pipeline(player)) {
3625                                 LOGE("failed to create textbin. continuing without text\n");
3626                                 goto ERROR;
3627                         }
3628
3629                         sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3630                         LOGD("creating textsink bin success\n");
3631
3632                         /* FIXIT : track number shouldn't be hardcoded */
3633                         mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1);
3634
3635                         player->textsink_linked  = 1;
3636                         LOGI("player->textsink_linked set to 1\n");
3637
3638                         sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "text_sink");
3639                         if (!sinkpad) {
3640                                 LOGE("failed to get pad from sinkbin\n");
3641                                 goto ERROR;
3642                         }
3643
3644                         mainbin = player->pipeline->mainbin;
3645
3646                         if (!mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst) {
3647                                 /* input selector */
3648                                 text_selector = gst_element_factory_make("input-selector", "subtitle_inselector");
3649                                 if (!text_selector) {
3650                                         LOGE("failed to create subtitle input selector element\n");
3651                                         goto ERROR;
3652                                 }
3653                                 g_object_set(text_selector, "sync-streams", TRUE, NULL);
3654
3655                                 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].id = MMPLAYER_M_T_INPUT_SELECTOR;
3656                                 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst = text_selector;
3657
3658                                 /* warm up */
3659                                 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_READY)) {
3660                                         LOGE("failed to set state(READY) to sinkbin\n");
3661                                         goto ERROR;
3662                                 }
3663
3664                                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), text_selector)) {
3665                                         LOGW("failed to add subtitle input selector\n");
3666                                         goto ERROR;
3667                                 }
3668
3669                                 LOGD("created element input-selector");
3670
3671                         } else {
3672                                 LOGD("already having subtitle input selector");
3673                                 text_selector = mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3674                         }
3675                 } else {
3676                         if (!player->textsink_linked) {
3677                                 LOGD("re-using textbin\n");
3678
3679                                 reusing = TRUE;
3680                                 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3681
3682                                 player->textsink_linked  = 1;
3683                                 LOGI("player->textsink_linked set to 1\n");
3684                         } else
3685                                 LOGD("ignoring internal subtutle since external subtitle is available");
3686                 }
3687         } else {
3688                 LOGW("unknown type of elementary stream!ignoring it...\n");
3689                 goto ERROR;
3690         }
3691
3692         if (sinkbin) {
3693                 if (!reusing) {
3694                         /* warm up */
3695                         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_READY)) {
3696                                 LOGE("failed to set state(READY) to sinkbin\n");
3697                                 goto ERROR;
3698                         }
3699
3700                         /* Added for multi audio support to avoid adding audio bin again*/
3701                         /* add */
3702                         if (FALSE == gst_bin_add(GST_BIN(pipeline), sinkbin)) {
3703                                 LOGE("failed to add sinkbin to pipeline\n");
3704                                 goto ERROR;
3705                         }
3706                 }
3707
3708                 /* link */
3709                 if (GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad)) {
3710                         LOGE("failed to get pad from sinkbin\n");
3711                         goto ERROR;
3712                 }
3713
3714                 if (!reusing) {
3715                         /* run */
3716                         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_PAUSED)) {
3717                                 LOGE("failed to set state(PAUSED) to sinkbin\n");
3718                                 goto ERROR;
3719                         }
3720
3721                         if (text_selector) {
3722                                 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_PAUSED)) {
3723                                         LOGE("failed to set state(PAUSED) to sinkbin\n");
3724                                         goto ERROR;
3725                                 }
3726                         }
3727                 }
3728
3729                 gst_object_unref(sinkpad);
3730                 sinkpad = NULL;
3731         }
3732
3733         LOGD("linking sink bin success\n");
3734
3735         /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
3736          * streaming task. if the task blocked, then buffer will not flow to the next element
3737          *(autoplugging element). so this is special hack for streaming. please try to remove it
3738          */
3739         /* dec stream count. we can remove fakesink if it's zero */
3740         if (player->num_dynamic_pad)
3741                 player->num_dynamic_pad--;
3742
3743         LOGD("no more pads: %d stream count dec : %d(num of dynamic pad)\n", player->no_more_pad, player->num_dynamic_pad);
3744
3745         if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
3746                 __mmplayer_pipeline_complete(NULL, player);
3747
3748         /* FIXIT : please leave a note why this code is needed */
3749         if (MMPLAYER_IS_WFD_STREAMING(player))
3750                 player->no_more_pad = TRUE;
3751
3752 ERROR:
3753
3754         MMPLAYER_FREEIF(caps_str);
3755
3756         if (caps)
3757                 gst_caps_unref(caps);
3758
3759         if (sinkpad)
3760                 gst_object_unref(GST_OBJECT(sinkpad));
3761
3762         /* flusing out new attributes */
3763         if (mmf_attrs_commit(attrs))
3764                 LOGE("failed to comit attributes\n");
3765
3766         return;
3767 }
3768
3769 static gboolean
3770 __mmplayer_get_property_value_for_rotation(mm_player_t* player, int rotation_angle, int *value)
3771 {
3772         int pro_value = 0; // in the case of expection, default will be returned.
3773         int dest_angle = rotation_angle;
3774         int rotation_type = -1;
3775
3776         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3777         MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
3778         MMPLAYER_RETURN_VAL_IF_FAIL(rotation_angle >= 0, FALSE);
3779
3780         if (rotation_angle >= 360)
3781                 dest_angle = rotation_angle - 360;
3782
3783         /* chech if supported or not */
3784         if (dest_angle % 90) {
3785                 LOGD("not supported rotation angle = %d", rotation_angle);
3786                 return FALSE;
3787         }
3788
3789         /*
3790           * waylandsink (A)
3791           * custom_convert - none (B)
3792           * videoflip - none (C)
3793           */
3794         if (player->set_mode.video_zc) {
3795                 if (player->pipeline->videobin[MMPLAYER_V_CONV].gst) // B
3796                         rotation_type = ROTATION_USING_CUSTOM;
3797                 else // A
3798                         rotation_type = ROTATION_USING_SINK;
3799         } else {
3800                 int surface_type = 0;
3801                 rotation_type = ROTATION_USING_FLIP;
3802
3803                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3804                 LOGD("check display surface type attribute: %d", surface_type);
3805
3806                 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY)
3807                         rotation_type = ROTATION_USING_SINK;
3808                 else
3809                         rotation_type = ROTATION_USING_FLIP; //C
3810
3811                 LOGD("using %d type for rotation", rotation_type);
3812         }
3813
3814         /* get property value for setting */
3815         switch (rotation_type) {
3816         case ROTATION_USING_SINK: // waylandsink
3817                 {
3818                         switch (dest_angle) {
3819                         case 0:
3820                                 break;
3821                         case 90:
3822                                 pro_value = 3; // clockwise 90
3823                                 break;
3824                         case 180:
3825                                 pro_value = 2;
3826                                 break;
3827                         case 270:
3828                                 pro_value = 1; // counter-clockwise 90
3829                                 break;
3830                         }
3831                 }
3832                 break;
3833         case ROTATION_USING_CUSTOM:
3834                 {
3835                         gchar *ename = NULL;
3836                         ename = GST_OBJECT_NAME(gst_element_get_factory(player->pipeline->videobin[MMPLAYER_V_CONV].gst));
3837
3838                         if (g_strrstr(ename, "fimcconvert")) {
3839                                 switch (dest_angle) {
3840                                 case 0:
3841                                         break;
3842                                 case 90:
3843                                         pro_value = 90; // clockwise 90
3844                                         break;
3845                                 case 180:
3846                                         pro_value = 180;
3847                                         break;
3848                                 case 270:
3849                                         pro_value = 270; // counter-clockwise 90
3850                                         break;
3851                                 }
3852                         }
3853                 }
3854                 break;
3855         case ROTATION_USING_FLIP: // videoflip
3856                 {
3857                                 switch (dest_angle) {
3858                                 case 0:
3859                                         break;
3860                                 case 90:
3861                                         pro_value = 1; // clockwise 90
3862                                         break;
3863                                 case 180:
3864                                         pro_value = 2;
3865                                         break;
3866                                 case 270:
3867                                         pro_value = 3; // counter-clockwise 90
3868                                         break;
3869                                 }
3870                 }
3871                 break;
3872         }
3873
3874         LOGD("setting rotation property value : %d, used rotation type : %d", pro_value, rotation_type);
3875
3876         *value = pro_value;
3877
3878         return TRUE;
3879 }
3880
3881 int
3882 __mmplayer_video_param_check_video_sink_bin(mm_player_t* player)
3883 {
3884         /* check video sinkbin is created */
3885         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3886                 player->pipeline &&
3887                 player->pipeline->videobin &&
3888                 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
3889                 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3890                 MM_ERROR_PLAYER_NOT_INITIALIZED);
3891
3892         return MM_ERROR_NONE;
3893 }
3894
3895 void
3896 __mmplayer_video_param_set_display_rotation(mm_player_t* player)
3897 {
3898         int rotation_value = 0;
3899         int org_angle = 0; // current supported angle values are 0, 90, 180, 270
3900         int user_angle = 0;
3901         MMPLAYER_FENTER();
3902
3903         /* check video sinkbin is created */
3904         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3905                 return;
3906
3907         __mmplayer_get_video_angle(player, &user_angle, &org_angle);
3908
3909         /* get rotation value to set */
3910         __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
3911         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
3912         LOGD("set video param : rotate %d", rotation_value);
3913 }
3914
3915 void
3916 __mmplayer_video_param_set_display_visible(mm_player_t* player)
3917 {
3918         MMHandleType attrs = 0;
3919         int visible = 0;
3920         MMPLAYER_FENTER();
3921
3922         /* check video sinkbin is created */
3923         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3924                 return;
3925
3926         attrs = MMPLAYER_GET_ATTRS(player);
3927         MMPLAYER_RETURN_IF_FAIL(attrs);
3928
3929         mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
3930         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
3931         LOGD("set video param : visible %d", visible);
3932 }
3933
3934 void
3935 __mmplayer_video_param_set_display_method(mm_player_t* player)
3936 {
3937         MMHandleType attrs = 0;
3938         int display_method = 0;
3939         MMPLAYER_FENTER();
3940
3941         /* check video sinkbin is created */
3942         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3943                 return;
3944
3945         attrs = MMPLAYER_GET_ATTRS(player);
3946         MMPLAYER_RETURN_IF_FAIL(attrs);
3947
3948         mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
3949         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
3950         LOGD("set video param : method %d", display_method);
3951 }
3952
3953 void
3954 __mmplayer_video_param_set_render_rectangle(mm_player_t* player)
3955 {
3956         MMHandleType attrs = 0;
3957         int display_method = 0;
3958         void *handle = NULL;
3959         /*set wl_display*/
3960         int wl_window_x = 0;
3961         int wl_window_y = 0;
3962         int wl_window_width = 0;
3963         int wl_window_height = 0;
3964         MMPLAYER_FENTER();
3965
3966         /* check video sinkbin is created */
3967         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3968                 return;
3969
3970         attrs = MMPLAYER_GET_ATTRS(player);
3971         MMPLAYER_RETURN_IF_FAIL(attrs);
3972
3973         /* check roi mode is set */
3974         mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
3975         if (display_method != PLAYER_DISPLAY_MODE_DST_ROI) {
3976                 LOGE("must be set display-geometry-method to DISP_GEO_METHOD_CUSTOM_ROI before setting render rectangle");
3977                 return;
3978         }
3979         mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3980
3981         if (handle) {
3982                 /*It should be set after setting window*/
3983                 mm_attrs_get_int_by_name(attrs, "wl_window_render_x", &wl_window_x);
3984                 mm_attrs_get_int_by_name(attrs, "wl_window_render_y", &wl_window_y);
3985                 mm_attrs_get_int_by_name(attrs, "wl_window_render_width", &wl_window_width);
3986                 mm_attrs_get_int_by_name(attrs, "wl_window_render_height", &wl_window_height);
3987
3988                 /* After setting window handle, set render      rectangle */
3989                 gst_video_overlay_set_render_rectangle(
3990                          GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3991                          wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3992                 LOGD("set video param : render rectangle : x(%d) y(%d) width(%d) height(%d)",
3993                         wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3994
3995         }
3996 }
3997 void
3998 __mmplayer_video_param_set_display_overlay(mm_player_t* player)
3999 {
4000         MMHandleType attrs = 0;
4001         void *handle = NULL;
4002         /*use wl_surface*/
4003         gboolean use_wl_surface = 0;
4004         void * wl_display = NULL;
4005         GstContext *context = NULL;
4006
4007         /* check video sinkbin is created */
4008         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
4009                 return;
4010
4011         attrs = MMPLAYER_GET_ATTRS(player);
4012         MMPLAYER_RETURN_IF_FAIL(attrs);
4013
4014         /* common case if using overlay surface */
4015         mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
4016         mm_attrs_get_int_by_name(attrs, "use_wl_surface", &use_wl_surface);
4017
4018         if (handle && !use_wl_surface) {
4019                 /* default is using wl_surface_id */
4020                 unsigned int wl_surface_id      = 0;
4021                 wl_surface_id = *(int*)handle;
4022                 LOGD("set video param : wl_surface_id %d %p", wl_surface_id, *(int*)handle);
4023                 gst_video_overlay_set_wl_window_wl_surface_id(
4024                                 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
4025                                 *(int*)handle);
4026         } else if (handle && use_wl_surface) {
4027                 /* use wl_surface for legacy_player_test */
4028                 mm_attrs_get_data_by_name(attrs, "wl_display", &wl_display);
4029                 if (wl_display)
4030                         context = gst_wayland_display_handle_context_new(wl_display);
4031                 if (context)
4032                         gst_element_set_context(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), context);
4033
4034                 guintptr wl_surface = (guintptr)handle;
4035                 LOGD("[use wl_surface for legacy_player_test] set video param : wayland surface %p", handle);
4036                 gst_video_overlay_set_window_handle(
4037                                 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
4038                                 wl_surface);
4039         } else
4040                 /* FIXIT : is it error case? */
4041                 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
4042 }
4043
4044
4045 int
4046 __mmplayer_update_wayland_videosink_video_param(mm_player_t* player, char *param_name)
4047 {
4048         bool update_all_param = FALSE;
4049         MMPLAYER_FENTER();
4050
4051         /* check video sinkbin is created */
4052         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
4053                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4054
4055         if (strcmp(player->ini.videosink_element_overlay, "waylandsink")) {
4056                 LOGE("can not find waylandsink");
4057                 return MM_ERROR_PLAYER_INTERNAL;
4058         }
4059
4060         LOGD("param_name : %s", param_name);
4061         if (!g_strcmp0(param_name, "update_all_param"))
4062                 update_all_param = TRUE;
4063
4064         if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
4065                 __mmplayer_video_param_set_display_overlay(player);
4066         if (update_all_param || !g_strcmp0(param_name, "display_method"))
4067                 __mmplayer_video_param_set_display_method(player);
4068         if (update_all_param || !g_strcmp0(param_name, "wl_window_render_x"))
4069                 __mmplayer_video_param_set_render_rectangle(player);
4070         if (update_all_param || !g_strcmp0(param_name, "display_visible"))
4071                 __mmplayer_video_param_set_display_visible(player);
4072         if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
4073                 __mmplayer_video_param_set_display_rotation(player);
4074
4075         return MM_ERROR_NONE;
4076 }
4077
4078 int
4079 _mmplayer_update_video_param(mm_player_t* player, char *param_name) // @
4080 {
4081         MMHandleType attrs = 0;
4082         int surface_type = 0;
4083         int ret = MM_ERROR_NONE;
4084
4085         MMPLAYER_FENTER();
4086
4087         /* check video sinkbin is created */
4088         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
4089                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4090
4091         attrs = MMPLAYER_GET_ATTRS(player);
4092         if (!attrs) {
4093                 LOGE("cannot get content attribute");
4094                 return MM_ERROR_PLAYER_INTERNAL;
4095         }
4096         LOGD("param_name : %s", param_name);
4097
4098         /* update display surface */
4099         mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
4100         LOGD("check display surface type attribute: %d", surface_type);
4101
4102         /* configuring display */
4103         switch (surface_type) {
4104         case MM_DISPLAY_SURFACE_OVERLAY:
4105                 {
4106                         ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
4107                         if (ret != MM_ERROR_NONE)
4108                                 return ret;
4109                 }
4110                 break;
4111         }
4112
4113         MMPLAYER_FLEAVE();
4114
4115         return MM_ERROR_NONE;
4116 }
4117
4118 static int
4119 __mmplayer_gst_element_link_bucket(GList* element_bucket) // @
4120 {
4121         GList* bucket = element_bucket;
4122         MMPlayerGstElement* element = NULL;
4123         MMPlayerGstElement* prv_element = NULL;
4124         gint successful_link_count = 0;
4125
4126         MMPLAYER_FENTER();
4127
4128         MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
4129
4130         prv_element = (MMPlayerGstElement*)bucket->data;
4131         bucket = bucket->next;
4132
4133         for (; bucket; bucket = bucket->next) {
4134                 element = (MMPlayerGstElement*)bucket->data;
4135
4136                 if (element && element->gst) {
4137                         /* If next element is audio appsrc then make a separate audio pipeline */
4138                         if (!strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "audio_appsrc") ||
4139                                 !strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "subtitle_appsrc")) {
4140                                 prv_element = element;
4141                                 continue;
4142                         }
4143
4144                         if (prv_element && prv_element->gst) {
4145                                 if (GST_ELEMENT_LINK(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
4146                                         LOGD("linking [%s] to [%s] success\n",
4147                                                 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4148                                                 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4149                                         successful_link_count++;
4150                                 } else {
4151                                         LOGD("linking [%s] to [%s] failed\n",
4152                                                 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4153                                                 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4154                                         return -1;
4155                                 }
4156                         }
4157                 }
4158
4159                 prv_element = element;
4160         }
4161
4162         MMPLAYER_FLEAVE();
4163
4164         return successful_link_count;
4165 }
4166
4167 static int
4168 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket) // @
4169 {
4170         GList* bucket = element_bucket;
4171         MMPlayerGstElement* element = NULL;
4172         int successful_add_count = 0;
4173
4174         MMPLAYER_FENTER();
4175
4176         MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
4177         MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
4178
4179         for (; bucket; bucket = bucket->next) {
4180                 element = (MMPlayerGstElement*)bucket->data;
4181
4182                 if (element && element->gst) {
4183                         if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
4184                                 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s]  to bin [%s] failed\n",
4185                                         GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
4186                                         GST_ELEMENT_NAME(GST_ELEMENT(bin)));
4187                                 return 0;
4188                         }
4189                         successful_add_count++;
4190                 }
4191         }
4192
4193         MMPLAYER_FLEAVE();
4194
4195         return successful_add_count;
4196 }
4197
4198 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data)
4199 {
4200         mm_player_t* player = (mm_player_t*) data;
4201         GstCaps *caps = NULL;
4202         GstStructure *str = NULL;
4203         const char *name;
4204
4205         MMPLAYER_FENTER();
4206
4207         MMPLAYER_RETURN_IF_FAIL(pad)
4208         MMPLAYER_RETURN_IF_FAIL(unused)
4209         MMPLAYER_RETURN_IF_FAIL(data)
4210
4211         caps = gst_pad_get_current_caps(pad);
4212         if (!caps)
4213                 return;
4214
4215         str = gst_caps_get_structure(caps, 0);
4216         if (!str)
4217                 goto ERROR;
4218
4219         name = gst_structure_get_name(str);
4220         if (!name)
4221                 goto ERROR;
4222
4223         LOGD("name = %s\n", name);
4224
4225         if (strstr(name, "audio")) {
4226                 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
4227
4228                 if (player->audio_stream_changed_cb) {
4229                         LOGE("call the audio stream changed cb\n");
4230                         player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
4231                 }
4232         } else if (strstr(name, "video")) {
4233                 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
4234
4235                 if (player->video_stream_changed_cb) {
4236                         LOGE("call the video stream changed cb\n");
4237                         player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
4238                 }
4239         } else
4240                 goto ERROR;
4241
4242 ERROR:
4243
4244         gst_caps_unref(caps);
4245
4246         MMPLAYER_FLEAVE();
4247
4248         return;
4249 }
4250
4251
4252
4253 /**
4254  * This function is to create audio pipeline for playing.
4255  *
4256  * @param       player          [in]    handle of player
4257  *
4258  * @return      This function returns zero on success.
4259  * @remark
4260  * @see         __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_pipeline
4261  */
4262 #define MMPLAYER_CREATEONLY_ELEMENT(x_bin, x_id, x_factory, x_name) \
4263 x_bin[x_id].id = x_id;\
4264 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4265 if (!x_bin[x_id].gst) {\
4266         LOGE("failed to create %s \n", x_factory);\
4267         goto ERROR;\
4268 } \
4269
4270 #define MMPLAYER_CREATE_ELEMENT_ADD_BIN(x_bin, x_id, x_factory, x_name, y_bin, x_player) \
4271 x_bin[x_id].id = x_id;\
4272 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4273 if (!x_bin[x_id].gst) {\
4274         LOGE("failed to create %s \n", x_factory);\
4275         goto ERROR;\
4276 } else {\
4277         if (x_player->ini.set_dump_element_flag)\
4278                 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
4279 } \
4280 if (!gst_bin_add(GST_BIN(y_bin), GST_ELEMENT(x_bin[x_id].gst))) { \
4281         LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s]  to bin [%s] failed\n",\
4282                 GST_ELEMENT_NAME(GST_ELEMENT(x_bin[x_id].gst)),\
4283                 GST_ELEMENT_NAME(GST_ELEMENT(y_bin)));\
4284         goto ERROR;\
4285 } \
4286
4287 /* macro for code readability. just for sinkbin-creation functions */
4288 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
4289 do {\
4290         x_bin[x_id].id = x_id;\
4291         x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4292         if (!x_bin[x_id].gst) {\
4293                 LOGE("failed to create %s \n", x_factory);\
4294                 goto ERROR;\
4295         } else {\
4296                 if (x_player->ini.set_dump_element_flag)\
4297                         __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
4298         } \
4299         if (x_add_bucket)\
4300                 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
4301 } while (0);
4302
4303 static void
4304 __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all)
4305 {
4306         GList *l = NULL;
4307
4308         MMPLAYER_FENTER();
4309         MMPLAYER_RETURN_IF_FAIL(player);
4310
4311         if (player->audio_stream_buff_list) {
4312                 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4313                         mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4314                         if (tmp) {
4315                                 if (send_all) {
4316                                         LOGD("[%lld] send remained data.", tmp->channel_mask);
4317                                         __mmplayer_audio_stream_send_data(player, tmp);
4318                                 }
4319                                 if (tmp->pcm_data)
4320                                         g_free(tmp->pcm_data);
4321                                 g_free(tmp);
4322                         }
4323                 }
4324                 g_list_free(player->audio_stream_buff_list);
4325                 player->audio_stream_buff_list = NULL;
4326         }
4327
4328         MMPLAYER_FLEAVE();
4329 }
4330
4331 static void
4332 __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer)
4333 {
4334         MMPlayerAudioStreamDataType audio_stream = { 0, };
4335
4336         MMPLAYER_FENTER();
4337         MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4338
4339         audio_stream.bitrate = a_buffer->bitrate;
4340         audio_stream.channel = a_buffer->channel;
4341         audio_stream.depth = a_buffer->depth;
4342         audio_stream.is_little_endian = a_buffer->is_little_endian;
4343         audio_stream.channel_mask = a_buffer->channel_mask;
4344         audio_stream.data_size = a_buffer->data_size;
4345         audio_stream.data = a_buffer->pcm_data;
4346
4347         /* LOGD("[%lld] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
4348         player->audio_stream_render_cb_ex(&audio_stream, player->audio_stream_cb_user_param);
4349
4350         MMPLAYER_FLEAVE();
4351 }
4352
4353 static void
4354 __mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4355 {
4356         mm_player_t* player = (mm_player_t*) data;
4357
4358         gint channel = 0;
4359         gint rate = 0;
4360         gint depth = 0;
4361         gint endianness = 0;
4362         guint64 channel_mask = 0;
4363         void *a_data = NULL;
4364         gint a_size = 0;
4365         mm_player_audio_stream_buff_t *a_buffer = NULL;
4366         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4367         GList *l = NULL;
4368
4369         MMPLAYER_FENTER();
4370         MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4371
4372         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4373         a_data = mapinfo.data;
4374         a_size = mapinfo.size;
4375
4376         GstCaps *caps = gst_pad_get_current_caps(pad);
4377         GstStructure *structure = gst_caps_get_structure(caps, 0);
4378
4379         /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
4380         gst_structure_get_int(structure, "rate", &rate);
4381         gst_structure_get_int(structure, "channels", &channel);
4382         gst_structure_get_int(structure, "depth", &depth);
4383         gst_structure_get_int(structure, "endianness", &endianness);
4384         gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
4385         gst_caps_unref(GST_CAPS(caps));
4386
4387         /* In case of the sync is false, use buffer list.              *
4388          * The num of buffer list depends on the num of audio channels */
4389         if (player->audio_stream_buff_list) {
4390                 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4391                         mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4392                         if (tmp) {
4393                                 if (channel_mask == tmp->channel_mask) {
4394                                         /* LOGD("[%lld] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
4395                                         if (tmp->data_size + a_size < tmp->buff_size) {
4396                                                 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
4397                                                 tmp->data_size += a_size;
4398                                         } else {
4399                                                 /* send data to client */
4400                                                 __mmplayer_audio_stream_send_data(player, tmp);
4401
4402                                                 if (a_size > tmp->buff_size) {
4403                                                         LOGD("[%lld] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
4404                                                         tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
4405                                                         if (tmp->pcm_data == NULL) {
4406                                                                 LOGE("failed to realloc data.");
4407                                                                 goto DONE;
4408                                                         }
4409                                                         tmp->buff_size = a_size;
4410                                                 }
4411                                                 memset(tmp->pcm_data, 0x00, tmp->buff_size);
4412                                                 memcpy(tmp->pcm_data, a_data, a_size);
4413                                                 tmp->data_size = a_size;
4414                                         }
4415                                         goto DONE;
4416                                 }
4417                         } else {
4418                                 LOGE("data is empty in list.");
4419                                 goto DONE;
4420                         }
4421                 }
4422         }
4423
4424         /* create new audio stream data */
4425         a_buffer = (mm_player_audio_stream_buff_t*)g_malloc0(sizeof(mm_player_audio_stream_buff_t));
4426         if (a_buffer == NULL) {
4427                 LOGE("failed to alloc data.");
4428                 goto DONE;
4429         }
4430         a_buffer->bitrate = rate;
4431         a_buffer->channel = channel;
4432         a_buffer->depth = depth;
4433         a_buffer->is_little_endian = (endianness == 1234 ? 1 : 0);
4434         a_buffer->channel_mask = channel_mask;
4435         a_buffer->data_size = a_size;
4436
4437         if (!player->audio_stream_sink_sync) {
4438                 /* If sync is FALSE, use buffer list to reduce the IPC. */
4439                 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
4440                 a_buffer->pcm_data = g_malloc(a_buffer->buff_size);
4441                 if (a_buffer->pcm_data == NULL) {
4442                         LOGE("failed to alloc data.");
4443                         g_free(a_buffer);
4444                         goto DONE;
4445                 }
4446                 memcpy(a_buffer->pcm_data, a_data, a_size);
4447                 /* LOGD("new [%lld] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
4448                 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
4449         } else {
4450                 /* If sync is TRUE, send data directly. */
4451                 a_buffer->pcm_data = a_data;
4452                 __mmplayer_audio_stream_send_data(player, a_buffer);
4453                 g_free(a_buffer);
4454         }
4455
4456 DONE:
4457         gst_buffer_unmap(buffer, &mapinfo);
4458         MMPLAYER_FLEAVE();
4459 }
4460
4461 static void
4462 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
4463 {
4464         mm_player_t* player = (mm_player_t*)data;
4465         MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4466         GstPad* sinkpad = NULL;
4467         GstElement *queue = NULL, *sink = NULL;
4468
4469         MMPLAYER_FENTER();
4470         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
4471
4472         queue = gst_element_factory_make("queue", NULL);
4473         if (queue == NULL) {
4474                 LOGD("fail make queue\n");
4475                 goto ERROR;
4476         }
4477
4478         sink = gst_element_factory_make("fakesink", NULL);
4479         if (sink == NULL) {
4480                 LOGD("fail make fakesink\n");
4481                 goto ERROR;
4482         }
4483
4484         gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
4485
4486         if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
4487                 LOGW("failed to link queue & sink\n");
4488                 goto ERROR;
4489         }
4490
4491         sinkpad = gst_element_get_static_pad(queue, "sink");
4492
4493         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
4494                 LOGW("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad));
4495                 goto ERROR;
4496         }
4497
4498         LOGE("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync);
4499
4500         gst_object_unref(sinkpad);
4501         g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
4502         g_object_set(sink, "signal-handoffs", TRUE, NULL);
4503
4504         gst_element_set_state(sink, GST_STATE_PAUSED);
4505         gst_element_set_state(queue, GST_STATE_PAUSED);
4506
4507         MMPLAYER_SIGNAL_CONNECT(player,
4508                 G_OBJECT(sink),
4509                 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4510                 "handoff",
4511                 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
4512                 (gpointer)player);
4513
4514         MMPLAYER_FLEAVE();
4515         return ;
4516
4517 ERROR:
4518         LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n");
4519         if (queue) {
4520                 gst_object_unref(GST_OBJECT(queue));
4521                 queue = NULL;
4522         }
4523         if (sink) {
4524                 gst_object_unref(GST_OBJECT(sink));
4525                 sink = NULL;
4526         }
4527         if (sinkpad) {
4528                 gst_object_unref(GST_OBJECT(sinkpad));
4529                 sinkpad = NULL;
4530         }
4531
4532         return;
4533 }
4534
4535 void __mmplayer_gst_set_audiosink_property(mm_player_t* player, MMHandleType attrs)
4536 {
4537         #define MAX_PROPS_LEN 64
4538         gint latency_mode = 0;
4539         gchar *stream_type = NULL;
4540         gchar *latency = NULL;
4541         gint stream_id = 0;
4542         gchar stream_props[MAX_PROPS_LEN] = {0,};
4543         GstStructure *props = NULL;
4544
4545         /* set volume table
4546          * It should be set after player creation through attribute.
4547          * But, it can not be changed during playing.
4548          */
4549         MMPLAYER_FENTER();
4550         mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
4551         mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
4552
4553         if (!stream_type) {
4554                 LOGE("stream_type is null.\n");
4555         } else {
4556                 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d", stream_type, stream_id);
4557                 props = gst_structure_from_string(stream_props, NULL);
4558                 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
4559                 LOGD("stream_id[%d], stream_type[%s], result[%s].\n", stream_id, stream_type, stream_props);
4560         }
4561
4562         mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
4563
4564         switch (latency_mode) {
4565         case AUDIO_LATENCY_MODE_LOW:
4566                 latency = g_strndup("low", 3);
4567                 break;
4568         case AUDIO_LATENCY_MODE_MID:
4569                 latency = g_strndup("mid", 3);
4570                 break;
4571         case AUDIO_LATENCY_MODE_HIGH:
4572                 latency = g_strndup("high", 4);
4573                 break;
4574         };
4575
4576 #if 0 //need to check
4577         if (player->sound_focus.user_route_policy != 0)
4578                 route_path = player->sound_focus.user_route_policy;
4579
4580         g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
4581                         "latency", latency_mode,
4582                         NULL);
4583
4584         LOGD("audiosink property status...volume type:%d, user-route=%d, latency=%d \n",
4585                 volume_type, route_path, latency_mode);
4586         MMPLAYER_FLEAVE();
4587
4588 #endif
4589
4590         g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
4591                         "latency", latency,
4592                         NULL);
4593
4594         LOGD("audiosink property - latency=%s \n", latency);
4595
4596         g_free(latency);
4597
4598         MMPLAYER_FLEAVE();
4599 }
4600
4601 static int
4602 __mmplayer_gst_create_audio_pipeline(mm_player_t* player)
4603 {
4604         MMPlayerGstElement* first_element = NULL;
4605         MMPlayerGstElement* audiobin = NULL;
4606         MMHandleType attrs = 0;
4607         GstPad *pad = NULL;
4608         GstPad *ghostpad = NULL;
4609         GList* element_bucket = NULL;
4610         gboolean link_audio_sink_now = TRUE;
4611         int i = 0;
4612
4613         MMPLAYER_FENTER();
4614
4615         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4616
4617         /* alloc handles */
4618         audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
4619         if (!audiobin) {
4620                 LOGE("failed to allocate memory for audiobin\n");
4621                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
4622         }
4623
4624         attrs = MMPLAYER_GET_ATTRS(player);
4625
4626         /* create bin */
4627         audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
4628         audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
4629         if (!audiobin[MMPLAYER_A_BIN].gst) {
4630                 LOGE("failed to create audiobin\n");
4631                 goto ERROR;
4632         }
4633
4634         /* take it */
4635         player->pipeline->audiobin = audiobin;
4636
4637         player->set_mode.pcm_extraction = __mmplayer_can_extract_pcm(player);
4638
4639         /* Adding audiotp plugin for reverse trickplay feature */
4640 //      MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TP, "audiotp", "audio trickplay", TRUE, player);
4641
4642         /* converter */
4643         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
4644
4645         /* resampler */
4646         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER,  player->ini.audioresampler_element, "audio resampler", TRUE, player);
4647
4648         if (player->set_mode.pcm_extraction) {
4649                 // pcm extraction only and no sound output
4650                 if (player->audio_stream_render_cb_ex) {
4651                         char *caps_str = NULL;
4652                         GstCaps* caps = NULL;
4653                         gchar *format = NULL;
4654
4655                         /* capsfilter */
4656                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4657
4658                         mm_attrs_get_string_by_name(player->attrs, "pcm_audioformat", &format);
4659
4660                         LOGD("contents : format: %s samplerate : %d pcm_channel: %d", format, player->pcm_samplerate, player->pcm_channel);
4661
4662                         caps = gst_caps_new_simple("audio/x-raw",
4663                                         "format", G_TYPE_STRING, format,
4664                                         "rate", G_TYPE_INT, player->pcm_samplerate,
4665                                         "channels", G_TYPE_INT, player->pcm_channel,
4666                                         NULL);
4667                         caps_str = gst_caps_to_string(caps);
4668                         LOGD("new caps : %s\n", caps_str);
4669
4670                         g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4671
4672                         /* clean */
4673                         gst_caps_unref(caps);
4674                         MMPLAYER_FREEIF(caps_str);
4675
4676                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
4677
4678                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
4679                         /* raw pad handling signal */
4680                         MMPLAYER_SIGNAL_CONNECT(player,
4681                                 (audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
4682                                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
4683                                                                                                 G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), player);
4684                 } else {
4685                         int dst_samplerate = 0;
4686                         int dst_channels = 0;
4687                         int dst_depth = 0;
4688                         char *caps_str = NULL;
4689                         GstCaps* caps = NULL;
4690
4691                         /* get conf. values */
4692                         mm_attrs_multiple_get(player->attrs,
4693                                                 NULL,
4694                                                 "pcm_extraction_samplerate", &dst_samplerate,
4695                                                 "pcm_extraction_channels", &dst_channels,
4696                                                 "pcm_extraction_depth", &dst_depth,
4697                                                 NULL);
4698
4699                         /* capsfilter */
4700                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4701                         caps = gst_caps_new_simple("audio/x-raw",
4702                                         "rate", G_TYPE_INT, dst_samplerate,
4703                                         "channels", G_TYPE_INT, dst_channels,
4704                                         "depth", G_TYPE_INT, dst_depth,
4705                                         NULL);
4706                         caps_str = gst_caps_to_string(caps);
4707                         LOGD("new caps : %s\n", caps_str);
4708
4709                         g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4710
4711                         /* clean */
4712                         gst_caps_unref(caps);
4713                         MMPLAYER_FREEIF(caps_str);
4714
4715                         /* fake sink */
4716                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "fakesink", TRUE, player);
4717
4718                         /* set sync */
4719                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL);
4720                 }
4721         } else {
4722                 // normal playback
4723                 //GstCaps* caps = NULL;
4724                 gint channels = 0;
4725
4726                 /* for logical volume control */
4727                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
4728                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
4729
4730                 if (player->sound.mute) {
4731                         LOGD("mute enabled\n");
4732                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
4733                 }
4734
4735 #if 0
4736                 /*capsfilter */
4737                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE, player);
4738                 caps = gst_caps_from_string("audio/x-raw-int, "
4739                                         "endianness = (int) LITTLE_ENDIAN, "
4740                                         "signed = (boolean) true, "
4741                                         "width = (int) 16, "
4742                                         "depth = (int) 16");
4743                 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4744                 gst_caps_unref(caps);
4745 #endif
4746
4747                 /* chech if multi-chennels */
4748                 if (player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) {
4749                         GstPad *srcpad = NULL;
4750                         GstCaps *caps = NULL;
4751
4752                         if ((srcpad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "src"))) {
4753                                 if ((caps = gst_pad_query_caps(srcpad, NULL))) {
4754                                         //MMPLAYER_LOG_GST_CAPS_TYPE(caps);
4755                                         GstStructure *str = gst_caps_get_structure(caps, 0);
4756                                         if (str)
4757                                                 gst_structure_get_int(str, "channels", &channels);
4758                                         gst_caps_unref(caps);
4759                                 }
4760                                 gst_object_unref(srcpad);
4761                         }
4762                 }
4763
4764                 /* audio effect element. if audio effect is enabled */
4765                 if ((strcmp(player->ini.audioeffect_element, ""))
4766                         && (channels <= 2)
4767                         && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4768                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
4769
4770                         LOGD("audio effect config. bypass = %d, effect type  = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
4771
4772                         if ((!player->bypass_audio_effect)
4773                                 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4774                                 if (MM_AUDIO_EFFECT_TYPE_CUSTOM == player->audio_effect_info.effect_type) {
4775                                         if (!_mmplayer_audio_effect_custom_apply(player))
4776                                                 LOGI("apply audio effect(custom) setting success\n");
4777                                 }
4778                         }
4779
4780                         if ((strcmp(player->ini.audioeffect_element_custom, ""))
4781                                 && (player->set_mode.rich_audio))
4782                                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
4783                 }
4784                 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
4785                         if (player->set_mode.rich_audio && channels <= 2)
4786                                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VSP, "audiovsp", "x-speed", TRUE, player);
4787                 }
4788
4789                 /* create audio sink */
4790                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", link_audio_sink_now, player);
4791
4792                 /* qos on */
4793                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL);       /* qos on */
4794                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
4795
4796
4797                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
4798                         (player->videodec_linked && player->ini.use_system_clock)) {
4799                         LOGD("system clock will be used.\n");
4800                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE,  NULL);
4801                 }
4802
4803                 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
4804                         __mmplayer_gst_set_audiosink_property(player, attrs);
4805         }
4806
4807         if (audiobin[MMPLAYER_A_SINK].gst) {
4808                 GstPad *sink_pad = NULL;
4809                 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
4810                 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4811                                         "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
4812                 gst_object_unref(GST_OBJECT(sink_pad));
4813         }
4814
4815         __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
4816
4817         /* adding created elements to bin */
4818         LOGD("adding created elements to bin\n");
4819         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket)) {
4820                 LOGE("failed to add elements\n");
4821                 goto ERROR;
4822         }
4823
4824         /* linking elements in the bucket by added order. */
4825         LOGD("Linking elements in the bucket by added order.\n");
4826         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4827                 LOGE("failed to link elements\n");
4828                 goto ERROR;
4829         }
4830
4831         /* get first element's sinkpad for creating ghostpad */
4832         first_element = (MMPlayerGstElement *)element_bucket->data;
4833         if (!first_element) {
4834                 LOGE("failed to get first elem\n");
4835                 goto ERROR;
4836         }
4837
4838         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
4839         if (!pad) {
4840                 LOGE("failed to get pad from first element of audiobin\n");
4841                 goto ERROR;
4842         }
4843
4844         ghostpad = gst_ghost_pad_new("sink", pad);
4845         if (!ghostpad) {
4846                 LOGE("failed to create ghostpad\n");
4847                 goto ERROR;
4848         }
4849
4850         if (FALSE == gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
4851                 LOGE("failed to add ghostpad to audiobin\n");
4852                 goto ERROR;
4853         }
4854
4855         gst_object_unref(pad);
4856
4857         g_list_free(element_bucket);
4858
4859         mm_attrs_set_int_by_name(attrs, "content_audio_found", TRUE);
4860
4861         MMPLAYER_FLEAVE();
4862
4863         return MM_ERROR_NONE;
4864
4865 ERROR:
4866
4867         LOGD("ERROR : releasing audiobin\n");
4868
4869         if (pad)
4870                 gst_object_unref(GST_OBJECT(pad));
4871
4872         if (ghostpad)
4873                 gst_object_unref(GST_OBJECT(ghostpad));
4874
4875         if (element_bucket)
4876                 g_list_free(element_bucket);
4877
4878         /* release element which are not added to bin */
4879         for (i = 1; i < MMPLAYER_A_NUM; i++) {
4880                 /* NOTE : skip bin */
4881                 if (audiobin[i].gst) {
4882                         GstObject* parent = NULL;
4883                         parent = gst_element_get_parent(audiobin[i].gst);
4884
4885                         if (!parent) {
4886                                 gst_object_unref(GST_OBJECT(audiobin[i].gst));
4887                                 audiobin[i].gst = NULL;
4888                         } else
4889                                 gst_object_unref(GST_OBJECT(parent));
4890                 }
4891         }
4892
4893         /* release audiobin with it's childs */
4894         if (audiobin[MMPLAYER_A_BIN].gst)
4895                 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
4896
4897         MMPLAYER_FREEIF(audiobin);
4898
4899         player->pipeline->audiobin = NULL;
4900
4901         return MM_ERROR_PLAYER_INTERNAL;
4902 }
4903
4904 static GstPadProbeReturn
4905 __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4906 {
4907         mm_player_t* player = (mm_player_t*) u_data;
4908         GstBuffer *pad_buffer = gst_pad_probe_info_get_buffer(info);
4909         GstMapInfo probe_info = GST_MAP_INFO_INIT;
4910
4911         gst_buffer_map(pad_buffer, &probe_info, GST_MAP_READ);
4912
4913         if (player->audio_stream_cb && probe_info.size && probe_info.data)
4914                 player->audio_stream_cb((void *)probe_info.data, probe_info.size, player->audio_stream_cb_user_param);
4915
4916         return GST_PAD_PROBE_OK;
4917 }
4918
4919 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
4920 {
4921         return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
4922 }
4923
4924 int _mmplayer_video_stream_release_bo(mm_player_t* player, void* bo)
4925 {
4926         int ret = MM_ERROR_NONE;
4927         GList *l = NULL;
4928         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4929         MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
4930
4931         MMPLAYER_VIDEO_BO_LOCK(player);
4932
4933         if (player->video_bo_list) {
4934                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4935                         mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4936                         if (tmp && tmp->bo == bo) {
4937                                 tmp->using = FALSE;
4938                                 LOGD("release bo %p", bo);
4939                                 MMPLAYER_VIDEO_BO_UNLOCK(player);
4940                                 MMPLAYER_VIDEO_BO_SIGNAL(player);
4941                                 return ret;
4942                         }
4943                 }
4944         } else {
4945                 /* hw codec is running or the list was reset for DRC. */
4946                 LOGW("there is no bo list.");
4947         }
4948         MMPLAYER_VIDEO_BO_UNLOCK(player);
4949
4950         LOGW("failed to find bo %p", bo);
4951         return ret;
4952 }
4953
4954 static void
4955 __mmplayer_video_stream_destroy_bo_list(mm_player_t* player)
4956 {
4957         GList *l = NULL;
4958
4959         MMPLAYER_FENTER();
4960         MMPLAYER_RETURN_IF_FAIL(player);
4961
4962         MMPLAYER_VIDEO_BO_LOCK(player);
4963         if (player->video_bo_list) {
4964                 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
4965                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4966                         mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4967                         if (tmp) {
4968                                 if (tmp->bo)
4969                                         tbm_bo_unref(tmp->bo);
4970                                 g_free(tmp);
4971                         }
4972                 }
4973                 g_list_free(player->video_bo_list);
4974                 player->video_bo_list = NULL;
4975         }
4976         player->video_bo_size = 0;
4977         MMPLAYER_VIDEO_BO_UNLOCK(player);
4978
4979         MMPLAYER_FLEAVE();
4980         return;
4981 }
4982
4983 static void*
4984 __mmplayer_video_stream_get_bo(mm_player_t* player, int size)
4985 {
4986         GList *l = NULL;
4987         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
4988         gboolean ret = TRUE;
4989
4990         /* check DRC, if it is, destroy the prev bo list to create again */
4991         if (player->video_bo_size != size) {
4992                 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
4993                 __mmplayer_video_stream_destroy_bo_list(player);
4994                 player->video_bo_size = size;
4995         }
4996
4997         MMPLAYER_VIDEO_BO_LOCK(player);
4998
4999         if ((!player->video_bo_list) ||
5000                 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
5001
5002                 /* create bo list */
5003                 int idx = 0;
5004                 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
5005
5006                 if (player->video_bo_list) {
5007                         /* if bo list did not created all, try it again. */
5008                         idx = g_list_length(player->video_bo_list);
5009                         LOGD("bo list exist(len: %d)", idx);
5010                 }
5011
5012                 for (; idx < player->ini.num_of_video_bo; idx++) {
5013                         mm_player_video_bo_info_t* bo_info = g_new(mm_player_video_bo_info_t, 1);
5014                         if (!bo_info) {
5015                                 LOGE("Fail to alloc bo_info.");
5016                                 break;
5017                         }
5018                         bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
5019                         if (!bo_info->bo) {
5020                                 LOGE("Fail to tbm_bo_alloc.");
5021                                 g_free(bo_info);
5022                                 break;
5023                         }
5024                         bo_info->using = FALSE;
5025                         player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
5026                 }
5027
5028                 /* update video num buffers */
5029                 player->video_num_buffers = idx;
5030                 if (idx == player->ini.num_of_video_bo)
5031                         player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
5032
5033                 if (idx == 0) {
5034                         MMPLAYER_VIDEO_BO_UNLOCK(player);
5035                         return NULL;
5036                 }
5037
5038                 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
5039         }
5040
5041         while (TRUE) {
5042                 /* get bo from list*/
5043                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
5044                         mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
5045                         if (tmp && (tmp->using == FALSE)) {
5046                                 LOGD("found bo %p to use", tmp->bo);
5047                                 tmp->using = TRUE;
5048                                 MMPLAYER_VIDEO_BO_UNLOCK(player);
5049                                 return tmp->bo;
5050                         }
5051                 }
5052                 if (!ret) {
5053                         LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
5054                         MMPLAYER_VIDEO_BO_UNLOCK(player);
5055                         return NULL;
5056                 }
5057
5058                 if (player->ini.video_bo_timeout <= 0) {
5059                         MMPLAYER_VIDEO_BO_WAIT(player);
5060                 } else {
5061                         gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout*G_TIME_SPAN_SECOND;
5062                         ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
5063                 }
5064                 continue;
5065         }
5066 }
5067
5068 static void
5069 __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5070 {
5071         mm_player_t* player = (mm_player_t*)data;
5072         MMPLAYER_FENTER();
5073         MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
5074
5075         /* send prerolled pkt */
5076         player->video_stream_prerolled = FALSE;
5077
5078         __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
5079
5080         /* not to send prerolled pkt again */
5081         player->video_stream_prerolled = TRUE;
5082 }
5083
5084 static void
5085 __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5086 {
5087         mm_player_t* player = (mm_player_t*)data;
5088         GstCaps *caps = NULL;
5089         MMPlayerVideoStreamDataType stream;
5090         MMVideoBuffer *video_buffer = NULL;
5091         GstMemory *dataBlock = NULL;
5092         GstMemory *metaBlock = NULL;
5093         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5094         GstStructure *structure = NULL;
5095         const gchar *string_format = NULL;
5096         unsigned int fourcc = 0;
5097
5098         MMPLAYER_FENTER();
5099         MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
5100
5101         if (player->video_stream_prerolled) {
5102                 player->video_stream_prerolled = FALSE;
5103                 LOGD("skip the prerolled pkt not to send it again");
5104                 return;
5105         }
5106
5107         caps = gst_pad_get_current_caps(pad);
5108         if (caps == NULL) {
5109                 LOGE("Caps is NULL.");
5110                 return;
5111         }
5112
5113         /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
5114
5115         /* clear stream data structure */
5116         memset(&stream, 0x0, sizeof(MMPlayerVideoStreamDataType));
5117
5118         structure = gst_caps_get_structure(caps, 0);
5119         gst_structure_get_int(structure, "width", & (stream.width));
5120         gst_structure_get_int(structure, "height", & (stream.height));
5121         string_format = gst_structure_get_string(structure, "format");
5122         if (string_format)
5123                 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
5124         stream.format = util_get_pixtype(fourcc);
5125         gst_caps_unref(caps);
5126         caps = NULL;
5127
5128     /*
5129         LOGD("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
5130                 GST_BUFFER_DATA(buffer), stream.width, stream.height, stream.format);
5131     */
5132
5133         if (stream.width == 0 || stream.height == 0 || stream.format == MM_PIXEL_FORMAT_INVALID) {
5134                 LOGE("Wrong condition!!");
5135                 return;
5136         }
5137
5138         /* set size and timestamp */
5139         dataBlock = gst_buffer_peek_memory(buffer, 0);
5140         stream.length_total = gst_memory_get_sizes(dataBlock, NULL, NULL);
5141         stream.timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/1000000); /* nano sec -> mili sec */
5142
5143         /* check zero-copy */
5144         if (player->set_mode.video_zc &&
5145                 player->set_mode.media_packet_video_stream &&
5146                 gst_buffer_n_memory(buffer) > 1) {
5147                 metaBlock = gst_buffer_peek_memory(buffer, 1);
5148                 gst_memory_map(metaBlock, &mapinfo, GST_MAP_READ);
5149                 video_buffer = (MMVideoBuffer *)mapinfo.data;
5150         }
5151
5152         if (video_buffer) { /* hw codec */
5153                 /* set tbm bo */
5154                 if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
5155                         /* copy pointer of tbm bo, stride, elevation */
5156                         memcpy(stream.bo, video_buffer->handle.bo,
5157                                         sizeof(void *) * MM_VIDEO_BUFFER_PLANE_MAX);
5158                 } else if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_PHYSICAL_ADDRESS) {
5159                         /* FIXME: need to check this path */
5160                         memcpy(stream.data, video_buffer->data,
5161                                         sizeof(void *) * MM_VIDEO_BUFFER_PLANE_MAX);
5162                 }
5163                 memcpy(stream.stride, video_buffer->stride_width,
5164                                 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5165                 memcpy(stream.elevation, video_buffer->stride_height,
5166                                 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5167                 /* set gst buffer */
5168                 stream.internal_buffer = buffer;
5169         } else { /* sw codec */
5170                 tbm_bo_handle thandle;
5171                 int stride = GST_ROUND_UP_4(stream.width);
5172                 int elevation = stream.height;
5173                 int size = 0;
5174
5175                 gboolean gst_ret;
5176                 gst_ret = gst_memory_map(dataBlock, &mapinfo, GST_MAP_READWRITE);
5177                 if (!gst_ret) {
5178                         LOGE("fail to gst_memory_map");
5179                         return;
5180                 }
5181
5182                 stream.stride[0] = stride;
5183                 stream.elevation[0] = elevation;
5184                 if (stream.format == MM_PIXEL_FORMAT_I420) {
5185                         stream.stride[1] = stream.stride[2] = GST_ROUND_UP_4(GST_ROUND_UP_2(stream.width) / 2);
5186                         stream.elevation[1] = stream.elevation[2] = stream.height / 2;
5187                         size = stream.stride[0] * stream.elevation[0] + stream.stride[1] * stream.elevation[1] + stream.stride[2] * stream.elevation[2];
5188                 } else if (stream.format == MM_PIXEL_FORMAT_RGBA) {
5189                         stream.stride[0] = stream.width * 4;
5190                         size = stream.stride[0] * stream.height;
5191                 } else {
5192                         LOGE("Not support format %d", stream.format);
5193                         gst_memory_unmap(dataBlock, &mapinfo);
5194                         return;
5195                 }
5196                 stream.bo[0] = __mmplayer_video_stream_get_bo(player, size);
5197                 if (!stream.bo[0]) {
5198                         LOGE("Fail to tbm_bo_alloc!!");
5199                         gst_memory_unmap(dataBlock, &mapinfo);
5200                         return;
5201                 }
5202                 thandle = tbm_bo_map(stream.bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
5203                 if (thandle.ptr && mapinfo.data)
5204                         memcpy(thandle.ptr, mapinfo.data, size);
5205                 else
5206                         LOGE("data pointer is wrong. dest : %p, src : %p",
5207                                         thandle.ptr, mapinfo.data);
5208                 tbm_bo_unmap(stream.bo[0]);
5209         }
5210
5211         if (player->video_stream_cb)
5212                 player->video_stream_cb(&stream, player->video_stream_cb_user_param);
5213
5214         if (metaBlock)
5215                 gst_memory_unmap(metaBlock, &mapinfo);
5216         else
5217                 gst_memory_unmap(dataBlock, &mapinfo);
5218
5219         return;
5220 }
5221
5222 static int
5223 __mmplayer_gst_create_video_filters(mm_player_t* player, GList** bucket)
5224 {
5225         MMDisplaySurfaceType surface_type = MM_DISPLAY_SURFACE_NULL;
5226         gchar* video_csc = "videoconvert"; // default colorspace converter
5227         GList* element_bucket = *bucket;
5228
5229         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5230
5231         MMPLAYER_FENTER();
5232
5233         mm_attrs_get_int_by_name(player->attrs, "display_surface_type", (int *)&surface_type);
5234
5235         if (player->set_mode.video_zc) {
5236                 video_csc = ""; /* videosinks don't use videoconvert normally */
5237         } else {
5238                 /* sw codec, if player use libav, waylandsink need videoconvert to render shm wl-buffer which support RGB only */
5239                 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) && (!strncmp(player->ini.videosink_element_overlay, "waylandsink", strlen(player->ini.videosink_element_overlay))))
5240                         video_csc = "videoconvert";
5241         }
5242         if (video_csc && (strcmp(video_csc, ""))) {
5243                 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
5244                 LOGD("using video converter: %s", video_csc);
5245         }
5246
5247         /* set video rotator */
5248         if (!player->set_mode.video_zc)
5249                 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
5250
5251         *bucket = element_bucket;
5252         MMPLAYER_FLEAVE();
5253         return MM_ERROR_NONE;
5254
5255 ERROR:
5256         *bucket = NULL;
5257         MMPLAYER_FLEAVE();
5258         return MM_ERROR_PLAYER_INTERNAL;
5259 }
5260
5261 /**
5262  * This function is to create video pipeline.
5263  *
5264  * @param       player          [in]    handle of player
5265  *              caps            [in]    src caps of decoder
5266  *              surface_type    [in]    surface type for video rendering
5267  *
5268  * @return      This function returns zero on success.
5269  * @remark
5270  * @see         __mmplayer_gst_create_audio_pipeline, __mmplayer_gst_create_midi_pipeline
5271  */
5272 /**
5273   * VIDEO PIPELINE
5274   * - video overlay surface(arm/x86) : waylandsink
5275   */
5276 static int
5277 __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
5278 {
5279         GstPad *pad = NULL;
5280         MMHandleType attrs;
5281         GList*element_bucket = NULL;
5282         MMPlayerGstElement* first_element = NULL;
5283         MMPlayerGstElement* videobin = NULL;
5284         gchar *videosink_element = NULL;
5285
5286         MMPLAYER_FENTER();
5287
5288         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5289
5290         /* alloc handles */
5291         videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
5292         if (!videobin)
5293                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5294
5295         player->pipeline->videobin = videobin;
5296
5297         attrs = MMPLAYER_GET_ATTRS(player);
5298         if (!attrs) {
5299                 LOGE("cannot get content attribute");
5300                 return MM_ERROR_PLAYER_INTERNAL;
5301         }
5302
5303         /* create bin */
5304         videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
5305         videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
5306         if (!videobin[MMPLAYER_V_BIN].gst) {
5307                 LOGE("failed to create videobin");
5308                 goto ERROR;
5309         }
5310
5311         int enable_video_decoded_cb = 0;
5312         mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable_video_decoded_cb);
5313
5314         /* set video sink */
5315         switch (surface_type) {
5316         case MM_DISPLAY_SURFACE_OVERLAY:
5317                 if (__mmplayer_gst_create_video_filters(player, &element_bucket) != MM_ERROR_NONE)
5318                         goto ERROR;
5319                 if (strlen(player->ini.videosink_element_overlay) > 0)
5320                         videosink_element = player->ini.videosink_element_overlay;
5321                 else
5322                         goto ERROR;
5323                 break;
5324         case MM_DISPLAY_SURFACE_NULL:
5325                 if (strlen(player->ini.videosink_element_fake) > 0)
5326                         videosink_element = player->ini.videosink_element_fake;
5327                 else
5328                         goto ERROR;
5329                 break;
5330         case MM_DISPLAY_SURFACE_REMOTE:
5331                 if (strlen(player->ini.videosink_element_fake) > 0)
5332                         videosink_element = player->ini.videosink_element_fake;
5333                 else
5334                         goto ERROR;
5335                 break;
5336         default:
5337                 LOGE("unidentified surface type");
5338                 goto ERROR;
5339         }
5340         LOGD("selected videosink name: %s", videosink_element);
5341
5342         MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_element, videosink_element, TRUE, player);
5343
5344         /* additional setting for sink plug-in */
5345         switch (surface_type) {
5346         case MM_DISPLAY_SURFACE_OVERLAY:
5347         {
5348                 bool use_tbm = player->set_mode.video_zc;
5349                 if (!use_tbm) {
5350                         LOGD("selected videosink name: %s", videosink_element);
5351
5352                         /* support shard memory with S/W codec on HawkP */
5353                         if (strncmp(videosink_element, "waylandsink", strlen(videosink_element)) == 0) {
5354                                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
5355                                         "use-tbm", use_tbm, NULL);
5356                         }
5357                 } else {
5358                         if (attrs) {
5359                                 int gapless = 0;
5360
5361                                 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5362
5363                                 if (gapless > 0) {
5364                                         LOGD("disable last-sample");
5365                                         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5366                                 }
5367                         }
5368                 }
5369                 if (player->set_mode.media_packet_video_stream) {
5370                         int enable = 0;
5371                         mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
5372                         if (enable)
5373                                 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
5374
5375                         MMPLAYER_SIGNAL_CONNECT(player,
5376                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5377                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5378                                                                         "handoff",
5379                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5380                                                                         (gpointer)player);
5381
5382                         MMPLAYER_SIGNAL_CONNECT(player,
5383                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5384                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5385                                                                         "preroll-handoff",
5386                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5387                                                                         (gpointer)player);
5388                 }
5389                 break;
5390         }
5391         case MM_DISPLAY_SURFACE_REMOTE:
5392         {
5393                 if (player->set_mode.media_packet_video_stream) {
5394                         LOGE("add data probe at videosink");
5395                         g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5396                                                                                         "sync", TRUE, "signal-handoffs", TRUE, NULL);
5397
5398                         MMPLAYER_SIGNAL_CONNECT(player,
5399                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5400                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5401                                                                         "handoff",
5402                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5403                                                                         (gpointer)player);
5404
5405                         MMPLAYER_SIGNAL_CONNECT(player,
5406                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5407                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5408                                                                         "preroll-handoff",
5409                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5410                                                                         (gpointer)player);
5411                         if (attrs) {
5412                                 int gapless = 0;
5413
5414                                 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5415
5416                                 if (gapless > 0) {
5417                                         LOGD("disable last-sample");
5418                                         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5419                                 }
5420                         }
5421                 }
5422                 break;
5423         }
5424         default:
5425                 break;
5426         }
5427
5428         if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
5429                 goto ERROR;
5430
5431         if (videobin[MMPLAYER_V_SINK].gst) {
5432                 GstPad *sink_pad = NULL;
5433                 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
5434                 if (sink_pad) {
5435                         MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5436                                         "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
5437                         gst_object_unref(GST_OBJECT(sink_pad));
5438                 } else
5439                         LOGW("failed to get sink pad from videosink\n");
5440         }
5441
5442         /* store it as it's sink element */
5443         __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
5444
5445         /* adding created elements to bin */
5446         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
5447                 LOGE("failed to add elements\n");
5448                 goto ERROR;
5449         }
5450
5451         /* Linking elements in the bucket by added order */
5452         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5453                 LOGE("failed to link elements\n");
5454                 goto ERROR;
5455         }
5456
5457         /* get first element's sinkpad for creating ghostpad */
5458         if (element_bucket)
5459                 first_element = (MMPlayerGstElement *)element_bucket->data;
5460         if (!first_element) {
5461                 LOGE("failed to get first element from bucket\n");
5462                 goto ERROR;
5463         }
5464
5465         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
5466         if (!pad) {
5467                 LOGE("failed to get pad from first element\n");
5468                 goto ERROR;
5469         }
5470
5471         /* create ghostpad */
5472         player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
5473         if (FALSE == gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
5474                 LOGE("failed to add ghostpad to videobin\n");
5475                 goto ERROR;
5476         }
5477         gst_object_unref(pad);
5478
5479         /* done. free allocated variables */
5480         if (element_bucket)
5481                 g_list_free(element_bucket);
5482
5483         mm_attrs_set_int_by_name(attrs, "content_video_found", TRUE);
5484
5485         MMPLAYER_FLEAVE();
5486
5487         return MM_ERROR_NONE;
5488
5489 ERROR:
5490         LOGE("ERROR : releasing videobin\n");
5491
5492         g_list_free(element_bucket);
5493
5494         if (pad)
5495                 gst_object_unref(GST_OBJECT(pad));
5496
5497         /* release videobin with it's childs */
5498         if (videobin[MMPLAYER_V_BIN].gst)
5499                 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
5500
5501
5502         MMPLAYER_FREEIF(videobin);
5503
5504         player->pipeline->videobin = NULL;
5505
5506         return MM_ERROR_PLAYER_INTERNAL;
5507 }
5508
5509 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
5510 {
5511         GList *element_bucket = NULL;
5512         MMPlayerGstElement *textbin = player->pipeline->textbin;
5513
5514         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
5515         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
5516         g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
5517                                                         "signal-handoffs", FALSE,
5518                                                         NULL);
5519
5520         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
5521         MMPLAYER_SIGNAL_CONNECT(player,
5522                                                         G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
5523                                                         MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
5524                                                         "handoff",
5525                                                         G_CALLBACK(__mmplayer_update_subtitle),
5526                                                         (gpointer)player);
5527
5528         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "async", TRUE, NULL);
5529         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE, NULL);
5530         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "signal-handoffs", TRUE, NULL);
5531
5532         if (!player->play_subtitle) {
5533                 LOGD("add textbin sink as sink element of whole pipeline.\n");
5534                 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
5535         }
5536
5537         /* adding created elements to bin */
5538         LOGD("adding created elements to bin\n");
5539         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
5540                 LOGE("failed to add elements\n");
5541                 goto ERROR;
5542         }
5543
5544         /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
5545         GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
5546         GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
5547
5548         /* linking elements in the bucket by added order. */
5549         LOGD("Linking elements in the bucket by added order.\n");
5550         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5551                 LOGE("failed to link elements\n");
5552                 goto ERROR;
5553         }
5554
5555         /* done. free allocated variables */
5556         g_list_free(element_bucket);
5557
5558         if (textbin[MMPLAYER_T_QUEUE].gst) {
5559                 GstPad *pad = NULL;
5560                 GstPad *ghostpad = NULL;
5561
5562                 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
5563                 if (!pad) {
5564                         LOGE("failed to get video pad of textbin\n");
5565                         return MM_ERROR_PLAYER_INTERNAL;
5566                 }
5567
5568                 ghostpad = gst_ghost_pad_new("text_sink", pad);
5569                 gst_object_unref(pad);
5570
5571                 if (!ghostpad) {
5572                         LOGE("failed to create ghostpad of textbin\n");
5573                         goto ERROR;
5574                 }
5575
5576                 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
5577                         LOGE("failed to add ghostpad to textbin\n");
5578                         goto ERROR;
5579                 }
5580         }
5581
5582         return MM_ERROR_NONE;
5583
5584 ERROR:
5585         g_list_free(element_bucket);
5586
5587         return MM_ERROR_PLAYER_INTERNAL;
5588 }
5589
5590 static int __mmplayer_gst_create_text_pipeline(mm_player_t* player)
5591 {
5592         MMPlayerGstElement *textbin = NULL;
5593         GList *element_bucket = NULL;
5594         gint i = 0;
5595
5596         MMPLAYER_FENTER();
5597
5598         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5599
5600         /* alloc handles */
5601         textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
5602         if (!textbin) {
5603                 LOGE("failed to allocate memory for textbin\n");
5604                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5605         }
5606
5607         /* create bin */
5608         textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
5609         textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
5610         if (!textbin[MMPLAYER_T_BIN].gst) {
5611                 LOGE("failed to create textbin\n");
5612                 goto ERROR;
5613         }
5614
5615         /* take it */
5616         player->pipeline->textbin = textbin;
5617
5618         /* fakesink */
5619         if (player->use_textoverlay) {
5620                 LOGD("use textoverlay for displaying \n");
5621
5622                 MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_QUEUE, "queue", "text_t_queue", textbin[MMPLAYER_T_BIN].gst, player);
5623
5624                 MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_VIDEO_QUEUE, "queue", "text_v_queue", textbin[MMPLAYER_T_BIN].gst, player);
5625
5626                 MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_VIDEO_CONVERTER, "fimcconvert", "text_v_converter", textbin[MMPLAYER_T_BIN].gst, player);
5627
5628                 MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_OVERLAY, "textoverlay", "text_overlay", textbin[MMPLAYER_T_BIN].gst, player);
5629
5630                 if (!gst_element_link_pads(textbin[MMPLAYER_T_VIDEO_QUEUE].gst, "src", textbin[MMPLAYER_T_VIDEO_CONVERTER].gst, "sink")) {
5631                         LOGE("failed to link queue and converter\n");
5632                         goto ERROR;
5633                 }
5634
5635                 if (!gst_element_link_pads(textbin[MMPLAYER_T_VIDEO_CONVERTER].gst, "src", textbin[MMPLAYER_T_OVERLAY].gst, "video_sink")) {
5636                         LOGE("failed to link queue and textoverlay\n");
5637                         goto ERROR;
5638                 }
5639
5640                 if (!gst_element_link_pads(textbin[MMPLAYER_T_QUEUE].gst, "src", textbin[MMPLAYER_T_OVERLAY].gst, "text_sink")) {
5641                         LOGE("failed to link queue and textoverlay\n");
5642                         goto ERROR;
5643                 }
5644         } else {
5645                 int surface_type = 0;
5646
5647                 LOGD("use subtitle message for displaying \n");
5648
5649                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
5650
5651                 switch (surface_type) {
5652                 case MM_DISPLAY_SURFACE_OVERLAY:
5653                 case MM_DISPLAY_SURFACE_NULL:
5654                 case MM_DISPLAY_SURFACE_REMOTE:
5655                         if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
5656                                 LOGE("failed to make plain text elements\n");
5657                                 goto ERROR;
5658                         }
5659                         break;
5660
5661                 default:
5662                         break;
5663                 }
5664         }
5665
5666         MMPLAYER_FLEAVE();
5667
5668         return MM_ERROR_NONE;
5669
5670 ERROR:
5671
5672         LOGD("ERROR : releasing textbin\n");
5673
5674         g_list_free(element_bucket);
5675
5676         /* release element which are not added to bin */
5677         for (i = 1; i < MMPLAYER_T_NUM; i++) {
5678                 /* NOTE : skip bin */
5679                 if (textbin[i].gst) {
5680                         GstObject* parent = NULL;
5681                         parent = gst_element_get_parent(textbin[i].gst);
5682
5683                         if (!parent) {
5684                                 gst_object_unref(GST_OBJECT(textbin[i].gst));
5685                                 textbin[i].gst = NULL;
5686                         } else
5687                                 gst_object_unref(GST_OBJECT(parent));
5688                 }
5689         }
5690
5691         /* release textbin with it's childs */
5692         if (textbin[MMPLAYER_T_BIN].gst)
5693                 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5694
5695         MMPLAYER_FREEIF(textbin);
5696
5697         player->pipeline->textbin = NULL;
5698
5699         return MM_ERROR_PLAYER_INTERNAL;
5700 }
5701
5702
5703 static int
5704 __mmplayer_gst_create_subtitle_src(mm_player_t* player)
5705 {
5706         MMPlayerGstElement* mainbin = NULL;
5707         MMHandleType attrs = 0;
5708         GstElement *subsrc = NULL;
5709         GstElement *subparse = NULL;
5710         gchar *subtitle_uri = NULL;
5711         const gchar *charset = NULL;
5712         GstPad *pad = NULL;
5713
5714         MMPLAYER_FENTER();
5715
5716         /* get mainbin */
5717         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5718
5719         mainbin = player->pipeline->mainbin;
5720
5721         attrs = MMPLAYER_GET_ATTRS(player);
5722         if (!attrs) {
5723                 LOGE("cannot get content attribute\n");
5724                 return MM_ERROR_PLAYER_INTERNAL;
5725         }
5726
5727         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
5728         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
5729                 LOGE("subtitle uri is not proper filepath.\n");
5730                 return MM_ERROR_PLAYER_INVALID_URI;
5731         }
5732         LOGD("subtitle file path is [%s].\n", subtitle_uri);
5733
5734
5735         /* create the subtitle source */
5736         subsrc = gst_element_factory_make("filesrc", "subtitle_source");
5737         if (!subsrc) {
5738                 LOGE("failed to create filesrc element\n");
5739                 goto ERROR;
5740         }
5741         g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
5742
5743         mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
5744         mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
5745
5746         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
5747                 LOGW("failed to add queue\n");
5748                 goto ERROR;
5749         }
5750
5751         /* subparse */
5752         subparse = gst_element_factory_make("subparse", "subtitle_parser");
5753         if (!subparse) {
5754                 LOGE("failed to create subparse element\n");
5755                 goto ERROR;
5756         }
5757
5758         charset = util_get_charset(subtitle_uri);
5759         if (charset) {
5760                 LOGD("detected charset is %s\n", charset);
5761                 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
5762         }
5763
5764         mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
5765         mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
5766
5767         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
5768                 LOGW("failed to add subparse\n");
5769                 goto ERROR;
5770         }
5771
5772         if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
5773                 LOGW("failed to link subsrc and subparse\n");
5774                 goto ERROR;
5775         }
5776
5777         player->play_subtitle = TRUE;
5778         player->adjust_subtitle_pos = 0;
5779
5780         LOGD("play subtitle using subtitle file\n");
5781
5782         if (player->pipeline->textbin == NULL) {
5783                 if (MM_ERROR_NONE !=  __mmplayer_gst_create_text_pipeline(player)) {
5784                         LOGE("failed to create textbin. continuing without text\n");
5785                         goto ERROR;
5786                 }
5787
5788                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(player->pipeline->textbin[MMPLAYER_T_BIN].gst))) {
5789                         LOGW("failed to add textbin\n");
5790                         goto ERROR;
5791                 }
5792
5793                 LOGD("link text input selector and textbin ghost pad");
5794
5795                 player->textsink_linked = 1;
5796                 player->external_text_idx = 0;
5797                 LOGI("player->textsink_linked set to 1\n");
5798         } else {
5799                 LOGD("text bin has been created. reuse it.");
5800                 player->external_text_idx = 1;
5801         }
5802
5803         if (!gst_element_link_pads(subparse, "src", player->pipeline->textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
5804                 LOGW("failed to link subparse and textbin\n");
5805                 goto ERROR;
5806         }
5807
5808         pad = gst_element_get_static_pad(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
5809
5810         if (!pad) {
5811                 LOGE("failed to get sink pad from textsink to probe data");
5812                 return MM_ERROR_PLAYER_INTERNAL;
5813         }
5814
5815         gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
5816                                 __mmplayer_subtitle_adjust_position_probe, player, NULL);
5817
5818         gst_object_unref(pad);
5819         pad = NULL;
5820
5821         /* create dot. for debugging */
5822         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
5823         MMPLAYER_FLEAVE();
5824
5825         return MM_ERROR_NONE;
5826
5827 ERROR:
5828         player->textsink_linked = 0;
5829         return MM_ERROR_PLAYER_INTERNAL;
5830 }
5831
5832 gboolean
5833 __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5834 {
5835         mm_player_t* player = (mm_player_t*) data;
5836         MMMessageParamType msg = {0, };
5837         GstClockTime duration = 0;
5838         gpointer text = NULL;
5839         guint text_size = 0;
5840         gboolean ret = TRUE;
5841         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5842
5843         MMPLAYER_FENTER();
5844
5845         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5846         MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
5847
5848         if (player->is_subtitle_force_drop)
5849         {
5850                 LOGW("subtitle is dropped forcedly.");
5851                 return ret;
5852         }
5853
5854         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
5855         text = mapinfo.data;
5856         text_size = mapinfo.size;
5857         duration = GST_BUFFER_DURATION(buffer);
5858
5859         if (player->set_mode.subtitle_off) {
5860                 LOGD("subtitle is OFF.\n");
5861                 return TRUE;
5862         }
5863
5864         if (!text || (text_size == 0)) {
5865                 LOGD("There is no subtitle to be displayed.\n");
5866                 return TRUE;
5867         }
5868
5869         msg.data = (void *) text;
5870         msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
5871
5872         LOGD("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data);
5873
5874         MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
5875         gst_buffer_unmap(buffer, &mapinfo);
5876
5877         MMPLAYER_FLEAVE();
5878
5879         return ret;
5880 }
5881
5882 static GstPadProbeReturn
5883 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
5884
5885 {
5886         mm_player_t *player = (mm_player_t *) u_data;
5887         GstClockTime cur_timestamp = 0;
5888         gint64 adjusted_timestamp = 0;
5889         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
5890
5891         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5892
5893         if (player->set_mode.subtitle_off) {
5894                 LOGD("subtitle is OFF.\n");
5895                 return TRUE;
5896         }
5897
5898         if (player->adjust_subtitle_pos == 0) {
5899                 LOGD("nothing to do");
5900                 return TRUE;
5901         }
5902
5903         cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
5904         adjusted_timestamp = (gint64) cur_timestamp +((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
5905
5906         if (adjusted_timestamp < 0) {
5907                 LOGD("adjusted_timestamp under zero");
5908                 MMPLAYER_FLEAVE();
5909                 return FALSE;
5910         }
5911
5912         GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
5913         LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
5914                                 GST_TIME_ARGS(cur_timestamp),
5915                                 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
5916
5917         return GST_PAD_PROBE_OK;
5918 }
5919 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
5920 {
5921         MMPLAYER_FENTER();
5922
5923         /* check player and subtitlebin are created */
5924         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5925         MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
5926
5927         if (position == 0) {
5928                 LOGD("nothing to do\n");
5929                 MMPLAYER_FLEAVE();
5930                 return MM_ERROR_NONE;
5931         }
5932
5933         switch (format) {
5934         case MM_PLAYER_POS_FORMAT_TIME:
5935                 {
5936                         /* check current postion */
5937                         player->adjust_subtitle_pos = position;
5938
5939                         LOGD("save adjust_subtitle_pos in player") ;
5940                 }
5941                 break;
5942
5943         default:
5944                 {
5945                         LOGW("invalid format.\n");
5946                         MMPLAYER_FLEAVE();
5947                         return MM_ERROR_INVALID_ARGUMENT;
5948                 }
5949         }
5950
5951         MMPLAYER_FLEAVE();
5952
5953         return MM_ERROR_NONE;
5954 }
5955 static int __gst_adjust_video_position(mm_player_t* player, int offset)
5956 {
5957         MMPLAYER_FENTER();
5958         LOGD("adjusting video_pos in player") ;
5959         int current_pos = 0;
5960         /* check player and videobin are created */
5961         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5962         if (!player->pipeline->videobin ||
5963                         !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
5964                 LOGD("no video pipeline or sink is there");
5965                 return MM_ERROR_PLAYER_INVALID_STATE ;
5966         }
5967         if (offset == 0) {
5968                 LOGD("nothing to do\n");
5969                 MMPLAYER_FLEAVE();
5970                 return MM_ERROR_NONE;
5971         }
5972         if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, (unsigned long*)&current_pos) != MM_ERROR_NONE) {
5973                 LOGD("failed to get current position");
5974                 return MM_ERROR_PLAYER_INTERNAL;
5975         }
5976         if ((current_pos - offset) < GST_TIME_AS_MSECONDS(player->duration)) {
5977                 LOGD("enter video delay is valid");
5978         } else {
5979                 LOGD("enter video delay is crossing content boundary");
5980                 return MM_ERROR_INVALID_ARGUMENT ;
5981         }
5982         g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "ts-offset", ((gint64) offset * G_GINT64_CONSTANT(1000000)), NULL);
5983         LOGD("video delay has been done");
5984         MMPLAYER_FLEAVE();
5985
5986         return MM_ERROR_NONE;
5987 }
5988
5989 static void
5990 __gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data) // @
5991 {
5992         GstElement *appsrc = element;
5993         tBuffer *buf = (tBuffer *)user_data;
5994         GstBuffer *buffer = NULL;
5995         GstFlowReturn ret = GST_FLOW_OK;
5996         gint len = size;
5997
5998         MMPLAYER_RETURN_IF_FAIL(element);
5999         MMPLAYER_RETURN_IF_FAIL(buf);
6000
6001         buffer = gst_buffer_new();
6002
6003         if (buf->offset >= buf->len) {
6004                 LOGD("call eos appsrc\n");
6005                 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
6006                 return;
6007         }
6008
6009         if (buf->len - buf->offset < size)
6010                 len = buf->len - buf->offset + buf->offset;
6011
6012         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));
6013         GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
6014         GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
6015
6016         //LOGD("feed buffer %p, offset %u-%u length %u\n", buffer, buf->offset, buf->len,len);
6017         g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
6018
6019         buf->offset += len;
6020 }
6021
6022 static gboolean
6023 __gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data) // @
6024 {
6025         tBuffer *buf = (tBuffer *)user_data;
6026
6027         MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
6028
6029         buf->offset  = (int)size;
6030
6031         return TRUE;
6032 }
6033
6034 static GstBusSyncReply
6035 __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data)
6036 {
6037         mm_player_t *player = (mm_player_t *)data;
6038         GstBusSyncReply reply = GST_BUS_DROP;
6039
6040         if (!(player->pipeline && player->pipeline->mainbin)) {
6041                 LOGE("player pipeline handle is null");
6042                 return GST_BUS_PASS;
6043         }
6044
6045         if (!__mmplayer_check_useful_message(player, message)) {
6046                 gst_message_unref(message);
6047                 return GST_BUS_DROP;
6048         }
6049
6050         switch (GST_MESSAGE_TYPE(message)) {
6051         case GST_MESSAGE_STATE_CHANGED:
6052                 /* post directly for fast launch */
6053                 if (player->sync_handler) {
6054                         __mmplayer_gst_callback(NULL, message, player);
6055                         reply = GST_BUS_DROP;
6056                 } else
6057                         reply = GST_BUS_PASS;
6058                 break;
6059         case GST_MESSAGE_TAG:
6060                 __mmplayer_gst_extract_tag_from_msg(player, message);
6061
6062                 #if 0 // debug
6063                 {
6064                         GstTagList *tags = NULL;
6065
6066                         gst_message_parse_tag(message, &tags);
6067                         if (tags) {
6068                                 LOGE("TAGS received from element \"%s\".\n",
6069                                 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
6070
6071                                 gst_tag_list_foreach(tags, print_tag, NULL);
6072                                 gst_tag_list_free(tags);
6073                                 tags = NULL;
6074                         }
6075                         break;
6076                 }
6077                 #endif
6078                 break;
6079
6080         case GST_MESSAGE_DURATION_CHANGED:
6081                 __mmplayer_gst_handle_duration(player, message);
6082                 break;
6083         case GST_MESSAGE_ASYNC_DONE:
6084                 /* NOTE:Don't call gst_callback directly
6085                  * because previous frame can be showed even though this message is received for seek.
6086                  */
6087         default:
6088                 reply = GST_BUS_PASS;
6089                 break;
6090         }
6091
6092         if (reply == GST_BUS_DROP)
6093                 gst_message_unref(message);
6094
6095         return reply;
6096 }
6097
6098 static gboolean
6099 __mmplayer_gst_create_decoder(mm_player_t *player,
6100                                                                 MMPlayerTrackType track,
6101                                                                 GstPad* srcpad,
6102                                                                 enum MainElementID elemId,
6103                                                                 const gchar* name)
6104 {
6105         gboolean ret = TRUE;
6106         GstPad *sinkpad = NULL;
6107
6108         MMPLAYER_FENTER();
6109
6110         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
6111                                                 player->pipeline &&
6112                                                 player->pipeline->mainbin, FALSE);
6113         MMPLAYER_RETURN_VAL_IF_FAIL((track == MM_PLAYER_TRACK_TYPE_AUDIO || track == MM_PLAYER_TRACK_TYPE_VIDEO), FALSE);
6114         MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
6115         MMPLAYER_RETURN_VAL_IF_FAIL((player->pipeline->mainbin[elemId].gst == NULL), FALSE);
6116
6117         GstElement *decodebin = NULL;
6118         GstCaps *dec_caps = NULL;
6119
6120         /* create decodebin */
6121         decodebin = gst_element_factory_make("decodebin", name);
6122
6123         if (!decodebin) {
6124                 LOGE("error : fail to create decodebin for %d decoder\n", track);
6125                 ret = FALSE;
6126                 goto ERROR;
6127         }
6128
6129         /* raw pad handling signal */
6130         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6131                                                                                 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
6132
6133         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6134         before looking for any elements that can handle that stream.*/
6135         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6136                                                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
6137
6138         /* This signal is emitted when a element is added to the bin.*/
6139         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6140                                                                                 G_CALLBACK(__mmplayer_gst_element_added), player);
6141
6142         if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6143                 LOGE("failed to add new decodebin\n");
6144                 ret = FALSE;
6145                 goto ERROR;
6146         }
6147
6148         dec_caps = gst_pad_query_caps(srcpad, NULL);
6149         if (dec_caps) {
6150                 //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
6151                 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
6152                 gst_caps_unref(dec_caps);
6153         }
6154
6155         player->pipeline->mainbin[elemId].id = elemId;
6156         player->pipeline->mainbin[elemId].gst = decodebin;
6157
6158         sinkpad = gst_element_get_static_pad(decodebin, "sink");
6159
6160         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6161                 LOGW("failed to link [%s:%s] to decoder\n", GST_DEBUG_PAD_NAME(srcpad));
6162                 gst_object_unref(GST_OBJECT(decodebin));
6163         }
6164
6165         if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin))
6166                 LOGE("failed to sync second level decodebin state with parent\n");
6167
6168         LOGD("Total num of %d tracks = %d \n", track, player->selector[track].total_track_num);
6169
6170 ERROR:
6171         if (sinkpad) {
6172                 gst_object_unref(GST_OBJECT(sinkpad));
6173                 sinkpad = NULL;
6174         }
6175         MMPLAYER_FLEAVE();
6176
6177         return ret;
6178 }
6179
6180 /**
6181  * This function is to create  audio or video pipeline for playing.
6182  *
6183  * @param       player          [in]    handle of player
6184  *
6185  * @return      This function returns zero on success.
6186  * @remark
6187  * @see
6188  */
6189 static int
6190 __mmplayer_gst_create_pipeline(mm_player_t* player) // @
6191 {
6192         GstBus  *bus = NULL;
6193         MMPlayerGstElement *mainbin = NULL;
6194         MMHandleType attrs = 0;
6195         GstElement* element = NULL;
6196         GstElement* elem_src_audio = NULL;
6197         GstElement* elem_src_subtitle = NULL;
6198         GstElement* es_video_queue = NULL;
6199         GstElement* es_audio_queue = NULL;
6200         GstElement* es_subtitle_queue = NULL;
6201         GList* element_bucket = NULL;
6202         gboolean need_state_holder = TRUE;
6203         gint i = 0;
6204 #ifdef SW_CODEC_ONLY
6205         int surface_type = 0;
6206 #endif
6207         MMPLAYER_FENTER();
6208
6209         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6210
6211         /* get profile attribute */
6212         attrs = MMPLAYER_GET_ATTRS(player);
6213         if (!attrs) {
6214                 LOGE("cannot get content attribute\n");
6215                 goto INIT_ERROR;
6216         }
6217
6218         /* create pipeline handles */
6219         if (player->pipeline) {
6220                 LOGW("pipeline should be released before create new one\n");
6221                 goto INIT_ERROR;
6222         }
6223
6224         player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0(sizeof(MMPlayerGstPipelineInfo));
6225         if (player->pipeline == NULL)
6226                 goto INIT_ERROR;
6227
6228         memset(player->pipeline, 0, sizeof(MMPlayerGstPipelineInfo));
6229
6230
6231         /* create mainbin */
6232         mainbin = (MMPlayerGstElement*) g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
6233         if (mainbin == NULL)
6234                 goto INIT_ERROR;
6235
6236         memset(mainbin, 0, sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
6237
6238         /* create pipeline */
6239         mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
6240         mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
6241         if (!mainbin[MMPLAYER_M_PIPE].gst) {
6242                 LOGE("failed to create pipeline\n");
6243                 goto INIT_ERROR;
6244         }
6245         player->demux_pad_index = 0;
6246         player->subtitle_language_list = NULL;
6247
6248         player->is_subtitle_force_drop = FALSE;
6249         player->last_multiwin_status = FALSE;
6250
6251         _mmplayer_track_initialize(player);
6252
6253         /* create source element */
6254         switch (player->profile.uri_type) {
6255         /* rtsp streamming */
6256         case MM_PLAYER_URI_TYPE_URL_RTSP:
6257                 {
6258                         gint network_bandwidth;
6259                         gchar *user_agent, *wap_profile;
6260
6261                         element = gst_element_factory_make("rtspsrc", "rtsp source");
6262
6263                         if (!element) {
6264                                 LOGE("failed to create streaming source element\n");
6265                                 break;
6266                         }
6267
6268                         /* make it zero */
6269                         network_bandwidth = 0;
6270                         user_agent = wap_profile = NULL;
6271
6272                         /* get attribute */
6273                         mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6274                         mm_attrs_get_string_by_name(attrs, "streaming_wap_profile", &wap_profile);
6275                         mm_attrs_get_int_by_name(attrs, "streaming_network_bandwidth", &network_bandwidth);
6276
6277                         SECURE_LOGD("user_agent : %s\n", user_agent);
6278                         SECURE_LOGD("wap_profile : %s\n", wap_profile);
6279
6280                         /* setting property to streaming source */
6281                         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6282                         if (user_agent)
6283                                 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6284                         if (wap_profile)
6285                                 g_object_set(G_OBJECT(element), "wap_profile", wap_profile, NULL);
6286
6287                         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6288                                 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), player);
6289                         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6290                                 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), player);
6291
6292                         player->use_decodebin = FALSE;
6293                 }
6294                 break;
6295
6296         /* http streaming*/
6297         case MM_PLAYER_URI_TYPE_URL_HTTP:
6298                 {
6299                         gchar *user_agent, *proxy, *cookies, **cookie_list;
6300                         gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6301                         user_agent = proxy = cookies = NULL;
6302                         cookie_list = NULL;
6303                         gint mode = MM_PLAYER_PD_MODE_NONE;
6304
6305                         mm_attrs_get_int_by_name(attrs, "pd_mode", &mode);
6306
6307                         player->pd_mode = mode;
6308
6309                         LOGD("http playback, PD mode : %d\n", player->pd_mode);
6310
6311                         if (!MMPLAYER_IS_HTTP_PD(player)) {
6312                                 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
6313                                 if (!element) {
6314                                         LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
6315                                         break;
6316                                 }
6317                                 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
6318
6319                                 /* get attribute */
6320                                 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
6321                                 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6322                                 mm_attrs_get_string_by_name(attrs, "streaming_proxy", &proxy);
6323                                 mm_attrs_get_int_by_name(attrs, "streaming_timeout", &http_timeout);
6324
6325                                 if ((http_timeout == DEFAULT_HTTP_TIMEOUT) &&
6326                                         (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)) {
6327                                         LOGD("get timeout from ini\n");
6328                                         http_timeout = player->ini.http_timeout;
6329                                 }
6330
6331                                 /* get attribute */
6332                                 SECURE_LOGD("location : %s\n", player->profile.uri);
6333                                 SECURE_LOGD("cookies : %s\n", cookies);
6334                                 SECURE_LOGD("proxy : %s\n", proxy);
6335                                 SECURE_LOGD("user_agent :  %s\n",  user_agent);
6336                                 LOGD("timeout : %d\n",  http_timeout);
6337
6338                                 /* setting property to streaming source */
6339                                 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6340                                 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6341                                 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
6342
6343                                 /* check if prosy is vailid or not */
6344                                 if (util_check_valid_url(proxy))
6345                                         g_object_set(G_OBJECT(element), "proxy", proxy, NULL);
6346                                 /* parsing cookies */
6347                                 if ((cookie_list = util_get_cookie_list((const char*)cookies)))
6348                                         g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
6349                                 if (user_agent)
6350                                         g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6351
6352                                 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
6353                                         LOGW("it's dash. and it's still experimental feature.");
6354                         } else {
6355                                 // progressive download
6356                                 gchar* location = NULL;
6357
6358                                 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
6359                                         gchar *path = NULL;
6360
6361                                         mm_attrs_get_string_by_name(attrs, "pd_location", &path);
6362
6363                                         MMPLAYER_FREEIF(player->pd_file_save_path);
6364
6365                                         LOGD("PD Location : %s\n", path);
6366
6367                                         if (path) {
6368                                                 player->pd_file_save_path = g_strdup(path);
6369                                         } else {
6370                                                 LOGE("can't find pd location so, it should be set \n");
6371                                                 break;
6372                                         }
6373                                 }
6374
6375                                 element = gst_element_factory_make("pdpushsrc", "PD pushsrc");
6376                                 if (!element) {
6377                                         LOGE("failed to create PD push source element[%s].\n", "pdpushsrc");
6378                                         break;
6379                                 }
6380
6381                                 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
6382                                         g_object_set(G_OBJECT(element), "location", player->pd_file_save_path, NULL);
6383                                 else
6384                                         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6385
6386                                 g_object_get(element, "location", &location, NULL);
6387                                 LOGD("PD_LOCATION [%s].\n", location);
6388                                 if (location)
6389                                         g_free(location);
6390                         }
6391                 }
6392                 break;
6393
6394         /* file source */
6395         case MM_PLAYER_URI_TYPE_FILE:
6396                 {
6397
6398                         LOGD("using filesrc for 'file://' handler.\n");
6399
6400                         element = gst_element_factory_make("filesrc", "source");
6401
6402                         if (!element) {
6403                                 LOGE("failed to create filesrc\n");
6404                                 break;
6405                         }
6406
6407                         g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL);     /* uri+7 -> remove "file:// */
6408                         //g_object_set(G_OBJECT(element), "use-mmap", TRUE, NULL);
6409                 }
6410                 break;
6411
6412         case MM_PLAYER_URI_TYPE_SS:
6413                 {
6414                         gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6415                         element = gst_element_factory_make("souphttpsrc", "http streaming source");
6416                         if (!element) {
6417                                 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
6418                                 break;
6419                         }
6420
6421                         mm_attrs_get_int_by_name(attrs, "streaming_timeout", &http_timeout);
6422
6423                         if ((http_timeout == DEFAULT_HTTP_TIMEOUT) &&
6424                                 (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)) {
6425                                 LOGD("get timeout from ini\n");
6426                                 http_timeout = player->ini.http_timeout;
6427                         }
6428
6429                         /* setting property to streaming source */
6430                         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6431                         g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6432                 }
6433                 break;
6434         case MM_PLAYER_URI_TYPE_MS_BUFF:
6435                 {
6436                         LOGD("MS buff src is selected\n");
6437
6438                         if (player->v_stream_caps) {
6439                                 element = gst_element_factory_make("appsrc", "video_appsrc");
6440                                 if (!element) {
6441                                         LOGF("failed to create video app source element[appsrc].\n");
6442                                         break;
6443                                 }
6444
6445                                 if (player->a_stream_caps) {
6446                                         elem_src_audio = gst_element_factory_make("appsrc", "audio_appsrc");
6447                                         if (!elem_src_audio) {
6448                                                 LOGF("failed to create audio app source element[appsrc].\n");
6449                                                 break;
6450                                         }
6451                                 }
6452                         } else if (player->a_stream_caps) {
6453                                 /* no video, only audio pipeline*/
6454                                 element = gst_element_factory_make("appsrc", "audio_appsrc");
6455                                 if (!element) {
6456                                         LOGF("failed to create audio app source element[appsrc].\n");
6457                                         break;
6458                                 }
6459                         }
6460
6461                         if (player->s_stream_caps) {
6462                                 elem_src_subtitle = gst_element_factory_make("appsrc", "subtitle_appsrc");
6463                                 if (!elem_src_subtitle) {
6464                                         LOGF("failed to create subtitle app source element[appsrc].\n");
6465                                         break;
6466                                 }
6467                         }
6468
6469                         LOGD("setting app sources properties.\n");
6470                         LOGD("location : %s\n", player->profile.uri);
6471
6472                         if (player->v_stream_caps && element) {
6473                                 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6474                                                                                             "blocksize", (guint)1048576,        /* size of many video frames are larger than default blocksize as 4096 */
6475                                                                                                 "caps", player->v_stream_caps, NULL);
6476
6477                                 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6478                                         g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6479                                 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6480                                         g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6481
6482                                 /*Fix Seek External Demuxer:  set audio and video appsrc as seekable */
6483                                 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6484                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6485                                                                                                                 G_CALLBACK(__gst_seek_video_data), player);
6486
6487                                 if (player->a_stream_caps && elem_src_audio) {
6488                                         g_object_set(G_OBJECT(elem_src_audio), "format", GST_FORMAT_TIME,
6489                                                                                                                         "caps", player->a_stream_caps, NULL);
6490
6491                                         if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6492                                                 g_object_set(G_OBJECT(elem_src_audio), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6493                                         if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6494                                                 g_object_set(G_OBJECT(elem_src_audio), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6495
6496                                         /*Fix Seek External Demuxer:  set audio and video appsrc as seekable */
6497                                         gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_audio), GST_APP_STREAM_TYPE_SEEKABLE);
6498                                         MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6499                                                                                                                 G_CALLBACK(__gst_seek_audio_data), player);
6500                                 }
6501                         } else if (player->a_stream_caps && element) {
6502                                 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6503                                                                                                 "caps", player->a_stream_caps, NULL);
6504
6505                                 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6506                                         g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6507                                 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6508                                         g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6509
6510                                 /*Fix Seek External Demuxer:  set audio and video appsrc as seekable */
6511                                 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6512                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6513                                                                                                                         G_CALLBACK(__gst_seek_audio_data), player);
6514                         }
6515
6516                         if (player->s_stream_caps && elem_src_subtitle) {
6517                                 g_object_set(G_OBJECT(elem_src_subtitle), "format", GST_FORMAT_TIME,
6518                                                                                                                  "caps", player->s_stream_caps, NULL);
6519
6520                                 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6521                                         g_object_set(G_OBJECT(elem_src_subtitle), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6522                                 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6523                                         g_object_set(G_OBJECT(elem_src_subtitle), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6524
6525                                 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_subtitle), GST_APP_STREAM_TYPE_SEEKABLE);
6526
6527                                 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6528                                                                                                                                 G_CALLBACK(__gst_seek_subtitle_data), player);
6529                         }
6530
6531                         if (player->v_stream_caps && element) {
6532                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6533                                                                                                                 G_CALLBACK(__gst_appsrc_feed_video_data), player);
6534                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6535                                                                                                                 G_CALLBACK(__gst_appsrc_enough_video_data), player);
6536
6537                                 if (player->a_stream_caps && elem_src_audio) {
6538                                         MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6539                                                                                                                 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6540                                         MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6541                                                                                                                 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6542                                 }
6543                         } else if (player->a_stream_caps && element) {
6544                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6545                                                                                                                 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6546                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6547                                                                                                                 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6548                         }
6549
6550                         if (player->s_stream_caps && elem_src_subtitle)
6551                                 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6552                                                                                                                 G_CALLBACK(__gst_appsrc_feed_subtitle_data), player);
6553
6554                         need_state_holder = FALSE;
6555
6556                         mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
6557                         if (mmf_attrs_commit(attrs)) /* return -1 if error */
6558                                 LOGE("failed to commit\n");
6559                 }
6560                 break;
6561         /* appsrc */
6562         case MM_PLAYER_URI_TYPE_MEM:
6563                 {
6564                         guint64 stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
6565
6566                         LOGD("mem src is selected\n");
6567
6568                         element = gst_element_factory_make("appsrc", "mem-source");
6569                         if (!element) {
6570                                 LOGE("failed to create appsrc element\n");
6571                                 break;
6572                         }
6573
6574                         g_object_set(element, "stream-type", stream_type, NULL);
6575                         g_object_set(element, "size", player->mem_buf.len, NULL);
6576                         g_object_set(element, "blocksize", (guint64)20480, NULL);
6577
6578                         MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6579                                 G_CALLBACK(__gst_appsrc_seek_data_mem), &player->mem_buf);
6580                         MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6581                                 G_CALLBACK(__gst_appsrc_feed_data_mem), &player->mem_buf);
6582                 }
6583                 break;
6584         case MM_PLAYER_URI_TYPE_URL:
6585                 break;
6586
6587         case MM_PLAYER_URI_TYPE_TEMP:
6588                 break;
6589
6590         case MM_PLAYER_URI_TYPE_NONE:
6591         default:
6592                 break;
6593         }
6594
6595         /* check source element is OK */
6596         if (!element) {
6597                 LOGE("no source element was created.\n");
6598                 goto INIT_ERROR;
6599         }
6600
6601         /* take source element */
6602         mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6603         mainbin[MMPLAYER_M_SRC].gst = element;
6604         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
6605
6606         if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
6607                 player->streamer = __mm_player_streaming_create();
6608                 __mm_player_streaming_initialize(player->streamer);
6609         }
6610
6611         if (MMPLAYER_IS_HTTP_PD(player)) {
6612                 gdouble pre_buffering_time = (gdouble)player->streamer->buffering_req.initial_second;
6613
6614                 LOGD("Picked queue2 element(pre buffer : %d sec)....\n", pre_buffering_time);
6615                 element = gst_element_factory_make("queue2", "queue2");
6616                 if (!element) {
6617                         LOGE("failed to create http streaming buffer element\n");
6618                         goto INIT_ERROR;
6619                 }
6620
6621                 /* take it */
6622                 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6623                 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element;
6624                 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]);
6625
6626                 pre_buffering_time = (pre_buffering_time > 0) ? (pre_buffering_time) : (player->ini.http_buffering_time);
6627
6628                 __mm_player_streaming_set_queue2(player->streamer,
6629                                 element,
6630                                 TRUE,
6631                                 player->ini.http_max_size_bytes,
6632                                 pre_buffering_time,
6633                                 1.0,
6634                                 player->ini.http_buffering_limit,
6635                                 MUXED_BUFFER_TYPE_MEM_QUEUE,
6636                                 NULL,
6637                                 0);
6638         }
6639         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6640                 if (player->v_stream_caps) {
6641                         es_video_queue = gst_element_factory_make("queue2", "video_queue");
6642                         if (!es_video_queue) {
6643                                 LOGE("create es_video_queue for es player failed\n");
6644                                 goto INIT_ERROR;
6645                         }
6646                         g_object_set(G_OBJECT(es_video_queue), "max-size-buffers", 2, NULL);
6647                         mainbin[MMPLAYER_M_V_BUFFER].id = MMPLAYER_M_V_BUFFER;
6648                         mainbin[MMPLAYER_M_V_BUFFER].gst = es_video_queue;
6649                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_V_BUFFER]);
6650
6651                         /* Adding audio appsrc to bucket */
6652                         if (player->a_stream_caps && elem_src_audio) {
6653                                 mainbin[MMPLAYER_M_2ND_SRC].id = MMPLAYER_M_2ND_SRC;
6654                                 mainbin[MMPLAYER_M_2ND_SRC].gst = elem_src_audio;
6655                                 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_2ND_SRC]);
6656
6657                                 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6658                                 if (!es_audio_queue) {
6659                                         LOGE("create es_audio_queue for es player failed\n");
6660                                         goto INIT_ERROR;
6661                                 }
6662                                 g_object_set(G_OBJECT(es_audio_queue), "max-size-buffers", 2, NULL);
6663
6664                                 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6665                                 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6666                                 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6667                         }
6668                 } else if (player->a_stream_caps) {
6669                         /* Only audio stream, no video */
6670                         es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6671                         if (!es_audio_queue) {
6672                                 LOGE("create es_audio_queue for es player failed\n");
6673                                 goto INIT_ERROR;
6674                         }
6675                         mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6676                         mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6677                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6678                 }
6679
6680                 if (player->s_stream_caps && elem_src_subtitle) {
6681                         mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
6682                         mainbin[MMPLAYER_M_SUBSRC].gst = elem_src_subtitle;
6683                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SUBSRC]);
6684
6685                         es_subtitle_queue = gst_element_factory_make("queue2", "subtitle_queue");
6686                         if (!es_subtitle_queue) {
6687                                 LOGE("create es_subtitle_queue for es player failed\n");
6688                                 goto INIT_ERROR;
6689                         }
6690                         mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_V_BUFFER;
6691                         mainbin[MMPLAYER_M_S_BUFFER].gst = es_subtitle_queue;
6692                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_S_BUFFER]);
6693                 }
6694         }
6695
6696         /* create autoplugging element if src element is not a rtsp src */
6697         if ((player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_RTSP) &&
6698                 (player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_WFD) &&
6699                 (player->profile.uri_type != MM_PLAYER_URI_TYPE_MS_BUFF)) {
6700                 element = NULL;
6701                 enum MainElementID elemId = MMPLAYER_M_NUM;
6702
6703                 if ((player->use_decodebin) &&
6704                         ((MMPLAYER_IS_HTTP_PD(player)) ||
6705                         (!MMPLAYER_IS_HTTP_STREAMING(player)))) {
6706                         elemId = MMPLAYER_M_AUTOPLUG;
6707                         element = __mmplayer_create_decodebin(player);
6708                         if (element) {
6709                                 /* default size of mq in decodebin is 2M
6710                                  * but it can cause blocking issue during seeking depends on content. */
6711                                 g_object_set(G_OBJECT(element), "max-size-bytes", (5*1024*1024), NULL);
6712                         }
6713                         need_state_holder = FALSE;
6714                 } else {
6715                         elemId = MMPLAYER_M_TYPEFIND;
6716                         element = gst_element_factory_make("typefind", "typefinder");
6717                         MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
6718                                 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6719                 }
6720
6721
6722                 /* check autoplug element is OK */
6723                 if (!element) {
6724                         LOGE("can not create element(%d)\n", elemId);
6725                         goto INIT_ERROR;
6726                 }
6727
6728                 mainbin[elemId].id = elemId;
6729                 mainbin[elemId].gst = element;
6730
6731                 element_bucket = g_list_append(element_bucket, &mainbin[elemId]);
6732         }
6733
6734         /* add elements to pipeline */
6735         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
6736                 LOGE("Failed to add elements to pipeline\n");
6737                 goto INIT_ERROR;
6738         }
6739
6740
6741         /* linking elements in the bucket by added order. */
6742         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
6743                 LOGE("Failed to link some elements\n");
6744                 goto INIT_ERROR;
6745         }
6746
6747
6748         /* create fakesink element for keeping the pipeline state PAUSED. if needed */
6749         if (need_state_holder) {
6750                 /* create */
6751                 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
6752                 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
6753
6754                 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
6755                         LOGE("fakesink element could not be created\n");
6756                         goto INIT_ERROR;
6757                 }
6758                 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
6759
6760                 /* take ownership of fakesink. we are reusing it */
6761                 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
6762
6763                 /* add */
6764                 if (FALSE == gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst),
6765                         mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
6766                         LOGE("failed to add fakesink to bin\n");
6767                         goto INIT_ERROR;
6768                 }
6769         }
6770
6771         /* now we have completed mainbin. take it */
6772         player->pipeline->mainbin = mainbin;
6773
6774         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6775                 GstPad *srcpad = NULL;
6776
6777                 if (mainbin[MMPLAYER_M_V_BUFFER].gst) {
6778                         srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_V_BUFFER].gst, "src");
6779                         if (srcpad) {
6780                                 __mmplayer_gst_create_decoder(player,
6781                                                                                                 MM_PLAYER_TRACK_TYPE_VIDEO,
6782                                                                                                 srcpad,
6783                                                                                                 MMPLAYER_M_AUTOPLUG_V_DEC,
6784                                                                                                 "video_decodebin");
6785
6786                                 gst_object_unref(GST_OBJECT(srcpad));
6787                                 srcpad = NULL;
6788                         }
6789                 }
6790
6791                 if ((player->a_stream_caps) && (mainbin[MMPLAYER_M_A_BUFFER].gst)) {
6792                         srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_A_BUFFER].gst, "src");
6793                         if (srcpad) {
6794                                 __mmplayer_gst_create_decoder(player,
6795                                                                                                 MM_PLAYER_TRACK_TYPE_AUDIO,
6796                                                                                                 srcpad,
6797                                                                                                 MMPLAYER_M_AUTOPLUG_A_DEC,
6798                                                                                                 "audio_decodebin");
6799
6800                                 gst_object_unref(GST_OBJECT(srcpad));
6801                                 srcpad = NULL;
6802                         } // else error
6803                 } //  else error
6804
6805                 if (mainbin[MMPLAYER_M_S_BUFFER].gst)
6806                         __mmplayer_try_to_plug_decodebin(player, gst_element_get_static_pad(mainbin[MMPLAYER_M_S_BUFFER].gst, "src"), player->s_stream_caps);
6807         }
6808
6809         /* connect bus callback */
6810         bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6811         if (!bus) {
6812                 LOGE("cannot get bus from pipeline.\n");
6813                 goto INIT_ERROR;
6814         }
6815
6816         player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_callback, player);
6817
6818         player->context.thread_default = g_main_context_get_thread_default();
6819
6820         if (NULL == player->context.thread_default) {
6821                 player->context.thread_default = g_main_context_default();
6822                 LOGD("thread-default context is the global default context");
6823         }
6824         LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
6825
6826         /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
6827         if (__mmplayer_check_subtitle(player)) {
6828                 if (MM_ERROR_NONE != __mmplayer_gst_create_subtitle_src(player))
6829                         LOGE("fail to create subtitle src\n");
6830         }
6831
6832         /* set sync handler to get tag synchronously */
6833         gst_bus_set_sync_handler(bus, __mmplayer_bus_sync_callback, player, NULL);
6834
6835         /* finished */
6836         gst_object_unref(GST_OBJECT(bus));
6837         g_list_free(element_bucket);
6838
6839         MMPLAYER_FLEAVE();
6840
6841         return MM_ERROR_NONE;
6842
6843 INIT_ERROR:
6844
6845         __mmplayer_gst_destroy_pipeline(player);
6846         g_list_free(element_bucket);
6847
6848         if (mainbin) {
6849                 /* release element which are not added to bin */
6850                 for (i = 1; i < MMPLAYER_M_NUM; i++) {
6851                         /* NOTE : skip pipeline */
6852                         if (mainbin[i].gst) {
6853                                 GstObject* parent = NULL;
6854                                 parent = gst_element_get_parent(mainbin[i].gst);
6855
6856                                 if (!parent) {
6857                                         gst_object_unref(GST_OBJECT(mainbin[i].gst));
6858                                         mainbin[i].gst = NULL;
6859                                 } else
6860                                         gst_object_unref(GST_OBJECT(parent));
6861                         }
6862                 }
6863
6864                 /* release pipeline with it's childs */
6865                 if (mainbin[MMPLAYER_M_PIPE].gst)
6866                         gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
6867
6868                 MMPLAYER_FREEIF(mainbin);
6869         }
6870
6871         MMPLAYER_FREEIF(player->pipeline);
6872         return MM_ERROR_PLAYER_INTERNAL;
6873 }
6874
6875 static void
6876 __mmplayer_reset_gapless_state(mm_player_t* player)
6877 {
6878         MMPLAYER_FENTER();
6879         MMPLAYER_RETURN_IF_FAIL(player
6880                 && player->pipeline
6881                 && player->pipeline->audiobin
6882                 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
6883
6884         memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
6885
6886         MMPLAYER_FLEAVE();
6887         return;
6888 }
6889
6890 static int
6891 __mmplayer_gst_destroy_pipeline(mm_player_t* player) // @
6892 {
6893         gint timeout = 0;
6894         int ret = MM_ERROR_NONE;
6895
6896         MMPLAYER_FENTER();
6897
6898         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
6899
6900         /* cleanup stuffs */
6901         MMPLAYER_FREEIF(player->type);
6902         player->have_dynamic_pad = FALSE;
6903         player->no_more_pad = FALSE;
6904         player->num_dynamic_pad = 0;
6905         player->demux_pad_index = 0;
6906         player->subtitle_language_list = NULL;
6907         player->use_deinterleave = FALSE;
6908         player->max_audio_channels = 0;
6909         player->video_share_api_delta = 0;
6910         player->video_share_clock_delta = 0;
6911         player->video_hub_download_mode = 0;
6912         __mmplayer_reset_gapless_state(player);
6913
6914         if (player->streamer) {
6915                 __mm_player_streaming_deinitialize(player->streamer);
6916                 __mm_player_streaming_destroy(player->streamer);
6917                 player->streamer = NULL;
6918         }
6919
6920         /* cleanup unlinked mime type */
6921         MMPLAYER_FREEIF(player->unlinked_audio_mime);
6922         MMPLAYER_FREEIF(player->unlinked_video_mime);
6923         MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
6924
6925         /* cleanup running stuffs */
6926         __mmplayer_cancel_eos_timer(player);
6927
6928         /* cleanup gst stuffs */
6929         if (player->pipeline) {
6930                 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
6931                 GstTagList* tag_list = player->pipeline->tag_list;
6932
6933                 /* first we need to disconnect all signal hander */
6934                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
6935
6936                 /* disconnecting bus watch */
6937                 if (player->bus_watcher)
6938                         __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
6939                 player->bus_watcher = 0;
6940
6941                 if (mainbin) {
6942                         MMPlayerGstElement* audiobin = player->pipeline->audiobin;
6943                         MMPlayerGstElement* videobin = player->pipeline->videobin;
6944                         MMPlayerGstElement* textbin = player->pipeline->textbin;
6945                         GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6946                         gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
6947                         gst_object_unref(bus);
6948
6949                         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
6950                         ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
6951                         if (ret != MM_ERROR_NONE) {
6952                                 LOGE("fail to change state to NULL\n");
6953                                 return MM_ERROR_PLAYER_INTERNAL;
6954                         }
6955
6956                         LOGW("succeeded in chaning state to NULL\n");
6957
6958                         gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
6959
6960                         /* free fakesink */
6961                         if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
6962                                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
6963
6964                         /* free avsysaudiosink
6965                            avsysaudiosink should be unref when destory pipeline just after start play with BT.
6966                            Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
6967                         */
6968                         MMPLAYER_FREEIF(audiobin);
6969                         MMPLAYER_FREEIF(videobin);
6970                         MMPLAYER_FREEIF(textbin);
6971                         MMPLAYER_FREEIF(mainbin);
6972                 }
6973
6974                 if (tag_list)
6975                         gst_tag_list_free(tag_list);
6976
6977                 MMPLAYER_FREEIF(player->pipeline);
6978         }
6979         MMPLAYER_FREEIF(player->album_art);
6980
6981         if (player->v_stream_caps) {
6982                 gst_caps_unref(player->v_stream_caps);
6983                 player->v_stream_caps = NULL;
6984         }
6985         if (player->a_stream_caps) {
6986                 gst_caps_unref(player->a_stream_caps);
6987                 player->a_stream_caps = NULL;
6988         }
6989
6990         if (player->s_stream_caps) {
6991                 gst_caps_unref(player->s_stream_caps);
6992                 player->s_stream_caps = NULL;
6993         }
6994         _mmplayer_track_destroy(player);
6995
6996         if (player->sink_elements)
6997                 g_list_free(player->sink_elements);
6998         player->sink_elements = NULL;
6999
7000         if (player->bufmgr) {
7001                 tbm_bufmgr_deinit(player->bufmgr);
7002                 player->bufmgr = NULL;
7003         }
7004
7005         LOGW("finished destroy pipeline\n");
7006
7007         MMPLAYER_FLEAVE();
7008
7009         return ret;
7010 }
7011
7012 static int __gst_realize(mm_player_t* player) // @
7013 {
7014         gint timeout = 0;
7015         int ret = MM_ERROR_NONE;
7016
7017         MMPLAYER_FENTER();
7018
7019         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7020
7021         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7022
7023         ret = __mmplayer_gst_create_pipeline(player);
7024         if (ret) {
7025                 LOGE("failed to create pipeline\n");
7026                 return ret;
7027         }
7028
7029         /* set pipeline state to READY */
7030         /* NOTE : state change to READY must be performed sync. */
7031         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7032         ret = __mmplayer_gst_set_state(player,
7033                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
7034
7035         if (ret != MM_ERROR_NONE) {
7036                 /* return error if failed to set state */
7037                 LOGE("failed to set READY state");
7038                 return ret;
7039         } else
7040                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7041
7042         /* create dot before error-return. for debugging */
7043         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
7044
7045         MMPLAYER_FLEAVE();
7046
7047         return ret;
7048 }
7049
7050 static int __gst_unrealize(mm_player_t* player) // @
7051 {
7052         int ret = MM_ERROR_NONE;
7053
7054         MMPLAYER_FENTER();
7055
7056         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7057
7058         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
7059         MMPLAYER_PRINT_STATE(player);
7060
7061         /* release miscellaneous information */
7062         __mmplayer_release_misc(player);
7063
7064         /* destroy pipeline */
7065         ret = __mmplayer_gst_destroy_pipeline(player);
7066         if (ret != MM_ERROR_NONE) {
7067                 LOGE("failed to destory pipeline\n");
7068                 return ret;
7069         }
7070
7071         /* release miscellaneous information.
7072            these info needs to be released after pipeline is destroyed. */
7073         __mmplayer_release_misc_post(player);
7074
7075         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
7076
7077         MMPLAYER_FLEAVE();
7078
7079         return ret;
7080 }
7081
7082 static int __gst_pending_seek(mm_player_t* player)
7083 {
7084         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7085         int ret = MM_ERROR_NONE;
7086
7087         MMPLAYER_FENTER();
7088
7089         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7090
7091         if (!player->pending_seek.is_pending) {
7092                 LOGD("pending seek is not reserved. nothing to do.\n");
7093                 return ret;
7094         }
7095
7096         /* check player state if player could pending seek or not. */
7097         current_state = MMPLAYER_CURRENT_STATE(player);
7098
7099         if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
7100                 LOGW("try to pending seek in %s state, try next time. \n",
7101                         MMPLAYER_STATE_GET_NAME(current_state));
7102                 return ret;
7103         }
7104
7105         LOGD("trying to play from(%lu) pending position\n", player->pending_seek.pos);
7106
7107         ret = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, FALSE);
7108
7109         if (MM_ERROR_NONE != ret)
7110                 LOGE("failed to seek pending postion. just keep staying current position.\n");
7111
7112         player->pending_seek.is_pending = FALSE;
7113
7114         MMPLAYER_FLEAVE();
7115
7116         return ret;
7117 }
7118
7119 static int __gst_start(mm_player_t* player) // @
7120 {
7121         gboolean sound_extraction = 0;
7122         int ret = MM_ERROR_NONE;
7123         gboolean async = FALSE;
7124
7125         MMPLAYER_FENTER();
7126
7127         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7128
7129         /* get sound_extraction property */
7130         mm_attrs_get_int_by_name(player->attrs, "pcm_extraction", &sound_extraction);
7131
7132         /* NOTE : if SetPosition was called before Start. do it now */
7133         /* streaming doesn't support it. so it should be always sync */
7134         /* !!create one more api to check if there is pending seek rather than checking variables */
7135         if ((player->pending_seek.is_pending || sound_extraction) && !MMPLAYER_IS_STREAMING(player)) {
7136                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
7137                 ret = __gst_pause(player, FALSE);
7138                 if (ret != MM_ERROR_NONE) {
7139                         LOGE("failed to set state to PAUSED for pending seek\n");
7140                         return ret;
7141                 }
7142
7143                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
7144
7145                 if (sound_extraction) {
7146                         LOGD("setting pcm extraction\n");
7147
7148                         ret = __mmplayer_set_pcm_extraction(player);
7149                         if (MM_ERROR_NONE != ret) {
7150                                 LOGW("failed to set pcm extraction\n");
7151                                 return ret;
7152                         }
7153                 } else {
7154                         if (MM_ERROR_NONE != __gst_pending_seek(player))
7155                                 LOGW("failed to seek pending postion. starting from the begin of content.\n");
7156                 }
7157         }
7158
7159         LOGD("current state before doing transition");
7160         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7161         MMPLAYER_PRINT_STATE(player);
7162
7163         /* set pipeline state to PLAYING  */
7164         if (player->es_player_push_mode)
7165                 async = TRUE;
7166         /* set pipeline state to PLAYING  */
7167         ret = __mmplayer_gst_set_state(player,
7168                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7169
7170         if (ret == MM_ERROR_NONE) {
7171                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7172         } else {
7173                 LOGE("failed to set state to PLAYING");
7174                 return ret;
7175         }
7176
7177         /* generating debug info before returning error */
7178         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
7179
7180         MMPLAYER_FLEAVE();
7181
7182         return ret;
7183 }
7184
7185 static void __mmplayer_do_sound_fadedown(mm_player_t* player, unsigned int time)
7186 {
7187         MMPLAYER_FENTER();
7188
7189         MMPLAYER_RETURN_IF_FAIL(player
7190                 && player->pipeline
7191                 && player->pipeline->audiobin
7192                 && player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
7193
7194         g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", TRUE, NULL);
7195
7196         usleep(time);
7197
7198         MMPLAYER_FLEAVE();
7199 }
7200
7201 static void __mmplayer_undo_sound_fadedown(mm_player_t* player)
7202 {
7203         MMPLAYER_FENTER();
7204
7205         MMPLAYER_RETURN_IF_FAIL(player
7206                 && player->pipeline
7207                 && player->pipeline->audiobin
7208                 && player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
7209
7210         g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", FALSE, NULL);
7211
7212         MMPLAYER_FLEAVE();
7213 }
7214
7215 static int __gst_stop(mm_player_t* player) // @
7216 {
7217         GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
7218         MMHandleType attrs = 0;
7219         gboolean fadedown = FALSE;
7220         gboolean rewind = FALSE;
7221         gint timeout = 0;
7222         int ret = MM_ERROR_NONE;
7223         gboolean async = FALSE;
7224
7225         MMPLAYER_FENTER();
7226
7227         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7228         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7229
7230         LOGD("current state before doing transition");
7231         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7232         MMPLAYER_PRINT_STATE(player);
7233
7234         attrs = MMPLAYER_GET_ATTRS(player);
7235         if (!attrs) {
7236                 LOGE("cannot get content attribute\n");
7237                 return MM_ERROR_PLAYER_INTERNAL;
7238         }
7239
7240         mm_attrs_get_int_by_name(attrs, "sound_fadedown", &fadedown);
7241
7242         /* enable fadedown */
7243         if (fadedown || player->sound_focus.by_asm_cb)
7244                 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
7245
7246         /* Just set state to PAUESED and the rewind. it's usual player behavior. */
7247         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7248
7249         if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
7250                 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
7251                 rewind = TRUE;
7252
7253         if (player->es_player_push_mode)
7254                 async = TRUE;
7255         /* set gst state */
7256         ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, timeout);
7257
7258         /* disable fadeout */
7259         if (fadedown || player->sound_focus.by_asm_cb)
7260                 __mmplayer_undo_sound_fadedown(player);
7261
7262         /* return if set_state has failed */
7263         if (ret != MM_ERROR_NONE) {
7264                 LOGE("failed to set state.\n");
7265                 return ret;
7266         }
7267
7268         /* rewind */
7269         if (rewind) {
7270                 if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7271                                 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
7272                                 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
7273                         LOGW("failed to rewind\n");
7274                         ret = MM_ERROR_PLAYER_SEEK;
7275                 }
7276         }
7277
7278         /* initialize */
7279         player->sent_bos = FALSE;
7280
7281         if (player->es_player_push_mode) //for cloudgame
7282                 timeout = 0;
7283
7284         /* wait for seek to complete */
7285         change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
7286         if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
7287                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7288         } else {
7289                 LOGE("fail to stop player.\n");
7290                 ret = MM_ERROR_PLAYER_INTERNAL;
7291                 __mmplayer_dump_pipeline_state(player);
7292         }
7293
7294         /* generate dot file if enabled */
7295         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
7296
7297         MMPLAYER_FLEAVE();
7298
7299         return ret;
7300 }
7301
7302 int __gst_pause(mm_player_t* player, gboolean async) // @
7303 {
7304         int ret = MM_ERROR_NONE;
7305
7306         MMPLAYER_FENTER();
7307
7308         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7309         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7310
7311         LOGD("current state before doing transition");
7312         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
7313         MMPLAYER_PRINT_STATE(player);
7314
7315         /* set pipeline status to PAUSED */
7316         player->ignore_asyncdone = TRUE;
7317
7318         ret = __mmplayer_gst_set_state(player,
7319                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7320
7321         player->ignore_asyncdone = FALSE;
7322
7323         if (FALSE == async) {
7324                 if (ret != MM_ERROR_NONE) {
7325                         GstMessage *msg = NULL;
7326                         GTimer *timer = NULL;
7327                         gdouble MAX_TIMEOUT_SEC = 3;
7328
7329                         LOGE("failed to set state to PAUSED");
7330
7331                         if (player->msg_posted) {
7332                                 LOGE("error msg is already posted.");
7333                                 return ret;
7334                         }
7335
7336                         timer = g_timer_new();
7337                         g_timer_start(timer);
7338
7339                         GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7340
7341                         do {
7342                                 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
7343                                 if (msg) {
7344                                         if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
7345                                                 GError *error = NULL;
7346
7347                                                 /* parse error code */
7348                                                 gst_message_parse_error(msg, &error, NULL);
7349
7350                                                 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
7351                                                         /* Note : the streaming error from the streaming source is handled
7352                                                          *   using __mmplayer_handle_streaming_error.
7353                                                          */
7354                                                         __mmplayer_handle_streaming_error(player, msg);
7355
7356                                                 } else if (error) {
7357                                                         LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
7358
7359                                                         if (error->domain == GST_STREAM_ERROR)
7360                                                                 ret = __gst_handle_stream_error(player, error, msg);
7361                                                         else if (error->domain == GST_RESOURCE_ERROR)
7362                                                                 ret = __gst_handle_resource_error(player, error->code);
7363                                                         else if (error->domain == GST_LIBRARY_ERROR)
7364                                                                 ret = __gst_handle_library_error(player, error->code);
7365                                                         else if (error->domain == GST_CORE_ERROR)
7366                                                                 ret = __gst_handle_core_error(player, error->code);
7367                                                 }
7368                                                 player->msg_posted = TRUE;
7369                                         }
7370                                         gst_message_unref(msg);
7371                                 }
7372                         } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
7373                         /* clean */
7374                         gst_object_unref(bus);
7375                         g_timer_stop(timer);
7376                         g_timer_destroy(timer);
7377
7378                         return ret;
7379
7380                 } else if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_stream_cb) &&
7381                                    (!player->pipeline->videobin) && (!player->pipeline->audiobin)) {
7382
7383                         return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
7384
7385                 } else if (ret == MM_ERROR_NONE) {
7386
7387                         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
7388                 }
7389         }
7390
7391         /* generate dot file before returning error */
7392         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
7393
7394         MMPLAYER_FLEAVE();
7395
7396         return ret;
7397 }
7398
7399 int __gst_resume(mm_player_t* player, gboolean async) // @
7400 {
7401         int ret = MM_ERROR_NONE;
7402         gint timeout = 0;
7403
7404         MMPLAYER_FENTER();
7405
7406         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
7407                 MM_ERROR_PLAYER_NOT_INITIALIZED);
7408
7409         LOGD("current state before doing transition");
7410         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7411         MMPLAYER_PRINT_STATE(player);
7412
7413         /* generate dot file before returning error */
7414         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7415
7416         if (async)
7417                 LOGD("do async state transition to PLAYING.\n");
7418
7419         /* set pipeline state to PLAYING */
7420         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7421
7422         ret = __mmplayer_gst_set_state(player,
7423                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
7424         if (ret != MM_ERROR_NONE) {
7425                 LOGE("failed to set state to PLAYING\n");
7426                 return ret;
7427         } else {
7428                 if (async == FALSE) {
7429                         // MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7430                         LOGD("update state machine to %d\n", MM_PLAYER_STATE_PLAYING);
7431                         ret = __mmplayer_set_state(player, MM_PLAYER_STATE_PLAYING);
7432                 }
7433         }
7434
7435         /* generate dot file before returning error */
7436         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7437
7438         MMPLAYER_FLEAVE();
7439
7440         return ret;
7441 }
7442
7443 static int
7444 __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called) // @
7445 {
7446         unsigned long dur_msec = 0;
7447         gint64 dur_nsec = 0;
7448         gint64 pos_nsec = 0;
7449         gboolean ret = TRUE;
7450         gboolean accurated = FALSE;
7451         GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
7452
7453         MMPLAYER_FENTER();
7454         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7455         MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
7456
7457         if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
7458                 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
7459                 goto PENDING;
7460
7461         if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7462                 /* check duration */
7463                 /* NOTE : duration cannot be zero except live streaming.
7464                  *              Since some element could have some timing problemn with quering duration, try again.
7465                  */
7466                 if (!player->duration) {
7467                         if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec))
7468                         {
7469                                 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
7470                                  * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
7471                                 if ((MMPLAYER_IS_RTSP_STREAMING( player )) && (__mmplayer_get_stream_service_type(player) != STREAMING_SERVICE_LIVE)) {
7472                                         player->pending_seek.is_pending = TRUE;
7473                                         player->pending_seek.format = format;
7474                                         player->pending_seek.pos = position;
7475                                         player->doing_seek = FALSE;
7476                                         MMPLAYER_POST_MSG ( player, MM_MESSAGE_SEEK_COMPLETED, NULL );
7477                                         return MM_ERROR_NONE;
7478                                 } else
7479                                 goto SEEK_ERROR;
7480                         }
7481                         player->duration = dur_nsec;
7482                 }
7483
7484                 if (player->duration) {
7485                         dur_msec = GST_TIME_AS_MSECONDS(player->duration);
7486                 } else {
7487                         LOGE("could not get the duration. fail to seek.\n");
7488                         goto SEEK_ERROR;
7489                 }
7490         }
7491         LOGD("playback rate: %f\n", player->playback_rate);
7492
7493         mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
7494         if (accurated)
7495                 seek_flags |= GST_SEEK_FLAG_ACCURATE;
7496         else
7497                 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
7498
7499         /* do seek */
7500         switch (format) {
7501         case MM_PLAYER_POS_FORMAT_TIME:
7502         {
7503                 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7504                         /* check position is valid or not */
7505                         if (position > dur_msec)
7506                                 goto INVALID_ARGS;
7507
7508                         LOGD("seeking to(%lu) msec, duration is %d msec\n", position, dur_msec);
7509
7510                         /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
7511                            But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
7512                            This causes problem is position calculation during normal pause resume scenarios also.
7513                            Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
7514                         if ((MMPLAYER_IS_RTSP_STREAMING( player )) &&
7515                                 (__mmplayer_get_stream_service_type(player) != STREAMING_SERVICE_LIVE)) {
7516                                 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
7517                                         LOGW("getting current position failed in seek\n");
7518
7519                                 player->last_position = pos_nsec;
7520                                 g_object_set( player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL );
7521                         }
7522
7523                         if (player->doing_seek) {
7524                                 LOGD("not completed seek");
7525                                 return MM_ERROR_PLAYER_DOING_SEEK;
7526                         }
7527                 }
7528
7529                 if (!internal_called)
7530                         player->doing_seek = TRUE;
7531
7532                 pos_nsec = position * G_GINT64_CONSTANT(1000000);
7533
7534                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) && (!player->videodec_linked)) {
7535                         gint64 cur_time = 0;
7536
7537                         /* get current position */
7538                         gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_time);
7539
7540                         /* flush */
7541                         GstEvent *event = gst_event_new_seek(1.0,
7542                                                         GST_FORMAT_TIME,
7543                                                         (GstSeekFlags)GST_SEEK_FLAG_FLUSH,
7544                                                         GST_SEEK_TYPE_SET, cur_time,
7545                                                         GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7546                         if (event)
7547                                 __gst_send_event_to_sink(player, event);
7548
7549                         if (!MMPLAYER_IS_RTSP_STREAMING(player))
7550                                 __gst_pause(player, FALSE);
7551                 }
7552
7553                 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
7554                         that's why set position through property. */
7555                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7556                         (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
7557                         (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
7558                         (!player->videodec_linked) && (!player->audiodec_linked)) {
7559
7560                         g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", pos_nsec, NULL);
7561                         LOGD("[%s] set position =%"GST_TIME_FORMAT,
7562                                         gst_element_get_name(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(pos_nsec));
7563                         player->doing_seek = FALSE;
7564                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7565                 } else {
7566                         ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7567                                                         GST_FORMAT_TIME, seek_flags,
7568                                                         GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7569                 }
7570
7571                 if (!ret) {
7572                         LOGE("failed to set position. dur[%lu]  pos[%lu]  pos_msec[%llu]\n", dur_msec, position, pos_nsec);
7573                         goto SEEK_ERROR;
7574                 }
7575         }
7576         break;
7577
7578         case MM_PLAYER_POS_FORMAT_PERCENT:
7579         {
7580                 LOGD("seeking to(%lu)%% \n", position);
7581
7582                 if (player->doing_seek) {
7583                         LOGD("not completed seek");
7584                         return MM_ERROR_PLAYER_DOING_SEEK;
7585                 }
7586
7587                 if (!internal_called)
7588                         player->doing_seek = TRUE;
7589
7590                 /* FIXIT : why don't we use 'GST_FORMAT_PERCENT' */
7591                 pos_nsec = (gint64)((position * player->duration) / 100);
7592                 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7593                                                 GST_FORMAT_TIME, seek_flags,
7594                                                 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7595                 if (!ret) {
7596                         LOGE("failed to set position. dur[%lud]  pos[%lud]  pos_msec[%"G_GUINT64_FORMAT"]\n", dur_msec, position, pos_nsec);
7597                         goto SEEK_ERROR;
7598                 }
7599         }
7600         break;
7601
7602         default:
7603                 goto INVALID_ARGS;
7604         }
7605
7606         /* NOTE : store last seeking point to overcome some bad operation
7607           *     (returning zero when getting current position) of some elements
7608           */
7609         player->last_position = pos_nsec;
7610
7611         /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
7612         if (player->playback_rate > 1.0)
7613                 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
7614
7615         MMPLAYER_FLEAVE();
7616         return MM_ERROR_NONE;
7617
7618 PENDING:
7619         player->pending_seek.is_pending = TRUE;
7620         player->pending_seek.format = format;
7621         player->pending_seek.pos = position;
7622
7623         LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%lu).\n",
7624                 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)), MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)), player->pending_seek.pos);
7625
7626         return MM_ERROR_NONE;
7627
7628 INVALID_ARGS:
7629         LOGE("invalid arguments, position : %ld  dur : %ld format : %d \n", position, dur_msec, format);
7630         return MM_ERROR_INVALID_ARGUMENT;
7631
7632 SEEK_ERROR:
7633         player->doing_seek = FALSE;
7634         return MM_ERROR_PLAYER_SEEK;
7635 }
7636
7637 #define TRICKPLAY_OFFSET GST_MSECOND
7638
7639 static int
7640 __gst_get_position(mm_player_t* player, int format, unsigned long* position) // @
7641 {
7642         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7643         gint64 pos_msec = 0;
7644         gboolean ret = TRUE;
7645
7646         MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
7647                 MM_ERROR_PLAYER_NOT_INITIALIZED);
7648
7649         current_state = MMPLAYER_CURRENT_STATE(player);
7650
7651         /* NOTE : query position except paused state to overcome some bad operation
7652          * please refer to below comments in details
7653          */
7654         if (current_state != MM_PLAYER_STATE_PAUSED)
7655                 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
7656
7657         /* NOTE : get last point to overcome some bad operation of some elements
7658          *(returning zero when getting current position in paused state
7659          * and when failed to get postion during seeking
7660          */
7661         if ((current_state == MM_PLAYER_STATE_PAUSED)
7662                 || (!ret)) {
7663                 //|| (player->last_position != 0 && pos_msec == 0))
7664                 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state);
7665
7666                 if (player->playback_rate < 0.0)
7667                         pos_msec = player->last_position - TRICKPLAY_OFFSET;
7668                 else
7669                         pos_msec = player->last_position;
7670
7671                 if (!ret)
7672                         pos_msec = player->last_position;
7673                 else
7674                         player->last_position = pos_msec;
7675
7676                 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_msec));
7677
7678         } else {
7679                 if (player->duration > 0 && pos_msec > player->duration)
7680                         pos_msec = player->duration;
7681
7682                 if (player->sound_focus.keep_last_pos) {
7683                         LOGD("return last pos as stop by asm, %"GST_TIME_FORMAT, GST_TIME_ARGS(player->last_position));
7684                         pos_msec = player->last_position;
7685                 } else
7686                         player->last_position = pos_msec;
7687         }
7688
7689         switch (format) {
7690         case MM_PLAYER_POS_FORMAT_TIME:
7691                 *position = GST_TIME_AS_MSECONDS(pos_msec);
7692                 break;
7693
7694         case MM_PLAYER_POS_FORMAT_PERCENT:
7695         {
7696                 if (player->duration <= 0) {
7697                         LOGD("duration is [%lld], so returning position 0\n", player->duration);
7698                         *position = 0;
7699                 } else {
7700                         LOGD("postion is [%lld] msec , duration is [%lld] msec", pos_msec, player->duration);
7701                         *position = pos_msec * 100 / player->duration;
7702                 }
7703                 break;
7704         }
7705         default:
7706                 return MM_ERROR_PLAYER_INTERNAL;
7707         }
7708
7709         return MM_ERROR_NONE;
7710 }
7711
7712
7713 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
7714 {
7715 #define STREAMING_IS_FINISHED   0
7716 #define BUFFERING_MAX_PER       100
7717 #define DEFAULT_PER_VALUE       -1
7718 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
7719
7720         MMPlayerGstElement *mainbin = NULL;
7721         gint start_per = DEFAULT_PER_VALUE, stop_per = DEFAULT_PER_VALUE;
7722         gint64 buffered_total = 0;
7723         unsigned long position = 0;
7724         gint buffered_sec = -1;
7725         GstBufferingMode mode = GST_BUFFERING_STREAM;
7726         gint64 content_size_time = player->duration;
7727         guint64 content_size_bytes = player->http_content_size;
7728
7729         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7730                                                 player->pipeline &&
7731                                                 player->pipeline->mainbin,
7732                                                 MM_ERROR_PLAYER_NOT_INITIALIZED);
7733
7734         MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT);
7735
7736         *start_pos = 0;
7737         *stop_pos = 0;
7738
7739         if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
7740                 /* and rtsp is not ready yet. */
7741                 LOGW("it's only used for http streaming case.\n");
7742                 return MM_ERROR_PLAYER_NO_OP;
7743         }
7744
7745         if (format != MM_PLAYER_POS_FORMAT_PERCENT) {
7746                 LOGW("Time format is not supported yet.\n");
7747                 return MM_ERROR_INVALID_ARGUMENT;
7748         }
7749
7750         if (content_size_time <= 0 || content_size_bytes <= 0) {
7751                 LOGW("there is no content size.");
7752                 return MM_ERROR_NONE;
7753         }
7754
7755         if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position) != MM_ERROR_NONE) {
7756                 LOGW("fail to get current position.");
7757                 return MM_ERROR_NONE;
7758         }
7759
7760         LOGD("pos %d ms, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
7761                 position, (guint)(content_size_time/GST_SECOND), content_size_bytes);
7762
7763         mainbin = player->pipeline->mainbin;
7764         start_per = ceil(100 *(position*GST_MSECOND) / content_size_time);
7765
7766         if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
7767                 GstQuery *query = NULL;
7768                 gint byte_in_rate = 0, byte_out_rate = 0;
7769                 gint64 estimated_total = 0;
7770
7771                 query = gst_query_new_buffering(GST_FORMAT_BYTES);
7772                 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
7773                         LOGW("fail to get buffering query from queue2");
7774                         if (query)
7775                                 gst_query_unref(query);
7776                         return MM_ERROR_NONE;
7777                 }
7778
7779                 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
7780                 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
7781
7782                 if (mode == GST_BUFFERING_STREAM) {
7783                         /* using only queue in case of push mode(ts / mp3) */
7784                         if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
7785                                 GST_FORMAT_BYTES, &buffered_total)) {
7786                                 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
7787                                 stop_per = 100 * buffered_total / content_size_bytes;
7788                         }
7789                 } else {
7790                         /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
7791                         guint idx = 0;
7792                         guint num_of_ranges = 0;
7793                         gint64 start_byte = 0, stop_byte = 0;
7794
7795                         gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
7796                         if (estimated_total != STREAMING_IS_FINISHED) {
7797                                 /* buffered size info from queue2 */
7798                                 num_of_ranges = gst_query_get_n_buffering_ranges(query);
7799                                 for (idx = 0; idx < num_of_ranges; idx++) {
7800                                         gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
7801                                         LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
7802
7803                                         buffered_total += (stop_byte - start_byte);
7804                                 }
7805                         } else
7806                                 stop_per = BUFFERING_MAX_PER;
7807                 }
7808                 gst_query_unref(query);
7809         }
7810
7811         if (stop_per == DEFAULT_PER_VALUE) {
7812                 guint dur_sec = (guint)(content_size_time/GST_SECOND);
7813                 if (dur_sec > 0) {
7814                         guint avg_byterate = (guint)(content_size_bytes/dur_sec);
7815
7816                         /* buffered size info from multiqueue */
7817                         if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
7818                                 guint curr_size_bytes = 0;
7819                                 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
7820                                         "curr-size-bytes", &curr_size_bytes, NULL);
7821                                 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
7822                                 buffered_total += curr_size_bytes;
7823                         }
7824
7825                         if (avg_byterate > 0)
7826                                 buffered_sec = (gint)(ceil((gdouble)buffered_total/(gdouble)avg_byterate));
7827                         else if (player->total_maximum_bitrate > 0)
7828                                 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_maximum_bitrate));
7829                         else if (player->total_bitrate > 0)
7830                                 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_bitrate));
7831
7832                         if (buffered_sec >= 0)
7833                                 stop_per = start_per +(gint)(ceil)(100*(gdouble)buffered_sec/(gdouble)dur_sec);
7834                 }
7835         }
7836
7837         *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
7838         *stop_pos = CHECK_PERCENT_VALUE(stop_per, *start_pos, 100);
7839
7840         LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %lu~%lu\n",
7841                 buffered_total, buffered_sec, *start_pos, *stop_pos);
7842
7843         return MM_ERROR_NONE;
7844 }
7845
7846 static int
7847 __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param) // @
7848 {
7849         MMPLAYER_FENTER();
7850
7851         if (!player) {
7852                 LOGW("set_message_callback is called with invalid player handle\n");
7853                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
7854         }
7855
7856         player->msg_cb = callback;
7857         player->msg_cb_param = user_param;
7858
7859         LOGD("msg_cb : %p     msg_cb_param : %p\n", callback, user_param);
7860
7861         MMPLAYER_FLEAVE();
7862
7863         return MM_ERROR_NONE;
7864 }
7865
7866 static int __mmfplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data) // @
7867 {
7868         int ret = MM_ERROR_PLAYER_INVALID_URI;
7869         char *path = NULL;
7870
7871         MMPLAYER_FENTER();
7872
7873         MMPLAYER_RETURN_VAL_IF_FAIL(uri , FALSE);
7874         MMPLAYER_RETURN_VAL_IF_FAIL(data , FALSE);
7875         MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), FALSE);
7876
7877         memset(data, 0, sizeof(MMPlayerParseProfile));
7878
7879         if ((path = strstr(uri, "es_buff://"))) {
7880                 if (strlen(path)) {
7881                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7882                         data->uri_type = MM_PLAYER_URI_TYPE_MS_BUFF;
7883                         ret = MM_ERROR_NONE;
7884                 }
7885         } else if ((path = strstr(uri, "rtsp://"))) {
7886                 if (strlen(path)) {
7887                         if ((path = strstr(uri, "/wfd1.0/"))) {
7888                                 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7889                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_WFD;
7890                                 ret = MM_ERROR_NONE;
7891                                 LOGD("uri is actually a wfd client path. giving it to wfdrtspsrc\n");
7892                         } else {
7893                                 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7894                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7895                                 ret = MM_ERROR_NONE;
7896                         }
7897                 }
7898         } else if ((path = strstr(uri, "http://"))) {
7899                 if (strlen(path)) {
7900                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7901
7902                         if (g_str_has_suffix(g_ascii_strdown(uri, strlen(uri)), ".ism/manifest") ||
7903                                 g_str_has_suffix(g_ascii_strdown(uri, strlen(uri)), ".isml/manifest"))
7904                                 data->uri_type = MM_PLAYER_URI_TYPE_SS;
7905                         else
7906                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
7907
7908                         ret = MM_ERROR_NONE;
7909                 }
7910         } else if ((path = strstr(uri, "https://"))) {
7911                 if (strlen(path)) {
7912                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7913
7914                 if (g_str_has_suffix(g_ascii_strdown(uri, strlen(uri)), ".ism/manifest") ||
7915                                 g_str_has_suffix(g_ascii_strdown(uri, strlen(uri)), ".isml/manifest"))
7916                                 data->uri_type = MM_PLAYER_URI_TYPE_SS;
7917
7918                         data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
7919
7920                         ret = MM_ERROR_NONE;
7921                 }
7922         } else if ((path = strstr(uri, "rtspu://"))) {
7923                 if (strlen(path)) {
7924                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7925                         data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7926                         ret = MM_ERROR_NONE;
7927                 }
7928         } else if ((path = strstr(uri, "rtspr://"))) {
7929                 strncpy(data->uri, path, MM_MAX_URL_LEN-1);
7930                 char *separater = strstr(path, "*");
7931
7932                 if (separater) {
7933                         int urgent_len = 0;
7934                         char *urgent = separater + strlen("*");
7935
7936                         if ((urgent_len = strlen(urgent))) {
7937                                 data->uri[strlen(path) - urgent_len - strlen("*")] = '\0';
7938                                 strncpy(data->urgent, urgent, MM_MAX_FILENAME_LEN-1);
7939                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7940                                 ret = MM_ERROR_NONE;
7941                         }
7942                 }
7943         } else if ((path = strstr(uri, "mms://"))) {
7944                 if (strlen(path)) {
7945                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7946                         data->uri_type = MM_PLAYER_URI_TYPE_URL_MMS;
7947                         ret = MM_ERROR_NONE;
7948                 }
7949         } else if ((path = strstr(uri, "mem://"))) {
7950                 if (strlen(path)) {
7951                         int mem_size = 0;
7952                         char *buffer = NULL;
7953                         char *seperator = strchr(path, ',');
7954                         char ext[100] = {0,}, size[100] = {0,};
7955
7956                         if (seperator) {
7957                                 if ((buffer = strstr(path, "ext="))) {
7958                                         buffer += strlen("ext=");
7959
7960                                         if (strlen(buffer)) {
7961                                                 strncpy(ext, buffer, 99);
7962
7963                                                 if ((seperator = strchr(ext, ','))
7964                                                         || (seperator = strchr(ext, ' '))
7965                                                         || (seperator = strchr(ext, '\0'))) {
7966                                                         seperator[0] = '\0';
7967                                                 }
7968                                         }
7969                                 }
7970
7971                                 if ((buffer = strstr(path, "size="))) {
7972                                         buffer += strlen("size=");
7973
7974                                         if (strlen(buffer) > 0) {
7975                                                 strncpy(size, buffer, 99);
7976
7977                                                 if ((seperator = strchr(size, ','))
7978                                                         || (seperator = strchr(size, ' '))
7979                                                         || (seperator = strchr(size, '\0'))) {
7980                                                         seperator[0] = '\0';
7981                                                 }
7982
7983                                                 mem_size = atoi(size);
7984                                         }
7985                                 }
7986                         }
7987
7988                         LOGD("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
7989                         if (mem_size && param) {
7990                                 data->mem = param;
7991                                 data->mem_size = mem_size;
7992                                 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
7993                                 ret = MM_ERROR_NONE;
7994                         }
7995                 }
7996         } else {
7997                 gchar *location = NULL;
7998                 GError *err = NULL;
7999
8000                 if ((path = strstr(uri, "file://"))) {
8001
8002                         location = g_filename_from_uri(uri, NULL, &err);
8003
8004                         if (!location || (err != NULL)) {
8005                           LOGE("Invalid URI '%s' for filesrc: %s", path,
8006                                  (err != NULL) ? err->message : "unknown error");
8007
8008                           if (err) g_error_free(err);
8009                           if (location) g_free(location);
8010
8011                           data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8012                           goto exit;
8013                         }
8014
8015                         LOGD("path from uri: %s", location);
8016                 }
8017
8018                 path = (location != NULL) ? (location) : ((char*)uri);
8019                 int file_stat = MM_ERROR_NONE;
8020
8021                 file_stat = util_exist_file_path(path);
8022
8023                 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8024                 if (file_stat == MM_ERROR_NONE) {
8025                         g_snprintf(data->uri,  MM_MAX_URL_LEN, "file://%s", path);
8026
8027                         if (util_is_sdp_file(path)) {
8028                                 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
8029                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8030                         } else {
8031                                 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8032                         }
8033                         ret = MM_ERROR_NONE;
8034                 } else if (file_stat == MM_ERROR_PLAYER_PERMISSION_DENIED) {
8035                         data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8036                 } else {
8037                         LOGE("invalid uri, could not play..\n");
8038                         data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8039                 }
8040
8041                 if (location) g_free(location);
8042         }
8043
8044 exit:
8045         if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
8046                 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
8047         else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
8048                 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
8049
8050         /* dump parse result */
8051         SECURE_LOGW("incomming uri : %s\n", uri);
8052         LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n",
8053                 data->uri_type, data->mem, data->mem_size, data->urgent);
8054
8055         MMPLAYER_FLEAVE();
8056
8057         return ret;
8058 }
8059
8060 gboolean _asm_postmsg(gpointer *data)
8061 {
8062         mm_player_t* player = (mm_player_t*)data;
8063         MMMessageParamType msg = {0, };
8064
8065         MMPLAYER_FENTER();
8066         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8067         LOGW("get notified");
8068
8069         if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
8070                 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
8071                 LOGW("dispatched");
8072                 return FALSE;
8073         }
8074
8075
8076         msg.union_type = MM_MSG_UNION_CODE;
8077         msg.code = player->sound_focus.focus_changed_msg;
8078
8079         MMPLAYER_POST_MSG(player, MM_MESSAGE_READY_TO_RESUME, &msg);
8080         player->resume_event_id = 0;
8081
8082         LOGW("dispatched");
8083         return FALSE;
8084 }
8085
8086 gboolean _asm_lazy_pause(gpointer *data)
8087 {
8088         mm_player_t* player = (mm_player_t*)data;
8089         int ret = MM_ERROR_NONE;
8090
8091         MMPLAYER_FENTER();
8092
8093         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8094
8095         if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING) {
8096                 LOGD("Ready to proceed lazy pause\n");
8097                 ret = _mmplayer_pause((MMHandleType)player);
8098                 if (MM_ERROR_NONE != ret)
8099                         LOGE("MMPlayer pause failed in ASM callback lazy pause\n");
8100         } else
8101                 LOGD("Invalid state to proceed lazy pause\n");
8102
8103         /* unset mute */
8104         if (player->pipeline && player->pipeline->audiobin)
8105                 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", 0, NULL);
8106
8107         player->sound_focus.by_asm_cb = FALSE; //should be reset here
8108
8109         MMPLAYER_FLEAVE();
8110
8111         return FALSE;
8112 }
8113
8114 gboolean
8115 __mmplayer_can_do_interrupt(mm_player_t *player)
8116 {
8117         if (!player || !player->pipeline || !player->attrs) {
8118                 LOGW("not initialized");
8119                 goto FAILED;
8120         }
8121
8122         if ((player->sound_focus.exit_cb) || (player->set_mode.pcm_extraction)) {
8123                 LOGW("leave from asm cb right now, %d, %d", player->sound_focus.exit_cb, player->set_mode.pcm_extraction);
8124                 goto FAILED;
8125         }
8126
8127         /* check if seeking */
8128         if (player->doing_seek) {
8129                 MMMessageParamType msg_param;
8130                 memset(&msg_param, 0, sizeof(MMMessageParamType));
8131                 msg_param.code = MM_ERROR_PLAYER_SEEK;
8132                 player->doing_seek = FALSE;
8133                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8134                 goto FAILED;
8135         }
8136
8137         /* check other thread */
8138         if (!MMPLAYER_CMD_TRYLOCK(player)) {
8139                 LOGW("locked already, cmd state : %d", player->cmd);
8140
8141                 /* check application command */
8142                 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
8143                         LOGW("playing.. should wait cmd lock then, will be interrupted");
8144
8145                         /* lock will be released at mrp_resource_release_cb() */
8146                         MMPLAYER_CMD_LOCK(player);
8147                         goto INTERRUPT;
8148                 }
8149                 LOGW("nothing to do");
8150                 goto FAILED;
8151         } else {
8152                 LOGW("can interrupt immediately");
8153                 goto INTERRUPT;
8154         }
8155
8156 FAILED:    /* with CMD UNLOCKED */
8157         return FALSE;
8158
8159 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
8160         return TRUE;
8161 }
8162
8163 /* if you want to enable USE_ASM, please check the history get the ASM cb code. */
8164 static int
8165 __mmplayer_convert_sound_focus_state(gboolean acquire, const char *reason_for_change, MMPlayerFocusChangedMsg *msg)
8166 {
8167         int ret = MM_ERROR_NONE;
8168         MMPlayerFocusChangedMsg focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_UNKNOWN;
8169
8170         if (strstr(reason_for_change, "alarm")) {
8171                 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_ALARM;
8172
8173         } else if (strstr(reason_for_change, "notification")) {
8174                 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_NOTIFICATION;
8175
8176         } else if (strstr(reason_for_change, "emergency")) {
8177                 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_EMERGENCY;
8178
8179         } else if (strstr(reason_for_change, "call-voice") ||
8180                                 strstr(reason_for_change, "call-video") ||
8181                                 strstr(reason_for_change, "voip") ||
8182                                 strstr(reason_for_change, "ringtone-voip") ||
8183                                 strstr(reason_for_change, "ringtone-call")) {
8184                 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_CALL;
8185
8186         } else if (strstr(reason_for_change, "media") ||
8187                                 strstr(reason_for_change, "radio") ||
8188                                 strstr(reason_for_change, "loopback") ||
8189                                 strstr(reason_for_change, "system") ||
8190                                 strstr(reason_for_change, "voice-information") ||
8191                                 strstr(reason_for_change, "voice-recognition")) {
8192                 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_MEDIA;
8193
8194         } else {
8195                 ret = MM_ERROR_INVALID_ARGUMENT;
8196                 LOGW("not supported reason(%s), err(0x%08x)", reason_for_change, ret);
8197                 goto DONE;
8198         }
8199
8200         if (acquire && (focus_msg != MM_PLAYER_FOCUS_CHANGED_BY_MEDIA))
8201                 /* can acqurie */
8202                 focus_msg = MM_PLAYER_FOCUS_CHANGED_COMPLETED;
8203
8204         LOGD("converted from reason(%s) to msg(%d)", reason_for_change, focus_msg);
8205         *msg = focus_msg;
8206
8207 DONE:
8208         return ret;
8209 }
8210
8211 /* FIXME: will be updated with new funct */
8212 void __mmplayer_sound_focus_watch_callback(int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e focus_state,
8213                                        const char *reason_for_change, const char *additional_info, void *user_data)
8214 {
8215         mm_player_t* player = (mm_player_t*) user_data;
8216         int result = MM_ERROR_NONE;
8217         MMPlayerFocusChangedMsg msg = MM_PLAYER_FOCUS_CHANGED_BY_UNKNOWN;
8218
8219         LOGW("focus watch notified");
8220
8221         if (!__mmplayer_can_do_interrupt(player)) {
8222                 LOGW("no need to interrupt, so leave");
8223                 goto EXIT_WITHOUT_UNLOCK;
8224         }
8225
8226         if (player->sound_focus.session_flags & MM_SESSION_OPTION_UNINTERRUPTIBLE) {
8227                 LOGW("flags is UNINTERRUPTIBLE. do nothing.");
8228                 goto EXIT;
8229         }
8230
8231         LOGW("watch: state: %d, focus_type : %d, reason_for_change : %s",
8232                 focus_state, focus_type, (reason_for_change ? reason_for_change : "N/A"));
8233
8234         player->sound_focus.cb_pending = TRUE;
8235         player->sound_focus.by_asm_cb = TRUE;
8236
8237         if (focus_state == FOCUS_IS_ACQUIRED) {
8238                 LOGW("watch: FOCUS_IS_ACQUIRED");
8239                 player->sound_focus.acquired = TRUE;
8240
8241                 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(FALSE, reason_for_change, &msg))
8242                         player->sound_focus.focus_changed_msg = (int)msg;
8243
8244                 if (strstr(reason_for_change, "call") ||
8245                         strstr(reason_for_change, "voip") ||    /* FIXME: to check */
8246                         strstr(reason_for_change, "alarm") ||
8247                         strstr(reason_for_change, "media")) {
8248                         if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
8249                                 // hold 0.7 second to excute "fadedown mute" effect
8250                                 LOGW("do fade down->pause->undo fade down");
8251
8252                                 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
8253
8254                                 result = _mmplayer_pause((MMHandleType)player);
8255                                 if (result != MM_ERROR_NONE) {
8256                                         LOGW("fail to set Pause state by asm");
8257                                         goto EXIT;
8258                                 }
8259                                 __mmplayer_undo_sound_fadedown(player);
8260                         } else
8261                                 /* rtsp should connect again in specific network becasue tcp session can't be kept any more */
8262                                 _mmplayer_unrealize((MMHandleType)player);
8263                 } else {
8264                         LOGW("pause immediately");
8265                         result = _mmplayer_pause((MMHandleType)player);
8266                         if (result != MM_ERROR_NONE) {
8267                                 LOGW("fail to set Pause state by asm");
8268                                 goto EXIT;
8269                         }
8270                 }
8271         } else if (focus_state == FOCUS_IS_RELEASED) {
8272                 LOGW("FOCUS_IS_RELEASED: Got msg from asm to resume");
8273                 player->sound_focus.acquired = FALSE;
8274                 player->sound_focus.antishock = TRUE;
8275                 player->sound_focus.by_asm_cb = FALSE;
8276
8277                 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(TRUE, reason_for_change, &msg))
8278                         player->sound_focus.focus_changed_msg = (int)msg;
8279
8280                 //ASM server is single thread daemon. So use g_idle_add() to post resume msg
8281                 player->resume_event_id = g_idle_add((GSourceFunc)_asm_postmsg, (gpointer)player);
8282                 goto DONE;
8283         } else
8284                 LOGW("unknown focus state %d", focus_state);
8285
8286 DONE:
8287         player->sound_focus.by_asm_cb = FALSE;
8288         player->sound_focus.cb_pending = FALSE;
8289
8290 EXIT:
8291         MMPLAYER_CMD_UNLOCK(player);
8292         LOGW("dispatched");
8293         return;
8294
8295 EXIT_WITHOUT_UNLOCK:
8296         LOGW("dispatched");
8297         return;
8298 }
8299
8300 void
8301 __mmplayer_sound_focus_callback(int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e focus_state,
8302         const char *reason_for_change, int option, const char *additional_info, void *user_data)
8303 {
8304         mm_player_t* player = (mm_player_t*) user_data;
8305         int result = MM_ERROR_NONE;
8306         MMPlayerFocusChangedMsg msg = MM_PLAYER_FOCUS_CHANGED_BY_UNKNOWN;
8307
8308         LOGW("get focus notified");
8309
8310         if (!__mmplayer_can_do_interrupt(player)) {
8311                 LOGW("no need to interrupt, so leave");
8312                 goto EXIT_WITHOUT_UNLOCK;
8313         }
8314
8315         if (player->sound_focus.session_flags & MM_SESSION_OPTION_UNINTERRUPTIBLE) {
8316                 LOGW("flags is UNINTERRUPTIBLE. do nothing.");
8317                 goto EXIT;
8318         }
8319
8320         LOGW("state: %d, focus_type : %d, reason_for_change : %s",
8321                 focus_state, focus_type, (reason_for_change ? reason_for_change : "N/A"));
8322
8323         player->sound_focus.cb_pending = TRUE;
8324         player->sound_focus.by_asm_cb = TRUE;
8325 //      player->sound_focus.event_src = event_src;
8326
8327         if (focus_state == FOCUS_IS_RELEASED) {
8328                 LOGW("FOCUS_IS_RELEASED");
8329                 player->sound_focus.acquired = FALSE;
8330
8331                 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(FALSE, reason_for_change, &msg))
8332                         player->sound_focus.focus_changed_msg = (int)msg;
8333
8334                 if (strstr(reason_for_change, "call") ||
8335                         strstr(reason_for_change, "voip") ||    /* FIXME: to check */
8336                         strstr(reason_for_change, "alarm") ||
8337                         strstr(reason_for_change, "media")) {
8338                         if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
8339                                 //hold 0.7 second to excute "fadedown mute" effect
8340                                 LOGW("do fade down->pause->undo fade down");
8341
8342                                 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
8343
8344                                 result = _mmplayer_pause((MMHandleType)player);
8345                                 if (result != MM_ERROR_NONE) {
8346                                         LOGW("fail to set Pause state by asm");
8347                                         goto EXIT;
8348                                 }
8349                                 __mmplayer_undo_sound_fadedown(player);
8350                         } else
8351                                 /* rtsp should connect again in specific network becasue tcp session can't be kept any more */
8352                                 _mmplayer_unrealize((MMHandleType)player);
8353                 } else {
8354                         LOGW("pause immediately");
8355                         result = _mmplayer_pause((MMHandleType)player);
8356                         if (result != MM_ERROR_NONE) {
8357                                 LOGW("fail to set Pause state by asm");
8358                                 goto EXIT;
8359                         }
8360                 }
8361         } else if (focus_state == FOCUS_IS_ACQUIRED) {
8362                 LOGW("FOCUS_IS_ACQUIRED: Got msg from asm to resume");
8363                 player->sound_focus.acquired = TRUE;
8364                 player->sound_focus.antishock = TRUE;
8365                 player->sound_focus.by_asm_cb = FALSE;
8366
8367                 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(TRUE, reason_for_change, &msg))
8368                         player->sound_focus.focus_changed_msg = (int)msg;
8369
8370                 //ASM server is single thread daemon. So use g_idle_add() to post resume msg
8371                 player->resume_event_id = g_idle_add((GSourceFunc)_asm_postmsg, (gpointer)player);
8372                 goto DONE;
8373         } else
8374                 LOGW("unknown focus state %d", focus_state);
8375
8376 DONE:
8377         player->sound_focus.by_asm_cb = FALSE;
8378         player->sound_focus.cb_pending = FALSE;
8379
8380 EXIT:
8381         MMPLAYER_CMD_UNLOCK(player);
8382         LOGW("dispatched");
8383         return;
8384
8385 EXIT_WITHOUT_UNLOCK:
8386         LOGW("dispatched");
8387         return;
8388 }
8389
8390
8391 int
8392 _mmplayer_create_player(MMHandleType handle) // @
8393 {
8394         int ret = MM_ERROR_PLAYER_INTERNAL;
8395         mm_player_t* player = MM_PLAYER_CAST(handle);
8396
8397         MMPLAYER_FENTER();
8398
8399         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8400
8401         /* initialize player state */
8402         MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
8403         MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
8404         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
8405         MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
8406
8407         /* check current state */
8408         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
8409
8410         /* construct attributes */
8411         player->attrs = _mmplayer_construct_attribute(handle);
8412
8413         if (!player->attrs) {
8414                 LOGE("Failed to construct attributes\n");
8415                 return ret;
8416         }
8417
8418         /* initialize gstreamer with configured parameter */
8419         if (!__mmplayer_init_gstreamer(player)) {
8420                 LOGE("Initializing gstreamer failed\n");
8421                 _mmplayer_deconstruct_attribute(handle);
8422                 return ret;
8423         }
8424
8425         /* initialize factories if not using decodebin */
8426         if (player->factories == NULL)
8427                 __mmplayer_init_factories(player);
8428
8429         /* create lock. note that g_tread_init() has already called in gst_init() */
8430         g_mutex_init(&player->fsink_lock);
8431
8432         /* create update tag lock */
8433         g_mutex_init(&player->update_tag_lock);
8434
8435         /* create repeat mutex */
8436         g_mutex_init(&player->repeat_thread_mutex);
8437
8438         /* create repeat cond */
8439         g_cond_init(&player->repeat_thread_cond);
8440
8441         /* create repeat thread */
8442         player->repeat_thread =
8443                 g_thread_try_new("repeat_thread", __mmplayer_repeat_thread, (gpointer)player, NULL);
8444         if (!player->repeat_thread) {
8445                 LOGE("failed to create repeat_thread(%s)");
8446                 g_mutex_clear(&player->repeat_thread_mutex);
8447                 g_cond_clear(&player->repeat_thread_cond);
8448                 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8449                 goto ERROR;
8450         }
8451
8452         /* create next play mutex */
8453         g_mutex_init(&player->next_play_thread_mutex);
8454
8455         /* create next play cond */
8456         g_cond_init(&player->next_play_thread_cond);
8457
8458         /* create next play thread */
8459         player->next_play_thread =
8460                 g_thread_try_new("next_play_thread", __mmplayer_next_play_thread, (gpointer)player, NULL);
8461         if (!player->next_play_thread) {
8462                 LOGE("failed to create next play thread");
8463                 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8464                 g_mutex_clear(&player->next_play_thread_mutex);
8465                 g_cond_clear(&player->next_play_thread_cond);
8466                 goto ERROR;
8467         }
8468
8469         ret = _mmplayer_initialize_video_capture(player);
8470         if (ret != MM_ERROR_NONE) {
8471                 LOGE("failed to initialize video capture\n");
8472                 goto ERROR;
8473         }
8474
8475         /* initialize resource manager */
8476         if (MM_ERROR_NONE != _mmplayer_resource_manager_init(&player->resource_manager, player)) {
8477                 LOGE("failed to initialize resource manager\n");
8478                 goto ERROR;
8479         }
8480
8481         if (MMPLAYER_IS_HTTP_PD(player)) {
8482                 player->pd_downloader = NULL;
8483                 player->pd_file_save_path = NULL;
8484         }
8485
8486         /* create video bo lock and cond */
8487         g_mutex_init(&player->video_bo_mutex);
8488         g_cond_init(&player->video_bo_cond);
8489
8490         /* create media stream callback mutex */
8491         g_mutex_init(&player->media_stream_cb_lock);
8492
8493         player->streaming_type = STREAMING_SERVICE_NONE;
8494
8495         /* give default value of audio effect setting */
8496         player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
8497         player->playback_rate = DEFAULT_PLAYBACK_RATE;
8498
8499         player->play_subtitle = FALSE;
8500         player->use_textoverlay = FALSE;
8501         player->play_count = 0;
8502         player->use_decodebin = TRUE;
8503         player->ignore_asyncdone = FALSE;
8504         player->use_deinterleave = FALSE;
8505         player->max_audio_channels = 0;
8506         player->video_share_api_delta = 0;
8507         player->video_share_clock_delta = 0;
8508         player->has_closed_caption = FALSE;
8509         player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8510         player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8511         player->pending_resume = FALSE;
8512         if (player->ini.dump_element_keyword[0][0] == '\0')
8513                 player->ini.set_dump_element_flag = FALSE;
8514         else
8515                 player->ini.set_dump_element_flag = TRUE;
8516
8517         /* set player state to null */
8518         MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8519         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
8520
8521         return MM_ERROR_NONE;
8522
8523 ERROR:
8524         /* free lock */
8525         g_mutex_clear(&player->fsink_lock);
8526
8527         /* free update tag lock */
8528         g_mutex_clear(&player->update_tag_lock);
8529
8530         /* free thread */
8531         if (player->repeat_thread) {
8532                 player->repeat_thread_exit = TRUE;
8533                 MMPLAYER_REPEAT_THREAD_SIGNAL(player);
8534
8535                 g_thread_join(player->repeat_thread);
8536                 player->repeat_thread = NULL;
8537
8538                 g_mutex_clear(&player->repeat_thread_mutex);
8539                 g_cond_clear(&player->repeat_thread_cond);
8540         }
8541
8542         /* free next play thread */
8543         if (player->next_play_thread) {
8544                 player->next_play_thread_exit = TRUE;
8545                 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8546
8547                 g_thread_join(player->next_play_thread);
8548                 player->next_play_thread = NULL;
8549
8550                 g_mutex_clear(&player->next_play_thread_mutex);
8551                 g_cond_clear(&player->next_play_thread_cond);
8552         }
8553
8554         /* release attributes */
8555         _mmplayer_deconstruct_attribute(handle);
8556
8557         MMPLAYER_FLEAVE();
8558
8559         return ret;
8560 }
8561
8562 static gboolean
8563 __mmplayer_init_gstreamer(mm_player_t* player) // @
8564 {
8565         static gboolean initialized = FALSE;
8566         static const int max_argc = 50;
8567         gint* argc = NULL;
8568         gchar** argv = NULL;
8569         gchar** argv2 = NULL;
8570         GError *err = NULL;
8571         int i = 0;
8572         int arg_count = 0;
8573
8574         if (initialized) {
8575                 LOGD("gstreamer already initialized.\n");
8576                 return TRUE;
8577         }
8578
8579         /* alloc */
8580         argc = malloc(sizeof(int));
8581         argv = malloc(sizeof(gchar*) * max_argc);
8582         argv2 = malloc(sizeof(gchar*) * max_argc);
8583
8584         if (!argc || !argv || !argv2)
8585                 goto ERROR;
8586
8587         memset(argv, 0, sizeof(gchar*) * max_argc);
8588         memset(argv2, 0, sizeof(gchar*) * max_argc);
8589
8590         /* add initial */
8591         *argc = 1;
8592         argv[0] = g_strdup("mmplayer");
8593
8594         /* add gst_param */
8595         for (i = 0; i < 5; i++) {
8596                 /* FIXIT : num of param is now fixed to 5. make it dynamic */
8597                 if (strlen(player->ini.gst_param[i]) > 0) {
8598                         argv[*argc] = g_strdup(player->ini.gst_param[i]);
8599                         (*argc)++;
8600                 }
8601         }
8602
8603         /* we would not do fork for scanning plugins */
8604         argv[*argc] = g_strdup("--gst-disable-registry-fork");
8605         (*argc)++;
8606
8607         /* check disable registry scan */
8608         if (player->ini.skip_rescan) {
8609                 argv[*argc] = g_strdup("--gst-disable-registry-update");
8610                 (*argc)++;
8611         }
8612
8613         /* check disable segtrap */
8614         if (player->ini.disable_segtrap) {
8615                 argv[*argc] = g_strdup("--gst-disable-segtrap");
8616                 (*argc)++;
8617         }
8618
8619         LOGD("initializing gstreamer with following parameter\n");
8620         LOGD("argc : %d\n", *argc);
8621         arg_count = *argc;
8622
8623         for (i = 0; i < arg_count; i++) {
8624                 argv2[i] = argv[i];
8625                 LOGD("argv[%d] : %s\n", i, argv2[i]);
8626         }
8627
8628
8629         /* initializing gstreamer */
8630         if (!gst_init_check(argc, &argv, &err)) {
8631                 LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
8632                 if (err)
8633                         g_error_free(err);
8634
8635                 goto ERROR;
8636         }
8637         /* release */
8638         for (i = 0; i < arg_count; i++) {
8639                 //LOGD("release - argv[%d] : %s\n", i, argv2[i]);
8640                 MMPLAYER_FREEIF(argv2[i]);
8641         }
8642
8643         MMPLAYER_FREEIF(argv);
8644         MMPLAYER_FREEIF(argv2);
8645         MMPLAYER_FREEIF(argc);
8646
8647         /* done */
8648         initialized = TRUE;
8649
8650         return TRUE;
8651
8652 ERROR:
8653
8654         /* release */
8655         for (i = 0; i < arg_count; i++) {
8656                 LOGD("free[%d] : %s\n", i, argv2[i]);
8657                 MMPLAYER_FREEIF(argv2[i]);
8658         }
8659
8660         MMPLAYER_FREEIF(argv);
8661         MMPLAYER_FREEIF(argv2);
8662         MMPLAYER_FREEIF(argc);
8663
8664         return FALSE;
8665 }
8666
8667 int
8668 __mmplayer_destroy_streaming_ext(mm_player_t* player)
8669 {
8670         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8671
8672         if (player->pd_downloader) {
8673                 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
8674                 MMPLAYER_FREEIF(player->pd_downloader);
8675         }
8676
8677         if (MMPLAYER_IS_HTTP_PD(player)) {
8678                 _mmplayer_destroy_pd_downloader((MMHandleType)player);
8679                 MMPLAYER_FREEIF(player->pd_file_save_path);
8680         }
8681
8682         return MM_ERROR_NONE;
8683 }
8684
8685 static void
8686 __mmplayer_check_async_state_transition(mm_player_t* player)
8687 {
8688         GstState element_state = GST_STATE_VOID_PENDING;
8689         GstState element_pending_state = GST_STATE_VOID_PENDING;
8690         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8691         GstElement * element = NULL;
8692         gboolean async = FALSE;
8693
8694         /* check player handle */
8695         MMPLAYER_RETURN_IF_FAIL(player &&
8696                                                 player->pipeline &&
8697                                                 player->pipeline->mainbin &&
8698                                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8699
8700         if (player->attrs)
8701                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
8702
8703         if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
8704                 LOGD("don't need to check the pipeline state");
8705                 return;
8706         }
8707
8708         MMPLAYER_PRINT_STATE(player);
8709
8710         /* wait for state transition */
8711         element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
8712         ret = gst_element_get_state(element, &element_state, &element_pending_state, 1*GST_SECOND);
8713
8714         if (ret == GST_STATE_CHANGE_FAILURE) {
8715                 LOGE(" [%s] state : %s   pending : %s \n",
8716                         GST_ELEMENT_NAME(element),
8717                         gst_element_state_get_name(element_state),
8718                         gst_element_state_get_name(element_pending_state));
8719
8720                 /* dump state of all element */
8721                 __mmplayer_dump_pipeline_state(player);
8722
8723                 return;
8724         }
8725
8726         LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
8727         return;
8728 }
8729
8730 int
8731 _mmplayer_destroy(MMHandleType handle) // @
8732 {
8733         mm_player_t* player = MM_PLAYER_CAST(handle);
8734
8735         MMPLAYER_FENTER();
8736
8737         /* check player handle */
8738         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8739
8740         /* destroy can called at anytime */
8741         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
8742
8743         /* check async state transition */
8744         __mmplayer_check_async_state_transition(player);
8745
8746         __mmplayer_destroy_streaming_ext(player);
8747
8748         /* release repeat thread */
8749         if (player->repeat_thread) {
8750                 player->repeat_thread_exit = TRUE;
8751                 MMPLAYER_REPEAT_THREAD_SIGNAL(player);
8752
8753                 LOGD("waitting for repeat thread exit\n");
8754                 g_thread_join(player->repeat_thread);
8755                 g_mutex_clear(&player->repeat_thread_mutex);
8756                 g_cond_clear(&player->repeat_thread_cond);
8757                 LOGD("repeat thread released\n");
8758         }
8759
8760         /* release next play thread */
8761         if (player->next_play_thread) {
8762                 player->next_play_thread_exit = TRUE;
8763                 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8764
8765                 LOGD("waitting for next play thread exit\n");
8766                 g_thread_join(player->next_play_thread);
8767                 g_mutex_clear(&player->next_play_thread_mutex);
8768                 g_cond_clear(&player->next_play_thread_cond);
8769                 LOGD("next play thread released\n");
8770         }
8771
8772         _mmplayer_release_video_capture(player);
8773
8774         /* flush any pending asm_cb */
8775         if (player->sound_focus.cb_pending) {
8776                 /* set a flag for make sure asm_cb to be returned immediately */
8777                 LOGW("asm cb has pending state");
8778                 player->sound_focus.exit_cb = TRUE;
8779
8780                 /* make sure to release any pending asm_cb which locked by cmd_lock */
8781                 MMPLAYER_CMD_UNLOCK(player);
8782                 sched_yield();
8783                 MMPLAYER_CMD_LOCK(player);
8784         }
8785
8786         /* withdraw asm */
8787         if (MM_ERROR_NONE != _mmplayer_sound_unregister(&player->sound_focus))
8788                 LOGE("failed to deregister asm server\n");
8789
8790         /* de-initialize resource manager */
8791         if (MM_ERROR_NONE != _mmplayer_resource_manager_deinit(&player->resource_manager))
8792                 LOGE("failed to deinitialize resource manager\n");
8793
8794 #ifdef USE_LAZY_PAUSE
8795         if (player->lazy_pause_event_id) {
8796                 __mmplayer_remove_g_source_from_context(player->context.global_default, player->lazy_pause_event_id);
8797                 player->lazy_pause_event_id = 0;
8798         }
8799 #endif
8800
8801         if (player->resume_event_id) {
8802                 g_source_remove(player->resume_event_id);
8803                 player->resume_event_id = 0;
8804         }
8805
8806         if (player->resumable_cancel_id) {
8807                 g_source_remove(player->resumable_cancel_id);
8808                 player->resumable_cancel_id = 0;
8809         }
8810
8811         /* release pipeline */
8812         if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
8813                 LOGE("failed to destory pipeline\n");
8814                 return MM_ERROR_PLAYER_INTERNAL;
8815         }
8816
8817         if (player->is_external_subtitle_present && player->subtitle_language_list) {
8818           g_list_free(player->subtitle_language_list);
8819           player->subtitle_language_list = NULL;
8820         }
8821
8822         __mmplayer_release_dump_list(player->dump_list);
8823
8824         /* release miscellaneous information.
8825            these info needs to be released after pipeline is destroyed. */
8826         __mmplayer_release_misc_post(player);
8827
8828         /* release attributes */
8829         _mmplayer_deconstruct_attribute(handle);
8830
8831         /* release factories */
8832         __mmplayer_release_factories(player);
8833
8834         /* release lock */
8835         g_mutex_clear(&player->fsink_lock);
8836
8837         /* release lock */
8838         g_mutex_clear(&player->update_tag_lock);
8839
8840         /* release video bo lock and cond */
8841         g_mutex_clear(&player->video_bo_mutex);
8842         g_cond_clear(&player->video_bo_cond);
8843
8844         /* release media stream callback lock */
8845         g_mutex_clear(&player->media_stream_cb_lock);
8846
8847         MMPLAYER_FLEAVE();
8848
8849         return MM_ERROR_NONE;
8850 }
8851
8852 int
8853 __mmplayer_realize_streaming_ext(mm_player_t* player)
8854 {
8855         int ret = MM_ERROR_NONE;
8856
8857         MMPLAYER_FENTER();
8858         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8859
8860         if (MMPLAYER_IS_HTTP_PD(player)) {
8861                 gboolean bret = FALSE;
8862
8863                 player->pd_downloader = _mmplayer_create_pd_downloader();
8864                 if (!player->pd_downloader) {
8865                         LOGE("Unable to create PD Downloader...");
8866                         ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
8867                 }
8868
8869                 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
8870
8871                 if (FALSE == bret) {
8872                         LOGE("Unable to create PD Downloader...");
8873                         ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
8874                 }
8875         }
8876
8877         MMPLAYER_FLEAVE();
8878         return ret;
8879 }
8880
8881 int
8882 _mmplayer_sound_register_with_pid(MMHandleType hplayer, int pid) // @
8883 {
8884         mm_player_t* player = (mm_player_t*)hplayer;
8885         MMHandleType attrs = 0;
8886         int ret = MM_ERROR_NONE;
8887
8888         attrs = MMPLAYER_GET_ATTRS(player);
8889         if (!attrs) {
8890                 LOGE("fail to get attributes.\n");
8891                 return MM_ERROR_PLAYER_INTERNAL;
8892         }
8893
8894         player->sound_focus.pid = pid;
8895
8896         /* register to asm */
8897         if (MM_ERROR_NONE != _mmplayer_sound_register(&player->sound_focus,
8898                                                 (mm_sound_focus_changed_cb)__mmplayer_sound_focus_callback,
8899                                                 (mm_sound_focus_changed_watch_cb)__mmplayer_sound_focus_watch_callback,
8900                                                 (void*)player)) {
8901                 /* NOTE : we are dealing it as an error since we cannot expect it's behavior */
8902                 LOGE("failed to register asm server\n");
8903                 return MM_ERROR_POLICY_INTERNAL;
8904         }
8905         return ret;
8906 }
8907
8908 int
8909 _mmplayer_get_client_pid(MMHandleType hplayer, int* pid)
8910 {
8911         mm_player_t* player = (mm_player_t*) hplayer;
8912
8913         MMPLAYER_FENTER();
8914
8915         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8916
8917         *pid = player->sound_focus.pid;
8918
8919         LOGD("registered pid[%d] %p", *pid, player);
8920
8921         MMPLAYER_FLEAVE();
8922
8923         return MM_ERROR_NONE;
8924 }
8925
8926 int
8927 _mmplayer_realize(MMHandleType hplayer) // @
8928 {
8929         mm_player_t* player = (mm_player_t*)hplayer;
8930         char *uri = NULL;
8931         void *param = NULL;
8932         gboolean update_registry = FALSE;
8933         MMHandleType attrs = 0;
8934         int ret = MM_ERROR_NONE;
8935
8936         MMPLAYER_FENTER();
8937
8938         /* check player handle */
8939         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED)
8940
8941         /* check current state */
8942         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
8943
8944         attrs = MMPLAYER_GET_ATTRS(player);
8945         if (!attrs) {
8946                 LOGE("fail to get attributes.\n");
8947                 return MM_ERROR_PLAYER_INTERNAL;
8948         }
8949         mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
8950         mm_attrs_get_data_by_name(attrs, "profile_user_param", &param);
8951
8952         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
8953                 ret = __mmfplayer_parse_profile((const char*)uri, param, &player->profile);
8954
8955                 if (ret != MM_ERROR_NONE) {
8956                         LOGE("failed to parse profile\n");
8957                         return ret;
8958                 }
8959         }
8960
8961         /* FIXIT : we can use thouse in player->profile directly */
8962         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM) {
8963                 player->mem_buf.buf = (char *)player->profile.mem;
8964                 player->mem_buf.len = player->profile.mem_size;
8965                 player->mem_buf.offset = 0;
8966         }
8967
8968         if (uri && (strstr(uri, "es_buff://"))) {
8969                 if (strstr(uri, "es_buff://push_mode"))
8970                         player->es_player_push_mode = TRUE;
8971                 else
8972                         player->es_player_push_mode = FALSE;
8973         }
8974
8975         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
8976                 LOGW("mms protocol is not supported format.\n");
8977                 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
8978         }
8979
8980         if (MMPLAYER_IS_STREAMING(player))
8981                 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
8982         else
8983                 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8984
8985         player->smooth_streaming = FALSE;
8986         player->videodec_linked  = 0;
8987         player->videosink_linked = 0;
8988         player->audiodec_linked  = 0;
8989         player->audiosink_linked = 0;
8990         player->textsink_linked = 0;
8991         player->is_external_subtitle_present = FALSE;
8992         player->is_external_subtitle_added_now = FALSE;
8993         /* set the subtitle ON default */
8994         player->is_subtitle_off = FALSE;
8995
8996         /* registry should be updated for downloadable codec */
8997         mm_attrs_get_int_by_name(attrs, "profile_update_registry", &update_registry);
8998
8999         if (update_registry) {
9000                 LOGD("updating registry...\n");
9001                 gst_update_registry();
9002
9003                 /* then we have to rebuild factories */
9004                 __mmplayer_release_factories(player);
9005                 __mmplayer_init_factories(player);
9006         }
9007
9008         /* realize pipeline */
9009         ret = __gst_realize(player);
9010         if (ret != MM_ERROR_NONE)
9011                 LOGE("fail to realize the player.\n");
9012         else
9013                 ret = __mmplayer_realize_streaming_ext(player);
9014
9015         MMPLAYER_FLEAVE();
9016
9017         return ret;
9018 }
9019
9020 int
9021 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
9022 {
9023         MMPLAYER_FENTER();
9024         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9025
9026         /* destroy can called at anytime */
9027         if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player)) {
9028                 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
9029                 MMPLAYER_FREEIF(player->pd_downloader);
9030         }
9031
9032         MMPLAYER_FLEAVE();
9033         return MM_ERROR_NONE;
9034 }
9035
9036 int
9037 _mmplayer_unrealize(MMHandleType hplayer)
9038 {
9039         mm_player_t* player = (mm_player_t*)hplayer;
9040         MMPlayerResourceState resource_state = RESOURCE_STATE_NONE;
9041         int ret = MM_ERROR_NONE;
9042
9043         MMPLAYER_FENTER();
9044
9045         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED)
9046
9047         /* check current state */
9048         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
9049
9050         /* check async state transition */
9051         __mmplayer_check_async_state_transition(player);
9052
9053         __mmplayer_unrealize_streaming_ext(player);
9054
9055         /* unrealize pipeline */
9056         ret = __gst_unrealize(player);
9057
9058         /* set asm stop if success */
9059         if (MM_ERROR_NONE == ret) {
9060                 ret = _mmplayer_sound_release_focus(&player->sound_focus);
9061                 if (ret != MM_ERROR_NONE)
9062                         LOGE("failed to release sound focus, ret(0x%x)\n", ret);
9063
9064                 if (!player->resource_manager.by_rm_cb &&
9065                         _mmplayer_resource_manager_get_state(&player->resource_manager, &resource_state) == MM_ERROR_NONE) {
9066                         if (resource_state >= RESOURCE_STATE_ACQUIRED) {
9067                                 ret = _mmplayer_resource_manager_release(&player->resource_manager);
9068                                 if (ret != MM_ERROR_NONE)
9069                                         LOGE("failed to release resource, ret(0x%x)\n", ret);
9070                         }
9071                 }
9072
9073                 if (_mmplayer_resource_manager_get_state(&player->resource_manager, &resource_state) == MM_ERROR_NONE) {
9074                         if (resource_state == RESOURCE_STATE_PREPARED) {
9075                                 ret = _mmplayer_resource_manager_unprepare(&player->resource_manager);
9076                                 if (ret != MM_ERROR_NONE)
9077                                         LOGE("failed to unprepare resource, ret(0x%x)\n", ret);
9078                         }
9079                 }
9080         } else
9081                 LOGE("failed and don't change asm state to stop");
9082
9083         MMPLAYER_FLEAVE();
9084
9085         return ret;
9086 }
9087
9088 int
9089 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param) // @
9090 {
9091         mm_player_t* player = (mm_player_t*)hplayer;
9092
9093         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9094
9095         return __gst_set_message_callback(player, callback, user_param);
9096 }
9097
9098 int
9099 _mmplayer_get_state(MMHandleType hplayer, int* state) // @
9100 {
9101         mm_player_t *player = (mm_player_t*)hplayer;
9102
9103         MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
9104
9105         *state = MMPLAYER_CURRENT_STATE(player);
9106
9107         return MM_ERROR_NONE;
9108 }
9109
9110
9111 int
9112 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume) // @
9113 {
9114         mm_player_t* player = (mm_player_t*) hplayer;
9115         GstElement* vol_element = NULL;
9116         int i = 0;
9117
9118         MMPLAYER_FENTER();
9119
9120         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9121
9122         LOGD("volume [L]=%f:[R]=%f\n",
9123                 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
9124
9125         /* invalid factor range or not */
9126         for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
9127                 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
9128                         LOGE("Invalid factor!(valid factor:0~1.0)\n");
9129                         return MM_ERROR_INVALID_ARGUMENT;
9130                 }
9131         }
9132
9133         /* not support to set other value into each channel */
9134         if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
9135                 return MM_ERROR_INVALID_ARGUMENT;
9136
9137         /* Save volume to handle. Currently the first array element will be saved. */
9138         player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
9139
9140         /* check pipeline handle */
9141         if (!player->pipeline || !player->pipeline->audiobin) {
9142                 LOGD("audiobin is not created yet\n");
9143                 LOGD("but, current stored volume will be set when it's created.\n");
9144
9145                 /* NOTE : stored volume will be used in create_audiobin
9146                  * returning MM_ERROR_NONE here makes application to able to
9147                  * set volume at anytime.
9148                  */
9149                 return MM_ERROR_NONE;
9150         }
9151
9152         /* setting volume to volume element */
9153         vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
9154
9155         if (vol_element) {
9156                 LOGD("volume is set [%f]\n", player->sound.volume);
9157                 g_object_set(vol_element, "volume", player->sound.volume, NULL);
9158         }
9159
9160         MMPLAYER_FLEAVE();
9161
9162         return MM_ERROR_NONE;
9163 }
9164
9165
9166 int
9167 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
9168 {
9169         mm_player_t* player = (mm_player_t*) hplayer;
9170         int i = 0;
9171
9172         MMPLAYER_FENTER();
9173
9174         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9175         MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
9176
9177         /* returning stored volume */
9178         for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
9179                 volume->level[i] = player->sound.volume;
9180
9181         MMPLAYER_FLEAVE();
9182
9183         return MM_ERROR_NONE;
9184 }
9185
9186
9187
9188 int
9189 _mmplayer_set_mute(MMHandleType hplayer, int mute) // @
9190 {
9191         mm_player_t* player = (mm_player_t*) hplayer;
9192         GstElement* vol_element = NULL;
9193
9194         MMPLAYER_FENTER();
9195
9196         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9197
9198         /* mute value shoud 0 or 1 */
9199         if (mute != 0 && mute != 1) {
9200                 LOGE("bad mute value\n");
9201
9202                 /* FIXIT : definitly, we need _BAD_PARAM error code */
9203                 return MM_ERROR_INVALID_ARGUMENT;
9204         }
9205
9206         player->sound.mute = mute;
9207
9208         /* just hold mute value if pipeline is not ready */
9209         if (!player->pipeline || !player->pipeline->audiobin) {
9210                 LOGD("pipeline is not ready. holding mute value\n");
9211                 return MM_ERROR_NONE;
9212         }
9213
9214         vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
9215
9216         /* NOTE : volume will only created when the bt is enabled */
9217         if (vol_element) {
9218                 LOGD("mute : %d\n", mute);
9219                 g_object_set(vol_element, "mute", mute, NULL);
9220         } else
9221                 LOGD("volume elemnet is not created. using volume in audiosink\n");
9222
9223         MMPLAYER_FLEAVE();
9224
9225         return MM_ERROR_NONE;
9226 }
9227
9228 int
9229 _mmplayer_get_mute(MMHandleType hplayer, int* pmute) // @
9230 {
9231         mm_player_t* player = (mm_player_t*) hplayer;
9232
9233         MMPLAYER_FENTER();
9234
9235         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9236         MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
9237
9238         /* just hold mute value if pipeline is not ready */
9239         if (!player->pipeline || !player->pipeline->audiobin) {
9240                 LOGD("pipeline is not ready. returning stored value\n");
9241                 *pmute = player->sound.mute;
9242                 return MM_ERROR_NONE;
9243         }
9244
9245         *pmute = player->sound.mute;
9246
9247         MMPLAYER_FLEAVE();
9248
9249         return MM_ERROR_NONE;
9250 }
9251
9252 int
9253 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
9254 {
9255         mm_player_t* player = (mm_player_t*) hplayer;
9256
9257         MMPLAYER_FENTER();
9258
9259         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9260
9261         player->video_stream_changed_cb = callback;
9262         player->video_stream_changed_cb_user_param = user_param;
9263         LOGD("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
9264
9265         MMPLAYER_FLEAVE();
9266
9267         return MM_ERROR_NONE;
9268 }
9269
9270 int
9271 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
9272 {
9273         mm_player_t* player = (mm_player_t*) hplayer;
9274
9275         MMPLAYER_FENTER();
9276
9277         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9278
9279         player->audio_stream_changed_cb = callback;
9280         player->audio_stream_changed_cb_user_param = user_param;
9281         LOGD("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
9282
9283         MMPLAYER_FLEAVE();
9284
9285         return MM_ERROR_NONE;
9286 }
9287
9288 int
9289 _mmplayer_set_audiostream_cb_ex(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback_ex callback, void *user_param) // @
9290 {
9291         mm_player_t* player = (mm_player_t*) hplayer;
9292
9293         MMPLAYER_FENTER();
9294
9295         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9296
9297         player->audio_stream_render_cb_ex = callback;
9298         player->audio_stream_cb_user_param = user_param;
9299         player->audio_stream_sink_sync = sync;
9300         LOGD("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);
9301
9302         MMPLAYER_FLEAVE();
9303
9304         return MM_ERROR_NONE;
9305 }
9306
9307 int
9308 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param) // @
9309 {
9310         mm_player_t* player = (mm_player_t*) hplayer;
9311
9312         MMPLAYER_FENTER();
9313
9314         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9315
9316         if (callback && !player->bufmgr)
9317                 player->bufmgr = tbm_bufmgr_init(-1);
9318
9319         player->set_mode.media_packet_video_stream = (callback) ? TRUE : FALSE;
9320         player->video_stream_cb = callback;
9321         player->video_stream_cb_user_param = user_param;
9322
9323         LOGD("Stream cb Handle value is %p : %p, enable:%d\n", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
9324
9325         MMPLAYER_FLEAVE();
9326
9327         return MM_ERROR_NONE;
9328 }
9329
9330 int
9331 _mmplayer_set_audiostream_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param) // @
9332 {
9333         mm_player_t* player = (mm_player_t*) hplayer;
9334
9335         MMPLAYER_FENTER();
9336
9337         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9338
9339         player->audio_stream_cb = callback;
9340         player->audio_stream_cb_user_param = user_param;
9341         LOGD("Audio Stream cb Handle value is %p : %p\n", player, player->audio_stream_cb);
9342
9343         MMPLAYER_FLEAVE();
9344
9345         return MM_ERROR_NONE;
9346 }
9347
9348 // set prepare size
9349 int
9350 _mmplayer_set_prepare_buffering_time(MMHandleType hplayer, int second)
9351 {
9352         mm_player_t* player = (mm_player_t*) hplayer;
9353
9354         MMPLAYER_FENTER();
9355
9356         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9357
9358         if (MMPLAYER_CURRENT_STATE(player) !=  MM_PLAYER_STATE_NULL)
9359                 return MM_ERROR_PLAYER_INVALID_STATE;
9360
9361         LOGD("pre buffer size : %d sec\n", second);
9362
9363         if (second <= 0) {
9364                 LOGE("bad size value\n");
9365                 return MM_ERROR_INVALID_ARGUMENT;
9366         }
9367
9368         if (player->streamer == NULL) {
9369                 player->streamer = __mm_player_streaming_create();
9370                 __mm_player_streaming_initialize(player->streamer);
9371         }
9372
9373         player->streamer->buffering_req.initial_second = second;
9374
9375         MMPLAYER_FLEAVE();
9376
9377         return MM_ERROR_NONE;
9378 }
9379
9380 // set runtime mode
9381 int
9382 _mmplayer_set_runtime_buffering_mode(MMHandleType hplayer, MMPlayerBufferingMode mode, int second)
9383 {
9384         mm_player_t* player = (mm_player_t*) hplayer;
9385
9386         MMPLAYER_FENTER();
9387
9388         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9389
9390         LOGD("mode %d\n", mode);
9391
9392         if ((mode < 0) || (mode > MM_PLAYER_BUFFERING_MODE_MAX) ||
9393                 ((mode == MM_PLAYER_BUFFERING_MODE_FIXED) && (second <= 0)))
9394                 return MM_ERROR_INVALID_ARGUMENT;
9395
9396         if (player->streamer == NULL) {
9397                 player->streamer = __mm_player_streaming_create();
9398                 __mm_player_streaming_initialize(player->streamer);
9399         }
9400
9401         player->streamer->buffering_req.mode = mode;
9402
9403         if ((second > 0) &&
9404                 ((mode == MM_PLAYER_BUFFERING_MODE_FIXED) ||
9405                 (mode == MM_PLAYER_BUFFERING_MODE_ADAPTIVE)))
9406                 player->streamer->buffering_req.runtime_second = second;
9407
9408         MMPLAYER_FLEAVE();
9409
9410         return MM_ERROR_NONE;
9411 }
9412
9413 int
9414 __mmplayer_start_streaming_ext(mm_player_t *player)
9415 {
9416         gint ret = MM_ERROR_NONE;
9417
9418         MMPLAYER_FENTER();
9419         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9420
9421         if (MMPLAYER_IS_HTTP_PD(player)) {
9422                 if (!player->pd_downloader) {
9423                         ret = __mmplayer_realize_streaming_ext(player);
9424
9425                         if (ret != MM_ERROR_NONE) {
9426                                 LOGE("failed to realize streaming ext\n");
9427                                 return ret;
9428                         }
9429                 }
9430
9431                 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI) {
9432                         ret = _mmplayer_start_pd_downloader((MMHandleType)player);
9433                         if (!ret) {
9434                                 LOGE("ERROR while starting PD...\n");
9435                                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
9436                         }
9437                         ret = MM_ERROR_NONE;
9438                 }
9439         }
9440
9441         MMPLAYER_FLEAVE();
9442         return ret;
9443 }
9444
9445 int
9446 _mmplayer_start(MMHandleType hplayer) // @
9447 {
9448         mm_player_t* player = (mm_player_t*) hplayer;
9449         gint ret = MM_ERROR_NONE;
9450
9451         MMPLAYER_FENTER();
9452
9453         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9454
9455         /* check current state */
9456         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
9457
9458         ret = _mmplayer_sound_acquire_focus(&player->sound_focus);
9459         if (ret != MM_ERROR_NONE) {
9460                 LOGE("failed to acquire sound focus.\n");
9461                 return ret;
9462         }
9463
9464         /* NOTE : we should check and create pipeline again if not created as we destroy
9465          * whole pipeline when stopping in streamming playback
9466          */
9467         if (!player->pipeline) {
9468                 ret = __gst_realize(player);
9469                 if (MM_ERROR_NONE != ret) {
9470                         LOGE("failed to realize before starting. only in streamming\n");
9471                         /* unlock */
9472                         return ret;
9473                 }
9474         }
9475
9476         ret = __mmplayer_start_streaming_ext(player);
9477         if (ret != MM_ERROR_NONE)
9478                 LOGE("failed to start streaming ext \n");
9479
9480         /* start pipeline */
9481         ret = __gst_start(player);
9482         if (ret != MM_ERROR_NONE)
9483                 LOGE("failed to start player.\n");
9484
9485         MMPLAYER_FLEAVE();
9486
9487         return ret;
9488 }
9489
9490 /* NOTE: post "not supported codec message" to application
9491  * when one codec is not found during AUTOPLUGGING in MSL.
9492  * So, it's separated with error of __mmplayer_gst_callback().
9493  * And, if any codec is not found, don't send message here.
9494  * Because GST_ERROR_MESSAGE is posted by other plugin internally.
9495  */
9496 int
9497 __mmplayer_handle_missed_plugin(mm_player_t* player)
9498 {
9499         MMMessageParamType msg_param;
9500         memset(&msg_param, 0, sizeof(MMMessageParamType));
9501         gboolean post_msg_direct = FALSE;
9502
9503         MMPLAYER_FENTER();
9504
9505         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9506
9507         LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
9508                         player->not_supported_codec, player->can_support_codec);
9509
9510         if (player->not_found_demuxer) {
9511                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9512                 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
9513
9514                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9515                 MMPLAYER_FREEIF(msg_param.data);
9516
9517                 return MM_ERROR_NONE;
9518         }
9519
9520         if (player->not_supported_codec) {
9521                 if (player->can_support_codec) {
9522                         // There is one codec to play
9523                         post_msg_direct = TRUE;
9524                 } else {
9525                         if (player->pipeline->audiobin) // Some content has only PCM data in container.
9526                                 post_msg_direct = TRUE;
9527                 }
9528
9529                 if (post_msg_direct) {
9530                         MMMessageParamType msg_param;
9531                         memset(&msg_param, 0, sizeof(MMMessageParamType));
9532
9533                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
9534                                 LOGW("not found AUDIO codec, posting error code to application.\n");
9535
9536                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9537                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9538                         } else if (player->not_supported_codec ==  MISSING_PLUGIN_VIDEO) {
9539                                 LOGW("not found VIDEO codec, posting error code to application.\n");
9540
9541                                 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
9542                                 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
9543                         }
9544
9545                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9546
9547                         MMPLAYER_FREEIF(msg_param.data);
9548
9549                         return MM_ERROR_NONE;
9550                 } else {
9551                         // no any supported codec case
9552                         LOGW("not found any codec, posting error code to application.\n");
9553
9554                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
9555                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9556                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9557                         } else {
9558                                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9559                                 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
9560                         }
9561
9562                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9563
9564                         MMPLAYER_FREEIF(msg_param.data);
9565                 }
9566         }
9567
9568         MMPLAYER_FLEAVE();
9569
9570         return MM_ERROR_NONE;
9571 }
9572
9573 static void __mmplayer_check_pipeline(mm_player_t* player)
9574 {
9575         GstState element_state = GST_STATE_VOID_PENDING;
9576         GstState element_pending_state = GST_STATE_VOID_PENDING;
9577         gint timeout = 0;
9578         int ret = MM_ERROR_NONE;
9579
9580         if (player->gapless.reconfigure) {
9581                 LOGW("pipeline is under construction.\n");
9582
9583                 MMPLAYER_PLAYBACK_LOCK(player);
9584                 MMPLAYER_PLAYBACK_UNLOCK(player);
9585
9586                 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
9587
9588                 /* wait for state transition */
9589                 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
9590
9591                 if (ret == GST_STATE_CHANGE_FAILURE)
9592                         LOGE("failed to change pipeline state within %d sec\n", timeout);
9593         }
9594 }
9595
9596 /* NOTE : it should be able to call 'stop' anytime*/
9597 int
9598 _mmplayer_stop(MMHandleType hplayer) // @
9599 {
9600         mm_player_t* player = (mm_player_t*)hplayer;
9601         int ret = MM_ERROR_NONE;
9602
9603         MMPLAYER_FENTER();
9604
9605         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9606
9607         /* check current state */
9608         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
9609
9610         /* check pipline building state */
9611         __mmplayer_check_pipeline(player);
9612         __mmplayer_reset_gapless_state(player);
9613
9614         /* NOTE : application should not wait for EOS after calling STOP */
9615         __mmplayer_cancel_eos_timer(player);
9616
9617         __mmplayer_unrealize_streaming_ext(player);
9618
9619         /* reset */
9620         player->doing_seek = FALSE;
9621
9622         /* stop pipeline */
9623         ret = __gst_stop(player);
9624
9625         if (ret != MM_ERROR_NONE)
9626                 LOGE("failed to stop player.\n");
9627
9628         MMPLAYER_FLEAVE();
9629
9630         return ret;
9631 }
9632
9633 int
9634 _mmplayer_pause(MMHandleType hplayer) // @
9635 {
9636         mm_player_t* player = (mm_player_t*)hplayer;
9637         gint64 pos_msec = 0;
9638         gboolean async = FALSE;
9639         gint ret = MM_ERROR_NONE;
9640
9641         MMPLAYER_FENTER();
9642
9643         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9644
9645         /* check current state */
9646         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
9647
9648         /* check pipline building state */
9649         __mmplayer_check_pipeline(player);
9650
9651         switch (MMPLAYER_CURRENT_STATE(player)) {
9652         case MM_PLAYER_STATE_READY:
9653                 {
9654                         /* check prepare async or not.
9655                          * In the case of streaming playback, it's recommned to avoid blocking wait.
9656                          */
9657                         mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9658                         LOGD("prepare working mode : %s", (async ? "async" : "sync"));
9659
9660                         /* Changing back sync of rtspsrc to async */
9661                         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9662                                 LOGD("async prepare working mode for rtsp");
9663                                 async = TRUE;
9664                         }
9665                 }
9666                 break;
9667
9668         case MM_PLAYER_STATE_PLAYING:
9669                 {
9670                         /* NOTE : store current point to overcome some bad operation
9671                         *(returning zero when getting current position in paused state) of some
9672                         * elements
9673                         */
9674                         if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec))
9675                                 LOGW("getting current position failed in paused\n");
9676
9677                         player->last_position = pos_msec;
9678
9679                         /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
9680                            But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
9681                            This causes problem is position calculation during normal pause resume scenarios also.
9682                            Currently during pause , we are sending the current position to rtspsrc module for position saving. */
9683                         if ((MMPLAYER_IS_RTSP_STREAMING( player )) &&
9684                                 (__mmplayer_get_stream_service_type(player) != STREAMING_SERVICE_LIVE)) {
9685                                 g_object_set( player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL );
9686                         }
9687                 }
9688                 break;
9689         }
9690
9691         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
9692                 LOGD("doing async pause in case of ms buff src");
9693                 async = TRUE;
9694         }
9695
9696         /* pause pipeline */
9697         ret = __gst_pause(player, async);
9698
9699         if (ret != MM_ERROR_NONE)
9700                 LOGE("failed to pause player. ret : 0x%x\n", ret);
9701
9702         if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
9703                 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
9704                         LOGE("failed to update display_rotation");
9705         }
9706
9707         MMPLAYER_FLEAVE();
9708
9709         return ret;
9710 }
9711
9712 int
9713 _mmplayer_resume(MMHandleType hplayer)
9714 {
9715         mm_player_t* player = (mm_player_t*)hplayer;
9716         int ret = MM_ERROR_NONE;
9717         gboolean async = FALSE;
9718
9719         MMPLAYER_FENTER();
9720
9721         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9722
9723         /* Changing back sync mode rtspsrc to async */
9724         if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
9725                 LOGD("async resume for rtsp case");
9726                 async = TRUE;
9727         }
9728
9729         ret = _mmplayer_sound_acquire_focus(&player->sound_focus);
9730         if (ret != MM_ERROR_NONE) {
9731                 LOGE("failed to acquire sound focus.\n");
9732                 return ret;
9733         }
9734
9735         /* check current state */
9736         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
9737
9738         ret = __gst_resume(player, async);
9739
9740         if (ret != MM_ERROR_NONE)
9741                 LOGE("failed to resume player.\n");
9742
9743         MMPLAYER_FLEAVE();
9744
9745         return ret;
9746 }
9747
9748 int
9749 __mmplayer_set_play_count(mm_player_t* player, gint count)
9750 {
9751         MMHandleType attrs = 0;
9752
9753         MMPLAYER_FENTER();
9754
9755         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9756
9757         attrs =  MMPLAYER_GET_ATTRS(player);
9758         if (!attrs) {
9759                 LOGE("fail to get attributes.\n");
9760                 return MM_ERROR_PLAYER_INTERNAL;
9761         }
9762
9763         mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
9764         if (mmf_attrs_commit(attrs)) /* return -1 if error */
9765                 LOGE("failed to commit\n");
9766
9767         MMPLAYER_FLEAVE();
9768
9769         return  MM_ERROR_NONE;
9770 }
9771
9772 int
9773 _mmplayer_activate_section_repeat(MMHandleType hplayer, unsigned long start, unsigned long end)
9774 {
9775         mm_player_t* player = (mm_player_t*)hplayer;
9776         gint64 start_pos = 0;
9777         gint64 end_pos = 0;
9778         gint infinity = -1;
9779
9780         MMPLAYER_FENTER();
9781
9782         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9783         MMPLAYER_RETURN_VAL_IF_FAIL(end <= GST_TIME_AS_MSECONDS(player->duration), MM_ERROR_INVALID_ARGUMENT);
9784
9785         player->section_repeat = TRUE;
9786         player->section_repeat_start = start;
9787         player->section_repeat_end = end;
9788
9789         start_pos = player->section_repeat_start * G_GINT64_CONSTANT(1000000);
9790         end_pos = player->section_repeat_end * G_GINT64_CONSTANT(1000000);
9791
9792         __mmplayer_set_play_count(player, infinity);
9793
9794         if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9795                                         player->playback_rate,
9796                                         GST_FORMAT_TIME,
9797                                         (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9798                                         GST_SEEK_TYPE_SET, start_pos,
9799                                         GST_SEEK_TYPE_SET, end_pos))) {
9800                 LOGE("failed to activate section repeat\n");
9801
9802                 return MM_ERROR_PLAYER_SEEK;
9803         }
9804
9805         LOGD("succeeded to set section repeat from %d to %d\n",
9806                 player->section_repeat_start, player->section_repeat_end);
9807
9808         MMPLAYER_FLEAVE();
9809
9810         return  MM_ERROR_NONE;
9811 }
9812
9813 static int
9814 __mmplayer_set_pcm_extraction(mm_player_t* player)
9815 {
9816         gint64 start_nsec = 0;
9817         gint64 end_nsec = 0;
9818         gint64 dur_nsec = 0;
9819         gint64 dur_msec = 0;
9820         int required_start = 0;
9821         int required_end = 0;
9822         int ret = 0;
9823
9824         MMPLAYER_FENTER();
9825
9826         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
9827
9828         mm_attrs_multiple_get(player->attrs,
9829                 NULL,
9830                 "pcm_extraction_start_msec", &required_start,
9831                 "pcm_extraction_end_msec", &required_end,
9832                 NULL);
9833
9834         LOGD("pcm extraction required position is from [%d] to [%d](msec)\n", required_start, required_end);
9835
9836         if (required_start == 0 && required_end == 0) {
9837                 LOGD("extracting entire stream");
9838                 return MM_ERROR_NONE;
9839         } else if (required_start < 0 || required_start > required_end || required_end < 0) {
9840                 LOGD("invalid range for pcm extraction");
9841                 return MM_ERROR_INVALID_ARGUMENT;
9842         }
9843
9844         /* get duration */
9845         ret = gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec);
9846         if (!ret) {
9847                 LOGE("failed to get duration");
9848                 return MM_ERROR_PLAYER_INTERNAL;
9849         }
9850         dur_msec = GST_TIME_AS_MSECONDS(dur_nsec);
9851
9852         if (dur_msec < required_end) {
9853                 // FIXME
9854                 LOGD("invalid end pos for pcm extraction");
9855                 return MM_ERROR_INVALID_ARGUMENT;
9856         }
9857
9858         start_nsec = required_start * G_GINT64_CONSTANT(1000000);
9859         end_nsec = required_end * G_GINT64_CONSTANT(1000000);
9860
9861         if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9862                                         1.0,
9863                                         GST_FORMAT_TIME,
9864                                         (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9865                                         GST_SEEK_TYPE_SET, start_nsec,
9866                                         GST_SEEK_TYPE_SET, end_nsec))) {
9867                 LOGE("failed to seek for pcm extraction\n");
9868
9869                 return MM_ERROR_PLAYER_SEEK;
9870         }
9871
9872         LOGD("succeeded to set up segment extraction from [%llu] to [%llu](nsec)\n", start_nsec, end_nsec);
9873
9874         MMPLAYER_FLEAVE();
9875
9876         return MM_ERROR_NONE;
9877 }
9878
9879 int
9880 _mmplayer_deactivate_section_repeat(MMHandleType hplayer)
9881 {
9882         mm_player_t* player = (mm_player_t*)hplayer;
9883         gint64 cur_pos = 0;
9884         gint onetime = 1;
9885
9886         MMPLAYER_FENTER();
9887
9888         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9889
9890         player->section_repeat = FALSE;
9891
9892         __mmplayer_set_play_count(player, onetime);
9893
9894         gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_pos);
9895
9896         if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9897                                         1.0,
9898                                         GST_FORMAT_TIME,
9899                                         (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9900                                         GST_SEEK_TYPE_SET, cur_pos,
9901                                         GST_SEEK_TYPE_SET, player->duration))) {
9902                 LOGE("failed to deactivate section repeat\n");
9903
9904                 return MM_ERROR_PLAYER_SEEK;
9905         }
9906
9907         MMPLAYER_FENTER();
9908
9909         return MM_ERROR_NONE;
9910 }
9911
9912 int
9913 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
9914 {
9915         mm_player_t* player = (mm_player_t*)hplayer;
9916         gint64 pos_msec = 0;
9917         int ret = MM_ERROR_NONE;
9918         int mute = FALSE;
9919         signed long long start = 0, stop = 0;
9920         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
9921         MMPLAYER_FENTER();
9922
9923         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9924         MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
9925
9926         /* The sound of video is not supported under 0.0 and over 2.0. */
9927         if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
9928                 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
9929                         mute = TRUE;
9930         }
9931         _mmplayer_set_mute(hplayer, mute);
9932
9933         if (player->playback_rate == rate)
9934                 return MM_ERROR_NONE;
9935
9936         /* If the position is reached at start potion during fast backward, EOS is posted.
9937          * So, This EOS have to be classified with it which is posted at reaching the end of stream.
9938          * */
9939         player->playback_rate = rate;
9940
9941         current_state = MMPLAYER_CURRENT_STATE(player);
9942
9943         if (current_state != MM_PLAYER_STATE_PAUSED)
9944                 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
9945
9946         LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state);
9947
9948         if ((current_state == MM_PLAYER_STATE_PAUSED)
9949                 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
9950                 LOGW("returning last point : %lld\n", player->last_position);
9951                 pos_msec = player->last_position;
9952         }
9953
9954
9955         if (rate >= 0) {
9956                 start = pos_msec;
9957                 stop = GST_CLOCK_TIME_NONE;
9958         } else {
9959                 start = GST_CLOCK_TIME_NONE;
9960                 stop = pos_msec;
9961         }
9962         if ((!gst_element_seek(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9963                                 rate,
9964                                 GST_FORMAT_TIME,
9965                                 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9966                                 GST_SEEK_TYPE_SET, start,
9967                                 GST_SEEK_TYPE_SET, stop))) {
9968                 LOGE("failed to set speed playback\n");
9969                 return MM_ERROR_PLAYER_SEEK;
9970         }
9971
9972         LOGD("succeeded to set speed playback as %0.1f\n", rate);
9973
9974         MMPLAYER_FLEAVE();
9975
9976         return MM_ERROR_NONE;;
9977 }
9978
9979 int
9980 _mmplayer_set_position(MMHandleType hplayer, int format, int position) // @
9981 {
9982         mm_player_t* player = (mm_player_t*)hplayer;
9983         int ret = MM_ERROR_NONE;
9984
9985         MMPLAYER_FENTER();
9986
9987         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9988
9989         /* check pipline building state */
9990         __mmplayer_check_pipeline(player);
9991
9992         ret = __gst_set_position(player, format, (unsigned long)position, FALSE);
9993
9994         MMPLAYER_FLEAVE();
9995
9996         return ret;
9997 }
9998
9999 int
10000 _mmplayer_get_position(MMHandleType hplayer, int format, unsigned long *position) // @
10001 {
10002         mm_player_t* player = (mm_player_t*)hplayer;
10003         int ret = MM_ERROR_NONE;
10004
10005         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10006
10007         ret = __gst_get_position(player, format, position);
10008
10009         return ret;
10010 }
10011
10012 int
10013 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos) // @
10014 {
10015         mm_player_t* player = (mm_player_t*)hplayer;
10016         int ret = MM_ERROR_NONE;
10017
10018         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10019
10020         ret = __gst_get_buffer_position(player, format, start_pos, stop_pos);
10021
10022         return ret;
10023 }
10024
10025 int
10026 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position) // @
10027 {
10028         mm_player_t* player = (mm_player_t*)hplayer;
10029         int ret = MM_ERROR_NONE;
10030
10031         MMPLAYER_FENTER();
10032
10033         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10034
10035         ret = __gst_adjust_subtitle_position(player, format, position);
10036
10037         MMPLAYER_FLEAVE();
10038
10039         return ret;
10040 }
10041 int
10042 _mmplayer_adjust_video_postion(MMHandleType hplayer, int offset) // @
10043 {
10044         mm_player_t* player = (mm_player_t*)hplayer;
10045         int ret = MM_ERROR_NONE;
10046
10047         MMPLAYER_FENTER();
10048
10049         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10050
10051         ret = __gst_adjust_video_position(player, offset);
10052
10053         MMPLAYER_FLEAVE();
10054
10055         return ret;
10056 }
10057
10058 static gboolean
10059 __mmplayer_is_midi_type(gchar* str_caps)
10060 {
10061         if ((g_strrstr(str_caps, "audio/midi")) ||
10062                 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
10063                 (g_strrstr(str_caps, "application/x-smaf")) ||
10064                 (g_strrstr(str_caps, "audio/x-imelody")) ||
10065                 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
10066                 (g_strrstr(str_caps, "audio/xmf")) ||
10067                 (g_strrstr(str_caps, "audio/mxmf"))) {
10068                 LOGD("midi\n");
10069                 return TRUE;
10070         }
10071
10072         return FALSE;
10073 }
10074
10075 static gboolean
10076 __mmplayer_is_only_mp3_type(gchar *str_caps)
10077 {
10078         if (g_strrstr(str_caps, "application/x-id3") ||
10079                 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
10080                 return TRUE;
10081         return FALSE;
10082 }
10083
10084 static void
10085 __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps)
10086 {
10087         GstStructure* caps_structure = NULL;
10088         gint samplerate = 0;
10089         gint channels = 0;
10090
10091         MMPLAYER_FENTER();
10092         MMPLAYER_RETURN_IF_FAIL(player && caps);
10093
10094         caps_structure = gst_caps_get_structure(caps, 0);
10095
10096         /* set stream information */
10097         gst_structure_get_int(caps_structure, "rate", &samplerate);
10098         mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
10099
10100         gst_structure_get_int(caps_structure, "channels", &channels);
10101         mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
10102
10103         LOGD("audio samplerate : %d     channels : %d\n", samplerate, channels);
10104 }
10105
10106 static void
10107 __mmplayer_update_content_type_info(mm_player_t* player)
10108 {
10109         MMPLAYER_FENTER();
10110         MMPLAYER_RETURN_IF_FAIL(player && player->type);
10111
10112         if (__mmplayer_is_midi_type(player->type)) {
10113                 player->bypass_audio_effect = TRUE;
10114         } else if (g_strrstr(player->type, "application/x-hls")) {
10115                 /* If it can't know exact type when it parses uri because of redirection case,
10116                  * it will be fixed by typefinder or when doing autoplugging.
10117                  */
10118                 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
10119                 if (player->streamer) {
10120                         player->streamer->is_adaptive_streaming = TRUE;
10121                         player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
10122                         player->streamer->buffering_req.runtime_second = 5;
10123                 }
10124         } else if (g_strrstr(player->type, "application/dash+xml")) {
10125                 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
10126         }
10127
10128         MMPLAYER_FLEAVE();
10129 }
10130
10131 static void
10132 __mmplayer_typefind_have_type(GstElement *tf, guint probability, // @
10133 GstCaps *caps, gpointer data)
10134 {
10135         mm_player_t* player = (mm_player_t*)data;
10136         GstPad* pad = NULL;
10137
10138         MMPLAYER_FENTER();
10139
10140         MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
10141
10142         /* store type string */
10143         MMPLAYER_FREEIF(player->type);
10144         player->type = gst_caps_to_string(caps);
10145         if (player->type)
10146                 LOGD("meida type %s found, probability %d%% / %d\n", player->type, probability, gst_caps_get_size(caps));
10147
10148         if ((!MMPLAYER_IS_WFD_STREAMING(player)) &&
10149                 (!MMPLAYER_IS_RTSP_STREAMING(player)) &&
10150                 (g_strrstr(player->type, "audio/x-raw-int"))) {
10151                 LOGE("not support media format\n");
10152
10153                 if (player->msg_posted == FALSE) {
10154                         MMMessageParamType msg_param;
10155                         memset(&msg_param, 0, sizeof(MMMessageParamType));
10156
10157                         msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
10158                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10159
10160                         /* don't post more if one was sent already */
10161                         player->msg_posted = TRUE;
10162                 }
10163                 return;
10164         }
10165
10166         __mmplayer_update_content_type_info(player);
10167
10168         pad = gst_element_get_static_pad(tf, "src");
10169         if (!pad) {
10170                 LOGE("fail to get typefind src pad.\n");
10171                 return;
10172         }
10173
10174         if (player->use_decodebin) {
10175                 if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
10176                         gboolean async = FALSE;
10177                         LOGE("failed to autoplug %s\n", player->type);
10178
10179                         mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
10180
10181                         if (async && player->msg_posted == FALSE)
10182                                 __mmplayer_handle_missed_plugin(player);
10183
10184                         goto DONE;
10185                 }
10186         } else {
10187                 /* try to plug */
10188                 if (!__mmplayer_try_to_plug(player, pad, caps)) {
10189                         gboolean async = FALSE;
10190                         LOGE("failed to autoplug %s\n", player->type);
10191
10192                         mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
10193
10194                         if (async && player->msg_posted == FALSE)
10195                                 __mmplayer_handle_missed_plugin(player);
10196
10197                         goto DONE;
10198                 }
10199
10200                 /* finish autopluging if no dynamic pad waiting */
10201                 if ((!player->have_dynamic_pad) && (!player->has_many_types)) {
10202                         if (!MMPLAYER_IS_RTSP_STREAMING(player))
10203                                 __mmplayer_pipeline_complete(NULL, (gpointer)player);
10204                 }
10205         }
10206
10207 DONE:
10208         gst_object_unref(GST_OBJECT(pad));
10209
10210         MMPLAYER_FLEAVE();
10211
10212         return;
10213 }
10214
10215 static GstElement *
10216 __mmplayer_create_decodebin(mm_player_t* player)
10217 {
10218         GstElement *decodebin = NULL;
10219
10220         MMPLAYER_FENTER();
10221
10222         /* create decodebin */
10223         decodebin = gst_element_factory_make("decodebin", NULL);
10224
10225         if (!decodebin) {
10226                 LOGE("fail to create decodebin\n");
10227                 goto ERROR;
10228         }
10229
10230         /* raw pad handling signal */
10231         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
10232                                                 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
10233
10234         /* no-more-pad pad handling signal */
10235         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
10236                                                 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), player);
10237
10238         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
10239                                                 G_CALLBACK(__mmplayer_gst_decode_pad_removed), player);
10240
10241         /* This signal is emitted when a pad for which there is no further possible
10242            decoding is added to the decodebin.*/
10243         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
10244                                                 G_CALLBACK(__mmplayer_gst_decode_unknown_type), player);
10245
10246         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
10247            before looking for any elements that can handle that stream.*/
10248         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
10249                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), player);
10250
10251         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
10252            before looking for any elements that can handle that stream.*/
10253         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
10254                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
10255
10256         /* This signal is emitted once decodebin has finished decoding all the data.*/
10257         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
10258                                                 G_CALLBACK(__mmplayer_gst_decode_drained), player);
10259
10260         /* This signal is emitted when a element is added to the bin.*/
10261         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
10262                                                 G_CALLBACK(__mmplayer_gst_element_added), player);
10263
10264 ERROR:
10265         return decodebin;
10266 }
10267
10268 static gboolean
10269 __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
10270 {
10271         MMPlayerGstElement* mainbin = NULL;
10272         GstElement* decodebin = NULL;
10273         GstElement* queue2 = NULL;
10274         GstPad* sinkpad = NULL;
10275         GstPad* qsrcpad = NULL;
10276         gchar *caps_str = NULL;
10277         gint64 dur_bytes = 0L;
10278
10279         guint max_buffer_size_bytes = 0;
10280         gdouble init_buffering_time = (gdouble)player->streamer->buffering_req.initial_second;
10281
10282         MMPLAYER_FENTER();
10283         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
10284
10285         mainbin = player->pipeline->mainbin;
10286
10287         if ((!MMPLAYER_IS_HTTP_PD(player)) &&
10288                 (MMPLAYER_IS_HTTP_STREAMING(player))) {
10289                 LOGD("creating http streaming buffering queue(queue2)\n");
10290
10291                 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
10292                         LOGE("MMPLAYER_M_MUXED_S_BUFFER is not null\n");
10293                 } else {
10294                         queue2 = gst_element_factory_make("queue2", "queue2");
10295                         if (!queue2) {
10296                                 LOGE("failed to create buffering queue element\n");
10297                                 goto ERROR;
10298                         }
10299
10300                         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
10301                                 LOGE("failed to add buffering queue\n");
10302                                 goto ERROR;
10303                         }
10304
10305                         sinkpad = gst_element_get_static_pad(queue2, "sink");
10306                         qsrcpad = gst_element_get_static_pad(queue2, "src");
10307
10308                         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
10309                                 LOGE("failed to link buffering queue\n");
10310                                 goto ERROR;
10311                         }
10312
10313                         if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
10314                                 LOGE("fail to get duration.\n");
10315
10316                         LOGD("dur_bytes = %lld\n", dur_bytes);
10317
10318                         muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
10319
10320                         if (dur_bytes > 0) {
10321                                 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
10322                                         type = MUXED_BUFFER_TYPE_FILE;
10323                                 } else {
10324                                         type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
10325                                         player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
10326                                 }
10327                         } else {
10328                                 dur_bytes = 0;
10329                         }
10330
10331                         /* NOTE : we cannot get any duration info from ts container in case of streaming */
10332                         // if (!g_strrstr(GST_ELEMENT_NAME(sinkelement), "mpegtsdemux"))
10333                         if (!g_strrstr(player->type, "video/mpegts")) {
10334                                 max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5*1024*1024);
10335                                 LOGD("max_buffer_size_bytes = %d\n", max_buffer_size_bytes);
10336
10337                                 __mm_player_streaming_set_queue2(player->streamer,
10338                                                                                                 queue2,
10339                                                                                                 FALSE,
10340                                                                                                 max_buffer_size_bytes,
10341                                                                                                 player->ini.http_buffering_time,
10342                                                                                                 1.0,                                                            // no meaning
10343                                                                                                 player->ini.http_buffering_limit,       // no meaning
10344                                                                                                 type,
10345                                                                                                 player->http_file_buffering_path,
10346                                                                                                 (guint64)dur_bytes);
10347                         }
10348
10349                         if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(queue2)) {
10350                                 LOGE("failed to sync queue2 state with parent\n");
10351                                 goto ERROR;
10352                         }
10353
10354                         srcpad = qsrcpad;
10355
10356                         gst_object_unref(GST_OBJECT(sinkpad));
10357
10358                         mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
10359                         mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
10360                 }
10361         }
10362
10363         /* create decodebin */
10364         decodebin = __mmplayer_create_decodebin(player);
10365
10366         if (!decodebin) {
10367                 LOGE("can not create autoplug element\n");
10368                 goto ERROR;
10369         }
10370
10371         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
10372                 LOGE("failed to add decodebin\n");
10373                 goto ERROR;
10374         }
10375
10376         /* to force caps on the decodebin element and avoid reparsing stuff by
10377         * typefind. It also avoids a deadlock in the way typefind activates pads in
10378         * the state change */
10379         g_object_set(decodebin, "sink-caps", caps, NULL);
10380
10381         sinkpad = gst_element_get_static_pad(decodebin, "sink");
10382
10383         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
10384                 LOGE("failed to link decodebin\n");
10385                 goto ERROR;
10386         }
10387
10388         gst_object_unref(GST_OBJECT(sinkpad));
10389
10390         mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
10391         mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
10392
10393         /* set decodebin property about buffer in streaming playback. *
10394          * in case of hls, it does not need to have big buffer        *
10395          * because it is kind of adaptive streaming.                  */
10396         if (((!MMPLAYER_IS_HTTP_PD(player)) &&
10397            (MMPLAYER_IS_HTTP_STREAMING(player))) || MMPLAYER_IS_DASH_STREAMING(player)) {
10398                 guint max_size_bytes = MAX_DECODEBIN_BUFFER_BYTES;
10399                 guint64 max_size_time = MAX_DECODEBIN_BUFFER_TIME;
10400                 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
10401
10402                 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {
10403                         max_size_bytes = MAX_DECODEBIN_ADAPTIVE_BUFFER_BYTES;
10404                         max_size_time = MAX_DECODEBIN_ADAPTIVE_BUFFER_TIME;
10405                 }
10406
10407                 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
10408                                                                                         "high-percent", (gint)player->ini.http_buffering_limit,
10409                                                                                         "low-percent", 1,   // 1%
10410                                                                                         "max-size-bytes", max_size_bytes,
10411                                                                                         "max-size-time", (guint64)(max_size_time * GST_SECOND),
10412                                                                                         "max-size-buffers", 0, NULL);  // disable or automatic
10413         }
10414
10415         if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) {
10416                 LOGE("failed to sync decodebin state with parent\n");
10417                 goto ERROR;
10418         }
10419
10420         MMPLAYER_FLEAVE();
10421
10422         return TRUE;
10423
10424 ERROR:
10425
10426         MMPLAYER_FREEIF(caps_str);
10427
10428         if (sinkpad)
10429                 gst_object_unref(GST_OBJECT(sinkpad));
10430
10431         if (queue2) {
10432                 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
10433                  * You need to explicitly set elements to the NULL state before
10434                  * dropping the final reference, to allow them to clean up.
10435                  */
10436                 gst_element_set_state(queue2, GST_STATE_NULL);
10437
10438                 /* And, it still has a parent "player".
10439                  * You need to let the parent manage the object instead of unreffing the object directly.
10440                  */
10441                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
10442                 gst_object_unref(queue2);
10443                 queue2 = NULL;
10444         }
10445
10446         if (decodebin) {
10447                 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
10448                  * You need to explicitly set elements to the NULL state before
10449                  * dropping the final reference, to allow them to clean up.
10450                  */
10451                 gst_element_set_state(decodebin, GST_STATE_NULL);
10452
10453                 /* And, it still has a parent "player".
10454                  * You need to let the parent manage the object instead of unreffing the object directly.
10455                  */
10456
10457                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
10458                 gst_object_unref(decodebin);
10459                 decodebin = NULL;
10460         }
10461
10462         return FALSE;
10463 }
10464
10465 /* it will return first created element */
10466 static gboolean
10467 __mmplayer_try_to_plug(mm_player_t* player, GstPad *pad, const GstCaps *caps) // @
10468 {
10469         MMPlayerGstElement* mainbin = NULL;
10470         const char* mime = NULL;
10471         const GList* item = NULL;
10472         const gchar* klass = NULL;
10473         GstCaps* res = NULL;
10474         gboolean skip = FALSE;
10475         GstPad* queue_pad = NULL;
10476         GstElement* queue = NULL;
10477         GstElement *element = NULL;
10478
10479         MMPLAYER_FENTER();
10480
10481         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
10482
10483         mainbin = player->pipeline->mainbin;
10484
10485         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10486
10487         /* return if we got raw output */
10488         if (g_str_has_prefix(mime, "video/x-raw") || g_str_has_prefix(mime, "audio/x-raw")
10489                 || g_str_has_prefix(mime, "text/plain") || g_str_has_prefix(mime, "text/x-pango-markup")) {
10490
10491                 element = (GstElement*)gst_pad_get_parent(pad);
10492 /* NOTE : When no decoder has added during autoplugging. like a simple wave playback.
10493  * No queue will be added. I think it can caused breaking sound when playing raw audio
10494  * frames but there's no different. Decodebin also doesn't add with those wav fils.
10495  * Anyway, currentely raw-queue seems not necessary.
10496  */
10497 #if 1
10498                 /* NOTE : check if previously linked element is demuxer/depayloader/parse means no decoder
10499                  * has linked. if so, we need to add queue for quality of output. note that
10500                  * decodebin also has same problem.
10501                  */
10502                 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
10503
10504                 /* add queue if needed */
10505                 if ((g_strrstr(klass, "Demux") || g_strrstr(klass, "Depayloader")
10506                         || g_strrstr(klass, "Parse")) &&  !g_str_has_prefix(mime, "text")) {
10507                         LOGD("adding raw queue\n");
10508
10509                         queue = gst_element_factory_make("queue", NULL);
10510                         if (!queue) {
10511                                 LOGW("failed to create queue\n");
10512                                 goto ERROR;
10513                         }
10514
10515                         /* warmup */
10516                         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_READY)) {
10517                                 LOGW("failed to set state READY to queue\n");
10518                                 goto ERROR;
10519                         }
10520
10521                         /* add to pipeline */
10522                         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue)) {
10523                                 LOGW("failed to add queue\n");
10524                                 goto ERROR;
10525                         }
10526
10527                         /* link queue */
10528                         queue_pad = gst_element_get_static_pad(queue, "sink");
10529
10530                         if (GST_PAD_LINK_OK != gst_pad_link(pad, queue_pad)) {
10531                                 LOGW("failed to link queue\n");
10532                                 goto ERROR;
10533                         }
10534                         gst_object_unref(GST_OBJECT(queue_pad));
10535                         queue_pad = NULL;
10536
10537                         /* running */
10538                         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_PAUSED)) {
10539                                 LOGW("failed to set state PAUSED to queue\n");
10540                                 goto ERROR;
10541                         }
10542
10543                         /* replace given pad to queue:src */
10544                         pad = gst_element_get_static_pad(queue, "src");
10545                         if (!pad) {
10546                                 LOGW("failed to get pad from queue\n");
10547                                 goto ERROR;
10548                         }
10549                 }
10550 #endif
10551                 /* check if player can do start continually */
10552                 MMPLAYER_CHECK_CMD_IF_EXIT(player);
10553
10554                 if (__mmplayer_link_sink(player, pad))
10555                         __mmplayer_gst_decode_callback(element, pad, player);
10556
10557                 gst_object_unref(GST_OBJECT(element));
10558                 element = NULL;
10559
10560                 return TRUE;
10561         }
10562
10563         item = player->factories;
10564         for (; item != NULL; item = item->next) {
10565                 GstElementFactory *factory = GST_ELEMENT_FACTORY(item->data);
10566                 const GList *pads;
10567                 gint idx = 0;
10568
10569                 skip = FALSE;
10570
10571                 /* filtering exclude keyword */
10572                 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
10573                         if (g_strrstr(GST_OBJECT_NAME(factory),
10574                                         player->ini.exclude_element_keyword[idx])) {
10575                                 LOGW("skipping [%s] by exculde keyword [%s]\n",
10576                                         GST_OBJECT_NAME(factory),
10577                                         player->ini.exclude_element_keyword[idx]);
10578
10579                                 skip = TRUE;
10580                                 break;
10581                         }
10582                 }
10583
10584                 if (MMPLAYER_IS_RTSP_STREAMING(player) && g_strrstr(GST_OBJECT_NAME(factory), "omx_mpeg4dec")) {
10585                         // omx decoder can not support mpeg4video data partitioned
10586                         // rtsp streaming didn't know mpeg4video data partitioned format
10587                         // so, if rtsp playback, player will skip omx_mpeg4dec.
10588                         LOGW("skipping [%s] when rtsp streaming \n",
10589                                         GST_OBJECT_NAME(factory));
10590
10591                         skip = TRUE;
10592                 }
10593
10594                 if (skip) continue;
10595
10596                 /* check factory class for filtering */
10597                 klass = gst_element_factory_get_metadata(GST_ELEMENT_FACTORY(factory), GST_ELEMENT_METADATA_KLASS);
10598
10599                 /*parsers are not required in case of external feeder*/
10600                 if (g_strrstr(klass, "Codec/Parser") && MMPLAYER_IS_MS_BUFF_SRC(player))
10601                         continue;
10602
10603                 /* NOTE : msl don't need to use image plugins.
10604                  * So, those plugins should be skipped for error handling.
10605                  */
10606                 if (g_strrstr(klass, "Codec/Decoder/Image")) {
10607                         LOGD("skipping [%s] by not required\n", GST_OBJECT_NAME(factory));
10608                         continue;
10609                 }
10610
10611                 /* check pad compatability */
10612                 for (pads = gst_element_factory_get_static_pad_templates(factory);
10613                                         pads != NULL; pads = pads->next) {
10614                         GstStaticPadTemplate *temp1 = pads->data;
10615                         GstCaps* static_caps = NULL;
10616
10617                         if (temp1->direction != GST_PAD_SINK
10618                                 || temp1->presence != GST_PAD_ALWAYS)
10619                                 continue;
10620
10621                         /* using existing caps */
10622                         if (GST_IS_CAPS(&temp1->static_caps.caps))
10623                                 static_caps = gst_caps_ref(temp1->static_caps.caps);
10624                         /* create one */
10625                         else
10626                                 static_caps = gst_caps_from_string(temp1->static_caps.string);
10627
10628                         res = gst_caps_intersect((GstCaps*)caps, static_caps);
10629                         gst_caps_unref(static_caps);
10630                         static_caps = NULL;
10631
10632                         if (res && !gst_caps_is_empty(res)) {
10633                                 GstElement *new_element;
10634                                 GList *elements = player->parsers;
10635                                 char *name_template = g_strdup(temp1->name_template);
10636                                 gchar *name_to_plug = GST_OBJECT_NAME(factory);
10637                                 gst_caps_unref(res);
10638
10639                                 /* check ALP Codec can be used or not */
10640                                 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
10641                                         /* consider mp3 audio only */
10642                                         if (!MMPLAYER_IS_STREAMING(player) && __mmplayer_is_only_mp3_type(player->type)) {
10643                                                 /* try to use ALP decoder first instead of selected decoder */
10644                                                 GstElement *element = NULL;
10645                                                 GstElementFactory * element_facory;
10646                                                 gchar *path = NULL;
10647                                                 guint64 data_size = 0;
10648                                                 #define MIN_THRESHOLD_SIZE  320 * 1024 // 320K
10649                                                 struct stat sb;
10650
10651                                                 mm_attrs_get_string_by_name(player->attrs, "profile_uri", &path);
10652
10653                                                 if (stat(path, &sb) == 0)
10654                                                         data_size = (guint64)sb.st_size;
10655                                                 LOGD("file size : %u", data_size);
10656
10657                                                 if (data_size > MIN_THRESHOLD_SIZE) {
10658                                                         LOGD("checking if ALP can be used or not");
10659                                                         element = gst_element_factory_make("omx_mp3dec", "omx mp3 decoder");
10660                                                         if (element) {
10661                                                                 /* check availability because multi-instance is not supported */
10662                                                                 GstStateChangeReturn ret = gst_element_set_state(element, GST_STATE_READY);
10663
10664                                                                 if (ret != GST_STATE_CHANGE_SUCCESS) {
10665                                                                         // use just selected decoder
10666                                                                         gst_object_unref(element);
10667                                                                 } else if (ret == GST_STATE_CHANGE_SUCCESS) {
10668                                                                         // replace facotry to use omx
10669                                                                         /* clean  */
10670                                                                         gst_element_set_state(element, GST_STATE_NULL);
10671                                                                         gst_object_unref(element);
10672
10673                                                                         element_facory = gst_element_factory_find("omx_mp3dec");
10674                                                                         /* replace, otherwise use selected thing instead */
10675                                                                         if (element_facory) {
10676                                                                                 factory = element_facory;
10677                                                                                 name_to_plug = GST_OBJECT_NAME(factory);
10678                                                                         }
10679                                                                 }
10680                                                         }
10681                                                 }
10682                                         }
10683                                 } else if ((g_strrstr(klass, "Codec/Decoder/Video"))) {
10684                                         if (g_strrstr(GST_OBJECT_NAME(factory), "omx_")) {
10685                                                 char *env = getenv("MM_PLAYER_HW_CODEC_DISABLE");
10686                                                 if (env != NULL) {
10687                                                         if (strncasecmp(env, "yes", 3) == 0) {
10688                                                                 LOGD("skipping [%s] by disabled\n", name_to_plug);
10689                                                                 MMPLAYER_FREEIF(name_template);
10690                                                                 continue;
10691                                                         }
10692                                                 }
10693                                         }
10694                                 }
10695
10696                                 LOGD("found %s to plug\n", name_to_plug);
10697
10698                                 new_element = gst_element_factory_create(GST_ELEMENT_FACTORY(factory), NULL);
10699                                 if (!new_element) {
10700                                         LOGE("failed to create element [%s]. continue with next.\n",
10701                                                 GST_OBJECT_NAME(factory));
10702
10703                                         MMPLAYER_FREEIF(name_template);
10704
10705                                         continue;
10706                                 }
10707
10708                                 /* check and skip it if it was already used. Otherwise, it can be an infinite loop
10709                                  * because parser can accept its own output as input.
10710                                  */
10711                                 if (g_strrstr(klass, "Parser")) {
10712                                         gchar *selected = NULL;
10713
10714                                         for (; elements; elements = g_list_next(elements)) {
10715                                                 gchar *element_name = elements->data;
10716
10717                                                 if (g_strrstr(element_name, name_to_plug)) {
10718                                                         LOGD("but, %s already linked, so skipping it\n", name_to_plug);
10719                                                         skip = TRUE;
10720                                                 }
10721                                         }
10722
10723                                         if (skip) {
10724                                                 MMPLAYER_FREEIF(name_template);
10725                                                 continue;
10726                                         }
10727
10728                                         selected = g_strdup(name_to_plug);
10729                                         player->parsers = g_list_append(player->parsers, selected);
10730                                 }
10731
10732                                 /* store specific handles for futher control */
10733                                 if (g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) {
10734                                         /* FIXIT : first value will be overwritten if there's more
10735                                          * than 1 demuxer/parser
10736                                          */
10737                                         LOGD("plugged element is demuxer. take it\n");
10738                                         mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
10739                                         mainbin[MMPLAYER_M_DEMUX].gst = new_element;
10740
10741                                         /*Added for multi audio support */
10742                                         if (g_strrstr(klass, "Demux")) {
10743                                                 mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
10744                                                 mainbin[MMPLAYER_M_DEMUX_EX].gst = new_element;
10745
10746                                                 /* NOTE : workaround for bug in mpegtsdemux since doesn't emit
10747                                                 no-more-pad signal. this may cause wrong content attributes at PAUSED state
10748                                                 this code should be removed after mpegtsdemux is fixed */
10749                                                 if (g_strrstr(GST_OBJECT_NAME(factory), "mpegtsdemux")) {
10750                                                         LOGW("force no-more-pad to TRUE since mpegtsdemux os not giving no-more-pad signal. content attributes may wrong");
10751                                                         player->no_more_pad = TRUE;
10752                                                 }
10753                                         }
10754                                         if (g_strrstr(name_to_plug, "asfdemux")) // to support trust-zone only
10755                                                 g_object_set(mainbin[MMPLAYER_M_DEMUX_EX].gst, "file-location", player->profile.uri, NULL);
10756                                 } else if (g_strrstr(klass, "Decoder") && __mmplayer_link_decoder(player, pad)) {
10757                                         if (mainbin[MMPLAYER_M_DEC1].gst == NULL) {
10758                                                 LOGD("plugged element is decoder. take it[MMPLAYER_M_DEC1]\n");
10759                                                 mainbin[MMPLAYER_M_DEC1].id = MMPLAYER_M_DEC1;
10760                                                 mainbin[MMPLAYER_M_DEC1].gst = new_element;
10761                                         } else if (mainbin[MMPLAYER_M_DEC2].gst == NULL) {
10762                                                 LOGD("plugged element is decoder. take it[MMPLAYER_M_DEC2]\n");
10763                                                 mainbin[MMPLAYER_M_DEC2].id = MMPLAYER_M_DEC2;
10764                                                 mainbin[MMPLAYER_M_DEC2].gst = new_element;
10765                                         }
10766                                         /* NOTE : IF one codec is found, add it to supported_codec and remove from
10767                                          * missing plugin. Both of them are used to check what's supported codec
10768                                          * before returning result of play start. And, missing plugin should be
10769                                          * updated here for multi track files.
10770                                          */
10771                                         if (g_str_has_prefix(mime, "video")) {
10772                                                 GstPad *src_pad = NULL;
10773                                                 GstPadTemplate *pad_templ = NULL;
10774                                                 GstCaps *caps = NULL;
10775                                                 gchar *caps_str = NULL;
10776
10777                                                 LOGD("found VIDEO decoder\n");
10778                                                 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
10779                                                 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
10780
10781                                                 src_pad = gst_element_get_static_pad(new_element, "src");
10782                                                 pad_templ = gst_pad_get_pad_template(src_pad);
10783                                                 caps = GST_PAD_TEMPLATE_CAPS(pad_templ);
10784
10785                                                 caps_str = gst_caps_to_string(caps);
10786
10787                                                 /* clean */
10788                                                 MMPLAYER_FREEIF(caps_str);
10789                                                 gst_object_unref(src_pad);
10790                                         } else if (g_str_has_prefix(mime, "audio")) {
10791                                                 LOGD("found AUDIO decoder\n");
10792                                                 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
10793                                                 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
10794                                         }
10795                                 }
10796
10797                                 if (!__mmplayer_close_link(player, pad, new_element,
10798                                                         name_template, gst_element_factory_get_static_pad_templates(factory))) {
10799                                         MMPLAYER_FREEIF(name_template);
10800                                         if (player->keep_detecting_vcodec)
10801                                                 continue;
10802
10803                                         /* Link is failed even though a supportable codec is found. */
10804                                         __mmplayer_check_not_supported_codec(player, klass, mime);
10805
10806                                         LOGE("failed to call _close_link\n");
10807                                         return FALSE;
10808                                 }
10809
10810                                 MMPLAYER_FREEIF(name_template);
10811                                 return TRUE;
10812                         }
10813
10814                         gst_caps_unref(res);
10815                         break;
10816                 }
10817         }
10818
10819         /* There is no available codec. */
10820         __mmplayer_check_not_supported_codec(player, klass, mime);
10821
10822         MMPLAYER_FLEAVE();
10823         return FALSE;
10824
10825 ERROR:
10826         /* release */
10827         if (queue)
10828                 gst_object_unref(queue);
10829
10830         if (queue_pad)
10831                 gst_object_unref(queue_pad);
10832
10833         if (element)
10834                 gst_object_unref(element);
10835
10836         return FALSE;
10837 }
10838
10839
10840 static int
10841 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
10842 {
10843         MMPLAYER_FENTER();
10844
10845         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
10846         MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
10847
10848         LOGD("class : %s, mime : %s \n", factory_class, mime);
10849
10850         /* add missing plugin */
10851         /* NOTE : msl should check missing plugin for image mime type.
10852          * Some motion jpeg clips can have playable audio track.
10853          * So, msl have to play audio after displaying popup written video format not supported.
10854          */
10855         if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
10856                 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
10857                         LOGD("not found demuxer\n");
10858                         player->not_found_demuxer = TRUE;
10859                         player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
10860
10861                         goto DONE;
10862                 }
10863         }
10864
10865         if (!g_strrstr(factory_class, "Demuxer")) {
10866                 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
10867                         LOGD("can support codec=%d, vdec_linked=%d, adec_linked=%d\n",
10868                                 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
10869
10870                         /* check that clip have multi tracks or not */
10871                         if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
10872                                 LOGD("video plugin is already linked\n");
10873                         } else {
10874                                 LOGW("add VIDEO to missing plugin\n");
10875                                 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
10876                         }
10877                 } else if (g_str_has_prefix(mime, "audio")) {
10878                         if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
10879                                 LOGD("audio plugin is already linked\n");
10880                         } else {
10881                                 LOGW("add AUDIO to missing plugin\n");
10882                                 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
10883                         }
10884                 }
10885         }
10886
10887 DONE:
10888         MMPLAYER_FLEAVE();
10889
10890         return MM_ERROR_NONE;
10891 }
10892
10893
10894 static void
10895 __mmplayer_pipeline_complete(GstElement *decodebin,  gpointer data)
10896 {
10897         mm_player_t* player = (mm_player_t*)data;
10898
10899         MMPLAYER_FENTER();
10900
10901         MMPLAYER_RETURN_IF_FAIL(player);
10902
10903         /* remove fakesink. */
10904         if (!__mmplayer_gst_remove_fakesink(player,
10905                                 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
10906                 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
10907                  * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
10908                  * source element are not same. To overcome this situation, this function will called
10909                  * several places and several times. Therefore, this is not an error case.
10910                  */
10911                 return;
10912         }
10913
10914         LOGD("pipeline has completely constructed\n");
10915
10916         if ((player->ini.async_start) &&
10917                 (player->msg_posted == FALSE) &&
10918                 (player->cmd >= MMPLAYER_COMMAND_START))
10919                 __mmplayer_handle_missed_plugin(player);
10920
10921         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
10922 }
10923
10924 static gboolean
10925 __mmplayer_verify_next_play_path(mm_player_t *player)
10926 {
10927         MMHandleType attrs = 0;
10928         MMPlayerParseProfile profile;
10929         gint uri_idx = 0, check_cnt = 0;
10930         char *uri = NULL;
10931         gint mode = MM_PLAYER_PD_MODE_NONE;
10932         gint video = 0;
10933         gint count = 0;
10934         gint gapless = 0;
10935         guint num_of_list = 0;
10936         static int profile_tv = -1;
10937
10938         MMPLAYER_FENTER();
10939
10940         LOGD("checking for gapless play");
10941
10942         if (player->pipeline->textbin) {
10943                 LOGE("subtitle path is enabled. gapless play is not supported.\n");
10944                 goto ERROR;
10945         }
10946
10947         attrs = MMPLAYER_GET_ATTRS(player);
10948         if (!attrs) {
10949                 LOGE("fail to get attributes.\n");
10950                 goto ERROR;
10951         }
10952
10953         mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
10954
10955         if (__builtin_expect(profile_tv == -1, 0)) {
10956                 char *profileName;
10957                 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
10958                 switch (*profileName) {
10959                         case 't':
10960                         case 'T':
10961                                 profile_tv = 1;
10962                                 break;
10963                         default:
10964                                 profile_tv = 0;
10965                 }
10966                 free(profileName);
10967         }
10968         /* gapless playback is not supported in case of video at TV profile. */
10969         if (profile_tv && video) {
10970                 LOGW("not support video gapless playback");
10971                 goto ERROR;
10972         }
10973
10974         if (mm_attrs_get_int_by_name(attrs, "pd_mode", &mode) == MM_ERROR_NONE) {
10975                 if (mode == TRUE) {
10976                         LOGW("pd mode\n");
10977                         goto ERROR;
10978                 }
10979         }
10980
10981         if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
10982                 LOGE("can not get play count\n");
10983
10984         if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
10985                 LOGE("can not get gapless mode\n");
10986
10987         if (video && !gapless) {
10988                 LOGW("not enabled video gapless playback");
10989                 goto ERROR;
10990         }
10991
10992         if ((count == -1 || count > 1)) /* enable gapless when looping or repeat */
10993                 gapless = 1;
10994
10995         if (!gapless) {
10996                 LOGW("gapless is disabled\n");  /* FIXME: playlist(without gapless) is not implemented. */
10997                 goto ERROR;
10998         }
10999
11000         num_of_list = g_list_length(player->uri_info.uri_list);
11001
11002         LOGD("repeat count = %d, num_of_list = %d\n", count, num_of_list);
11003
11004         if (num_of_list == 0) {
11005                 if (mm_attrs_get_string_by_name(player->attrs, "profile_uri", &uri) != MM_ERROR_NONE) {
11006                         LOGE("can not get profile_uri\n");
11007                         goto ERROR;
11008                 }
11009
11010                 if (!uri) {
11011                         LOGE("uri list is empty.\n");
11012                         goto ERROR;
11013                 }
11014
11015                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
11016                 LOGD("add original path : %s ", uri);
11017
11018                 num_of_list = 1;
11019                 uri = NULL;
11020         }
11021
11022         uri_idx = player->uri_info.uri_idx;
11023
11024         while (TRUE) {
11025                 check_cnt++;
11026
11027                 if (check_cnt > num_of_list) {
11028                         LOGE("there is no valid uri.");
11029                         goto ERROR;
11030                 }
11031
11032                 LOGD("uri idx : %d / %d\n", uri_idx, num_of_list);
11033
11034                 if (uri_idx < num_of_list-1) {
11035                         uri_idx++;
11036                 } else {
11037                         if ((count <= 1) && (count != -1)) {
11038                                 LOGD("no repeat.");
11039                                 goto ERROR;
11040                         } else if (count > 1) {
11041                                 /* decrease play count */
11042                                 /* we succeeded to rewind. update play count and then wait for next EOS */
11043                                 count--;
11044
11045                                 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
11046
11047                                 /* commit attribute */
11048                                 if (mmf_attrs_commit(attrs))
11049                                         LOGE("failed to commit attribute\n");
11050                         }
11051
11052                         /* count < 0 : repeat continually */
11053                         uri_idx = 0;
11054                 }
11055
11056                 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
11057                 LOGD("uri idx : %d, uri = %s\n", uri_idx, uri);
11058
11059                 if (uri == NULL) {
11060                         LOGW("next uri does not exist\n");
11061                         continue;
11062                 }
11063
11064                 if (__mmfplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) {
11065                         LOGE("failed to parse profile\n");
11066                         continue;
11067                 }
11068
11069                 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
11070                         (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
11071                         LOGW("uri type is not supported(%d).", profile.uri_type);
11072                         continue;
11073                 }
11074
11075                 break;
11076         }
11077
11078         player->uri_info.uri_idx = uri_idx;
11079         mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
11080
11081         if (mmf_attrs_commit(player->attrs)) {
11082                 LOGE("failed to commit.\n");
11083                 goto ERROR;
11084         }
11085
11086         LOGD("next uri %s(%d)\n", uri, uri_idx);
11087
11088         return TRUE;
11089
11090 ERROR:
11091
11092         LOGE("unable to play next path. EOS will be posted soon.\n");
11093         return FALSE;
11094 }
11095
11096 static void
11097 __mmplayer_initialize_next_play(mm_player_t *player)
11098 {
11099         int i;
11100
11101         MMPLAYER_FENTER();
11102
11103         player->smooth_streaming = FALSE;
11104         player->videodec_linked = 0;
11105         player->audiodec_linked = 0;
11106         player->videosink_linked = 0;
11107         player->audiosink_linked = 0;
11108         player->textsink_linked = 0;
11109         player->is_external_subtitle_present = FALSE;
11110         player->is_external_subtitle_added_now = FALSE;
11111         player->not_supported_codec = MISSING_PLUGIN_NONE;
11112         player->can_support_codec = FOUND_PLUGIN_NONE;
11113         player->pending_seek.is_pending = FALSE;
11114         player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
11115         player->pending_seek.pos = 0;
11116         player->msg_posted = FALSE;
11117         player->has_many_types = FALSE;
11118         player->no_more_pad = FALSE;
11119         player->not_found_demuxer = 0;
11120         player->doing_seek = FALSE;
11121         player->max_audio_channels = 0;
11122         player->is_subtitle_force_drop = FALSE;
11123         player->play_subtitle = FALSE;
11124         player->use_textoverlay = FALSE;
11125         player->adjust_subtitle_pos = 0;
11126
11127         player->updated_bitrate_count = 0;
11128         player->total_bitrate = 0;
11129         player->updated_maximum_bitrate_count = 0;
11130         player->total_maximum_bitrate = 0;
11131
11132         _mmplayer_track_initialize(player);
11133
11134         for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
11135                 player->bitrate[i] = 0;
11136                 player->maximum_bitrate[i] = 0;
11137         }
11138
11139         if (player->v_stream_caps) {
11140                 gst_caps_unref(player->v_stream_caps);
11141                 player->v_stream_caps = NULL;
11142         }
11143
11144         mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
11145         mm_attrs_set_int_by_name(player->attrs, "content_audio_found", 0);
11146
11147         /* clean found parsers */
11148         if (player->parsers) {
11149                 GList *parsers = player->parsers;
11150                 for (; parsers; parsers = g_list_next(parsers)) {
11151                         gchar *name = parsers->data;
11152                         MMPLAYER_FREEIF(name);
11153                 }
11154                 g_list_free(player->parsers);
11155                 player->parsers = NULL;
11156         }
11157
11158         /* clean found audio decoders */
11159         if (player->audio_decoders) {
11160                 GList *a_dec = player->audio_decoders;
11161                 for (; a_dec; a_dec = g_list_next(a_dec)) {
11162                         gchar *name = a_dec->data;
11163                         MMPLAYER_FREEIF(name);
11164                 }
11165                 g_list_free(player->audio_decoders);
11166                 player->audio_decoders = NULL;
11167         }
11168
11169         MMPLAYER_FLEAVE();
11170 }
11171
11172 static void
11173 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
11174 {
11175         MMPlayerGstElement *mainbin = NULL;
11176         MMMessageParamType msg_param = {0,};
11177         GstElement *element = NULL;
11178         MMHandleType attrs = 0;
11179         char *uri = NULL;
11180         enum MainElementID elemId = MMPLAYER_M_NUM;
11181
11182         MMPLAYER_FENTER();
11183
11184         if ((player == NULL) ||
11185                 (player->pipeline == NULL) ||
11186                 (player->pipeline->mainbin == NULL)) {
11187                 LOGE("player is null.\n");
11188                 goto ERROR;
11189         }
11190
11191         mainbin = player->pipeline->mainbin;
11192         msg_param.code = MM_ERROR_PLAYER_INTERNAL;
11193
11194         attrs = MMPLAYER_GET_ATTRS(player);
11195         if (!attrs) {
11196                 LOGE("fail to get attributes.\n");
11197                 goto ERROR;
11198         }
11199
11200         /* Initialize Player values */
11201         __mmplayer_initialize_next_play(player);
11202
11203         mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
11204
11205         if (__mmfplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) {
11206                 LOGE("failed to parse profile\n");
11207                 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
11208                 goto ERROR;
11209         }
11210
11211         if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
11212                 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
11213                 LOGE("it's dash or hls. not support.");
11214                 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
11215                 goto ERROR;
11216         }
11217
11218         /* setup source */
11219         switch (player->profile.uri_type) {
11220         /* file source */
11221         case MM_PLAYER_URI_TYPE_FILE:
11222         {
11223                 LOGD("using filesrc for 'file://' handler.\n");
11224
11225                 element = gst_element_factory_make("filesrc", "source");
11226
11227                 if (!element) {
11228                         LOGE("failed to create filesrc\n");
11229                         break;
11230                 }
11231
11232                 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL);     /* uri+7 -> remove "file:// */
11233                 break;
11234         }
11235         case MM_PLAYER_URI_TYPE_URL_HTTP:
11236         {
11237                 gchar *user_agent, *proxy, *cookies, **cookie_list;
11238                 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
11239                 user_agent = proxy = cookies = NULL;
11240                 cookie_list = NULL;
11241
11242                 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
11243                 if (!element) {
11244                         LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
11245                         break;
11246                 }
11247                 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
11248
11249                 /* get attribute */
11250                 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
11251                 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
11252                 mm_attrs_get_string_by_name(attrs, "streaming_proxy", &proxy);
11253                 mm_attrs_get_int_by_name(attrs, "streaming_timeout", &http_timeout);
11254
11255                 if ((http_timeout == DEFAULT_HTTP_TIMEOUT) &&
11256                         (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)) {
11257                         LOGD("get timeout from ini\n");
11258                         http_timeout = player->ini.http_timeout;
11259                 }
11260
11261                 /* get attribute */
11262                 SECURE_LOGD("location : %s\n", player->profile.uri);
11263                 SECURE_LOGD("cookies : %s\n", cookies);
11264                 SECURE_LOGD("proxy : %s\n", proxy);
11265                 SECURE_LOGD("user_agent :  %s\n", user_agent);
11266                 LOGD("timeout : %d\n", http_timeout);
11267
11268                 /* setting property to streaming source */
11269                 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
11270                 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
11271                 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
11272
11273                 /* check if prosy is vailid or not */
11274                 if (util_check_valid_url(proxy))
11275                         g_object_set(G_OBJECT(element), "proxy", proxy, NULL);
11276                 /* parsing cookies */
11277                 if ((cookie_list = util_get_cookie_list((const char*)cookies)))
11278                         g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
11279                 if (user_agent)
11280                         g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL);
11281                 break;
11282         }
11283         default:
11284                 LOGE("not support uri type %d\n", player->profile.uri_type);
11285                 break;
11286         }
11287
11288         if (!element) {
11289                 LOGE("no source element was created.\n");
11290                 goto ERROR;
11291         }
11292
11293         if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
11294                 LOGE("failed to add source element to pipeline\n");
11295                 gst_object_unref(GST_OBJECT(element));
11296                 element = NULL;
11297                 goto ERROR;
11298         }
11299
11300         /* take source element */
11301         mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
11302         mainbin[MMPLAYER_M_SRC].gst = element;
11303
11304         element = NULL;
11305
11306         if (MMPLAYER_IS_HTTP_STREAMING(player)) {
11307                 if (player->streamer == NULL) {
11308                         player->streamer = __mm_player_streaming_create();
11309                         __mm_player_streaming_initialize(player->streamer);
11310                 }
11311
11312                 elemId = MMPLAYER_M_TYPEFIND;
11313                 element = gst_element_factory_make("typefind", "typefinder");
11314                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
11315                         G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
11316         } else {
11317                 elemId = MMPLAYER_M_AUTOPLUG;
11318                 element = __mmplayer_create_decodebin(player);
11319         }
11320
11321         /* check autoplug element is OK */
11322         if (!element) {
11323                 LOGE("can not create element(%d)\n", elemId);
11324                 goto ERROR;
11325         }
11326
11327         if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
11328                 LOGE("failed to add sinkbin to pipeline\n");
11329                 gst_object_unref(GST_OBJECT(element));
11330                 element = NULL;
11331                 goto ERROR;
11332         }
11333
11334         mainbin[elemId].id = elemId;
11335         mainbin[elemId].gst = element;
11336
11337         if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elemId].gst) == FALSE) {
11338                 LOGE("Failed to link src - autoplug(or typefind)\n");
11339                 goto ERROR;
11340         }
11341
11342         if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
11343                 LOGE("Failed to change state of src element\n");
11344                 goto ERROR;
11345         }
11346
11347         if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
11348                 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
11349                         LOGE("Failed to change state of decodebin\n");
11350                         goto ERROR;
11351                 }
11352         } else {
11353                 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
11354                         LOGE("Failed to change state of src element\n");
11355                         goto ERROR;
11356                 }
11357         }
11358
11359         player->gapless.stream_changed = TRUE;
11360         player->gapless.running = TRUE;
11361         MMPLAYER_FLEAVE();
11362         return;
11363
11364 ERROR:
11365         if (player) {
11366                 MMPLAYER_PLAYBACK_UNLOCK(player);
11367
11368                 if (!player->msg_posted) {
11369                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
11370                         player->msg_posted = TRUE;
11371                 }
11372         }
11373         return;
11374 }
11375
11376 static gboolean
11377 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
11378 {
11379         mm_player_selector_t *selector = &player->selector[type];
11380         MMPlayerGstElement *sinkbin = NULL;
11381         enum MainElementID selectorId = MMPLAYER_M_NUM;
11382         enum MainElementID sinkId = MMPLAYER_M_NUM;
11383         GstPad *srcpad = NULL;
11384         GstPad *sinkpad = NULL;
11385         gboolean send_notice = FALSE;
11386
11387         MMPLAYER_FENTER();
11388         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11389
11390         LOGD("type %d", type);
11391
11392         switch (type) {
11393         case MM_PLAYER_TRACK_TYPE_AUDIO:
11394                 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
11395                 sinkId = MMPLAYER_A_BIN;
11396                 sinkbin = player->pipeline->audiobin;
11397                 break;
11398         case MM_PLAYER_TRACK_TYPE_VIDEO:
11399                 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
11400                 sinkId = MMPLAYER_V_BIN;
11401                 sinkbin = player->pipeline->videobin;
11402                 send_notice = TRUE;
11403                 break;
11404         case MM_PLAYER_TRACK_TYPE_TEXT:
11405                 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
11406                 sinkId = MMPLAYER_T_BIN;
11407                 sinkbin = player->pipeline->textbin;
11408                 break;
11409         default:
11410                 LOGE("requested type is not supportable");
11411                 return FALSE;
11412                 break;
11413         }
11414
11415         if (player->pipeline->mainbin[selectorId].gst) {
11416                 gint n;
11417
11418                 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
11419
11420                 if (selector->event_probe_id != 0)
11421                         gst_pad_remove_probe(srcpad, selector->event_probe_id);
11422                 selector->event_probe_id = 0;
11423
11424                 if ((sinkbin) && (sinkbin[sinkId].gst)) {
11425                         sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
11426
11427                         if (srcpad && sinkpad) {
11428                                 /* after getting drained signal there is no data flows, so no need to do pad_block */
11429                                 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
11430                                 gst_pad_unlink(srcpad, sinkpad);
11431
11432                                 /* send custom event to sink pad to handle it at video sink */
11433                                 if (send_notice) {
11434                                         LOGD("send custom event to sinkpad");
11435                                         GstStructure *s = gst_structure_new_empty("application/flush-buffer");
11436                                         GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
11437                                         gst_pad_send_event(sinkpad, event);
11438                                 }
11439                         }
11440
11441                         gst_object_unref(sinkpad);
11442                         sinkpad = NULL;
11443                 }
11444                 gst_object_unref(srcpad);
11445                 srcpad = NULL;
11446
11447                 LOGD("selector release");
11448
11449                 /* release and unref requests pad from the selector */
11450                 for (n = 0; n < selector->channels->len; n++) {
11451                         GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
11452                         gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
11453                 }
11454                 g_ptr_array_set_size(selector->channels, 0);
11455
11456                 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
11457                 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
11458
11459                 player->pipeline->mainbin[selectorId].gst = NULL;
11460                 selector = NULL;
11461         }
11462
11463         return TRUE;
11464 }
11465
11466 static void
11467 __mmplayer_deactivate_old_path(mm_player_t *player)
11468 {
11469         MMPLAYER_FENTER();
11470         MMPLAYER_RETURN_IF_FAIL(player);
11471
11472         if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
11473                 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
11474                 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
11475                 LOGE("deactivate selector error");
11476                 goto ERROR;
11477         }
11478
11479         _mmplayer_track_destroy(player);
11480         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
11481
11482         if (player->streamer) {
11483                 __mm_player_streaming_deinitialize(player->streamer);
11484                 __mm_player_streaming_destroy(player->streamer);
11485                 player->streamer = NULL;
11486         }
11487
11488         MMPLAYER_PLAYBACK_LOCK(player);
11489         MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
11490
11491         MMPLAYER_FLEAVE();
11492         return;
11493
11494 ERROR:
11495
11496         if (!player->msg_posted) {
11497                 MMMessageParamType msg = {0,};
11498
11499                 /*post error*/
11500                 msg.code = MM_ERROR_PLAYER_INTERNAL;
11501                 LOGE("next_uri_play> deactivate error");
11502
11503                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
11504                 player->msg_posted = TRUE;
11505         }
11506         return;
11507 }
11508
11509 int _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char* file_path)
11510 {
11511         int result = MM_ERROR_NONE;
11512         mm_player_t* player = (mm_player_t*) hplayer;
11513         MMPLAYER_FENTER();
11514
11515         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11516
11517         if (file_path) {
11518                 player->http_file_buffering_path = (gchar*)file_path;
11519                 LOGD("temp file path: %s\n", player->http_file_buffering_path);
11520         }
11521         MMPLAYER_FLEAVE();
11522         return result;
11523 }
11524
11525 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
11526 {
11527         int result = MM_ERROR_NONE;
11528         mm_player_t* player = (mm_player_t*) hplayer;
11529         MMPLAYER_FENTER();
11530
11531         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11532
11533         mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
11534         if (mmf_attrs_commit(player->attrs)) {
11535                 LOGE("failed to commit the original uri.\n");
11536                 result = MM_ERROR_PLAYER_INTERNAL;
11537         } else {
11538                 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
11539                         LOGE("failed to add the original uri in the uri list.\n");
11540         }
11541
11542         MMPLAYER_FLEAVE();
11543         return result;
11544 }
11545
11546 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
11547 {
11548         mm_player_t* player = (mm_player_t*) hplayer;
11549         guint num_of_list = 0;
11550
11551         MMPLAYER_FENTER();
11552
11553         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11554         MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
11555
11556         if (player->pipeline && player->pipeline->textbin) {
11557                 LOGE("subtitle path is enabled.\n");
11558                 return MM_ERROR_PLAYER_INVALID_STATE;
11559         }
11560
11561         num_of_list = g_list_length(player->uri_info.uri_list);
11562
11563         if (is_first_path == TRUE) {
11564                 if (num_of_list == 0) {
11565                         player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
11566                         LOGD("add original path : %s", uri);
11567                 } else {
11568                         player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
11569                         player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
11570
11571                         LOGD("change original path : %s", uri);
11572                 }
11573         } else {
11574                 MMHandleType attrs = 0;
11575                 attrs = MMPLAYER_GET_ATTRS(player);
11576
11577                 if (num_of_list == 0) {
11578                         char *original_uri = NULL;
11579
11580                         if (attrs) {
11581                                 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
11582
11583                                 if (!original_uri) {
11584                                         LOGE("there is no original uri.");
11585                                         return MM_ERROR_PLAYER_INVALID_STATE;
11586                                 }
11587
11588                                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
11589                                 player->uri_info.uri_idx = 0;
11590
11591                                 LOGD("add original path at first : %s(%d)", original_uri);
11592                         }
11593                 }
11594
11595                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
11596                 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
11597         }
11598
11599         MMPLAYER_FLEAVE();
11600         return MM_ERROR_NONE;
11601 }
11602
11603 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
11604 {
11605         mm_player_t* player = (mm_player_t*) hplayer;
11606         char *next_uri = NULL;
11607         guint num_of_list = 0;
11608
11609         MMPLAYER_FENTER();
11610         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11611
11612         num_of_list = g_list_length(player->uri_info.uri_list);
11613
11614         if (num_of_list > 0) {
11615                 gint uri_idx = player->uri_info.uri_idx;
11616
11617                 if (uri_idx < num_of_list-1)
11618                         uri_idx++;
11619                 else
11620                         uri_idx = 0;
11621
11622                 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
11623                 LOGE("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
11624
11625                 *uri = g_strdup(next_uri);
11626         }
11627
11628         MMPLAYER_FLEAVE();
11629         return MM_ERROR_NONE;
11630 }
11631
11632 static void
11633 __mmplayer_gst_decode_unknown_type(GstElement *elem,  GstPad* pad,
11634 GstCaps *caps, gpointer data)
11635 {
11636         mm_player_t* player = (mm_player_t*)data;
11637         const gchar* klass = NULL;
11638         const gchar* mime = NULL;
11639         gchar* caps_str = NULL;
11640
11641         klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
11642         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
11643         caps_str = gst_caps_to_string(caps);
11644
11645         LOGW("unknown type of caps : %s from %s",
11646                                         caps_str, GST_ELEMENT_NAME(elem));
11647
11648         MMPLAYER_FREEIF(caps_str);
11649
11650         /* There is no available codec. */
11651         __mmplayer_check_not_supported_codec(player, klass, mime);
11652 }
11653
11654 static gboolean
11655 __mmplayer_gst_decode_autoplug_continue(GstElement *bin,  GstPad* pad,
11656 GstCaps * caps,  gpointer data)
11657 {
11658         mm_player_t* player = (mm_player_t*)data;
11659         const char* mime = NULL;
11660         gboolean ret = TRUE;
11661
11662         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
11663         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
11664
11665         if (g_str_has_prefix(mime, "audio")) {
11666                 GstStructure* caps_structure = NULL;
11667                 gint samplerate = 0;
11668                 gint channels = 0;
11669                 gchar *caps_str = NULL;
11670
11671                 caps_structure = gst_caps_get_structure(caps, 0);
11672                 gst_structure_get_int(caps_structure, "rate", &samplerate);
11673                 gst_structure_get_int(caps_structure, "channels", &channels);
11674
11675                 if ((channels > 0 && samplerate == 0)) {
11676                         LOGD("exclude audio...");
11677                         ret = FALSE;
11678                 }
11679
11680                 caps_str = gst_caps_to_string(caps);
11681                 /* set it directly because not sent by TAG */
11682                 if (g_strrstr(caps_str, "mobile-xmf"))
11683                         mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
11684                 MMPLAYER_FREEIF(caps_str);
11685         } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
11686                 MMMessageParamType msg_param;
11687                 memset(&msg_param, 0, sizeof(MMMessageParamType));
11688                 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
11689                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
11690                 LOGD("video file is not supported on this device");
11691                 ret = FALSE;
11692         } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
11693                 LOGD("already video linked");
11694                 ret = FALSE;
11695         } else {
11696                 LOGD("found new stream");
11697         }
11698
11699         return ret;
11700 }
11701
11702 static gint
11703 __mmplayer_gst_decode_autoplug_select(GstElement *bin,  GstPad* pad,
11704 GstCaps* caps, GstElementFactory* factory, gpointer data)
11705 {
11706         /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
11707          We are defining our own and will be removed when it actually exposed */
11708         typedef enum {
11709                 GST_AUTOPLUG_SELECT_TRY,
11710                 GST_AUTOPLUG_SELECT_EXPOSE,
11711                 GST_AUTOPLUG_SELECT_SKIP
11712         } GstAutoplugSelectResult;
11713
11714         GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
11715         mm_player_t* player = (mm_player_t*)data;
11716
11717         gchar* factory_name = NULL;
11718         gchar* caps_str = NULL;
11719         const gchar* klass = NULL;
11720         gint idx = 0;
11721         int surface_type = 0;
11722
11723         factory_name = GST_OBJECT_NAME(factory);
11724         klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
11725         caps_str = gst_caps_to_string(caps);
11726
11727         LOGD("found new element [%s] to link", factory_name);
11728
11729         /* store type string */
11730         if (player->type == NULL) {
11731                 player->type = gst_caps_to_string(caps);
11732                 __mmplayer_update_content_type_info(player);
11733         }
11734
11735         mm_attrs_get_int_by_name(player->attrs,
11736                                 "display_surface_type", &surface_type);
11737         LOGD("check display surface type attribute: %d", surface_type);
11738
11739         /* filtering exclude keyword */
11740         for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
11741                 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
11742                         LOGW("skipping [%s] by exculde keyword [%s]\n",
11743                         factory_name, player->ini.exclude_element_keyword[idx]);
11744
11745                         // NOTE : does we need to check n_value against the number of item selected?
11746                         result = GST_AUTOPLUG_SELECT_SKIP;
11747                         goto DONE;
11748                 }
11749         }
11750
11751         /* exclude webm format */
11752         /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
11753          * because webm format is not supportable.
11754          * If webm is disabled in "autoplug-continue", there is no state change
11755          * failure or error because the decodebin will expose the pad directly.
11756          * It make MSL invoke _prepare_async_callback.
11757          * So, we need to disable webm format in "autoplug-select" */
11758         if (caps_str && strstr(caps_str, "webm")) {
11759                 LOGW("webm is not supported");
11760                 result = GST_AUTOPLUG_SELECT_SKIP;
11761                 goto DONE;
11762         }
11763
11764         /* check factory class for filtering */
11765         /* NOTE : msl don't need to use image plugins.
11766          * So, those plugins should be skipped for error handling.
11767          */
11768         if (g_strrstr(klass, "Codec/Decoder/Image")) {
11769                 LOGD("skipping [%s] by not required\n", factory_name);
11770                 result = GST_AUTOPLUG_SELECT_SKIP;
11771                 goto DONE;
11772         }
11773
11774         if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
11775                 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
11776                 // TO CHECK : subtitle if needed, add subparse exception.
11777                 LOGD("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
11778                 result = GST_AUTOPLUG_SELECT_SKIP;
11779                 goto DONE;
11780         }
11781
11782         if (g_strrstr(factory_name, "mpegpsdemux")) {
11783                 LOGD("skipping PS container - not support\n");
11784                 result = GST_AUTOPLUG_SELECT_SKIP;
11785                 goto DONE;
11786         }
11787
11788         if (g_strrstr(factory_name, "mssdemux"))
11789                 player->smooth_streaming = TRUE;
11790
11791         /* check ALP Codec can be used or not */
11792         if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
11793                 GstStructure* str = NULL;
11794                 gint channels = 0;
11795
11796                 str = gst_caps_get_structure(caps, 0);
11797                 if (str) {
11798                         gst_structure_get_int(str, "channels", &channels);
11799
11800                         LOGD("check audio ch : %d %d\n", player->max_audio_channels, channels);
11801                         if (player->max_audio_channels < channels)
11802                                 player->max_audio_channels = channels;
11803                 }
11804                 /* set stream information */
11805                 if (!player->audiodec_linked)
11806                         __mmplayer_set_audio_attrs(player, caps);
11807         } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
11808                 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
11809                         (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
11810                         /* prepare resource manager for video decoder */
11811                         MMPlayerResourceState resource_state = RESOURCE_STATE_NONE;
11812
11813                         if (_mmplayer_resource_manager_get_state(&player->resource_manager, &resource_state) == MM_ERROR_NONE) {
11814                                 /* prepare resource manager for video decoder */
11815                                 if ((resource_state >= RESOURCE_STATE_INITIALIZED) && (resource_state < RESOURCE_STATE_ACQUIRED)) {
11816                                         if (_mmplayer_resource_manager_prepare(&player->resource_manager, RESOURCE_TYPE_VIDEO_DECODER)
11817                                                 != MM_ERROR_NONE) {
11818                                                 LOGW("could not prepare for video_decoder resource, skip it.");
11819                                                 result = GST_AUTOPLUG_SELECT_SKIP;
11820                                                 goto DONE;
11821                                         }
11822                                 }
11823                         }
11824                 }
11825         }
11826
11827         if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
11828                 (g_strrstr(klass, "Codec/Decoder/Video"))) {
11829                 gint stype = 0;
11830                 gint width = 0;
11831                 GstStructure *str = NULL;
11832                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
11833
11834                 /* don't make video because of not required */
11835                 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
11836                         (player->set_mode.media_packet_video_stream == FALSE)) {
11837                         LOGD("no video because it's not required. -> return expose");
11838                         result = GST_AUTOPLUG_SELECT_EXPOSE;
11839                         goto DONE;
11840                 }
11841
11842                 /* get w/h for omx state-tune */
11843                 str = gst_caps_get_structure(caps, 0);
11844                 gst_structure_get_int(str, "width", &width);
11845
11846                 if (width != 0) {
11847                         if (player->v_stream_caps) {
11848                                 gst_caps_unref(player->v_stream_caps);
11849                                 player->v_stream_caps = NULL;
11850                         }
11851
11852                         player->v_stream_caps = gst_caps_copy(caps);
11853                         LOGD("take caps for video state tune");
11854                         MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
11855                 }
11856         }
11857
11858         if (g_strrstr(klass, "Decoder")) {
11859                 const char* mime = NULL;
11860                 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
11861
11862                 if (g_str_has_prefix(mime, "video")) {
11863                         // __mmplayer_check_video_zero_cpoy(player, factory);
11864
11865                         player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
11866                         player->can_support_codec |= FOUND_PLUGIN_VIDEO;
11867
11868                         player->videodec_linked = 1;
11869                 } else if (g_str_has_prefix(mime, "audio")) {
11870                         player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
11871                         player->can_support_codec |= FOUND_PLUGIN_AUDIO;
11872
11873                         player->audiodec_linked = 1;
11874                 }
11875         }
11876
11877 DONE:
11878         MMPLAYER_FREEIF(caps_str);
11879
11880         return result;
11881 }
11882
11883
11884 #if 0
11885 static GValueArray*
11886 __mmplayer_gst_decode_autoplug_factories(GstElement *bin,  GstPad* pad,
11887 GstCaps * caps,  gpointer data)
11888 {
11889         //mm_player_t* player = (mm_player_t*)data;
11890
11891         LOGD("decodebin is requesting factories for caps [%s] from element[%s]",
11892         gst_caps_to_string(caps),
11893         GST_ELEMENT_NAME(GST_PAD_PARENT(pad)));
11894
11895         return NULL;
11896 }
11897 #endif
11898
11899 static void
11900 __mmplayer_gst_decode_pad_removed(GstElement *elem,  GstPad* new_pad,
11901 gpointer data) // @
11902 {
11903         //mm_player_t* player = (mm_player_t*)data;
11904         GstCaps* caps = NULL;
11905
11906         LOGD("[Decodebin2] pad-removed signal\n");
11907
11908         caps = gst_pad_query_caps(new_pad, NULL);
11909         if (caps) {
11910                 gchar* caps_str = NULL;
11911                 caps_str = gst_caps_to_string(caps);
11912
11913                 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
11914
11915                 MMPLAYER_FREEIF(caps_str);
11916         }
11917 }
11918
11919 static void
11920 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
11921 {
11922         mm_player_t* player = (mm_player_t*)data;
11923         GstIterator *iter = NULL;
11924         GValue item = { 0, };
11925         GstPad *pad = NULL;
11926         gboolean done = FALSE;
11927         gboolean is_all_drained = TRUE;
11928
11929         MMPLAYER_FENTER();
11930         MMPLAYER_RETURN_IF_FAIL(player);
11931
11932         LOGD("__mmplayer_gst_decode_drained");
11933
11934         if (player->use_deinterleave == TRUE) {
11935                 LOGD("group playing mode.");
11936                 return;
11937         }
11938
11939         if (!MMPLAYER_CMD_TRYLOCK(player)) {
11940                 LOGW("Fail to get cmd lock");
11941                 return;
11942         }
11943
11944         if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
11945                 !__mmplayer_verify_next_play_path(player)) {
11946                 LOGD("decoding is finished.");
11947                 __mmplayer_reset_gapless_state(player);
11948                 MMPLAYER_CMD_UNLOCK(player);
11949                 return;
11950         }
11951
11952         player->gapless.reconfigure = TRUE;
11953
11954         /* check decodebin src pads whether they received EOS or not */
11955         iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11956
11957         while (!done) {
11958                 switch (gst_iterator_next(iter, &item)) {
11959                 case GST_ITERATOR_OK:
11960                         pad = g_value_get_object(&item);
11961                         if (!GST_PAD_IS_EOS(pad)) {
11962                                 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
11963                                 is_all_drained = FALSE;
11964                                 break;
11965                         }
11966                         g_value_reset(&item);
11967                         break;
11968                 case GST_ITERATOR_RESYNC:
11969                         gst_iterator_resync(iter);
11970                         break;
11971                 case GST_ITERATOR_ERROR:
11972                 case GST_ITERATOR_DONE:
11973                         done = TRUE;
11974                         break;
11975                 }
11976         }
11977         g_value_unset(&item);
11978         gst_iterator_free(iter);
11979
11980         if (!is_all_drained) {
11981                 LOGD("Wait util the all pads get EOS.");
11982                 MMPLAYER_CMD_UNLOCK(player);
11983                 MMPLAYER_FLEAVE();
11984                 return;
11985         }
11986
11987         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
11988         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
11989
11990         /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
11991         MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
11992         __mmplayer_deactivate_old_path(player);
11993         MMPLAYER_CMD_UNLOCK(player);
11994
11995         MMPLAYER_FLEAVE();
11996 }
11997
11998 static void
11999 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
12000 {
12001         mm_player_t* player = (mm_player_t*)data;
12002         const gchar* klass = NULL;
12003         gchar* factory_name = NULL;
12004
12005         klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
12006         factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
12007
12008         LOGD("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
12009
12010         if (__mmplayer_add_dump_buffer_probe(player, element))
12011                 LOGD("add buffer probe");
12012
12013         //<-
12014         if (g_strrstr(klass, "Codec/Decoder/Audio")) {
12015                 gchar* selected = NULL;
12016                 selected = g_strdup(GST_ELEMENT_NAME(element));
12017                 player->audio_decoders = g_list_append(player->audio_decoders, selected);
12018         }
12019         //-> temp code
12020
12021         if (g_strrstr(klass, "Parser")) {
12022                 gchar* selected = NULL;
12023
12024                 selected = g_strdup(factory_name);
12025                 player->parsers = g_list_append(player->parsers, selected);
12026         }
12027
12028         if ((g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) && !(g_strrstr(klass, "Adaptive"))) {
12029                 /* FIXIT : first value will be overwritten if there's more
12030                  * than 1 demuxer/parser
12031                  */
12032
12033                 //LOGD("plugged element is demuxer. take it\n");
12034                 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
12035                 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
12036
12037                 /*Added for multi audio support */ // Q. del?
12038                 if (g_strrstr(klass, "Demux")) {
12039                         player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
12040                         player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].gst = element;
12041                 }
12042         }
12043
12044         if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
12045                 int surface_type = 0;
12046
12047                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
12048         }
12049
12050         // to support trust-zone only
12051         if (g_strrstr(factory_name, "asfdemux")) {
12052                 LOGD("set file-location %s\n", player->profile.uri);
12053                 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
12054
12055                 if (player->video_hub_download_mode == TRUE)
12056                         g_object_set(G_OBJECT(element), "downloading-mode", player->video_hub_download_mode, NULL);
12057         } else if (g_strrstr(factory_name, "legacyh264parse")) {
12058                 LOGD("[%s] output-format to legacyh264parse\n", "mssdemux");
12059                 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
12060         } else if (g_strrstr(factory_name, "mpegaudioparse")) {
12061                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
12062                         (__mmplayer_is_only_mp3_type(player->type))) {
12063                         LOGD("[mpegaudioparse] set streaming pull mode.");
12064                         g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
12065                 }
12066         } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw))
12067                 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
12068
12069
12070         if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
12071                 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
12072                 LOGD("plugged element is multiqueue. take it\n");
12073
12074                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
12075                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
12076
12077                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
12078                         (MMPLAYER_IS_HTTP_LIVE_STREAMING(player))) {
12079                         /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
12080                         __mm_player_streaming_set_multiqueue(player->streamer,
12081                                 element,
12082                                 TRUE,
12083                                 player->ini.http_buffering_time,
12084                                 1.0,
12085                                 player->ini.http_buffering_limit);
12086
12087                         __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
12088                 }
12089         }
12090
12091         return;
12092 }
12093
12094 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player)
12095 {
12096         MMPLAYER_FENTER();
12097         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12098
12099         if (MMPLAYER_IS_STREAMING(player))
12100                 return FALSE;
12101
12102         /* This callback can be set to music player only. */
12103         if ((player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO) {
12104                 LOGW("audio callback is not supported for video");
12105                 return FALSE;
12106         }
12107
12108         if (player->audio_stream_cb) {
12109                 GstPad *pad = NULL;
12110
12111                 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
12112
12113                 if (!pad) {
12114                         LOGE("failed to get sink pad from audiosink to probe data\n");
12115                         return FALSE;
12116                 }
12117                 player->audio_cb_probe_id = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
12118                         __mmplayer_audio_stream_probe, player, NULL);
12119
12120                 gst_object_unref(pad);
12121
12122                 pad = NULL;
12123         } else {
12124                 LOGE("There is no audio callback to configure.\n");
12125                 return FALSE;
12126         }
12127
12128         MMPLAYER_FLEAVE();
12129
12130         return TRUE;
12131 }
12132
12133 static void
12134 __mmplayer_init_factories(mm_player_t* player) // @
12135 {
12136         MMPLAYER_RETURN_IF_FAIL(player);
12137
12138         player->factories = gst_registry_feature_filter(gst_registry_get(),
12139                 (GstPluginFeatureFilter)__mmplayer_feature_filter, FALSE, NULL);
12140         player->factories = g_list_sort(player->factories, (GCompareFunc)util_factory_rank_compare);
12141 }
12142
12143 static void
12144 __mmplayer_release_factories(mm_player_t* player) // @
12145 {
12146         MMPLAYER_FENTER();
12147         MMPLAYER_RETURN_IF_FAIL(player);
12148
12149         if (player->factories) {
12150                 gst_plugin_feature_list_free(player->factories);
12151                 player->factories = NULL;
12152         }
12153
12154         MMPLAYER_FLEAVE();
12155 }
12156
12157 static void
12158 __mmplayer_release_misc(mm_player_t* player)
12159 {
12160         int i;
12161         gboolean cur_mode = player->set_mode.rich_audio;
12162         MMPLAYER_FENTER();
12163
12164         MMPLAYER_RETURN_IF_FAIL(player);
12165
12166         player->video_stream_cb = NULL;
12167         player->video_stream_cb_user_param = NULL;
12168         player->video_stream_prerolled = FALSE;
12169
12170         player->audio_stream_cb = NULL;
12171         player->audio_stream_render_cb_ex = NULL;
12172         player->audio_stream_cb_user_param = NULL;
12173         player->audio_stream_sink_sync = false;
12174
12175         player->video_stream_changed_cb = NULL;
12176         player->video_stream_changed_cb_user_param = NULL;
12177
12178         player->audio_stream_changed_cb = NULL;
12179         player->audio_stream_changed_cb_user_param = NULL;
12180
12181         player->sent_bos = FALSE;
12182         player->playback_rate = DEFAULT_PLAYBACK_RATE;
12183
12184         player->doing_seek = FALSE;
12185
12186         player->updated_bitrate_count = 0;
12187         player->total_bitrate = 0;
12188         player->updated_maximum_bitrate_count = 0;
12189         player->total_maximum_bitrate = 0;
12190
12191         player->not_found_demuxer = 0;
12192
12193         player->last_position = 0;
12194         player->duration = 0;
12195         player->http_content_size = 0;
12196         player->not_supported_codec = MISSING_PLUGIN_NONE;
12197         player->can_support_codec = FOUND_PLUGIN_NONE;
12198         player->pending_seek.is_pending = FALSE;
12199         player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
12200         player->pending_seek.pos = 0;
12201         player->msg_posted = FALSE;
12202         player->has_many_types = FALSE;
12203         player->max_audio_channels = 0;
12204         player->video_share_api_delta = 0;
12205         player->video_share_clock_delta = 0;
12206         player->sound_focus.keep_last_pos = FALSE;
12207         player->sound_focus.acquired = FALSE;
12208         player->is_subtitle_force_drop = FALSE;
12209         player->play_subtitle = FALSE;
12210         player->use_textoverlay = FALSE;
12211         player->adjust_subtitle_pos = 0;
12212         player->last_multiwin_status = FALSE;
12213         player->has_closed_caption = FALSE;
12214         player->set_mode.media_packet_video_stream = FALSE;
12215         player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
12216         memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
12217         /* recover mode */
12218         player->set_mode.rich_audio = cur_mode;
12219
12220         for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
12221                 player->bitrate[i] = 0;
12222                 player->maximum_bitrate[i] = 0;
12223         }
12224
12225         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
12226
12227         /* remove media stream cb(appsrc cb) */
12228         for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
12229                 player->media_stream_buffer_status_cb[i] = NULL;
12230                 player->media_stream_seek_data_cb[i] = NULL;
12231         }
12232         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
12233
12234         /* free memory related to audio effect */
12235         MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
12236
12237         if (player->state_tune_caps) {
12238                 gst_caps_unref(player->state_tune_caps);
12239                 player->state_tune_caps = NULL;
12240         }
12241
12242         MMPLAYER_FLEAVE();
12243 }
12244
12245 static void
12246 __mmplayer_release_misc_post(mm_player_t* player)
12247 {
12248         char *original_uri = NULL;
12249         MMPLAYER_FENTER();
12250
12251         /* player->pipeline is already released before. */
12252
12253         MMPLAYER_RETURN_IF_FAIL(player);
12254
12255         mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
12256         mm_attrs_set_int_by_name(player->attrs, "content_audio_found", 0);
12257
12258         /* clean found parsers */
12259         if (player->parsers) {
12260                 GList *parsers = player->parsers;
12261                 for (; parsers; parsers = g_list_next(parsers)) {
12262                         gchar *name = parsers->data;
12263                         MMPLAYER_FREEIF(name);
12264                 }
12265                 g_list_free(player->parsers);
12266                 player->parsers = NULL;
12267         }
12268
12269         /* clean found audio decoders */
12270         if (player->audio_decoders) {
12271                 GList *a_dec = player->audio_decoders;
12272                 for (; a_dec; a_dec = g_list_next(a_dec)) {
12273                         gchar *name = a_dec->data;
12274                         MMPLAYER_FREEIF(name);
12275                 }
12276                 g_list_free(player->audio_decoders);
12277                 player->audio_decoders = NULL;
12278         }
12279
12280         /* clean the uri list except original uri */
12281         if (player->uri_info.uri_list) {
12282                 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
12283
12284                 if (player->attrs) {
12285                         mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
12286                         LOGD("restore original uri = %s\n", original_uri);
12287
12288                         if (mmf_attrs_commit(player->attrs))
12289                                 LOGE("failed to commit the original uri.\n");
12290                 }
12291
12292                 GList *uri_list = player->uri_info.uri_list;
12293                 for (; uri_list; uri_list = g_list_next(uri_list)) {
12294                         gchar *uri = uri_list->data;
12295                         MMPLAYER_FREEIF(uri);
12296                 }
12297                 g_list_free(player->uri_info.uri_list);
12298                 player->uri_info.uri_list = NULL;
12299         }
12300
12301         /* clear the audio stream buffer list */
12302         __mmplayer_audio_stream_clear_buffer(player, FALSE);
12303
12304         /* clear the video stream bo list */
12305         __mmplayer_video_stream_destroy_bo_list(player);
12306
12307         player->uri_info.uri_idx = 0;
12308         MMPLAYER_FLEAVE();
12309 }
12310
12311 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name)
12312 {
12313         GstElement *element = NULL;
12314         GstPad *sinkpad;
12315
12316         LOGD("creating %s to plug\n", name);
12317
12318         element = gst_element_factory_make(name, NULL);
12319         if (!element) {
12320                 LOGE("failed to create queue\n");
12321                 return NULL;
12322         }
12323
12324         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(element, GST_STATE_READY)) {
12325                 LOGE("failed to set state READY to %s\n", name);
12326                 gst_object_unref(element);
12327                 return NULL;
12328         }
12329
12330         if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), element)) {
12331                 LOGE("failed to add %s\n", name);
12332                 gst_object_unref(element);
12333                 return NULL;
12334         }
12335
12336         sinkpad = gst_element_get_static_pad(element, "sink");
12337
12338         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
12339                 LOGE("failed to link %s\n", name);
12340                 gst_object_unref(sinkpad);
12341                 gst_object_unref(element);
12342                 return NULL;
12343         }
12344
12345         LOGD("linked %s to pipeline successfully\n", name);
12346
12347         gst_object_unref(sinkpad);
12348
12349         return element;
12350 }
12351
12352 static gboolean
12353 __mmplayer_close_link(mm_player_t* player, GstPad *srcpad, GstElement *sinkelement,
12354 const char *padname, const GList *templlist)
12355 {
12356         GstPad *pad = NULL;
12357         gboolean has_dynamic_pads = FALSE;
12358         gboolean has_many_types = FALSE;
12359         const char *klass = NULL;
12360         GstStaticPadTemplate *padtemplate = NULL;
12361         GstElementFactory *factory = NULL;
12362         GstElement* queue = NULL;
12363         GstElement* parser = NULL;
12364         GstPad *pssrcpad = NULL;
12365         GstPad *qsrcpad = NULL, *qsinkpad = NULL;
12366         MMPlayerGstElement *mainbin = NULL;
12367         GstStructure* str = NULL;
12368         GstCaps* srccaps = NULL;
12369         GstState target_state = GST_STATE_READY;
12370         gboolean isvideo_decoder = FALSE;
12371         guint q_max_size_time = 0;
12372
12373         MMPLAYER_FENTER();
12374
12375         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12376                 player->pipeline &&
12377                 player->pipeline->mainbin,
12378                 FALSE);
12379
12380         mainbin = player->pipeline->mainbin;
12381
12382         LOGD("plugging pad %s:%s to newly create %s:%s\n",
12383                         GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)),
12384                         GST_PAD_NAME(srcpad),
12385                         GST_ELEMENT_NAME(sinkelement),
12386                         padname);
12387
12388         factory = gst_element_get_factory(sinkelement);
12389         klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
12390
12391         /* check if player can do start continually */
12392         MMPLAYER_CHECK_CMD_IF_EXIT(player);
12393
12394         /* need it to warm up omx before linking to pipeline */
12395         if (g_strrstr(GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), "demux")) {
12396                 LOGD("get demux caps.\n");
12397                 if (player->state_tune_caps) {
12398                         gst_caps_unref(player->state_tune_caps);
12399                         player->state_tune_caps = NULL;
12400                 }
12401                 player->state_tune_caps = gst_caps_copy(gst_pad_get_current_caps(srcpad));
12402         }
12403
12404         /* NOTE : OMX Codec can check if resource is available or not at this state. */
12405         if (g_strrstr(GST_ELEMENT_NAME(sinkelement), "omx")) {
12406                 if (player->state_tune_caps != NULL) {
12407                         LOGD("set demux's caps to omx codec if resource is available");
12408                         if (gst_pad_set_caps(gst_element_get_static_pad(sinkelement, "sink"), player->state_tune_caps)) {
12409                                 target_state = GST_STATE_PAUSED;
12410                                 isvideo_decoder = TRUE;
12411                                 g_object_set(G_OBJECT(sinkelement), "state-tuning", TRUE, NULL);
12412                         } else
12413                                 LOGW("failed to set caps for state tuning");
12414                 }
12415                 gst_caps_unref(player->state_tune_caps);
12416                 player->state_tune_caps = NULL;
12417         }
12418
12419         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkelement, target_state)) {
12420                 LOGE("failed to set %d state to %s\n", target_state, GST_ELEMENT_NAME(sinkelement));
12421                 if (isvideo_decoder) {
12422                         gst_element_set_state(sinkelement, GST_STATE_NULL);
12423                         gst_object_unref(G_OBJECT(sinkelement));
12424                         player->keep_detecting_vcodec = TRUE;
12425                 }
12426                 goto ERROR;
12427         }
12428
12429         /* add to pipeline */
12430         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), sinkelement)) {
12431                 LOGE("failed to add %s to mainbin\n", GST_ELEMENT_NAME(sinkelement));
12432                 goto ERROR;
12433         }
12434
12435         LOGD("element klass : %s\n", klass);
12436
12437         /* added to support multi track files */
12438         /* only decoder case and any of the video/audio still need to link*/
12439         if (g_strrstr(klass, "Decoder") && __mmplayer_link_decoder(player, srcpad)) {
12440                 gchar *name = g_strdup(GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)));
12441
12442                 if (g_strrstr(name, "mpegtsdemux") || g_strrstr(name, "mssdemux")) {
12443                         gchar *src_demux_caps_str = NULL;
12444                         gchar *needed_parser = NULL;
12445                         GstCaps *src_demux_caps = NULL;
12446                         gboolean smooth_streaming = FALSE;
12447
12448                         src_demux_caps = gst_pad_query_caps(srcpad, NULL);
12449                         src_demux_caps_str = gst_caps_to_string(src_demux_caps);
12450
12451                         gst_caps_unref(src_demux_caps);
12452
12453                         if (g_strrstr(src_demux_caps_str, "video/x-h264")) {
12454                                 if (g_strrstr(name, "mssdemux")) {
12455                                         needed_parser = g_strdup("legacyh264parse");
12456                                         smooth_streaming = TRUE;
12457                                 } else
12458                                         needed_parser = g_strdup("h264parse");
12459                         } else if (g_strrstr(src_demux_caps_str, "video/mpeg"))
12460                                 needed_parser = g_strdup("mpeg4videoparse");
12461
12462                         MMPLAYER_FREEIF(src_demux_caps_str);
12463
12464                         if (needed_parser) {
12465                                 parser = __mmplayer_element_create_and_link(player, srcpad, needed_parser);
12466                                 MMPLAYER_FREEIF(needed_parser);
12467
12468                                 if (!parser) {
12469                                         LOGE("failed to create parser\n");
12470                                 } else {
12471                                         if (smooth_streaming)
12472                                                 g_object_set(parser, "output-format", 1, NULL); /* NALU/Byte Stream format */
12473
12474                                         /* update srcpad if parser is created */
12475                                         pssrcpad = gst_element_get_static_pad(parser, "src");
12476                                         srcpad = pssrcpad;
12477                                 }
12478                         }
12479                 }
12480                 MMPLAYER_FREEIF(name);
12481
12482                 queue = __mmplayer_element_create_and_link(player, srcpad, "queue"); // parser - queue or demuxer - queue
12483                 if (!queue) {
12484                         LOGE("failed to create queue\n");
12485                         goto ERROR;
12486                 }
12487
12488                 /* update srcpad to link with decoder */
12489                 qsrcpad = gst_element_get_static_pad(queue, "src");
12490                 srcpad = qsrcpad;
12491
12492                 q_max_size_time = GST_QUEUE_DEFAULT_TIME;
12493
12494                 /* assigning queue handle for futher manipulation purpose */
12495                 /* FIXIT : make it some kind of list so that msl can support more then two stream(text, data, etc...) */
12496                 if (mainbin[MMPLAYER_M_Q1].gst == NULL) {
12497                         mainbin[MMPLAYER_M_Q1].id = MMPLAYER_M_Q1;
12498                         mainbin[MMPLAYER_M_Q1].gst = queue;
12499
12500                         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_SS) {
12501                                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q1].gst), "max-size-time", 0 , NULL);
12502                                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q1].gst), "max-size-buffers", 2, NULL);
12503                                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q1].gst), "max-size-bytes", 0, NULL);
12504                         } else {
12505                                 if (!MMPLAYER_IS_RTSP_STREAMING(player))
12506                                         g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q1].gst), "max-size-time", q_max_size_time * GST_SECOND, NULL);
12507                         }
12508                 } else if (mainbin[MMPLAYER_M_Q2].gst == NULL) {
12509                         mainbin[MMPLAYER_M_Q2].id = MMPLAYER_M_Q2;
12510                         mainbin[MMPLAYER_M_Q2].gst = queue;
12511
12512                         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_SS) {
12513                                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q2].gst), "max-size-time", 0 , NULL);
12514                                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q2].gst), "max-size-buffers", 2, NULL);
12515                                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q2].gst), "max-size-bytes", 0, NULL);
12516                         } else {
12517                                 if (!MMPLAYER_IS_RTSP_STREAMING(player))
12518                                         g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q2].gst), "max-size-time", q_max_size_time * GST_SECOND, NULL);
12519                         }
12520                 } else {
12521                         LOGE("Not supporting more then two elementary stream\n");
12522                         g_assert(1);
12523                 }
12524
12525                 pad = gst_element_get_static_pad(sinkelement, padname);
12526
12527                 if (!pad) {
12528                         LOGW("failed to get pad(%s) from %s. retrying with [sink]\n",
12529                                 padname, GST_ELEMENT_NAME(sinkelement));
12530
12531                         pad = gst_element_get_static_pad(sinkelement, "sink");
12532                         if (!pad) {
12533                                 LOGE("failed to get pad(sink) from %s. \n",
12534                                 GST_ELEMENT_NAME(sinkelement));
12535                                 goto ERROR;
12536                         }
12537                 }
12538
12539                 /* to check the video/audio type set the proper flag*/
12540                 const gchar *mime_type = NULL;
12541                 srccaps = gst_pad_query_caps(srcpad, NULL);
12542                 if (!srccaps)
12543                         goto ERROR;
12544                 str = gst_caps_get_structure(srccaps, 0);
12545                 if (!str)
12546                         goto ERROR;
12547                 mime_type = gst_structure_get_name(str);
12548                 if (!mime_type)
12549                         goto ERROR;
12550
12551                 /* link queue and decoder. so, it will be queue - decoder. */
12552                 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, pad)) {
12553                         gst_object_unref(GST_OBJECT(pad));
12554                         LOGE("failed to link(%s) to pad(%s)\n", GST_ELEMENT_NAME(sinkelement), padname);
12555
12556                         /* reconstitute supportable codec */
12557                         if (strstr(mime_type, "video"))
12558                                 player->can_support_codec ^= FOUND_PLUGIN_VIDEO;
12559                         else if (strstr(mime_type, "audio"))
12560                                 player->can_support_codec ^= FOUND_PLUGIN_AUDIO;
12561                         goto ERROR;
12562                 }
12563
12564                 if (strstr(mime_type, "video")) {
12565                         player->videodec_linked = 1;
12566                         LOGI("player->videodec_linked set to 1\n");
12567
12568                 } else if (strstr(mime_type, "audio")) {
12569                         player->audiodec_linked = 1;
12570                         LOGI("player->auddiodec_linked set to 1\n");
12571                 }
12572
12573                 gst_object_unref(GST_OBJECT(pad));
12574                 gst_caps_unref(GST_CAPS(srccaps));
12575                 srccaps = NULL;
12576         }
12577
12578         if (!MMPLAYER_IS_HTTP_PD(player)) {
12579                 if ((g_strrstr(klass, "Demux") && !g_strrstr(klass, "Metadata")) || (g_strrstr(klass, "Parser"))) {
12580                         if (MMPLAYER_IS_HTTP_STREAMING(player)) {
12581                                 gint64 dur_bytes = 0L;
12582                                 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
12583
12584                                 if (!mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
12585                                         LOGD("creating http streaming buffering queue\n");
12586
12587                                         queue = gst_element_factory_make("queue2", "queue2");
12588                                         if (!queue) {
12589                                                 LOGE("failed to create buffering queue element\n");
12590                                                 goto ERROR;
12591                                         }
12592
12593                                         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_READY)) {
12594                                                 LOGE("failed to set state READY to buffering queue\n");
12595                                                 goto ERROR;
12596                                         }
12597
12598                                         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue)) {
12599                                                 LOGE("failed to add buffering queue\n");
12600                                                 goto ERROR;
12601                                         }
12602
12603                                         qsinkpad = gst_element_get_static_pad(queue, "sink");
12604                                         qsrcpad = gst_element_get_static_pad(queue, "src");
12605
12606                                         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, qsinkpad)) {
12607                                                 LOGE("failed to link buffering queue\n");
12608                                                 goto ERROR;
12609                                         }
12610                                         srcpad = qsrcpad;
12611
12612
12613                                         mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
12614                                         mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue;
12615
12616                                         if (!MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {
12617                                                 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
12618                                                         LOGE("fail to get duration.\n");
12619
12620                                                 if (dur_bytes > 0) {
12621                                                         if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
12622                                                                 type = MUXED_BUFFER_TYPE_FILE;
12623                                                         } else {
12624                                                                 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
12625                                                                 if (player->streamer)
12626                                                                         player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
12627                                                         }
12628                                                 } else {
12629                                                         dur_bytes = 0;
12630                                                 }
12631                                         }
12632
12633                                         /* NOTE : we cannot get any duration info from ts container in case of streaming */
12634                                         if (!g_strrstr(GST_ELEMENT_NAME(sinkelement), "mpegtsdemux")) {
12635                                                 __mm_player_streaming_set_queue2(player->streamer,
12636                                                         queue,
12637                                                         TRUE,
12638                                                         player->ini.http_max_size_bytes,
12639                                                         player->ini.http_buffering_time,
12640                                                         1.0,
12641                                                         player->ini.http_buffering_limit,
12642                                                         type,
12643                                                         player->http_file_buffering_path,
12644                                                         (guint64)dur_bytes);
12645                                         }
12646                                 }
12647                         }
12648                 }
12649         }
12650         /* if it is not decoder or */
12651         /* in decoder case any of the video/audio still need to link*/
12652         if (!g_strrstr(klass, "Decoder")) {
12653                 pad = gst_element_get_static_pad(sinkelement, padname);
12654                 if (!pad) {
12655                         LOGW("failed to get pad(%s) from %s. retrying with [sink]\n",
12656                                         padname, GST_ELEMENT_NAME(sinkelement));
12657
12658                         pad = gst_element_get_static_pad(sinkelement, "sink");
12659
12660                         if (!pad) {
12661                                 LOGE("failed to get pad(sink) from %s. \n",
12662                                         GST_ELEMENT_NAME(sinkelement));
12663                                 goto ERROR;
12664                         }
12665                 }
12666
12667                 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, pad)) {
12668                         gst_object_unref(GST_OBJECT(pad));
12669                         LOGE("failed to link(%s) to pad(%s)\n", GST_ELEMENT_NAME(sinkelement), padname);
12670                         goto ERROR;
12671                 }
12672
12673                 gst_object_unref(GST_OBJECT(pad));
12674         }
12675
12676         for (; templlist != NULL; templlist = templlist->next) {
12677                 padtemplate = templlist->data;
12678
12679                 LOGD("director = [%d], presence = [%d]\n", padtemplate->direction, padtemplate->presence);
12680
12681                 if (padtemplate->direction != GST_PAD_SRC ||
12682                         padtemplate->presence == GST_PAD_REQUEST)
12683                         continue;
12684
12685                 switch (padtemplate->presence) {
12686                 case GST_PAD_ALWAYS:
12687                         {
12688                                 GstPad *srcpad = gst_element_get_static_pad(sinkelement, "src");
12689                                 GstCaps *caps = gst_pad_query_caps(srcpad, NULL);
12690
12691                                 /* Check whether caps has many types */
12692                                 if (!gst_caps_is_fixed(caps)) {
12693                                         LOGD("always pad but, caps has many types");
12694                                         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
12695                                         has_many_types = TRUE;
12696                                         break;
12697                                 }
12698
12699                                 if (!__mmplayer_try_to_plug(player, srcpad, caps)) {
12700                                         gst_object_unref(GST_OBJECT(srcpad));
12701                                         gst_caps_unref(GST_CAPS(caps));
12702
12703                                         LOGE("failed to plug something after %s\n", GST_ELEMENT_NAME(sinkelement));
12704                                         goto ERROR;
12705                                 }
12706
12707                                 gst_caps_unref(GST_CAPS(caps));
12708                                 gst_object_unref(GST_OBJECT(srcpad));
12709
12710                         }
12711                         break;
12712
12713
12714                 case GST_PAD_SOMETIMES:
12715                         has_dynamic_pads = TRUE;
12716                         break;
12717
12718                 default:
12719                         break;
12720                 }
12721         }
12722
12723         /* check if player can do start continually */
12724         MMPLAYER_CHECK_CMD_IF_EXIT(player);
12725
12726         if (has_dynamic_pads) {
12727                 player->have_dynamic_pad = TRUE;
12728                 MMPLAYER_SIGNAL_CONNECT(player, sinkelement, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
12729                         G_CALLBACK(__mmplayer_add_new_pad), player);
12730
12731                 /* for streaming, more then one typefind will used for each elementary stream
12732                  * so this doesn't mean the whole pipeline completion
12733                  */
12734                 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
12735                         MMPLAYER_SIGNAL_CONNECT(player, sinkelement, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
12736                                 G_CALLBACK(__mmplayer_pipeline_complete), player);
12737                 }
12738         }
12739
12740         if (has_many_types) {
12741                 GstPad *pad = NULL;
12742
12743                 player->has_many_types = has_many_types;
12744
12745                 pad = gst_element_get_static_pad(sinkelement, "src");
12746                 MMPLAYER_SIGNAL_CONNECT(player, pad, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "notify::caps", G_CALLBACK(__mmplayer_add_new_caps), player);
12747                 gst_object_unref(GST_OBJECT(pad));
12748         }
12749
12750
12751         /* check if player can do start continually */
12752         MMPLAYER_CHECK_CMD_IF_EXIT(player);
12753
12754         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkelement, GST_STATE_PAUSED)) {
12755                 LOGE("failed to set state PAUSED to %s\n", GST_ELEMENT_NAME(sinkelement));
12756                 goto ERROR;
12757         }
12758
12759         if (queue) {
12760                 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_PAUSED)) {
12761                         LOGE("failed to set state PAUSED to queue\n");
12762                         goto ERROR;
12763                 }
12764
12765                 queue = NULL;
12766
12767                 gst_object_unref(GST_OBJECT(qsrcpad));
12768                 qsrcpad = NULL;
12769         }
12770
12771         if (parser) {
12772                 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(parser, GST_STATE_PAUSED)) {
12773                         LOGE("failed to set state PAUSED to queue\n");
12774                         goto ERROR;
12775                 }
12776
12777                 parser = NULL;
12778
12779                 gst_object_unref(GST_OBJECT(pssrcpad));
12780                 pssrcpad = NULL;
12781         }
12782
12783         MMPLAYER_FLEAVE();
12784
12785         return TRUE;
12786
12787 ERROR:
12788
12789         if (queue) {
12790                 gst_object_unref(GST_OBJECT(qsrcpad));
12791
12792                 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
12793                  * You need to explicitly set elements to the NULL state before
12794                  * dropping the final reference, to allow them to clean up.
12795                  */
12796                 gst_element_set_state(queue, GST_STATE_NULL);
12797                 /* And, it still has a parent "player".
12798                  * You need to let the parent manage the object instead of unreffing the object directly.
12799                  */
12800
12801                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue);
12802                 //gst_object_unref(queue);
12803         }
12804
12805         if (srccaps)
12806                 gst_caps_unref(GST_CAPS(srccaps));
12807
12808         return FALSE;
12809 }
12810
12811 static gboolean __mmplayer_feature_filter(GstPluginFeature *feature, gpointer data) // @
12812 {
12813         const gchar *klass;
12814
12815         /* we only care about element factories */
12816         if (!GST_IS_ELEMENT_FACTORY(feature))
12817                 return FALSE;
12818
12819         /* only parsers, demuxers and decoders */
12820                 klass = gst_element_factory_get_metadata(GST_ELEMENT_FACTORY(feature), GST_ELEMENT_METADATA_KLASS);
12821
12822         if (g_strrstr(klass, "Demux") == NULL &&
12823                         g_strrstr(klass, "Codec/Decoder") == NULL &&
12824                         g_strrstr(klass, "Depayloader") == NULL &&
12825                         g_strrstr(klass, "Parse") == NULL)
12826                 return FALSE;
12827         return TRUE;
12828 }
12829
12830
12831 static void     __mmplayer_add_new_caps(GstPad* pad, GParamSpec* unused, gpointer data)
12832 {
12833         mm_player_t* player = (mm_player_t*) data;
12834         GstCaps *caps = NULL;
12835         GstStructure *str = NULL;
12836         const char *name;
12837
12838         MMPLAYER_FENTER();
12839
12840         MMPLAYER_RETURN_IF_FAIL(pad)
12841         MMPLAYER_RETURN_IF_FAIL(unused)
12842         MMPLAYER_RETURN_IF_FAIL(data)
12843
12844         caps = gst_pad_query_caps(pad, NULL);
12845         if (!caps)
12846                 return;
12847
12848         str = gst_caps_get_structure(caps, 0);
12849         if (!str)
12850                 return;
12851
12852         name = gst_structure_get_name(str);
12853         if (!name)
12854                 return;
12855         LOGD("name=%s\n", name);
12856
12857         if (!__mmplayer_try_to_plug(player, pad, caps)) {
12858                 LOGE("failed to autoplug for type(%s)\n", name);
12859                 gst_caps_unref(caps);
12860                 return;
12861         }
12862
12863         gst_caps_unref(caps);
12864
12865         __mmplayer_pipeline_complete(NULL, (gpointer)player);
12866
12867         MMPLAYER_FLEAVE();
12868
12869         return;
12870 }
12871
12872 static void __mmplayer_set_unlinked_mime_type(mm_player_t* player, GstCaps *caps)
12873 {
12874         GstStructure *str;
12875         gint version = 0;
12876         const char *stream_type;
12877         gchar *version_field = NULL;
12878
12879         MMPLAYER_FENTER();
12880
12881         MMPLAYER_RETURN_IF_FAIL(player);
12882         MMPLAYER_RETURN_IF_FAIL(caps);
12883
12884         str = gst_caps_get_structure(caps, 0);
12885         if (!str)
12886                 return;
12887
12888         stream_type = gst_structure_get_name(str);
12889         if (!stream_type)
12890                 return;
12891
12892
12893         /* set unlinked mime type for downloadable codec */
12894         if (g_str_has_prefix(stream_type, "video/")) {
12895                 if (g_str_has_prefix(stream_type, "video/mpeg")) {
12896                         gst_structure_get_int(str, MM_PLAYER_MPEG_VNAME, &version);
12897                         version_field = MM_PLAYER_MPEG_VNAME;
12898                 } else if (g_str_has_prefix(stream_type, "video/x-wmv")) {
12899                         gst_structure_get_int(str, MM_PLAYER_WMV_VNAME, &version);
12900                         version_field = MM_PLAYER_WMV_VNAME;
12901
12902                 } else if (g_str_has_prefix(stream_type, "video/x-divx")) {
12903                         gst_structure_get_int(str, MM_PLAYER_DIVX_VNAME, &version);
12904                         version_field = MM_PLAYER_DIVX_VNAME;
12905                 }
12906
12907                 if (version)
12908                         player->unlinked_video_mime = g_strdup_printf("%s, %s=%d", stream_type, version_field, version);
12909                 else
12910                         player->unlinked_video_mime = g_strdup_printf("%s", stream_type);
12911         } else if (g_str_has_prefix(stream_type, "audio/")) {
12912                 if (g_str_has_prefix(stream_type, "audio/mpeg")) {
12913                         // mp3 or aac
12914                         gst_structure_get_int(str, MM_PLAYER_MPEG_VNAME, &version);
12915                         version_field = MM_PLAYER_MPEG_VNAME;
12916                 } else if (g_str_has_prefix(stream_type, "audio/x-wma")) {
12917                         gst_structure_get_int(str, MM_PLAYER_WMA_VNAME, &version);
12918                         version_field = MM_PLAYER_WMA_VNAME;
12919                 }
12920
12921                 if (version)
12922                         player->unlinked_audio_mime = g_strdup_printf("%s, %s=%d", stream_type, version_field, version);
12923                 else
12924                         player->unlinked_audio_mime = g_strdup_printf("%s", stream_type);
12925         }
12926
12927         MMPLAYER_FLEAVE();
12928 }
12929
12930 static void __mmplayer_add_new_pad(GstElement *element, GstPad *pad, gpointer data)
12931 {
12932         mm_player_t* player = (mm_player_t*) data;
12933         GstCaps *caps = NULL;
12934         GstStructure *str = NULL;
12935         const char *name;
12936
12937         MMPLAYER_FENTER();
12938         MMPLAYER_RETURN_IF_FAIL(player);
12939         MMPLAYER_RETURN_IF_FAIL(pad);
12940
12941         GST_OBJECT_LOCK(pad);
12942         if ((caps = gst_pad_get_current_caps(pad)))
12943                 gst_caps_ref(caps);
12944         GST_OBJECT_UNLOCK(pad);
12945
12946         if (NULL == caps) {
12947                 caps = gst_pad_query_caps(pad, NULL);
12948                 if (!caps) return;
12949         }
12950
12951         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
12952
12953         str = gst_caps_get_structure(caps, 0);
12954         if (!str)
12955                 return;
12956
12957         name = gst_structure_get_name(str);
12958         if (!name)
12959                 return;
12960
12961         player->num_dynamic_pad++;
12962         LOGD("stream count inc : %d\n", player->num_dynamic_pad);
12963
12964         /* Note : If the stream is the subtitle, we try not to play it. Just close the demuxer subtitle pad.
12965           *     If want to play it, remove this code.
12966           */
12967         if (g_strrstr(name, "application")) {
12968                 if (g_strrstr(name, "x-id3") || g_strrstr(name, "x-apetag")) {
12969                         /* If id3/ape tag comes, keep going */
12970                         LOGD("application mime exception : id3/ape tag");
12971                 } else {
12972                         /* Otherwise, we assume that this stream is subtile. */
12973                         LOGD(" application mime type pad is closed.");
12974                         return;
12975                 }
12976         } else if (g_strrstr(name, "audio")) {
12977                 gint samplerate = 0, channels = 0;
12978
12979                 if (player->audiodec_linked) {
12980                         gst_caps_unref(caps);
12981                         LOGD("multi tracks. skip to plug");
12982                         return;
12983                 }
12984
12985                 /* set stream information */
12986                 /* if possible, set it here because the caps is not distrubed by resampler. */
12987                 gst_structure_get_int(str, "rate", &samplerate);
12988                 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
12989
12990                 gst_structure_get_int(str, "channels", &channels);
12991                 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
12992
12993                 LOGD("audio samplerate : %d     channels : %d", samplerate, channels);
12994         } else if (g_strrstr(name, "video")) {
12995                 gint stype;
12996                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
12997
12998                 /* don't make video because of not required */
12999                 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
13000                         LOGD("no video because it's not required");
13001                         return;
13002                 }
13003
13004                 player->v_stream_caps = gst_caps_copy(caps); //if needed, video caps is required when videobin is created
13005         }
13006
13007         if (!__mmplayer_try_to_plug(player, pad, caps)) {
13008                 LOGE("failed to autoplug for type(%s)", name);
13009
13010                 __mmplayer_set_unlinked_mime_type(player, caps);
13011         }
13012
13013         gst_caps_unref(caps);
13014
13015         MMPLAYER_FLEAVE();
13016         return;
13017 }
13018
13019 gboolean
13020 __mmplayer_check_subtitle(mm_player_t* player)
13021 {
13022         MMHandleType attrs = 0;
13023         char *subtitle_uri = NULL;
13024
13025         MMPLAYER_FENTER();
13026
13027         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13028
13029         /* get subtitle attribute */
13030         attrs = MMPLAYER_GET_ATTRS(player);
13031         if (!attrs)
13032                 return FALSE;
13033
13034         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
13035         if (!subtitle_uri || !strlen(subtitle_uri))
13036                 return FALSE;
13037
13038         LOGD("subtite uri is %s[%d]\n", subtitle_uri, strlen(subtitle_uri));
13039         player->is_external_subtitle_present = TRUE;
13040
13041         MMPLAYER_FLEAVE();
13042
13043         return TRUE;
13044 }
13045
13046 static gboolean
13047 __mmplayer_can_extract_pcm(mm_player_t* player)
13048 {
13049         MMHandleType attrs = 0;
13050         gboolean sound_extraction = FALSE;
13051
13052         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13053
13054         attrs = MMPLAYER_GET_ATTRS(player);
13055         if (!attrs) {
13056                 LOGE("fail to get attributes.");
13057                 return FALSE;
13058         }
13059
13060         /* get sound_extraction property */
13061         mm_attrs_get_int_by_name(attrs, "pcm_extraction", &sound_extraction);
13062
13063         if (!sound_extraction) {
13064                 LOGD("checking pcm extraction mode : %d ", sound_extraction);
13065                 return FALSE;
13066         }
13067
13068         return TRUE;
13069 }
13070
13071 static gboolean
13072 __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message)
13073 {
13074         LOGD("\n");
13075         MMMessageParamType msg_param;
13076         gchar *msg_src_element = NULL;
13077         GstStructure *s = NULL;
13078         guint error_id = 0;
13079         gchar *error_string = NULL;
13080
13081         MMPLAYER_FENTER();
13082
13083         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13084         MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
13085
13086         s = malloc(sizeof(GstStructure));
13087         memcpy(s, gst_message_get_structure(message), sizeof(GstStructure));
13088
13089         if (!gst_structure_get_uint(s, "error_id", &error_id))
13090                 error_id = MMPLAYER_STREAMING_ERROR_NONE;
13091
13092         switch (error_id) {
13093         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
13094                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
13095                 break;
13096         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
13097                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
13098                 break;
13099         case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
13100                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
13101                 break;
13102         case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
13103                 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
13104                 break;
13105         case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
13106                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
13107                 break;
13108         case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
13109                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
13110                 break;
13111         case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
13112                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
13113                 break;
13114         case MMPLAYER_STREAMING_ERROR_INVALID_URL:
13115                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
13116                 break;
13117         case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
13118                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
13119                 break;
13120         case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
13121                 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
13122                 break;
13123         case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
13124                 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
13125                 break;
13126         case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
13127                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
13128                 break;
13129         case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
13130                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
13131                 break;
13132         case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
13133                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
13134                 break;
13135         case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
13136                 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
13137                 break;
13138         case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
13139                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
13140                 break;
13141         case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
13142                 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
13143                 break;
13144         case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
13145                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
13146                 break;
13147         case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
13148                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
13149                 break;
13150         case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
13151                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
13152                 break;
13153         case MMPLAYER_STREAMING_ERROR_GONE:
13154                 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
13155                 break;
13156         case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
13157                 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
13158                 break;
13159         case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
13160                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
13161                 break;
13162         case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
13163                 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
13164                 break;
13165         case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
13166                 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
13167                 break;
13168         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
13169                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
13170                 break;
13171         case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
13172                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
13173                 break;
13174         case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
13175                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
13176                 break;
13177         case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
13178                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
13179                 break;
13180         case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
13181                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
13182                 break;
13183         case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
13184                 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
13185                 break;
13186         case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
13187                 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
13188                 break;
13189         case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
13190                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
13191                 break;
13192         case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
13193                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
13194                 break;
13195         case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
13196                 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
13197                 break;
13198         case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
13199                 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
13200                 break;
13201         case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
13202                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
13203                 break;
13204         case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
13205                 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
13206                 break;
13207         case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
13208                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
13209                 break;
13210         case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
13211                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
13212                 break;
13213         case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
13214                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
13215                 break;
13216         case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
13217                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
13218                 break;
13219         case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
13220                 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
13221                 break;
13222         case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
13223                 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
13224                 break;
13225         case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
13226                 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
13227                 break;
13228         default:
13229                 {
13230                         MMPLAYER_FREEIF(s);
13231                         return MM_ERROR_PLAYER_STREAMING_FAIL;
13232                 }
13233         }
13234
13235         error_string = g_strdup(gst_structure_get_string(s, "error_string"));
13236         if (error_string)
13237                 msg_param.data = (void *) error_string;
13238
13239         if (message->src) {
13240                 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
13241
13242                 LOGE("-Msg src : [%s] Code : [%x] Error : [%s]  \n",
13243                         msg_src_element, msg_param.code, (char*)msg_param.data);
13244         }
13245
13246         /* post error to application */
13247         if (!player->msg_posted) {
13248                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
13249
13250                 /* don't post more if one was sent already */
13251                 player->msg_posted = TRUE;
13252         } else
13253                 LOGD("skip error post because it's sent already.\n");
13254
13255         MMPLAYER_FREEIF(s);
13256         MMPLAYER_FLEAVE();
13257         g_free(error_string);
13258
13259         return TRUE;
13260
13261 }
13262
13263 static void
13264 __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms)
13265 {
13266         MMPLAYER_RETURN_IF_FAIL(player);
13267
13268
13269         /* post now if delay is zero */
13270         if (delay_in_ms == 0 || player->set_mode.pcm_extraction) {
13271                 LOGD("eos delay is zero. posting EOS now\n");
13272                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
13273
13274                 if (player->set_mode.pcm_extraction)
13275                         __mmplayer_cancel_eos_timer(player);
13276
13277                 return;
13278         }
13279
13280         /* cancel if existing */
13281         __mmplayer_cancel_eos_timer(player);
13282
13283         /* init new timeout */
13284         /* NOTE : consider give high priority to this timer */
13285         LOGD("posting EOS message after [%d] msec\n", delay_in_ms);
13286
13287         player->eos_timer = g_timeout_add(delay_in_ms,
13288                 __mmplayer_eos_timer_cb, player);
13289
13290         player->context.global_default = g_main_context_default();
13291         LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
13292
13293         /* check timer is valid. if not, send EOS now */
13294         if (player->eos_timer == 0) {
13295                 LOGW("creating timer for delayed EOS has failed. sending EOS now\n");
13296                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
13297         }
13298 }
13299
13300 static void
13301 __mmplayer_cancel_eos_timer(mm_player_t* player)
13302 {
13303         MMPLAYER_RETURN_IF_FAIL(player);
13304
13305         if (player->eos_timer) {
13306                 LOGD("cancel eos timer");
13307                 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
13308                 player->eos_timer = 0;
13309         }
13310
13311         return;
13312 }
13313
13314 static gboolean
13315 __mmplayer_eos_timer_cb(gpointer u_data)
13316 {
13317         mm_player_t* player = NULL;
13318         player = (mm_player_t*) u_data;
13319
13320         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13321
13322         if (player->play_count > 1) {
13323                 gint ret_value = 0;
13324                 ret_value = __gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, 0, TRUE);
13325                 if (ret_value == MM_ERROR_NONE) {
13326                         MMHandleType attrs = 0;
13327                         attrs = MMPLAYER_GET_ATTRS(player);
13328
13329                         /* we successeded to rewind. update play count and then wait for next EOS */
13330                         player->play_count--;
13331
13332                         mm_attrs_set_int_by_name(attrs, "profile_play_count", player->play_count);
13333                         mmf_attrs_commit(attrs);
13334                 } else
13335                         LOGE("seeking to 0 failed in repeat play");
13336         } else
13337                 /* posting eos */
13338                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
13339
13340         /* we are returning FALSE as we need only one posting */
13341         return FALSE;
13342 }
13343
13344 static gboolean
13345 __mmplayer_link_decoder(mm_player_t* player, GstPad *srcpad)
13346 {
13347         const gchar* name = NULL;
13348         GstStructure* str = NULL;
13349         GstCaps* srccaps = NULL;
13350
13351         MMPLAYER_FENTER();
13352
13353         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13354         MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
13355
13356         /* to check any of the decoder(video/audio) need to be linked  to parser*/
13357         srccaps = gst_pad_query_caps(srcpad, NULL);
13358         if (!srccaps)
13359                 goto ERROR;
13360
13361         str = gst_caps_get_structure(srccaps, 0);
13362         if (!str)
13363                 goto ERROR;
13364
13365         name = gst_structure_get_name(str);
13366         if (!name)
13367                 goto ERROR;
13368
13369         if (strstr(name, "video")) {
13370                 if (player->videodec_linked) {
13371                     LOGI("Video decoder already linked\n");
13372                         return FALSE;
13373                 }
13374         }
13375         if (strstr(name, "audio")) {
13376                 if (player->audiodec_linked) {
13377                     LOGI("Audio decoder already linked\n");
13378                         return FALSE;
13379                 }
13380         }
13381
13382         gst_caps_unref(srccaps);
13383
13384         MMPLAYER_FLEAVE();
13385
13386         return TRUE;
13387
13388 ERROR:
13389         if (srccaps)
13390                 gst_caps_unref(srccaps);
13391
13392         return FALSE;
13393 }
13394
13395 static gboolean
13396 __mmplayer_link_sink(mm_player_t* player , GstPad *srcpad)
13397 {
13398         const gchar* name = NULL;
13399         GstStructure* str = NULL;
13400         GstCaps* srccaps = NULL;
13401
13402         MMPLAYER_FENTER();
13403
13404         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13405         MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
13406
13407         /* to check any of the decoder(video/audio) need to be linked   to parser*/
13408         srccaps = gst_pad_query_caps(srcpad, NULL);
13409         if (!srccaps)
13410                 goto ERROR;
13411
13412         str = gst_caps_get_structure(srccaps, 0);
13413         if (!str)
13414                 goto ERROR;
13415
13416         name = gst_structure_get_name(str);
13417         if (!name)
13418                 goto ERROR;
13419
13420         if (strstr(name, "video")) {
13421                 if (player->videosink_linked) {
13422                         LOGI("Video Sink already linked\n");
13423                         return FALSE;
13424                 }
13425         }
13426         if (strstr(name, "audio")) {
13427                 if (player->audiosink_linked) {
13428                         LOGI("Audio Sink already linked\n");
13429                         return FALSE;
13430                 }
13431         }
13432         if (strstr(name, "text")) {
13433                 if (player->textsink_linked) {
13434                         LOGI("Text Sink already linked\n");
13435                         return FALSE;
13436                 }
13437         }
13438
13439         gst_caps_unref(srccaps);
13440
13441         MMPLAYER_FLEAVE();
13442
13443         //return (!player->videosink_linked || !player->audiosink_linked);
13444         return TRUE;
13445
13446 ERROR:
13447         if (srccaps)
13448                 gst_caps_unref(srccaps);
13449
13450         return FALSE;
13451 }
13452
13453
13454 /* sending event to one of sinkelements */
13455 static gboolean
13456 __gst_send_event_to_sink(mm_player_t* player, GstEvent* event)
13457 {
13458         GstEvent * event2 = NULL;
13459         GList *sinks = NULL;
13460         gboolean res = FALSE;
13461         MMPLAYER_FENTER();
13462
13463         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13464         MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
13465
13466         /* While adding subtitles in live feeds seek is getting called.
13467            Adding defensive check in framework layer.*/
13468         if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
13469                 if (MMPLAYER_IS_LIVE_STREAMING (player)) {
13470                         LOGE ("Should not send seek event during live playback");
13471                         return TRUE;
13472                 }
13473         }
13474
13475         if (player->play_subtitle && !player->use_textoverlay)
13476                 event2 = gst_event_copy((const GstEvent *)event);
13477
13478         sinks = player->sink_elements;
13479         while (sinks) {
13480                 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
13481
13482                 if (GST_IS_ELEMENT(sink)) {
13483                         /* keep ref to the event */
13484                         gst_event_ref(event);
13485
13486                         if ((res = gst_element_send_event(sink, event))) {
13487                                 LOGD("sending event[%s] to sink element [%s] success!\n",
13488                                         GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
13489
13490                                 /* rtsp case, asyn_done is not called after seek during pause state */
13491                                 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
13492                                         if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
13493                                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
13494                                                         LOGD("RTSP seek completed, after pause state..\n");
13495                                                         player->doing_seek = FALSE;
13496                                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
13497                                                 }
13498
13499                                         }
13500                                 }
13501
13502                                 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
13503                                         sinks = g_list_next(sinks);
13504                                         continue;
13505                                 } else
13506                                         break;
13507                         }
13508
13509                         LOGD("sending event[%s] to sink element [%s] failed. try with next one.\n",
13510                                 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
13511                 }
13512
13513                 sinks = g_list_next(sinks);
13514         }
13515
13516 #if 0
13517         if (internal_sub)
13518           request pad name = sink0;
13519         else
13520           request pad name = sink1; // external
13521 #endif
13522
13523         /* Note : Textbin is not linked to the video or audio bin.
13524          * It needs to send the event to the text sink seperatelly.
13525          */
13526          if (player->play_subtitle && !player->use_textoverlay) {
13527                 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
13528
13529                 if (GST_IS_ELEMENT(text_sink)) {
13530                         /* keep ref to the event */
13531                         gst_event_ref(event2);
13532
13533                         if ((res = gst_element_send_event(text_sink, event2)))
13534                                 LOGD("sending event[%s] to subtitle sink element [%s] success!\n",
13535                                         GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
13536                         else
13537                                 LOGE("sending event[%s] to subtitle sink element [%s] failed!\n",
13538                                         GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
13539
13540                         gst_event_unref(event2);
13541                 }
13542          }
13543
13544         gst_event_unref(event);
13545
13546         MMPLAYER_FLEAVE();
13547
13548         return res;
13549 }
13550
13551 static void
13552 __mmplayer_add_sink(mm_player_t* player, GstElement* sink)
13553 {
13554         MMPLAYER_FENTER();
13555
13556         MMPLAYER_RETURN_IF_FAIL(player);
13557         MMPLAYER_RETURN_IF_FAIL(sink);
13558
13559         player->sink_elements =
13560                 g_list_append(player->sink_elements, sink);
13561
13562         MMPLAYER_FLEAVE();
13563 }
13564
13565 static void
13566 __mmplayer_del_sink(mm_player_t* player, GstElement* sink)
13567 {
13568         MMPLAYER_FENTER();
13569
13570         MMPLAYER_RETURN_IF_FAIL(player);
13571         MMPLAYER_RETURN_IF_FAIL(sink);
13572
13573         player->sink_elements =
13574                         g_list_remove(player->sink_elements, sink);
13575
13576         MMPLAYER_FLEAVE();
13577 }
13578
13579 static gboolean
13580 __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
13581                         GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
13582                         gint64 cur, GstSeekType stop_type, gint64 stop)
13583 {
13584         GstEvent* event = NULL;
13585         gboolean result = FALSE;
13586
13587         MMPLAYER_FENTER();
13588
13589         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13590
13591         if (player->pipeline && player->pipeline->textbin)
13592                 __mmplayer_drop_subtitle(player, FALSE);
13593
13594         event = gst_event_new_seek(rate, format, flags, cur_type,
13595                 cur, stop_type, stop);
13596
13597         result = __gst_send_event_to_sink(player, event);
13598
13599         MMPLAYER_FLEAVE();
13600
13601         return result;
13602 }
13603
13604 /* NOTE : be careful with calling this api. please refer to below glib comment
13605  * glib comment : Note that there is a bug in GObject that makes this function much
13606  * less useful than it might seem otherwise. Once gobject is disposed, the callback
13607  * will no longer be called, but, the signal handler is not currently disconnected.
13608  * If the instance is itself being freed at the same time than this doesn't matter,
13609  * since the signal will automatically be removed, but if instance persists,
13610  * then the signal handler will leak. You should not remove the signal yourself
13611  * because in a future versions of GObject, the handler will automatically be
13612  * disconnected.
13613  *
13614  * It's possible to work around this problem in a way that will continue to work
13615  * with future versions of GObject by checking that the signal handler is still
13616  * connected before disconnected it:
13617  *
13618  *  if (g_signal_handler_is_connected(instance, id))
13619  *    g_signal_handler_disconnect(instance, id);
13620  */
13621 static void
13622 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
13623 {
13624         GList* sig_list = NULL;
13625         MMPlayerSignalItem* item = NULL;
13626
13627         MMPLAYER_FENTER();
13628
13629         MMPLAYER_RETURN_IF_FAIL(player);
13630
13631         LOGD("release signals type : %d", type);
13632
13633         if ((type < MM_PLAYER_SIGNAL_TYPE_AUTOPLUG) || (type >= MM_PLAYER_SIGNAL_TYPE_ALL)) {
13634                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
13635                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
13636                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
13637                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
13638                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
13639                 return;
13640         }
13641
13642         sig_list = player->signals[type];
13643
13644         for (; sig_list; sig_list = sig_list->next) {
13645                 item = sig_list->data;
13646
13647                 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
13648                         if (g_signal_handler_is_connected(item->obj, item->sig))
13649                                 g_signal_handler_disconnect(item->obj, item->sig);
13650                 }
13651
13652                 MMPLAYER_FREEIF(item);
13653         }
13654
13655         g_list_free(player->signals[type]);
13656         player->signals[type] = NULL;
13657
13658         MMPLAYER_FLEAVE();
13659
13660         return;
13661 }
13662
13663 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
13664 {
13665         mm_player_t* player = 0;
13666         int prev_display_surface_type = 0;
13667         void *prev_display_overlay = NULL;
13668         const gchar *klass = NULL;
13669         gchar *cur_videosink_name = NULL;
13670         int ret = 0;
13671         int i = 0;
13672         int num_of_dec = 2; /* DEC1, DEC2 */
13673
13674         MMPLAYER_FENTER();
13675
13676         MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
13677         MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
13678
13679         player = MM_PLAYER_CAST(handle);
13680
13681         if (surface_type < MM_DISPLAY_SURFACE_OVERLAY || surface_type >= MM_DISPLAY_SURFACE_NUM) {
13682                 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
13683                 MMPLAYER_FLEAVE();
13684                 return MM_ERROR_INVALID_ARGUMENT;
13685         }
13686
13687         /* load previous attributes */
13688         if (player->attrs) {
13689                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
13690                 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
13691                 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
13692                 if (prev_display_surface_type == surface_type) {
13693                         LOGD("incoming display surface type is same as previous one, do nothing..");
13694                         MMPLAYER_FLEAVE();
13695                         return MM_ERROR_NONE;
13696                 }
13697         } else {
13698                 LOGE("failed to load attributes");
13699                 MMPLAYER_FLEAVE();
13700                 return MM_ERROR_PLAYER_INTERNAL;
13701         }
13702
13703         /* check videosink element is created */
13704         if (!player->pipeline || !player->pipeline->videobin ||
13705                 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
13706                 LOGD("videosink element is not yet ready");
13707
13708                 /* videobin is not created yet, so we just set attributes related to display surface */
13709                 LOGD("store display attribute for given surface type(%d)", surface_type);
13710                 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
13711                 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
13712                 if (mmf_attrs_commit(player->attrs)) {
13713                         LOGE("failed to commit attribute");
13714                         MMPLAYER_FLEAVE();
13715                         return MM_ERROR_PLAYER_INTERNAL;
13716                 }
13717                 MMPLAYER_FLEAVE();
13718                 return MM_ERROR_NONE;
13719         } else {
13720                 /* get player command status */
13721                 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME || player->cmd == MMPLAYER_COMMAND_PAUSE)) {
13722                         LOGE("invalid player command status(%d), __mmplayer_do_change_videosink() is only available with START/RESUME/PAUSE command", player->cmd);
13723                         MMPLAYER_FLEAVE();
13724                         return MM_ERROR_PLAYER_INVALID_STATE;
13725                 }
13726
13727                 /* surface change */
13728                 for (i = 0 ; i < num_of_dec ; i++) {
13729                         if (player->pipeline->mainbin &&
13730                                 player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst) {
13731                                 GstElementFactory *decfactory;
13732                                 decfactory = gst_element_get_factory(player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst);
13733
13734                                 klass = gst_element_factory_get_metadata(decfactory, GST_ELEMENT_METADATA_KLASS);
13735                                 if ((g_strrstr(klass, "Codec/Decoder/Video"))) {
13736                                         if ((prev_display_surface_type == MM_DISPLAY_SURFACE_OVERLAY) && (surface_type == MM_DISPLAY_SURFACE_REMOTE)) {
13737                                                 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, "fakesink", surface_type, display_overlay);
13738                                                 if (ret) {
13739                                                         goto ERROR_CASE;
13740                                                 } else {
13741                                                         LOGW("success to changing display surface(%d)", surface_type);
13742                                                         MMPLAYER_FLEAVE();
13743                                                         return MM_ERROR_NONE;
13744                                                 }
13745                                         } else if ((prev_display_surface_type == MM_DISPLAY_SURFACE_REMOTE) && (surface_type == MM_DISPLAY_SURFACE_OVERLAY)) {
13746                                                 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, player->ini.videosink_element_overlay, surface_type, display_overlay);
13747                                                 if (ret) {
13748                                                         goto ERROR_CASE;
13749                                                 } else {
13750                                                         LOGW("success to changing display surface(%d)", surface_type);
13751                                                         MMPLAYER_FLEAVE();
13752                                                         return MM_ERROR_NONE;
13753                                                 }
13754                                         } else {
13755                                                 LOGE("invalid incoming surface type(%d) and current videosink_name(%s) for changing display surface", surface_type, cur_videosink_name);
13756                                                 ret = MM_ERROR_PLAYER_INTERNAL;
13757                                                 goto ERROR_CASE;
13758                                         }
13759                                 }
13760                         }
13761                 }
13762         }
13763
13764 ERROR_CASE:
13765         /* rollback to previous attributes */
13766         mm_attrs_set_int_by_name(player->attrs, "display_surface_type", prev_display_surface_type);
13767         mm_attrs_set_data_by_name(player->attrs, "display_overlay", prev_display_overlay, sizeof(void*));
13768         if (mmf_attrs_commit(player->attrs)) {
13769                 LOGE("failed to commit attributes to rollback");
13770                 MMPLAYER_FLEAVE();
13771                 return MM_ERROR_PLAYER_INTERNAL;
13772         }
13773         MMPLAYER_FLEAVE();
13774         return ret;
13775 }
13776
13777 /* NOTE : It does not support some use cases, eg using colorspace converter */
13778 int
13779 __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay)
13780 {
13781         GstPad *src_pad_dec = NULL;
13782         GstPad *sink_pad_videosink = NULL;
13783         GstPad *sink_pad_videobin = NULL;
13784         GstClock *clock = NULL;
13785         MMPlayerStateType previous_state = MM_PLAYER_STATE_NUM;
13786         int ret = MM_ERROR_NONE;
13787         gboolean is_audiobin_created = TRUE;
13788
13789         MMPLAYER_FENTER();
13790
13791         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_COMMON_INVALID_ARGUMENT);
13792         MMPLAYER_RETURN_VAL_IF_FAIL(videosink_element, MM_ERROR_COMMON_INVALID_ARGUMENT);
13793         MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
13794
13795         LOGD("video dec is found(idx:%d), we are going to change videosink to %s", dec_index, videosink_element);
13796         LOGD("surface type(%d), display overlay(%x)", surface_type, display_overlay);
13797
13798         /* get information whether if audiobin is created */
13799         if (!player->pipeline->audiobin ||
13800                      !player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
13801                 LOGW("audiobin is null, this video content may not have audio data");
13802                 is_audiobin_created = FALSE;
13803         }
13804
13805         /* get current state of player */
13806         previous_state = MMPLAYER_CURRENT_STATE(player);
13807         LOGD("previous state(%d)", previous_state);
13808
13809
13810         /* get src pad of decoder and block it */
13811         src_pad_dec = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), "src");
13812         if (!src_pad_dec) {
13813                 LOGE("failed to get src pad from decode in mainbin");
13814                 return MM_ERROR_PLAYER_INTERNAL;
13815         }
13816
13817         if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
13818                 LOGW("trying to block pad(video)");
13819 //              if (!gst_pad_set_blocked(src_pad_dec, TRUE))
13820                 gst_pad_add_probe(src_pad_dec, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
13821                         NULL, NULL, NULL);
13822                 {
13823                         LOGE("failed to set block pad(video)");
13824                         return MM_ERROR_PLAYER_INTERNAL;
13825                 }
13826                 LOGW("pad is blocked(video)");
13827         } else {
13828                 /* no data flows, so no need to do pad_block */
13829                 if (player->doing_seek)
13830                         LOGW("not completed seek(%d), do nothing", player->doing_seek);
13831
13832                 LOGD("MM_PLAYER_STATE is not PLAYING now, skip pad-block(TRUE)");
13833         }
13834
13835         /* remove pad */
13836         if (!gst_element_remove_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst,
13837                 GST_PAD_CAST(GST_GHOST_PAD(player->ghost_pad_for_videobin)))) {
13838                 LOGE("failed to remove previous ghost_pad for videobin");
13839                 return MM_ERROR_PLAYER_INTERNAL;
13840         }
13841
13842         /* change state of videobin to NULL */
13843         LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_NULL);
13844         ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_NULL);
13845         if (ret != GST_STATE_CHANGE_SUCCESS) {
13846                 LOGE("failed to change state of videobin to NULL");
13847                 return MM_ERROR_PLAYER_INTERNAL;
13848         }
13849
13850         /* unlink between decoder and videobin and remove previous videosink from videobin */
13851         GST_ELEMENT_UNLINK(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst));
13852         if (!gst_bin_remove(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst))) {
13853                 LOGE("failed to remove former videosink from videobin");
13854                 return MM_ERROR_PLAYER_INTERNAL;
13855         }
13856
13857         __mmplayer_del_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13858
13859         /* create a new videosink and add it to videobin */
13860         player->pipeline->videobin[MMPLAYER_V_SINK].gst = gst_element_factory_make(videosink_element, videosink_element);
13861         if (!player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
13862                 LOGE("failed to create videosink element\n");
13863                 MMPLAYER_FLEAVE();
13864                 return MM_ERROR_PLAYER_INTERNAL;
13865         }
13866         gst_bin_add(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst));
13867         __mmplayer_add_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13868         g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "qos", TRUE, NULL);
13869
13870         /* save attributes */
13871         if (player->attrs) {
13872                 /* set a new display surface type */
13873                 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
13874                 /* set a new diplay overlay */
13875                 switch (surface_type) {
13876                 case MM_DISPLAY_SURFACE_OVERLAY:
13877                         LOGD("save attributes related to video display surface : id = %d", *(int*)display_overlay);
13878                         mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
13879                         break;
13880                 default:
13881                         LOGE("invalid type(%d) for changing display surface", surface_type);
13882                         MMPLAYER_FLEAVE();
13883                         return MM_ERROR_INVALID_ARGUMENT;
13884                 }
13885                 if (mmf_attrs_commit(player->attrs)) {
13886                         LOGE("failed to commit");
13887                         MMPLAYER_FLEAVE();
13888                         return MM_ERROR_PLAYER_INTERNAL;
13889                 }
13890         } else {
13891                 LOGE("player->attrs is null, failed to save attributes");
13892                 MMPLAYER_FLEAVE();
13893                 return MM_ERROR_PLAYER_INTERNAL;
13894         }
13895
13896         /* update video param */
13897         if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "update_all_param")) {
13898                 LOGE("failed to update video param");
13899                 return MM_ERROR_PLAYER_INTERNAL;
13900         }
13901
13902         /* change state of videobin to READY */
13903         LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_READY);
13904         ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_READY);
13905         if (ret != GST_STATE_CHANGE_SUCCESS) {
13906                 LOGE("failed to change state of videobin to READY");
13907                 return MM_ERROR_PLAYER_INTERNAL;
13908         }
13909
13910         /* change ghostpad */
13911         sink_pad_videosink = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "sink");
13912         if (!sink_pad_videosink) {
13913                 LOGE("failed to get sink pad from videosink element");
13914                 return MM_ERROR_PLAYER_INTERNAL;
13915         }
13916         player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", sink_pad_videosink);
13917         if (!gst_pad_set_active(player->ghost_pad_for_videobin, TRUE)) {
13918                 LOGE("failed to set active to ghost_pad");
13919                 return MM_ERROR_PLAYER_INTERNAL;
13920         }
13921         if (FALSE == gst_element_add_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
13922                 LOGE("failed to change ghostpad for videobin");
13923                 return MM_ERROR_PLAYER_INTERNAL;
13924         }
13925         gst_object_unref(sink_pad_videosink);
13926
13927         /* link decoder with videobin */
13928         sink_pad_videobin = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst), "sink");
13929         if (!sink_pad_videobin) {
13930                 LOGE("failed to get sink pad from videobin");
13931                 return MM_ERROR_PLAYER_INTERNAL;
13932         }
13933         if (GST_PAD_LINK_OK != GST_PAD_LINK(src_pad_dec, sink_pad_videobin)) {
13934                 LOGE("failed to link");
13935                 return MM_ERROR_PLAYER_INTERNAL;
13936         }
13937         gst_object_unref(sink_pad_videobin);
13938
13939         /* clock setting for a new videosink plugin */
13940         /* NOTE : Below operation is needed, because a new videosink plugin doesn't have clock for basesink,
13941                         so we set it from audiosink plugin or pipeline(system clock) */
13942         if (!is_audiobin_created) {
13943                 LOGW("audiobin is not created, get clock from pipeline..");
13944                 clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
13945         } else {
13946                 clock = GST_ELEMENT_CLOCK(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13947         }
13948         if (clock) {
13949                 GstClockTime now;
13950                 GstClockTime base_time;
13951                 LOGD("set the clock to videosink");
13952                 gst_element_set_clock(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), clock);
13953                 clock = GST_ELEMENT_CLOCK(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13954                 if (clock) {
13955                         LOGD("got clock of videosink");
13956                         now = gst_clock_get_time(clock);
13957                         base_time = GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst)->base_time;
13958                         LOGD("at time %" GST_TIME_FORMAT ", base %"
13959                                         GST_TIME_FORMAT, GST_TIME_ARGS(now), GST_TIME_ARGS(base_time));
13960                 } else {
13961                         LOGE("failed to get clock of videosink after setting clock");
13962                         return MM_ERROR_PLAYER_INTERNAL;
13963                 }
13964         } else
13965                 LOGW("failed to get clock, maybe it is the time before first playing");
13966
13967         if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
13968                 /* change state of videobin to PAUSED */
13969                 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PLAYING);
13970                 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PLAYING);
13971                 if (ret != GST_STATE_CHANGE_FAILURE) {
13972                         LOGW("change state of videobin to PLAYING, ret(%d)", ret);
13973                 } else {
13974                         LOGE("failed to change state of videobin to PLAYING");
13975                         return MM_ERROR_PLAYER_INTERNAL;
13976                 }
13977
13978                 /* release blocked and unref src pad of video decoder */
13979                 #if 0
13980                 if (!gst_pad_set_blocked(src_pad_dec, FALSE)) {
13981                         LOGE("failed to set pad blocked FALSE(video)");
13982                         return MM_ERROR_PLAYER_INTERNAL;
13983                 }
13984                 #endif
13985                 LOGW("pad is unblocked(video)");
13986         } else {
13987                 if (player->doing_seek)
13988                         LOGW("not completed seek(%d)", player->doing_seek);
13989                 /* change state of videobin to PAUSED */
13990                 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PAUSED);
13991                 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PAUSED);
13992                 if (ret != GST_STATE_CHANGE_FAILURE) {
13993                         LOGW("change state of videobin to PAUSED, ret(%d)", ret);
13994                 } else {
13995                         LOGE("failed to change state of videobin to PLAYING");
13996                         return MM_ERROR_PLAYER_INTERNAL;
13997                 }
13998
13999                 /* already skipped pad block */
14000                 LOGD("previous MM_PLAYER_STATE is not PLAYING, skip pad-block(FALSE)");
14001         }
14002
14003         /* do get/set position for new videosink plugin */
14004         {
14005                 unsigned long position = 0;
14006                 gint64 pos_msec = 0;
14007
14008                 LOGD("do get/set position for new videosink plugin");
14009                 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position)) {
14010                         LOGE("failed to get position");
14011                         return MM_ERROR_PLAYER_INTERNAL;
14012                 }
14013 #ifdef SINKCHANGE_WITH_ACCURATE_SEEK
14014                 /* accurate seek */
14015                 if (__gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, position, TRUE)) {
14016                         LOGE("failed to set position");
14017                         return MM_ERROR_PLAYER_INTERNAL;
14018                 }
14019 #else
14020                 /* key unit seek */
14021                 pos_msec = position * G_GINT64_CONSTANT(1000000);
14022                 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
14023                                 GST_FORMAT_TIME, (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT),
14024                                                         GST_SEEK_TYPE_SET, pos_msec,
14025                                                         GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
14026                 if (!ret) {
14027                         LOGE("failed to set position");
14028                         return MM_ERROR_PLAYER_INTERNAL;
14029                 }
14030 #endif
14031         }
14032
14033         if (src_pad_dec)
14034                 gst_object_unref(src_pad_dec);
14035         LOGD("success to change sink");
14036
14037         MMPLAYER_FLEAVE();
14038
14039         return MM_ERROR_NONE;
14040 }
14041
14042
14043 /* Note : if silent is true, then subtitle would not be displayed. :*/
14044 int _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
14045 {
14046         mm_player_t* player = (mm_player_t*) hplayer;
14047
14048         MMPLAYER_FENTER();
14049
14050         /* check player handle */
14051         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14052
14053         player->set_mode.subtitle_off = silent;
14054
14055         LOGD("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
14056
14057         MMPLAYER_FLEAVE();
14058
14059         return MM_ERROR_NONE;
14060 }
14061
14062 int _mmplayer_remove_audio_parser_decoder(mm_player_t* player, GstPad *inpad)
14063 {
14064         int result = MM_ERROR_NONE;
14065         GstPad *peer = NULL, *pad = NULL;
14066         GstElement *Element = NULL;
14067         MMPlayerGstElement* mainbin = NULL;
14068         mainbin = player->pipeline->mainbin;
14069
14070         #if 0
14071         if (!gst_pad_set_blocked(inpad, TRUE)) {
14072                 result = MM_ERROR_PLAYER_INTERNAL;
14073                 goto EXIT;
14074         }
14075         #endif
14076         gst_pad_add_probe(inpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
14077                         NULL, NULL, NULL);
14078
14079         /*Getting pad connected to demuxer audio pad */
14080         peer = gst_pad_get_peer(inpad);
14081         /* Disconnecting Demuxer and its peer plugin [audio] */
14082         if (peer) {
14083                 if (!gst_pad_unlink(inpad, peer)) {
14084                         result = MM_ERROR_PLAYER_INTERNAL;
14085                         goto EXIT;
14086                 }
14087         } else {
14088                 result = MM_ERROR_PLAYER_INTERNAL;
14089                 goto EXIT;
14090         }
14091         /*Removing elements between Demuxer and audiobin*/
14092         while (peer != NULL) {
14093                 gchar *Element_name = NULL;
14094                 gchar *factory_name = NULL;
14095                 GList *elements = NULL;
14096                 GstElementFactory *factory = NULL;
14097                 /*Getting peer element*/
14098                 Element = gst_pad_get_parent_element(peer);
14099                 if (Element == NULL) {
14100                         gst_object_unref(peer);
14101                         result = MM_ERROR_PLAYER_INTERNAL;
14102                         break;
14103                 }
14104
14105                 Element_name = gst_element_get_name(Element);
14106                 factory = gst_element_get_factory(Element);
14107                 /*checking the element is audio bin*/
14108                 if (!strcmp(Element_name, "audiobin")) {
14109                         gst_object_unref(peer);
14110                         result = MM_ERROR_NONE;
14111                         g_free(Element_name);
14112                         break;
14113                 }
14114                 factory_name = GST_OBJECT_NAME(factory);
14115                 pad = gst_element_get_static_pad(Element, "src");
14116                 if (pad == NULL) {
14117                         result = MM_ERROR_PLAYER_INTERNAL;
14118                         g_free(Element_name);
14119                         break;
14120                 }
14121                 gst_object_unref(peer);
14122                 peer = gst_pad_get_peer(pad);
14123                 if (peer) {
14124                         if (!gst_pad_unlink(pad, peer)) {
14125                                 gst_object_unref(peer);
14126                                 gst_object_unref(pad);
14127                                 result = MM_ERROR_PLAYER_INTERNAL;
14128                                 g_free(Element_name);
14129                                 break;
14130                         }
14131                 }
14132                 elements = player->parsers;
14133                 /* Removing the element form the list*/
14134                 for (; elements; elements = g_list_next(elements)) {
14135                         Element_name = elements->data;
14136                         if (g_strrstr(Element_name, factory_name))
14137                                 player->parsers = g_list_remove(player->parsers, elements->data);
14138                 }
14139                 gst_element_set_state(Element, GST_STATE_NULL);
14140                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), Element);
14141                 gst_object_unref(pad);
14142                 if (Element == mainbin[MMPLAYER_M_Q1].gst)
14143                         mainbin[MMPLAYER_M_Q1].gst = NULL;
14144                 else if (Element == mainbin[MMPLAYER_M_Q2].gst)
14145                         mainbin[MMPLAYER_M_Q2].gst = NULL;
14146                 else if (Element == mainbin[MMPLAYER_M_DEC1].gst)
14147                         mainbin[MMPLAYER_M_DEC1].gst = NULL;
14148                 else if (Element == mainbin[MMPLAYER_M_DEC2].gst)
14149                         mainbin[MMPLAYER_M_DEC2].gst = NULL;
14150
14151                 gst_object_unref(Element);
14152         }
14153 EXIT:
14154         return result;
14155 }
14156
14157 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
14158 {
14159         MMPlayerGstElement* mainbin = NULL;
14160         MMPlayerGstElement* textbin = NULL;
14161         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
14162         GstState current_state = GST_STATE_VOID_PENDING;
14163         GstState element_state = GST_STATE_VOID_PENDING;
14164         GstState element_pending_state = GST_STATE_VOID_PENDING;
14165         gint64 time = 0;
14166         GstEvent *event = NULL;
14167         int result = MM_ERROR_NONE;
14168
14169         GstClock *curr_clock = NULL;
14170         GstClockTime base_time, start_time, curr_time;
14171
14172
14173         MMPLAYER_FENTER();
14174
14175         /* check player handle */
14176         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline , MM_ERROR_PLAYER_NOT_INITIALIZED);
14177
14178         if (!(player->pipeline->mainbin) || !(player->pipeline->textbin)) {
14179                 LOGE("Pipeline is not in proper state\n");
14180                 result = MM_ERROR_PLAYER_NOT_INITIALIZED;
14181                 goto EXIT;
14182         }
14183
14184         mainbin = player->pipeline->mainbin;
14185         textbin = player->pipeline->textbin;
14186
14187         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
14188
14189         // sync clock with current pipeline
14190         curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
14191         curr_time = gst_clock_get_time(curr_clock);
14192
14193         base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
14194         start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
14195
14196         LOGD("base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
14197                 GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
14198
14199         if (current_state > GST_STATE_READY) {
14200                 // sync state with current pipeline
14201                 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
14202                 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
14203                 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
14204
14205                 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
14206                 if (GST_STATE_CHANGE_FAILURE == ret)
14207                         LOGE("fail to state change.\n");
14208         }
14209
14210         gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
14211         gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
14212
14213         if (curr_clock) {
14214                 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
14215                 gst_object_unref(curr_clock);
14216         }
14217
14218         // seek to current position
14219         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
14220                 result = MM_ERROR_PLAYER_INVALID_STATE;
14221                 LOGE("gst_element_query_position failed, invalid state\n");
14222                 goto EXIT;
14223         }
14224
14225         LOGD("seek time = %lld, rate = %f\n", time, player->playback_rate);
14226         event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME, (GstSeekFlags)(GST_SEEK_FLAG_FLUSH), GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
14227         if (event) {
14228                 __gst_send_event_to_sink(player, event);
14229         } else {
14230                 result = MM_ERROR_PLAYER_INTERNAL;
14231                 LOGE("gst_event_new_seek failed\n");
14232                 goto EXIT;
14233         }
14234
14235         // sync state with current pipeline
14236         gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
14237         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
14238         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
14239
14240 EXIT:
14241         return result;
14242 }
14243
14244 static int
14245 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
14246 {
14247         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
14248         GstState current_state = GST_STATE_VOID_PENDING;
14249
14250         MMHandleType attrs = 0;
14251         MMPlayerGstElement* mainbin = NULL;
14252         MMPlayerGstElement* textbin = NULL;
14253
14254         gchar* subtitle_uri = NULL;
14255         int result = MM_ERROR_NONE;
14256         const gchar *charset = NULL;
14257
14258         MMPLAYER_FENTER();
14259
14260         /* check player handle */
14261         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14262         MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
14263
14264         if (!(player->pipeline) || !(player->pipeline->mainbin)) {
14265                 result = MM_ERROR_PLAYER_INVALID_STATE;
14266                 LOGE("Pipeline is not in proper state\n");
14267                 goto EXIT;
14268         }
14269
14270         mainbin = player->pipeline->mainbin;
14271         textbin = player->pipeline->textbin;
14272
14273         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
14274         if (current_state < GST_STATE_READY) {
14275                 result = MM_ERROR_PLAYER_INVALID_STATE;
14276                 LOGE("Pipeline is not in proper state\n");
14277                 goto EXIT;
14278         }
14279
14280         attrs = MMPLAYER_GET_ATTRS(player);
14281         if (!attrs) {
14282                 LOGE("cannot get content attribute\n");
14283                 result = MM_ERROR_PLAYER_INTERNAL;
14284                 goto EXIT;
14285         }
14286
14287         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
14288         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
14289                 LOGE("subtitle uri is not proper filepath\n");
14290                 result = MM_ERROR_PLAYER_INVALID_URI;
14291                 goto EXIT;
14292         }
14293
14294         LOGD("old subtitle file path is [%s]\n", subtitle_uri);
14295         LOGD("new subtitle file path is [%s]\n", filepath);
14296
14297         if (!strcmp(filepath, subtitle_uri)) {
14298                 LOGD("No need to swtich subtitle, as input filepath is same as current filepath\n");
14299                 goto EXIT;
14300         } else {
14301                 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
14302                 if (mmf_attrs_commit(player->attrs)) {
14303                         LOGE("failed to commit.\n");
14304                         goto EXIT;
14305                 }
14306         }
14307
14308         //gst_pad_set_blocked_async(src-srcpad, TRUE)
14309
14310         ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
14311         if (ret != GST_STATE_CHANGE_SUCCESS) {
14312                 LOGE("failed to change state of textbin to READY");
14313                 result = MM_ERROR_PLAYER_INTERNAL;
14314                 goto EXIT;
14315         }
14316
14317         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
14318         if (ret != GST_STATE_CHANGE_SUCCESS) {
14319                 LOGE("failed to change state of subparse to READY");
14320                 result = MM_ERROR_PLAYER_INTERNAL;
14321                 goto EXIT;
14322         }
14323
14324         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
14325         if (ret != GST_STATE_CHANGE_SUCCESS) {
14326                 LOGE("failed to change state of filesrc to READY");
14327                 result = MM_ERROR_PLAYER_INTERNAL;
14328                 goto EXIT;
14329         }
14330
14331         g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
14332
14333         charset = util_get_charset(filepath);
14334         if (charset) {
14335                 LOGD("detected charset is %s\n", charset);
14336                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
14337         }
14338
14339         result = _mmplayer_sync_subtitle_pipeline(player);
14340
14341 EXIT:
14342         MMPLAYER_FLEAVE();
14343         return result;
14344 }
14345
14346 /* API to switch between external subtitles */
14347 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
14348 {
14349         int result = MM_ERROR_NONE;
14350         mm_player_t* player = (mm_player_t*)hplayer;
14351
14352         MMPLAYER_FENTER();
14353
14354         /* check player handle */
14355         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14356
14357         if (!player->pipeline) {
14358                 // IDLE state
14359                 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
14360                 if (mmf_attrs_commit(player->attrs)) {
14361                         LOGE("failed to commit.\n");
14362                         result = MM_ERROR_PLAYER_INTERNAL;
14363                 }
14364         } else {
14365                 // cur state <> IDLE(READY, PAUSE, PLAYING..)
14366                 if (filepath == NULL)
14367                         return MM_ERROR_COMMON_INVALID_ARGUMENT;
14368
14369                 if (!__mmplayer_check_subtitle(player)) {
14370                         mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
14371                         if (mmf_attrs_commit(player->attrs)) {
14372                                 LOGE("failed to commit.\n");
14373                                 result = MM_ERROR_PLAYER_INTERNAL;
14374                         }
14375
14376                         if (MM_ERROR_NONE != __mmplayer_gst_create_subtitle_src(player))
14377                                 LOGE("fail to create subtitle src\n");
14378
14379                         result = _mmplayer_sync_subtitle_pipeline(player);
14380                 } else
14381                         result = __mmplayer_change_external_subtitle_language(player, filepath);
14382
14383                 player->is_external_subtitle_added_now = TRUE;
14384         }
14385
14386         MMPLAYER_FLEAVE();
14387         return result;
14388 }
14389
14390 static int
14391 __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index)
14392 {
14393         int result = MM_ERROR_NONE;
14394         gchar* change_pad_name = NULL;
14395         GstPad* sinkpad = NULL;
14396         MMPlayerGstElement* mainbin = NULL;
14397         enum MainElementID elemId = MMPLAYER_M_NUM;
14398         GstCaps* caps = NULL;
14399         gint total_track_num = 0;
14400
14401         MMPLAYER_FENTER();
14402
14403         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
14404                                                                                                         MM_ERROR_PLAYER_NOT_INITIALIZED);
14405
14406         LOGD("Change Track(%d) to %d\n", type, index);
14407
14408         mainbin = player->pipeline->mainbin;
14409
14410         if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
14411                 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
14412         } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
14413                 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
14414         } else {
14415                 /* Changing Video Track is not supported. */
14416                 LOGE("Track Type Error\n");
14417                 goto EXIT;
14418         }
14419
14420         if (mainbin[elemId].gst == NULL) {
14421                 result = MM_ERROR_PLAYER_NO_OP;
14422                 LOGD("Req track doesn't exist\n");
14423                 goto EXIT;
14424         }
14425
14426         total_track_num = player->selector[type].total_track_num;
14427         if (total_track_num <= 0) {
14428                 result = MM_ERROR_PLAYER_NO_OP;
14429                 LOGD("Language list is not available \n");
14430                 goto EXIT;
14431         }
14432
14433         if ((index < 0) || (index >= total_track_num)) {
14434                 result = MM_ERROR_INVALID_ARGUMENT;
14435                 LOGD("Not a proper index : %d \n", index);
14436                 goto EXIT;
14437         }
14438
14439         /*To get the new pad from the selector*/
14440         change_pad_name = g_strdup_printf("sink_%u", index);
14441         if (change_pad_name == NULL) {
14442                 result = MM_ERROR_PLAYER_INTERNAL;
14443                 LOGD("Pad does not exists\n");
14444                 goto EXIT;
14445         }
14446
14447         LOGD("new active pad name: %s\n", change_pad_name);
14448
14449         sinkpad = gst_element_get_static_pad(mainbin[elemId].gst, change_pad_name);
14450         if (sinkpad == NULL) {
14451                 LOGD("sinkpad is NULL");
14452                 result = MM_ERROR_PLAYER_INTERNAL;
14453                 goto EXIT;
14454         }
14455
14456         LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
14457         g_object_set(mainbin[elemId].gst, "active-pad", sinkpad, NULL);
14458
14459         caps = gst_pad_get_current_caps(sinkpad);
14460         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
14461
14462         if (sinkpad)
14463                 gst_object_unref(sinkpad);
14464
14465         if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
14466                 __mmplayer_set_audio_attrs(player, caps);
14467
14468 EXIT:
14469
14470         MMPLAYER_FREEIF(change_pad_name);
14471         return result;
14472 }
14473
14474 int _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
14475 {
14476         int result = MM_ERROR_NONE;
14477         mm_player_t* player = NULL;
14478         MMPlayerGstElement* mainbin = NULL;
14479
14480         gint current_active_index = 0;
14481
14482         GstState current_state = GST_STATE_VOID_PENDING;
14483         GstEvent* event = NULL;
14484         gint64 time = 0;
14485
14486         MMPLAYER_FENTER();
14487
14488         player = (mm_player_t*)hplayer;
14489         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14490
14491         if (!player->pipeline) {
14492                 LOGE("Track %d pre setting -> %d\n", type, index);
14493
14494                 player->selector[type].active_pad_index = index;
14495                 goto EXIT;
14496         }
14497
14498         mainbin = player->pipeline->mainbin;
14499
14500         current_active_index = player->selector[type].active_pad_index;
14501
14502         /*If index is same as running index no need to change the pad*/
14503         if (current_active_index == index)
14504                 goto EXIT;
14505
14506         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
14507                 result = MM_ERROR_PLAYER_INVALID_STATE;
14508                 goto EXIT;
14509         }
14510
14511         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
14512         if (current_state < GST_STATE_PAUSED) {
14513                 result = MM_ERROR_PLAYER_INVALID_STATE;
14514                 LOGW("Pipeline not in porper state\n");
14515                 goto EXIT;
14516         }
14517
14518         result = __mmplayer_change_selector_pad(player, type, index);
14519         if (result != MM_ERROR_NONE) {
14520                 LOGE("change selector pad error\n");
14521                 goto EXIT;
14522         }
14523
14524         player->selector[type].active_pad_index = index;
14525
14526         if (current_state == GST_STATE_PLAYING) {
14527                 event = gst_event_new_seek(player->playback_rate, 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);
14528                 if (event) {
14529                         __gst_send_event_to_sink(player, event);
14530                 } else {
14531                         result = MM_ERROR_PLAYER_INTERNAL;
14532                         goto EXIT;
14533                 }
14534         }
14535
14536 EXIT:
14537         return result;
14538 }
14539
14540 int _mmplayer_get_subtitle_silent(MMHandleType hplayer, int* silent)
14541 {
14542         mm_player_t* player = (mm_player_t*) hplayer;
14543
14544         MMPLAYER_FENTER();
14545
14546         /* check player handle */
14547         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14548
14549         *silent = player->set_mode.subtitle_off;
14550
14551         LOGD("subtitle is %s.\n", silent ? "ON" : "OFF");
14552
14553         MMPLAYER_FLEAVE();
14554
14555         return MM_ERROR_NONE;
14556 }
14557
14558 gboolean
14559 __is_ms_buff_src(mm_player_t* player)
14560 {
14561         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
14562
14563         return (player->profile.uri_type == MM_PLAYER_URI_TYPE_MS_BUFF) ? TRUE : FALSE;
14564 }
14565
14566 gboolean
14567 __has_suffix(mm_player_t* player, const gchar* suffix)
14568 {
14569         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
14570         MMPLAYER_RETURN_VAL_IF_FAIL(suffix, FALSE);
14571
14572         gboolean ret = FALSE;
14573         gchar* t_url = g_ascii_strdown(player->profile.uri, -1);
14574         gchar* t_suffix = g_ascii_strdown(suffix, -1);
14575
14576         if (g_str_has_suffix(player->profile.uri, suffix))
14577                 ret = TRUE;
14578
14579         MMPLAYER_FREEIF(t_url);
14580         MMPLAYER_FREEIF(t_suffix);
14581
14582         return ret;
14583 }
14584
14585 int
14586 _mmplayer_set_display_zoom(MMHandleType hplayer, float level, int x, int y)
14587 {
14588         mm_player_t* player = (mm_player_t*) hplayer;
14589
14590         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14591
14592         MMPLAYER_VIDEO_SINK_CHECK(player);
14593
14594         LOGD("setting display zoom level = %f, offset = %d, %d", level, x, y);
14595
14596         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "zoom", level, "zoom-pos-x", x, "zoom-pos-y", y, NULL);
14597
14598         return MM_ERROR_NONE;
14599 }
14600 int
14601 _mmplayer_get_display_zoom(MMHandleType hplayer, float *level, int *x, int *y)
14602 {
14603
14604         mm_player_t* player = (mm_player_t*) hplayer;
14605         float _level = 0.0;
14606         int _x = 0;
14607         int _y = 0;
14608
14609         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14610
14611         MMPLAYER_VIDEO_SINK_CHECK(player);
14612
14613         g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "zoom", &_level, "zoom-pos-x", &_x, "zoom-pos-y", &_y, NULL);
14614
14615         LOGD("display zoom level = %f, start off x = %d, y = %d", _level, _x, _y);
14616
14617         *level = _level;
14618         *x = _x;
14619         *y = _y;
14620
14621         return MM_ERROR_NONE;
14622 }
14623
14624 int
14625 _mmplayer_set_video_hub_download_mode(MMHandleType hplayer, bool mode)
14626 {
14627         mm_player_t* player = (mm_player_t*) hplayer;
14628
14629         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14630
14631         if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL) {
14632                 MMPLAYER_PRINT_STATE(player);
14633                 LOGE("wrong-state : can't set the download mode to parse");
14634                 return MM_ERROR_PLAYER_INVALID_STATE;
14635         }
14636
14637         LOGD("set video hub download mode to %s", (mode) ? "ON" : "OFF");
14638         player->video_hub_download_mode = mode;
14639
14640         return MM_ERROR_NONE;
14641 }
14642
14643 int
14644 _mmplayer_enable_sync_handler(MMHandleType hplayer, bool enable)
14645 {
14646         mm_player_t* player = (mm_player_t*) hplayer;
14647
14648         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14649
14650         LOGD("enable sync handler : %s", (enable) ? "ON" : "OFF");
14651         player->sync_handler = enable;
14652
14653         return MM_ERROR_NONE;
14654 }
14655
14656 int
14657 _mmplayer_set_video_share_master_clock(MMHandleType hplayer,
14658                                         long long clock,
14659                                         long long clock_delta,
14660                                         long long video_time,
14661                                         long long media_clock,
14662                                         long long audio_time)
14663 {
14664         mm_player_t* player = (mm_player_t*) hplayer;
14665         MMPlayerGstElement* mainbin = NULL;
14666         GstClockTime start_time_audio = 0, start_time_video = 0;
14667         GstClockTimeDiff base_time = 0, new_base_time = 0;
14668         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
14669         gint64 api_delta = 0;
14670         gint64 position = 0, position_delta = 0;
14671         gint64 adj_base_time = 0;
14672         GstClock *curr_clock = NULL;
14673         GstClockTime curr_time = 0;
14674         gboolean query_ret = TRUE;
14675         int result = MM_ERROR_NONE;
14676
14677         MMPLAYER_FENTER();
14678
14679         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
14680         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
14681         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
14682
14683         // LOGD("in(us) : %lld, %lld, %lld, %lld, %lld", clock, clock_delta, video_time, media_clock, audio_time);
14684
14685         if ((video_time < 0) || (player->doing_seek)) {
14686                 LOGD("skip setting master clock.  %lld", video_time);
14687                 goto EXIT;
14688         }
14689
14690         mainbin = player->pipeline->mainbin;
14691
14692         curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
14693         curr_time = gst_clock_get_time(curr_clock);
14694
14695         current_state = MMPLAYER_CURRENT_STATE(player);
14696
14697         if (current_state == MM_PLAYER_STATE_PLAYING)
14698                 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
14699
14700         if ((current_state != MM_PLAYER_STATE_PLAYING) ||
14701                 (!query_ret)) {
14702                 position = player->last_position;
14703                 LOGD("query fail. %lld", position);
14704         }
14705
14706         clock *= GST_USECOND;
14707         clock_delta *= GST_USECOND;
14708
14709         api_delta = clock - curr_time;
14710         if ((player->video_share_api_delta == 0) || (player->video_share_api_delta > api_delta))
14711                 player->video_share_api_delta = api_delta;
14712         else
14713                 clock_delta += (api_delta - player->video_share_api_delta);
14714
14715         if ((player->video_share_clock_delta == 0) || (player->video_share_clock_delta > clock_delta)) {
14716                 player->video_share_clock_delta = (gint64)clock_delta;
14717
14718                 position_delta = (position/GST_USECOND) - video_time;
14719                 position_delta *= GST_USECOND;
14720
14721                 adj_base_time = position_delta;
14722                 LOGD("video_share_clock_delta = %lld, adj = %lld", player->video_share_clock_delta, adj_base_time);
14723
14724         } else {
14725                 gint64 new_play_time = 0;
14726                 gint64 network_delay = 0;
14727
14728                 video_time *= GST_USECOND;
14729
14730                 network_delay = clock_delta - player->video_share_clock_delta;
14731                 new_play_time = video_time + network_delay;
14732
14733                 adj_base_time = position - new_play_time;
14734
14735                 LOGD("%lld(delay) = %lld - %lld / %lld(adj) = %lld(slave_pos) - %lld(master_pos) - %lld(delay)",
14736                         network_delay, clock_delta, player->video_share_clock_delta, adj_base_time, position, video_time, network_delay);
14737         }
14738
14739         /* Adjust Current Stream Time with base_time of sink
14740          * 1. Set Start time to CLOCK NONE, to control the base time by MSL
14741          * 2. Set new base time
14742          *    if adj_base_time is positive value, the stream time will be decreased.
14743          * 3. If seek event is occurred, the start time will be reset. */
14744         if ((player->pipeline->audiobin) &&
14745                 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst)) {
14746                 start_time_audio = gst_element_get_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
14747
14748                 if (start_time_audio != GST_CLOCK_TIME_NONE) {
14749                         LOGD("audio sink : gst_element_set_start_time -> NONE");
14750                         gst_element_set_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, GST_CLOCK_TIME_NONE);
14751                 }
14752
14753                 base_time = gst_element_get_base_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
14754         }
14755
14756         if ((player->pipeline->videobin) &&
14757                 (player->pipeline->videobin[MMPLAYER_V_SINK].gst)) {
14758                 start_time_video = gst_element_get_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
14759
14760                 if (start_time_video != GST_CLOCK_TIME_NONE) {
14761                         LOGD("video sink : gst_element_set_start_time -> NONE");
14762                         gst_element_set_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst, GST_CLOCK_TIME_NONE);
14763                 }
14764
14765                 // if videobin exist, get base_time from videobin.
14766                 base_time = gst_element_get_base_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
14767         }
14768
14769         new_base_time = base_time + adj_base_time;
14770
14771         if ((player->pipeline->audiobin) &&
14772                 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst))
14773                 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), (GstClockTime)new_base_time);
14774
14775         if ((player->pipeline->videobin) &&
14776                 (player->pipeline->videobin[MMPLAYER_V_SINK].gst))
14777                 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), (GstClockTime)new_base_time);
14778
14779 EXIT:
14780         MMPLAYER_FLEAVE();
14781
14782         return result;
14783 }
14784
14785 int
14786 _mmplayer_get_video_share_master_clock(MMHandleType hplayer,
14787                                         long long *video_time,
14788                                         long long *media_clock,
14789                                         long long *audio_time)
14790 {
14791         mm_player_t* player = (mm_player_t*) hplayer;
14792         MMPlayerGstElement* mainbin = NULL;
14793         GstClock *curr_clock = NULL;
14794         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
14795         gint64 position = 0;
14796         gboolean query_ret = TRUE;
14797
14798         MMPLAYER_FENTER();
14799
14800         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
14801         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
14802         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
14803
14804         MMPLAYER_RETURN_VAL_IF_FAIL(video_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
14805         MMPLAYER_RETURN_VAL_IF_FAIL(media_clock, MM_ERROR_COMMON_INVALID_ARGUMENT);
14806         MMPLAYER_RETURN_VAL_IF_FAIL(audio_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
14807
14808         mainbin = player->pipeline->mainbin;
14809
14810         curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
14811
14812         current_state = MMPLAYER_CURRENT_STATE(player);
14813
14814         if (current_state != MM_PLAYER_STATE_PAUSED)
14815                 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
14816
14817         if ((current_state == MM_PLAYER_STATE_PAUSED) ||
14818                 (!query_ret))
14819                 position = player->last_position;
14820
14821         *media_clock = *video_time = *audio_time = (position/GST_USECOND);
14822
14823         LOGD("media_clock: %lld, video_time: %lld(us)", *media_clock, *video_time);
14824
14825         if (curr_clock)
14826                 gst_object_unref(curr_clock);
14827
14828         MMPLAYER_FLEAVE();
14829
14830         return MM_ERROR_NONE;
14831 }
14832
14833 int
14834 _mmplayer_get_video_rotate_angle(MMHandleType hplayer, int *angle)
14835 {
14836         mm_player_t* player = (mm_player_t*) hplayer;
14837         int org_angle = 0;
14838
14839         MMPLAYER_FENTER();
14840
14841         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14842         MMPLAYER_RETURN_VAL_IF_FAIL(angle, MM_ERROR_COMMON_INVALID_ARGUMENT);
14843
14844         if (player->v_stream_caps) {
14845                 GstStructure *str = NULL;
14846
14847                 str = gst_caps_get_structure(player->v_stream_caps, 0);
14848                 if (!gst_structure_get_int(str, "orientation", &org_angle))
14849                         LOGD("missing 'orientation' field in video caps");
14850         }
14851
14852         LOGD("orientation: %d", org_angle);
14853         *angle = org_angle;
14854
14855         MMPLAYER_FLEAVE();
14856         return MM_ERROR_NONE;
14857 }
14858
14859 static gboolean
14860 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
14861 {
14862         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
14863         MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
14864
14865         gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
14866         gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
14867
14868         int idx = 0;
14869
14870         for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
14871                 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
14872                         LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
14873                         mm_player_dump_t *dump_s;
14874                         dump_s = g_malloc(sizeof(mm_player_dump_t));
14875
14876                         if (dump_s == NULL) {
14877                                 LOGE("malloc fail");
14878                                 return FALSE;
14879                         }
14880
14881                         dump_s->dump_element_file = NULL;
14882                         dump_s->dump_pad = NULL;
14883                         dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
14884
14885                         if (dump_s->dump_pad) {
14886                                 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
14887                                 snprintf(dump_file_name, PLAYER_INI_MAX_STRLEN*2, "%s/%s_sink_pad.dump", player->ini.dump_element_path, player->ini.dump_element_keyword[idx]);
14888                                 dump_s->dump_element_file = fopen(dump_file_name, "w+");
14889                                 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);
14890                                 /* add list for removed buffer probe and close FILE */
14891                                 player->dump_list = g_list_append(player->dump_list, dump_s);
14892                                 LOGD("%s sink pad added buffer probe for dump", factory_name);
14893                                 return TRUE;
14894                         } else {
14895                                 g_free(dump_s);
14896                                 dump_s = NULL;
14897                                 LOGE("failed to get %s sink pad added", factory_name);
14898                         }
14899
14900
14901                 }
14902         }
14903         return FALSE;
14904 }
14905
14906 static GstPadProbeReturn
14907 __mmplayer_dump_buffer_probe_cb(GstPad *pad,  GstPadProbeInfo *info, gpointer u_data)
14908 {
14909         FILE *dump_data = (FILE *) u_data;
14910 //      int written = 0;
14911         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
14912         GstMapInfo probe_info = GST_MAP_INFO_INIT;
14913
14914         MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, FALSE);
14915
14916         gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
14917
14918 //      LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
14919
14920         fwrite(probe_info.data, 1, probe_info.size , dump_data);
14921
14922         return GST_PAD_PROBE_OK;
14923 }
14924
14925 static void
14926 __mmplayer_release_dump_list(GList *dump_list)
14927 {
14928         if (dump_list) {
14929                 GList *d_list = dump_list;
14930                 for (; d_list; d_list = g_list_next(d_list)) {
14931                         mm_player_dump_t *dump_s = d_list->data;
14932                         if (dump_s->dump_pad) {
14933                                 if (dump_s->probe_handle_id)
14934                                         gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
14935                         }
14936                         if (dump_s->dump_element_file) {
14937                                 fclose(dump_s->dump_element_file);
14938                                 dump_s->dump_element_file = NULL;
14939                         }
14940                         MMPLAYER_FREEIF(dump_s);
14941                 }
14942                 g_list_free(dump_list);
14943                 dump_list = NULL;
14944         }
14945 }
14946
14947 int
14948 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
14949 {
14950         mm_player_t* player = (mm_player_t*) hplayer;
14951
14952         MMPLAYER_FENTER();
14953
14954         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14955         MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
14956
14957         *exist = player->has_closed_caption;
14958
14959         MMPLAYER_FLEAVE();
14960
14961         return MM_ERROR_NONE;
14962 }
14963
14964 void * _mm_player_media_packet_video_stream_internal_buffer_ref(void *buffer)
14965 {
14966         void * ret = NULL
14967         MMPLAYER_FENTER();
14968         /* increase ref count of gst buffer */
14969         if (buffer)
14970                 ret = gst_buffer_ref((GstBuffer *)buffer);
14971
14972         MMPLAYER_FLEAVE();
14973         return ret;
14974 }
14975
14976 void _mm_player_media_packet_video_stream_internal_buffer_unref(void *buffer)
14977 {
14978         MMPLAYER_FENTER();
14979         if (buffer) {
14980                 gst_buffer_unref((GstBuffer *)buffer);
14981                 buffer = NULL;
14982         }
14983         MMPLAYER_FLEAVE();
14984 }
14985
14986 void
14987 __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data)
14988 {
14989         mm_player_t *player  = (mm_player_t*)user_data;
14990         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
14991         guint64 current_level_bytes = 0;
14992
14993         MMPLAYER_RETURN_IF_FAIL(player);
14994
14995         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
14996
14997         LOGI("app-src: feed audio(%llu)\n", current_level_bytes);
14998         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
14999
15000         if (player->media_stream_buffer_status_cb[type])
15001                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param);
15002         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15003
15004 }
15005
15006 void
15007 __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data)
15008 {
15009         mm_player_t *player  = (mm_player_t*)user_data;
15010         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
15011         guint64 current_level_bytes = 0;
15012
15013         MMPLAYER_RETURN_IF_FAIL(player);
15014
15015         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
15016
15017         LOGI("app-src: feed video(%llu)\n", current_level_bytes);
15018
15019         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
15020         if (player->media_stream_buffer_status_cb[type])
15021                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param);
15022         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15023 }
15024
15025 void
15026 __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data)
15027 {
15028         mm_player_t *player  = (mm_player_t*)user_data;
15029         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
15030         guint64 current_level_bytes = 0;
15031
15032         MMPLAYER_RETURN_IF_FAIL(player);
15033
15034         LOGI("app-src: feed subtitle\n");
15035
15036         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
15037
15038         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
15039         if (player->media_stream_buffer_status_cb[type])
15040                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param);
15041
15042         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15043 }
15044
15045 void
15046 __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data)
15047 {
15048         mm_player_t *player  = (mm_player_t*)user_data;
15049         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
15050         guint64 current_level_bytes = 0;
15051
15052         MMPLAYER_RETURN_IF_FAIL(player);
15053
15054         LOGI("app-src: audio buffer is full.\n");
15055
15056         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
15057
15058         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
15059
15060         if (player->media_stream_buffer_status_cb[type])
15061                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param);
15062
15063         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15064 }
15065
15066 void
15067 __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data)
15068 {
15069         mm_player_t *player  = (mm_player_t*)user_data;
15070         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
15071         guint64 current_level_bytes = 0;
15072
15073         MMPLAYER_RETURN_IF_FAIL(player);
15074
15075         LOGI("app-src: video buffer is full.\n");
15076
15077         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
15078
15079         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
15080         if (player->media_stream_buffer_status_cb[type])
15081                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param);
15082
15083         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15084 }
15085
15086 gboolean
15087 __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data)
15088 {
15089         mm_player_t *player  = (mm_player_t*)user_data;
15090         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
15091
15092         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
15093
15094         LOGD("app-src: seek audio data %llu\n", position);
15095         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
15096
15097         if (player->media_stream_seek_data_cb[type])
15098                 player->media_stream_seek_data_cb[type](type, position, player->buffer_cb_user_param);
15099         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15100
15101         return TRUE;
15102 }
15103
15104 gboolean
15105 __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data)
15106 {
15107         mm_player_t *player  = (mm_player_t*)user_data;
15108         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
15109
15110         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
15111
15112         LOGD("app-src: seek video data %llu\n", position);
15113         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
15114         if (player->media_stream_seek_data_cb[type])
15115                 player->media_stream_seek_data_cb[type](type, position, player->buffer_cb_user_param);
15116         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15117
15118         return TRUE;
15119 }
15120
15121 gboolean
15122 __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data)
15123 {
15124         mm_player_t *player  = (mm_player_t*)user_data;
15125         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
15126
15127         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
15128
15129         LOGD("app-src: seek subtitle data\n");
15130         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
15131
15132         if (player->media_stream_seek_data_cb[type])
15133                 player->media_stream_seek_data_cb[type](type, position, player->buffer_cb_user_param);
15134         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15135
15136         return TRUE;
15137 }
15138
15139 int
15140 _mmplayer_set_pcm_spec(MMHandleType hplayer, int samplerate, int channel)
15141 {
15142         mm_player_t* player = (mm_player_t*) hplayer;
15143
15144         MMPLAYER_FENTER();
15145
15146         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
15147
15148         player->pcm_samplerate = samplerate;
15149         player->pcm_channel = channel;
15150
15151         MMPLAYER_FLEAVE();
15152         return MM_ERROR_NONE;
15153 }
15154
15155 int _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
15156 {
15157         mm_player_t* player = (mm_player_t*) hplayer;
15158
15159         MMPLAYER_FENTER();
15160
15161         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
15162         MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
15163
15164         if (MMPLAYER_IS_STREAMING(player))
15165                 *timeout = player->ini.live_state_change_timeout;
15166         else
15167                 *timeout = player->ini.localplayback_state_change_timeout;
15168
15169         LOGD("timeout = %d\n", *timeout);
15170
15171         MMPLAYER_FLEAVE();
15172         return MM_ERROR_NONE;
15173 }
15174
15175 int _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
15176 {
15177         mm_player_t* player = (mm_player_t*) hplayer;
15178
15179         MMPLAYER_FENTER();
15180
15181         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
15182         MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
15183
15184         *num = player->video_num_buffers;
15185         *extra_num = player->video_extra_num_buffers;
15186
15187         LOGD("state %d, num %d(%d)\n", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
15188
15189         MMPLAYER_FLEAVE();
15190         return MM_ERROR_NONE;
15191 }
15192