[0.6.112] Add gst bus watcher for using msg queue
[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/audio/gstaudiobasesink.h>
33 #include <unistd.h>
34 #include <sys/stat.h>
35 #include <string.h>
36 #include <sys/time.h>
37 #include <stdlib.h>
38 #include <dlog.h>
39
40 #include <mm_error.h>
41 #include <mm_attrs.h>
42 #include <mm_attrs_private.h>
43
44 #include "mm_player_priv.h"
45 #include "mm_player_ini.h"
46 #include "mm_player_attrs.h"
47 #include "mm_player_capture.h"
48 #include "mm_player_utils.h"
49 #include "mm_player_tracks.h"
50 #include "mm_player_360.h"
51
52 #include <system_info.h>
53 #include <sound_manager.h>
54
55 /*===========================================================================================
56 |                                                                                                                                                                                       |
57 |  LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE                                                                                        |
58 |                                                                                                                                                                                       |
59 ========================================================================================== */
60
61 /*---------------------------------------------------------------------------
62 |    GLOBAL CONSTANT DEFINITIONS:                                                                                       |
63 ---------------------------------------------------------------------------*/
64
65 /*---------------------------------------------------------------------------
66 |    IMPORTED VARIABLE DECLARATIONS:                                                                            |
67 ---------------------------------------------------------------------------*/
68
69 /*---------------------------------------------------------------------------
70 |    IMPORTED FUNCTION DECLARATIONS:                                                                            |
71 ---------------------------------------------------------------------------*/
72
73 /*---------------------------------------------------------------------------
74 |    LOCAL #defines:                                                                                                            |
75 ---------------------------------------------------------------------------*/
76 #define TRICK_PLAY_MUTE_THRESHOLD_MAX   2.0
77 #define TRICK_PLAY_MUTE_THRESHOLD_MIN   0.0
78
79 #define MM_VOLUME_FACTOR_DEFAULT                1.0
80 #define MM_VOLUME_FACTOR_MIN                    0
81 #define MM_VOLUME_FACTOR_MAX                    1.0
82
83 /* Don't need to sleep for sound fadeout
84  * fadeout related fucntion will be deleted(Deprecated)
85  */
86 #define MM_PLAYER_FADEOUT_TIME_DEFAULT  0
87
88 #define DEFAULT_PLAYBACK_RATE                   1.0
89 #define DEFAULT_NUM_OF_V_OUT_BUFFER             3
90
91 #define MMPLAYER_USE_FILE_FOR_BUFFERING(player) \
92         (((player)->profile.uri_type != MM_PLAYER_URI_TYPE_HLS) && \
93         (player->ini.http_use_file_buffer) && \
94         (player->http_file_buffering_path) && \
95         (strlen(player->http_file_buffering_path) > 0))
96
97 #define PLAYER_DISPLAY_MODE_DST_ROI             5
98
99 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
100
101 #define PLAYER_BUS_MSG_DEFAULT_TIMEOUT 500 /* bus msg wait timeout */
102 #define PLAYER_BUS_MSG_PREPARE_TIMEOUT 10
103
104 #define PLAYER_SPHERICAL_DEFAULT_YAW   0  /* sync from video360 plugin */
105 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
106 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
107 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
108
109 #define SPATIAL_AUDIO_CAPS             "audio/x-raw,format=S16LE,channels=4"
110 #define FEATURE_NAME_SPHERICAL_VIDEO   "http://tizen.org/feature/multimedia.player.spherical_video"
111
112 /*---------------------------------------------------------------------------
113 |    LOCAL CONSTANT DEFINITIONS:                                                                                        |
114 ---------------------------------------------------------------------------*/
115
116 /*---------------------------------------------------------------------------
117 |    LOCAL DATA TYPE DEFINITIONS:                                                                                       |
118 ---------------------------------------------------------------------------*/
119
120 /*---------------------------------------------------------------------------
121 |    GLOBAL VARIABLE DEFINITIONS:                                                                                       |
122 ---------------------------------------------------------------------------*/
123
124 /*---------------------------------------------------------------------------
125 |    LOCAL VARIABLE DEFINITIONS:                                                                                        |
126 ---------------------------------------------------------------------------*/
127 static sound_stream_info_h stream_info;
128
129 /*---------------------------------------------------------------------------
130 |    LOCAL FUNCTION PROTOTYPES:                                                                                         |
131 ---------------------------------------------------------------------------*/
132 static int              __mmplayer_gst_create_pipeline(mm_player_t* player);
133 static int              __mmplayer_gst_destroy_pipeline(mm_player_t* player);
134 static int              __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps *caps, MMDisplaySurfaceType surface_type);
135 static int              __mmplayer_gst_create_audio_pipeline(mm_player_t* player);
136 static int              __mmplayer_gst_create_text_pipeline(mm_player_t* player);
137 static int              __mmplayer_gst_create_text_sink_bin(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 void __mmplayer_gst_decode_pad_removed(GstElement *elem,  GstPad* new_pad, gpointer data);
148 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
149 static void     __mmplayer_gst_element_added(GstElement* bin, GstElement* element, gpointer data);
150 static GstElement * __mmplayer_create_decodebin(mm_player_t* player);
151 static gboolean __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps);
152 static void     __mmplayer_typefind_have_type(GstElement *tf, guint probability, GstCaps *caps, gpointer data);
153 static void     __mmplayer_pipeline_complete(GstElement *decodebin,  gpointer data);
154 static gboolean __mmplayer_is_midi_type(gchar* str_caps);
155 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
156 static void     __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps);
157
158 static void             __mmplayer_gst_rtp_no_more_pads(GstElement *element,  gpointer data);
159 static void             __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data);
160 static MMStreamingType  __mmplayer_get_stream_service_type(mm_player_t* player);
161 static gboolean __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
162 static void             __mmplayer_release_misc(mm_player_t* player);
163 static void             __mmplayer_release_misc_post(mm_player_t* player);
164 static gboolean __mmplayer_init_gstreamer(mm_player_t* player);
165 static GstBusSyncReply __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data);
166 static void __mmplayer_gst_callback(GstMessage *msg, gpointer data);
167 static gboolean __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage *msg);
168 static gboolean      __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg);
169 static gboolean __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink);
170 static GstPadProbeReturn __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
171 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
172 static void __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
173 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
174 static int __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index);
175
176 static gboolean __mmplayer_check_subtitle(mm_player_t* player);
177 static gboolean __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message);
178 static void             __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms);
179 static void             __mmplayer_cancel_eos_timer(mm_player_t* player);
180 static gboolean __mmplayer_eos_timer_cb(gpointer u_data);
181 static int              __mmplayer_handle_missed_plugin(mm_player_t* player);
182 static int              __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime);
183 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player);
184 static void             __mmplayer_add_sink(mm_player_t* player, GstElement* sink);
185 static void             __mmplayer_del_sink(mm_player_t* player, GstElement* sink);
186 static void             __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type);
187 static gpointer __mmplayer_next_play_thread(gpointer data);
188 static gboolean _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag);
189
190 static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element);
191 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad,  GstPadProbeInfo *info, gpointer u_data);
192 static void __mmplayer_release_dump_list(GList *dump_list);
193
194 static int              __gst_realize(mm_player_t* player);
195 static int              __gst_unrealize(mm_player_t* player);
196 static int              __gst_start(mm_player_t* player);
197 static int              __gst_stop(mm_player_t* player);
198 static int              __gst_pause(mm_player_t* player, gboolean async);
199 static int              __gst_resume(mm_player_t* player, gboolean async);
200 static gboolean __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
201                                         GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
202                                         gint64 cur, GstSeekType stop_type, gint64 stop);
203 static int __gst_pending_seek(mm_player_t* player);
204
205 static int              __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called);
206 static int              __gst_get_position(mm_player_t* player, int format, unsigned long *position);
207 static int              __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos);
208 static int              __gst_adjust_subtitle_position(mm_player_t* player, int format, int position);
209 static int              __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param);
210
211 static gboolean __gst_send_event_to_sink(mm_player_t* player, GstEvent* event);
212
213 static int __mmplayer_set_pcm_extraction(mm_player_t* player);
214 static gboolean __mmplayer_can_extract_pcm(mm_player_t* player);
215
216 /* util */
217 static gboolean __is_ms_buff_src(mm_player_t* player);
218 static gboolean __has_suffix(mm_player_t * player, const gchar * suffix);
219
220 static int __mmplayer_realize_streaming_ext(mm_player_t* player);
221 static int __mmplayer_unrealize_streaming_ext(mm_player_t *player);
222 static int __mmplayer_start_streaming_ext(mm_player_t *player);
223 static int __mmplayer_destroy_streaming_ext(mm_player_t* player);
224 static int __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay);
225
226 static gboolean __mmplayer_verify_next_play_path(mm_player_t *player);
227 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
228 static void __mmplayer_check_pipeline(mm_player_t* player);
229 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
230 static void __mmplayer_deactivate_old_path(mm_player_t *player);
231
232 static void __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg);
233 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name);
234
235 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player);
236 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name);
237 static void             __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data);
238 static void             __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data);
239 static void     __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data);
240 static void             __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data);
241 static void             __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data);
242 static gboolean __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data);
243 static gboolean __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data);
244 static gboolean __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data);
245 static void             __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data);
246 static void             __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all);
247 static void             __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer);
248 static void             __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type);
249 static void             __mmplayer_get_metadata_360_from_tags(GstTagList *tags, mm_player_spherical_metadata_t *metadata);
250 static int              __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res, void *user_data);
251
252 /*===========================================================================================
253 |                                                                                                                                                                                       |
254 |  FUNCTION DEFINITIONS                                                                                                                                         |
255 |                                                                                                                                                                                       |
256 ========================================================================================== */
257
258 #if 0 //debug
259 static void
260 print_tag(const GstTagList * list, const gchar * tag, gpointer unused)
261 {
262         gint i, count;
263
264         count = gst_tag_list_get_tag_size(list, tag);
265
266         LOGD("count = %d", count);
267
268         for (i = 0; i < count; i++) {
269                 gchar *str;
270
271                 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
272                         if (!gst_tag_list_get_string_index(list, tag, i, &str))
273                                 g_assert_not_reached();
274                 } else
275                         str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
276
277                 if (i == 0)
278                         g_print("  %15s: %s\n", gst_tag_get_nick(tag), str);
279                 else
280                         g_print("                 : %s\n", str);
281
282                 g_free(str);
283         }
284 }
285 #endif
286
287 /* This function should be called after the pipeline goes PAUSED or higher
288 state. */
289 gboolean
290 _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag)
291 {
292         static gboolean has_duration = FALSE;
293         static gboolean has_video_attrs = FALSE;
294         static gboolean has_audio_attrs = FALSE;
295         static gboolean has_bitrate = FALSE;
296         gboolean missing_only = FALSE;
297         gboolean all = FALSE;
298         gint64 dur_nsec = 0;
299         GstStructure* p = NULL;
300         MMHandleType attrs = 0;
301         gchar *path = NULL;
302         struct stat sb;
303
304         MMPLAYER_FENTER();
305
306         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
307
308         /* check player state here */
309         if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
310                 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
311                 /* give warning now only */
312                 LOGW("be careful. content attributes may not available in this state ");
313         }
314
315         /* get content attribute first */
316         attrs = MMPLAYER_GET_ATTRS(player);
317         if (!attrs) {
318                 LOGE("cannot get content attribute");
319                 return FALSE;
320         }
321
322         /* get update flag */
323
324         if (flag & ATTR_MISSING_ONLY) {
325                 missing_only = TRUE;
326                 LOGD("updating missed attr only");
327         }
328
329         if (flag & ATTR_ALL) {
330                 all = TRUE;
331                 has_duration = FALSE;
332                 has_video_attrs = FALSE;
333                 has_audio_attrs = FALSE;
334                 has_bitrate = FALSE;
335
336                 LOGD("updating all attrs");
337         }
338
339         if (missing_only && all) {
340                 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
341                 missing_only = FALSE;
342         }
343
344         if ((flag & ATTR_DURATION) ||   (!has_duration && missing_only) || all) {
345                 LOGD("try to update duration");
346                 has_duration = FALSE;
347
348                 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
349                         player->duration = dur_nsec;
350                         LOGW("duration : %lld msec", GST_TIME_AS_MSECONDS(dur_nsec));
351                 }
352
353                 if (player->duration < 0) {
354                         LOGW("duration : %lld is Non-Initialized !!! \n", player->duration);
355                         player->duration = 0;
356                 }
357
358                 /* update streaming service type */
359                 player->streaming_type =  __mmplayer_get_stream_service_type(player);
360
361                 /* check duration is OK */
362                 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player)) {
363                         /* FIXIT : find another way to get duration here. */
364                         LOGE("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
365                 } else {
366                         /*update duration */
367                         mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(dur_nsec));
368                         has_duration = TRUE;
369                 }
370         }
371
372         if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all) {
373                 /* update audio params
374                 NOTE : We need original audio params and it can be only obtained from src pad of audio
375                 decoder. Below code only valid when we are not using 'resampler' just before
376                 'audioconverter'. */
377
378                 LOGD("try to update audio attrs");
379                 has_audio_attrs = FALSE;
380
381                 if (player->pipeline->audiobin &&
382                          player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
383                         GstCaps *caps_a = NULL;
384                         GstPad* pad = NULL;
385                         gint samplerate = 0, channels = 0;
386
387                         pad = gst_element_get_static_pad(
388                                         player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
389
390                         if (pad) {
391                                 caps_a = gst_pad_get_current_caps(pad);
392
393                                 if (caps_a) {
394                                         p = gst_caps_get_structure(caps_a, 0);
395
396                                         mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
397
398                                         gst_structure_get_int(p, "rate", &samplerate);
399                                         mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
400
401                                         gst_structure_get_int(p, "channels", &channels);
402                                         mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
403
404                                         SECURE_LOGD("samplerate : %d    channels : %d", samplerate, channels);
405
406                                         gst_caps_unref(caps_a);
407                                         caps_a = NULL;
408
409                                         has_audio_attrs = TRUE;
410                                 } else
411                                         LOGW("not ready to get audio caps");
412
413                                 gst_object_unref(pad);
414                         } else
415                                 LOGW("failed to get pad from audiosink");
416                 }
417         }
418
419         if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all) {
420                 LOGD("try to update video attrs");
421                 has_video_attrs = FALSE;
422
423                 if (player->pipeline->videobin &&
424                          player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
425                         GstCaps *caps_v = NULL;
426                         GstPad* pad = NULL;
427                         gint tmpNu, tmpDe;
428                         gint width, height;
429
430                         pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
431                         if (pad) {
432                                 caps_v = gst_pad_get_current_caps(pad);
433
434                                 /* Use v_stream_caps, if fail to get video_sink sink pad*/
435                                 if (!caps_v && player->v_stream_caps) {
436                                         caps_v = player->v_stream_caps;
437                                         gst_caps_ref(caps_v);
438                                 }
439
440                                 if (caps_v) {
441                                         p = gst_caps_get_structure(caps_v, 0);
442                                         gst_structure_get_int(p, "width", &width);
443                                         mm_attrs_set_int_by_name(attrs, "content_video_width", width);
444
445                                         gst_structure_get_int(p, "height", &height);
446                                         mm_attrs_set_int_by_name(attrs, "content_video_height", height);
447
448                                         gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
449
450                                         SECURE_LOGD("width : %d     height : %d", width, height);
451
452                                         gst_caps_unref(caps_v);
453                                         caps_v = NULL;
454
455                                         if (tmpDe > 0) {
456                                                 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
457                                                 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
458                                         }
459
460                                         has_video_attrs = TRUE;
461                                 } else
462                                         LOGD("no negitiated caps from videosink");
463                                 gst_object_unref(pad);
464                                 pad = NULL;
465                         } else
466                                 LOGD("no videosink sink pad");
467                 }
468         }
469
470
471         if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all) {
472                 has_bitrate = FALSE;
473
474                 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
475                 if (player->duration) {
476                         guint64 data_size = 0;
477
478                         if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
479                                 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
480
481                                 if (stat(path, &sb) == 0)
482                                         data_size = (guint64)sb.st_size;
483                         } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
484                                 data_size = player->http_content_size;
485                         }
486                         LOGD("try to update bitrate : data_size = %lld", data_size);
487
488                         if (data_size) {
489                                 guint64 bitrate = 0;
490                                 guint64 msec_dur = 0;
491
492                                 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
493                                 if (msec_dur > 0) {
494                                         bitrate = data_size * 8 * 1000 / msec_dur;
495                                         SECURE_LOGD("file size : %u, video bitrate = %llu", data_size, bitrate);
496                                         mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
497
498                                         has_bitrate = TRUE;
499                                 } else {
500                                         LOGD("player duration is less than 0");
501                                 }
502                         }
503
504                         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
505                                 if (player->total_bitrate) {
506                                         mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
507                                         has_bitrate = TRUE;
508                                 }
509                         }
510                 }
511         }
512
513         /* validate all */
514         if (mmf_attrs_commit(attrs)) {
515                 LOGE("failed to update attributes\n");
516                 return FALSE;
517         }
518
519         MMPLAYER_FLEAVE();
520
521         return TRUE;
522 }
523
524 static MMStreamingType __mmplayer_get_stream_service_type(mm_player_t* player)
525 {
526         MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
527
528         MMPLAYER_FENTER();
529
530         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
531                         player->pipeline &&
532                         player->pipeline->mainbin &&
533                         player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
534                         STREAMING_SERVICE_NONE);
535
536         /* streaming service type if streaming */
537         if (!MMPLAYER_IS_STREAMING(player))
538                 return STREAMING_SERVICE_NONE;
539
540         if (MMPLAYER_IS_HTTP_STREAMING(player))
541                 streaming_type = (player->duration == 0) ?
542                         STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
543
544         switch (streaming_type) {
545         case STREAMING_SERVICE_LIVE:
546                 LOGD("it's live streaming");
547                 break;
548         case STREAMING_SERVICE_VOD:
549                 LOGD("it's vod streaming");
550                 break;
551         default:
552                 LOGE("should not get here");
553                 break;
554         }
555
556         MMPLAYER_FLEAVE();
557
558         return streaming_type;
559 }
560
561
562 /* this function sets the player state and also report
563  * it to applicaton by calling callback function
564  */
565 int
566 __mmplayer_set_state(mm_player_t* player, int state)
567 {
568         MMMessageParamType msg = {0, };
569         gboolean post_bos = FALSE;
570
571         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
572
573         if (MMPLAYER_CURRENT_STATE(player) == state) {
574                 LOGW("already same state(%s)\n", MMPLAYER_STATE_GET_NAME(state));
575                 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
576                 return MM_ERROR_NONE;
577         }
578
579         /* update player states */
580         MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
581         MMPLAYER_CURRENT_STATE(player) = state;
582
583         if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
584                 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
585
586         /* print state */
587         MMPLAYER_PRINT_STATE(player);
588
589         switch (MMPLAYER_CURRENT_STATE(player)) {
590         case MM_PLAYER_STATE_NULL:
591         case MM_PLAYER_STATE_READY:
592                 break;
593
594         case MM_PLAYER_STATE_PAUSED:
595                 {
596                         if (!player->sent_bos) {
597                                 /* rtsp case, get content attrs by GstMessage */
598                                 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
599                                         /* it's first time to update all content attrs. */
600                                         _mmplayer_update_content_attrs(player, ATTR_ALL);
601                                 }
602                         }
603
604                         /* add audio callback probe if condition is satisfied */
605                         if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
606                                 __mmplayer_configure_audio_callback(player);
607
608                         /* FIXIT : handle return value */
609                 }
610                 break;
611
612         case MM_PLAYER_STATE_PLAYING:
613                 {
614                         /* try to get content metadata */
615                         if (!player->sent_bos) {
616                                 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
617                                  * c-api since c-api doesn't use _start() anymore. It may not work propery with
618                                  * legacy mmfw-player api */
619                                 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
620                         }
621
622                         if ((player->cmd == MMPLAYER_COMMAND_START) || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
623                                 if (!player->sent_bos)
624                                         __mmplayer_handle_missed_plugin(player);
625                         }
626
627                         if (player->resumed_by_rewind && player->playback_rate < 0.0) {
628                                 /* initialize because auto resume is done well. */
629                                 player->resumed_by_rewind = FALSE;
630                                 player->playback_rate = 1.0;
631                         }
632
633                         if (!player->sent_bos) {
634                                 /* check audio codec field is set or not
635                                  * we can get it from typefinder or codec's caps.
636                                  */
637                                 gchar *audio_codec = NULL;
638                                 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
639
640                                 /* The codec format can't be sent for audio only case like amr, mid etc.
641                                  * Because, parser don't make related TAG.
642                                  * So, if it's not set yet, fill it with found data.
643                                  */
644                                 if (!audio_codec) {
645                                         if (g_strrstr(player->type, "audio/midi"))
646                                                 audio_codec = g_strdup("MIDI");
647                                         else if (g_strrstr(player->type, "audio/x-amr"))
648                                                 audio_codec = g_strdup("AMR");
649                                         else if (g_strrstr(player->type, "audio/mpeg") && !g_strrstr(player->type, "mpegversion= (int)1"))
650                                                 audio_codec = g_strdup("AAC");
651                                         else
652                                                 audio_codec = g_strdup("unknown");
653                                         mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
654
655                                         MMPLAYER_FREEIF(audio_codec);
656                                         if (mmf_attrs_commit(player->attrs))
657                                                 LOGE("failed to update attributes\n");
658
659                                         LOGD("set audio codec type with caps\n");
660                                 }
661
662                                 post_bos = TRUE;
663                         }
664                 }
665                 break;
666
667         case MM_PLAYER_STATE_NONE:
668         default:
669                 LOGW("invalid target state, there is nothing to do.\n");
670                 break;
671         }
672
673
674         /* post message to application */
675         if (MMPLAYER_TARGET_STATE(player) == state) {
676                 /* fill the message with state of player */
677                 msg.union_type = MM_MSG_UNION_STATE;
678                 msg.state.previous = MMPLAYER_PREV_STATE(player);
679                 msg.state.current = MMPLAYER_CURRENT_STATE(player);
680
681                 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
682
683                 /* state changed by resource callback */
684                 if (player->interrupted_by_resource) {
685                         msg.state.code = MM_PLAYER_FOCUS_CHANGED_BY_RESOURCE_CONFLICT;
686                         MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
687                 } else { /* state changed by usecase */
688                         MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
689                 }
690         } else {
691                 LOGD("intermediate state, do nothing.\n");
692                 MMPLAYER_PRINT_STATE(player);
693                 return MM_ERROR_NONE;
694         }
695
696         if (post_bos) {
697                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
698                 player->sent_bos = TRUE;
699         }
700
701         return MM_ERROR_NONE;
702 }
703
704 static gpointer __mmplayer_next_play_thread(gpointer data)
705 {
706         mm_player_t* player = (mm_player_t*) data;
707         MMPlayerGstElement *mainbin = NULL;
708
709         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
710
711         MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
712         while (!player->next_play_thread_exit) {
713                 LOGD("next play thread started. waiting for signal.\n");
714                 MMPLAYER_NEXT_PLAY_THREAD_WAIT(player);
715
716                 LOGD("reconfigure pipeline for gapless play.\n");
717
718                 if (player->next_play_thread_exit) {
719                         if (player->gapless.reconfigure) {
720                                 player->gapless.reconfigure = false;
721                                 MMPLAYER_PLAYBACK_UNLOCK(player);
722                         }
723                         LOGD("exiting gapless play thread\n");
724                         break;
725                 }
726
727                 mainbin = player->pipeline->mainbin;
728
729                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
730                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
731                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
732                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
733                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
734
735                 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
736         }
737         MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
738
739         return NULL;
740 }
741
742 static void
743 __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg)
744 {
745         MMHandleType attrs = 0;
746         guint64 data_size = 0;
747         gchar* path = NULL;
748         unsigned long pos_msec = 0;
749         struct stat sb;
750
751         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
752
753         __gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &pos_msec);       // update last_position
754
755         attrs = MMPLAYER_GET_ATTRS(player);
756         if (!attrs) {
757                 LOGE("fail to get attributes.\n");
758                 return;
759         }
760
761         if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
762                 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
763
764                 if (stat(path, &sb) == 0)
765                         data_size = (guint64)sb.st_size;
766         } else if (MMPLAYER_IS_HTTP_STREAMING(player))
767                 data_size = player->http_content_size;
768
769         __mm_player_streaming_buffering(player->streamer,
770                                                                                 buffering_msg,
771                                                                                 data_size,
772                                                                                 player->last_position,
773                                                                                 player->duration);
774
775         __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
776
777         return;
778 }
779
780 static int
781 __mmplayer_handle_buffering_message(mm_player_t* player)
782 {
783         int ret = MM_ERROR_NONE;
784         MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
785         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
786         MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
787         MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
788
789         if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
790                 LOGW("do nothing for buffering msg\n");
791                 ret = MM_ERROR_PLAYER_INVALID_STATE;
792                 goto exit;
793         }
794
795         prev_state = MMPLAYER_PREV_STATE(player);
796         current_state = MMPLAYER_CURRENT_STATE(player);
797         target_state = MMPLAYER_TARGET_STATE(player);
798         pending_state = MMPLAYER_PENDING_STATE(player);
799
800         LOGD("player state : prev %s, current %s, pending %s, target %s, buffering %d",
801                 MMPLAYER_STATE_GET_NAME(prev_state),
802                 MMPLAYER_STATE_GET_NAME(current_state),
803                 MMPLAYER_STATE_GET_NAME(pending_state),
804                 MMPLAYER_STATE_GET_NAME(target_state),
805                 player->streamer->is_buffering);
806
807         if (!player->streamer->is_buffering) {
808                 /* NOTE : if buffering has done, player has to go to target state. */
809                 switch (target_state) {
810                 case MM_PLAYER_STATE_PAUSED:
811                         {
812                                 switch (pending_state) {
813                                 case MM_PLAYER_STATE_PLAYING:
814                                         __gst_pause(player, TRUE);
815                                         break;
816
817                                 case MM_PLAYER_STATE_PAUSED:
818                                         LOGD("player is already going to paused state, there is nothing to do.\n");
819                                         break;
820
821                                 case MM_PLAYER_STATE_NONE:
822                                 case MM_PLAYER_STATE_NULL:
823                                 case MM_PLAYER_STATE_READY:
824                                 default:
825                                         LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
826                                         break;
827                                 }
828                         }
829                         break;
830
831                 case MM_PLAYER_STATE_PLAYING:
832                         {
833                                 switch (pending_state) {
834                                 case MM_PLAYER_STATE_NONE:
835                                         {
836                                                 if (current_state != MM_PLAYER_STATE_PLAYING)
837                                                         __gst_resume(player, TRUE);
838                                         }
839                                         break;
840
841                                 case MM_PLAYER_STATE_PAUSED:
842                                         /* NOTE: It should be worked as asynchronously.
843                                          * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
844                                          */
845                                         if (current_state == MM_PLAYER_STATE_PLAYING) {
846                                                 /* NOTE: If the current state is PLAYING, it means, async __gst_pause() is not completed yet.
847                                                  * The current state should be changed to paused purposely to prevent state conflict.
848                                                  */
849                                                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
850                                         }
851                                         __gst_resume(player, TRUE);
852                                         break;
853
854                                 case MM_PLAYER_STATE_PLAYING:
855                                         LOGD("player is already going to playing state, there is nothing to do.\n");
856                                         break;
857
858                                 case MM_PLAYER_STATE_NULL:
859                                 case MM_PLAYER_STATE_READY:
860                                 default:
861                                         LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
862                                         break;
863                                 }
864                         }
865                         break;
866
867                 case MM_PLAYER_STATE_NULL:
868                 case MM_PLAYER_STATE_READY:
869                 case MM_PLAYER_STATE_NONE:
870                 default:
871                         LOGW("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state));
872                         break;
873                 }
874         } else {
875                 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
876                  *      it's for stopping the pipeline clock to prevent dropping the data in sink element.
877                  */
878                 switch (pending_state) {
879                 case MM_PLAYER_STATE_NONE:
880                         {
881                                 if (current_state != MM_PLAYER_STATE_PAUSED) {
882                                         /* rtsp streaming pause makes rtsp server stop sending data. */
883                                         if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
884                                                 LOGD("set pause state during buffering\n");
885                                                 __gst_pause(player, TRUE);
886                                         }
887                                 }
888                         }
889                         break;
890
891                 case MM_PLAYER_STATE_PLAYING:
892                         /* rtsp streaming pause makes rtsp server stop sending data. */
893                         if (!MMPLAYER_IS_RTSP_STREAMING(player))
894                                 __gst_pause(player, TRUE);
895                         break;
896
897                 case MM_PLAYER_STATE_PAUSED:
898                         break;
899
900                 case MM_PLAYER_STATE_NULL:
901                 case MM_PLAYER_STATE_READY:
902                 default:
903                         LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
904                         break;
905                 }
906         }
907
908 exit:
909         return ret;
910 }
911
912 static void
913 __mmplayer_drop_subtitle(mm_player_t* player, gboolean is_drop)
914 {
915         MMPlayerGstElement *textbin;
916         MMPLAYER_FENTER();
917
918         MMPLAYER_RETURN_IF_FAIL(player &&
919                                         player->pipeline &&
920                                         player->pipeline->textbin);
921
922         MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
923
924         textbin = player->pipeline->textbin;
925
926         if (is_drop) {
927                 LOGD("Drop subtitle text after getting EOS\n");
928
929                 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", FALSE, NULL);
930                 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
931
932                 player->is_subtitle_force_drop = TRUE;
933         } else {
934                 if (player->is_subtitle_force_drop == TRUE) {
935                         LOGD("Enable subtitle data path without drop\n");
936
937                         g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
938                         g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", TRUE, NULL);
939
940                         LOGD("non-connected with external display");
941
942                         player->is_subtitle_force_drop = FALSE;
943                 }
944         }
945 }
946
947 static VariantData *
948 __mmplayer_adaptive_var_info(const VariantData *self, gpointer user_data)
949 {
950         VariantData *var_info = NULL;
951         g_return_val_if_fail(self != NULL, NULL);
952
953         var_info = g_new0(VariantData, 1);
954         if (!var_info) return NULL;
955         var_info->bandwidth = self->bandwidth;
956         var_info->width = self->width;
957         var_info->height = self->height;
958         return var_info;
959 }
960
961 void _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
962 {
963         mm_player_t* player = (mm_player_t*)hplayer;
964         GstMessage *msg = NULL;
965         GQueue *queue = NULL;
966
967         MMPLAYER_FENTER();
968         MMPLAYER_RETURN_IF_FAIL(player);
969
970         player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
971
972         /* destroy the gst bus msg thread */
973         if (player->bus_msg_thread) {
974                 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
975                 player->bus_msg_thread_exit = TRUE;
976                 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
977                 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
978
979                 LOGD("gst bus msg thread exit.");
980                 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
981                 player->bus_msg_thread = NULL;
982
983                 g_mutex_clear(&player->bus_msg_thread_mutex);
984                 g_cond_clear(&player->bus_msg_thread_cond);
985         }
986
987         g_mutex_lock(&player->bus_msg_q_lock);
988         queue = player->bus_msg_q;
989         while (!g_queue_is_empty(queue)) {
990                 msg = (GstMessage *)g_queue_pop_head(queue);
991                 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
992                 gst_message_unref(msg);
993         }
994         g_mutex_unlock(&player->bus_msg_q_lock);
995
996         MMPLAYER_FLEAVE();
997 }
998
999 gboolean __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
1000 {
1001         mm_player_t *player = (mm_player_t *) data;
1002
1003         g_return_val_if_fail(player, FALSE);
1004         g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
1005
1006         gst_message_ref(msg);
1007
1008         g_mutex_lock(&player->bus_msg_q_lock);
1009         g_queue_push_tail(player->bus_msg_q, msg);
1010         g_mutex_unlock(&player->bus_msg_q_lock);
1011
1012         MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1013         MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
1014         MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1015         return TRUE;
1016 }
1017
1018 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
1019 {
1020         mm_player_t *player = (mm_player_t*)(data);
1021         GstMessage *msg = NULL;
1022         GstBus *bus = NULL;
1023
1024         MMPLAYER_FENTER();
1025         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
1026                                                 player->pipeline &&
1027                                                 player->pipeline->mainbin &&
1028                                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
1029                                                 NULL);
1030
1031         bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
1032         if (!bus) {
1033                 LOGE("cannot get BUS from the pipeline");
1034                 return NULL;
1035         }
1036
1037         MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1038
1039         LOGD("[handle: %p] gst bus msg thread will be started.", player);
1040         while (!player->bus_msg_thread_exit) {
1041                 g_mutex_lock(&player->bus_msg_q_lock);
1042                 msg = g_queue_pop_head(player->bus_msg_q);
1043                 g_mutex_unlock(&player->bus_msg_q_lock);
1044                 if (msg == NULL) {
1045                         MMPLAYER_BUS_MSG_THREAD_WAIT(player);
1046                         continue;
1047                 }
1048                 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1049                 /* handle the gst msg */
1050                 __mmplayer_gst_callback(msg, player);
1051                 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1052                 gst_message_unref(msg);
1053         }
1054
1055         MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1056         gst_object_unref(GST_OBJECT(bus));
1057
1058         MMPLAYER_FLEAVE();
1059         return NULL;
1060 }
1061
1062 static void
1063 __mmplayer_gst_callback(GstMessage *msg, gpointer data)
1064 {
1065         mm_player_t* player = (mm_player_t*)(data);
1066         static gboolean async_done = FALSE;
1067
1068         MMPLAYER_RETURN_IF_FAIL(player);
1069         MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1070
1071         switch (GST_MESSAGE_TYPE(msg)) {
1072         case GST_MESSAGE_UNKNOWN:
1073                 LOGD("unknown message received\n");
1074                 break;
1075
1076         case GST_MESSAGE_EOS:
1077                 {
1078                         MMHandleType attrs = 0;
1079                         gint count = 0;
1080
1081                         LOGD("GST_MESSAGE_EOS received\n");
1082
1083                         /* NOTE : EOS event is comming multiple time. watch out it */
1084                         /* check state. we only process EOS when pipeline state goes to PLAYING */
1085                         if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1086                                 LOGD("EOS received on non-playing state. ignoring it\n");
1087                                 break;
1088                         }
1089
1090                         if (player->pipeline) {
1091                                 if (player->pipeline->textbin)
1092                                         __mmplayer_drop_subtitle(player, TRUE);
1093
1094                                 if ((player->audio_stream_cb) && (player->set_mode.pcm_extraction) && (!player->audio_stream_render_cb_ex)) {
1095                                         GstPad *pad = NULL;
1096
1097                                         pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
1098
1099                                         LOGD("release audio callback\n");
1100
1101                                         /* release audio callback */
1102                                         gst_pad_remove_probe(pad, player->audio_cb_probe_id);
1103                                         player->audio_cb_probe_id = 0;
1104                                         /* audio callback should be free because it can be called even though probe remove.*/
1105                                         player->audio_stream_cb = NULL;
1106                                         player->audio_stream_cb_user_param = NULL;
1107
1108                                 }
1109                         }
1110                         if ((player->audio_stream_render_cb_ex) && (!player->audio_stream_sink_sync))
1111                                 __mmplayer_audio_stream_clear_buffer(player, TRUE);
1112
1113                         /* rewind if repeat count is greater then zero */
1114                         /* get play count */
1115                         attrs = MMPLAYER_GET_ATTRS(player);
1116
1117                         if (attrs) {
1118                                 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1119
1120                                 LOGD("play count: %d, playback rate: %f\n", count, player->playback_rate);
1121
1122                                 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1123                                         if (player->playback_rate < 0.0) {
1124                                                 player->resumed_by_rewind = TRUE;
1125                                                 _mmplayer_set_mute((MMHandleType)player, 0);
1126                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1127                                         }
1128
1129                                         __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1130
1131                                         /* initialize */
1132                                         player->sent_bos = FALSE;
1133
1134                                         /* not posting eos when repeating */
1135                                         break;
1136                                 }
1137                         }
1138
1139                         if (player->pipeline)
1140                                 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1141
1142                         /* post eos message to application */
1143                         __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1144
1145                         /* reset last position */
1146                         player->last_position = 0;
1147                 }
1148                 break;
1149
1150         case GST_MESSAGE_ERROR:
1151                 {
1152                         GError *error = NULL;
1153                         gchar* debug = NULL;
1154
1155                         /* generating debug info before returning error */
1156                         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1157
1158                         /* get error code */
1159                         gst_message_parse_error(msg, &error, &debug);
1160
1161                         if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1162                                 /* Note : the streaming error from the streaming source is handled
1163                                  *   using __mmplayer_handle_streaming_error.
1164                                  */
1165                                 __mmplayer_handle_streaming_error(player, msg);
1166
1167                                 /* dump state of all element */
1168                                 __mmplayer_dump_pipeline_state(player);
1169                         } else {
1170                                 /* traslate gst error code to msl error code. then post it
1171                                  * to application if needed
1172                                  */
1173                                 __mmplayer_handle_gst_error(player, msg, error);
1174
1175                                 if (debug)
1176                                         LOGE("error debug : %s", debug);
1177                         }
1178
1179                         if (MMPLAYER_IS_HTTP_PD(player))
1180                                 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
1181
1182                         MMPLAYER_FREEIF(debug);
1183                         g_error_free(error);
1184                 }
1185                 break;
1186
1187         case GST_MESSAGE_WARNING:
1188                 {
1189                         char* debug = NULL;
1190                         GError* error = NULL;
1191
1192                         gst_message_parse_warning(msg, &error, &debug);
1193
1194                         LOGD("warning : %s\n", error->message);
1195                         LOGD("debug : %s\n", debug);
1196
1197                         MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1198
1199                         MMPLAYER_FREEIF(debug);
1200                         g_error_free(error);
1201                 }
1202                 break;
1203
1204         case GST_MESSAGE_TAG:
1205                 {
1206                         LOGD("GST_MESSAGE_TAG\n");
1207                         if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1208                                 LOGW("failed to extract tags from gstmessage\n");
1209                 }
1210                 break;
1211
1212         case GST_MESSAGE_BUFFERING:
1213                 {
1214                         MMMessageParamType msg_param = {0, };
1215                         int bRet = MM_ERROR_NONE;
1216
1217                         if (!(player->pipeline && player->pipeline->mainbin)) {
1218                                 LOGE("player pipeline handle is null");
1219                                 break;
1220                         }
1221
1222                         if (!MMPLAYER_IS_STREAMING(player))
1223                                 break;
1224
1225                         if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
1226                                 if (!MMPLAYER_CMD_TRYLOCK(player)) {
1227                                         /* skip the playback control by buffering msg while user request is handled. */
1228                                         gint per = 0;
1229
1230                                         LOGW("[PD mode] can't get cmd lock, only post buffering msg");
1231
1232                                         gst_message_parse_buffering(msg, &per);
1233                                         LOGD("[PD mode][%s] buffering %d %%....", GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)), per);
1234
1235                                         msg_param.connection.buffering = per;
1236                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1237                                         break;
1238                                 }
1239                         } else {
1240                                 MMPLAYER_CMD_LOCK(player);
1241                         }
1242
1243                         /* ignore the prev buffering message */
1244                         if ((player->streamer) && (player->streamer->is_buffering == FALSE)
1245                                 && (player->streamer->is_buffering_done == TRUE)) {
1246                                 gint buffer_percent = 0;
1247
1248                                 gst_message_parse_buffering(msg, &buffer_percent);
1249
1250                                 if (buffer_percent == MAX_BUFFER_PERCENT) {
1251                                         LOGD("Ignored all the previous buffering msg!(got %d%%)\n", buffer_percent);
1252                                         player->streamer->is_buffering_done = FALSE;
1253                                 }
1254                                 MMPLAYER_CMD_UNLOCK(player);
1255                                 break;
1256                         }
1257
1258                         __mmplayer_update_buffer_setting(player, msg);
1259
1260                         bRet = __mmplayer_handle_buffering_message(player);
1261
1262                         if (bRet == MM_ERROR_NONE) {
1263                                 msg_param.connection.buffering = player->streamer->buffering_percent;
1264                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1265
1266                                 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1267                                         player->pending_resume &&
1268                                         (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1269
1270                                         player->is_external_subtitle_added_now = FALSE;
1271                                         player->pending_resume = FALSE;
1272                                         _mmplayer_resume((MMHandleType)player);
1273                                 }
1274
1275                                 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1276                                         (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1277
1278                                         if (player->doing_seek) {
1279                                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1280                                                         player->doing_seek = FALSE;
1281                                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1282                                                 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1283                                                         async_done = TRUE;
1284                                                 }
1285                                         }
1286                                 }
1287                         } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1288                                 if (!player->streamer) {
1289                                         LOGW("player->streamer is NULL, so discarding the buffering percent update\n");
1290                                         MMPLAYER_CMD_UNLOCK(player);
1291                                         break;
1292                                 }
1293
1294                                 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1295
1296                                         LOGD("player->last_position=%lld , player->streamer->buffering_percent=%d \n",
1297                                                         GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1298
1299                                         if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1300                                                 msg_param.connection.buffering = player->streamer->buffering_percent;
1301                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1302                                         } else {
1303                                                 LOGD("Not updating Buffering Message for Live RTSP case !!!\n");
1304                                         }
1305                                 } else {
1306                                         msg_param.connection.buffering = player->streamer->buffering_percent;
1307                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1308                                 }
1309                         }
1310                         MMPLAYER_CMD_UNLOCK(player);
1311                 }
1312                 break;
1313
1314         case GST_MESSAGE_STATE_CHANGED:
1315                 {
1316                         MMPlayerGstElement *mainbin;
1317                         const GValue *voldstate, *vnewstate, *vpending;
1318                         GstState oldstate = GST_STATE_NULL;
1319                         GstState newstate = GST_STATE_NULL;
1320                         GstState pending = GST_STATE_NULL;
1321
1322                         if (!(player->pipeline && player->pipeline->mainbin)) {
1323                                 LOGE("player pipeline handle is null");
1324                                 break;
1325                         }
1326
1327                         mainbin = player->pipeline->mainbin;
1328
1329                         /* we only handle messages from pipeline */
1330                         if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1331                                 break;
1332
1333                         /* get state info from msg */
1334                         voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1335                         vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1336                         vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1337
1338                         if (!voldstate || !vnewstate) {
1339                                 LOGE("received msg has wrong format.");
1340                                 break;
1341                         }
1342
1343                         oldstate = (GstState)voldstate->data[0].v_int;
1344                         newstate = (GstState)vnewstate->data[0].v_int;
1345                         if (vpending)
1346                                 pending = (GstState)vpending->data[0].v_int;
1347
1348                         LOGD("state changed [%s] : %s ---> %s     final : %s\n",
1349                                 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1350                                 gst_element_state_get_name((GstState)oldstate),
1351                                 gst_element_state_get_name((GstState)newstate),
1352                                 gst_element_state_get_name((GstState)pending));
1353
1354                         if (newstate == GST_STATE_PLAYING) {
1355                                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1356
1357                                         int retVal = MM_ERROR_NONE;
1358                                         LOGD("trying to play from (%lu) pending position\n", player->pending_seek.pos);
1359
1360                                         retVal = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, TRUE);
1361
1362                                         if (MM_ERROR_NONE != retVal)
1363                                                 LOGE("failed to seek pending postion. just keep staying current position.\n");
1364
1365                                         player->pending_seek.is_pending = FALSE;
1366                                 }
1367                         }
1368
1369                         if (oldstate == newstate) {
1370                                 LOGD("pipeline reports state transition to old state");
1371                                 break;
1372                         }
1373
1374                         switch (newstate) {
1375                         case GST_STATE_VOID_PENDING:
1376                                 break;
1377
1378                         case GST_STATE_NULL:
1379                                 break;
1380
1381                         case GST_STATE_READY:
1382                                 break;
1383
1384                         case GST_STATE_PAUSED:
1385                                 {
1386                                         gboolean prepare_async = FALSE;
1387                                         player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
1388
1389                                         if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
1390                                                 __mmplayer_configure_audio_callback(player);
1391
1392                                         if (!player->sent_bos && oldstate == GST_STATE_READY) {
1393                                                 // managed prepare async case
1394                                                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1395                                                 LOGD("checking prepare mode for async transition - %d", prepare_async);
1396                                         }
1397
1398                                         if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1399                                                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1400
1401                                                 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1402                                                         __mm_player_streaming_set_content_bitrate(player->streamer,
1403                                                                 player->total_maximum_bitrate, player->total_bitrate);
1404
1405                                                 if (player->pending_seek.is_pending) {
1406                                                         LOGW("trying to do pending seek");
1407                                                         MMPLAYER_CMD_LOCK(player);
1408                                                         __gst_pending_seek(player);
1409                                                         MMPLAYER_CMD_UNLOCK(player);
1410                                                 }
1411                                         }
1412                                 }
1413                                 break;
1414
1415                         case GST_STATE_PLAYING:
1416                                 {
1417                                         player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
1418
1419                                         if (MMPLAYER_IS_STREAMING(player)) {
1420                                                 // managed prepare async case when buffering is completed
1421                                                 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1422                                                 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1423                                                         (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1424                                                         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1425
1426                                                 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1427
1428                                                         LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1429                                                         if (player->streamer->buffering_percent < 100) {
1430
1431                                                                 MMMessageParamType msg_param = {0, };
1432                                                                 LOGW("Posting Buffering Completed Message to Application !!!");
1433
1434                                                                 msg_param.connection.buffering = 100;
1435                                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1436                                                         }
1437                                                 }
1438                                         }
1439
1440                                         if (player->gapless.stream_changed) {
1441                                                 _mmplayer_update_content_attrs(player, ATTR_ALL);
1442                                                 player->gapless.stream_changed = FALSE;
1443                                         }
1444
1445                                         if (player->doing_seek && async_done) {
1446                                                 player->doing_seek = FALSE;
1447                                                 async_done = FALSE;
1448                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1449                                         }
1450                                 }
1451                                 break;
1452
1453                         default:
1454                                 break;
1455                         }
1456                 }
1457                 break;
1458
1459         case GST_MESSAGE_CLOCK_LOST:
1460                         {
1461                                 GstClock *clock = NULL;
1462                                 gboolean need_new_clock = FALSE;
1463
1464                                 gst_message_parse_clock_lost(msg, &clock);
1465                                 LOGD("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1466
1467                                 if (!player->videodec_linked)
1468                                         need_new_clock = TRUE;
1469                                 else if (!player->ini.use_system_clock)
1470                                         need_new_clock = TRUE;
1471
1472                                 if (need_new_clock) {
1473                                         LOGD("Provide clock is TRUE, do pause->resume\n");
1474                                         __gst_pause(player, FALSE);
1475                                         __gst_resume(player, FALSE);
1476                                 }
1477                         }
1478                         break;
1479
1480         case GST_MESSAGE_NEW_CLOCK:
1481                         {
1482                                 GstClock *clock = NULL;
1483                                 gst_message_parse_new_clock(msg, &clock);
1484                                 LOGD("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1485                         }
1486                         break;
1487
1488         case GST_MESSAGE_ELEMENT:
1489                         {
1490                                 const gchar *structure_name;
1491                                 gint count = 0, idx = 0;
1492                                 MMHandleType attrs = 0;
1493
1494                                 attrs = MMPLAYER_GET_ATTRS(player);
1495                                 if (!attrs) {
1496                                         LOGE("cannot get content attribute");
1497                                         break;
1498                                 }
1499
1500                                 if (gst_message_get_structure(msg) == NULL)
1501                                         break;
1502
1503                                 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1504                                 if (!structure_name)
1505                                         break;
1506
1507                                 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1508
1509                                 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1510                                         const GValue *var_info = NULL;
1511
1512                                         var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1513                                         if (var_info != NULL) {
1514                                                 if (player->adaptive_info.var_list)
1515                                                         g_list_free_full(player->adaptive_info.var_list, g_free);
1516
1517                                                 /* share addr or copy the list */
1518                                                 player->adaptive_info.var_list =
1519                                                         g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1520
1521                                                 count = g_list_length(player->adaptive_info.var_list);
1522                                                 if (count > 0) {
1523                                                         VariantData *temp = NULL;
1524
1525                                                         /* print out for debug */
1526                                                         LOGD("num of variant_info %d", count);
1527                                                         for (idx = 0; idx < count; idx++) {
1528                                                                 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1529                                                                 if (temp)
1530                                                                         LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1531                                                         }
1532                                                 }
1533                                         }
1534                                 }
1535
1536                                 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1537                                         gint num_buffers = 0;
1538                                         gint extra_num_buffers = 0;
1539
1540                                         if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1541                                                 player->video_num_buffers = num_buffers;
1542                                                 LOGD("video_num_buffers : %d", player->video_num_buffers);
1543                                         }
1544
1545                                         if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1546                                                 player->video_extra_num_buffers = extra_num_buffers;
1547                                                 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1548                                         }
1549                                         break;
1550                                 }
1551
1552                                 if (!strcmp(structure_name, "Language_list")) {
1553                                         const GValue *lang_list = NULL;
1554                                         lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1555                                         if (lang_list != NULL) {
1556                                                 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1557                                                 if (count > 1)
1558                                                         LOGD("Total audio tracks(from parser) = %d \n", count);
1559                                         }
1560                                 }
1561
1562                                 if (!strcmp(structure_name, "Ext_Sub_Language_List")) {
1563                                         const GValue *lang_list = NULL;
1564                                         MMPlayerLangStruct *temp = NULL;
1565
1566                                         lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1567                                         if (lang_list != NULL) {
1568                                                 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1569                                                 if (count) {
1570                                                         MMPLAYER_SUBTITLE_INFO_LOCK(player);
1571                                                         player->subtitle_language_list = (GList *)g_value_get_pointer(lang_list);
1572                                                         mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)count);
1573                                                         if (mmf_attrs_commit(attrs))
1574                                                                 LOGE("failed to commit.\n");
1575                                                         LOGD("Total subtitle tracks = %d \n", count);
1576
1577                                                         while (count) {
1578                                                                 temp = g_list_nth_data(player->subtitle_language_list, count - 1);
1579                                                                 if (temp)
1580                                                                         LOGD("value of lang_key is %s and lang_code is %s",
1581                                                                                                 temp->language_key, temp->language_code);
1582                                                                 count--;
1583                                                         }
1584                                                         MMPLAYER_SUBTITLE_INFO_SIGNAL(player);
1585                                                         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
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                                         player->streaming_type = __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                         if (!__mmplayer_gst_handle_duration(player, msg))
1651                                 LOGW("failed to update duration");
1652                 }
1653
1654                 break;
1655
1656         case GST_MESSAGE_ASYNC_START:
1657                         LOGD("GST_MESSAGE_ASYNC_START : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1658                 break;
1659
1660         case GST_MESSAGE_ASYNC_DONE:
1661                 {
1662                         LOGD("GST_MESSAGE_ASYNC_DONE : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1663
1664                         /* we only handle messages from pipeline */
1665                         if (msg->src != (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst)
1666                                 break;
1667
1668                         if (player->doing_seek) {
1669                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1670                                         player->doing_seek = FALSE;
1671                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1672                                 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1673                                         if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1674                                                 (player->streamer) &&
1675                                                 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1676                                                 (player->streamer->is_buffering == FALSE)) {
1677                                                 GstQuery *query = NULL;
1678                                                 gboolean busy = FALSE;
1679                                                 gint percent = 0;
1680
1681                                                 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1682                                                         query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1683                                                         if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1684                                                                 gst_query_parse_buffering_percent(query, &busy, &percent);
1685                                                         gst_query_unref(query);
1686
1687                                                         LOGD("buffered percent(%s): %d\n",
1688                                                                 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1689                                                 }
1690
1691                                                 if (percent >= 100) {
1692                                                         player->streamer->is_buffering = FALSE;
1693                                                         __mmplayer_handle_buffering_message(player);
1694                                                 }
1695                                         }
1696
1697                                         async_done = TRUE;
1698                                 }
1699                         }
1700                 }
1701                 break;
1702
1703         #if 0 /* delete unnecessary logs */
1704         case GST_MESSAGE_REQUEST_STATE:         LOGD("GST_MESSAGE_REQUEST_STATE\n"); break;
1705         case GST_MESSAGE_STEP_START:            LOGD("GST_MESSAGE_STEP_START\n"); break;
1706         case GST_MESSAGE_QOS:                           LOGD("GST_MESSAGE_QOS\n"); break;
1707         case GST_MESSAGE_PROGRESS:                      LOGD("GST_MESSAGE_PROGRESS\n"); break;
1708         case GST_MESSAGE_ANY:                           LOGD("GST_MESSAGE_ANY\n"); break;
1709         case GST_MESSAGE_INFO:                          LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1710         case GST_MESSAGE_STATE_DIRTY:           LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1711         case GST_MESSAGE_STEP_DONE:                     LOGD("GST_MESSAGE_STEP_DONE\n"); break;
1712         case GST_MESSAGE_CLOCK_PROVIDE:         LOGD("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
1713         case GST_MESSAGE_STRUCTURE_CHANGE:      LOGD("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
1714         case GST_MESSAGE_STREAM_STATUS:         LOGD("GST_MESSAGE_STREAM_STATUS\n"); break;
1715         case GST_MESSAGE_APPLICATION:           LOGD("GST_MESSAGE_APPLICATION\n"); break;
1716         case GST_MESSAGE_SEGMENT_START:         LOGD("GST_MESSAGE_SEGMENT_START\n"); break;
1717         case GST_MESSAGE_SEGMENT_DONE:          LOGD("GST_MESSAGE_SEGMENT_DONE\n"); break;
1718         case GST_MESSAGE_LATENCY:                               LOGD("GST_MESSAGE_LATENCY\n"); break;
1719         #endif
1720
1721         default:
1722                 break;
1723         }
1724
1725         /* should not call 'gst_message_unref(msg)' */
1726         return;
1727 }
1728
1729 static gboolean
1730 __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg)
1731 {
1732         gint64 bytes = 0;
1733
1734         MMPLAYER_FENTER();
1735
1736         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1737         MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1738
1739         if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1740                 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1741                 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1742
1743                 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1744                         LOGD("data total size of http content: %lld", bytes);
1745                         player->http_content_size = (bytes > 0) ? (bytes) : (0);
1746                 }
1747         } else
1748                 /* handling audio clip which has vbr. means duration is keep changing */
1749                 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1750
1751         MMPLAYER_FLEAVE();
1752
1753         return TRUE;
1754 }
1755
1756 static void __mmplayer_get_metadata_360_from_tags(GstTagList *tags,
1757                 mm_player_spherical_metadata_t *metadata) {
1758         gst_tag_list_get_int(tags, "is_spherical", &metadata->is_spherical);
1759         gst_tag_list_get_int(tags, "is_stitched", &metadata->is_stitched);
1760         gst_tag_list_get_string(tags, "stitching_software",
1761                         &metadata->stitching_software);
1762         gst_tag_list_get_string(tags, "projection_type",
1763                         &metadata->projection_type_string);
1764         gst_tag_list_get_string(tags, "stereo_mode", &metadata->stereo_mode_string);
1765         gst_tag_list_get_int(tags, "source_count", &metadata->source_count);
1766         gst_tag_list_get_int(tags, "init_view_heading",
1767                         &metadata->init_view_heading);
1768         gst_tag_list_get_int(tags, "init_view_pitch", &metadata->init_view_pitch);
1769         gst_tag_list_get_int(tags, "init_view_roll", &metadata->init_view_roll);
1770         gst_tag_list_get_int(tags, "timestamp", &metadata->timestamp);
1771         gst_tag_list_get_int(tags, "full_pano_width_pixels",
1772                         &metadata->full_pano_width_pixels);
1773         gst_tag_list_get_int(tags, "full_pano_height_pixels",
1774                         &metadata->full_pano_height_pixels);
1775         gst_tag_list_get_int(tags, "cropped_area_image_width",
1776                         &metadata->cropped_area_image_width);
1777         gst_tag_list_get_int(tags, "cropped_area_image_height",
1778                         &metadata->cropped_area_image_height);
1779         gst_tag_list_get_int(tags, "cropped_area_left",
1780                         &metadata->cropped_area_left);
1781         gst_tag_list_get_int(tags, "cropped_area_top", &metadata->cropped_area_top);
1782         gst_tag_list_get_int(tags, "ambisonic_type", &metadata->ambisonic_type);
1783         gst_tag_list_get_int(tags, "ambisonic_format", &metadata->ambisonic_format);
1784         gst_tag_list_get_int(tags, "ambisonic_order", &metadata->ambisonic_order);
1785 }
1786
1787 static gboolean
1788 __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg)
1789 {
1790
1791 /* macro for better code readability */
1792 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
1793 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
1794         if (string != NULL) { \
1795                 SECURE_LOGD("update tag string : %s\n", string); \
1796                 if (strlen(string) > MM_MAX_STRING_LENGTH) { \
1797                         char *new_string = malloc(MM_MAX_STRING_LENGTH); \
1798                         strncpy(new_string, string, MM_MAX_STRING_LENGTH-1); \
1799                         new_string[MM_MAX_STRING_LENGTH-1] = '\0'; \
1800                         mm_attrs_set_string_by_name(attribute, playertag, new_string); \
1801                         g_free(new_string); \
1802                         new_string = NULL; \
1803                 } else { \
1804                         mm_attrs_set_string_by_name(attribute, playertag, string); \
1805                 } \
1806                 g_free(string); \
1807                 string = NULL; \
1808         } \
1809 }
1810
1811 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
1812 do {    \
1813         GstSample *sample = NULL;\
1814         if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
1815                 GstMapInfo info = GST_MAP_INFO_INIT;\
1816                 buffer = gst_sample_get_buffer(sample);\
1817                 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
1818                         LOGD("failed to get image data from tag");\
1819                         gst_sample_unref(sample);\
1820                         return FALSE;\
1821                 } \
1822                 SECURE_LOGD("update album cover data : %p, size : %d\n", info.data, info.size);\
1823                 MMPLAYER_FREEIF(player->album_art);\
1824                 player->album_art = (gchar *)g_malloc(info.size);\
1825                 if (player->album_art) {\
1826                         memcpy(player->album_art, info.data, info.size);\
1827                         mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size);\
1828                         if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
1829                                 msg_param.data = (void *)player->album_art;\
1830                                 msg_param.size = info.size;\
1831                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
1832                                 SECURE_LOGD("post message image buffer data : %p, size : %d\n", info.data, info.size);\
1833                         } \
1834                 } \
1835                 gst_buffer_unmap(buffer, &info);\
1836                 gst_sample_unref(sample);\
1837         }       \
1838 } while (0)
1839
1840 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
1841 do {    \
1842         if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
1843                 if (v_uint) { \
1844                         int i = 0; \
1845                         gchar *tag_list_str = NULL; \
1846                         MMPlayerTrackType track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
1847                         if (strstr(GST_OBJECT_NAME(msg->src), "audio")) \
1848                                 track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
1849                         else if (strstr(GST_OBJECT_NAME(msg->src), "video")) \
1850                                 track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
1851                         else \
1852                                 track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
1853                         if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
1854                                 if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
1855                                         mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
1856                                 player->bitrate[track_type] = v_uint; \
1857                                 player->total_bitrate = 0; \
1858                                 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
1859                                         player->total_bitrate += player->bitrate[i]; \
1860                                 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate); \
1861                                 SECURE_LOGD("update bitrate %d[bps] of stream #%d.\n", v_uint, (int)track_type); \
1862                         } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
1863                                 player->maximum_bitrate[track_type] = v_uint; \
1864                                 player->total_maximum_bitrate = 0; \
1865                                 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
1866                                         player->total_maximum_bitrate += player->maximum_bitrate[i]; \
1867                                 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate);\
1868                                 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d\n", v_uint, (int)track_type);\
1869                         } else { \
1870                                 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
1871                         } \
1872                         v_uint = 0;\
1873                         g_free(tag_list_str); \
1874                 } \
1875         } \
1876 } while (0)
1877
1878 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
1879 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
1880         if (date != NULL) {\
1881                 string = g_strdup_printf("%d", g_date_get_year(date));\
1882                 mm_attrs_set_string_by_name(attribute, playertag, string);\
1883                 SECURE_LOGD("metainfo year : %s\n", string);\
1884                 MMPLAYER_FREEIF(string);\
1885                 g_date_free(date);\
1886         } \
1887 }
1888
1889 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, attribute, playertag) \
1890 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
1891         if (datetime != NULL) {\
1892                 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
1893                 mm_attrs_set_string_by_name(attribute, playertag, string);\
1894                 SECURE_LOGD("metainfo year : %s\n", string);\
1895                 MMPLAYER_FREEIF(string);\
1896                 gst_date_time_unref(datetime);\
1897         } \
1898 }
1899
1900 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
1901 if (gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64)) {\
1902         if (v_uint64) {\
1903                 /* FIXIT : don't know how to store date */\
1904                 g_assert(1);\
1905                 v_uint64 = 0;\
1906         } \
1907 }
1908
1909 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
1910 if (gst_tag_list_get_double(tag_list, gsttag, &v_double)) {\
1911         if (v_double) {\
1912                 /* FIXIT : don't know how to store date */\
1913                 g_assert(1);\
1914                 v_double = 0;\
1915         } \
1916 }
1917
1918         /* function start */
1919         GstTagList* tag_list = NULL;
1920
1921         MMHandleType attrs = 0;
1922
1923         char *string = NULL;
1924         guint v_uint = 0;
1925         GDate *date = NULL;
1926         GstDateTime *datetime = NULL;
1927         /* album cover */
1928         GstBuffer *buffer = NULL;
1929         gint index = 0;
1930         MMMessageParamType msg_param = {0, };
1931
1932         /* currently not used. but those are needed for above macro */
1933         //guint64 v_uint64 = 0;
1934         //gdouble v_double = 0;
1935
1936         MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
1937
1938         attrs = MMPLAYER_GET_ATTRS(player);
1939
1940         MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE);
1941
1942         /* get tag list from gst message */
1943         gst_message_parse_tag(msg, &tag_list);
1944
1945         /* store tags to player attributes */
1946         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
1947         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
1948         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
1949         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
1950         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
1951         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
1952         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
1953         MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
1954         MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, attrs, "tag_date");
1955         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
1956         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
1957         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
1958         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
1959         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
1960         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
1961         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
1962         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
1963         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
1964         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
1965         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
1966         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
1967         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
1968         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
1969         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
1970         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
1971         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
1972         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
1973         /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
1974         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
1975         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
1976         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
1977         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
1978         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
1979         MMPLAYER_UPDATE_TAG_LOCK(player);
1980         MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
1981         MMPLAYER_UPDATE_TAG_UNLOCK(player);
1982         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
1983         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
1984         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
1985         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
1986         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
1987         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
1988         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
1989         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
1990         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
1991         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
1992         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
1993         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
1994         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation");
1995
1996         if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
1997                 if (player->video360_metadata.is_spherical == -1) {
1998                         __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
1999                         mm_attrs_set_int_by_name(attrs, "content_video_is_spherical",
2000                                         player->video360_metadata.is_spherical);
2001                         if (player->video360_metadata.is_spherical == 1) {
2002                                 LOGD("This is spherical content for 360 playback.");
2003                                 player->is_content_spherical = TRUE;
2004                         } else {
2005                                 LOGD("This is not spherical content");
2006                                 player->is_content_spherical = FALSE;
2007                         }
2008
2009                         if (player->video360_metadata.projection_type_string) {
2010                                 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
2011                                         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
2012                                 } else {
2013                                         LOGE("Projection %s: code not implemented.\n", player->video360_metadata.projection_type_string);
2014                                         player->is_content_spherical = player->is_video360_enabled = FALSE;
2015                                 }
2016                         }
2017
2018                         if (player->video360_metadata.stereo_mode_string) {
2019                                 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
2020                                         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
2021                                 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
2022                                         player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
2023                                 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
2024                                         player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
2025                                 } else {
2026                                         LOGE("Stereo mode %s: code not implemented.\n", player->video360_metadata.stereo_mode_string);
2027                                         player->is_content_spherical = player->is_video360_enabled = FALSE;
2028                                 }
2029                         }
2030                 }
2031         }
2032
2033         if (mmf_attrs_commit(attrs))
2034                 LOGE("failed to commit.\n");
2035
2036         gst_tag_list_free(tag_list);
2037
2038         return TRUE;
2039 }
2040
2041 static void
2042 __mmplayer_gst_rtp_no_more_pads(GstElement *element,  gpointer data)
2043 {
2044         mm_player_t* player = (mm_player_t*) data;
2045
2046         MMPLAYER_FENTER();
2047
2048         /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2049           * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2050           * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2051           * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2052
2053           * [1] audio and video will be dumped with filesink.
2054           * [2] autoplugging is done by just using pad caps.
2055           * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2056           * and the video will be dumped via filesink.
2057           */
2058         if (player->num_dynamic_pad == 0) {
2059                 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
2060
2061                 if (!__mmplayer_gst_remove_fakesink(player,
2062                         &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2063                         /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
2064                          * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2065                          * source element are not same. To overcome this situation, this function will called
2066                          * several places and several times. Therefore, this is not an error case.
2067                          */
2068                         return;
2069         }
2070
2071         /* create dot before error-return. for debugging */
2072         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2073
2074         player->no_more_pad = TRUE;
2075
2076         MMPLAYER_FLEAVE();
2077 }
2078
2079 static gboolean
2080 __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink)
2081 {
2082         GstElement* parent = NULL;
2083
2084         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
2085
2086         /* if we have no fakesink. this meas we are using decodebin which doesn'
2087         t need to add extra fakesink */
2088         MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
2089
2090         /* lock */
2091         MMPLAYER_FSINK_LOCK(player);
2092
2093         if (!fakesink->gst)
2094                 goto ERROR;
2095
2096         /* get parent of fakesink */
2097         parent = (GstElement*)gst_object_get_parent((GstObject*)fakesink->gst);
2098         if (!parent) {
2099                 LOGD("fakesink already removed\n");
2100                 goto ERROR;
2101         }
2102
2103         gst_element_set_locked_state(fakesink->gst, TRUE);
2104
2105         /* setting the state to NULL never returns async
2106          * so no need to wait for completion of state transiton
2107          */
2108         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
2109                 LOGE("fakesink state change failure!\n");
2110                 /* FIXIT : should I return here? or try to proceed to next? */
2111                 /* return FALSE; */
2112
2113         /* remove fakesink from it's parent */
2114         if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
2115                 LOGE("failed to remove fakesink\n");
2116
2117                 gst_object_unref(parent);
2118
2119                 goto ERROR;
2120         }
2121
2122         gst_object_unref(parent);
2123
2124         LOGD("state-holder removed\n");
2125
2126         gst_element_set_locked_state(fakesink->gst, FALSE);
2127
2128         MMPLAYER_FSINK_UNLOCK(player);
2129         return TRUE;
2130
2131 ERROR:
2132         if (fakesink->gst)
2133                 gst_element_set_locked_state(fakesink->gst, FALSE);
2134
2135         MMPLAYER_FSINK_UNLOCK(player);
2136         return FALSE;
2137 }
2138
2139
2140 static void
2141 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2142 {
2143         GstPad *sinkpad = NULL;
2144         GstCaps* caps = NULL;
2145         GstElement* new_element = NULL;
2146         GstStructure* str = NULL;
2147         const gchar* name = NULL;
2148
2149         mm_player_t* player = (mm_player_t*) data;
2150
2151         MMPLAYER_FENTER();
2152
2153         MMPLAYER_RETURN_IF_FAIL(element && pad);
2154         MMPLAYER_RETURN_IF_FAIL(player &&
2155                                         player->pipeline &&
2156                                         player->pipeline->mainbin);
2157
2158
2159         /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2160          * num_dynamic_pad will decreased after creating a sinkbin.
2161          */
2162         player->num_dynamic_pad++;
2163         LOGD("stream count inc : %d\n", player->num_dynamic_pad);
2164
2165         caps = gst_pad_query_caps(pad, NULL);
2166
2167         MMPLAYER_CHECK_NULL(caps);
2168
2169         /* clear  previous result*/
2170         player->have_dynamic_pad = FALSE;
2171
2172         str = gst_caps_get_structure(caps, 0);
2173
2174         if (!str) {
2175                 LOGE("cannot get structure from caps.\n");
2176                 goto ERROR;
2177         }
2178
2179         name = gst_structure_get_name(str);
2180         if (!name) {
2181                 LOGE("cannot get mimetype from structure.\n");
2182                 goto ERROR;
2183         }
2184
2185         if (strstr(name, "video")) {
2186                 gint stype = 0;
2187                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2188
2189                 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
2190                         if (player->v_stream_caps) {
2191                                 gst_caps_unref(player->v_stream_caps);
2192                                 player->v_stream_caps = NULL;
2193                         }
2194
2195                         new_element = gst_element_factory_make("fakesink", NULL);
2196                         player->num_dynamic_pad--;
2197                         goto NEW_ELEMENT;
2198                 }
2199         }
2200
2201         /* clear  previous result*/
2202         player->have_dynamic_pad = FALSE;
2203
2204         if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
2205                 LOGE("failed to autoplug for caps");
2206                 goto ERROR;
2207         }
2208
2209         /* check if there's dynamic pad*/
2210         if (player->have_dynamic_pad) {
2211                 LOGE("using pad caps assums there's no dynamic pad !\n");
2212                 goto ERROR;
2213         }
2214
2215         gst_caps_unref(caps);
2216         caps = NULL;
2217
2218 NEW_ELEMENT:
2219
2220         /* excute new_element if created*/
2221         if (new_element) {
2222                 LOGD("adding new element to pipeline\n");
2223
2224                 /* set state to READY before add to bin */
2225                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2226
2227                 /* add new element to the pipeline */
2228                 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2229                         LOGE("failed to add autoplug element to bin\n");
2230                         goto ERROR;
2231                 }
2232
2233                 /* get pad from element */
2234                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2235                 if (!sinkpad) {
2236                         LOGE("failed to get sinkpad from autoplug element\n");
2237                         goto ERROR;
2238                 }
2239
2240                 /* link it */
2241                 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2242                         LOGE("failed to link autoplug element\n");
2243                         goto ERROR;
2244                 }
2245
2246                 gst_object_unref(sinkpad);
2247                 sinkpad = NULL;
2248
2249                 /* run. setting PLAYING here since streamming source is live source */
2250                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2251         }
2252
2253         if (caps)
2254                 gst_caps_unref(caps);
2255
2256         MMPLAYER_FLEAVE();
2257
2258         return;
2259
2260 STATE_CHANGE_FAILED:
2261 ERROR:
2262         /* FIXIT : take care if new_element has already added to pipeline */
2263         if (new_element)
2264                 gst_object_unref(GST_OBJECT(new_element));
2265
2266         if (sinkpad)
2267                 gst_object_unref(GST_OBJECT(sinkpad));
2268
2269         if (caps)
2270                 gst_caps_unref(caps);
2271
2272         /* FIXIT : how to inform this error to MSL ????? */
2273         /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2274          * then post an error to application
2275          */
2276 }
2277
2278 static GstPadProbeReturn
2279 __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data)
2280 {
2281         LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
2282         return GST_PAD_PROBE_OK;
2283 }
2284
2285 static GstPadProbeReturn
2286 __mmplayer_gst_selector_event_probe(GstPad * pad, GstPadProbeInfo * info, gpointer data)
2287 {
2288         GstPadProbeReturn ret = GST_PAD_PROBE_OK;
2289         GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
2290         mm_player_t* player = (mm_player_t*)data;
2291         GstCaps* caps = NULL;
2292         GstStructure* str = NULL;
2293         const gchar* name = NULL;
2294         MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2295
2296
2297         if (GST_EVENT_IS_DOWNSTREAM(event)) {
2298                 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
2299                         GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
2300                         GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
2301                         GST_EVENT_TYPE(event) != GST_EVENT_EOS)
2302                         return ret;
2303         } else if (GST_EVENT_IS_UPSTREAM(event)) {
2304                 if (GST_EVENT_TYPE(event) != GST_EVENT_QOS)
2305                         return ret;
2306         }
2307
2308         caps = gst_pad_query_caps(pad, NULL);
2309         if (!caps) {
2310                 LOGE("failed to get caps from pad[%s:%s]", GST_DEBUG_PAD_NAME(pad));
2311                 return ret;
2312         }
2313
2314         str = gst_caps_get_structure(caps, 0);
2315         if (!str) {
2316                 LOGE("failed to get structure from caps");
2317                 goto ERROR;
2318         }
2319
2320         name = gst_structure_get_name(str);
2321         if (!name) {
2322                 LOGE("failed to get name from str");
2323                 goto ERROR;
2324         }
2325
2326         if (strstr(name, "audio")) {
2327                 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2328         } else if (strstr(name, "video")) {
2329                 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2330         } else {
2331                 /* text track is not supportable */
2332                 LOGE("invalid name %s", name);
2333                 goto ERROR;
2334         }
2335
2336         switch (GST_EVENT_TYPE(event)) {
2337         case GST_EVENT_EOS:
2338                 {
2339                         /* in case of gapless, drop eos event not to send it to sink */
2340                         if (player->gapless.reconfigure && !player->msg_posted) {
2341                                 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
2342                                 ret = GST_PAD_PROBE_DROP;
2343                         }
2344                         break;
2345                 }
2346         case GST_EVENT_STREAM_START:
2347                 {
2348                         gint64 stop_running_time = 0;
2349                         gint64 position_running_time = 0;
2350                         gint64 position = 0;
2351                         gint idx = 0;
2352
2353                         for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
2354                                 if ((player->gapless.update_segment[idx] == TRUE) ||
2355                                         !(player->selector[idx].event_probe_id)) {
2356                                         /* LOGW("[%d] skip", idx); */
2357                                         continue;
2358                                 }
2359
2360                                 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
2361                                         stop_running_time =
2362                                                 gst_segment_to_running_time(&player->gapless.segment[idx],
2363                                                                 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
2364                                 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
2365                                         stop_running_time =
2366                                                 gst_segment_to_running_time(&player->gapless.segment[idx],
2367                                                                 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
2368                                 } else {
2369                                         LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
2370                                         stop_running_time =
2371                                                 gst_segment_to_running_time(&player->gapless.segment[idx],
2372                                                                 GST_FORMAT_TIME, player->duration);
2373                                 }
2374
2375                                 position_running_time =
2376                                         gst_segment_to_running_time(&player->gapless.segment[idx],
2377                                         GST_FORMAT_TIME, player->gapless.segment[idx].position);
2378
2379                                 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
2380                                         GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
2381                                         idx,
2382                                         GST_TIME_ARGS(stop_running_time),
2383                                         GST_TIME_ARGS(position_running_time),
2384                                         GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
2385                                         GST_FORMAT_TIME, player->gapless.segment[idx].start)));
2386
2387                                 position_running_time = MAX(position_running_time, stop_running_time);
2388                                 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
2389                                                                                                 GST_FORMAT_TIME, player->gapless.segment[idx].start);
2390                                 position_running_time = MAX(0, position_running_time);
2391                                 position = MAX(position, position_running_time);
2392                         }
2393
2394                         if (position != 0) {
2395                                 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2396                                         stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
2397                                         GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
2398
2399                                 player->gapless.start_time[stream_type] += position;
2400                         }
2401                         break;
2402                 }
2403         case GST_EVENT_FLUSH_STOP:
2404                 {
2405                         LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
2406                         gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
2407                         player->gapless.start_time[stream_type] = 0;
2408                         break;
2409                 }
2410         case GST_EVENT_SEGMENT:
2411                 {
2412                         GstSegment segment;
2413                         GstEvent *tmpev;
2414
2415                         LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
2416                         gst_event_copy_segment(event, &segment);
2417
2418                         if (segment.format == GST_FORMAT_TIME) {
2419                                 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
2420                                          ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
2421                                          ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
2422                                         GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
2423                                         GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
2424                                         GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
2425
2426                                 /* keep the all the segment ev to cover the seeking */
2427                                 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
2428                                 player->gapless.update_segment[stream_type] = TRUE;
2429
2430                                 if (!player->gapless.running)
2431                                         break;
2432
2433                                 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
2434
2435                                 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
2436
2437                                 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
2438                                 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
2439                                 gst_event_unref(event);
2440                                 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2441                         }
2442                         break;
2443                 }
2444         case GST_EVENT_QOS:
2445                 {
2446                         gdouble proportion = 0.0;
2447                         GstClockTimeDiff diff = 0;
2448                         GstClockTime timestamp = 0;
2449                         gint64 running_time_diff = -1;
2450                         GstQOSType type = 0;
2451                         GstEvent *tmpev = NULL;
2452
2453                         running_time_diff = player->gapless.segment[stream_type].base;
2454
2455                         if (running_time_diff <= 0) /* don't need to adjust */
2456                                 break;
2457
2458                         gst_event_parse_qos(event, &type, &proportion, &diff, &timestamp);
2459                         gst_event_unref(event);
2460
2461                         if (timestamp < running_time_diff) {
2462                                 LOGW("QOS event from previous group");
2463                                 ret = GST_PAD_PROBE_DROP;
2464                                 break;
2465                         }
2466
2467                         LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
2468                                  " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
2469                                                 stream_type, GST_TIME_ARGS(timestamp),
2470                                                 GST_TIME_ARGS(running_time_diff),
2471                                                 GST_TIME_ARGS(timestamp - running_time_diff));
2472
2473                         timestamp -= running_time_diff;
2474
2475                         /* That case is invalid for QoS events */
2476                         if (diff < 0 && -diff > timestamp) {
2477                                 LOGW("QOS event from previous group");
2478                                 ret = GST_PAD_PROBE_DROP;
2479                                 break;
2480                         }
2481
2482                         tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
2483                         GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2484
2485                         break;
2486                 }
2487         default:
2488                 break;
2489         }
2490
2491 ERROR:
2492         if (caps)
2493                 gst_caps_unref(caps);
2494         return ret;
2495 }
2496
2497 static void
2498 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2499 {
2500         mm_player_t* player = NULL;
2501         GstElement* pipeline = NULL;
2502         GstElement* selector = NULL;
2503         GstElement* fakesink = NULL;
2504         GstCaps* caps = NULL;
2505         GstStructure* str = NULL;
2506         const gchar* name = NULL;
2507         GstPad* sinkpad = NULL;
2508         GstPad* srcpad = NULL;
2509         gboolean first_track = FALSE;
2510
2511         enum MainElementID elemId = MMPLAYER_M_NUM;
2512         MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2513
2514         /* check handles */
2515         player = (mm_player_t*)data;
2516
2517         MMPLAYER_RETURN_IF_FAIL(elem && pad);
2518         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2519
2520         //LOGD("pad-added signal handling\n");
2521
2522         pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
2523
2524         /* get mimetype from caps */
2525         caps = gst_pad_query_caps(pad, NULL);
2526         if (!caps) {
2527                 LOGE("cannot get caps from pad.\n");
2528                 goto ERROR;
2529         }
2530
2531         str = gst_caps_get_structure(caps, 0);
2532         if (!str) {
2533                 LOGE("cannot get structure from caps.\n");
2534                 goto ERROR;
2535         }
2536
2537         name = gst_structure_get_name(str);
2538         if (!name) {
2539                 LOGE("cannot get mimetype from structure.\n");
2540                 goto ERROR;
2541         }
2542
2543         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2544         //LOGD("detected mimetype : %s\n", name);
2545
2546         if (strstr(name, "video")) {
2547                 gint stype = 0;
2548
2549                 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
2550                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2551
2552                 /* don't make video because of not required, and not support multiple track */
2553                 if (stype == MM_DISPLAY_SURFACE_NULL) {
2554                         LOGD("no video sink by null surface");
2555
2556                         gchar *caps_str = gst_caps_to_string(caps);
2557                         if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
2558                                 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
2559                                 player->set_mode.video_zc = TRUE;
2560
2561                         MMPLAYER_FREEIF(caps_str);
2562
2563                         if (player->v_stream_caps) {
2564                                 gst_caps_unref(player->v_stream_caps);
2565                                 player->v_stream_caps = NULL;
2566                         }
2567
2568                         LOGD("create fakesink instead of videobin");
2569
2570                         /* fake sink */
2571                         fakesink = gst_element_factory_make("fakesink", NULL);
2572                         if (fakesink == NULL) {
2573                                 LOGE("ERROR : fakesink create error\n");
2574                                 goto ERROR;
2575                         }
2576
2577                         if (player->ini.set_dump_element_flag)
2578                                 __mmplayer_add_dump_buffer_probe(player, fakesink);
2579
2580                         player->video_fakesink = fakesink;
2581
2582                         /* store it as it's sink element */
2583                         __mmplayer_add_sink(player, player->video_fakesink);
2584
2585                         gst_bin_add(GST_BIN(pipeline), fakesink);
2586
2587                         // link
2588                         sinkpad = gst_element_get_static_pad(fakesink, "sink");
2589
2590                         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2591                                 LOGW("failed to link fakesink\n");
2592                                 gst_object_unref(GST_OBJECT(fakesink));
2593                                 goto ERROR;
2594                         }
2595
2596                         if (stype == MM_DISPLAY_SURFACE_REMOTE) {
2597                                 MMPLAYER_SIGNAL_CONNECT(player, sinkpad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2598                                                 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
2599                         }
2600
2601                         if (player->set_mode.media_packet_video_stream) {
2602                                 g_object_set(G_OBJECT(fakesink), "signal-handoffs", TRUE, NULL);
2603
2604                                 MMPLAYER_SIGNAL_CONNECT(player,
2605                                                                                 G_OBJECT(fakesink),
2606                                                                                 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2607                                                                                 "handoff",
2608                                                                                 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
2609                                                                                 (gpointer)player);
2610
2611                                 MMPLAYER_SIGNAL_CONNECT(player,
2612                                                                                 G_OBJECT(fakesink),
2613                                                                                 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2614                                                                                 "preroll-handoff",
2615                                                                                 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
2616                                                                                 (gpointer)player);
2617                         }
2618
2619                         g_object_set(G_OBJECT(fakesink), "async", TRUE, "sync", TRUE, NULL);
2620                         gst_element_set_state(fakesink, GST_STATE_PAUSED);
2621                         goto DONE;
2622                 }
2623
2624                 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2625                         __mmplayer_gst_decode_callback(elem, pad, player);
2626                         goto DONE;
2627                 }
2628
2629                 LOGD("video selector \n");
2630                 elemId = MMPLAYER_M_V_INPUT_SELECTOR;
2631                 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2632         } else {
2633                 if (strstr(name, "audio")) {
2634                         gint samplerate = 0;
2635                         gint channels = 0;
2636
2637                         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2638                                 __mmplayer_gst_decode_callback(elem, pad, player);
2639                                 goto DONE;
2640                         }
2641
2642                         LOGD("audio selector \n");
2643                         elemId = MMPLAYER_M_A_INPUT_SELECTOR;
2644                         stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2645
2646                         gst_structure_get_int(str, "rate", &samplerate);
2647                         gst_structure_get_int(str, "channels", &channels);
2648
2649                         if ((channels > 0 && samplerate == 0)) {//exclude audio decoding
2650                                 /* fake sink */
2651                                 fakesink = gst_element_factory_make("fakesink", NULL);
2652                                 if (fakesink == NULL) {
2653                                         LOGE("ERROR : fakesink create error\n");
2654                                         goto ERROR;
2655                                 }
2656
2657                                 gst_bin_add(GST_BIN(pipeline), fakesink);
2658
2659                                 /* link */
2660                                 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2661
2662                                 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2663                                         LOGW("failed to link fakesink\n");
2664                                         gst_object_unref(GST_OBJECT(fakesink));
2665                                         goto ERROR;
2666                                 }
2667
2668                                 g_object_set(G_OBJECT(fakesink), "async", TRUE, NULL);
2669                                 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
2670                                 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2671
2672                                 goto DONE;
2673                         }
2674                 } else if (strstr(name, "text")) {
2675                         LOGD("text selector \n");
2676                         elemId = MMPLAYER_M_T_INPUT_SELECTOR;
2677                         stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
2678                 } else {
2679                         LOGE("wrong elem id \n");
2680                         goto ERROR;
2681                 }
2682         }
2683
2684         selector = player->pipeline->mainbin[elemId].gst;
2685         if (selector == NULL) {
2686                 selector = gst_element_factory_make("input-selector", NULL);
2687                 LOGD("Creating input-selector\n");
2688                 if (selector == NULL) {
2689                         LOGE("ERROR : input-selector create error\n");
2690                         goto ERROR;
2691                 }
2692                 g_object_set(selector, "sync-streams", TRUE, NULL);
2693
2694                 player->pipeline->mainbin[elemId].id = elemId;
2695                 player->pipeline->mainbin[elemId].gst = selector;
2696
2697                 first_track = TRUE;
2698                 // player->selector[stream_type].active_pad_index = DEFAULT_TRACK;      // default
2699
2700                 srcpad = gst_element_get_static_pad(selector, "src");
2701
2702                 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2703                 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
2704                         __mmplayer_gst_selector_blocked, NULL, NULL);
2705                 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
2706                         __mmplayer_gst_selector_event_probe, player, NULL);
2707
2708                 gst_element_set_state(selector, GST_STATE_PAUSED);
2709                 gst_bin_add(GST_BIN(pipeline), selector);
2710         } else
2711                 LOGD("input-selector is already created.\n");
2712
2713         // link
2714         LOGD("Calling request pad with selector %p \n", selector);
2715         sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2716
2717         LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(sinkpad));
2718
2719         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2720                 LOGW("failed to link selector\n");
2721                 gst_object_unref(GST_OBJECT(selector));
2722                 goto ERROR;
2723         }
2724
2725         if (first_track) {
2726                 LOGD("this is first track --> active track \n");
2727                 g_object_set(selector, "active-pad", sinkpad, NULL);
2728         }
2729
2730         _mmplayer_track_update_info(player, stream_type, sinkpad);
2731
2732
2733 DONE:
2734 ERROR:
2735
2736         if (caps)
2737                 gst_caps_unref(caps);
2738
2739         if (sinkpad) {
2740                 gst_object_unref(GST_OBJECT(sinkpad));
2741                 sinkpad = NULL;
2742         }
2743
2744         if (srcpad) {
2745                 gst_object_unref(GST_OBJECT(srcpad));
2746                 srcpad = NULL;
2747         }
2748
2749         return;
2750 }
2751
2752 static void __mmplayer_handle_text_decode_path(mm_player_t* player, GstElement* text_selector)
2753 {
2754         GstPad* srcpad = NULL;
2755         MMHandleType attrs = 0;
2756         gint active_index = 0;
2757
2758         // [link] input-selector :: textbin
2759         srcpad = gst_element_get_static_pad(text_selector, "src");
2760         if (!srcpad) {
2761                 LOGE("failed to get srcpad from selector\n");
2762                 return;
2763         }
2764
2765         LOGD("got pad %s:%s from text selector\n", GST_DEBUG_PAD_NAME(srcpad));
2766
2767         active_index = player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index;
2768         if ((active_index != DEFAULT_TRACK) &&
2769                 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_TEXT, active_index) != MM_ERROR_NONE)) {
2770                 LOGW("failed to change text track\n");
2771                 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index = DEFAULT_TRACK;
2772         }
2773
2774         player->no_more_pad = TRUE;
2775         __mmplayer_gst_decode_callback(text_selector, srcpad, player);
2776
2777         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2778         if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id) {
2779                 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id);
2780                 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id = 0;
2781         }
2782
2783         LOGD("Total text tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2784
2785         if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
2786                 player->has_closed_caption = TRUE;
2787
2788         attrs = MMPLAYER_GET_ATTRS(player);
2789         if (attrs) {
2790                 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2791                 if (mmf_attrs_commit(attrs))
2792                         LOGE("failed to commit.\n");
2793         } else
2794                 LOGE("cannot get content attribute");
2795
2796         if (srcpad) {
2797                 gst_object_unref(GST_OBJECT(srcpad));
2798                 srcpad = NULL;
2799         }
2800 }
2801
2802 static void
2803 __mmplayer_gst_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2804 {
2805         mm_player_t* player = (mm_player_t*)data;
2806         GstElement* selector = NULL;
2807         GstElement* queue = NULL;
2808
2809         GstPad* srcpad = NULL;
2810         GstPad* sinkpad = NULL;
2811         GstCaps* caps = NULL;
2812         gchar* caps_str = NULL;
2813
2814         MMPLAYER_FENTER();
2815         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2816
2817         caps = gst_pad_get_current_caps(pad);
2818         caps_str = gst_caps_to_string(caps);
2819         LOGD("deinterleave new caps : %s\n", caps_str);
2820         MMPLAYER_FREEIF(caps_str);
2821         gst_caps_unref(caps);
2822
2823         if ((queue = __mmplayer_element_create_and_link(player, pad, "queue")) == NULL) {
2824                 LOGE("ERROR : queue create error\n");
2825                 goto ERROR;
2826         }
2827
2828         g_object_set(G_OBJECT(queue),
2829                                 "max-size-buffers", 10,
2830                                 "max-size-bytes", 0,
2831                                 "max-size-time", (guint64)0,
2832                                 NULL);
2833
2834         selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2835
2836         if (!selector) {
2837                 LOGE("there is no audio channel selector.\n");
2838                 goto ERROR;
2839         }
2840
2841         srcpad = gst_element_get_static_pad(queue, "src");
2842         sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2843
2844         LOGD("link(%s:%s - %s:%s)\n", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
2845
2846         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
2847                 LOGW("failed to link deinterleave - selector\n");
2848                 goto ERROR;
2849         }
2850
2851         gst_element_set_state(queue, GST_STATE_PAUSED);
2852         player->audio_mode.total_track_num++;
2853
2854 ERROR:
2855
2856         if (srcpad) {
2857                 gst_object_unref(GST_OBJECT(srcpad));
2858                 srcpad = NULL;
2859         }
2860
2861         if (sinkpad) {
2862                 gst_object_unref(GST_OBJECT(sinkpad));
2863                 sinkpad = NULL;
2864         }
2865
2866         MMPLAYER_FLEAVE();
2867         return;
2868 }
2869
2870 static void
2871 __mmplayer_gst_deinterleave_no_more_pads(GstElement *elem, gpointer data)
2872 {
2873         mm_player_t* player = NULL;
2874         GstElement* selector = NULL;
2875         GstPad* sinkpad = NULL;
2876         gint active_index = 0;
2877         gchar* change_pad_name = NULL;
2878         GstCaps* caps = NULL;   // no need to unref
2879         gint default_audio_ch = 0;
2880
2881         MMPLAYER_FENTER();
2882         player = (mm_player_t*) data;
2883
2884         selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2885
2886         if (!selector) {
2887                 LOGE("there is no audio channel selector.\n");
2888                 goto ERROR;
2889         }
2890
2891         active_index = player->audio_mode.active_pad_index;
2892
2893         if (active_index != default_audio_ch) {
2894                 gint audio_ch = default_audio_ch;
2895
2896                 /*To get the new pad from the selector*/
2897                 change_pad_name = g_strdup_printf("sink%d", active_index);
2898                 if (change_pad_name != NULL) {
2899                         sinkpad = gst_element_get_static_pad(selector, change_pad_name);
2900                         if (sinkpad != NULL) {
2901                                 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
2902                                 g_object_set(selector, "active-pad", sinkpad, NULL);
2903
2904                                 audio_ch = active_index;
2905
2906                                 caps = gst_pad_get_current_caps(sinkpad);
2907                                 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2908
2909                                 __mmplayer_set_audio_attrs(player, caps);
2910                                 gst_caps_unref(caps);
2911                         }
2912                         MMPLAYER_FREEIF(change_pad_name);
2913                 }
2914
2915                 player->audio_mode.active_pad_index = audio_ch;
2916                 LOGD("audio LR info(0:stereo) = %d\n", player->audio_mode.active_pad_index);
2917         }
2918
2919 ERROR:
2920
2921         if (sinkpad)
2922                 gst_object_unref(sinkpad);
2923
2924         MMPLAYER_FLEAVE();
2925         return;
2926 }
2927
2928 static void
2929 __mmplayer_gst_build_deinterleave_path(GstElement *elem, GstPad *pad, gpointer data)
2930 {
2931         mm_player_t* player = NULL;
2932         MMPlayerGstElement *mainbin = NULL;
2933
2934         GstElement* tee = NULL;
2935         GstElement* stereo_queue = NULL;
2936         GstElement* mono_queue = NULL;
2937         GstElement* conv = NULL;
2938         GstElement* filter = NULL;
2939         GstElement* deinterleave = NULL;
2940         GstElement* selector = NULL;
2941
2942         GstPad* srcpad = NULL;
2943         GstPad* selector_srcpad = NULL;
2944         GstPad* sinkpad = NULL;
2945         GstCaps* caps = NULL;
2946         gulong block_id = 0;
2947
2948         MMPLAYER_FENTER();
2949
2950         /* check handles */
2951         player = (mm_player_t*) data;
2952
2953         MMPLAYER_RETURN_IF_FAIL(elem && pad);
2954         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2955
2956         mainbin = player->pipeline->mainbin;
2957
2958         /* tee */
2959         if ((tee = __mmplayer_element_create_and_link(player, pad, "tee")) == NULL) {
2960                 LOGE("ERROR : tee create error\n");
2961                 goto ERROR;
2962         }
2963
2964         mainbin[MMPLAYER_M_A_TEE].id = MMPLAYER_M_A_TEE;
2965         mainbin[MMPLAYER_M_A_TEE].gst = tee;
2966
2967         gst_element_set_state(tee, GST_STATE_PAUSED);
2968
2969         /* queue */
2970         srcpad = gst_element_get_request_pad(tee, "src_%u");
2971         if ((stereo_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
2972                 LOGE("ERROR : stereo queue create error\n");
2973                 goto ERROR;
2974         }
2975
2976         g_object_set(G_OBJECT(stereo_queue),
2977                                 "max-size-buffers", 10,
2978                                 "max-size-bytes", 0,
2979                                 "max-size-time", (guint64)0,
2980                                 NULL);
2981
2982         player->pipeline->mainbin[MMPLAYER_M_A_Q1].id = MMPLAYER_M_A_Q1;
2983         player->pipeline->mainbin[MMPLAYER_M_A_Q1].gst = stereo_queue;
2984
2985         if (srcpad) {
2986                 gst_object_unref(GST_OBJECT(srcpad));
2987                 srcpad = NULL;
2988         }
2989
2990         srcpad = gst_element_get_request_pad(tee, "src_%u");
2991
2992         if ((mono_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
2993                 LOGE("ERROR : mono queue create error\n");
2994                 goto ERROR;
2995         }
2996
2997         g_object_set(G_OBJECT(mono_queue),
2998                                 "max-size-buffers", 10,
2999                                 "max-size-bytes", 0,
3000                                 "max-size-time", (guint64)0,
3001                                 NULL);
3002
3003         player->pipeline->mainbin[MMPLAYER_M_A_Q2].id = MMPLAYER_M_A_Q2;
3004         player->pipeline->mainbin[MMPLAYER_M_A_Q2].gst = mono_queue;
3005
3006         gst_element_set_state(stereo_queue, GST_STATE_PAUSED);
3007         gst_element_set_state(mono_queue, GST_STATE_PAUSED);
3008
3009         /* audioconvert */
3010         srcpad = gst_element_get_static_pad(mono_queue, "src");
3011         if ((conv = __mmplayer_element_create_and_link(player, srcpad, "audioconvert")) == NULL) {
3012                 LOGE("ERROR : audioconvert create error\n");
3013                 goto ERROR;
3014         }
3015
3016         player->pipeline->mainbin[MMPLAYER_M_A_CONV].id = MMPLAYER_M_A_CONV;
3017         player->pipeline->mainbin[MMPLAYER_M_A_CONV].gst = conv;
3018
3019         /* caps filter */
3020         if (srcpad) {
3021                 gst_object_unref(GST_OBJECT(srcpad));
3022                 srcpad = NULL;
3023         }
3024         srcpad = gst_element_get_static_pad(conv, "src");
3025
3026         if ((filter = __mmplayer_element_create_and_link(player, srcpad, "capsfilter")) == NULL) {
3027                 LOGE("ERROR : capsfilter create error\n");
3028                 goto ERROR;
3029         }
3030
3031         player->pipeline->mainbin[MMPLAYER_M_A_FILTER].id = MMPLAYER_M_A_FILTER;
3032         player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst = filter;
3033
3034         caps = gst_caps_from_string("audio/x-raw-int, "
3035                                 "width = (int) 16, "
3036                                 "depth = (int) 16, "
3037                                 "channels = (int) 2");
3038
3039         g_object_set(GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst), "caps", caps, NULL);
3040         gst_caps_unref(caps);
3041
3042         gst_element_set_state(conv, GST_STATE_PAUSED);
3043         gst_element_set_state(filter, GST_STATE_PAUSED);
3044
3045         /* deinterleave */
3046         if (srcpad) {
3047                 gst_object_unref(GST_OBJECT(srcpad));
3048                 srcpad = NULL;
3049         }
3050         srcpad = gst_element_get_static_pad(filter, "src");
3051
3052         if ((deinterleave = __mmplayer_element_create_and_link(player, srcpad, "deinterleave")) == NULL) {
3053                 LOGE("ERROR : deinterleave create error\n");
3054                 goto ERROR;
3055         }
3056
3057         g_object_set(deinterleave, "keep-positions", TRUE, NULL);
3058
3059         MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
3060                                                         G_CALLBACK(__mmplayer_gst_deinterleave_pad_added), player);
3061
3062         MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
3063                                                         G_CALLBACK(__mmplayer_gst_deinterleave_no_more_pads), player);
3064
3065         player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].id = MMPLAYER_M_A_DEINTERLEAVE;
3066         player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].gst = deinterleave;
3067
3068         /* selector */
3069         selector = gst_element_factory_make("input-selector", "audio-channel-selector");
3070         if (selector == NULL) {
3071                 LOGE("ERROR : audio-selector create error\n");
3072                 goto ERROR;
3073         }
3074
3075         g_object_set(selector, "sync-streams", TRUE, NULL);
3076         gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), selector);
3077
3078         player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].id = MMPLAYER_M_A_SELECTOR;
3079         player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst = selector;
3080
3081         selector_srcpad = gst_element_get_static_pad(selector, "src");
3082
3083         LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3084         block_id =
3085                 gst_pad_add_probe(selector_srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
3086                         __mmplayer_gst_selector_blocked, NULL, NULL);
3087
3088         if (srcpad) {
3089                 gst_object_unref(GST_OBJECT(srcpad));
3090                 srcpad = NULL;
3091         }
3092
3093         srcpad = gst_element_get_static_pad(stereo_queue, "src");
3094         sinkpad = gst_element_get_request_pad(selector, "sink_%u");
3095
3096         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
3097                 LOGW("failed to link queue_stereo - selector\n");
3098                 goto ERROR;
3099         }
3100
3101         player->audio_mode.total_track_num++;
3102
3103         g_object_set(selector, "active-pad", sinkpad, NULL);
3104         gst_element_set_state(deinterleave, GST_STATE_PAUSED);
3105         gst_element_set_state(selector, GST_STATE_PAUSED);
3106
3107         __mmplayer_gst_decode_callback(selector, selector_srcpad, player);
3108
3109 ERROR:
3110
3111         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3112         if (block_id != 0) {
3113                 gst_pad_remove_probe(selector_srcpad, block_id);
3114                 block_id = 0;
3115         }
3116
3117         if (sinkpad) {
3118                 gst_object_unref(GST_OBJECT(sinkpad));
3119                 sinkpad = NULL;
3120         }
3121
3122         if (srcpad) {
3123                 gst_object_unref(GST_OBJECT(srcpad));
3124                 srcpad = NULL;
3125         }
3126
3127         if (selector_srcpad) {
3128                 gst_object_unref(GST_OBJECT(selector_srcpad));
3129                 selector_srcpad = NULL;
3130         }
3131
3132         MMPLAYER_FLEAVE();
3133         return;
3134 }
3135
3136 static void
3137 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
3138 {
3139         mm_player_t* player = NULL;
3140         GstPad* srcpad = NULL;
3141         GstElement* video_selector = NULL;
3142         GstElement* audio_selector = NULL;
3143         GstElement* text_selector = NULL;
3144         MMHandleType attrs = 0;
3145         gint active_index = 0;
3146         gint64 dur_bytes = 0L;
3147
3148         player = (mm_player_t*) data;
3149
3150         LOGD("no-more-pad signal handling\n");
3151
3152         if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
3153                 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
3154                 LOGW("no need to go more");
3155
3156                 if (player->gapless.reconfigure) {
3157                         player->gapless.reconfigure = FALSE;
3158                         MMPLAYER_PLAYBACK_UNLOCK(player);
3159                 }
3160
3161                 return;
3162         }
3163
3164         if ((!MMPLAYER_IS_HTTP_PD(player)) &&
3165                 (MMPLAYER_IS_HTTP_STREAMING(player)) &&
3166                 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
3167                 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
3168                 #define ESTIMATED_BUFFER_UNIT (1*1024*1024)
3169
3170                 if (NULL == player->streamer) {
3171                         LOGW("invalid state for buffering");
3172                         goto ERROR;
3173                 }
3174
3175                 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
3176                 guint buffer_bytes = (guint)(init_buffering_time/1000) * ESTIMATED_BUFFER_UNIT;
3177
3178                 buffer_bytes = MAX(buffer_bytes, player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffering_bytes);
3179                 LOGD("[Decodebin2] set use-buffering on Q2(pre buffer time: %d ms, buffer size : %d)\n", init_buffering_time, buffer_bytes);
3180
3181                 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
3182
3183                 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
3184                         LOGE("fail to get duration.\n");
3185
3186                 // enable use-buffering on queue2 instead of multiqueue(ex)audio only streaming
3187                 // use file information was already set on Q2 when it was created.
3188                 __mm_player_streaming_set_queue2(player->streamer,
3189                                                 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
3190                                                 TRUE,                                                           // use_buffering
3191                                                 buffer_bytes,
3192                                                 init_buffering_time,
3193                                                 1.0,                                                            // low percent
3194                                                 player->ini.http_buffering_limit,       // high percent
3195                                                 MUXED_BUFFER_TYPE_MEM_QUEUE,
3196                                                 NULL,
3197                                                 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
3198         }
3199
3200         video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
3201         audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
3202         text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3203         if (video_selector) {
3204                 // [link] input-selector :: videobin
3205                 srcpad = gst_element_get_static_pad(video_selector, "src");
3206                 if (!srcpad) {
3207                         LOGE("failed to get srcpad from video selector\n");
3208                         goto ERROR;
3209                 }
3210
3211                 LOGD("got pad %s:%s from video selector\n", GST_DEBUG_PAD_NAME(srcpad));
3212                 if (!text_selector && !audio_selector)
3213                         player->no_more_pad = TRUE;
3214
3215                 __mmplayer_gst_decode_callback(video_selector, srcpad, player);
3216
3217                 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3218                 if (player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id) {
3219                         gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id);
3220                         player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id = 0;
3221                 }
3222         }
3223
3224         if (audio_selector) {
3225                 active_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
3226                 if ((active_index != DEFAULT_TRACK) &&
3227                         (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_AUDIO, active_index) != MM_ERROR_NONE)) {
3228                         LOGW("failed to change audio track\n");
3229                         player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index = DEFAULT_TRACK;
3230                 }
3231
3232                 // [link] input-selector :: audiobin
3233                 srcpad = gst_element_get_static_pad(audio_selector, "src");
3234                 if (!srcpad) {
3235                         LOGE("failed to get srcpad from selector\n");
3236                         goto ERROR;
3237                 }
3238
3239                 LOGD("got pad %s:%s from selector\n", GST_DEBUG_PAD_NAME(srcpad));
3240                 if (!text_selector)
3241                         player->no_more_pad = TRUE;
3242
3243                 if ((player->use_deinterleave == TRUE) && (player->max_audio_channels >= 2)) {
3244                         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3245                         if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3246                                 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3247                                 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3248                         }
3249
3250                         __mmplayer_gst_build_deinterleave_path(audio_selector, srcpad, player);
3251                 } else {
3252                         __mmplayer_gst_decode_callback(audio_selector, srcpad, player);
3253
3254                         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3255                         if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3256                                 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3257                                 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3258                         }
3259                 }
3260
3261                 LOGD("Total audio tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3262
3263                 attrs = MMPLAYER_GET_ATTRS(player);
3264                 if (attrs) {
3265                         mm_attrs_set_int_by_name(attrs, "content_audio_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3266                         if (mmf_attrs_commit(attrs))
3267                                 LOGE("failed to commit.\n");
3268                 } else
3269                         LOGE("cannot get content attribute");
3270         } else {
3271                 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
3272                         LOGD("There is no audio track : remove audiobin");
3273
3274                         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
3275                         __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
3276
3277                         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
3278                         MMPLAYER_FREEIF(player->pipeline->audiobin);
3279                 }
3280
3281                 if (player->num_dynamic_pad == 0)
3282                         __mmplayer_pipeline_complete(NULL, player);
3283         }
3284
3285         if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
3286                 if (text_selector)
3287                         __mmplayer_handle_text_decode_path(player, text_selector);
3288         }
3289
3290         MMPLAYER_FLEAVE();
3291
3292 ERROR:
3293         if (srcpad) {
3294                 gst_object_unref(GST_OBJECT(srcpad));
3295                 srcpad = NULL;
3296         }
3297
3298         if (player->gapless.reconfigure) {
3299                 player->gapless.reconfigure = FALSE;
3300                 MMPLAYER_PLAYBACK_UNLOCK(player);
3301         }
3302 }
3303
3304 static void
3305 __mmplayer_gst_decode_callback(GstElement *elem, GstPad *pad, gpointer data)
3306 {
3307         mm_player_t* player = NULL;
3308         MMHandleType attrs = 0;
3309         GstElement* pipeline = NULL;
3310         GstCaps* caps = NULL;
3311         gchar* caps_str = NULL;
3312         GstStructure* str = NULL;
3313         const gchar* name = NULL;
3314         GstPad* sinkpad = NULL;
3315         GstElement* sinkbin = NULL;
3316         gboolean reusing = FALSE;
3317         GstElement *text_selector = NULL;
3318
3319         /* check handles */
3320         player = (mm_player_t*) data;
3321
3322         MMPLAYER_RETURN_IF_FAIL(elem && pad);
3323         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3324
3325         pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
3326
3327         attrs = MMPLAYER_GET_ATTRS(player);
3328         if (!attrs) {
3329                 LOGE("cannot get content attribute\n");
3330                 goto ERROR;
3331         }
3332
3333         /* get mimetype from caps */
3334         caps = gst_pad_query_caps(pad, NULL);
3335         if (!caps) {
3336                 LOGE("cannot get caps from pad.\n");
3337                 goto ERROR;
3338         }
3339         caps_str = gst_caps_to_string(caps);
3340
3341         str = gst_caps_get_structure(caps, 0);
3342         if (!str) {
3343                 LOGE("cannot get structure from caps.\n");
3344                 goto ERROR;
3345         }
3346
3347         name = gst_structure_get_name(str);
3348         if (!name) {
3349                 LOGE("cannot get mimetype from structure.\n");
3350                 goto ERROR;
3351         }
3352
3353         //LOGD("detected mimetype : %s\n", name);
3354
3355         if (strstr(name, "audio")) {
3356                 if (player->pipeline->audiobin == NULL) {
3357                         if (MM_ERROR_NONE !=  __mmplayer_gst_create_audio_pipeline(player)) {
3358                                 LOGE("failed to create audiobin. continuing without audio\n");
3359                                 goto ERROR;
3360                         }
3361
3362                         sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3363                         LOGD("creating audiosink bin success\n");
3364                 } else {
3365                         reusing = TRUE;
3366                         sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3367                         LOGD("reusing audiobin\n");
3368                         _mmplayer_update_content_attrs(player, ATTR_AUDIO);
3369                 }
3370
3371                 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num <= 0) // should not update if content have multi audio tracks
3372                         mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 1);
3373
3374                 player->audiosink_linked  = 1;
3375
3376                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3377                 if (!sinkpad) {
3378                         LOGE("failed to get pad from sinkbin\n");
3379                         goto ERROR;
3380                 }
3381         } else if (strstr(name, "video")) {
3382                 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
3383                         strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
3384                         player->set_mode.video_zc = TRUE;
3385
3386                 if (player->pipeline->videobin == NULL) {
3387                         /* NOTE : not make videobin because application dose not want to play it even though file has video stream. */
3388                         /* get video surface type */
3389                         int surface_type = 0;
3390                         mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3391                         LOGD("display_surface_type(%d)\n", surface_type);
3392
3393                         if (surface_type == MM_DISPLAY_SURFACE_NULL) {
3394                                 LOGD("not make videobin because it dose not want\n");
3395                                 goto ERROR;
3396                         }
3397
3398                         if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3399                                 /* mark video overlay for acquire */
3400                                 if (player->video_overlay_resource == NULL) {
3401                                         if (mm_resource_manager_mark_for_acquire(player->resource_manager,
3402                                                         MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
3403                                                         MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
3404                                                         &player->video_overlay_resource)
3405                                                         != MM_RESOURCE_MANAGER_ERROR_NONE) {
3406                                                 LOGE("could not mark video_overlay resource for acquire\n");
3407                                                 goto ERROR;
3408                                         }
3409                                 }
3410                         }
3411
3412                         player->interrupted_by_resource = FALSE;
3413                         /* acquire resources for video overlay */
3414                         if (mm_resource_manager_commit(player->resource_manager) !=
3415                                         MM_RESOURCE_MANAGER_ERROR_NONE) {
3416                                 LOGE("could not acquire resources for video playing\n");
3417                                 goto ERROR;
3418                         }
3419
3420                         if (MM_ERROR_NONE !=  __mmplayer_gst_create_video_pipeline(player, caps, surface_type)) {
3421                                 LOGE("failed to create videobin. continuing without video\n");
3422                                 goto ERROR;
3423                         }
3424
3425                         sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3426                         LOGD("creating videosink bin success\n");
3427                 } else {
3428                         reusing = TRUE;
3429                         sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3430                         LOGD("re-using videobin\n");
3431                         _mmplayer_update_content_attrs(player, ATTR_VIDEO);
3432                 }
3433
3434                 player->videosink_linked  = 1;
3435
3436                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3437                 if (!sinkpad) {
3438                         LOGE("failed to get pad from sinkbin\n");
3439                         goto ERROR;
3440                 }
3441         } else if (strstr(name, "text")) {
3442                 if (player->pipeline->textbin == NULL) {
3443                         MMPlayerGstElement* mainbin = NULL;
3444
3445                         if (MM_ERROR_NONE !=  __mmplayer_gst_create_text_sink_bin(player)) {
3446                                 LOGE("failed to create text sink bin. continuing without text\n");
3447                                 goto ERROR;
3448                         }
3449
3450                         sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3451                         LOGD("creating textsink bin success\n");
3452
3453                         /* FIXIT : track number shouldn't be hardcoded */
3454                         mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1);
3455
3456                         player->textsink_linked  = 1;
3457                         LOGI("player->textsink_linked set to 1\n");
3458
3459                         sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "text_sink");
3460                         if (!sinkpad) {
3461                                 LOGE("failed to get pad from sinkbin\n");
3462                                 goto ERROR;
3463                         }
3464
3465                         mainbin = player->pipeline->mainbin;
3466
3467                         if (!mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst) {
3468                                 /* input selector */
3469                                 text_selector = gst_element_factory_make("input-selector", "subtitle_inselector");
3470                                 if (!text_selector) {
3471                                         LOGE("failed to create subtitle input selector element\n");
3472                                         goto ERROR;
3473                                 }
3474                                 g_object_set(text_selector, "sync-streams", TRUE, NULL);
3475
3476                                 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].id = MMPLAYER_M_T_INPUT_SELECTOR;
3477                                 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst = text_selector;
3478
3479                                 /* warm up */
3480                                 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_READY)) {
3481                                         LOGE("failed to set state(READY) to sinkbin\n");
3482                                         goto ERROR;
3483                                 }
3484
3485                                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), text_selector)) {
3486                                         LOGW("failed to add subtitle input selector\n");
3487                                         goto ERROR;
3488                                 }
3489
3490                                 LOGD("created element input-selector");
3491
3492                         } else {
3493                                 LOGD("already having subtitle input selector");
3494                                 text_selector = mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3495                         }
3496                 } else {
3497                         if (!player->textsink_linked) {
3498                                 LOGD("re-using textbin\n");
3499
3500                                 reusing = TRUE;
3501                                 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3502
3503                                 player->textsink_linked  = 1;
3504                                 LOGI("player->textsink_linked set to 1\n");
3505                         } else
3506                                 LOGD("ignoring internal subtutle since external subtitle is available");
3507                 }
3508         } else {
3509                 LOGW("unknown type of elementary stream!ignoring it...\n");
3510                 goto ERROR;
3511         }
3512
3513         if (sinkbin) {
3514                 if (!reusing) {
3515                         /* warm up */
3516                         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_READY)) {
3517                                 LOGE("failed to set state(READY) to sinkbin\n");
3518                                 goto ERROR;
3519                         }
3520
3521                         /* Added for multi audio support to avoid adding audio bin again*/
3522                         /* add */
3523                         if (FALSE == gst_bin_add(GST_BIN(pipeline), sinkbin)) {
3524                                 LOGE("failed to add sinkbin to pipeline\n");
3525                                 goto ERROR;
3526                         }
3527                 }
3528
3529                 /* link */
3530                 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
3531                         LOGE("failed to get pad from sinkbin\n");
3532                         goto ERROR;
3533                 }
3534
3535                 if (!reusing) {
3536                         /* run */
3537                         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_PAUSED)) {
3538                                 LOGE("failed to set state(PAUSED) to sinkbin\n");
3539                                 goto ERROR;
3540                         }
3541
3542                         if (text_selector) {
3543                                 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_PAUSED)) {
3544                                         LOGE("failed to set state(PAUSED) to sinkbin\n");
3545                                         goto ERROR;
3546                                 }
3547                         }
3548                 }
3549
3550                 gst_object_unref(sinkpad);
3551                 sinkpad = NULL;
3552         }
3553
3554         LOGD("[handle: %p] linking sink bin success", player);
3555
3556         /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
3557          * streaming task. if the task blocked, then buffer will not flow to the next element
3558          *(autoplugging element). so this is special hack for streaming. please try to remove it
3559          */
3560         /* dec stream count. we can remove fakesink if it's zero */
3561         if (player->num_dynamic_pad)
3562                 player->num_dynamic_pad--;
3563
3564         LOGD("no more pads: %d stream count dec : %d(num of dynamic pad)\n", player->no_more_pad, player->num_dynamic_pad);
3565
3566         if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
3567                 __mmplayer_pipeline_complete(NULL, player);
3568
3569 ERROR:
3570
3571         MMPLAYER_FREEIF(caps_str);
3572
3573         if (caps)
3574                 gst_caps_unref(caps);
3575
3576         if (sinkpad)
3577                 gst_object_unref(GST_OBJECT(sinkpad));
3578
3579         /* flusing out new attributes */
3580         if (mmf_attrs_commit(attrs))
3581                 LOGE("failed to comit attributes\n");
3582
3583         return;
3584 }
3585
3586 static gboolean
3587 __mmplayer_get_property_value_for_rotation(mm_player_t* player, int rotation_angle, int *value)
3588 {
3589         int pro_value = 0; // in the case of expection, default will be returned.
3590         int dest_angle = rotation_angle;
3591         int rotation_type = -1;
3592
3593         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3594         MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
3595         MMPLAYER_RETURN_VAL_IF_FAIL(rotation_angle >= 0, FALSE);
3596
3597         if (rotation_angle >= 360)
3598                 dest_angle = rotation_angle - 360;
3599
3600         /* chech if supported or not */
3601         if (dest_angle % 90) {
3602                 LOGD("not supported rotation angle = %d", rotation_angle);
3603                 return FALSE;
3604         }
3605
3606         /*
3607           * tizenwlsink (A)
3608           * custom_convert - none (B)
3609           * videoflip - none (C)
3610           */
3611         if (player->set_mode.video_zc) {
3612                 if (player->pipeline->videobin[MMPLAYER_V_CONV].gst) // B
3613                         rotation_type = ROTATION_USING_CUSTOM;
3614                 else // A
3615                         rotation_type = ROTATION_USING_SINK;
3616         } else {
3617                 int surface_type = 0;
3618                 rotation_type = ROTATION_USING_FLIP;
3619
3620                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3621                 LOGD("check display surface type attribute: %d", surface_type);
3622
3623                 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY)
3624                         rotation_type = ROTATION_USING_SINK;
3625                 else
3626                         rotation_type = ROTATION_USING_FLIP; //C
3627
3628                 LOGD("using %d type for rotation", rotation_type);
3629         }
3630
3631         /* get property value for setting */
3632         switch (rotation_type) {
3633         case ROTATION_USING_SINK: // tizenwlsink
3634                 {
3635                         switch (dest_angle) {
3636                         case 0:
3637                                 break;
3638                         case 90:
3639                                 pro_value = 3; // clockwise 90
3640                                 break;
3641                         case 180:
3642                                 pro_value = 2;
3643                                 break;
3644                         case 270:
3645                                 pro_value = 1; // counter-clockwise 90
3646                                 break;
3647                         }
3648                 }
3649                 break;
3650         case ROTATION_USING_CUSTOM:
3651                 {
3652                         gchar *ename = NULL;
3653                         ename = GST_OBJECT_NAME(gst_element_get_factory(player->pipeline->videobin[MMPLAYER_V_CONV].gst));
3654
3655                         if (g_strrstr(ename, "fimcconvert")) {
3656                                 switch (dest_angle) {
3657                                 case 0:
3658                                         break;
3659                                 case 90:
3660                                         pro_value = 90; // clockwise 90
3661                                         break;
3662                                 case 180:
3663                                         pro_value = 180;
3664                                         break;
3665                                 case 270:
3666                                         pro_value = 270; // counter-clockwise 90
3667                                         break;
3668                                 }
3669                         }
3670                 }
3671                 break;
3672         case ROTATION_USING_FLIP: // videoflip
3673                 {
3674                                 switch (dest_angle) {
3675                                 case 0:
3676                                         break;
3677                                 case 90:
3678                                         pro_value = 1; // clockwise 90
3679                                         break;
3680                                 case 180:
3681                                         pro_value = 2;
3682                                         break;
3683                                 case 270:
3684                                         pro_value = 3; // counter-clockwise 90
3685                                         break;
3686                                 }
3687                 }
3688                 break;
3689         }
3690
3691         LOGD("setting rotation property value : %d, used rotation type : %d", pro_value, rotation_type);
3692
3693         *value = pro_value;
3694
3695         return TRUE;
3696 }
3697
3698 int
3699 __mmplayer_video_param_check_video_sink_bin(mm_player_t* player)
3700 {
3701         /* check video sinkbin is created */
3702         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3703                 player->pipeline &&
3704                 player->pipeline->videobin &&
3705                 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
3706                 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3707                 MM_ERROR_PLAYER_NOT_INITIALIZED);
3708
3709         return MM_ERROR_NONE;
3710 }
3711
3712 void
3713 __mmplayer_video_param_set_display_rotation(mm_player_t* player)
3714 {
3715         int rotation_value = 0;
3716         int org_angle = 0; // current supported angle values are 0, 90, 180, 270
3717         int user_angle = 0;
3718         MMPLAYER_FENTER();
3719
3720         /* check video sinkbin is created */
3721         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3722                 return;
3723
3724         __mmplayer_get_video_angle(player, &user_angle, &org_angle);
3725
3726         /* get rotation value to set */
3727         __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
3728         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
3729         LOGD("set video param : rotate %d", rotation_value);
3730 }
3731
3732 void
3733 __mmplayer_video_param_set_display_visible(mm_player_t* player)
3734 {
3735         MMHandleType attrs = 0;
3736         int visible = 0;
3737         MMPLAYER_FENTER();
3738
3739         /* check video sinkbin is created */
3740         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3741                 return;
3742
3743         attrs = MMPLAYER_GET_ATTRS(player);
3744         MMPLAYER_RETURN_IF_FAIL(attrs);
3745
3746         mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
3747         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
3748         LOGD("set video param : visible %d", visible);
3749 }
3750
3751 void
3752 __mmplayer_video_param_set_display_method(mm_player_t* player)
3753 {
3754         MMHandleType attrs = 0;
3755         int display_method = 0;
3756         MMPLAYER_FENTER();
3757
3758         /* check video sinkbin is created */
3759         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3760                 return;
3761
3762         attrs = MMPLAYER_GET_ATTRS(player);
3763         MMPLAYER_RETURN_IF_FAIL(attrs);
3764
3765         mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
3766         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
3767         LOGD("set video param : method %d", display_method);
3768 }
3769
3770 void
3771 __mmplayer_video_param_set_render_rectangle(mm_player_t* player)
3772 {
3773         MMHandleType attrs = 0;
3774         void *handle = NULL;
3775         /*set wl_display*/
3776         int wl_window_x = 0;
3777         int wl_window_y = 0;
3778         int wl_window_width = 0;
3779         int wl_window_height = 0;
3780         MMPLAYER_FENTER();
3781
3782         /* check video sinkbin is created */
3783         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3784                 return;
3785
3786         attrs = MMPLAYER_GET_ATTRS(player);
3787         MMPLAYER_RETURN_IF_FAIL(attrs);
3788
3789         mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3790
3791         if (handle) {
3792                 /*It should be set after setting window*/
3793                 mm_attrs_get_int_by_name(attrs, "wl_window_render_x", &wl_window_x);
3794                 mm_attrs_get_int_by_name(attrs, "wl_window_render_y", &wl_window_y);
3795                 mm_attrs_get_int_by_name(attrs, "wl_window_render_width", &wl_window_width);
3796                 mm_attrs_get_int_by_name(attrs, "wl_window_render_height", &wl_window_height);
3797
3798                 /* After setting window handle, set render      rectangle */
3799                 gst_video_overlay_set_render_rectangle(
3800                          GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3801                          wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3802                 LOGD("set video param : render rectangle : x(%d) y(%d) width(%d) height(%d)",
3803                         wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3804
3805         }
3806 }
3807 void
3808 __mmplayer_video_param_set_display_overlay(mm_player_t* player)
3809 {
3810         MMHandleType attrs = 0;
3811         void *handle = NULL;
3812
3813         /* check video sinkbin is created */
3814         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3815                 return;
3816
3817         attrs = MMPLAYER_GET_ATTRS(player);
3818         MMPLAYER_RETURN_IF_FAIL(attrs);
3819
3820         /* common case if using overlay surface */
3821         mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3822
3823         if (handle) {
3824                 /* default is using wl_surface_id */
3825                 unsigned int wl_surface_id      = 0;
3826                 wl_surface_id = *(int*)handle;
3827                 LOGD("set video param : wl_surface_id %d %p", wl_surface_id, *(int*)handle);
3828                 gst_video_overlay_set_wl_window_wl_surface_id(
3829                                 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3830                                 *(int*)handle);
3831         } else
3832                 /* FIXIT : is it error case? */
3833                 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
3834 }
3835
3836
3837 int
3838 __mmplayer_update_wayland_videosink_video_param(mm_player_t* player, char *param_name)
3839 {
3840         bool update_all_param = FALSE;
3841         MMPLAYER_FENTER();
3842
3843         /* check video sinkbin is created */
3844         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3845                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3846
3847         if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
3848                 LOGE("can not find tizenwlsink");
3849                 return MM_ERROR_PLAYER_INTERNAL;
3850         }
3851
3852         LOGD("param_name : %s", param_name);
3853         if (!g_strcmp0(param_name, "update_all_param"))
3854                 update_all_param = TRUE;
3855
3856         if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
3857                 __mmplayer_video_param_set_display_overlay(player);
3858         if (update_all_param || !g_strcmp0(param_name, "display_method"))
3859                 __mmplayer_video_param_set_display_method(player);
3860         if (update_all_param || !g_strcmp0(param_name, "wl_window_render_x"))
3861                 __mmplayer_video_param_set_render_rectangle(player);
3862         if (update_all_param || !g_strcmp0(param_name, "display_visible"))
3863                 __mmplayer_video_param_set_display_visible(player);
3864         if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
3865                 __mmplayer_video_param_set_display_rotation(player);
3866
3867         return MM_ERROR_NONE;
3868 }
3869
3870 int
3871 _mmplayer_update_video_param(mm_player_t* player, char *param_name)
3872 {
3873         MMHandleType attrs = 0;
3874         int surface_type = 0;
3875         int ret = MM_ERROR_NONE;
3876
3877         MMPLAYER_FENTER();
3878
3879         /* check video sinkbin is created */
3880         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3881                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3882
3883         attrs = MMPLAYER_GET_ATTRS(player);
3884         if (!attrs) {
3885                 LOGE("cannot get content attribute");
3886                 return MM_ERROR_PLAYER_INTERNAL;
3887         }
3888         LOGD("param_name : %s", param_name);
3889
3890         /* update display surface */
3891         mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
3892         LOGD("check display surface type attribute: %d", surface_type);
3893
3894         /* configuring display */
3895         switch (surface_type) {
3896         case MM_DISPLAY_SURFACE_OVERLAY:
3897                 {
3898                         ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
3899                         if (ret != MM_ERROR_NONE)
3900                                 return ret;
3901                 }
3902                 break;
3903         }
3904
3905         MMPLAYER_FLEAVE();
3906
3907         return MM_ERROR_NONE;
3908 }
3909
3910 int
3911 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
3912 {
3913         gboolean disable_overlay = FALSE;
3914         mm_player_t* player = (mm_player_t*) hplayer;
3915         int ret = MM_ERROR_NONE;
3916
3917         MMPLAYER_FENTER();
3918         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3919         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
3920                                                                 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3921                                                                 MM_ERROR_PLAYER_NO_OP); /* invalid op */
3922
3923         if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
3924                 LOGW("Display control is not supported");
3925                 return MM_ERROR_PLAYER_INTERNAL;
3926         }
3927
3928         g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
3929
3930         if (audio_only == (bool)disable_overlay) {
3931                 LOGE("It's the same with current setting: (%d)", audio_only);
3932                 return MM_ERROR_NONE;
3933         }
3934
3935         if (audio_only) {
3936                 LOGE("disable overlay");
3937                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
3938
3939                 /* release overlay resource */
3940                 if (player->video_overlay_resource != NULL) {
3941                         ret = mm_resource_manager_mark_for_release(player->resource_manager,
3942                                         player->video_overlay_resource);
3943                         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3944                                 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
3945                                 goto ERROR;
3946                         }
3947                         player->video_overlay_resource = NULL;
3948                 }
3949
3950                 ret = mm_resource_manager_commit(player->resource_manager);
3951                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3952                         LOGE("failed to commit acquiring of overlay resource, ret(0x%x)\n", ret);
3953                         goto ERROR;
3954                 }
3955         } else {
3956                 /* mark video overlay for acquire */
3957                 if (player->video_overlay_resource == NULL) {
3958                         ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
3959                                         MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
3960                                         MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
3961                                         &player->video_overlay_resource);
3962                         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3963                                 LOGE("could not prepare for video_overlay resource\n");
3964                                 goto ERROR;
3965                         }
3966                 }
3967
3968                 player->interrupted_by_resource = FALSE;
3969                 /* acquire resources for video overlay */
3970                 ret = mm_resource_manager_commit(player->resource_manager);
3971                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3972                         LOGE("could not acquire resources for video playing\n");
3973                         goto ERROR;
3974                 }
3975
3976                 LOGD("enable overlay");
3977                 __mmplayer_video_param_set_display_overlay(player);
3978                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
3979         }
3980
3981 ERROR:
3982         MMPLAYER_FLEAVE();
3983         return MM_ERROR_NONE;
3984 }
3985
3986 int
3987 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
3988 {
3989         mm_player_t* player = (mm_player_t*) hplayer;
3990         gboolean disable_overlay = FALSE;
3991
3992         MMPLAYER_FENTER();
3993
3994         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3995         MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
3996         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
3997                                                                 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3998                                                                 MM_ERROR_PLAYER_NO_OP); /* invalid op */
3999
4000         if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
4001                 LOGW("Display control is not supported");
4002                 return MM_ERROR_PLAYER_INTERNAL;
4003         }
4004
4005         g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
4006
4007         *paudio_only = (bool)(disable_overlay);
4008
4009         LOGD("audio_only : %d", *paudio_only);
4010
4011         MMPLAYER_FLEAVE();
4012
4013         return MM_ERROR_NONE;
4014 }
4015
4016 static int
4017 __mmplayer_gst_element_link_bucket(GList* element_bucket)
4018 {
4019         GList* bucket = element_bucket;
4020         MMPlayerGstElement* element = NULL;
4021         MMPlayerGstElement* prv_element = NULL;
4022         gint successful_link_count = 0;
4023
4024         MMPLAYER_FENTER();
4025
4026         MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
4027
4028         prv_element = (MMPlayerGstElement*)bucket->data;
4029         bucket = bucket->next;
4030
4031         for (; bucket; bucket = bucket->next) {
4032                 element = (MMPlayerGstElement*)bucket->data;
4033
4034                 if (element && element->gst) {
4035                         /* If next element is audio appsrc then make a separate audio pipeline */
4036                         if (!strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "audio_appsrc") ||
4037                                 !strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "subtitle_appsrc")) {
4038                                 prv_element = element;
4039                                 continue;
4040                         }
4041
4042                         if (prv_element && prv_element->gst) {
4043                                 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
4044                                         LOGD("linking [%s] to [%s] success\n",
4045                                                 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4046                                                 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4047                                         successful_link_count++;
4048                                 } else {
4049                                         LOGD("linking [%s] to [%s] failed\n",
4050                                                 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4051                                                 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4052                                         return -1;
4053                                 }
4054                         }
4055                 }
4056
4057                 prv_element = element;
4058         }
4059
4060         MMPLAYER_FLEAVE();
4061
4062         return successful_link_count;
4063 }
4064
4065 static int
4066 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket)
4067 {
4068         GList* bucket = element_bucket;
4069         MMPlayerGstElement* element = NULL;
4070         int successful_add_count = 0;
4071
4072         MMPLAYER_FENTER();
4073
4074         MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
4075         MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
4076
4077         for (; bucket; bucket = bucket->next) {
4078                 element = (MMPlayerGstElement*)bucket->data;
4079
4080                 if (element && element->gst) {
4081                         if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
4082                                 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s]  to bin [%s] failed\n",
4083                                         GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
4084                                         GST_ELEMENT_NAME(GST_ELEMENT(bin)));
4085                                 return 0;
4086                         }
4087                         successful_add_count++;
4088                 }
4089         }
4090
4091         MMPLAYER_FLEAVE();
4092
4093         return successful_add_count;
4094 }
4095
4096 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data)
4097 {
4098         mm_player_t* player = (mm_player_t*) data;
4099         GstCaps *caps = NULL;
4100         GstStructure *str = NULL;
4101         const char *name;
4102
4103         MMPLAYER_FENTER();
4104
4105         MMPLAYER_RETURN_IF_FAIL(pad)
4106         MMPLAYER_RETURN_IF_FAIL(unused)
4107         MMPLAYER_RETURN_IF_FAIL(data)
4108
4109         caps = gst_pad_get_current_caps(pad);
4110         if (!caps)
4111                 return;
4112
4113         str = gst_caps_get_structure(caps, 0);
4114         if (!str)
4115                 goto ERROR;
4116
4117         name = gst_structure_get_name(str);
4118         if (!name)
4119                 goto ERROR;
4120
4121         LOGD("name = %s\n", name);
4122
4123         if (strstr(name, "audio")) {
4124                 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
4125
4126                 if (player->audio_stream_changed_cb) {
4127                         LOGE("call the audio stream changed cb\n");
4128                         player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
4129                 }
4130         } else if (strstr(name, "video")) {
4131                 if ((name = gst_structure_get_string(str, "format")))
4132                         player->set_mode.video_zc = name[0] == 'S';
4133
4134                 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
4135
4136                 if (player->video_stream_changed_cb) {
4137                         LOGE("call the video stream changed cb\n");
4138                         player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
4139                 }
4140         } else
4141                 goto ERROR;
4142
4143 ERROR:
4144
4145         gst_caps_unref(caps);
4146
4147         MMPLAYER_FLEAVE();
4148
4149         return;
4150 }
4151
4152
4153
4154 /**
4155  * This function is to create audio pipeline for playing.
4156  *
4157  * @param       player          [in]    handle of player
4158  *
4159  * @return      This function returns zero on success.
4160  * @remark
4161  * @see         __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_pipeline
4162  */
4163 /* macro for code readability. just for sinkbin-creation functions */
4164 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
4165 do {\
4166         x_bin[x_id].id = x_id;\
4167         x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4168         if (!x_bin[x_id].gst) {\
4169                 LOGE("failed to create %s \n", x_factory);\
4170                 goto ERROR;\
4171         } else {\
4172                 if (x_player->ini.set_dump_element_flag)\
4173                         __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
4174         } \
4175         if (x_add_bucket)\
4176                 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
4177 } while (0);
4178
4179 static void
4180 __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all)
4181 {
4182         GList *l = NULL;
4183
4184         MMPLAYER_FENTER();
4185         MMPLAYER_RETURN_IF_FAIL(player);
4186
4187         if (player->audio_stream_buff_list) {
4188                 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4189                         mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4190                         if (tmp) {
4191                                 if (send_all) {
4192                                         LOGD("[%lld] send remained data.", tmp->channel_mask);
4193                                         __mmplayer_audio_stream_send_data(player, tmp);
4194                                 }
4195                                 if (tmp->pcm_data)
4196                                         g_free(tmp->pcm_data);
4197                                 g_free(tmp);
4198                         }
4199                 }
4200                 g_list_free(player->audio_stream_buff_list);
4201                 player->audio_stream_buff_list = NULL;
4202         }
4203
4204         MMPLAYER_FLEAVE();
4205 }
4206
4207 static void
4208 __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer)
4209 {
4210         MMPlayerAudioStreamDataType audio_stream = { 0, };
4211
4212         MMPLAYER_FENTER();
4213         MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4214
4215         audio_stream.bitrate = a_buffer->bitrate;
4216         audio_stream.channel = a_buffer->channel;
4217         audio_stream.depth = a_buffer->depth;
4218         audio_stream.is_little_endian = a_buffer->is_little_endian;
4219         audio_stream.channel_mask = a_buffer->channel_mask;
4220         audio_stream.data_size = a_buffer->data_size;
4221         audio_stream.data = a_buffer->pcm_data;
4222
4223         /* LOGD("[%lld] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
4224         player->audio_stream_render_cb_ex(&audio_stream, player->audio_stream_cb_user_param);
4225
4226         MMPLAYER_FLEAVE();
4227 }
4228
4229 static void
4230 __mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4231 {
4232         mm_player_t* player = (mm_player_t*) data;
4233
4234         gint channel = 0;
4235         gint rate = 0;
4236         gint depth = 0;
4237         gint endianness = 0;
4238         guint64 channel_mask = 0;
4239         void *a_data = NULL;
4240         gint a_size = 0;
4241         mm_player_audio_stream_buff_t *a_buffer = NULL;
4242         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4243         GList *l = NULL;
4244
4245         MMPLAYER_FENTER();
4246         MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4247
4248         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4249         a_data = mapinfo.data;
4250         a_size = mapinfo.size;
4251
4252         GstCaps *caps = gst_pad_get_current_caps(pad);
4253         GstStructure *structure = gst_caps_get_structure(caps, 0);
4254
4255         /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
4256         gst_structure_get_int(structure, "rate", &rate);
4257         gst_structure_get_int(structure, "channels", &channel);
4258         gst_structure_get_int(structure, "depth", &depth);
4259         gst_structure_get_int(structure, "endianness", &endianness);
4260         gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
4261         gst_caps_unref(GST_CAPS(caps));
4262
4263         /* In case of the sync is false, use buffer list.              *
4264          * The num of buffer list depends on the num of audio channels */
4265         if (player->audio_stream_buff_list) {
4266                 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4267                         mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4268                         if (tmp) {
4269                                 if (channel_mask == tmp->channel_mask) {
4270                                         /* LOGD("[%lld] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
4271                                         if (tmp->data_size + a_size < tmp->buff_size) {
4272                                                 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
4273                                                 tmp->data_size += a_size;
4274                                         } else {
4275                                                 /* send data to client */
4276                                                 __mmplayer_audio_stream_send_data(player, tmp);
4277
4278                                                 if (a_size > tmp->buff_size) {
4279                                                         LOGD("[%lld] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
4280                                                         tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
4281                                                         if (tmp->pcm_data == NULL) {
4282                                                                 LOGE("failed to realloc data.");
4283                                                                 goto DONE;
4284                                                         }
4285                                                         tmp->buff_size = a_size;
4286                                                 }
4287                                                 memset(tmp->pcm_data, 0x00, tmp->buff_size);
4288                                                 memcpy(tmp->pcm_data, a_data, a_size);
4289                                                 tmp->data_size = a_size;
4290                                         }
4291                                         goto DONE;
4292                                 }
4293                         } else {
4294                                 LOGE("data is empty in list.");
4295                                 goto DONE;
4296                         }
4297                 }
4298         }
4299
4300         /* create new audio stream data */
4301         a_buffer = (mm_player_audio_stream_buff_t*)g_malloc0(sizeof(mm_player_audio_stream_buff_t));
4302         if (a_buffer == NULL) {
4303                 LOGE("failed to alloc data.");
4304                 goto DONE;
4305         }
4306         a_buffer->bitrate = rate;
4307         a_buffer->channel = channel;
4308         a_buffer->depth = depth;
4309         a_buffer->is_little_endian = (endianness == 1234 ? 1 : 0);
4310         a_buffer->channel_mask = channel_mask;
4311         a_buffer->data_size = a_size;
4312
4313         if (!player->audio_stream_sink_sync) {
4314                 /* If sync is FALSE, use buffer list to reduce the IPC. */
4315                 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
4316                 a_buffer->pcm_data = g_malloc(a_buffer->buff_size);
4317                 if (a_buffer->pcm_data == NULL) {
4318                         LOGE("failed to alloc data.");
4319                         g_free(a_buffer);
4320                         goto DONE;
4321                 }
4322                 memcpy(a_buffer->pcm_data, a_data, a_size);
4323                 /* LOGD("new [%lld] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
4324                 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
4325         } else {
4326                 /* If sync is TRUE, send data directly. */
4327                 a_buffer->pcm_data = a_data;
4328                 __mmplayer_audio_stream_send_data(player, a_buffer);
4329                 g_free(a_buffer);
4330         }
4331
4332 DONE:
4333         gst_buffer_unmap(buffer, &mapinfo);
4334         MMPLAYER_FLEAVE();
4335 }
4336
4337 static void
4338 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
4339 {
4340         mm_player_t* player = (mm_player_t*)data;
4341         MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4342         GstPad* sinkpad = NULL;
4343         GstElement *queue = NULL, *sink = NULL;
4344
4345         MMPLAYER_FENTER();
4346         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
4347
4348         queue = gst_element_factory_make("queue", NULL);
4349         if (queue == NULL) {
4350                 LOGD("fail make queue\n");
4351                 goto ERROR;
4352         }
4353
4354         sink = gst_element_factory_make("fakesink", NULL);
4355         if (sink == NULL) {
4356                 LOGD("fail make fakesink\n");
4357                 goto ERROR;
4358         }
4359
4360         gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
4361
4362         if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
4363                 LOGW("failed to link queue & sink\n");
4364                 goto ERROR;
4365         }
4366
4367         sinkpad = gst_element_get_static_pad(queue, "sink");
4368
4369         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
4370                 LOGW("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad));
4371                 goto ERROR;
4372         }
4373
4374         LOGE("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync);
4375
4376         gst_object_unref(sinkpad);
4377         g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
4378         g_object_set(sink, "signal-handoffs", TRUE, NULL);
4379
4380         gst_element_set_state(sink, GST_STATE_PAUSED);
4381         gst_element_set_state(queue, GST_STATE_PAUSED);
4382
4383         MMPLAYER_SIGNAL_CONNECT(player,
4384                 G_OBJECT(sink),
4385                 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4386                 "handoff",
4387                 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
4388                 (gpointer)player);
4389
4390         MMPLAYER_FLEAVE();
4391         return;
4392
4393 ERROR:
4394         LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n");
4395         if (queue) {
4396                 gst_object_unref(GST_OBJECT(queue));
4397                 queue = NULL;
4398         }
4399         if (sink) {
4400                 gst_object_unref(GST_OBJECT(sink));
4401                 sink = NULL;
4402         }
4403         if (sinkpad) {
4404                 gst_object_unref(GST_OBJECT(sinkpad));
4405                 sinkpad = NULL;
4406         }
4407
4408         return;
4409 }
4410
4411 void __mmplayer_gst_set_audiosink_property(mm_player_t* player, MMHandleType attrs)
4412 {
4413         #define MAX_PROPS_LEN 128
4414         gint latency_mode = 0;
4415         gchar *stream_type = NULL;
4416         gchar *latency = NULL;
4417         gint stream_id = 0;
4418         gchar stream_props[MAX_PROPS_LEN] = {0,};
4419         GstStructure *props = NULL;
4420
4421         /* set volume table
4422          * It should be set after player creation through attribute.
4423          * But, it can not be changed during playing.
4424          */
4425         MMPLAYER_FENTER();
4426         mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
4427         mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
4428
4429         if (!stream_type) {
4430                 LOGE("stream_type is null.\n");
4431         } else {
4432                 if (player->sound.focus_id)
4433                         snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d",
4434                                         stream_type, stream_id, player->sound.focus_id);
4435                 else
4436                         snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d",
4437                                         stream_type, stream_id);
4438                 props = gst_structure_from_string(stream_props, NULL);
4439                 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
4440                 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], result[%s].\n",
4441                         stream_type, stream_id, player->sound.focus_id, stream_props);
4442                 gst_structure_free(props);
4443         }
4444
4445         mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
4446
4447         switch (latency_mode) {
4448         case AUDIO_LATENCY_MODE_LOW:
4449                 latency = g_strndup("low", 3);
4450                 break;
4451         case AUDIO_LATENCY_MODE_MID:
4452                 latency = g_strndup("mid", 3);
4453                 break;
4454         case AUDIO_LATENCY_MODE_HIGH:
4455                 latency = g_strndup("high", 4);
4456                 break;
4457         };
4458
4459         g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
4460                         "latency", latency,
4461                         NULL);
4462
4463         LOGD("audiosink property - latency=%s \n", latency);
4464
4465         g_free(latency);
4466
4467         MMPLAYER_FLEAVE();
4468 }
4469
4470 static int
4471 __mmplayer_gst_create_audio_pipeline(mm_player_t* player)
4472 {
4473         MMPlayerGstElement* first_element = NULL;
4474         MMPlayerGstElement* audiobin = NULL;
4475         MMHandleType attrs = 0;
4476         GstPad *pad = NULL;
4477         GstPad *ghostpad = NULL;
4478         GList* element_bucket = NULL;
4479         gboolean link_audio_sink_now = TRUE;
4480         int i = 0;
4481         GstCaps *acaps;
4482
4483         MMPLAYER_FENTER();
4484
4485         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4486
4487         /* alloc handles */
4488         audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
4489         if (!audiobin) {
4490                 LOGE("failed to allocate memory for audiobin\n");
4491                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
4492         }
4493
4494         attrs = MMPLAYER_GET_ATTRS(player);
4495
4496         /* create bin */
4497         audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
4498         audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
4499         if (!audiobin[MMPLAYER_A_BIN].gst) {
4500                 LOGE("failed to create audiobin\n");
4501                 goto ERROR;
4502         }
4503
4504         /* take it */
4505         player->pipeline->audiobin = audiobin;
4506
4507         player->set_mode.pcm_extraction = __mmplayer_can_extract_pcm(player);
4508
4509         /* Adding audiotp plugin for reverse trickplay feature */
4510 //      MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TP, "audiotp", "audio trickplay", TRUE, player);
4511
4512         /* converter */
4513         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
4514
4515         /* replaygain volume */
4516         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player);
4517         if (player->sound.rg_enable)
4518                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
4519         else
4520                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
4521
4522         /* resampler */
4523         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER,  player->ini.audioresampler_element, "audio resampler", TRUE, player);
4524
4525         if (player->set_mode.pcm_extraction) {
4526                 // pcm extraction only and no sound output
4527                 if (player->audio_stream_render_cb_ex) {
4528                         char *caps_str = NULL;
4529                         GstCaps* caps = NULL;
4530                         gchar *format = NULL;
4531
4532                         /* capsfilter */
4533                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4534
4535                         mm_attrs_get_string_by_name(player->attrs, "pcm_audioformat", &format);
4536
4537                         LOGD("contents : format: %s samplerate : %d pcm_channel: %d", format, player->pcm_samplerate, player->pcm_channel);
4538
4539                         caps = gst_caps_new_simple("audio/x-raw",
4540                                         "format", G_TYPE_STRING, format,
4541                                         "rate", G_TYPE_INT, player->pcm_samplerate,
4542                                         "channels", G_TYPE_INT, player->pcm_channel,
4543                                         NULL);
4544                         caps_str = gst_caps_to_string(caps);
4545                         LOGD("new caps : %s\n", caps_str);
4546
4547                         g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4548
4549                         /* clean */
4550                         gst_caps_unref(caps);
4551                         MMPLAYER_FREEIF(caps_str);
4552
4553                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
4554
4555                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
4556                         /* raw pad handling signal */
4557                         MMPLAYER_SIGNAL_CONNECT(player,
4558                                 (audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
4559                                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
4560                                                                                                 G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), player);
4561                 } else {
4562                         int dst_samplerate = 0;
4563                         int dst_channels = 0;
4564                         int dst_depth = 0;
4565                         char *caps_str = NULL;
4566                         GstCaps* caps = NULL;
4567
4568                         /* get conf. values */
4569                         mm_attrs_multiple_get(player->attrs,
4570                                                 NULL,
4571                                                 "pcm_extraction_samplerate", &dst_samplerate,
4572                                                 "pcm_extraction_channels", &dst_channels,
4573                                                 "pcm_extraction_depth", &dst_depth,
4574                                                 NULL);
4575
4576                         /* capsfilter */
4577                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4578                         caps = gst_caps_new_simple("audio/x-raw",
4579                                         "rate", G_TYPE_INT, dst_samplerate,
4580                                         "channels", G_TYPE_INT, dst_channels,
4581                                         "depth", G_TYPE_INT, dst_depth,
4582                                         NULL);
4583                         caps_str = gst_caps_to_string(caps);
4584                         LOGD("new caps : %s\n", caps_str);
4585
4586                         g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4587
4588                         /* clean */
4589                         gst_caps_unref(caps);
4590                         MMPLAYER_FREEIF(caps_str);
4591
4592                         /* fake sink */
4593                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "fakesink", TRUE, player);
4594
4595                         /* set sync */
4596                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL);
4597                 }
4598         } else {
4599                 // normal playback
4600                 //GstCaps* caps = NULL;
4601                 gint channels = 0;
4602
4603                 /* for logical volume control */
4604                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
4605                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
4606
4607                 if (player->sound.mute) {
4608                         LOGD("mute enabled\n");
4609                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
4610                 }
4611
4612 #if 0
4613                 /*capsfilter */
4614                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE, player);
4615                 caps = gst_caps_from_string("audio/x-raw-int, "
4616                                         "endianness = (int) LITTLE_ENDIAN, "
4617                                         "signed = (boolean) true, "
4618                                         "width = (int) 16, "
4619                                         "depth = (int) 16");
4620                 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4621                 gst_caps_unref(caps);
4622 #endif
4623
4624                 /* check if multi-channels */
4625                 if (player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) {
4626                         GstPad *srcpad = NULL;
4627                         GstCaps *caps = NULL;
4628
4629                         if ((srcpad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "src"))) {
4630                                 if ((caps = gst_pad_query_caps(srcpad, NULL))) {
4631                                         //MMPLAYER_LOG_GST_CAPS_TYPE(caps);
4632                                         GstStructure *str = gst_caps_get_structure(caps, 0);
4633                                         if (str)
4634                                                 gst_structure_get_int(str, "channels", &channels);
4635                                         gst_caps_unref(caps);
4636                                 }
4637                                 gst_object_unref(srcpad);
4638                         }
4639                 }
4640
4641                 /* audio effect element. if audio effect is enabled */
4642                 if ((strcmp(player->ini.audioeffect_element, ""))
4643                         && (channels <= 2)
4644                         && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4645                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
4646
4647                         LOGD("audio effect config. bypass = %d, effect type  = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
4648
4649                         if ((!player->bypass_audio_effect)
4650                                 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4651                                 if (MM_AUDIO_EFFECT_TYPE_CUSTOM == player->audio_effect_info.effect_type) {
4652                                         if (!_mmplayer_audio_effect_custom_apply(player))
4653                                                 LOGI("apply audio effect(custom) setting success\n");
4654                                 }
4655                         }
4656
4657                         if ((strcmp(player->ini.audioeffect_element_custom, ""))
4658                                 && (player->set_mode.rich_audio))
4659                                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
4660                 }
4661
4662                 /* create audio sink */
4663                 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
4664                                 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
4665                                 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
4666
4667                 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
4668                 if (player->is_360_feature_enabled &&
4669                         player->is_content_spherical &&
4670                         channels == 4 &&
4671                         player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
4672                         player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
4673                         player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
4674
4675                         strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
4676
4677                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", link_audio_sink_now, player);
4678
4679                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", link_audio_sink_now, player);
4680                         acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
4681                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
4682                         gst_caps_unref(acaps);
4683
4684                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", link_audio_sink_now, player);
4685                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
4686                         sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
4687                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
4688
4689                         player->is_openal_plugin_used = TRUE;
4690
4691                         if (player->video360_yaw_radians <= M_PI &&
4692                                         player->video360_yaw_radians >= -M_PI &&
4693                                         player->video360_pitch_radians <= M_PI_2 &&
4694                                         player->video360_pitch_radians >= -M_PI_2) {
4695                                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
4696                                                 "source-orientation-y", (int) (player->video360_yaw_radians * 180.0 / M_PI),
4697                                                 "source-orientation-x", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
4698                         } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
4699                                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
4700                                                 "source-orientation-y", player->video360_metadata.init_view_heading,
4701                                                 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
4702                         }
4703                 } else {
4704                         if (player->is_360_feature_enabled && player->is_content_spherical)
4705                                 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.\n");
4706                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", link_audio_sink_now, player);
4707                 }
4708
4709                 /* qos on */
4710                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL);       /* qos on */
4711                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
4712
4713
4714                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
4715                         (player->videodec_linked && player->ini.use_system_clock)) {
4716                         LOGD("system clock will be used.\n");
4717                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE,  NULL);
4718                 }
4719
4720                 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
4721                         __mmplayer_gst_set_audiosink_property(player, attrs);
4722         }
4723
4724         if (audiobin[MMPLAYER_A_SINK].gst) {
4725                 GstPad *sink_pad = NULL;
4726                 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
4727                 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4728                                         "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
4729                 gst_object_unref(GST_OBJECT(sink_pad));
4730         }
4731
4732         __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
4733
4734         /* adding created elements to bin */
4735         LOGD("adding created elements to bin\n");
4736         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket)) {
4737                 LOGE("failed to add elements\n");
4738                 goto ERROR;
4739         }
4740
4741         /* linking elements in the bucket by added order. */
4742         LOGD("Linking elements in the bucket by added order.\n");
4743         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4744                 LOGE("failed to link elements\n");
4745                 goto ERROR;
4746         }
4747
4748         /* get first element's sinkpad for creating ghostpad */
4749         first_element = (MMPlayerGstElement *)element_bucket->data;
4750         if (!first_element) {
4751                 LOGE("failed to get first elem\n");
4752                 goto ERROR;
4753         }
4754
4755         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
4756         if (!pad) {
4757                 LOGE("failed to get pad from first element of audiobin\n");
4758                 goto ERROR;
4759         }
4760
4761         ghostpad = gst_ghost_pad_new("sink", pad);
4762         if (!ghostpad) {
4763                 LOGE("failed to create ghostpad\n");
4764                 goto ERROR;
4765         }
4766
4767         if (FALSE == gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
4768                 LOGE("failed to add ghostpad to audiobin\n");
4769                 goto ERROR;
4770         }
4771
4772         gst_object_unref(pad);
4773
4774         g_list_free(element_bucket);
4775         MMPLAYER_FLEAVE();
4776
4777         return MM_ERROR_NONE;
4778
4779 ERROR:
4780
4781         LOGD("ERROR : releasing audiobin\n");
4782
4783         if (pad)
4784                 gst_object_unref(GST_OBJECT(pad));
4785
4786         if (ghostpad)
4787                 gst_object_unref(GST_OBJECT(ghostpad));
4788
4789         if (element_bucket)
4790                 g_list_free(element_bucket);
4791
4792         /* release element which are not added to bin */
4793         for (i = 1; i < MMPLAYER_A_NUM; i++) {
4794                 /* NOTE : skip bin */
4795                 if (audiobin[i].gst) {
4796                         GstObject* parent = NULL;
4797                         parent = gst_element_get_parent(audiobin[i].gst);
4798
4799                         if (!parent) {
4800                                 gst_object_unref(GST_OBJECT(audiobin[i].gst));
4801                                 audiobin[i].gst = NULL;
4802                         } else
4803                                 gst_object_unref(GST_OBJECT(parent));
4804                 }
4805         }
4806
4807         /* release audiobin with it's childs */
4808         if (audiobin[MMPLAYER_A_BIN].gst)
4809                 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
4810
4811         MMPLAYER_FREEIF(audiobin);
4812
4813         player->pipeline->audiobin = NULL;
4814
4815         return MM_ERROR_PLAYER_INTERNAL;
4816 }
4817
4818 static GstPadProbeReturn
4819 __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4820 {
4821         mm_player_t* player = (mm_player_t*) u_data;
4822         GstBuffer *pad_buffer = gst_pad_probe_info_get_buffer(info);
4823         GstMapInfo probe_info = GST_MAP_INFO_INIT;
4824
4825         gst_buffer_map(pad_buffer, &probe_info, GST_MAP_READ);
4826
4827         if (player->audio_stream_cb && probe_info.size && probe_info.data)
4828                 player->audio_stream_cb((void *)probe_info.data, probe_info.size, player->audio_stream_cb_user_param);
4829
4830         return GST_PAD_PROBE_OK;
4831 }
4832
4833 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
4834 {
4835         return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
4836 }
4837
4838 int _mmplayer_video_stream_release_bo(mm_player_t* player, void* bo)
4839 {
4840         int ret = MM_ERROR_NONE;
4841         GList *l = NULL;
4842         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4843         MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
4844
4845         MMPLAYER_VIDEO_BO_LOCK(player);
4846
4847         if (player->video_bo_list) {
4848                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4849                         mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4850                         if (tmp && tmp->bo == bo) {
4851                                 tmp->using = FALSE;
4852                                 LOGD("release bo %p", bo);
4853                                 tbm_bo_unref(tmp->bo);
4854                                 MMPLAYER_VIDEO_BO_UNLOCK(player);
4855                                 MMPLAYER_VIDEO_BO_SIGNAL(player);
4856                                 return ret;
4857                         }
4858                 }
4859         } else {
4860                 /* hw codec is running or the list was reset for DRC. */
4861                 LOGW("there is no bo list.");
4862         }
4863         MMPLAYER_VIDEO_BO_UNLOCK(player);
4864
4865         LOGW("failed to find bo %p", bo);
4866         return ret;
4867 }
4868
4869 static void
4870 __mmplayer_video_stream_destroy_bo_list(mm_player_t* player)
4871 {
4872         GList *l = NULL;
4873
4874         MMPLAYER_FENTER();
4875         MMPLAYER_RETURN_IF_FAIL(player);
4876
4877         MMPLAYER_VIDEO_BO_LOCK(player);
4878         if (player->video_bo_list) {
4879                 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
4880                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4881                         mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4882                         if (tmp) {
4883                                 if (tmp->bo)
4884                                         tbm_bo_unref(tmp->bo);
4885                                 g_free(tmp);
4886                         }
4887                 }
4888                 g_list_free(player->video_bo_list);
4889                 player->video_bo_list = NULL;
4890         }
4891         player->video_bo_size = 0;
4892         MMPLAYER_VIDEO_BO_UNLOCK(player);
4893
4894         MMPLAYER_FLEAVE();
4895         return;
4896 }
4897
4898 static void*
4899 __mmplayer_video_stream_get_bo(mm_player_t* player, int size)
4900 {
4901         GList *l = NULL;
4902         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
4903         gboolean ret = TRUE;
4904
4905         /* check DRC, if it is, destroy the prev bo list to create again */
4906         if (player->video_bo_size != size) {
4907                 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
4908                 __mmplayer_video_stream_destroy_bo_list(player);
4909                 player->video_bo_size = size;
4910         }
4911
4912         MMPLAYER_VIDEO_BO_LOCK(player);
4913
4914         if ((!player->video_bo_list) ||
4915                 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
4916
4917                 /* create bo list */
4918                 int idx = 0;
4919                 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
4920
4921                 if (player->video_bo_list) {
4922                         /* if bo list did not created all, try it again. */
4923                         idx = g_list_length(player->video_bo_list);
4924                         LOGD("bo list exist(len: %d)", idx);
4925                 }
4926
4927                 for (; idx < player->ini.num_of_video_bo; idx++) {
4928                         mm_player_video_bo_info_t* bo_info = g_new(mm_player_video_bo_info_t, 1);
4929                         if (!bo_info) {
4930                                 LOGE("Fail to alloc bo_info.");
4931                                 break;
4932                         }
4933                         bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
4934                         if (!bo_info->bo) {
4935                                 LOGE("Fail to tbm_bo_alloc.");
4936                                 g_free(bo_info);
4937                                 break;
4938                         }
4939                         bo_info->using = FALSE;
4940                         player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
4941                 }
4942
4943                 /* update video num buffers */
4944                 player->video_num_buffers = idx;
4945                 if (idx == player->ini.num_of_video_bo)
4946                         player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
4947
4948                 if (idx == 0) {
4949                         MMPLAYER_VIDEO_BO_UNLOCK(player);
4950                         return NULL;
4951                 }
4952
4953                 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
4954         }
4955
4956         while (TRUE) {
4957                 /* get bo from list*/
4958                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4959                         mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4960                         if (tmp && (tmp->using == FALSE)) {
4961                                 LOGD("found bo %p to use", tmp->bo);
4962                                 tmp->using = TRUE;
4963                                 MMPLAYER_VIDEO_BO_UNLOCK(player);
4964                                 return tbm_bo_ref(tmp->bo);
4965                         }
4966                 }
4967                 if (!ret) {
4968                         LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
4969                         MMPLAYER_VIDEO_BO_UNLOCK(player);
4970                         return NULL;
4971                 }
4972
4973                 if (player->ini.video_bo_timeout <= 0) {
4974                         MMPLAYER_VIDEO_BO_WAIT(player);
4975                 } else {
4976                         gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout*G_TIME_SPAN_SECOND;
4977                         ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
4978                 }
4979                 continue;
4980         }
4981 }
4982
4983 static void
4984 __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4985 {
4986         mm_player_t* player = (mm_player_t*)data;
4987         MMPLAYER_FENTER();
4988         MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
4989
4990         /* send prerolled pkt */
4991         player->video_stream_prerolled = FALSE;
4992
4993         __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
4994
4995         /* not to send prerolled pkt again */
4996         player->video_stream_prerolled = TRUE;
4997 }
4998
4999 static void
5000 __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5001 {
5002         mm_player_t* player = (mm_player_t*)data;
5003         GstCaps *caps = NULL;
5004         MMPlayerVideoStreamDataType *stream = NULL;
5005         MMVideoBuffer *video_buffer = NULL;
5006         GstMemory *dataBlock = NULL;
5007         GstMemory *metaBlock = NULL;
5008         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5009         GstStructure *structure = NULL;
5010         const gchar *string_format = NULL;
5011         unsigned int fourcc = 0;
5012
5013         MMPLAYER_FENTER();
5014         MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
5015
5016         if (player->video_stream_prerolled) {
5017                 player->video_stream_prerolled = FALSE;
5018                 LOGD("skip the prerolled pkt not to send it again");
5019                 return;
5020         }
5021
5022         caps = gst_pad_get_current_caps(pad);
5023         if (caps == NULL) {
5024                 LOGE("Caps is NULL.");
5025                 return;
5026         }
5027
5028         /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
5029
5030         /* clear stream data structure */
5031         stream = (MMPlayerVideoStreamDataType *)g_malloc0(sizeof(MMPlayerVideoStreamDataType));
5032         if (!stream) {
5033                 LOGE("failed to alloc mem for video data");
5034                 return;
5035         }
5036
5037         structure = gst_caps_get_structure(caps, 0);
5038         gst_structure_get_int(structure, "width", &(stream->width));
5039         gst_structure_get_int(structure, "height", &(stream->height));
5040         string_format = gst_structure_get_string(structure, "format");
5041         if (string_format)
5042                 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
5043         stream->format = util_get_pixtype(fourcc);
5044         gst_caps_unref(caps);
5045         caps = NULL;
5046
5047     /*
5048         LOGD("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
5049                 GST_BUFFER_DATA(buffer), stream.width, stream.height, stream.format);
5050     */
5051
5052         if (stream->width == 0 || stream->height == 0 || stream->format == MM_PIXEL_FORMAT_INVALID) {
5053                 LOGE("Wrong condition!!");
5054                 goto ERROR;
5055         }
5056
5057         /* set size and timestamp */
5058         dataBlock = gst_buffer_peek_memory(buffer, 0);
5059         stream->length_total = gst_memory_get_sizes(dataBlock, NULL, NULL);
5060         stream->timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/1000000); /* nano sec -> mili sec */
5061
5062         /* check zero-copy */
5063         if (player->set_mode.video_zc &&
5064                 player->set_mode.media_packet_video_stream &&
5065                 gst_buffer_n_memory(buffer) > 1) {
5066                 metaBlock = gst_buffer_peek_memory(buffer, 1);
5067                 gst_memory_map(metaBlock, &mapinfo, GST_MAP_READ);
5068                 video_buffer = (MMVideoBuffer *)mapinfo.data;
5069         }
5070
5071         if (video_buffer) { /* hw codec */
5072                 /* set tbm bo */
5073                 if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
5074                         int i = 0;
5075
5076                         /* copy pointer of tbm bo, stride, elevation */
5077                         while (i < MM_VIDEO_BUFFER_PLANE_MAX && video_buffer->handle.bo[i]) {
5078                                 stream->bo[i] = tbm_bo_ref(video_buffer->handle.bo[i]);
5079                                 i++;
5080                         }
5081                 } else {
5082                         LOGE("Not support video buffer format");
5083                         goto ERROR;
5084                 }
5085                 memcpy(stream->stride, video_buffer->stride_width,
5086                                 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5087                 memcpy(stream->elevation, video_buffer->stride_height,
5088                                 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5089
5090                 /* will be released, by calling _mm_player_video_stream_internal_buffer_unref() */
5091                 stream->internal_buffer = gst_buffer_ref(buffer);
5092         } else { /* sw codec */
5093                 int i = 0;
5094                 int j = 0;
5095                 int k = 0;
5096                 int ret = TBM_SURFACE_ERROR_NONE;
5097                 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
5098                 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
5099                 int size = 0;
5100                 unsigned char *src = NULL;
5101                 unsigned char *dest = NULL;
5102                 tbm_bo_handle thandle;
5103                 tbm_surface_h surface;
5104                 tbm_surface_info_s info;
5105                 gboolean gst_ret;
5106
5107                 gst_ret = gst_memory_map(dataBlock, &mapinfo, GST_MAP_READWRITE);
5108                 if (!gst_ret) {
5109                         LOGE("fail to gst_memory_map");
5110                         goto ERROR;
5111                 }
5112
5113
5114                 if (stream->format == MM_PIXEL_FORMAT_I420) {
5115                         surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
5116
5117                         ret = tbm_surface_get_info(surface, &info);
5118
5119                         if (ret != TBM_SURFACE_ERROR_NONE) {
5120                                 tbm_surface_destroy(surface);
5121                                 goto ERROR;
5122                         }
5123                         tbm_surface_destroy(surface);
5124
5125                         src_stride[0] = GST_ROUND_UP_4(stream->width);
5126                         src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width>>1);
5127                         src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
5128                         src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height)>>1));
5129                         stream->stride[0] = info.planes[0].stride;
5130                         stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
5131                         stream->stride[1] = info.planes[1].stride;
5132                         stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
5133                         stream->stride[2] = info.planes[2].stride;
5134                         stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
5135                         size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
5136                 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
5137                         stream->stride[0] = stream->width * 4;
5138                         stream->elevation[0] = stream->height;
5139                         size = stream->stride[0] * stream->height;
5140                 } else {
5141                         LOGE("Not support format %d", stream->format);
5142                         goto ERROR;
5143                 }
5144
5145                 stream->bo[0] = __mmplayer_video_stream_get_bo(player, size);
5146                 if (!stream->bo[0]) {
5147                         LOGE("Fail to tbm_bo_alloc!!");
5148                         goto ERROR;
5149                 }
5150
5151                 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
5152                 if (thandle.ptr && mapinfo.data) {
5153                         if (stream->format == MM_PIXEL_FORMAT_I420) {
5154                                 for (i = 0; i < 3; i++) {
5155                                         src = mapinfo.data + src_offset[i];
5156                                         dest = thandle.ptr + info.planes[i].offset;
5157
5158                                         if (i > 0) k = 1;
5159                                         for (j = 0; j < stream->height>>k; j++) {
5160                                                 memcpy(dest, src, stream->width>>k);
5161                                                 src += src_stride[i];
5162                                                 dest += stream->stride[i];
5163                                         }
5164                                 }
5165                         } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
5166                                 memcpy(thandle.ptr, mapinfo.data, size);
5167                         } else {
5168                                 LOGE("Not support format %d", stream->format);
5169                                 goto ERROR;
5170                         }
5171                 } else {
5172                         LOGE("data pointer is wrong. dest : %p, src : %p",
5173                                         thandle.ptr, mapinfo.data);
5174                         goto ERROR;
5175                 }
5176                 tbm_bo_unmap(stream->bo[0]);
5177         }
5178
5179         if (player->video_stream_cb) { /* This has been already checked at the entry */
5180                 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
5181                         LOGE("failed to send video stream data.");
5182                         goto ERROR;
5183                 }
5184         }
5185
5186         if (metaBlock)
5187                 gst_memory_unmap(metaBlock, &mapinfo);
5188         else
5189                 gst_memory_unmap(dataBlock, &mapinfo);
5190
5191         return;
5192
5193 ERROR:
5194         LOGE("release video stream resource.");
5195         if (metaBlock) {
5196                 int i = 0;
5197                 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
5198                         if (stream->bo[i])
5199                                 tbm_bo_unref(stream->bo[i]);
5200                 }
5201                 gst_memory_unmap(metaBlock, &mapinfo);
5202
5203                 /* unref gst buffer */
5204                 if (stream->internal_buffer)
5205                         gst_buffer_unref(stream->internal_buffer);
5206         } else if (dataBlock) {
5207                 if (stream->bo[0])
5208                         _mmplayer_video_stream_release_bo(player, stream->bo[0]);
5209                 gst_memory_unmap(dataBlock, &mapinfo);
5210         }
5211
5212         g_free(stream);
5213         return;
5214 }
5215
5216 static int
5217 __mmplayer_gst_create_video_filters(mm_player_t* player, GList** bucket)
5218 {
5219         gchar* video_csc = "videoconvert"; /* default colorspace converter */
5220         GList* element_bucket = NULL;
5221
5222         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5223
5224         MMPLAYER_FENTER();
5225
5226         if (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical)) {
5227                 LOGD("do not need to add video filters.");
5228                 return MM_ERROR_NONE;
5229         }
5230
5231         /* in case of sw codec except 360 playback,
5232          * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
5233         MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
5234         LOGD("using video converter: %s", video_csc);
5235
5236         /* set video rotator */
5237         MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
5238
5239         *bucket = element_bucket;
5240         MMPLAYER_FLEAVE();
5241         return MM_ERROR_NONE;
5242
5243 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
5244         g_list_free(element_bucket);
5245
5246         *bucket = NULL;
5247         MMPLAYER_FLEAVE();
5248         return MM_ERROR_PLAYER_INTERNAL;
5249 }
5250
5251 /**
5252  * This function is to create video pipeline.
5253  *
5254  * @param       player          [in]    handle of player
5255  *              caps            [in]    src caps of decoder
5256  *              surface_type    [in]    surface type for video rendering
5257  *
5258  * @return      This function returns zero on success.
5259  * @remark
5260  * @see         __mmplayer_gst_create_audio_pipeline, __mmplayer_gst_create_midi_pipeline
5261  */
5262 /**
5263   * VIDEO PIPELINE
5264   * - video overlay surface(arm/x86) : tizenwlsink
5265   */
5266 static int
5267 __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
5268 {
5269         GstPad *pad = NULL;
5270         MMHandleType attrs;
5271         GList*element_bucket = NULL;
5272         MMPlayerGstElement* first_element = NULL;
5273         MMPlayerGstElement* videobin = NULL;
5274         gchar *videosink_element = NULL;
5275
5276         MMPLAYER_FENTER();
5277
5278         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5279
5280         /* alloc handles */
5281         videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
5282         if (!videobin)
5283                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5284
5285         player->pipeline->videobin = videobin;
5286
5287         attrs = MMPLAYER_GET_ATTRS(player);
5288         if (!attrs) {
5289                 LOGE("cannot get content attribute");
5290                 return MM_ERROR_PLAYER_INTERNAL;
5291         }
5292
5293         /* create bin */
5294         videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
5295         videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
5296         if (!videobin[MMPLAYER_V_BIN].gst) {
5297                 LOGE("failed to create videobin");
5298                 goto ERROR;
5299         }
5300
5301         int enable_video_decoded_cb = 0;
5302         mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable_video_decoded_cb);
5303
5304         if (player->is_360_feature_enabled && player->is_content_spherical) {
5305                 LOGD("video360 elem will be added.");
5306
5307                 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_360, "video360",
5308                                 "video-360", TRUE, player);
5309
5310                 /* Set spatial media metadata and/or user settings to the element.
5311                  * */
5312                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5313                                 "projection-type", player->video360_metadata.projection_type, NULL);
5314
5315                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5316                                 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
5317
5318                 if (player->video360_metadata.full_pano_width_pixels &&
5319                                 player->video360_metadata.full_pano_height_pixels &&
5320                                 player->video360_metadata.cropped_area_image_width &&
5321                                 player->video360_metadata.cropped_area_image_height) {
5322                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5323                                         "projection-bounds-top", player->video360_metadata.cropped_area_top,
5324                                         "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
5325                                                         player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
5326                                         "projection-bounds-left", player->video360_metadata.cropped_area_left,
5327                                         "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
5328                                                         player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
5329                                         NULL);
5330                 }
5331
5332                 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
5333                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5334                                         "horizontal-fov", player->video360_horizontal_fov,
5335                                         "vertical-fov", player->video360_vertical_fov, NULL);
5336                 }
5337
5338                 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
5339                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5340                                         "zoom", 1.0f / player->video360_zoom, NULL);
5341                 }
5342
5343                 if (player->video360_yaw_radians <= M_PI &&
5344                                 player->video360_yaw_radians >= -M_PI &&
5345                                 player->video360_pitch_radians <= M_PI_2 &&
5346                                 player->video360_pitch_radians >= -M_PI_2) {
5347                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5348                                         "pose-yaw", (int) (player->video360_yaw_radians * 180.0 / M_PI),
5349                                         "pose-pitch", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
5350                 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
5351                         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5352                                         "pose-yaw", player->video360_metadata.init_view_heading,
5353                                         "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
5354                 }
5355
5356                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5357                                 "passthrough", !player->is_video360_enabled, NULL);
5358         }
5359
5360         /* set video sink */
5361         switch (surface_type) {
5362         case MM_DISPLAY_SURFACE_OVERLAY:
5363                 if (__mmplayer_gst_create_video_filters(player, &element_bucket) != MM_ERROR_NONE)
5364                         goto ERROR;
5365                 if (strlen(player->ini.videosink_element_overlay) > 0)
5366                         videosink_element = player->ini.videosink_element_overlay;
5367                 else
5368                         goto ERROR;
5369                 break;
5370         case MM_DISPLAY_SURFACE_NULL:
5371                 if (strlen(player->ini.videosink_element_fake) > 0)
5372                         videosink_element = player->ini.videosink_element_fake;
5373                 else
5374                         goto ERROR;
5375                 break;
5376         case MM_DISPLAY_SURFACE_REMOTE:
5377                 if (strlen(player->ini.videosink_element_fake) > 0)
5378                         videosink_element = player->ini.videosink_element_fake;
5379                 else
5380                         goto ERROR;
5381                 break;
5382         default:
5383                 LOGE("unidentified surface type");
5384                 goto ERROR;
5385         }
5386         LOGD("surface_type %d, selected videosink name: %s", surface_type, videosink_element);
5387
5388         MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_element, "videosink", TRUE, player);
5389
5390         /* additional setting for sink plug-in */
5391         switch (surface_type) {
5392         case MM_DISPLAY_SURFACE_OVERLAY:
5393         {
5394                 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
5395                 if (!use_tbm) {
5396                         LOGD("selected videosink name: %s", videosink_element);
5397
5398                         /* support shard memory with S/W codec on HawkP */
5399                         if (strncmp(videosink_element, "tizenwlsink", strlen(videosink_element)) == 0) {
5400                                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
5401                                         "use-tbm", use_tbm, NULL);
5402                         }
5403                 } else {
5404                         if (attrs) {
5405                                 int gapless = 0;
5406
5407                                 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5408
5409                                 if (gapless > 0) {
5410                                         LOGD("disable last-sample");
5411                                         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5412                                 }
5413                         }
5414                 }
5415                 if (player->set_mode.media_packet_video_stream) {
5416                         int enable = 0;
5417                         mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
5418                         if (enable)
5419                                 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
5420
5421                         MMPLAYER_SIGNAL_CONNECT(player,
5422                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5423                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5424                                                                         "handoff",
5425                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5426                                                                         (gpointer)player);
5427
5428                         MMPLAYER_SIGNAL_CONNECT(player,
5429                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5430                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5431                                                                         "preroll-handoff",
5432                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5433                                                                         (gpointer)player);
5434                 }
5435                 break;
5436         }
5437         case MM_DISPLAY_SURFACE_REMOTE:
5438         {
5439                 if (player->set_mode.media_packet_video_stream) {
5440                         LOGE("add data probe at videosink");
5441                         g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5442                                                                                         "sync", TRUE, "signal-handoffs", TRUE, NULL);
5443
5444                         MMPLAYER_SIGNAL_CONNECT(player,
5445                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5446                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5447                                                                         "handoff",
5448                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5449                                                                         (gpointer)player);
5450
5451                         MMPLAYER_SIGNAL_CONNECT(player,
5452                                                                         G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5453                                                                         MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5454                                                                         "preroll-handoff",
5455                                                                         G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5456                                                                         (gpointer)player);
5457                         if (attrs) {
5458                                 int gapless = 0;
5459
5460                                 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5461
5462                                 if (gapless > 0) {
5463                                         LOGD("disable last-sample");
5464                                         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5465                                 }
5466                         }
5467                 }
5468                 break;
5469         }
5470         default:
5471                 break;
5472         }
5473
5474         if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
5475                 goto ERROR;
5476
5477         if (videobin[MMPLAYER_V_SINK].gst) {
5478                 GstPad *sink_pad = NULL;
5479                 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
5480                 if (sink_pad) {
5481                         MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5482                                         "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
5483                         gst_object_unref(GST_OBJECT(sink_pad));
5484                 } else
5485                         LOGW("failed to get sink pad from videosink\n");
5486         }
5487
5488         /* store it as it's sink element */
5489         __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
5490
5491         /* adding created elements to bin */
5492         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
5493                 LOGE("failed to add elements\n");
5494                 goto ERROR;
5495         }
5496
5497         /* Linking elements in the bucket by added order */
5498         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5499                 LOGE("failed to link elements\n");
5500                 goto ERROR;
5501         }
5502
5503         /* get first element's sinkpad for creating ghostpad */
5504         if (element_bucket)
5505                 first_element = (MMPlayerGstElement *)element_bucket->data;
5506         if (!first_element) {
5507                 LOGE("failed to get first element from bucket\n");
5508                 goto ERROR;
5509         }
5510
5511         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
5512         if (!pad) {
5513                 LOGE("failed to get pad from first element\n");
5514                 goto ERROR;
5515         }
5516
5517         /* create ghostpad */
5518         player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
5519         if (FALSE == gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
5520                 LOGE("failed to add ghostpad to videobin\n");
5521                 goto ERROR;
5522         }
5523         gst_object_unref(pad);
5524
5525         /* done. free allocated variables */
5526         if (element_bucket)
5527                 g_list_free(element_bucket);
5528
5529         MMPLAYER_FLEAVE();
5530
5531         return MM_ERROR_NONE;
5532
5533 ERROR:
5534         LOGE("ERROR : releasing videobin\n");
5535
5536         g_list_free(element_bucket);
5537
5538         if (pad)
5539                 gst_object_unref(GST_OBJECT(pad));
5540
5541         /* release videobin with it's childs */
5542         if (videobin[MMPLAYER_V_BIN].gst)
5543                 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
5544
5545
5546         MMPLAYER_FREEIF(videobin);
5547
5548         player->pipeline->videobin = NULL;
5549
5550         return MM_ERROR_PLAYER_INTERNAL;
5551 }
5552
5553 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
5554 {
5555         GList *element_bucket = NULL;
5556         MMPlayerGstElement *textbin = player->pipeline->textbin;
5557
5558         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
5559         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
5560         g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
5561                                                         "signal-handoffs", FALSE,
5562                                                         NULL);
5563
5564         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
5565         MMPLAYER_SIGNAL_CONNECT(player,
5566                                                         G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
5567                                                         MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
5568                                                         "handoff",
5569                                                         G_CALLBACK(__mmplayer_update_subtitle),
5570                                                         (gpointer)player);
5571
5572         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "async", TRUE, NULL);
5573         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE, NULL);
5574         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "signal-handoffs", TRUE, NULL);
5575
5576         if (!player->play_subtitle) {
5577                 LOGD("add textbin sink as sink element of whole pipeline.\n");
5578                 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
5579         }
5580
5581         /* adding created elements to bin */
5582         LOGD("adding created elements to bin\n");
5583         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
5584                 LOGE("failed to add elements\n");
5585                 goto ERROR;
5586         }
5587
5588         /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
5589         GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
5590         GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
5591
5592         /* linking elements in the bucket by added order. */
5593         LOGD("Linking elements in the bucket by added order.\n");
5594         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5595                 LOGE("failed to link elements\n");
5596                 goto ERROR;
5597         }
5598
5599         /* done. free allocated variables */
5600         g_list_free(element_bucket);
5601
5602         if (textbin[MMPLAYER_T_QUEUE].gst) {
5603                 GstPad *pad = NULL;
5604                 GstPad *ghostpad = NULL;
5605
5606                 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
5607                 if (!pad) {
5608                         LOGE("failed to get sink pad of text queue");
5609                         goto ERROR;
5610                 }
5611
5612                 ghostpad = gst_ghost_pad_new("text_sink", pad);
5613                 gst_object_unref(pad);
5614
5615                 if (!ghostpad) {
5616                         LOGE("failed to create ghostpad of textbin\n");
5617                         goto ERROR;
5618                 }
5619
5620                 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
5621                         LOGE("failed to add ghostpad to textbin\n");
5622                         gst_object_unref(ghostpad);
5623                         goto ERROR;
5624                 }
5625         }
5626
5627         return MM_ERROR_NONE;
5628
5629 ERROR:
5630         g_list_free(element_bucket);
5631
5632         if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
5633                 LOGE("remove textbin sink from sink list");
5634                 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
5635         }
5636
5637         /* release element at __mmplayer_gst_create_text_sink_bin */
5638         return MM_ERROR_PLAYER_INTERNAL;
5639 }
5640
5641 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player)
5642 {
5643         MMPlayerGstElement *textbin = NULL;
5644         GList *element_bucket = NULL;
5645         int surface_type = 0;
5646         gint i = 0;
5647
5648         MMPLAYER_FENTER();
5649
5650         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5651
5652         /* alloc handles */
5653         textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
5654         if (!textbin) {
5655                 LOGE("failed to allocate memory for textbin\n");
5656                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5657         }
5658
5659         /* create bin */
5660         textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
5661         textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
5662         if (!textbin[MMPLAYER_T_BIN].gst) {
5663                 LOGE("failed to create textbin\n");
5664                 goto ERROR;
5665         }
5666
5667         /* take it */
5668         player->pipeline->textbin = textbin;
5669
5670         /* fakesink */
5671         mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
5672         LOGD("surface type for subtitle : %d", surface_type);
5673         switch (surface_type) {
5674         case MM_DISPLAY_SURFACE_OVERLAY:
5675         case MM_DISPLAY_SURFACE_NULL:
5676         case MM_DISPLAY_SURFACE_REMOTE:
5677                 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
5678                         LOGE("failed to make plain text elements\n");
5679                         goto ERROR;
5680                 }
5681                 break;
5682         default:
5683                 goto ERROR;
5684                 break;
5685         }
5686
5687         MMPLAYER_FLEAVE();
5688
5689         return MM_ERROR_NONE;
5690
5691 ERROR:
5692
5693         LOGD("ERROR : releasing textbin\n");
5694
5695         g_list_free(element_bucket);
5696
5697         /* release signal */
5698         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5699
5700         /* release element which are not added to bin */
5701         for (i = 1; i < MMPLAYER_T_NUM; i++) {
5702                 /* NOTE : skip bin */
5703                 if (textbin[i].gst) {
5704                         GstObject* parent = NULL;
5705                         parent = gst_element_get_parent(textbin[i].gst);
5706
5707                         if (!parent) {
5708                                 gst_object_unref(GST_OBJECT(textbin[i].gst));
5709                                 textbin[i].gst = NULL;
5710                         } else {
5711                                 gst_object_unref(GST_OBJECT(parent));
5712                         }
5713                 }
5714         }
5715
5716         /* release textbin with it's childs */
5717         if (textbin[MMPLAYER_T_BIN].gst)
5718                 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5719
5720         MMPLAYER_FREEIF(player->pipeline->textbin);
5721         player->pipeline->textbin = NULL;
5722
5723         MMPLAYER_FLEAVE();
5724         return MM_ERROR_PLAYER_INTERNAL;
5725 }
5726
5727
5728 static int
5729 __mmplayer_gst_create_text_pipeline(mm_player_t* player)
5730 {
5731         MMPlayerGstElement* mainbin = NULL;
5732         MMPlayerGstElement* textbin = NULL;
5733         MMHandleType attrs = 0;
5734         GstElement *subsrc = NULL;
5735         GstElement *subparse = NULL;
5736         gchar *subtitle_uri = NULL;
5737         const gchar *charset = NULL;
5738         GstPad *pad = NULL;
5739
5740         MMPLAYER_FENTER();
5741
5742         /* get mainbin */
5743         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5744                                                                 player->pipeline &&
5745                                                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5746
5747         mainbin = player->pipeline->mainbin;
5748
5749         attrs = MMPLAYER_GET_ATTRS(player);
5750         if (!attrs) {
5751                 LOGE("cannot get content attribute\n");
5752                 return MM_ERROR_PLAYER_INTERNAL;
5753         }
5754
5755         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
5756         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
5757                 LOGE("subtitle uri is not proper filepath.\n");
5758                 return MM_ERROR_PLAYER_INVALID_URI;
5759         }
5760
5761         if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
5762                 LOGE("failed to get storage info of subtitle path");
5763                 return MM_ERROR_PLAYER_INVALID_URI;
5764         }
5765
5766         SECURE_LOGD("subtitle file path is [%s].\n", subtitle_uri);
5767
5768         MMPLAYER_SUBTITLE_INFO_LOCK(player);
5769         player->subtitle_language_list = NULL;
5770         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
5771
5772         /* create the subtitle source */
5773         subsrc = gst_element_factory_make("filesrc", "subtitle_source");
5774         if (!subsrc) {
5775                 LOGE("failed to create filesrc element\n");
5776                 goto ERROR;
5777         }
5778         g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
5779
5780         mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
5781         mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
5782
5783         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
5784                 LOGW("failed to add queue\n");
5785                 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
5786                 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
5787                 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
5788                 goto ERROR;
5789         }
5790
5791         /* subparse */
5792         subparse = gst_element_factory_make("subparse", "subtitle_parser");
5793         if (!subparse) {
5794                 LOGE("failed to create subparse element\n");
5795                 goto ERROR;
5796         }
5797
5798         charset = util_get_charset(subtitle_uri);
5799         if (charset) {
5800                 LOGD("detected charset is %s\n", charset);
5801                 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
5802         }
5803
5804         mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
5805         mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
5806
5807         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
5808                 LOGW("failed to add subparse\n");
5809                 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
5810                 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
5811                 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
5812                 goto ERROR;
5813         }
5814
5815         if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
5816                 LOGW("failed to link subsrc and subparse\n");
5817                 goto ERROR;
5818         }
5819
5820         player->play_subtitle = TRUE;
5821         player->adjust_subtitle_pos = 0;
5822
5823         LOGD("play subtitle using subtitle file\n");
5824
5825         if (player->pipeline->textbin == NULL) {
5826                 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
5827                         LOGE("failed to create text sink bin. continuing without text\n");
5828                         goto ERROR;
5829                 }
5830
5831                 textbin = player->pipeline->textbin;
5832
5833                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
5834                         LOGW("failed to add textbin\n");
5835
5836                         /* release signal */
5837                         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5838
5839                         /* release textbin with it's childs */
5840                         gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5841                         MMPLAYER_FREEIF(player->pipeline->textbin);
5842                         player->pipeline->textbin = textbin = NULL;
5843                         goto ERROR;
5844                 }
5845
5846                 LOGD("link text input selector and textbin ghost pad");
5847
5848                 player->textsink_linked = 1;
5849                 player->external_text_idx = 0;
5850                 LOGI("player->textsink_linked set to 1\n");
5851         } else {
5852                 textbin = player->pipeline->textbin;
5853                 LOGD("text bin has been created. reuse it.");
5854                 player->external_text_idx = 1;
5855         }
5856
5857         if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
5858                 LOGW("failed to link subparse and textbin\n");
5859                 goto ERROR;
5860         }
5861
5862         pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
5863         if (!pad) {
5864                 LOGE("failed to get sink pad from textsink to probe data");
5865                 goto ERROR;
5866         }
5867
5868         gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
5869                                 __mmplayer_subtitle_adjust_position_probe, player, NULL);
5870
5871         gst_object_unref(pad);
5872         pad = NULL;
5873
5874         /* create dot. for debugging */
5875         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
5876         MMPLAYER_FLEAVE();
5877
5878         return MM_ERROR_NONE;
5879
5880 ERROR:
5881         /* release text pipeline resource */
5882         player->textsink_linked = 0;
5883
5884         /* release signal */
5885         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5886
5887         if (player->pipeline->textbin) {
5888                 LOGE("remove textbin");
5889
5890                 /* release textbin with it's childs */
5891                 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
5892                 MMPLAYER_FREEIF(player->pipeline->textbin);
5893                 player->pipeline->textbin = NULL;
5894
5895         }
5896
5897         /* release subtitle elem */
5898         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
5899         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
5900
5901         return MM_ERROR_PLAYER_INTERNAL;
5902 }
5903
5904 gboolean
5905 __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5906 {
5907         mm_player_t* player = (mm_player_t*) data;
5908         MMMessageParamType msg = {0, };
5909         GstClockTime duration = 0;
5910         gpointer text = NULL;
5911         guint text_size = 0;
5912         gboolean ret = TRUE;
5913         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5914
5915         MMPLAYER_FENTER();
5916
5917         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5918         MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
5919
5920         if (player->is_subtitle_force_drop) {
5921                 LOGW("subtitle is dropped forcedly.");
5922                 return ret;
5923         }
5924
5925         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
5926         text = mapinfo.data;
5927         text_size = mapinfo.size;
5928         duration = GST_BUFFER_DURATION(buffer);
5929
5930         if (player->set_mode.subtitle_off) {
5931                 LOGD("subtitle is OFF.\n");
5932                 return TRUE;
5933         }
5934
5935         if (!text || (text_size == 0)) {
5936                 LOGD("There is no subtitle to be displayed.\n");
5937                 return TRUE;
5938         }
5939
5940         msg.data = (void *) text;
5941         msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
5942
5943         LOGD("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data);
5944
5945         MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
5946         gst_buffer_unmap(buffer, &mapinfo);
5947
5948         MMPLAYER_FLEAVE();
5949
5950         return ret;
5951 }
5952
5953 static GstPadProbeReturn
5954 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
5955 {
5956         mm_player_t *player = (mm_player_t *) u_data;
5957         GstClockTime cur_timestamp = 0;
5958         gint64 adjusted_timestamp = 0;
5959         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
5960
5961         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5962
5963         if (player->set_mode.subtitle_off) {
5964                 LOGD("subtitle is OFF.\n");
5965                 return TRUE;
5966         }
5967
5968         if (player->adjust_subtitle_pos == 0) {
5969                 LOGD("nothing to do");
5970                 return TRUE;
5971         }
5972
5973         cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
5974         adjusted_timestamp = (gint64) cur_timestamp +((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
5975
5976         if (adjusted_timestamp < 0) {
5977                 LOGD("adjusted_timestamp under zero");
5978                 MMPLAYER_FLEAVE();
5979                 return FALSE;
5980         }
5981
5982         GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
5983         LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
5984                                 GST_TIME_ARGS(cur_timestamp),
5985                                 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
5986
5987         return GST_PAD_PROBE_OK;
5988 }
5989 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
5990 {
5991         MMPLAYER_FENTER();
5992
5993         /* check player and subtitlebin are created */
5994         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5995         MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
5996
5997         if (position == 0) {
5998                 LOGD("nothing to do\n");
5999                 MMPLAYER_FLEAVE();
6000                 return MM_ERROR_NONE;
6001         }
6002
6003         switch (format) {
6004         case MM_PLAYER_POS_FORMAT_TIME:
6005                 {
6006                         /* check current postion */
6007                         player->adjust_subtitle_pos = position;
6008
6009                         LOGD("save adjust_subtitle_pos in player") ;
6010                 }
6011                 break;
6012
6013         default:
6014                 {
6015                         LOGW("invalid format.\n");
6016                         MMPLAYER_FLEAVE();
6017                         return MM_ERROR_INVALID_ARGUMENT;
6018                 }
6019         }
6020
6021         MMPLAYER_FLEAVE();
6022
6023         return MM_ERROR_NONE;
6024 }
6025 static int __gst_adjust_video_position(mm_player_t* player, int offset)
6026 {
6027         MMPLAYER_FENTER();
6028         LOGD("adjusting video_pos in player") ;
6029         int current_pos = 0;
6030         /* check player and videobin are created */
6031         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6032         if (!player->pipeline->videobin ||
6033                         !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
6034                 LOGD("no video pipeline or sink is there");
6035                 return MM_ERROR_PLAYER_INVALID_STATE ;
6036         }
6037         if (offset == 0) {
6038                 LOGD("nothing to do\n");
6039                 MMPLAYER_FLEAVE();
6040                 return MM_ERROR_NONE;
6041         }
6042         if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, (unsigned long*)&current_pos) != MM_ERROR_NONE) {
6043                 LOGD("failed to get current position");
6044                 return MM_ERROR_PLAYER_INTERNAL;
6045         }
6046         if ((current_pos - offset) < GST_TIME_AS_MSECONDS(player->duration)) {
6047                 LOGD("enter video delay is valid");
6048         } else {
6049                 LOGD("enter video delay is crossing content boundary");
6050                 return MM_ERROR_INVALID_ARGUMENT ;
6051         }
6052         g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "ts-offset", ((gint64) offset * G_GINT64_CONSTANT(1000000)), NULL);
6053         LOGD("video delay has been done");
6054         MMPLAYER_FLEAVE();
6055
6056         return MM_ERROR_NONE;
6057 }
6058
6059 static void
6060 __gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
6061 {
6062         GstElement *appsrc = element;
6063         MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
6064         GstBuffer *buffer = NULL;
6065         GstFlowReturn ret = GST_FLOW_OK;
6066         gint len = size;
6067
6068         MMPLAYER_RETURN_IF_FAIL(element);
6069         MMPLAYER_RETURN_IF_FAIL(buf);
6070
6071         buffer = gst_buffer_new();
6072
6073         if (buf->offset >= buf->len) {
6074                 LOGD("call eos appsrc\n");
6075                 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
6076                 return;
6077         }
6078
6079         if (buf->len - buf->offset < size)
6080                 len = buf->len - buf->offset;
6081
6082         gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
6083         GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
6084         GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
6085
6086         //LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
6087         g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
6088
6089         buf->offset += len;
6090 }
6091
6092 static gboolean
6093 __gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
6094 {
6095         MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
6096
6097         MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
6098
6099         buf->offset  = (int)size;
6100
6101         return TRUE;
6102 }
6103
6104 static GstBusSyncReply
6105 __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data)
6106 {
6107         mm_player_t *player = (mm_player_t *)data;
6108         GstBusSyncReply reply = GST_BUS_DROP;
6109
6110         if (!(player->pipeline && player->pipeline->mainbin)) {
6111                 LOGE("player pipeline handle is null");
6112                 return GST_BUS_PASS;
6113         }
6114
6115         if (!__mmplayer_check_useful_message(player, message)) {
6116                 gst_message_unref(message);
6117                 return GST_BUS_DROP;
6118         }
6119
6120         switch (GST_MESSAGE_TYPE(message)) {
6121         case GST_MESSAGE_STATE_CHANGED:
6122                 /* post directly for fast launch */
6123                 if (player->sync_handler) {
6124                         __mmplayer_gst_callback(message, player);
6125                         reply = GST_BUS_DROP;
6126                 } else
6127                         reply = GST_BUS_PASS;
6128                 break;
6129         case GST_MESSAGE_TAG:
6130                 __mmplayer_gst_extract_tag_from_msg(player, message);
6131
6132                 #if 0 // debug
6133                 {
6134                         GstTagList *tags = NULL;
6135
6136                         gst_message_parse_tag(message, &tags);
6137                         if (tags) {
6138                                 LOGE("TAGS received from element \"%s\".\n",
6139                                 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
6140
6141                                 gst_tag_list_foreach(tags, print_tag, NULL);
6142                                 gst_tag_list_free(tags);
6143                                 tags = NULL;
6144                         }
6145                         break;
6146                 }
6147                 #endif
6148                 break;
6149
6150         case GST_MESSAGE_DURATION_CHANGED:
6151                 __mmplayer_gst_handle_duration(player, message);
6152                 break;
6153         case GST_MESSAGE_ASYNC_DONE:
6154                 /* NOTE:Don't call gst_callback directly
6155                  * because previous frame can be showed even though this message is received for seek.
6156                  */
6157         default:
6158                 reply = GST_BUS_PASS;
6159                 break;
6160         }
6161
6162         if (reply == GST_BUS_DROP)
6163                 gst_message_unref(message);
6164
6165         return reply;
6166 }
6167
6168 static gboolean
6169 __mmplayer_gst_create_decoder(mm_player_t *player,
6170                                                                 MMPlayerTrackType track,
6171                                                                 GstPad* srcpad,
6172                                                                 enum MainElementID elemId,
6173                                                                 const gchar* name)
6174 {
6175         gboolean ret = TRUE;
6176         GstPad *sinkpad = NULL;
6177
6178         MMPLAYER_FENTER();
6179
6180         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
6181                                                 player->pipeline &&
6182                                                 player->pipeline->mainbin, FALSE);
6183         MMPLAYER_RETURN_VAL_IF_FAIL((track == MM_PLAYER_TRACK_TYPE_AUDIO || track == MM_PLAYER_TRACK_TYPE_VIDEO), FALSE);
6184         MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
6185         MMPLAYER_RETURN_VAL_IF_FAIL((player->pipeline->mainbin[elemId].gst == NULL), FALSE);
6186
6187         GstElement *decodebin = NULL;
6188         GstCaps *dec_caps = NULL;
6189
6190         /* create decodebin */
6191         decodebin = gst_element_factory_make("decodebin", name);
6192
6193         if (!decodebin) {
6194                 LOGE("error : fail to create decodebin for %d decoder\n", track);
6195                 ret = FALSE;
6196                 goto ERROR;
6197         }
6198
6199         /* raw pad handling signal */
6200         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6201                                                                                 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
6202
6203         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6204         before looking for any elements that can handle that stream.*/
6205         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6206                                                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
6207
6208         /* This signal is emitted when a element is added to the bin.*/
6209         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6210                                                                                 G_CALLBACK(__mmplayer_gst_element_added), player);
6211
6212         if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6213                 LOGE("failed to add new decodebin\n");
6214                 ret = FALSE;
6215                 goto ERROR;
6216         }
6217
6218         dec_caps = gst_pad_query_caps(srcpad, NULL);
6219         if (dec_caps) {
6220                 //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
6221                 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
6222                 gst_caps_unref(dec_caps);
6223         }
6224
6225         player->pipeline->mainbin[elemId].id = elemId;
6226         player->pipeline->mainbin[elemId].gst = decodebin;
6227
6228         sinkpad = gst_element_get_static_pad(decodebin, "sink");
6229
6230         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6231                 LOGW("failed to link [%s:%s] to decoder\n", GST_DEBUG_PAD_NAME(srcpad));
6232                 gst_object_unref(GST_OBJECT(decodebin));
6233         }
6234
6235         if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin))
6236                 LOGE("failed to sync second level decodebin state with parent\n");
6237
6238         LOGD("Total num of %d tracks = %d \n", track, player->selector[track].total_track_num);
6239
6240 ERROR:
6241         if (sinkpad) {
6242                 gst_object_unref(GST_OBJECT(sinkpad));
6243                 sinkpad = NULL;
6244         }
6245         MMPLAYER_FLEAVE();
6246
6247         return ret;
6248 }
6249
6250 /**
6251  * This function is to create  audio or video pipeline for playing.
6252  *
6253  * @param       player          [in]    handle of player
6254  *
6255  * @return      This function returns zero on success.
6256  * @remark
6257  * @see
6258  */
6259 static int
6260 __mmplayer_gst_create_pipeline(mm_player_t* player)
6261 {
6262         GstBus  *bus = NULL;
6263         MMPlayerGstElement *mainbin = NULL;
6264         MMHandleType attrs = 0;
6265         GstElement* element = NULL;
6266         GstElement* elem_src_audio = NULL;
6267         GstElement* elem_src_subtitle = NULL;
6268         GstElement* es_video_queue = NULL;
6269         GstElement* es_audio_queue = NULL;
6270         GstElement* es_subtitle_queue = NULL;
6271         GList* element_bucket = NULL;
6272         gboolean need_state_holder = TRUE;
6273         gint i = 0;
6274 #ifdef SW_CODEC_ONLY
6275         int surface_type = 0;
6276 #endif
6277         MMPLAYER_FENTER();
6278
6279         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6280
6281         /* get profile attribute */
6282         attrs = MMPLAYER_GET_ATTRS(player);
6283         if (!attrs) {
6284                 LOGE("cannot get content attribute\n");
6285                 goto INIT_ERROR;
6286         }
6287
6288         /* create pipeline handles */
6289         if (player->pipeline) {
6290                 LOGW("pipeline should be released before create new one\n");
6291                 goto INIT_ERROR;
6292         }
6293
6294         player->video360_metadata.is_spherical = -1;
6295         player->is_openal_plugin_used = FALSE;
6296
6297         player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0(sizeof(MMPlayerGstPipelineInfo));
6298         if (player->pipeline == NULL)
6299                 goto INIT_ERROR;
6300
6301         memset(player->pipeline, 0, sizeof(MMPlayerGstPipelineInfo)); /* g_malloc0 did this job already */
6302
6303         /* create mainbin */
6304         mainbin = (MMPlayerGstElement*) g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
6305         if (mainbin == NULL)
6306                 goto INIT_ERROR;
6307
6308         memset(mainbin, 0, sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM); /* g_malloc0 did this job already */
6309
6310         /* create pipeline */
6311         mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
6312         mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
6313         if (!mainbin[MMPLAYER_M_PIPE].gst) {
6314                 LOGE("failed to create pipeline\n");
6315                 goto INIT_ERROR;
6316         }
6317         player->demux_pad_index = 0;
6318         player->subtitle_language_list = NULL;
6319
6320         player->is_subtitle_force_drop = FALSE;
6321         player->last_multiwin_status = FALSE;
6322
6323         _mmplayer_track_initialize(player);
6324         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6325
6326         /* create source element */
6327         switch (player->profile.uri_type) {
6328         /* rtsp streamming */
6329         case MM_PLAYER_URI_TYPE_URL_RTSP:
6330                 {
6331                         gchar *user_agent;
6332
6333                         element = gst_element_factory_make("rtspsrc", "rtsp source");
6334
6335                         if (!element) {
6336                                 LOGE("failed to create streaming source element\n");
6337                                 break;
6338                         }
6339
6340                         /* make it zero */
6341                         user_agent = NULL;
6342
6343                         /* get attribute */
6344                         mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6345
6346                         SECURE_LOGD("user_agent : %s\n", user_agent);
6347
6348                         /* setting property to streaming source */
6349                         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6350                         if (user_agent)
6351                                 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6352
6353                         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6354                                 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), player);
6355                         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6356                                 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), player);
6357                 }
6358                 break;
6359
6360         /* http streaming*/
6361         case MM_PLAYER_URI_TYPE_URL_HTTP:
6362                 {
6363                         gchar *user_agent, *cookies, **cookie_list;
6364                         gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6365                         user_agent = cookies = NULL;
6366                         cookie_list = NULL;
6367                         gint mode = MM_PLAYER_PD_MODE_NONE;
6368
6369                         mm_attrs_get_int_by_name(attrs, "pd_mode", &mode);
6370
6371                         player->pd_mode = mode;
6372
6373                         LOGD("http playback, PD mode : %d\n", player->pd_mode);
6374
6375                         if (!MMPLAYER_IS_HTTP_PD(player)) {
6376                                 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
6377                                 if (!element) {
6378                                         LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
6379                                         break;
6380                                 }
6381                                 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
6382
6383                                 /* get attribute */
6384                                 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
6385                                 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6386
6387                                 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
6388                                         LOGD("get timeout from ini\n");
6389                                         http_timeout = player->ini.http_timeout;
6390                                 }
6391
6392                                 /* get attribute */
6393                                 SECURE_LOGD("location : %s\n", player->profile.uri);
6394                                 SECURE_LOGD("cookies : %s\n", cookies);
6395                                 SECURE_LOGD("user_agent :  %s\n",  user_agent);
6396                                 LOGD("timeout : %d\n",  http_timeout);
6397
6398                                 /* setting property to streaming source */
6399                                 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6400                                 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6401                                 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
6402
6403                                 /* parsing cookies */
6404                                 if ((cookie_list = util_get_cookie_list((const char*)cookies))) {
6405                                         g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
6406                                         g_strfreev(cookie_list);
6407                                 }
6408                                 if (user_agent)
6409                                         g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6410
6411                                 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
6412                                         LOGW("it's dash. and it's still experimental feature.");
6413                         } else {
6414                                 // progressive download
6415                                 gchar* location = NULL;
6416
6417                                 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
6418                                         gchar *path = NULL;
6419
6420                                         mm_attrs_get_string_by_name(attrs, "pd_location", &path);
6421
6422                                         MMPLAYER_FREEIF(player->pd_file_save_path);
6423
6424                                         LOGD("PD Location : %s\n", path);
6425
6426                                         if (path) {
6427                                                 if (!util_get_storage_info(path, &player->storage_info[MMPLAYER_PATH_VOD])) {
6428                                                         LOGE("failed to get storage info");
6429                                                         break;
6430                                                 }
6431                                                 player->pd_file_save_path = g_strdup(path);
6432                                         } else {
6433                                                 LOGE("can't find pd location so, it should be set \n");
6434                                                 break;
6435                                         }
6436                                 }
6437
6438                                 element = gst_element_factory_make("pdpushsrc", "PD pushsrc");
6439                                 if (!element) {
6440                                         LOGE("failed to create PD push source element[%s].\n", "pdpushsrc");
6441                                         break;
6442                                 }
6443
6444                                 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
6445                                         g_object_set(G_OBJECT(element), "location", player->pd_file_save_path, NULL);
6446                                 else
6447                                         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6448                                 g_object_get(element, "location", &location, NULL);
6449                                 LOGD("PD_LOCATION [%s].\n", location);
6450                                 if (location)
6451                                         g_free(location);
6452                         }
6453                 }
6454                 break;
6455
6456         /* file source */
6457         case MM_PLAYER_URI_TYPE_FILE:
6458                 {
6459                         LOGD("using filesrc for 'file://' handler.\n");
6460                         if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
6461                                 LOGE("failed to get storage info");
6462                                 break;
6463                         }
6464
6465                         element = gst_element_factory_make("filesrc", "source");
6466                         if (!element) {
6467                                 LOGE("failed to create filesrc\n");
6468                                 break;
6469                         }
6470
6471                         g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL);     /* uri+7 -> remove "file:// */
6472                 }
6473                 break;
6474
6475         case MM_PLAYER_URI_TYPE_SS:
6476                 {
6477                         gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6478                         element = gst_element_factory_make("souphttpsrc", "http streaming source");
6479                         if (!element) {
6480                                 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
6481                                 break;
6482                         }
6483
6484                         if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
6485                                 LOGD("get timeout from ini\n");
6486                                 http_timeout = player->ini.http_timeout;
6487                         }
6488
6489                         /* setting property to streaming source */
6490                         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6491                         g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6492                 }
6493                 break;
6494         case MM_PLAYER_URI_TYPE_MS_BUFF:
6495                 {
6496                         LOGD("MS buff src is selected\n");
6497
6498                         if (player->v_stream_caps) {
6499                                 element = gst_element_factory_make("appsrc", "video_appsrc");
6500                                 if (!element) {
6501                                         LOGF("failed to create video app source element[appsrc].\n");
6502                                         break;
6503                                 }
6504
6505                                 if (player->a_stream_caps) {
6506                                         elem_src_audio = gst_element_factory_make("appsrc", "audio_appsrc");
6507                                         if (!elem_src_audio) {
6508                                                 LOGF("failed to create audio app source element[appsrc].\n");
6509                                                 break;
6510                                         }
6511                                 }
6512                         } else if (player->a_stream_caps) {
6513                                 /* no video, only audio pipeline*/
6514                                 element = gst_element_factory_make("appsrc", "audio_appsrc");
6515                                 if (!element) {
6516                                         LOGF("failed to create audio app source element[appsrc].\n");
6517                                         break;
6518                                 }
6519                         }
6520
6521                         if (player->s_stream_caps) {
6522                                 elem_src_subtitle = gst_element_factory_make("appsrc", "subtitle_appsrc");
6523                                 if (!elem_src_subtitle) {
6524                                         LOGF("failed to create subtitle app source element[appsrc].\n");
6525                                         break;
6526                                 }
6527                         }
6528
6529                         LOGD("setting app sources properties.\n");
6530                         LOGD("location : %s\n", player->profile.uri);
6531
6532                         if (player->v_stream_caps && element) {
6533                                 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6534                                                                                             "blocksize", (guint)1048576,        /* size of many video frames are larger than default blocksize as 4096 */
6535                                                                                                 "caps", player->v_stream_caps, NULL);
6536
6537                                 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6538                                         g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6539                                 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6540                                         g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6541
6542                                 /*Fix Seek External Demuxer:  set audio and video appsrc as seekable */
6543                                 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6544                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6545                                                                                                                 G_CALLBACK(__gst_seek_video_data), player);
6546
6547                                 if (player->a_stream_caps && elem_src_audio) {
6548                                         g_object_set(G_OBJECT(elem_src_audio), "format", GST_FORMAT_TIME,
6549                                                                                                                         "caps", player->a_stream_caps, NULL);
6550
6551                                         if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6552                                                 g_object_set(G_OBJECT(elem_src_audio), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6553                                         if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6554                                                 g_object_set(G_OBJECT(elem_src_audio), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6555
6556                                         /*Fix Seek External Demuxer:  set audio and video appsrc as seekable */
6557                                         gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_audio), GST_APP_STREAM_TYPE_SEEKABLE);
6558                                         MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6559                                                                                                                 G_CALLBACK(__gst_seek_audio_data), player);
6560                                 }
6561                         } else if (player->a_stream_caps && element) {
6562                                 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6563                                                                                                 "caps", player->a_stream_caps, NULL);
6564
6565                                 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6566                                         g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6567                                 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6568                                         g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6569
6570                                 /*Fix Seek External Demuxer:  set audio and video appsrc as seekable */
6571                                 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6572                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6573                                                                                                                         G_CALLBACK(__gst_seek_audio_data), player);
6574                         }
6575
6576                         if (player->s_stream_caps && elem_src_subtitle) {
6577                                 g_object_set(G_OBJECT(elem_src_subtitle), "format", GST_FORMAT_TIME,
6578                                                                                                                  "caps", player->s_stream_caps, NULL);
6579
6580                                 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6581                                         g_object_set(G_OBJECT(elem_src_subtitle), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6582                                 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6583                                         g_object_set(G_OBJECT(elem_src_subtitle), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6584
6585                                 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_subtitle), GST_APP_STREAM_TYPE_SEEKABLE);
6586
6587                                 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6588                                                                                                                                 G_CALLBACK(__gst_seek_subtitle_data), player);
6589                         }
6590
6591                         if (player->v_stream_caps && element) {
6592                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6593                                                                                                                 G_CALLBACK(__gst_appsrc_feed_video_data), player);
6594                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6595                                                                                                                 G_CALLBACK(__gst_appsrc_enough_video_data), player);
6596
6597                                 if (player->a_stream_caps && elem_src_audio) {
6598                                         MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6599                                                                                                                 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6600                                         MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6601                                                                                                                 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6602                                 }
6603                         } else if (player->a_stream_caps && element) {
6604                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6605                                                                                                                 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6606                                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6607                                                                                                                 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6608                         }
6609
6610                         if (player->s_stream_caps && elem_src_subtitle)
6611                                 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6612                                                                                                                 G_CALLBACK(__gst_appsrc_feed_subtitle_data), player);
6613
6614                         need_state_holder = FALSE;
6615
6616                         mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
6617                         if (mmf_attrs_commit(attrs)) /* return -1 if error */
6618                                 LOGE("failed to commit\n");
6619                 }
6620                 break;
6621         /* appsrc */
6622         case MM_PLAYER_URI_TYPE_MEM:
6623                 {
6624                         guint64 stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
6625
6626                         LOGD("mem src is selected\n");
6627
6628                         element = gst_element_factory_make("appsrc", "mem-source");
6629                         if (!element) {
6630                                 LOGE("failed to create appsrc element\n");
6631                                 break;
6632                         }
6633
6634                         g_object_set(element, "stream-type", stream_type, NULL);
6635                         g_object_set(element, "size", player->profile.input_mem.len, NULL);
6636                         g_object_set(element, "blocksize", (guint64)20480, NULL);
6637
6638                         MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6639                                 G_CALLBACK(__gst_appsrc_seek_data_mem), &player->profile.input_mem);
6640                         MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6641                                 G_CALLBACK(__gst_appsrc_feed_data_mem), &player->profile.input_mem);
6642                 }
6643                 break;
6644         case MM_PLAYER_URI_TYPE_URL:
6645                 break;
6646
6647         case MM_PLAYER_URI_TYPE_TEMP:
6648                 break;
6649
6650         case MM_PLAYER_URI_TYPE_NONE:
6651         default:
6652                 break;
6653         }
6654
6655         /* check source element is OK */
6656         if (!element) {
6657                 LOGE("no source element was created.\n");
6658                 goto INIT_ERROR;
6659         }
6660
6661         /* take source element */
6662         mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6663         mainbin[MMPLAYER_M_SRC].gst = element;
6664         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
6665
6666         if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
6667                 player->streamer = __mm_player_streaming_create();
6668                 __mm_player_streaming_initialize(player->streamer);
6669         }
6670
6671         if (MMPLAYER_IS_HTTP_PD(player)) {
6672                 gint pre_buffering_time = player->streamer->buffering_req.prebuffer_time;
6673
6674                 LOGD("Picked queue2 element(pre buffer : %d ms)....\n", pre_buffering_time);
6675                 element = gst_element_factory_make("queue2", "queue2");
6676                 if (!element) {
6677                         LOGE("failed to create http streaming buffer element\n");
6678                         goto INIT_ERROR;
6679                 }
6680
6681                 /* take it */
6682                 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6683                 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element;
6684                 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]);
6685
6686                 pre_buffering_time = (pre_buffering_time > 0) ? (pre_buffering_time) : (player->ini.http_buffering_time);
6687
6688                 __mm_player_streaming_set_queue2(player->streamer,
6689                                 element,
6690                                 TRUE,
6691                                 player->ini.http_max_size_bytes + 52428800, // http_max_size_types + 5Mb
6692                                 pre_buffering_time,
6693                                 1.0,
6694                                 player->ini.http_buffering_limit,
6695                                 MUXED_BUFFER_TYPE_MEM_QUEUE,
6696                                 NULL,
6697                                 0);
6698         }
6699         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6700                 if (player->v_stream_caps) {
6701                         es_video_queue = gst_element_factory_make("queue2", "video_queue");
6702                         if (!es_video_queue) {
6703                                 LOGE("create es_video_queue for es player failed\n");
6704                                 goto INIT_ERROR;
6705                         }
6706                         g_object_set(G_OBJECT(es_video_queue), "max-size-buffers", 2, NULL);
6707                         mainbin[MMPLAYER_M_V_BUFFER].id = MMPLAYER_M_V_BUFFER;
6708                         mainbin[MMPLAYER_M_V_BUFFER].gst = es_video_queue;
6709                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_V_BUFFER]);
6710
6711                         /* Adding audio appsrc to bucket */
6712                         if (player->a_stream_caps && elem_src_audio) {
6713                                 mainbin[MMPLAYER_M_2ND_SRC].id = MMPLAYER_M_2ND_SRC;
6714                                 mainbin[MMPLAYER_M_2ND_SRC].gst = elem_src_audio;
6715                                 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_2ND_SRC]);
6716
6717                                 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6718                                 if (!es_audio_queue) {
6719                                         LOGE("create es_audio_queue for es player failed\n");
6720                                         goto INIT_ERROR;
6721                                 }
6722                                 g_object_set(G_OBJECT(es_audio_queue), "max-size-buffers", 2, NULL);
6723
6724                                 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6725                                 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6726                                 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6727                         }
6728                 } else if (player->a_stream_caps) {
6729                         /* Only audio stream, no video */
6730                         es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6731                         if (!es_audio_queue) {
6732                                 LOGE("create es_audio_queue for es player failed\n");
6733                                 goto INIT_ERROR;
6734                         }
6735                         mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6736                         mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6737                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6738                 }
6739
6740                 if (player->s_stream_caps && elem_src_subtitle) {
6741                         mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
6742                         mainbin[MMPLAYER_M_SUBSRC].gst = elem_src_subtitle;
6743                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SUBSRC]);
6744
6745                         es_subtitle_queue = gst_element_factory_make("queue2", "subtitle_queue");
6746                         if (!es_subtitle_queue) {
6747                                 LOGE("create es_subtitle_queue for es player failed\n");
6748                                 goto INIT_ERROR;
6749                         }
6750                         mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_V_BUFFER;
6751                         mainbin[MMPLAYER_M_S_BUFFER].gst = es_subtitle_queue;
6752                         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_S_BUFFER]);
6753                 }
6754         }
6755
6756         /* create autoplugging element if src element is not a rtsp src */
6757         if ((player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_RTSP) &&
6758                 (player->profile.uri_type != MM_PLAYER_URI_TYPE_MS_BUFF)) {
6759                 element = NULL;
6760                 enum MainElementID elemId = MMPLAYER_M_NUM;
6761
6762                 if (((MMPLAYER_IS_HTTP_PD(player)) ||
6763                         (!MMPLAYER_IS_HTTP_STREAMING(player)))) {
6764                         elemId = MMPLAYER_M_AUTOPLUG;
6765                         element = __mmplayer_create_decodebin(player);
6766                         if (element) {
6767                                 /* default size of mq in decodebin is 2M
6768                                  * but it can cause blocking issue during seeking depends on content. */
6769                                 g_object_set(G_OBJECT(element), "max-size-bytes", (5*1024*1024), NULL);
6770                         }
6771                         need_state_holder = FALSE;
6772                 } else {
6773                         elemId = MMPLAYER_M_TYPEFIND;
6774                         element = gst_element_factory_make("typefind", "typefinder");
6775                         MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
6776                                 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6777                 }
6778
6779
6780                 /* check autoplug element is OK */
6781                 if (!element) {
6782                         LOGE("can not create element(%d)\n", elemId);
6783                         goto INIT_ERROR;
6784                 }
6785
6786                 mainbin[elemId].id = elemId;
6787                 mainbin[elemId].gst = element;
6788
6789                 element_bucket = g_list_append(element_bucket, &mainbin[elemId]);
6790         }
6791
6792         /* add elements to pipeline */
6793         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
6794                 LOGE("Failed to add elements to pipeline\n");
6795                 goto INIT_ERROR;
6796         }
6797
6798
6799         /* linking elements in the bucket by added order. */
6800         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
6801                 LOGE("Failed to link some elements\n");
6802                 goto INIT_ERROR;
6803         }
6804
6805
6806         /* create fakesink element for keeping the pipeline state PAUSED. if needed */
6807         if (need_state_holder) {
6808                 /* create */
6809                 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
6810                 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
6811
6812                 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
6813                         LOGE("fakesink element could not be created\n");
6814                         goto INIT_ERROR;
6815                 }
6816                 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
6817
6818                 /* take ownership of fakesink. we are reusing it */
6819                 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
6820
6821                 /* add */
6822                 if (FALSE == gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst),
6823                         mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
6824                         LOGE("failed to add fakesink to bin\n");
6825                         goto INIT_ERROR;
6826                 }
6827         }
6828
6829         /* now we have completed mainbin. take it */
6830         player->pipeline->mainbin = mainbin;
6831
6832         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6833                 GstPad *srcpad = NULL;
6834
6835                 if (mainbin[MMPLAYER_M_V_BUFFER].gst) {
6836                         srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_V_BUFFER].gst, "src");
6837                         if (srcpad) {
6838                                 __mmplayer_gst_create_decoder(player,
6839                                                                                                 MM_PLAYER_TRACK_TYPE_VIDEO,
6840                                                                                                 srcpad,
6841                                                                                                 MMPLAYER_M_AUTOPLUG_V_DEC,
6842                                                                                                 "video_decodebin");
6843
6844                                 gst_object_unref(GST_OBJECT(srcpad));
6845                                 srcpad = NULL;
6846                         }
6847                 }
6848
6849                 if ((player->a_stream_caps) && (mainbin[MMPLAYER_M_A_BUFFER].gst)) {
6850                         srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_A_BUFFER].gst, "src");
6851                         if (srcpad) {
6852                                 __mmplayer_gst_create_decoder(player,
6853                                                                                                 MM_PLAYER_TRACK_TYPE_AUDIO,
6854                                                                                                 srcpad,
6855                                                                                                 MMPLAYER_M_AUTOPLUG_A_DEC,
6856                                                                                                 "audio_decodebin");
6857
6858                                 gst_object_unref(GST_OBJECT(srcpad));
6859                                 srcpad = NULL;
6860                         } // else error
6861                 } //  else error
6862
6863                 if (mainbin[MMPLAYER_M_S_BUFFER].gst)
6864                         __mmplayer_try_to_plug_decodebin(player, gst_element_get_static_pad(mainbin[MMPLAYER_M_S_BUFFER].gst, "src"), player->s_stream_caps);
6865         }
6866
6867         /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
6868         if (__mmplayer_check_subtitle(player)) {
6869                 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player))
6870                         LOGE("fail to create text pipeline");
6871         }
6872
6873         /* connect bus callback */
6874         bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6875         if (!bus) {
6876                 LOGE("cannot get bus from pipeline.\n");
6877                 goto INIT_ERROR;
6878         }
6879
6880         player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_msg_push, player);
6881
6882         player->context.thread_default = g_main_context_get_thread_default();
6883
6884         if (player->context.thread_default == NULL) {
6885                 player->context.thread_default = g_main_context_default();
6886                 LOGD("thread-default context is the global default context");
6887         }
6888         LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
6889
6890         /* set sync handler to get tag synchronously */
6891         gst_bus_set_sync_handler(bus, __mmplayer_bus_sync_callback, player, NULL);
6892
6893         /* finished */
6894         gst_object_unref(GST_OBJECT(bus));
6895         g_list_free(element_bucket);
6896
6897         /* create gst bus_msb_cb thread */
6898         g_mutex_init(&player->bus_msg_thread_mutex);
6899         g_cond_init(&player->bus_msg_thread_cond);
6900         player->bus_msg_thread_exit = FALSE;
6901         player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
6902         player->bus_msg_thread =
6903                 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
6904         if (!player->bus_msg_thread) {
6905                 LOGE("failed to create gst BUS msg thread");
6906                 g_mutex_clear(&player->bus_msg_thread_mutex);
6907                 g_cond_clear(&player->bus_msg_thread_cond);
6908                 goto INIT_ERROR;
6909         }
6910
6911         MMPLAYER_FLEAVE();
6912
6913         return MM_ERROR_NONE;
6914
6915 INIT_ERROR:
6916         __mmplayer_gst_destroy_pipeline(player);
6917         g_list_free(element_bucket);
6918
6919         if (mainbin) {
6920                 /* release element which are not added to bin */
6921                 for (i = 1; i < MMPLAYER_M_NUM; i++) {
6922                         /* NOTE : skip pipeline */
6923                         if (mainbin[i].gst) {
6924                                 GstObject* parent = NULL;
6925                                 parent = gst_element_get_parent(mainbin[i].gst);
6926
6927                                 if (!parent) {
6928                                         gst_object_unref(GST_OBJECT(mainbin[i].gst));
6929                                         mainbin[i].gst = NULL;
6930                                 } else
6931                                         gst_object_unref(GST_OBJECT(parent));
6932                         }
6933                 }
6934
6935                 /* release pipeline with it's childs */
6936                 if (mainbin[MMPLAYER_M_PIPE].gst)
6937                         gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
6938
6939                 MMPLAYER_FREEIF(mainbin);
6940         }
6941
6942         MMPLAYER_FREEIF(player->pipeline);
6943         return MM_ERROR_PLAYER_INTERNAL;
6944 }
6945
6946 static void
6947 __mmplayer_reset_gapless_state(mm_player_t* player)
6948 {
6949         MMPLAYER_FENTER();
6950         MMPLAYER_RETURN_IF_FAIL(player
6951                 && player->pipeline
6952                 && player->pipeline->audiobin
6953                 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
6954
6955         memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
6956
6957         MMPLAYER_FLEAVE();
6958         return;
6959 }
6960
6961 static int
6962 __mmplayer_gst_destroy_pipeline(mm_player_t* player)
6963 {
6964         gint timeout = 0;
6965         int ret = MM_ERROR_NONE;
6966
6967         MMPLAYER_FENTER();
6968
6969         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
6970
6971         /* cleanup stuffs */
6972         MMPLAYER_FREEIF(player->type);
6973         player->have_dynamic_pad = FALSE;
6974         player->no_more_pad = FALSE;
6975         player->num_dynamic_pad = 0;
6976         player->demux_pad_index = 0;
6977         player->use_deinterleave = FALSE;
6978         player->max_audio_channels = 0;
6979         player->video_share_api_delta = 0;
6980         player->video_share_clock_delta = 0;
6981         player->video_hub_download_mode = 0;
6982
6983         MMPLAYER_SUBTITLE_INFO_LOCK(player);
6984         player->subtitle_language_list = NULL;
6985         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
6986
6987         __mmplayer_reset_gapless_state(player);
6988
6989         if (player->streamer) {
6990                 __mm_player_streaming_deinitialize(player->streamer);
6991                 __mm_player_streaming_destroy(player->streamer);
6992                 player->streamer = NULL;
6993         }
6994
6995         /* cleanup unlinked mime type */
6996         MMPLAYER_FREEIF(player->unlinked_audio_mime);
6997         MMPLAYER_FREEIF(player->unlinked_video_mime);
6998         MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
6999
7000         /* cleanup running stuffs */
7001         __mmplayer_cancel_eos_timer(player);
7002
7003         /* cleanup gst stuffs */
7004         if (player->pipeline) {
7005                 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
7006                 GstTagList* tag_list = player->pipeline->tag_list;
7007
7008                 /* first we need to disconnect all signal hander */
7009                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
7010
7011                 if (player->bus_watcher)
7012                         __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
7013                 player->bus_watcher = 0;
7014
7015                 if (mainbin) {
7016                         MMPlayerGstElement* audiobin = player->pipeline->audiobin;
7017                         MMPlayerGstElement* videobin = player->pipeline->videobin;
7018                         MMPlayerGstElement* textbin = player->pipeline->textbin;
7019                         GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
7020                         gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
7021                         gst_object_unref(bus);
7022
7023                         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7024                         ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
7025                         if (ret != MM_ERROR_NONE) {
7026                                 LOGE("fail to change state to NULL\n");
7027                                 return MM_ERROR_PLAYER_INTERNAL;
7028                         }
7029
7030                         LOGW("succeeded in chaning state to NULL\n");
7031
7032                         gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
7033
7034                         /* free fakesink */
7035                         if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
7036                                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
7037
7038                         /* free avsysaudiosink
7039                            avsysaudiosink should be unref when destory pipeline just after start play with BT.
7040                            Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
7041                         */
7042                         MMPLAYER_FREEIF(audiobin);
7043                         MMPLAYER_FREEIF(videobin);
7044                         MMPLAYER_FREEIF(textbin);
7045                         MMPLAYER_FREEIF(mainbin);
7046                 }
7047
7048                 if (tag_list)
7049                         gst_tag_list_free(tag_list);
7050
7051                 MMPLAYER_FREEIF(player->pipeline);
7052         }
7053         MMPLAYER_FREEIF(player->album_art);
7054
7055         if (player->v_stream_caps) {
7056                 gst_caps_unref(player->v_stream_caps);
7057                 player->v_stream_caps = NULL;
7058         }
7059         if (player->a_stream_caps) {
7060                 gst_caps_unref(player->a_stream_caps);
7061                 player->a_stream_caps = NULL;
7062         }
7063
7064         if (player->s_stream_caps) {
7065                 gst_caps_unref(player->s_stream_caps);
7066                 player->s_stream_caps = NULL;
7067         }
7068         _mmplayer_track_destroy(player);
7069
7070         if (player->sink_elements)
7071                 g_list_free(player->sink_elements);
7072         player->sink_elements = NULL;
7073
7074         if (player->bufmgr) {
7075                 tbm_bufmgr_deinit(player->bufmgr);
7076                 player->bufmgr = NULL;
7077         }
7078
7079         LOGW("finished destroy pipeline\n");
7080
7081         MMPLAYER_FLEAVE();
7082
7083         return ret;
7084 }
7085
7086 static int __gst_realize(mm_player_t* player)
7087 {
7088         gint timeout = 0;
7089         int ret = MM_ERROR_NONE;
7090
7091         MMPLAYER_FENTER();
7092
7093         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7094
7095         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7096
7097         ret = __mmplayer_gst_create_pipeline(player);
7098         if (ret) {
7099                 LOGE("failed to create pipeline\n");
7100                 return ret;
7101         }
7102
7103         /* set pipeline state to READY */
7104         /* NOTE : state change to READY must be performed sync. */
7105         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7106         ret = __mmplayer_gst_set_state(player,
7107                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
7108
7109         if (ret != MM_ERROR_NONE) {
7110                 /* return error if failed to set state */
7111                 LOGE("failed to set READY state");
7112                 return ret;
7113         }
7114
7115         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7116
7117         /* create dot before error-return. for debugging */
7118         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
7119
7120         MMPLAYER_FLEAVE();
7121
7122         return ret;
7123 }
7124
7125 static int __gst_unrealize(mm_player_t* player)
7126 {
7127         int ret = MM_ERROR_NONE;
7128
7129         MMPLAYER_FENTER();
7130
7131         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7132
7133         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
7134         MMPLAYER_PRINT_STATE(player);
7135
7136         /* release miscellaneous information */
7137         __mmplayer_release_misc(player);
7138
7139         /* destroy pipeline */
7140         ret = __mmplayer_gst_destroy_pipeline(player);
7141         if (ret != MM_ERROR_NONE) {
7142                 LOGE("failed to destory pipeline\n");
7143                 return ret;
7144         }
7145
7146         /* release miscellaneous information.
7147            these info needs to be released after pipeline is destroyed. */
7148         __mmplayer_release_misc_post(player);
7149
7150         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
7151
7152         MMPLAYER_FLEAVE();
7153
7154         return ret;
7155 }
7156
7157 static int __gst_pending_seek(mm_player_t* player)
7158 {
7159         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7160         int ret = MM_ERROR_NONE;
7161
7162         MMPLAYER_FENTER();
7163
7164         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7165
7166         if (!player->pending_seek.is_pending) {
7167                 LOGD("pending seek is not reserved. nothing to do.\n");
7168                 return ret;
7169         }
7170
7171         /* check player state if player could pending seek or not. */
7172         current_state = MMPLAYER_CURRENT_STATE(player);
7173
7174         if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
7175                 LOGW("try to pending seek in %s state, try next time. \n",
7176                         MMPLAYER_STATE_GET_NAME(current_state));
7177                 return ret;
7178         }
7179
7180         LOGD("trying to play from(%lu) pending position\n", player->pending_seek.pos);
7181
7182         ret = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, FALSE);
7183
7184         if (MM_ERROR_NONE != ret)
7185                 LOGE("failed to seek pending postion. just keep staying current position.\n");
7186
7187         player->pending_seek.is_pending = FALSE;
7188
7189         MMPLAYER_FLEAVE();
7190
7191         return ret;
7192 }
7193
7194 static int __gst_start(mm_player_t* player)
7195 {
7196         gboolean sound_extraction = 0;
7197         int ret = MM_ERROR_NONE;
7198         gboolean async = FALSE;
7199
7200         MMPLAYER_FENTER();
7201
7202         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7203
7204         /* get sound_extraction property */
7205         mm_attrs_get_int_by_name(player->attrs, "pcm_extraction", &sound_extraction);
7206
7207         /* NOTE : if SetPosition was called before Start. do it now */
7208         /* streaming doesn't support it. so it should be always sync */
7209         /* !!create one more api to check if there is pending seek rather than checking variables */
7210         if ((player->pending_seek.is_pending || sound_extraction) && !MMPLAYER_IS_STREAMING(player)) {
7211                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
7212                 ret = __gst_pause(player, FALSE);
7213                 if (ret != MM_ERROR_NONE) {
7214                         LOGE("failed to set state to PAUSED for pending seek\n");
7215                         return ret;
7216                 }
7217
7218                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
7219
7220                 if (sound_extraction) {
7221                         LOGD("setting pcm extraction\n");
7222
7223                         ret = __mmplayer_set_pcm_extraction(player);
7224                         if (MM_ERROR_NONE != ret) {
7225                                 LOGW("failed to set pcm extraction\n");
7226                                 return ret;
7227                         }
7228                 } else {
7229                         if (MM_ERROR_NONE != __gst_pending_seek(player))
7230                                 LOGW("failed to seek pending postion. starting from the begin of content.\n");
7231                 }
7232         }
7233
7234         LOGD("current state before doing transition");
7235         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7236         MMPLAYER_PRINT_STATE(player);
7237
7238         /* set pipeline state to PLAYING  */
7239         if (player->es_player_push_mode)
7240                 async = TRUE;
7241         /* set pipeline state to PLAYING  */
7242         ret = __mmplayer_gst_set_state(player,
7243                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7244
7245         if (ret == MM_ERROR_NONE) {
7246                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7247         } else {
7248                 LOGE("failed to set state to PLAYING");
7249                 return ret;
7250         }
7251
7252         /* generating debug info before returning error */
7253         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
7254
7255         MMPLAYER_FLEAVE();
7256
7257         return ret;
7258 }
7259
7260 static int __gst_stop(mm_player_t* player)
7261 {
7262         GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
7263         MMHandleType attrs = 0;
7264         gboolean rewind = FALSE;
7265         gint timeout = 0;
7266         int ret = MM_ERROR_NONE;
7267         gboolean async = FALSE;
7268
7269         MMPLAYER_FENTER();
7270
7271         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7272         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7273
7274         LOGD("current state before doing transition");
7275         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7276         MMPLAYER_PRINT_STATE(player);
7277
7278         attrs = MMPLAYER_GET_ATTRS(player);
7279         if (!attrs) {
7280                 LOGE("cannot get content attribute\n");
7281                 return MM_ERROR_PLAYER_INTERNAL;
7282         }
7283
7284         /* Just set state to PAUESED and the rewind. it's usual player behavior. */
7285         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7286
7287         if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
7288                 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
7289                 rewind = TRUE;
7290
7291         if (player->es_player_push_mode)
7292                 async = TRUE;
7293         /* set gst state */
7294         ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, timeout);
7295
7296         /* return if set_state has failed */
7297         if (ret != MM_ERROR_NONE) {
7298                 LOGE("failed to set state.\n");
7299                 return ret;
7300         }
7301
7302         /* rewind */
7303         if (rewind) {
7304                 if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7305                                 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
7306                                 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
7307                         LOGW("failed to rewind\n");
7308                         ret = MM_ERROR_PLAYER_SEEK;
7309                 }
7310         }
7311
7312         /* initialize */
7313         player->sent_bos = FALSE;
7314
7315         if (player->es_player_push_mode) //for cloudgame
7316                 timeout = 0;
7317
7318         /* wait for seek to complete */
7319         change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
7320         if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
7321                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7322         } else {
7323                 LOGE("fail to stop player.\n");
7324                 ret = MM_ERROR_PLAYER_INTERNAL;
7325                 __mmplayer_dump_pipeline_state(player);
7326         }
7327
7328         /* generate dot file if enabled */
7329         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
7330
7331         MMPLAYER_FLEAVE();
7332
7333         return ret;
7334 }
7335
7336 int __gst_pause(mm_player_t* player, gboolean async)
7337 {
7338         int ret = MM_ERROR_NONE;
7339
7340         MMPLAYER_FENTER();
7341
7342         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7343         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7344
7345         LOGD("current state before doing transition");
7346         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
7347         MMPLAYER_PRINT_STATE(player);
7348
7349         /* set pipeline status to PAUSED */
7350         ret = __mmplayer_gst_set_state(player,
7351                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7352
7353         if (FALSE == async) {
7354                 if (ret != MM_ERROR_NONE) {
7355                         GstMessage *msg = NULL;
7356                         GTimer *timer = NULL;
7357                         gdouble MAX_TIMEOUT_SEC = 3;
7358
7359                         LOGE("failed to set state to PAUSED");
7360
7361                         if (player->msg_posted) {
7362                                 LOGE("error msg is already posted.");
7363                                 return ret;
7364                         }
7365
7366                         timer = g_timer_new();
7367                         g_timer_start(timer);
7368
7369                         GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7370
7371                         do {
7372                                 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
7373                                 if (msg) {
7374                                         if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
7375                                                 GError *error = NULL;
7376
7377                                                 /* parse error code */
7378                                                 gst_message_parse_error(msg, &error, NULL);
7379
7380                                                 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
7381                                                         /* Note : the streaming error from the streaming source is handled
7382                                                          *   using __mmplayer_handle_streaming_error.
7383                                                          */
7384                                                         __mmplayer_handle_streaming_error(player, msg);
7385
7386                                                 } else if (error) {
7387                                                         LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
7388
7389                                                         if (error->domain == GST_STREAM_ERROR)
7390                                                                 ret = __gst_handle_stream_error(player, error, msg);
7391                                                         else if (error->domain == GST_RESOURCE_ERROR)
7392                                                                 ret = __gst_handle_resource_error(player, error->code, NULL);
7393                                                         else if (error->domain == GST_LIBRARY_ERROR)
7394                                                                 ret = __gst_handle_library_error(player, error->code);
7395                                                         else if (error->domain == GST_CORE_ERROR)
7396                                                                 ret = __gst_handle_core_error(player, error->code);
7397
7398                                                         g_error_free(error);
7399                                                 }
7400                                                 player->msg_posted = TRUE;
7401                                         }
7402                                         gst_message_unref(msg);
7403                                 }
7404                         } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
7405                         /* clean */
7406                         gst_object_unref(bus);
7407                         g_timer_stop(timer);
7408                         g_timer_destroy(timer);
7409
7410                         return ret;
7411
7412                 } else if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_stream_cb) &&
7413                                    (!player->pipeline->videobin) && (!player->pipeline->audiobin)) {
7414
7415                         return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
7416
7417                 } else if (ret == MM_ERROR_NONE) {
7418
7419                         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
7420                 }
7421         }
7422
7423         /* generate dot file before returning error */
7424         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
7425
7426         MMPLAYER_FLEAVE();
7427
7428         return ret;
7429 }
7430
7431 int __gst_resume(mm_player_t* player, gboolean async)
7432 {
7433         int ret = MM_ERROR_NONE;
7434         gint timeout = 0;
7435
7436         MMPLAYER_FENTER();
7437
7438         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
7439                 MM_ERROR_PLAYER_NOT_INITIALIZED);
7440
7441         LOGD("current state before doing transition");
7442         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7443         MMPLAYER_PRINT_STATE(player);
7444
7445         /* generate dot file before returning error */
7446         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7447
7448         if (async)
7449                 LOGD("do async state transition to PLAYING.\n");
7450
7451         /* set pipeline state to PLAYING */
7452         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7453
7454         ret = __mmplayer_gst_set_state(player,
7455                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
7456         if (ret != MM_ERROR_NONE) {
7457                 LOGE("failed to set state to PLAYING\n");
7458                 return ret;
7459         } else {
7460                 if (async == FALSE) {
7461                         // MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7462                         LOGD("update state machine to %d\n", MM_PLAYER_STATE_PLAYING);
7463                         ret = __mmplayer_set_state(player, MM_PLAYER_STATE_PLAYING);
7464                 }
7465         }
7466
7467         /* generate dot file before returning error */
7468         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7469
7470         MMPLAYER_FLEAVE();
7471
7472         return ret;
7473 }
7474
7475 static int
7476 __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called)
7477 {
7478         unsigned long dur_msec = 0;
7479         gint64 dur_nsec = 0;
7480         gint64 pos_nsec = 0;
7481         gboolean ret = TRUE;
7482         gboolean accurated = FALSE;
7483         GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
7484
7485         MMPLAYER_FENTER();
7486         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7487         MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
7488
7489         if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
7490                 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
7491                 goto PENDING;
7492
7493         if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7494                 /* check duration */
7495                 /* NOTE : duration cannot be zero except live streaming.
7496                  *              Since some element could have some timing problemn with quering duration, try again.
7497                  */
7498                 if (!player->duration) {
7499                         if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
7500                                 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
7501                                  * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
7502                                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
7503                                         player->pending_seek.is_pending = TRUE;
7504                                         player->pending_seek.format = format;
7505                                         player->pending_seek.pos = position;
7506                                         player->doing_seek = FALSE;
7507                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7508                                         return MM_ERROR_NONE;
7509                                 } else {
7510                                         goto SEEK_ERROR;
7511                                 }
7512                         }
7513                         player->duration = dur_nsec;
7514                 }
7515
7516                 if (player->duration) {
7517                         dur_msec = GST_TIME_AS_MSECONDS(player->duration);
7518                 } else {
7519                         LOGE("could not get the duration. fail to seek.\n");
7520                         goto SEEK_ERROR;
7521                 }
7522         }
7523         LOGD("playback rate: %f\n", player->playback_rate);
7524
7525         mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
7526         if (accurated)
7527                 seek_flags |= GST_SEEK_FLAG_ACCURATE;
7528         else
7529                 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
7530
7531         /* do seek */
7532         switch (format) {
7533         case MM_PLAYER_POS_FORMAT_TIME:
7534         {
7535                 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7536                         GstQuery *query = NULL;
7537                         gboolean seekable = FALSE;
7538
7539                         /* check position is valid or not */
7540                         if (position > dur_msec)
7541                                 goto INVALID_ARGS;
7542
7543                         query = gst_query_new_seeking(GST_FORMAT_TIME);
7544                         if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
7545                                 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
7546                                 gst_query_unref(query);
7547
7548                                 if (!seekable) {
7549                                         LOGW("non-seekable content");
7550                                         player->doing_seek = FALSE;
7551                                         return MM_ERROR_PLAYER_NO_OP;
7552                                 }
7553                         } else {
7554                                 LOGW("failed to get seeking query");
7555                                 gst_query_unref(query); /* keep seeking operation */
7556                         }
7557
7558                         LOGD("seeking to(%lu) msec, duration is %d msec\n", position, dur_msec);
7559
7560                         /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
7561                            But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
7562                            This causes problem is position calculation during normal pause resume scenarios also.
7563                            Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
7564                         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7565                                 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
7566                                 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
7567                                         LOGW("getting current position failed in seek\n");
7568
7569                                 player->last_position = pos_nsec;
7570                                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
7571                         }
7572
7573                         if (player->doing_seek) {
7574                                 LOGD("not completed seek");
7575                                 return MM_ERROR_PLAYER_DOING_SEEK;
7576                         }
7577                 }
7578
7579                 if (!internal_called)
7580                         player->doing_seek = TRUE;
7581
7582                 pos_nsec = position * G_GINT64_CONSTANT(1000000);
7583
7584                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) && (!player->videodec_linked)) {
7585                         gint64 cur_time = 0;
7586
7587                         /* get current position */
7588                         gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_time);
7589
7590                         /* flush */
7591                         GstEvent *event = gst_event_new_seek(1.0,
7592                                                         GST_FORMAT_TIME,
7593                                                         (GstSeekFlags)GST_SEEK_FLAG_FLUSH,
7594                                                         GST_SEEK_TYPE_SET, cur_time,
7595                                                         GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7596                         if (event)
7597                                 __gst_send_event_to_sink(player, event);
7598
7599                         if (!MMPLAYER_IS_RTSP_STREAMING(player))
7600                                 __gst_pause(player, FALSE);
7601                 }
7602
7603                 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
7604                         that's why set position through property. */
7605                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7606                         (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
7607                         (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
7608                         (!player->videodec_linked) && (!player->audiodec_linked)) {
7609
7610                         g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", pos_nsec, NULL);
7611                         LOGD("[%s] set position =%"GST_TIME_FORMAT,
7612                                         GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(pos_nsec));
7613                         player->doing_seek = FALSE;
7614                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7615                 } else {
7616                         ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7617                                                         GST_FORMAT_TIME, seek_flags,
7618                                                         GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7619                 }
7620
7621                 if (!ret) {
7622                         LOGE("failed to set position. dur[%lu]  pos[%lu]  pos_msec[%llu]\n", dur_msec, position, pos_nsec);
7623                         goto SEEK_ERROR;
7624                 }
7625         }
7626         break;
7627
7628         case MM_PLAYER_POS_FORMAT_PERCENT:
7629         {
7630                 LOGD("seeking to(%lu)%% \n", position);
7631
7632                 if (player->doing_seek) {
7633                         LOGD("not completed seek");
7634                         return MM_ERROR_PLAYER_DOING_SEEK;
7635                 }
7636
7637                 if (!internal_called)
7638                         player->doing_seek = TRUE;
7639
7640                 /* FIXIT : why don't we use 'GST_FORMAT_PERCENT' */
7641                 pos_nsec = (gint64)((position * player->duration) / 100);
7642                 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7643                                                 GST_FORMAT_TIME, seek_flags,
7644                                                 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7645                 if (!ret) {
7646                         LOGE("failed to set position. dur[%lud]  pos[%lud]  pos_msec[%"G_GUINT64_FORMAT"]\n", dur_msec, position, pos_nsec);
7647                         goto SEEK_ERROR;
7648                 }
7649         }
7650         break;
7651
7652         default:
7653                 goto INVALID_ARGS;
7654         }
7655
7656         /* NOTE : store last seeking point to overcome some bad operation
7657           *     (returning zero when getting current position) of some elements
7658           */
7659         player->last_position = pos_nsec;
7660
7661         /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
7662         if (player->playback_rate > 1.0)
7663                 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
7664
7665         MMPLAYER_FLEAVE();
7666         return MM_ERROR_NONE;
7667
7668 PENDING:
7669         player->pending_seek.is_pending = TRUE;
7670         player->pending_seek.format = format;
7671         player->pending_seek.pos = position;
7672
7673         LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%lu).\n",
7674                 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)), MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)), player->pending_seek.pos);
7675
7676         return MM_ERROR_NONE;
7677
7678 INVALID_ARGS:
7679         LOGE("invalid arguments, position : %ld  dur : %ld format : %d \n", position, dur_msec, format);
7680         return MM_ERROR_INVALID_ARGUMENT;
7681
7682 SEEK_ERROR:
7683         player->doing_seek = FALSE;
7684         return MM_ERROR_PLAYER_SEEK;
7685 }
7686
7687 #define TRICKPLAY_OFFSET GST_MSECOND
7688
7689 static int
7690 __gst_get_position(mm_player_t* player, int format, unsigned long* position)
7691 {
7692         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7693         gint64 pos_msec = 0;
7694         gboolean ret = TRUE;
7695
7696         MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
7697                 MM_ERROR_PLAYER_NOT_INITIALIZED);
7698
7699         current_state = MMPLAYER_CURRENT_STATE(player);
7700
7701         /* NOTE : query position except paused state to overcome some bad operation
7702          * please refer to below comments in details
7703          */
7704         if (current_state != MM_PLAYER_STATE_PAUSED)
7705                 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
7706
7707         /* NOTE : get last point to overcome some bad operation of some elements
7708          *(returning zero when getting current position in paused state
7709          * and when failed to get postion during seeking
7710          */
7711         if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
7712                 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state);
7713
7714                 if (player->playback_rate < 0.0)
7715                         pos_msec = player->last_position - TRICKPLAY_OFFSET;
7716                 else
7717                         pos_msec = player->last_position;
7718
7719                 if (!ret)
7720                         pos_msec = player->last_position;
7721                 else
7722                         player->last_position = pos_msec;
7723
7724                 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_msec));
7725
7726         } else {
7727                 if (player->duration > 0 && pos_msec > player->duration)
7728                         pos_msec = player->duration;
7729
7730                 player->last_position = pos_msec;
7731         }
7732
7733         switch (format) {
7734         case MM_PLAYER_POS_FORMAT_TIME:
7735                 *position = GST_TIME_AS_MSECONDS(pos_msec);
7736                 break;
7737
7738         case MM_PLAYER_POS_FORMAT_PERCENT:
7739         {
7740                 if (player->duration <= 0) {
7741                         LOGD("duration is [%lld], so returning position 0\n", player->duration);
7742                         *position = 0;
7743                 } else {
7744                         LOGD("postion is [%lld] msec , duration is [%lld] msec", pos_msec, player->duration);
7745                         *position = pos_msec * 100 / player->duration;
7746                 }
7747                 break;
7748         }
7749         default:
7750                 return MM_ERROR_PLAYER_INTERNAL;
7751         }
7752
7753         return MM_ERROR_NONE;
7754 }
7755
7756
7757 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
7758 {
7759 #define STREAMING_IS_FINISHED   0
7760 #define BUFFERING_MAX_PER       100
7761 #define DEFAULT_PER_VALUE       -1
7762 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
7763
7764         MMPlayerGstElement *mainbin = NULL;
7765         gint start_per = DEFAULT_PER_VALUE, stop_per = DEFAULT_PER_VALUE;
7766         gint64 buffered_total = 0;
7767         unsigned long position = 0;
7768         gint buffered_sec = -1;
7769         GstBufferingMode mode = GST_BUFFERING_STREAM;
7770         gint64 content_size_time = player->duration;
7771         guint64 content_size_bytes = player->http_content_size;
7772
7773         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7774                                                 player->pipeline &&
7775                                                 player->pipeline->mainbin,
7776                                                 MM_ERROR_PLAYER_NOT_INITIALIZED);
7777
7778         MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT);
7779
7780         *start_pos = 0;
7781         *stop_pos = 0;
7782
7783         if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
7784                 /* and rtsp is not ready yet. */
7785                 LOGW("it's only used for http streaming case.\n");
7786                 return MM_ERROR_PLAYER_NO_OP;
7787         }
7788
7789         if (format != MM_PLAYER_POS_FORMAT_PERCENT) {
7790                 LOGW("Time format is not supported yet.\n");
7791                 return MM_ERROR_INVALID_ARGUMENT;
7792         }
7793
7794         if (content_size_time <= 0 || content_size_bytes <= 0) {
7795                 LOGW("there is no content size.");
7796                 return MM_ERROR_NONE;
7797         }
7798
7799         if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position) != MM_ERROR_NONE) {
7800                 LOGW("fail to get current position.");
7801                 return MM_ERROR_NONE;
7802         }
7803
7804         LOGD("pos %d ms, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
7805                 position, (guint)(content_size_time/GST_SECOND), content_size_bytes);
7806
7807         mainbin = player->pipeline->mainbin;
7808         start_per = (gint)(floor(100 *(gdouble)(position*GST_MSECOND) / (gdouble)content_size_time));
7809
7810         if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
7811                 GstQuery *query = NULL;
7812                 gint byte_in_rate = 0, byte_out_rate = 0;
7813                 gint64 estimated_total = 0;
7814
7815                 query = gst_query_new_buffering(GST_FORMAT_BYTES);
7816                 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
7817                         LOGW("fail to get buffering query from queue2");
7818                         if (query)
7819                                 gst_query_unref(query);
7820                         return MM_ERROR_NONE;
7821                 }
7822
7823                 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
7824                 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
7825
7826                 if (mode == GST_BUFFERING_STREAM) {
7827                         /* using only queue in case of push mode(ts / mp3) */
7828                         if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
7829                                 GST_FORMAT_BYTES, &buffered_total)) {
7830                                 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
7831                                 stop_per = 100 * buffered_total / content_size_bytes;
7832                         }
7833                 } else {
7834                         /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
7835                         guint idx = 0;
7836                         guint num_of_ranges = 0;
7837                         gint64 start_byte = 0, stop_byte = 0;
7838
7839                         gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
7840                         if (estimated_total != STREAMING_IS_FINISHED) {
7841                                 /* buffered size info from queue2 */
7842                                 num_of_ranges = gst_query_get_n_buffering_ranges(query);
7843                                 for (idx = 0; idx < num_of_ranges; idx++) {
7844                                         gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
7845                                         LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
7846
7847                                         buffered_total += (stop_byte - start_byte);
7848                                 }
7849                         } else
7850                                 stop_per = BUFFERING_MAX_PER;
7851                 }
7852                 gst_query_unref(query);
7853         }
7854
7855         if (stop_per == DEFAULT_PER_VALUE) {
7856                 guint dur_sec = (guint)(content_size_time/GST_SECOND);
7857                 if (dur_sec > 0) {
7858                         guint avg_byterate = (guint)(content_size_bytes/dur_sec);
7859
7860                         /* buffered size info from multiqueue */
7861                         if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
7862                                 guint curr_size_bytes = 0;
7863                                 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
7864                                         "curr-size-bytes", &curr_size_bytes, NULL);
7865                                 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
7866                                 buffered_total += curr_size_bytes;
7867                         }
7868
7869                         if (avg_byterate > 0)
7870                                 buffered_sec = (gint)(ceil((gdouble)buffered_total/(gdouble)avg_byterate));
7871                         else if (player->total_maximum_bitrate > 0)
7872                                 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_maximum_bitrate));
7873                         else if (player->total_bitrate > 0)
7874                                 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_bitrate));
7875
7876                         if (buffered_sec >= 0)
7877                                 stop_per = start_per +(gint)(ceil)(100*(gdouble)buffered_sec/(gdouble)dur_sec);
7878                 }
7879         }
7880
7881         *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
7882         *stop_pos = CHECK_PERCENT_VALUE(stop_per, *start_pos, 100);
7883
7884         LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %lu~%lu\n",
7885                 buffered_total, buffered_sec, *start_pos, *stop_pos);
7886
7887         return MM_ERROR_NONE;
7888 }
7889
7890 static int
7891 __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param)
7892 {
7893         MMPLAYER_FENTER();
7894
7895         if (!player) {
7896                 LOGW("set_message_callback is called with invalid player handle\n");
7897                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
7898         }
7899
7900         player->msg_cb = callback;
7901         player->msg_cb_param = user_param;
7902
7903         LOGD("msg_cb : %p     msg_cb_param : %p\n", callback, user_param);
7904
7905         MMPLAYER_FLEAVE();
7906
7907         return MM_ERROR_NONE;
7908 }
7909
7910 static int __mmfplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data)
7911 {
7912         int ret = MM_ERROR_PLAYER_INVALID_URI;
7913         char *path = NULL;
7914
7915         MMPLAYER_FENTER();
7916
7917         MMPLAYER_RETURN_VAL_IF_FAIL(uri , FALSE);
7918         MMPLAYER_RETURN_VAL_IF_FAIL(data , FALSE);
7919         MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), FALSE);
7920
7921         memset(data, 0, sizeof(MMPlayerParseProfile));
7922
7923         if ((path = strstr(uri, "es_buff://"))) {
7924                 if (strlen(path)) {
7925                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7926                         data->uri_type = MM_PLAYER_URI_TYPE_MS_BUFF;
7927                         ret = MM_ERROR_NONE;
7928                 }
7929         } else if ((path = strstr(uri, "rtsp://")) || (path = strstr(uri, "rtsps://"))) {
7930                 if (strlen(path)) {
7931                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7932                         data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7933                         ret = MM_ERROR_NONE;
7934                 }
7935         } else if ((path = strstr(uri, "http://")) || (path = strstr(uri, "https://"))) {
7936                 if (strlen(path)) {
7937                         gchar *tmp = NULL;
7938                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7939                         tmp = g_ascii_strdown(uri, strlen(uri));
7940
7941                         if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
7942                                 data->uri_type = MM_PLAYER_URI_TYPE_SS;
7943                         else
7944                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
7945
7946                         ret = MM_ERROR_NONE;
7947                         g_free(tmp);
7948                 }
7949         } else if ((path = strstr(uri, "rtspu://"))) {
7950                 if (strlen(path)) {
7951                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7952                         data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7953                         ret = MM_ERROR_NONE;
7954                 }
7955         } else if ((path = strstr(uri, "rtspr://"))) {
7956                 strncpy(data->uri, path, MM_MAX_URL_LEN-1);
7957                 char *separater = strstr(path, "*");
7958
7959                 if (separater) {
7960                         int urgent_len = 0;
7961                         char *urgent = separater + strlen("*");
7962
7963                         if ((urgent_len = strlen(urgent))) {
7964                                 data->uri[strlen(path) - urgent_len - strlen("*")] = '\0';
7965                                 strncpy(data->urgent, urgent, MM_MAX_FILENAME_LEN-1);
7966                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7967                                 ret = MM_ERROR_NONE;
7968                         }
7969                 }
7970         } else if ((path = strstr(uri, "mms://"))) {
7971                 if (strlen(path)) {
7972                         strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7973                         data->uri_type = MM_PLAYER_URI_TYPE_URL_MMS;
7974                         ret = MM_ERROR_NONE;
7975                 }
7976         } else if ((path = strstr(uri, "mem://"))) {
7977                 if (strlen(path)) {
7978                         int mem_size = 0;
7979                         char *buffer = NULL;
7980                         char *seperator = strchr(path, ',');
7981                         char ext[100] = {0,}, size[100] = {0,};
7982
7983                         if (seperator) {
7984                                 if ((buffer = strstr(path, "ext="))) {
7985                                         buffer += strlen("ext=");
7986
7987                                         if (strlen(buffer)) {
7988                                                 strncpy(ext, buffer, 99);
7989
7990                                                 if ((seperator = strchr(ext, ','))
7991                                                         || (seperator = strchr(ext, ' '))
7992                                                         || (seperator = strchr(ext, '\0'))) {
7993                                                         seperator[0] = '\0';
7994                                                 }
7995                                         }
7996                                 }
7997
7998                                 if ((buffer = strstr(path, "size="))) {
7999                                         buffer += strlen("size=");
8000
8001                                         if (strlen(buffer) > 0) {
8002                                                 strncpy(size, buffer, 99);
8003
8004                                                 if ((seperator = strchr(size, ','))
8005                                                         || (seperator = strchr(size, ' '))
8006                                                         || (seperator = strchr(size, '\0'))) {
8007                                                         seperator[0] = '\0';
8008                                                 }
8009
8010                                                 mem_size = atoi(size);
8011                                         }
8012                                 }
8013                         }
8014
8015                         LOGD("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
8016                         if (mem_size && param) {
8017                                 if (data->input_mem.buf)
8018                                         free(data->input_mem.buf);
8019                                 data->input_mem.buf = malloc(mem_size);
8020
8021                                 if (data->input_mem.buf) {
8022                                         memcpy(data->input_mem.buf, param, mem_size);
8023                                         data->input_mem.len = mem_size;
8024                                         ret = MM_ERROR_NONE;
8025                                 } else {
8026                                         LOGE("failed to alloc mem %d", mem_size);
8027                                         ret = MM_ERROR_PLAYER_INTERNAL;
8028                                 }
8029
8030                                 data->input_mem.offset = 0;
8031                                 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
8032                         }
8033                 }
8034         } else {
8035                 gchar *location = NULL;
8036                 GError *err = NULL;
8037
8038                 if ((path = strstr(uri, "file://"))) {
8039
8040                         location = g_filename_from_uri(uri, NULL, &err);
8041
8042                         if (!location || (err != NULL)) {
8043                           LOGE("Invalid URI '%s' for filesrc: %s", path,
8044                                  (err != NULL) ? err->message : "unknown error");
8045
8046                           if (err) g_error_free(err);
8047                           if (location) g_free(location);
8048
8049                           data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8050                           goto exit;
8051                         }
8052
8053                         LOGD("path from uri: %s", location);
8054                 }
8055
8056                 path = (location != NULL) ? (location) : ((char*)uri);
8057                 int file_stat = MM_ERROR_NONE;
8058
8059                 file_stat = util_exist_file_path(path);
8060
8061                 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8062                 if (file_stat == MM_ERROR_NONE) {
8063                         g_snprintf(data->uri,  MM_MAX_URL_LEN, "file://%s", path);
8064
8065                         if (util_is_sdp_file(path)) {
8066                                 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
8067                                 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8068                         } else {
8069                                 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8070                         }
8071                         ret = MM_ERROR_NONE;
8072                 } else if (file_stat == MM_ERROR_PLAYER_PERMISSION_DENIED) {
8073                         data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8074                 } else {
8075                         LOGE("invalid uri, could not play..\n");
8076                         data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8077                 }
8078
8079                 if (location) g_free(location);
8080         }
8081
8082 exit:
8083         if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
8084                 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
8085         else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
8086                 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
8087
8088         /* dump parse result */
8089         SECURE_LOGW("incomming uri : %s\n", uri);
8090         LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n",
8091                 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
8092
8093         MMPLAYER_FLEAVE();
8094
8095         return ret;
8096 }
8097
8098 gboolean
8099 __mmplayer_can_do_interrupt(mm_player_t *player)
8100 {
8101         if (!player || !player->pipeline || !player->attrs) {
8102                 LOGW("not initialized");
8103                 goto FAILED;
8104         }
8105
8106         if (player->set_mode.pcm_extraction) {
8107                 LOGW("leave right now, %d", player->set_mode.pcm_extraction);
8108                 goto FAILED;
8109         }
8110
8111         /* check if seeking */
8112         if (player->doing_seek) {
8113                 MMMessageParamType msg_param;
8114                 memset(&msg_param, 0, sizeof(MMMessageParamType));
8115                 msg_param.code = MM_ERROR_PLAYER_SEEK;
8116                 player->doing_seek = FALSE;
8117                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8118                 goto FAILED;
8119         }
8120
8121         /* check other thread */
8122         if (!MMPLAYER_CMD_TRYLOCK(player)) {
8123                 LOGW("locked already, cmd state : %d", player->cmd);
8124
8125                 /* check application command */
8126                 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
8127                         LOGW("playing.. should wait cmd lock then, will be interrupted");
8128
8129                         /* lock will be released at mrp_resource_release_cb() */
8130                         MMPLAYER_CMD_LOCK(player);
8131                         goto INTERRUPT;
8132                 }
8133                 LOGW("nothing to do");
8134                 goto FAILED;
8135         } else {
8136                 LOGW("can interrupt immediately");
8137                 goto INTERRUPT;
8138         }
8139
8140 FAILED:    /* with CMD UNLOCKED */
8141         return FALSE;
8142
8143 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
8144         return TRUE;
8145 }
8146
8147 static int
8148 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
8149                 void *user_data)
8150 {
8151         mm_player_t *player = NULL;
8152
8153         MMPLAYER_FENTER();
8154
8155         if (user_data == NULL) {
8156                 LOGE("- user_data is null\n");
8157                 return FALSE;
8158         }
8159         player = (mm_player_t *)user_data;
8160
8161         /* do something to release resource here.
8162          * player stop and interrupt forwarding */
8163         if (!__mmplayer_can_do_interrupt(player)) {
8164                 LOGW("no need to interrupt, so leave");
8165         } else {
8166                 MMMessageParamType msg = {0, };
8167                 unsigned long pos = 0;
8168
8169                 player->interrupted_by_resource = TRUE;
8170
8171                 /* get last play position */
8172                 if (_mmplayer_get_position((MMHandleType)player, MM_PLAYER_POS_FORMAT_TIME, &pos) != MM_ERROR_NONE) {
8173                         LOGW("failed to get play position.");
8174                 } else {
8175                         msg.union_type = MM_MSG_UNION_TIME;
8176                         msg.time.elapsed = (unsigned int)pos;
8177                         MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
8178                 }
8179                 LOGD("video resource conflict so, resource will be freed by unrealizing");
8180                 if (_mmplayer_unrealize((MMHandleType)player))
8181                         LOGW("failed to unrealize");
8182
8183                 /* lock is called in __mmplayer_can_do_interrupt() */
8184                 MMPLAYER_CMD_UNLOCK(player);
8185         }
8186
8187         if (res == player->video_overlay_resource)
8188                 player->video_overlay_resource = FALSE;
8189         else
8190                 player->video_decoder_resource = FALSE;
8191
8192         MMPLAYER_FLEAVE();
8193
8194         return FALSE;
8195 }
8196
8197 int
8198 _mmplayer_create_player(MMHandleType handle)
8199 {
8200         int ret = MM_ERROR_PLAYER_INTERNAL;
8201         bool enabled = false;
8202
8203         mm_player_t* player = MM_PLAYER_CAST(handle);
8204
8205         MMPLAYER_FENTER();
8206
8207         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8208
8209         /* initialize player state */
8210         MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
8211         MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
8212         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
8213         MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
8214
8215         /* check current state */
8216         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
8217
8218         /* construct attributes */
8219         player->attrs = _mmplayer_construct_attribute(handle);
8220
8221         if (!player->attrs) {
8222                 LOGE("Failed to construct attributes\n");
8223                 return ret;
8224         }
8225
8226         /* initialize gstreamer with configured parameter */
8227         if (!__mmplayer_init_gstreamer(player)) {
8228                 LOGE("Initializing gstreamer failed\n");
8229                 _mmplayer_deconstruct_attribute(handle);
8230                 return ret;
8231         }
8232
8233         /* create lock. note that g_tread_init() has already called in gst_init() */
8234         g_mutex_init(&player->fsink_lock);
8235
8236         /* create update tag lock */
8237         g_mutex_init(&player->update_tag_lock);
8238
8239         /* create next play mutex */
8240         g_mutex_init(&player->next_play_thread_mutex);
8241
8242         /* create next play cond */
8243         g_cond_init(&player->next_play_thread_cond);
8244
8245         /* create next play thread */
8246         player->next_play_thread =
8247                 g_thread_try_new("next_play_thread", __mmplayer_next_play_thread, (gpointer)player, NULL);
8248         if (!player->next_play_thread) {
8249                 LOGE("failed to create next play thread");
8250                 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8251                 g_mutex_clear(&player->next_play_thread_mutex);
8252                 g_cond_clear(&player->next_play_thread_cond);
8253                 goto ERROR;
8254         }
8255
8256         player->bus_msg_q = g_queue_new();
8257         if (!player->bus_msg_q) {
8258                 LOGE("failed to create queue for bus_msg");
8259                 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8260                 goto ERROR;
8261         }
8262
8263         ret = _mmplayer_initialize_video_capture(player);
8264         if (ret != MM_ERROR_NONE) {
8265                 LOGE("failed to initialize video capture\n");
8266                 goto ERROR;
8267         }
8268
8269         /* initialize resource manager */
8270         if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_create(
8271                         MM_RESOURCE_MANAGER_APP_CLASS_MEDIA, __resource_release_cb, player,
8272                         &player->resource_manager)) {
8273                 LOGE("failed to initialize resource manager\n");
8274                 goto ERROR;
8275         }
8276
8277         if (MMPLAYER_IS_HTTP_PD(player)) {
8278                 player->pd_downloader = NULL;
8279                 player->pd_file_save_path = NULL;
8280         }
8281
8282         /* create video bo lock and cond */
8283         g_mutex_init(&player->video_bo_mutex);
8284         g_cond_init(&player->video_bo_cond);
8285
8286         /* create media stream callback mutex */
8287         g_mutex_init(&player->media_stream_cb_lock);
8288
8289         /* create subtitle info lock and cond */
8290         g_mutex_init(&player->subtitle_info_mutex);
8291         g_cond_init(&player->subtitle_info_cond);
8292
8293         player->streaming_type = STREAMING_SERVICE_NONE;
8294
8295         /* give default value of audio effect setting */
8296         player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
8297         player->sound.rg_enable = false;
8298         player->playback_rate = DEFAULT_PLAYBACK_RATE;
8299
8300         player->play_subtitle = FALSE;
8301         player->use_deinterleave = FALSE;
8302         player->max_audio_channels = 0;
8303         player->video_share_api_delta = 0;
8304         player->video_share_clock_delta = 0;
8305         player->has_closed_caption = FALSE;
8306         player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8307         player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8308         player->pending_resume = FALSE;
8309         if (player->ini.dump_element_keyword[0][0] == '\0')
8310                 player->ini.set_dump_element_flag = FALSE;
8311         else
8312                 player->ini.set_dump_element_flag = TRUE;
8313
8314         player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8315         player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8316         player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8317
8318         /* Set video360 settings to their defaults for just-created player.
8319          * */
8320
8321         player->is_360_feature_enabled = FALSE;
8322         if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
8323                 LOGI("spherical feature info: %d", enabled);
8324                 if (enabled)
8325                         player->is_360_feature_enabled = TRUE;
8326         } else {
8327                 LOGE("failed to get spherical feature info");
8328         }
8329
8330         player->is_content_spherical = FALSE;
8331         player->is_video360_enabled = TRUE;
8332         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
8333         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
8334         player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
8335         player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
8336         player->video360_zoom = 1.0f;
8337         player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
8338         player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
8339
8340         /* set player state to null */
8341         MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8342         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
8343
8344         return MM_ERROR_NONE;
8345
8346 ERROR:
8347         /* free lock */
8348         g_mutex_clear(&player->fsink_lock);
8349
8350         /* free update tag lock */
8351         g_mutex_clear(&player->update_tag_lock);
8352
8353         g_queue_free(player->bus_msg_q);
8354
8355         /* free next play thread */
8356         if (player->next_play_thread) {
8357                 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8358                 player->next_play_thread_exit = TRUE;
8359                 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8360                 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8361
8362                 g_thread_join(player->next_play_thread);
8363                 player->next_play_thread = NULL;
8364
8365                 g_mutex_clear(&player->next_play_thread_mutex);
8366                 g_cond_clear(&player->next_play_thread_cond);
8367         }
8368
8369         /* release attributes */
8370         _mmplayer_deconstruct_attribute(handle);
8371
8372         MMPLAYER_FLEAVE();
8373
8374         return ret;
8375 }
8376
8377 static gboolean
8378 __mmplayer_init_gstreamer(mm_player_t* player)
8379 {
8380         static gboolean initialized = FALSE;
8381         static const int max_argc = 50;
8382         gint* argc = NULL;
8383         gchar** argv = NULL;
8384         gchar** argv2 = NULL;
8385         GError *err = NULL;
8386         int i = 0;
8387         int arg_count = 0;
8388
8389         if (initialized) {
8390                 LOGD("gstreamer already initialized.\n");
8391                 return TRUE;
8392         }
8393
8394         /* alloc */
8395         argc = malloc(sizeof(int));
8396         argv = malloc(sizeof(gchar*) * max_argc);
8397         argv2 = malloc(sizeof(gchar*) * max_argc);
8398
8399         if (!argc || !argv || !argv2)
8400                 goto ERROR;
8401
8402         memset(argv, 0, sizeof(gchar*) * max_argc);
8403         memset(argv2, 0, sizeof(gchar*) * max_argc);
8404
8405         /* add initial */
8406         *argc = 1;
8407         argv[0] = g_strdup("mmplayer");
8408
8409         /* add gst_param */
8410         for (i = 0; i < 5; i++) {
8411                 /* FIXIT : num of param is now fixed to 5. make it dynamic */
8412                 if (strlen(player->ini.gst_param[i]) > 0) {
8413                         argv[*argc] = g_strdup(player->ini.gst_param[i]);
8414                         (*argc)++;
8415                 }
8416         }
8417
8418         /* we would not do fork for scanning plugins */
8419         argv[*argc] = g_strdup("--gst-disable-registry-fork");
8420         (*argc)++;
8421
8422         /* check disable registry scan */
8423         if (player->ini.skip_rescan) {
8424                 argv[*argc] = g_strdup("--gst-disable-registry-update");
8425                 (*argc)++;
8426         }
8427
8428         /* check disable segtrap */
8429         if (player->ini.disable_segtrap) {
8430                 argv[*argc] = g_strdup("--gst-disable-segtrap");
8431                 (*argc)++;
8432         }
8433
8434         LOGD("initializing gstreamer with following parameter\n");
8435         LOGD("argc : %d\n", *argc);
8436         arg_count = *argc;
8437
8438         for (i = 0; i < arg_count; i++) {
8439                 argv2[i] = argv[i];
8440                 LOGD("argv[%d] : %s\n", i, argv2[i]);
8441         }
8442
8443         /* initializing gstreamer */
8444         if (!gst_init_check(argc, &argv, &err)) {
8445                 LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
8446                 if (err)
8447                         g_error_free(err);
8448
8449                 goto ERROR;
8450         }
8451         /* release */
8452         for (i = 0; i < arg_count; i++) {
8453                 //LOGD("release - argv[%d] : %s\n", i, argv2[i]);
8454                 MMPLAYER_FREEIF(argv2[i]);
8455         }
8456
8457         MMPLAYER_FREEIF(argv);
8458         MMPLAYER_FREEIF(argv2);
8459         MMPLAYER_FREEIF(argc);
8460
8461         /* done */
8462         initialized = TRUE;
8463
8464         return TRUE;
8465
8466 ERROR:
8467
8468         /* release */
8469         for (i = 0; i < arg_count; i++) {
8470                 LOGD("free[%d] : %s\n", i, argv2[i]);
8471                 MMPLAYER_FREEIF(argv2[i]);
8472         }
8473
8474         MMPLAYER_FREEIF(argv);
8475         MMPLAYER_FREEIF(argv2);
8476         MMPLAYER_FREEIF(argc);
8477
8478         return FALSE;
8479 }
8480
8481 int
8482 __mmplayer_destroy_streaming_ext(mm_player_t* player)
8483 {
8484         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8485
8486         if (player->pd_downloader || MMPLAYER_IS_HTTP_PD(player)) {
8487                 _mmplayer_destroy_pd_downloader((MMHandleType)player);
8488                 MMPLAYER_FREEIF(player->pd_file_save_path);
8489         }
8490
8491         return MM_ERROR_NONE;
8492 }
8493
8494 static void
8495 __mmplayer_check_async_state_transition(mm_player_t* player)
8496 {
8497         GstState element_state = GST_STATE_VOID_PENDING;
8498         GstState element_pending_state = GST_STATE_VOID_PENDING;
8499         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8500         GstElement * element = NULL;
8501         gboolean async = FALSE;
8502
8503         /* check player handle */
8504         MMPLAYER_RETURN_IF_FAIL(player &&
8505                                                 player->pipeline &&
8506                                                 player->pipeline->mainbin &&
8507                                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8508
8509         if (player->attrs)
8510                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
8511
8512         if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
8513                 LOGD("don't need to check the pipeline state");
8514                 return;
8515         }
8516
8517         MMPLAYER_PRINT_STATE(player);
8518
8519         /* wait for state transition */
8520         element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
8521         ret = gst_element_get_state(element, &element_state, &element_pending_state, 1*GST_SECOND);
8522
8523         if (ret == GST_STATE_CHANGE_FAILURE) {
8524                 LOGE(" [%s] state : %s   pending : %s \n",
8525                         GST_ELEMENT_NAME(element),
8526                         gst_element_state_get_name(element_state),
8527                         gst_element_state_get_name(element_pending_state));
8528
8529                 /* dump state of all element */
8530                 __mmplayer_dump_pipeline_state(player);
8531
8532                 return;
8533         }
8534
8535         LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
8536         return;
8537 }
8538
8539 int
8540 _mmplayer_destroy(MMHandleType handle)
8541 {
8542         mm_player_t* player = MM_PLAYER_CAST(handle);
8543
8544         MMPLAYER_FENTER();
8545
8546         /* check player handle */
8547         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8548
8549         /* destroy can called at anytime */
8550         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
8551
8552         /* check async state transition */
8553         __mmplayer_check_async_state_transition(player);
8554
8555         __mmplayer_destroy_streaming_ext(player);
8556
8557         /* release next play thread */
8558         if (player->next_play_thread) {
8559                 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8560                 player->next_play_thread_exit = TRUE;
8561                 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8562                 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8563
8564                 LOGD("waitting for next play thread exit\n");
8565                 g_thread_join(player->next_play_thread);
8566                 g_mutex_clear(&player->next_play_thread_mutex);
8567                 g_cond_clear(&player->next_play_thread_cond);
8568                 LOGD("next play thread released\n");
8569         }
8570
8571         _mmplayer_release_video_capture(player);
8572
8573         /* de-initialize resource manager */
8574         if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
8575                         player->resource_manager))
8576                 LOGE("failed to deinitialize resource manager\n");
8577
8578         /* release pipeline */
8579         if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
8580                 LOGE("failed to destory pipeline\n");
8581                 return MM_ERROR_PLAYER_INTERNAL;
8582         }
8583
8584         g_queue_free(player->bus_msg_q);
8585
8586         /* release subtitle info lock and cond */
8587         g_mutex_clear(&player->subtitle_info_mutex);
8588         g_cond_clear(&player->subtitle_info_cond);
8589
8590         __mmplayer_release_dump_list(player->dump_list);
8591
8592         /* release miscellaneous information */
8593         __mmplayer_release_misc(player);
8594
8595         /* release miscellaneous information.
8596            these info needs to be released after pipeline is destroyed. */
8597         __mmplayer_release_misc_post(player);
8598
8599         /* release attributes */
8600         _mmplayer_deconstruct_attribute(handle);
8601
8602         /* release lock */
8603         g_mutex_clear(&player->fsink_lock);
8604
8605         /* release lock */
8606         g_mutex_clear(&player->update_tag_lock);
8607
8608         /* release video bo lock and cond */
8609         g_mutex_clear(&player->video_bo_mutex);
8610         g_cond_clear(&player->video_bo_cond);
8611
8612         /* release media stream callback lock */
8613         g_mutex_clear(&player->media_stream_cb_lock);
8614
8615         MMPLAYER_FLEAVE();
8616
8617         return MM_ERROR_NONE;
8618 }
8619
8620 int
8621 __mmplayer_realize_streaming_ext(mm_player_t* player)
8622 {
8623         int ret = MM_ERROR_NONE;
8624
8625         MMPLAYER_FENTER();
8626         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8627
8628         if (MMPLAYER_IS_HTTP_PD(player)) {
8629                 gboolean bret = FALSE;
8630
8631                 player->pd_downloader = _mmplayer_create_pd_downloader();
8632                 if (!player->pd_downloader) {
8633                         LOGE("Unable to create PD Downloader...");
8634                         ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
8635                 }
8636
8637                 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
8638
8639                 if (FALSE == bret) {
8640                         LOGE("Unable to create PD Downloader...");
8641                         ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
8642                 }
8643         }
8644
8645         MMPLAYER_FLEAVE();
8646         return ret;
8647 }
8648
8649 int
8650 _mmplayer_realize(MMHandleType hplayer)
8651 {
8652         mm_player_t* player = (mm_player_t*)hplayer;
8653         char *uri = NULL;
8654         void *param = NULL;
8655         MMHandleType attrs = 0;
8656         int ret = MM_ERROR_NONE;
8657
8658         MMPLAYER_FENTER();
8659
8660         /* check player handle */
8661         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED)
8662
8663         /* check current state */
8664         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
8665
8666         attrs = MMPLAYER_GET_ATTRS(player);
8667         if (!attrs) {
8668                 LOGE("fail to get attributes.\n");
8669                 return MM_ERROR_PLAYER_INTERNAL;
8670         }
8671         mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
8672         mm_attrs_get_data_by_name(attrs, "profile_user_param", &param);
8673
8674         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
8675                 ret = __mmfplayer_parse_profile((const char*)uri, param, &player->profile);
8676
8677                 if (ret != MM_ERROR_NONE) {
8678                         LOGE("failed to parse profile\n");
8679                         return ret;
8680                 }
8681         }
8682
8683         if (uri && (strstr(uri, "es_buff://"))) {
8684                 if (strstr(uri, "es_buff://push_mode"))
8685                         player->es_player_push_mode = TRUE;
8686                 else
8687                         player->es_player_push_mode = FALSE;
8688         }
8689
8690         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
8691                 LOGW("mms protocol is not supported format.\n");
8692                 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
8693         }
8694
8695         if (MMPLAYER_IS_STREAMING(player))
8696                 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
8697         else
8698                 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8699
8700         player->smooth_streaming = FALSE;
8701         player->videodec_linked  = 0;
8702         player->videosink_linked = 0;
8703         player->audiodec_linked  = 0;
8704         player->audiosink_linked = 0;
8705         player->textsink_linked = 0;
8706         player->is_external_subtitle_present = FALSE;
8707         player->is_external_subtitle_added_now = FALSE;
8708         /* set the subtitle ON default */
8709         player->is_subtitle_off = FALSE;
8710
8711         /* realize pipeline */
8712         ret = __gst_realize(player);
8713         if (ret != MM_ERROR_NONE)
8714                 LOGE("fail to realize the player.\n");
8715         else
8716                 ret = __mmplayer_realize_streaming_ext(player);
8717
8718         player->bus_msg_timeout = PLAYER_BUS_MSG_PREPARE_TIMEOUT;
8719         MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8720
8721         MMPLAYER_FLEAVE();
8722
8723         return ret;
8724 }
8725
8726 int
8727 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
8728 {
8729         MMPLAYER_FENTER();
8730         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8731
8732         /* destroy can called at anytime */
8733         if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player))
8734                 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
8735
8736         MMPLAYER_FLEAVE();
8737         return MM_ERROR_NONE;
8738 }
8739
8740 int
8741 _mmplayer_unrealize(MMHandleType hplayer)
8742 {
8743         mm_player_t* player = (mm_player_t*)hplayer;
8744         int ret = MM_ERROR_NONE;
8745
8746         MMPLAYER_FENTER();
8747
8748         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8749
8750         MMPLAYER_CMD_UNLOCK(player);
8751         /* destroy the gst bus msg thread which is created during realize.
8752            this funct have to be called before getting cmd lock. */
8753         _mmplayer_bus_msg_thread_destroy(player);
8754         MMPLAYER_CMD_LOCK(player);
8755
8756         /* check current state */
8757         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
8758
8759         /* check async state transition */
8760         __mmplayer_check_async_state_transition(player);
8761
8762         __mmplayer_unrealize_streaming_ext(player);
8763
8764         /* unrealize pipeline */
8765         ret = __gst_unrealize(player);
8766
8767         /* set asm stop if success */
8768         if (MM_ERROR_NONE == ret) {
8769                 if (!player->interrupted_by_resource) {
8770                         if (player->video_decoder_resource != NULL) {
8771                                 ret = mm_resource_manager_mark_for_release(player->resource_manager,
8772                                                 player->video_decoder_resource);
8773                                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8774                                         LOGE("failed to mark decoder resource for release, ret(0x%x)\n", ret);
8775                                 else
8776                                         player->video_decoder_resource = NULL;
8777                         }
8778
8779                         if (player->video_overlay_resource != NULL) {
8780                                 ret = mm_resource_manager_mark_for_release(player->resource_manager,
8781                                                 player->video_overlay_resource);
8782                                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8783                                         LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
8784                                 else
8785                                         player->video_overlay_resource = NULL;
8786                         }
8787
8788                         ret = mm_resource_manager_commit(player->resource_manager);
8789                         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8790                                 LOGE("failed to commit resource releases, ret(0x%x)\n", ret);
8791                 }
8792         } else
8793                 LOGE("failed and don't change asm state to stop");
8794
8795         MMPLAYER_FLEAVE();
8796
8797         return ret;
8798 }
8799
8800 int
8801 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
8802 {
8803         mm_player_t* player = (mm_player_t*)hplayer;
8804
8805         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8806
8807         return __gst_set_message_callback(player, callback, user_param);
8808 }
8809
8810 int
8811 _mmplayer_get_state(MMHandleType hplayer, int* state)
8812 {
8813         mm_player_t *player = (mm_player_t*)hplayer;
8814
8815         MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
8816
8817         *state = MMPLAYER_CURRENT_STATE(player);
8818
8819         return MM_ERROR_NONE;
8820 }
8821
8822
8823 int
8824 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
8825 {
8826         mm_player_t* player = (mm_player_t*) hplayer;
8827         GstElement* vol_element = NULL;
8828         int i = 0;
8829
8830         MMPLAYER_FENTER();
8831
8832         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8833
8834         LOGD("volume [L]=%f:[R]=%f\n",
8835                 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
8836
8837         /* invalid factor range or not */
8838         for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
8839                 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
8840                         LOGE("Invalid factor!(valid factor:0~1.0)\n");
8841                         return MM_ERROR_INVALID_ARGUMENT;
8842                 }
8843         }
8844
8845         /* not support to set other value into each channel */
8846         if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
8847                 return MM_ERROR_INVALID_ARGUMENT;
8848
8849         /* Save volume to handle. Currently the first array element will be saved. */
8850         player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
8851
8852         /* check pipeline handle */
8853         if (!player->pipeline || !player->pipeline->audiobin) {
8854                 LOGD("audiobin is not created yet\n");
8855                 LOGD("but, current stored volume will be set when it's created.\n");
8856
8857                 /* NOTE : stored volume will be used in create_audiobin
8858                  * returning MM_ERROR_NONE here makes application to able to
8859                  * set volume at anytime.
8860                  */
8861                 return MM_ERROR_NONE;
8862         }
8863
8864         /* setting volume to volume element */
8865         vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
8866
8867         if (vol_element) {
8868                 LOGD("volume is set [%f]\n", player->sound.volume);
8869                 g_object_set(vol_element, "volume", player->sound.volume, NULL);
8870         }
8871
8872         MMPLAYER_FLEAVE();
8873
8874         return MM_ERROR_NONE;
8875 }
8876
8877
8878 int
8879 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
8880 {
8881         mm_player_t* player = (mm_player_t*) hplayer;
8882         int i = 0;
8883
8884         MMPLAYER_FENTER();
8885
8886         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8887         MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
8888
8889         /* returning stored volume */
8890         for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
8891                 volume->level[i] = player->sound.volume;
8892
8893         MMPLAYER_FLEAVE();
8894
8895         return MM_ERROR_NONE;
8896 }
8897
8898 int
8899 _mmplayer_set_mute(MMHandleType hplayer, int mute)
8900 {
8901         mm_player_t* player = (mm_player_t*) hplayer;
8902         GstElement* vol_element = NULL;
8903
8904         MMPLAYER_FENTER();
8905
8906         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8907
8908         /* mute value shoud 0 or 1 */
8909         if (mute != 0 && mute != 1) {
8910                 LOGE("bad mute value\n");
8911
8912                 /* FIXIT : definitly, we need _BAD_PARAM error code */
8913                 return MM_ERROR_INVALID_ARGUMENT;
8914         }
8915
8916         player->sound.mute = mute;
8917
8918         /* just hold mute value if pipeline is not ready */
8919         if (!player->pipeline || !player->pipeline->audiobin) {
8920                 LOGD("pipeline is not ready. holding mute value\n");
8921                 return MM_ERROR_NONE;
8922         }
8923
8924         vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
8925
8926         /* NOTE : volume will only created when the bt is enabled */
8927         if (vol_element) {
8928                 LOGD("mute : %d\n", mute);
8929                 g_object_set(vol_element, "mute", mute, NULL);
8930         } else
8931                 LOGD("volume elemnet is not created. using volume in audiosink\n");
8932
8933         MMPLAYER_FLEAVE();
8934
8935         return MM_ERROR_NONE;
8936 }
8937
8938 int
8939 _mmplayer_get_mute(MMHandleType hplayer, int* pmute)
8940 {
8941         mm_player_t* player = (mm_player_t*) hplayer;
8942
8943         MMPLAYER_FENTER();
8944
8945         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8946         MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
8947
8948         /* just hold mute value if pipeline is not ready */
8949         if (!player->pipeline || !player->pipeline->audiobin) {
8950                 LOGD("pipeline is not ready. returning stored value\n");
8951                 *pmute = player->sound.mute;
8952                 return MM_ERROR_NONE;
8953         }
8954
8955         *pmute = player->sound.mute;
8956
8957         MMPLAYER_FLEAVE();
8958
8959         return MM_ERROR_NONE;
8960 }
8961
8962 int
8963 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
8964 {
8965         mm_player_t* player = (mm_player_t*) hplayer;
8966
8967         MMPLAYER_FENTER();
8968
8969         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8970
8971         player->video_stream_changed_cb = callback;
8972         player->video_stream_changed_cb_user_param = user_param;
8973         LOGD("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
8974
8975         MMPLAYER_FLEAVE();
8976
8977         return MM_ERROR_NONE;
8978 }
8979
8980 int
8981 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
8982 {
8983         mm_player_t* player = (mm_player_t*) hplayer;
8984
8985         MMPLAYER_FENTER();
8986
8987         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8988
8989         player->audio_stream_changed_cb = callback;
8990         player->audio_stream_changed_cb_user_param = user_param;
8991         LOGD("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
8992
8993         MMPLAYER_FLEAVE();
8994
8995         return MM_ERROR_NONE;
8996 }
8997
8998 int
8999 _mmplayer_set_audiostream_cb_ex(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback_ex callback, void *user_param)
9000 {
9001         mm_player_t* player = (mm_player_t*) hplayer;
9002
9003         MMPLAYER_FENTER();
9004
9005         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9006
9007         player->audio_stream_render_cb_ex = callback;
9008         player->audio_stream_cb_user_param = user_param;
9009         player->audio_stream_sink_sync = sync;
9010         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);
9011
9012         MMPLAYER_FLEAVE();
9013
9014         return MM_ERROR_NONE;
9015 }
9016
9017 int
9018 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
9019 {
9020         mm_player_t* player = (mm_player_t*) hplayer;
9021
9022         MMPLAYER_FENTER();
9023
9024         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9025
9026         if (callback && !player->bufmgr)
9027                 player->bufmgr = tbm_bufmgr_init(-1);
9028
9029         player->set_mode.media_packet_video_stream = (callback) ? TRUE : FALSE;
9030         player->video_stream_cb = callback;
9031         player->video_stream_cb_user_param = user_param;
9032
9033         LOGD("Stream cb Handle value is %p : %p, enable:%d\n", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
9034
9035         MMPLAYER_FLEAVE();
9036
9037         return MM_ERROR_NONE;
9038 }
9039
9040 int
9041 _mmplayer_set_audiostream_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param)
9042 {
9043         mm_player_t* player = (mm_player_t*) hplayer;
9044
9045         MMPLAYER_FENTER();
9046
9047         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9048
9049         player->audio_stream_cb = callback;
9050         player->audio_stream_cb_user_param = user_param;
9051         LOGD("Audio Stream cb Handle value is %p : %p\n", player, player->audio_stream_cb);
9052
9053         MMPLAYER_FLEAVE();
9054
9055         return MM_ERROR_NONE;
9056 }
9057
9058 static int
9059 __mmplayer_start_streaming_ext(mm_player_t *player)
9060 {
9061         gint ret = MM_ERROR_NONE;
9062
9063         MMPLAYER_FENTER();
9064         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9065
9066         if (MMPLAYER_IS_HTTP_PD(player)) {
9067                 if (!player->pd_downloader) {
9068                         ret = __mmplayer_realize_streaming_ext(player);
9069
9070                         if (ret != MM_ERROR_NONE) {
9071                                 LOGE("failed to realize streaming ext\n");
9072                                 return ret;
9073                         }
9074                 }
9075
9076                 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI) {
9077                         ret = _mmplayer_start_pd_downloader((MMHandleType)player);
9078                         if (!ret) {
9079                                 LOGE("ERROR while starting PD...\n");
9080                                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
9081                         }
9082                         ret = MM_ERROR_NONE;
9083                 }
9084         }
9085
9086         MMPLAYER_FLEAVE();
9087         return ret;
9088 }
9089
9090 int
9091 _mmplayer_start(MMHandleType hplayer)
9092 {
9093         mm_player_t* player = (mm_player_t*) hplayer;
9094         gint ret = MM_ERROR_NONE;
9095
9096         MMPLAYER_FENTER();
9097
9098         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9099
9100         /* check current state */
9101         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
9102
9103         /* NOTE : we should check and create pipeline again if not created as we destroy
9104          * whole pipeline when stopping in streamming playback
9105          */
9106         if (!player->pipeline) {
9107                 ret = __gst_realize(player);
9108                 if (MM_ERROR_NONE != ret) {
9109                         LOGE("failed to realize before starting. only in streamming\n");
9110                         /* unlock */
9111                         return ret;
9112                 }
9113         }
9114
9115         ret = __mmplayer_start_streaming_ext(player);
9116         if (ret != MM_ERROR_NONE) {
9117                 LOGE("failed to start streaming ext 0x%X", ret);
9118                 return ret;
9119         }
9120
9121         /* start pipeline */
9122         ret = __gst_start(player);
9123         if (ret != MM_ERROR_NONE)
9124                 LOGE("failed to start player.\n");
9125
9126         MMPLAYER_FLEAVE();
9127
9128         return ret;
9129 }
9130
9131 /* NOTE: post "not supported codec message" to application
9132  * when one codec is not found during AUTOPLUGGING in MSL.
9133  * So, it's separated with error of __mmplayer_gst_callback().
9134  * And, if any codec is not found, don't send message here.
9135  * Because GST_ERROR_MESSAGE is posted by other plugin internally.
9136  */
9137 int
9138 __mmplayer_handle_missed_plugin(mm_player_t* player)
9139 {
9140         MMMessageParamType msg_param;
9141         memset(&msg_param, 0, sizeof(MMMessageParamType));
9142         gboolean post_msg_direct = FALSE;
9143
9144         MMPLAYER_FENTER();
9145
9146         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9147
9148         LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
9149                         player->not_supported_codec, player->can_support_codec);
9150
9151         if (player->not_found_demuxer) {
9152                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9153                 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
9154
9155                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9156                 MMPLAYER_FREEIF(msg_param.data);
9157
9158                 return MM_ERROR_NONE;
9159         }
9160
9161         if (player->not_supported_codec) {
9162                 if (player->can_support_codec) {
9163                         // There is one codec to play
9164                         post_msg_direct = TRUE;
9165                 } else {
9166                         if (player->pipeline->audiobin) // Some content has only PCM data in container.
9167                                 post_msg_direct = TRUE;
9168                 }
9169
9170                 if (post_msg_direct) {
9171                         MMMessageParamType msg_param;
9172                         memset(&msg_param, 0, sizeof(MMMessageParamType));
9173
9174                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
9175                                 LOGW("not found AUDIO codec, posting error code to application.\n");
9176
9177                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9178                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9179                         } else if (player->not_supported_codec ==  MISSING_PLUGIN_VIDEO) {
9180                                 LOGW("not found VIDEO codec, posting error code to application.\n");
9181
9182                                 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
9183                                 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
9184                         }
9185
9186                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9187
9188                         MMPLAYER_FREEIF(msg_param.data);
9189
9190                         return MM_ERROR_NONE;
9191                 } else {
9192                         // no any supported codec case
9193                         LOGW("not found any codec, posting error code to application.\n");
9194
9195                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
9196                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9197                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9198                         } else {
9199                                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9200                                 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
9201                         }
9202
9203                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9204
9205                         MMPLAYER_FREEIF(msg_param.data);
9206                 }
9207         }
9208
9209         MMPLAYER_FLEAVE();
9210
9211         return MM_ERROR_NONE;
9212 }
9213
9214 static void __mmplayer_check_pipeline(mm_player_t* player)
9215 {
9216         GstState element_state = GST_STATE_VOID_PENDING;
9217         GstState element_pending_state = GST_STATE_VOID_PENDING;
9218         gint timeout = 0;
9219         int ret = MM_ERROR_NONE;
9220
9221         if (player->gapless.reconfigure) {
9222                 LOGW("pipeline is under construction.\n");
9223
9224                 MMPLAYER_PLAYBACK_LOCK(player);
9225                 MMPLAYER_PLAYBACK_UNLOCK(player);
9226
9227                 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
9228
9229                 /* wait for state transition */
9230                 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
9231
9232                 if (ret == GST_STATE_CHANGE_FAILURE)
9233                         LOGE("failed to change pipeline state within %d sec\n", timeout);
9234         }
9235 }
9236
9237 /* NOTE : it should be able to call 'stop' anytime*/
9238 int
9239 _mmplayer_stop(MMHandleType hplayer)
9240 {
9241         mm_player_t* player = (mm_player_t*)hplayer;
9242         int ret = MM_ERROR_NONE;
9243
9244         MMPLAYER_FENTER();
9245
9246         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9247
9248         /* check current state */
9249         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
9250
9251         /* check pipline building state */
9252         __mmplayer_check_pipeline(player);
9253         __mmplayer_reset_gapless_state(player);
9254
9255         /* NOTE : application should not wait for EOS after calling STOP */
9256         __mmplayer_cancel_eos_timer(player);
9257
9258         __mmplayer_unrealize_streaming_ext(player);
9259
9260         /* reset */
9261         player->doing_seek = FALSE;
9262
9263         /* stop pipeline */
9264         ret = __gst_stop(player);
9265
9266         if (ret != MM_ERROR_NONE)
9267                 LOGE("failed to stop player.\n");
9268
9269         MMPLAYER_FLEAVE();
9270
9271         return ret;
9272 }
9273
9274 int
9275 _mmplayer_pause(MMHandleType hplayer)
9276 {
9277         mm_player_t* player = (mm_player_t*)hplayer;
9278         gint64 pos_msec = 0;
9279         gboolean async = FALSE;
9280         gint ret = MM_ERROR_NONE;
9281
9282         MMPLAYER_FENTER();
9283
9284         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9285
9286         /* check current state */
9287         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
9288
9289         /* check pipline building state */
9290         __mmplayer_check_pipeline(player);
9291
9292         switch (MMPLAYER_CURRENT_STATE(player)) {
9293         case MM_PLAYER_STATE_READY:
9294                 {
9295                         /* check prepare async or not.
9296                          * In the case of streaming playback, it's recommned to avoid blocking wait.
9297                          */
9298                         mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9299                         LOGD("prepare working mode : %s", (async ? "async" : "sync"));
9300
9301                         /* Changing back sync of rtspsrc to async */
9302                         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9303                                 LOGD("async prepare working mode for rtsp");
9304                                 async = TRUE;
9305                         }
9306                 }
9307                 break;
9308
9309         case MM_PLAYER_STATE_PLAYING:
9310                 {
9311                         /* NOTE : store current point to overcome some bad operation
9312                         *(returning zero when getting current position in paused state) of some
9313                         * elements
9314                         */
9315                         if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec))
9316                                 LOGW("getting current position failed in paused\n");
9317
9318                         player->last_position = pos_msec;
9319
9320                         /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
9321                            But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
9322                            This causes problem is position calculation during normal pause resume scenarios also.
9323                            Currently during pause , we are sending the current position to rtspsrc module for position saving. */
9324                         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
9325                                 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
9326                                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
9327                         }
9328                 }
9329                 break;
9330         }
9331
9332         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
9333                 LOGD("doing async pause in case of ms buff src");
9334                 async = TRUE;
9335         }
9336
9337         /* pause pipeline */
9338         ret = __gst_pause(player, async);
9339
9340         if (ret != MM_ERROR_NONE)
9341                 LOGE("failed to pause player. ret : 0x%x\n", ret);
9342
9343         if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
9344                 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
9345                         LOGE("failed to update display_rotation");
9346         }
9347
9348         MMPLAYER_FLEAVE();
9349
9350         return ret;
9351 }
9352
9353 int
9354 _mmplayer_resume(MMHandleType hplayer)
9355 {
9356         mm_player_t* player = (mm_player_t*)hplayer;
9357         int ret = MM_ERROR_NONE;
9358         gboolean async = FALSE;
9359
9360         MMPLAYER_FENTER();
9361
9362         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9363
9364         /* Changing back sync mode rtspsrc to async */
9365         if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
9366                 LOGD("async resume for rtsp case");
9367                 async = TRUE;
9368         }
9369
9370         /* check current state */
9371         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
9372
9373         ret = __gst_resume(player, async);
9374
9375         if (ret != MM_ERROR_NONE)
9376                 LOGE("failed to resume player.\n");
9377
9378         MMPLAYER_FLEAVE();
9379
9380         return ret;
9381 }
9382
9383 static int
9384 __mmplayer_set_pcm_extraction(mm_player_t* player)
9385 {
9386         gint64 start_nsec = 0;
9387         gint64 end_nsec = 0;
9388         gint64 dur_nsec = 0;
9389         gint64 dur_msec = 0;
9390         int required_start = 0;
9391         int required_end = 0;
9392         int ret = 0;
9393
9394         MMPLAYER_FENTER();
9395
9396         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
9397
9398         mm_attrs_multiple_get(player->attrs,
9399                 NULL,
9400                 "pcm_extraction_start_msec", &required_start,
9401                 "pcm_extraction_end_msec", &required_end,
9402                 NULL);
9403
9404         LOGD("pcm extraction required position is from [%d] to [%d](msec)\n", required_start, required_end);
9405
9406         if (required_start == 0 && required_end == 0) {
9407                 LOGD("extracting entire stream");
9408                 return MM_ERROR_NONE;
9409         } else if (required_start < 0 || required_start > required_end || required_end < 0) {
9410                 LOGD("invalid range for pcm extraction");
9411                 return MM_ERROR_INVALID_ARGUMENT;
9412         }
9413
9414         /* get duration */
9415         ret = gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec);
9416         if (!ret) {
9417                 LOGE("failed to get duration");
9418                 return MM_ERROR_PLAYER_INTERNAL;
9419         }
9420         dur_msec = GST_TIME_AS_MSECONDS(dur_nsec);
9421
9422         if (dur_msec < required_end) {
9423                 // FIXME
9424                 LOGD("invalid end pos for pcm extraction");
9425                 return MM_ERROR_INVALID_ARGUMENT;
9426         }
9427
9428         start_nsec = required_start * G_GINT64_CONSTANT(1000000);
9429         end_nsec = required_end * G_GINT64_CONSTANT(1000000);
9430
9431         if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9432                                         1.0,
9433                                         GST_FORMAT_TIME,
9434                                         (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9435                                         GST_SEEK_TYPE_SET, start_nsec,
9436                                         GST_SEEK_TYPE_SET, end_nsec))) {
9437                 LOGE("failed to seek for pcm extraction\n");
9438
9439                 return MM_ERROR_PLAYER_SEEK;
9440         }
9441
9442         LOGD("succeeded to set up segment extraction from [%llu] to [%llu](nsec)\n", start_nsec, end_nsec);
9443
9444         MMPLAYER_FLEAVE();
9445
9446         return MM_ERROR_NONE;
9447 }
9448
9449 int
9450 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
9451 {
9452         mm_player_t* player = (mm_player_t*)hplayer;
9453         gint64 pos_msec = 0;
9454         int ret = MM_ERROR_NONE;
9455         int mute = FALSE;
9456         signed long long start = 0, stop = 0;
9457         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
9458         MMPLAYER_FENTER();
9459
9460         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9461         MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
9462
9463         /* The sound of video is not supported under 0.0 and over 2.0. */
9464         if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
9465                 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
9466                         mute = TRUE;
9467         }
9468         _mmplayer_set_mute(hplayer, mute);
9469
9470         if (player->playback_rate == rate)
9471                 return MM_ERROR_NONE;
9472
9473         /* If the position is reached at start potion during fast backward, EOS is posted.
9474          * So, This EOS have to be classified with it which is posted at reaching the end of stream.
9475          * */
9476         player->playback_rate = rate;
9477
9478         current_state = MMPLAYER_CURRENT_STATE(player);
9479
9480         if (current_state != MM_PLAYER_STATE_PAUSED)
9481                 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
9482
9483         LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state);
9484
9485         if ((current_state == MM_PLAYER_STATE_PAUSED)
9486                 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
9487                 LOGW("returning last point : %lld\n", player->last_position);
9488                 pos_msec = player->last_position;
9489         }
9490
9491         if (rate >= 0) {
9492                 start = pos_msec;
9493                 stop = GST_CLOCK_TIME_NONE;
9494         } else {
9495                 start = GST_CLOCK_TIME_NONE;
9496                 stop = pos_msec;
9497         }
9498
9499         if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9500                                 player->playback_rate,
9501                                 GST_FORMAT_TIME,
9502                                 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9503                                 GST_SEEK_TYPE_SET, start,
9504                                 GST_SEEK_TYPE_SET, stop)) {
9505                 LOGE("failed to set speed playback\n");
9506                 return MM_ERROR_PLAYER_SEEK;
9507         }
9508
9509         LOGD("succeeded to set speed playback as %0.1f\n", rate);
9510
9511         MMPLAYER_FLEAVE();
9512
9513         return MM_ERROR_NONE;;
9514 }
9515
9516 int
9517 _mmplayer_set_position(MMHandleType hplayer, int format, int position)
9518 {
9519         mm_player_t* player = (mm_player_t*)hplayer;
9520         int ret = MM_ERROR_NONE;
9521
9522         MMPLAYER_FENTER();
9523
9524         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9525
9526         /* check pipline building state */
9527         __mmplayer_check_pipeline(player);
9528
9529         ret = __gst_set_position(player, format, (unsigned long)position, FALSE);
9530
9531         MMPLAYER_FLEAVE();
9532
9533         return ret;
9534 }
9535
9536 int
9537 _mmplayer_get_position(MMHandleType hplayer, int format, unsigned long *position)
9538 {
9539         mm_player_t* player = (mm_player_t*)hplayer;
9540         int ret = MM_ERROR_NONE;
9541
9542         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9543
9544         ret = __gst_get_position(player, format, position);
9545
9546         return ret;
9547 }
9548
9549 int
9550 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos)
9551 {
9552         mm_player_t* player = (mm_player_t*)hplayer;
9553         int ret = MM_ERROR_NONE;
9554
9555         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9556
9557         ret = __gst_get_buffer_position(player, format, start_pos, stop_pos);
9558
9559         return ret;
9560 }
9561
9562 int
9563 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
9564 {
9565         mm_player_t* player = (mm_player_t*)hplayer;
9566         int ret = MM_ERROR_NONE;
9567
9568         MMPLAYER_FENTER();
9569
9570         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9571
9572         ret = __gst_adjust_subtitle_position(player, format, position);
9573
9574         MMPLAYER_FLEAVE();
9575
9576         return ret;
9577 }
9578 int
9579 _mmplayer_adjust_video_postion(MMHandleType hplayer, int offset)
9580 {
9581         mm_player_t* player = (mm_player_t*)hplayer;
9582         int ret = MM_ERROR_NONE;
9583
9584         MMPLAYER_FENTER();
9585
9586         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9587
9588         ret = __gst_adjust_video_position(player, offset);
9589
9590         MMPLAYER_FLEAVE();
9591
9592         return ret;
9593 }
9594
9595 static gboolean
9596 __mmplayer_is_midi_type(gchar* str_caps)
9597 {
9598         if ((g_strrstr(str_caps, "audio/midi")) ||
9599                 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
9600                 (g_strrstr(str_caps, "application/x-smaf")) ||
9601                 (g_strrstr(str_caps, "audio/x-imelody")) ||
9602                 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
9603                 (g_strrstr(str_caps, "audio/xmf")) ||
9604                 (g_strrstr(str_caps, "audio/mxmf"))) {
9605                 LOGD("midi\n");
9606                 return TRUE;
9607         }
9608
9609         return FALSE;
9610 }
9611
9612 static gboolean
9613 __mmplayer_is_only_mp3_type(gchar *str_caps)
9614 {
9615         if (g_strrstr(str_caps, "application/x-id3") ||
9616                 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
9617                 return TRUE;
9618         return FALSE;
9619 }
9620
9621 static void
9622 __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps)
9623 {
9624         GstStructure* caps_structure = NULL;
9625         gint samplerate = 0;
9626         gint channels = 0;
9627
9628         MMPLAYER_FENTER();
9629         MMPLAYER_RETURN_IF_FAIL(player && caps);
9630
9631         caps_structure = gst_caps_get_structure(caps, 0);
9632
9633         /* set stream information */
9634         gst_structure_get_int(caps_structure, "rate", &samplerate);
9635         mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
9636
9637         gst_structure_get_int(caps_structure, "channels", &channels);
9638         mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
9639
9640         LOGD("audio samplerate : %d     channels : %d\n", samplerate, channels);
9641 }
9642
9643 static void
9644 __mmplayer_update_content_type_info(mm_player_t* player)
9645 {
9646         MMPLAYER_FENTER();
9647         MMPLAYER_RETURN_IF_FAIL(player && player->type);
9648
9649         if (__mmplayer_is_midi_type(player->type)) {
9650                 player->bypass_audio_effect = TRUE;
9651         } else if (g_strrstr(player->type, "application/x-hls")) {
9652                 /* If it can't know exact type when it parses uri because of redirection case,
9653                  * it will be fixed by typefinder or when doing autoplugging.
9654                  */
9655                 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
9656                 if (player->streamer) {
9657                         player->streamer->is_adaptive_streaming = TRUE;
9658                         player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
9659                         player->streamer->buffering_req.rebuffer_time = 5 * 1000;
9660                 }
9661         } else if (g_strrstr(player->type, "application/dash+xml")) {
9662                 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
9663         }
9664
9665         MMPLAYER_FLEAVE();
9666 }
9667
9668 static void
9669 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
9670 GstCaps *caps, gpointer data)
9671 {
9672         mm_player_t* player = (mm_player_t*)data;
9673         GstPad* pad = NULL;
9674
9675         MMPLAYER_FENTER();
9676
9677         MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
9678
9679         /* store type string */
9680         MMPLAYER_FREEIF(player->type);
9681         player->type = gst_caps_to_string(caps);
9682         if (player->type) {
9683                 LOGD("[handle: %p] media type %s found, probability %d%% / %d\n",
9684                                 player, player->type, probability, gst_caps_get_size(caps));
9685         }
9686
9687         if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
9688                 (g_strrstr(player->type, "audio/x-raw-int"))) {
9689                 LOGE("not support media format\n");
9690
9691                 if (player->msg_posted == FALSE) {
9692                         MMMessageParamType msg_param;
9693                         memset(&msg_param, 0, sizeof(MMMessageParamType));
9694
9695                         msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
9696                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9697
9698                         /* don't post more if one was sent already */
9699                         player->msg_posted = TRUE;
9700                 }
9701                 return;
9702         }
9703
9704         __mmplayer_update_content_type_info(player);
9705
9706         pad = gst_element_get_static_pad(tf, "src");
9707         if (!pad) {
9708                 LOGE("fail to get typefind src pad.\n");
9709                 return;
9710         }
9711
9712         if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
9713                 gboolean async = FALSE;
9714                 LOGE("failed to autoplug %s\n", player->type);
9715
9716                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9717
9718                 if (async && player->msg_posted == FALSE)
9719                         __mmplayer_handle_missed_plugin(player);
9720
9721                 goto DONE;
9722         }
9723
9724 DONE:
9725         gst_object_unref(GST_OBJECT(pad));
9726
9727         MMPLAYER_FLEAVE();
9728
9729         return;
9730 }
9731
9732 static GstElement *
9733 __mmplayer_create_decodebin(mm_player_t* player)
9734 {
9735         GstElement *decodebin = NULL;
9736
9737         MMPLAYER_FENTER();
9738
9739         /* create decodebin */
9740         decodebin = gst_element_factory_make("decodebin", NULL);
9741
9742         if (!decodebin) {
9743                 LOGE("fail to create decodebin\n");
9744                 goto ERROR;
9745         }
9746
9747         /* raw pad handling signal */
9748         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
9749                                                 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
9750
9751         /* no-more-pad pad handling signal */
9752         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
9753                                                 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), player);
9754
9755         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
9756                                                 G_CALLBACK(__mmplayer_gst_decode_pad_removed), player);
9757
9758         /* This signal is emitted when a pad for which there is no further possible
9759            decoding is added to the decodebin.*/
9760         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
9761                                                 G_CALLBACK(__mmplayer_gst_decode_unknown_type), player);
9762
9763         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
9764            before looking for any elements that can handle that stream.*/
9765         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
9766                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), player);
9767
9768         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
9769            before looking for any elements that can handle that stream.*/
9770         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
9771                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
9772
9773         /* This signal is emitted once decodebin has finished decoding all the data.*/
9774         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
9775                                                 G_CALLBACK(__mmplayer_gst_decode_drained), player);
9776
9777         /* This signal is emitted when a element is added to the bin.*/
9778         MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
9779                                                 G_CALLBACK(__mmplayer_gst_element_added), player);
9780
9781 ERROR:
9782         return decodebin;
9783 }
9784
9785 static gboolean
9786 __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
9787 {
9788         MMPlayerGstElement* mainbin = NULL;
9789         GstElement* decodebin = NULL;
9790         GstElement* queue2 = NULL;
9791         GstPad* sinkpad = NULL;
9792         GstPad* qsrcpad = NULL;
9793         gint64 dur_bytes = 0L;
9794
9795         guint max_buffer_size_bytes = 0;
9796         gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
9797
9798         MMPLAYER_FENTER();
9799         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
9800
9801         mainbin = player->pipeline->mainbin;
9802
9803         if ((!MMPLAYER_IS_HTTP_PD(player)) &&
9804                 (MMPLAYER_IS_HTTP_STREAMING(player))) {
9805                 LOGD("creating http streaming buffering queue(queue2)\n");
9806
9807                 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
9808                         LOGE("MMPLAYER_M_MUXED_S_BUFFER is not null\n");
9809                 } else {
9810                         queue2 = gst_element_factory_make("queue2", "queue2");
9811                         if (!queue2) {
9812                                 LOGE("failed to create buffering queue element\n");
9813                                 goto ERROR;
9814                         }
9815
9816                         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
9817                                 LOGE("failed to add buffering queue\n");
9818                                 goto ERROR;
9819                         }
9820
9821                         sinkpad = gst_element_get_static_pad(queue2, "sink");
9822                         qsrcpad = gst_element_get_static_pad(queue2, "src");
9823
9824                         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
9825                                 LOGE("failed to link buffering queue\n");
9826                                 goto ERROR;
9827                         }
9828
9829                         if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
9830                                 LOGE("fail to get duration.\n");
9831
9832                         LOGD("dur_bytes = %lld\n", dur_bytes);
9833
9834                         muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
9835
9836                         if (dur_bytes > 0) {
9837                                 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
9838                                         type = MUXED_BUFFER_TYPE_FILE;
9839                                 } else {
9840                                         type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
9841                                         player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
9842                                 }
9843                         } else {
9844                                 dur_bytes = 0;
9845                         }
9846
9847                         /* NOTE : we cannot get any duration info from ts container in case of streaming */
9848                         // if (!g_strrstr(GST_ELEMENT_NAME(sinkelement), "mpegtsdemux"))
9849                         if (!g_strrstr(player->type, "video/mpegts")) {
9850                                 max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5*1024*1024);
9851                                 LOGD("max_buffer_size_bytes = %d\n", max_buffer_size_bytes);
9852
9853                                 // FIXME : pass ini setting directly. is this ok?
9854                                 __mm_player_streaming_set_queue2(player->streamer,
9855                                                                                                 queue2,
9856                                                                                                 FALSE,
9857                                                                                                 max_buffer_size_bytes,
9858                                                                                                 player->ini.http_buffering_time,
9859                                                                                                 1.0,                                                            // no meaning
9860                                                                                                 player->ini.http_buffering_limit,       // no meaning
9861                                                                                                 type,
9862                                                                                                 player->http_file_buffering_path,
9863                                                                                                 (guint64)dur_bytes);
9864                         }
9865
9866                         if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(queue2)) {
9867                                 LOGE("failed to sync queue2 state with parent\n");
9868                                 goto ERROR;
9869                         }
9870
9871                         srcpad = qsrcpad;
9872
9873                         gst_object_unref(GST_OBJECT(sinkpad));
9874
9875                         mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
9876                         mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
9877                 }
9878         }
9879
9880         /* create decodebin */
9881         decodebin = __mmplayer_create_decodebin(player);
9882
9883         if (!decodebin) {
9884                 LOGE("can not create autoplug element\n");
9885                 goto ERROR;
9886         }
9887
9888         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
9889                 LOGE("failed to add decodebin\n");
9890                 goto ERROR;
9891         }
9892
9893         /* to force caps on the decodebin element and avoid reparsing stuff by
9894         * typefind. It also avoids a deadlock in the way typefind activates pads in
9895         * the state change */
9896         g_object_set(decodebin, "sink-caps", caps, NULL);
9897
9898         sinkpad = gst_element_get_static_pad(decodebin, "sink");
9899
9900         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
9901                 LOGE("failed to link decodebin\n");
9902                 goto ERROR;
9903         }
9904
9905         gst_object_unref(GST_OBJECT(sinkpad));
9906
9907         mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
9908         mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
9909
9910         /* set decodebin property about buffer in streaming playback. *
9911          * in case of HLS/DASH, it does not need to have big buffer        *
9912          * because it is kind of adaptive streaming.                  */
9913         if (!MMPLAYER_IS_HTTP_PD(player) && MMPLAYER_IS_HTTP_STREAMING(player)) {
9914                 guint max_size_bytes = MAX_DECODEBIN_BUFFER_BYTES;
9915                 guint64 max_size_time = MAX_DECODEBIN_BUFFER_TIME;
9916                 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
9917
9918                 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
9919                         || MMPLAYER_IS_DASH_STREAMING(player)) {
9920                         max_size_bytes = MAX_DECODEBIN_ADAPTIVE_BUFFER_BYTES;
9921                         max_size_time = MAX_DECODEBIN_ADAPTIVE_BUFFER_TIME;
9922                 }
9923
9924                 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
9925                                                                                         "high-percent", (gint)player->ini.http_buffering_limit,
9926                                                                                         "low-percent", 1,   // 1%
9927                                                                                         "max-size-bytes", max_size_bytes,
9928                                                                                         "max-size-time", (guint64)(max_size_time * GST_SECOND),
9929                                                                                         "max-size-buffers", 0, NULL);  // disable or automatic
9930         }
9931
9932         if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) {
9933                 LOGE("failed to sync decodebin state with parent\n");
9934                 goto ERROR;
9935         }
9936
9937         MMPLAYER_FLEAVE();
9938
9939         return TRUE;
9940
9941 ERROR:
9942
9943         if (sinkpad)
9944                 gst_object_unref(GST_OBJECT(sinkpad));
9945
9946         if (queue2) {
9947                 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
9948                  * You need to explicitly set elements to the NULL state before
9949                  * dropping the final reference, to allow them to clean up.
9950                  */
9951                 gst_element_set_state(queue2, GST_STATE_NULL);
9952
9953                 /* And, it still has a parent "player".
9954                  * You need to let the parent manage the object instead of unreffing the object directly.
9955                  */
9956                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
9957                 gst_object_unref(queue2);
9958                 queue2 = NULL;
9959         }
9960
9961         if (decodebin) {
9962                 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
9963                  * You need to explicitly set elements to the NULL state before
9964                  * dropping the final reference, to allow them to clean up.
9965                  */
9966                 gst_element_set_state(decodebin, GST_STATE_NULL);
9967
9968                 /* And, it still has a parent "player".
9969                  * You need to let the parent manage the object instead of unreffing the object directly.
9970                  */
9971
9972                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
9973                 gst_object_unref(decodebin);
9974                 decodebin = NULL;
9975         }
9976
9977         return FALSE;
9978 }
9979
9980 static int
9981 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
9982 {
9983         MMPLAYER_FENTER();
9984
9985         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9986         MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
9987
9988         LOGD("class : %s, mime : %s \n", factory_class, mime);
9989
9990         /* add missing plugin */
9991         /* NOTE : msl should check missing plugin for image mime type.
9992          * Some motion jpeg clips can have playable audio track.
9993          * So, msl have to play audio after displaying popup written video format not supported.
9994          */
9995         if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
9996                 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
9997                         LOGD("not found demuxer\n");
9998                         player->not_found_demuxer = TRUE;
9999                         player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
10000
10001                         goto DONE;
10002                 }
10003         }
10004
10005         if (!g_strrstr(factory_class, "Demuxer")) {
10006                 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
10007                         LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d\n",
10008                                 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
10009
10010                         /* check that clip have multi tracks or not */
10011                         if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
10012                                 LOGD("video plugin is already linked\n");
10013                         } else {
10014                                 LOGW("add VIDEO to missing plugin\n");
10015                                 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
10016                                 player->unlinked_video_mime = g_strdup_printf("%s", mime);
10017                         }
10018                 } else if (g_str_has_prefix(mime, "audio")) {
10019                         if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
10020                                 LOGD("audio plugin is already linked\n");
10021                         } else {
10022                                 LOGW("add AUDIO to missing plugin\n");
10023                                 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
10024                                 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
10025                         }
10026                 }
10027         }
10028
10029 DONE:
10030         MMPLAYER_FLEAVE();
10031
10032         return MM_ERROR_NONE;
10033 }
10034
10035
10036 static void
10037 __mmplayer_pipeline_complete(GstElement *decodebin,  gpointer data)
10038 {
10039         mm_player_t* player = (mm_player_t*)data;
10040
10041         MMPLAYER_FENTER();
10042
10043         MMPLAYER_RETURN_IF_FAIL(player);
10044
10045         /* remove fakesink. */
10046         if (!__mmplayer_gst_remove_fakesink(player,
10047                                 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
10048                 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
10049                  * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
10050                  * source element are not same. To overcome this situation, this function will called
10051                  * several places and several times. Therefore, this is not an error case.
10052                  */
10053                 return;
10054         }
10055
10056         LOGD("[handle: %p] pipeline has completely constructed", player);
10057
10058         if ((player->ini.async_start) &&
10059                 (player->msg_posted == FALSE) &&
10060                 (player->cmd >= MMPLAYER_COMMAND_START))
10061                 __mmplayer_handle_missed_plugin(player);
10062
10063         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
10064 }
10065
10066 static gboolean
10067 __mmplayer_verify_next_play_path(mm_player_t *player)
10068 {
10069         MMHandleType attrs = 0;
10070         MMPlayerParseProfile profile;
10071         gint uri_idx = 0, check_cnt = 0;
10072         char *uri = NULL;
10073         gint mode = MM_PLAYER_PD_MODE_NONE;
10074         gint video = 0;
10075         gint count = 0;
10076         gint gapless = 0;
10077         guint num_of_list = 0;
10078         static int profile_tv = -1;
10079
10080         MMPLAYER_FENTER();
10081
10082         LOGD("checking for gapless play");
10083
10084         if (player->pipeline->textbin) {
10085                 LOGE("subtitle path is enabled. gapless play is not supported.\n");
10086                 goto ERROR;
10087         }
10088
10089         attrs = MMPLAYER_GET_ATTRS(player);
10090         if (!attrs) {
10091                 LOGE("fail to get attributes.\n");
10092                 goto ERROR;
10093         }
10094
10095         mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
10096
10097         if (__builtin_expect(profile_tv == -1, 0)) {
10098                 char *profileName;
10099                 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
10100                 switch (*profileName) {
10101                 case 't':
10102                 case 'T':
10103                         profile_tv = 1;
10104                         break;
10105                 default:
10106                         profile_tv = 0;
10107                 }
10108                 free(profileName);
10109         }
10110         /* gapless playback is not supported in case of video at TV profile. */
10111         if (profile_tv && video) {
10112                 LOGW("not support video gapless playback");
10113                 goto ERROR;
10114         }
10115
10116         if (mm_attrs_get_int_by_name(attrs, "pd_mode", &mode) == MM_ERROR_NONE) {
10117                 if (mode == TRUE) {
10118                         LOGW("pd mode\n");
10119                         goto ERROR;
10120                 }
10121         }
10122
10123         if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
10124                 LOGE("can not get play count\n");
10125
10126         if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
10127                 LOGE("can not get gapless mode\n");
10128
10129         if (video && !gapless) {
10130                 LOGW("not enabled video gapless playback");
10131                 goto ERROR;
10132         }
10133
10134         if ((count == -1 || count > 1)) /* enable gapless when looping or repeat */
10135                 gapless = 1;
10136
10137         if (!gapless) {
10138                 LOGW("gapless is disabled\n");  /* FIXME: playlist(without gapless) is not implemented. */
10139                 goto ERROR;
10140         }
10141
10142         num_of_list = g_list_length(player->uri_info.uri_list);
10143
10144         LOGD("repeat count = %d, num_of_list = %d\n", count, num_of_list);
10145
10146         if (num_of_list == 0) {
10147                 if (mm_attrs_get_string_by_name(player->attrs, "profile_uri", &uri) != MM_ERROR_NONE) {
10148                         LOGE("can not get profile_uri\n");
10149                         goto ERROR;
10150                 }
10151
10152                 if (!uri) {
10153                         LOGE("uri list is empty.\n");
10154                         goto ERROR;
10155                 }
10156
10157                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10158                 LOGD("add original path : %s ", uri);
10159
10160                 num_of_list = 1;
10161                 uri = NULL;
10162         }
10163
10164         uri_idx = player->uri_info.uri_idx;
10165
10166         while (TRUE) {
10167                 check_cnt++;
10168
10169                 if (check_cnt > num_of_list) {
10170                         LOGE("there is no valid uri.");
10171                         goto ERROR;
10172                 }
10173
10174                 LOGD("uri idx : %d / %d\n", uri_idx, num_of_list);
10175
10176                 if (uri_idx < num_of_list-1) {
10177                         uri_idx++;
10178                 } else {
10179                         if ((count <= 1) && (count != -1)) {
10180                                 LOGD("no repeat.");
10181                                 goto ERROR;
10182                         } else if (count > 1) {
10183                                 /* decrease play count */
10184                                 /* we succeeded to rewind. update play count and then wait for next EOS */
10185                                 count--;
10186
10187                                 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
10188
10189                                 /* commit attribute */
10190                                 if (mmf_attrs_commit(attrs))
10191                                         LOGE("failed to commit attribute\n");
10192                         }
10193
10194                         /* count < 0 : repeat continually */
10195                         uri_idx = 0;
10196                 }
10197
10198                 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
10199                 LOGD("uri idx : %d, uri = %s\n", uri_idx, uri);
10200
10201                 if (uri == NULL) {
10202                         LOGW("next uri does not exist\n");
10203                         continue;
10204                 }
10205
10206                 if (__mmfplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) {
10207                         LOGE("failed to parse profile\n");
10208                         continue;
10209                 }
10210
10211                 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
10212                         (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
10213                         LOGW("uri type is not supported(%d).", profile.uri_type);
10214                         continue;
10215                 }
10216
10217                 break;
10218         }
10219
10220         player->uri_info.uri_idx = uri_idx;
10221         mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
10222
10223         if (mmf_attrs_commit(player->attrs)) {
10224                 LOGE("failed to commit.\n");
10225                 goto ERROR;
10226         }
10227
10228         LOGD("next uri %s(%d)\n", uri, uri_idx);
10229
10230         return TRUE;
10231
10232 ERROR:
10233
10234         LOGE("unable to play next path. EOS will be posted soon.\n");
10235         return FALSE;
10236 }
10237
10238 static void
10239 __mmplayer_initialize_next_play(mm_player_t *player)
10240 {
10241         int i;
10242
10243         MMPLAYER_FENTER();
10244
10245         player->smooth_streaming = FALSE;
10246         player->videodec_linked = 0;
10247         player->audiodec_linked = 0;
10248         player->videosink_linked = 0;
10249         player->audiosink_linked = 0;
10250         player->textsink_linked = 0;
10251         player->is_external_subtitle_present = FALSE;
10252         player->is_external_subtitle_added_now = FALSE;
10253         player->not_supported_codec = MISSING_PLUGIN_NONE;
10254         player->can_support_codec = FOUND_PLUGIN_NONE;
10255         player->pending_seek.is_pending = FALSE;
10256         player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
10257         player->pending_seek.pos = 0;
10258         player->msg_posted = FALSE;
10259         player->has_many_types = FALSE;
10260         player->no_more_pad = FALSE;
10261         player->not_found_demuxer = 0;
10262         player->doing_seek = FALSE;
10263         player->max_audio_channels = 0;
10264         player->is_subtitle_force_drop = FALSE;
10265         player->play_subtitle = FALSE;
10266         player->adjust_subtitle_pos = 0;
10267
10268         player->total_bitrate = 0;
10269         player->total_maximum_bitrate = 0;
10270
10271         _mmplayer_track_initialize(player);
10272         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
10273
10274         for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
10275                 player->bitrate[i] = 0;
10276                 player->maximum_bitrate[i] = 0;
10277         }
10278
10279         if (player->v_stream_caps) {
10280                 gst_caps_unref(player->v_stream_caps);
10281                 player->v_stream_caps = NULL;
10282         }
10283
10284         mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
10285
10286         /* clean found parsers */
10287         if (player->parsers) {
10288                 GList *parsers = player->parsers;
10289                 for (; parsers; parsers = g_list_next(parsers)) {
10290                         gchar *name = parsers->data;
10291                         MMPLAYER_FREEIF(name);
10292                 }
10293                 g_list_free(player->parsers);
10294                 player->parsers = NULL;
10295         }
10296
10297         /* clean found audio decoders */
10298         if (player->audio_decoders) {
10299                 GList *a_dec = player->audio_decoders;
10300                 for (; a_dec; a_dec = g_list_next(a_dec)) {
10301                         gchar *name = a_dec->data;
10302                         MMPLAYER_FREEIF(name);
10303                 }
10304                 g_list_free(player->audio_decoders);
10305                 player->audio_decoders = NULL;
10306         }
10307
10308         MMPLAYER_FLEAVE();
10309 }
10310
10311 static void
10312 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
10313 {
10314         MMPlayerGstElement *mainbin = NULL;
10315         MMMessageParamType msg_param = {0,};
10316         GstElement *element = NULL;
10317         MMHandleType attrs = 0;
10318         char *uri = NULL;
10319         enum MainElementID elemId = MMPLAYER_M_NUM;
10320
10321         MMPLAYER_FENTER();
10322
10323         if ((player == NULL) ||
10324                 (player->pipeline == NULL) ||
10325                 (player->pipeline->mainbin == NULL)) {
10326                 LOGE("player is null.\n");
10327                 goto ERROR;
10328         }
10329
10330         mainbin = player->pipeline->mainbin;
10331         msg_param.code = MM_ERROR_PLAYER_INTERNAL;
10332
10333         attrs = MMPLAYER_GET_ATTRS(player);
10334         if (!attrs) {
10335                 LOGE("fail to get attributes.\n");
10336                 goto ERROR;
10337         }
10338
10339         /* Initialize Player values */
10340         __mmplayer_initialize_next_play(player);
10341
10342         mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
10343
10344         if (__mmfplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) {
10345                 LOGE("failed to parse profile\n");
10346                 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
10347                 goto ERROR;
10348         }
10349
10350         if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
10351                 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
10352                 LOGE("it's dash or hls. not support.");
10353                 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
10354                 goto ERROR;
10355         }
10356
10357         /* setup source */
10358         switch (player->profile.uri_type) {
10359         /* file source */
10360         case MM_PLAYER_URI_TYPE_FILE:
10361         {
10362                 LOGD("using filesrc for 'file://' handler.\n");
10363                 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
10364                         LOGE("failed to get storage info");
10365                         break;
10366                 }
10367
10368                 element = gst_element_factory_make("filesrc", "source");
10369
10370                 if (!element) {
10371                         LOGE("failed to create filesrc\n");
10372                         break;
10373                 }
10374
10375                 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL);     /* uri+7 -> remove "file:// */
10376                 break;
10377         }
10378         case MM_PLAYER_URI_TYPE_URL_HTTP:
10379         {
10380                 gchar *user_agent, *cookies, **cookie_list;
10381                 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
10382                 user_agent = cookies = NULL;
10383                 cookie_list = NULL;
10384
10385                 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
10386                 if (!element) {
10387                         LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
10388                         break;
10389                 }
10390                 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
10391
10392                 /* get attribute */
10393                 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
10394                 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
10395
10396                 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
10397                         LOGD("get timeout from ini\n");
10398                         http_timeout = player->ini.http_timeout;
10399                 }
10400
10401                 /* get attribute */
10402                 SECURE_LOGD("location : %s\n", player->profile.uri);
10403                 SECURE_LOGD("cookies : %s\n", cookies);
10404                 SECURE_LOGD("user_agent :  %s\n", user_agent);
10405                 LOGD("timeout : %d\n", http_timeout);
10406
10407                 /* setting property to streaming source */
10408                 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
10409                 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
10410                 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
10411
10412                 /* parsing cookies */
10413                 if ((cookie_list = util_get_cookie_list((const char*)cookies)))
10414                         g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
10415                 if (user_agent)
10416                         g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL);
10417                 break;
10418         }
10419         default:
10420                 LOGE("not support uri type %d\n", player->profile.uri_type);
10421                 break;
10422         }
10423
10424         if (!element) {
10425                 LOGE("no source element was created.\n");
10426                 goto ERROR;
10427         }
10428
10429         if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
10430                 LOGE("failed to add source element to pipeline\n");
10431                 gst_object_unref(GST_OBJECT(element));
10432                 element = NULL;
10433                 goto ERROR;
10434         }
10435
10436         /* take source element */
10437         mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
10438         mainbin[MMPLAYER_M_SRC].gst = element;
10439
10440         element = NULL;
10441
10442         if (MMPLAYER_IS_HTTP_STREAMING(player)) {
10443                 if (player->streamer == NULL) {
10444                         player->streamer = __mm_player_streaming_create();
10445                         __mm_player_streaming_initialize(player->streamer);
10446                 }
10447
10448                 elemId = MMPLAYER_M_TYPEFIND;
10449                 element = gst_element_factory_make("typefind", "typefinder");
10450                 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
10451                         G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
10452         } else {
10453                 elemId = MMPLAYER_M_AUTOPLUG;
10454                 element = __mmplayer_create_decodebin(player);
10455         }
10456
10457         /* check autoplug element is OK */
10458         if (!element) {
10459                 LOGE("can not create element(%d)\n", elemId);
10460                 goto ERROR;
10461         }
10462
10463         if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
10464                 LOGE("failed to add sinkbin to pipeline\n");
10465                 gst_object_unref(GST_OBJECT(element));
10466                 element = NULL;
10467                 goto ERROR;
10468         }
10469
10470         mainbin[elemId].id = elemId;
10471         mainbin[elemId].gst = element;
10472
10473         if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elemId].gst) == FALSE) {
10474                 LOGE("Failed to link src - autoplug(or typefind)\n");
10475                 goto ERROR;
10476         }
10477
10478         if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
10479                 LOGE("Failed to change state of src element\n");
10480                 goto ERROR;
10481         }
10482
10483         if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
10484                 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
10485                         LOGE("Failed to change state of decodebin\n");
10486                         goto ERROR;
10487                 }
10488         } else {
10489                 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
10490                         LOGE("Failed to change state of src element\n");
10491                         goto ERROR;
10492                 }
10493         }
10494
10495         player->gapless.stream_changed = TRUE;
10496         player->gapless.running = TRUE;
10497         MMPLAYER_FLEAVE();
10498         return;
10499
10500 ERROR:
10501         if (player) {
10502                 MMPLAYER_PLAYBACK_UNLOCK(player);
10503
10504                 if (!player->msg_posted) {
10505                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10506                         player->msg_posted = TRUE;
10507                 }
10508         }
10509         return;
10510 }
10511
10512 static gboolean
10513 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
10514 {
10515         mm_player_selector_t *selector = &player->selector[type];
10516         MMPlayerGstElement *sinkbin = NULL;
10517         enum MainElementID selectorId = MMPLAYER_M_NUM;
10518         enum MainElementID sinkId = MMPLAYER_M_NUM;
10519         GstPad *srcpad = NULL;
10520         GstPad *sinkpad = NULL;
10521         gboolean send_notice = FALSE;
10522
10523         MMPLAYER_FENTER();
10524         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
10525
10526         LOGD("type %d", type);
10527
10528         switch (type) {
10529         case MM_PLAYER_TRACK_TYPE_AUDIO:
10530                 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
10531                 sinkId = MMPLAYER_A_BIN;
10532                 sinkbin = player->pipeline->audiobin;
10533                 break;
10534         case MM_PLAYER_TRACK_TYPE_VIDEO:
10535                 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
10536                 sinkId = MMPLAYER_V_BIN;
10537                 sinkbin = player->pipeline->videobin;
10538                 send_notice = TRUE;
10539                 break;
10540         case MM_PLAYER_TRACK_TYPE_TEXT:
10541                 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
10542                 sinkId = MMPLAYER_T_BIN;
10543                 sinkbin = player->pipeline->textbin;
10544                 break;
10545         default:
10546                 LOGE("requested type is not supportable");
10547                 return FALSE;
10548                 break;
10549         }
10550
10551         if (player->pipeline->mainbin[selectorId].gst) {
10552                 gint n;
10553
10554                 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
10555
10556                 if (selector->event_probe_id != 0)
10557                         gst_pad_remove_probe(srcpad, selector->event_probe_id);
10558                 selector->event_probe_id = 0;
10559
10560                 if ((sinkbin) && (sinkbin[sinkId].gst)) {
10561                         sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
10562
10563                         if (srcpad && sinkpad) {
10564                                 /* after getting drained signal there is no data flows, so no need to do pad_block */
10565                                 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
10566                                 gst_pad_unlink(srcpad, sinkpad);
10567
10568                                 /* send custom event to sink pad to handle it at video sink */
10569                                 if (send_notice) {
10570                                         LOGD("send custom event to sinkpad");
10571                                         GstStructure *s = gst_structure_new_empty("application/flush-buffer");
10572                                         GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
10573                                         gst_pad_send_event(sinkpad, event);
10574                                 }
10575                         }
10576
10577                         gst_object_unref(sinkpad);
10578                         sinkpad = NULL;
10579                 }
10580                 gst_object_unref(srcpad);
10581                 srcpad = NULL;
10582
10583                 LOGD("selector release");
10584
10585                 /* release and unref requests pad from the selector */
10586                 for (n = 0; n < selector->channels->len; n++) {
10587                         GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
10588                         gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
10589                 }
10590                 g_ptr_array_set_size(selector->channels, 0);
10591
10592                 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
10593                 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
10594
10595                 player->pipeline->mainbin[selectorId].gst = NULL;
10596                 selector = NULL;
10597         }
10598
10599         return TRUE;
10600 }
10601
10602 static void
10603 __mmplayer_deactivate_old_path(mm_player_t *player)
10604 {
10605         MMPLAYER_FENTER();
10606         MMPLAYER_RETURN_IF_FAIL(player);
10607
10608         if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
10609                 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
10610                 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
10611                 LOGE("deactivate selector error");
10612                 goto ERROR;
10613         }
10614
10615         _mmplayer_track_destroy(player);
10616         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
10617
10618         if (player->streamer) {
10619                 __mm_player_streaming_deinitialize(player->streamer);
10620                 __mm_player_streaming_destroy(player->streamer);
10621                 player->streamer = NULL;
10622         }
10623
10624         MMPLAYER_PLAYBACK_LOCK(player);
10625         MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
10626
10627         MMPLAYER_FLEAVE();
10628         return;
10629
10630 ERROR:
10631
10632         if (!player->msg_posted) {
10633                 MMMessageParamType msg = {0,};
10634
10635                 /*post error*/
10636                 msg.code = MM_ERROR_PLAYER_INTERNAL;
10637                 LOGE("next_uri_play> deactivate error");
10638
10639                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
10640                 player->msg_posted = TRUE;
10641         }
10642         return;
10643 }
10644
10645 int _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char* file_path)
10646 {
10647         int result = MM_ERROR_NONE;
10648         mm_player_t* player = (mm_player_t*) hplayer;
10649         MMPLAYER_FENTER();
10650
10651         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10652
10653         if (file_path) {
10654                 player->http_file_buffering_path = (gchar*)file_path;
10655                 LOGD("temp file path: %s\n", player->http_file_buffering_path);
10656         }
10657         MMPLAYER_FLEAVE();
10658         return result;
10659 }
10660
10661 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
10662 {
10663         int result = MM_ERROR_NONE;
10664         mm_player_t* player = (mm_player_t*) hplayer;
10665         MMPLAYER_FENTER();
10666
10667         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10668
10669         mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
10670         if (mmf_attrs_commit(player->attrs)) {
10671                 LOGE("failed to commit the original uri.\n");
10672                 result = MM_ERROR_PLAYER_INTERNAL;
10673         } else {
10674                 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
10675                         LOGE("failed to add the original uri in the uri list.\n");
10676         }
10677
10678         MMPLAYER_FLEAVE();
10679         return result;
10680 }
10681
10682 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
10683 {
10684         mm_player_t* player = (mm_player_t*) hplayer;
10685         guint num_of_list = 0;
10686
10687         MMPLAYER_FENTER();
10688
10689         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10690         MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
10691
10692         if (player->pipeline && player->pipeline->textbin) {
10693                 LOGE("subtitle path is enabled.\n");
10694                 return MM_ERROR_PLAYER_INVALID_STATE;
10695         }
10696
10697         num_of_list = g_list_length(player->uri_info.uri_list);
10698
10699         if (is_first_path == TRUE) {
10700                 if (num_of_list == 0) {
10701                         player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10702                         LOGD("add original path : %s", uri);
10703                 } else {
10704                         player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
10705                         player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
10706
10707                         LOGD("change original path : %s", uri);
10708                 }
10709         } else {
10710                 MMHandleType attrs = 0;
10711                 attrs = MMPLAYER_GET_ATTRS(player);
10712
10713                 if (num_of_list == 0) {
10714                         char *original_uri = NULL;
10715
10716                         if (attrs) {
10717                                 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
10718
10719                                 if (!original_uri) {
10720                                         LOGE("there is no original uri.");
10721                                         return MM_ERROR_PLAYER_INVALID_STATE;
10722                                 }
10723
10724                                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
10725                                 player->uri_info.uri_idx = 0;
10726
10727                                 LOGD("add original path at first : %s(%d)", original_uri);
10728                         }
10729                 }
10730
10731                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10732                 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
10733         }
10734
10735         MMPLAYER_FLEAVE();
10736         return MM_ERROR_NONE;
10737 }
10738
10739 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
10740 {
10741         mm_player_t* player = (mm_player_t*) hplayer;
10742         char *next_uri = NULL;
10743         guint num_of_list = 0;
10744
10745         MMPLAYER_FENTER();
10746         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10747
10748         num_of_list = g_list_length(player->uri_info.uri_list);
10749
10750         if (num_of_list > 0) {
10751                 gint uri_idx = player->uri_info.uri_idx;
10752
10753                 if (uri_idx < num_of_list-1)
10754                         uri_idx++;
10755                 else
10756                         uri_idx = 0;
10757
10758                 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
10759                 LOGE("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
10760
10761                 *uri = g_strdup(next_uri);
10762         }
10763
10764         MMPLAYER_FLEAVE();
10765         return MM_ERROR_NONE;
10766 }
10767
10768 static void
10769 __mmplayer_gst_decode_unknown_type(GstElement *elem,  GstPad* pad,
10770 GstCaps *caps, gpointer data)
10771 {
10772         mm_player_t* player = (mm_player_t*)data;
10773         const gchar* klass = NULL;
10774         const gchar* mime = NULL;
10775         gchar* caps_str = NULL;
10776
10777         klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
10778         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10779         caps_str = gst_caps_to_string(caps);
10780
10781         LOGW("unknown type of caps : %s from %s",
10782                                         caps_str, GST_ELEMENT_NAME(elem));
10783
10784         MMPLAYER_FREEIF(caps_str);
10785
10786         /* There is no available codec. */
10787         __mmplayer_check_not_supported_codec(player, klass, mime);
10788 }
10789
10790 static gboolean
10791 __mmplayer_gst_decode_autoplug_continue(GstElement *bin,  GstPad* pad,
10792 GstCaps * caps,  gpointer data)
10793 {
10794         mm_player_t* player = (mm_player_t*)data;
10795         const char* mime = NULL;
10796         gboolean ret = TRUE;
10797
10798         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
10799         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10800
10801         if (g_str_has_prefix(mime, "audio")) {
10802                 GstStructure* caps_structure = NULL;
10803                 gint samplerate = 0;
10804                 gint channels = 0;
10805                 gchar *caps_str = NULL;
10806
10807                 caps_structure = gst_caps_get_structure(caps, 0);
10808                 gst_structure_get_int(caps_structure, "rate", &samplerate);
10809                 gst_structure_get_int(caps_structure, "channels", &channels);
10810
10811                 if ((channels > 0 && samplerate == 0)) {
10812                         LOGD("exclude audio...");
10813                         ret = FALSE;
10814                 }
10815
10816                 caps_str = gst_caps_to_string(caps);
10817                 /* set it directly because not sent by TAG */
10818                 if (g_strrstr(caps_str, "mobile-xmf"))
10819                         mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
10820                 MMPLAYER_FREEIF(caps_str);
10821         } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
10822                 MMMessageParamType msg_param;
10823                 memset(&msg_param, 0, sizeof(MMMessageParamType));
10824                 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
10825                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10826                 LOGD("video file is not supported on this device");
10827                 ret = FALSE;
10828         } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
10829                 LOGD("already video linked");
10830                 ret = FALSE;
10831         } else {
10832                 LOGD("found new stream");
10833         }
10834
10835         return ret;
10836 }
10837
10838 static int
10839 __mmplayer_check_codec_info(mm_player_t* player, const char* klass, GstCaps* caps, char* factory_name)
10840 {
10841         int ret = MM_ERROR_NONE;
10842         int idx = 0;
10843         int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
10844
10845         if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
10846                 GstStructure* str = NULL;
10847                 gint channels = 0;
10848                 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
10849
10850                 LOGD("audio codec type: %d", codec_type);
10851                 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
10852                         /* sw codec will be skipped */
10853                         for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
10854                                 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
10855                                         LOGW("skipping sw acodec:[%s] by codec type", factory_name);
10856                                         ret = MM_ERROR_PLAYER_INTERNAL;
10857                                         goto DONE;
10858                                 }
10859                         }
10860                 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
10861                         /* hw codec will be skipped */
10862                         if (strcmp(player->ini.audiocodec_element_hw, "") &&
10863                             g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
10864                                 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
10865                                 ret = MM_ERROR_PLAYER_INTERNAL;
10866                                 goto DONE;
10867                         }
10868                 }
10869
10870                 str = gst_caps_get_structure(caps, 0);
10871                 if (str) {
10872                         gst_structure_get_int(str, "channels", &channels);
10873
10874                         LOGD("check audio ch : %d %d\n", player->max_audio_channels, channels);
10875                         if (player->max_audio_channels < channels)
10876                                 player->max_audio_channels = channels;
10877                 }
10878                 /* set stream information */
10879                 if (!player->audiodec_linked)
10880                         __mmplayer_set_audio_attrs(player, caps);
10881
10882                 /* update codec info */
10883                 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
10884                 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
10885                 player->audiodec_linked = 1;
10886
10887         } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
10888
10889                 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
10890
10891                 LOGD("video codec type: %d", codec_type);
10892                 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
10893                         /* sw codec is skipped */
10894                         for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
10895                                 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
10896                                         LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
10897                                         ret = MM_ERROR_PLAYER_INTERNAL;
10898                                         goto DONE;
10899                                 }
10900                         }
10901                 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
10902                         /* hw codec is skipped */
10903                         if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
10904                                 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
10905                                 ret = MM_ERROR_PLAYER_INTERNAL;
10906                                 goto DONE;
10907                         }
10908                 }
10909
10910                 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
10911                         (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
10912
10913                         /* mark video decoder for acquire */
10914                         if (player->video_decoder_resource == NULL) {
10915                                 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
10916                                                 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
10917                                                 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
10918                                                 &player->video_decoder_resource)
10919                                         != MM_RESOURCE_MANAGER_ERROR_NONE) {
10920                                         LOGE("could not mark video_decoder resource for acquire");
10921                                         ret = MM_ERROR_PLAYER_INTERNAL;
10922                                         goto DONE;
10923                                 }
10924                         } else {
10925                                 LOGW("video decoder resource is already acquired, skip it.");
10926                                 ret = MM_ERROR_PLAYER_INTERNAL;
10927                                 goto DONE;
10928                         }
10929
10930                         player->interrupted_by_resource = FALSE;
10931                         /* acquire resources for video playing */
10932                         if (mm_resource_manager_commit(player->resource_manager)
10933                                         != MM_RESOURCE_MANAGER_ERROR_NONE) {
10934                                 LOGE("could not acquire resources for video decoding\n");
10935                                 ret = MM_ERROR_PLAYER_INTERNAL;
10936                                 goto DONE;
10937                         }
10938                 }
10939
10940                 /* update codec info */
10941                 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
10942                 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
10943                 player->videodec_linked = 1;
10944         }
10945
10946 DONE:
10947         return ret;
10948 }
10949
10950 static gint
10951 __mmplayer_gst_decode_autoplug_select(GstElement *bin,  GstPad* pad,
10952 GstCaps* caps, GstElementFactory* factory, gpointer data)
10953 {
10954         /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
10955          We are defining our own and will be removed when it actually exposed */
10956         typedef enum {
10957                 GST_AUTOPLUG_SELECT_TRY,
10958                 GST_AUTOPLUG_SELECT_EXPOSE,
10959                 GST_AUTOPLUG_SELECT_SKIP
10960         } GstAutoplugSelectResult;
10961
10962         GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
10963         mm_player_t* player = (mm_player_t*)data;
10964
10965         gchar* factory_name = NULL;
10966         gchar* caps_str = NULL;
10967         const gchar* klass = NULL;
10968         gint idx = 0;
10969
10970         factory_name = GST_OBJECT_NAME(factory);
10971         klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
10972         caps_str = gst_caps_to_string(caps);
10973
10974         LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
10975
10976         /* store type string */
10977         if (player->type == NULL) {
10978                 player->type = gst_caps_to_string(caps);
10979                 __mmplayer_update_content_type_info(player);
10980         }
10981
10982         /* filtering exclude keyword */
10983         for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
10984                 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
10985                         LOGW("skipping [%s] by exculde keyword [%s]\n",
10986                                         factory_name, player->ini.exclude_element_keyword[idx]);
10987
10988                         result = GST_AUTOPLUG_SELECT_SKIP;
10989                         goto DONE;
10990                 }
10991         }
10992
10993         /* exclude webm format */
10994         /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
10995          * because webm format is not supportable.
10996          * If webm is disabled in "autoplug-continue", there is no state change
10997          * failure or error because the decodebin will expose the pad directly.
10998          * It make MSL invoke _prepare_async_callback.
10999          * So, we need to disable webm format in "autoplug-select" */
11000         if (caps_str && strstr(caps_str, "webm")) {
11001                 LOGW("webm is not supported");
11002                 result = GST_AUTOPLUG_SELECT_SKIP;
11003                 goto DONE;
11004         }
11005
11006         /* check factory class for filtering */
11007         /* NOTE : msl don't need to use image plugins.
11008          * So, those plugins should be skipped for error handling.
11009          */
11010         if (g_strrstr(klass, "Codec/Decoder/Image")) {
11011                 LOGD("skipping [%s] by not required\n", factory_name);
11012                 result = GST_AUTOPLUG_SELECT_SKIP;
11013                 goto DONE;
11014         }
11015
11016         if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
11017                 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
11018                 // TO CHECK : subtitle if needed, add subparse exception.
11019                 LOGD("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
11020                 result = GST_AUTOPLUG_SELECT_SKIP;
11021                 goto DONE;
11022         }
11023
11024         if (g_strrstr(factory_name, "mpegpsdemux")) {
11025                 LOGD("skipping PS container - not support\n");
11026                 result = GST_AUTOPLUG_SELECT_SKIP;
11027                 goto DONE;
11028         }
11029
11030         if (g_strrstr(factory_name, "mssdemux"))
11031                 player->smooth_streaming = TRUE;
11032
11033         if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
11034                 (g_strrstr(klass, "Codec/Decoder/Video"))) {
11035                 gint stype = 0;
11036                 gint width = 0;
11037                 GstStructure *str = NULL;
11038                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
11039
11040                 /* don't make video because of not required */
11041                 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
11042                         (player->set_mode.media_packet_video_stream == FALSE)) {
11043                         LOGD("no video because it's not required. -> return expose");
11044                         result = GST_AUTOPLUG_SELECT_EXPOSE;
11045                         goto DONE;
11046                 }
11047
11048                 /* get w/h for omx state-tune */
11049                 /* FIXME: deprecated? */
11050                 str = gst_caps_get_structure(caps, 0);
11051                 gst_structure_get_int(str, "width", &width);
11052
11053                 if (width != 0) {
11054                         if (player->v_stream_caps) {
11055                                 gst_caps_unref(player->v_stream_caps);
11056                                 player->v_stream_caps = NULL;
11057                         }
11058
11059                         player->v_stream_caps = gst_caps_copy(caps);
11060                         LOGD("take caps for video state tune");
11061                         MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
11062                 }
11063         }
11064
11065         if (g_strrstr(klass, "Codec/Decoder")) {
11066                 if (__mmplayer_check_codec_info(player, klass, caps, factory_name) != MM_ERROR_NONE) {
11067                         LOGD("skipping %s codec", factory_name);
11068                         result = GST_AUTOPLUG_SELECT_SKIP;
11069                         goto DONE;
11070                 }
11071         }
11072
11073 DONE:
11074         MMPLAYER_FREEIF(caps_str);
11075
11076         return result;
11077 }
11078
11079 static void
11080 __mmplayer_gst_decode_pad_removed(GstElement *elem,  GstPad* new_pad,
11081 gpointer data)
11082 {
11083         //mm_player_t* player = (mm_player_t*)data;
11084         GstCaps* caps = NULL;
11085
11086         LOGD("[Decodebin2] pad-removed signal\n");
11087
11088         caps = gst_pad_query_caps(new_pad, NULL);
11089         if (caps) {
11090                 gchar* caps_str = NULL;
11091                 caps_str = gst_caps_to_string(caps);
11092
11093                 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
11094
11095                 MMPLAYER_FREEIF(caps_str);
11096                 gst_caps_unref(caps);
11097         }
11098 }
11099
11100 static void
11101 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
11102 {
11103         mm_player_t* player = (mm_player_t*)data;
11104         GstIterator *iter = NULL;
11105         GValue item = { 0, };
11106         GstPad *pad = NULL;
11107         gboolean done = FALSE;
11108         gboolean is_all_drained = TRUE;
11109
11110         MMPLAYER_FENTER();
11111         MMPLAYER_RETURN_IF_FAIL(player);
11112
11113         LOGD("__mmplayer_gst_decode_drained");
11114
11115         if (player->use_deinterleave == TRUE) {
11116                 LOGD("group playing mode.");
11117                 return;
11118         }
11119
11120         if (!MMPLAYER_CMD_TRYLOCK(player)) {
11121                 LOGW("Fail to get cmd lock");
11122                 return;
11123         }
11124
11125         if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
11126                 !__mmplayer_verify_next_play_path(player)) {
11127                 LOGD("decoding is finished.");
11128                 __mmplayer_reset_gapless_state(player);
11129                 MMPLAYER_CMD_UNLOCK(player);
11130                 return;
11131         }
11132
11133         player->gapless.reconfigure = TRUE;
11134
11135         /* check decodebin src pads whether they received EOS or not */
11136         iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11137
11138         while (!done) {
11139                 switch (gst_iterator_next(iter, &item)) {
11140                 case GST_ITERATOR_OK:
11141                         pad = g_value_get_object(&item);
11142                         if (pad && !GST_PAD_IS_EOS(pad)) {
11143                                 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
11144                                 is_all_drained = FALSE;
11145                                 break;
11146                         }
11147                         g_value_reset(&item);
11148                         break;
11149                 case GST_ITERATOR_RESYNC:
11150                         gst_iterator_resync(iter);
11151                         break;
11152                 case GST_ITERATOR_ERROR:
11153                 case GST_ITERATOR_DONE:
11154                         done = TRUE;
11155                         break;
11156                 }
11157         }
11158         g_value_unset(&item);
11159         gst_iterator_free(iter);
11160
11161         if (!is_all_drained) {
11162                 LOGD("Wait util the all pads get EOS.");
11163                 MMPLAYER_CMD_UNLOCK(player);
11164                 MMPLAYER_FLEAVE();
11165                 return;
11166         }
11167
11168         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
11169         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
11170
11171         /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
11172         MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
11173         __mmplayer_deactivate_old_path(player);
11174         MMPLAYER_CMD_UNLOCK(player);
11175
11176         MMPLAYER_FLEAVE();
11177 }
11178
11179 static void
11180 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
11181 {
11182         mm_player_t* player = (mm_player_t*)data;
11183         const gchar* klass = NULL;
11184         gchar* factory_name = NULL;
11185
11186         klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
11187         factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
11188
11189         LOGD("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
11190
11191         if (__mmplayer_add_dump_buffer_probe(player, element))
11192                 LOGD("add buffer probe");
11193
11194         //<-
11195         if (g_strrstr(klass, "Codec/Decoder/Audio")) {
11196                 gchar* selected = NULL;
11197                 selected = g_strdup(GST_ELEMENT_NAME(element));
11198                 player->audio_decoders = g_list_append(player->audio_decoders, selected);
11199         }
11200         //-> temp code
11201
11202         if (g_strrstr(klass, "Parser")) {
11203                 gchar* selected = NULL;
11204
11205                 selected = g_strdup(factory_name);
11206                 player->parsers = g_list_append(player->parsers, selected);
11207         }
11208
11209         if (g_strrstr(klass, "Demuxer/Adaptive")) {
11210                 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
11211                 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
11212
11213                 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
11214                                                 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
11215
11216                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
11217                                                 "max-bandwidth", player->adaptive_info.limit.bandwidth,
11218                                                 "max-video-width", player->adaptive_info.limit.width,
11219                                                 "max-video-height", player->adaptive_info.limit.height, NULL);
11220
11221         } else if (g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) {
11222                 /* FIXIT : first value will be overwritten if there's more
11223                  * than 1 demuxer/parser
11224                  */
11225
11226                 //LOGD("plugged element is demuxer. take it\n");
11227                 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
11228                 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
11229
11230                 /*Added for multi audio support */ // Q. del?
11231                 if (g_strrstr(klass, "Demux")) {
11232                         player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
11233                         player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].gst = element;
11234                 }
11235         }
11236
11237         if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
11238                 int surface_type = 0;
11239
11240                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
11241         }
11242
11243         // to support trust-zone only
11244         if (g_strrstr(factory_name, "asfdemux")) {
11245                 LOGD("set file-location %s\n", player->profile.uri);
11246                 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
11247
11248                 if (player->video_hub_download_mode == TRUE)
11249                         g_object_set(G_OBJECT(element), "downloading-mode", player->video_hub_download_mode, NULL);
11250         } else if (g_strrstr(factory_name, "legacyh264parse")) {
11251                 LOGD("[%s] output-format to legacyh264parse\n", "mssdemux");
11252                 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
11253         } else if (g_strrstr(factory_name, "mpegaudioparse")) {
11254                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
11255                         (__mmplayer_is_only_mp3_type(player->type))) {
11256                         LOGD("[mpegaudioparse] set streaming pull mode.");
11257                         g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
11258                 }
11259         } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
11260                 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
11261         }
11262
11263         if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
11264                 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
11265                 LOGD("plugged element is multiqueue. take it\n");
11266
11267                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
11268                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
11269
11270                 if (!MMPLAYER_IS_HTTP_PD(player) &&
11271                         ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
11272                         (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)))) {
11273                         /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
11274                         __mm_player_streaming_set_multiqueue(player->streamer,
11275                                 element,
11276                                 TRUE,
11277                                 player->ini.http_buffering_time,
11278                                 1.0,
11279                                 player->ini.http_buffering_limit);
11280
11281                         __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11282                 }
11283         }
11284
11285         return;
11286 }
11287
11288 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player)
11289 {
11290         MMPLAYER_FENTER();
11291         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11292
11293         if (MMPLAYER_IS_STREAMING(player))
11294                 return FALSE;
11295
11296         /* This callback can be set to music player only. */
11297         if ((player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO) {
11298                 LOGW("audio callback is not supported for video");
11299                 return FALSE;
11300         }
11301
11302         if (player->audio_stream_cb) {
11303                 GstPad *pad = NULL;
11304
11305                 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
11306
11307                 if (!pad) {
11308                         LOGE("failed to get sink pad from audiosink to probe data\n");
11309                         return FALSE;
11310                 }
11311                 player->audio_cb_probe_id = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
11312                         __mmplayer_audio_stream_probe, player, NULL);
11313
11314                 gst_object_unref(pad);
11315
11316                 pad = NULL;
11317         } else {
11318                 LOGE("There is no audio callback to configure.\n");
11319                 return FALSE;
11320         }
11321
11322         MMPLAYER_FLEAVE();
11323
11324         return TRUE;
11325 }
11326
11327 static void
11328 __mmplayer_release_misc(mm_player_t* player)
11329 {
11330         int i;
11331         bool cur_mode = player->set_mode.rich_audio;
11332         MMPLAYER_FENTER();
11333
11334         MMPLAYER_RETURN_IF_FAIL(player);
11335
11336         player->video_stream_cb = NULL;
11337         player->video_stream_cb_user_param = NULL;
11338         player->video_stream_prerolled = FALSE;
11339
11340         player->audio_stream_cb = NULL;
11341         player->audio_stream_render_cb_ex = NULL;
11342         player->audio_stream_cb_user_param = NULL;
11343         player->audio_stream_sink_sync = false;
11344
11345         player->video_stream_changed_cb = NULL;
11346         player->video_stream_changed_cb_user_param = NULL;
11347
11348         player->audio_stream_changed_cb = NULL;
11349         player->audio_stream_changed_cb_user_param = NULL;
11350
11351         player->sent_bos = FALSE;
11352         player->playback_rate = DEFAULT_PLAYBACK_RATE;
11353
11354         player->doing_seek = FALSE;
11355
11356         player->total_bitrate = 0;
11357         player->total_maximum_bitrate = 0;
11358
11359         player->not_found_demuxer = 0;
11360
11361         player->last_position = 0;
11362         player->duration = 0;
11363         player->http_content_size = 0;
11364         player->not_supported_codec = MISSING_PLUGIN_NONE;
11365         player->can_support_codec = FOUND_PLUGIN_NONE;
11366         player->pending_seek.is_pending = FALSE;
11367         player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
11368         player->pending_seek.pos = 0;
11369         player->msg_posted = FALSE;
11370         player->has_many_types = FALSE;
11371         player->max_audio_channels = 0;
11372         player->video_share_api_delta = 0;
11373         player->video_share_clock_delta = 0;
11374         player->is_subtitle_force_drop = FALSE;
11375         player->play_subtitle = FALSE;
11376         player->adjust_subtitle_pos = 0;
11377         player->last_multiwin_status = FALSE;
11378         player->has_closed_caption = FALSE;
11379         player->set_mode.media_packet_video_stream = FALSE;
11380         player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
11381         memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
11382         /* recover mode */
11383         player->set_mode.rich_audio = cur_mode;
11384
11385         for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
11386                 player->bitrate[i] = 0;
11387                 player->maximum_bitrate[i] = 0;
11388         }
11389
11390         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
11391
11392         /* remove media stream cb(appsrc cb) */
11393         for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
11394                 player->media_stream_buffer_status_cb[i] = NULL;
11395                 player->media_stream_seek_data_cb[i] = NULL;
11396                 player->buffer_cb_user_param[i] = NULL;
11397                 player->seek_cb_user_param[i] = NULL;
11398         }
11399         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
11400
11401         /* free memory related to audio effect */
11402         MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
11403
11404         if (player->adaptive_info.var_list) {
11405                 g_list_free_full(player->adaptive_info.var_list, g_free);
11406                 player->adaptive_info.var_list = NULL;
11407         }
11408
11409         player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11410         player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11411         player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11412
11413         /* Reset video360 settings to their defaults in case if the pipeline is to be
11414          * re-created.
11415          * */
11416         player->video360_metadata.is_spherical = -1;
11417         player->is_openal_plugin_used = FALSE;
11418
11419         player->is_content_spherical = FALSE;
11420         player->is_video360_enabled = TRUE;
11421         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
11422         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
11423         player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
11424         player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
11425         player->video360_zoom = 1.0f;
11426         player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
11427         player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
11428
11429         player->sound.rg_enable = false;
11430
11431         MMPLAYER_FLEAVE();
11432 }
11433
11434 static void
11435 __mmplayer_release_misc_post(mm_player_t* player)
11436 {
11437         char *original_uri = NULL;
11438         MMPLAYER_FENTER();
11439
11440         /* player->pipeline is already released before. */
11441
11442         MMPLAYER_RETURN_IF_FAIL(player);
11443
11444         mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
11445
11446         /* clean found parsers */
11447         if (player->parsers) {
11448                 GList *parsers = player->parsers;
11449                 for (; parsers; parsers = g_list_next(parsers)) {
11450                         gchar *name = parsers->data;
11451                         MMPLAYER_FREEIF(name);
11452                 }
11453                 g_list_free(player->parsers);
11454                 player->parsers = NULL;
11455         }
11456
11457         /* clean found audio decoders */
11458         if (player->audio_decoders) {
11459                 GList *a_dec = player->audio_decoders;
11460                 for (; a_dec; a_dec = g_list_next(a_dec)) {
11461                         gchar *name = a_dec->data;
11462                         MMPLAYER_FREEIF(name);
11463                 }
11464                 g_list_free(player->audio_decoders);
11465                 player->audio_decoders = NULL;
11466         }
11467
11468         /* clean the uri list except original uri */
11469         if (player->uri_info.uri_list) {
11470                 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
11471
11472                 if (player->attrs) {
11473                         mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
11474                         LOGD("restore original uri = %s\n", original_uri);
11475
11476                         if (mmf_attrs_commit(player->attrs))
11477                                 LOGE("failed to commit the original uri.\n");
11478                 }
11479
11480                 GList *uri_list = player->uri_info.uri_list;
11481                 for (; uri_list; uri_list = g_list_next(uri_list)) {
11482                         gchar *uri = uri_list->data;
11483                         MMPLAYER_FREEIF(uri);
11484                 }
11485                 g_list_free(player->uri_info.uri_list);
11486                 player->uri_info.uri_list = NULL;
11487         }
11488
11489         /* clear the audio stream buffer list */
11490         __mmplayer_audio_stream_clear_buffer(player, FALSE);
11491
11492         /* clear the video stream bo list */
11493         __mmplayer_video_stream_destroy_bo_list(player);
11494         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
11495
11496         if (player->profile.input_mem.buf) {
11497                 free(player->profile.input_mem.buf);
11498                 player->profile.input_mem.buf = NULL;
11499         }
11500         player->profile.input_mem.len = 0;
11501         player->profile.input_mem.offset = 0;
11502
11503         player->uri_info.uri_idx = 0;
11504         MMPLAYER_FLEAVE();
11505 }
11506
11507 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name)
11508 {
11509         GstElement *element = NULL;
11510         GstPad *sinkpad;
11511
11512         LOGD("creating %s to plug\n", name);
11513
11514         element = gst_element_factory_make(name, NULL);
11515         if (!element) {
11516                 LOGE("failed to create queue\n");
11517                 return NULL;
11518         }
11519
11520         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(element, GST_STATE_READY)) {
11521                 LOGE("failed to set state READY to %s\n", name);
11522                 gst_object_unref(element);
11523                 return NULL;
11524         }
11525
11526         if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), element)) {
11527                 LOGE("failed to add %s\n", name);
11528                 gst_object_unref(element);
11529                 return NULL;
11530         }
11531
11532         sinkpad = gst_element_get_static_pad(element, "sink");
11533
11534         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
11535                 LOGE("failed to link %s\n", name);
11536                 gst_object_unref(sinkpad);
11537                 gst_object_unref(element);
11538                 return NULL;
11539         }
11540
11541         LOGD("linked %s to pipeline successfully\n", name);
11542
11543         gst_object_unref(sinkpad);
11544
11545         return element;
11546 }
11547
11548 gboolean
11549 __mmplayer_check_subtitle(mm_player_t* player)
11550 {
11551         MMHandleType attrs = 0;
11552         char *subtitle_uri = NULL;
11553
11554         MMPLAYER_FENTER();
11555
11556         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11557
11558         /* get subtitle attribute */
11559         attrs = MMPLAYER_GET_ATTRS(player);
11560         if (!attrs)
11561                 return FALSE;
11562
11563         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
11564         if (!subtitle_uri || !strlen(subtitle_uri))
11565                 return FALSE;
11566
11567         LOGD("subtite uri is %s[%d]\n", subtitle_uri, strlen(subtitle_uri));
11568         player->is_external_subtitle_present = TRUE;
11569
11570         MMPLAYER_FLEAVE();
11571
11572         return TRUE;
11573 }
11574
11575 static gboolean
11576 __mmplayer_can_extract_pcm(mm_player_t* player)
11577 {
11578         MMHandleType attrs = 0;
11579         gboolean sound_extraction = FALSE;
11580
11581         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11582
11583         attrs = MMPLAYER_GET_ATTRS(player);
11584         if (!attrs) {
11585                 LOGE("fail to get attributes.");
11586                 return FALSE;
11587         }
11588
11589         /* get sound_extraction property */
11590         mm_attrs_get_int_by_name(attrs, "pcm_extraction", &sound_extraction);
11591
11592         if (!sound_extraction) {
11593                 LOGD("checking pcm extraction mode : %d ", sound_extraction);
11594                 return FALSE;
11595         }
11596
11597         return TRUE;
11598 }
11599
11600 static gboolean
11601 __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message)
11602 {
11603         LOGD("\n");
11604         MMMessageParamType msg_param;
11605         gchar *msg_src_element = NULL;
11606         GstStructure *s = NULL;
11607         guint error_id = 0;
11608         gchar *error_string = NULL;
11609
11610         MMPLAYER_FENTER();
11611
11612         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11613         MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
11614
11615         s = gst_structure_copy(gst_message_get_structure(message));
11616
11617
11618         if (!gst_structure_get_uint(s, "error_id", &error_id))
11619                 error_id = MMPLAYER_STREAMING_ERROR_NONE;
11620
11621         switch (error_id) {
11622         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
11623                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
11624                 break;
11625         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
11626                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
11627                 break;
11628         case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
11629                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
11630                 break;
11631         case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
11632                 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
11633                 break;
11634         case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
11635                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
11636                 break;
11637         case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
11638                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
11639                 break;
11640         case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
11641                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
11642                 break;
11643         case MMPLAYER_STREAMING_ERROR_INVALID_URL:
11644                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
11645                 break;
11646         case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
11647                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
11648                 break;
11649         case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
11650                 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
11651                 break;
11652         case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
11653                 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
11654                 break;
11655         case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
11656                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
11657                 break;
11658         case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
11659                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
11660                 break;
11661         case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
11662                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
11663                 break;
11664         case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
11665                 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
11666                 break;
11667         case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
11668                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
11669                 break;
11670         case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
11671                 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
11672                 break;
11673         case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
11674                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
11675                 break;
11676         case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
11677                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
11678                 break;
11679         case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
11680                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
11681                 break;
11682         case MMPLAYER_STREAMING_ERROR_GONE:
11683                 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
11684                 break;
11685         case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
11686                 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
11687                 break;
11688         case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
11689                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
11690                 break;
11691         case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
11692                 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
11693                 break;
11694         case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
11695                 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
11696                 break;
11697         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
11698                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
11699                 break;
11700         case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
11701                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
11702                 break;
11703         case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
11704                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
11705                 break;
11706         case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
11707                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
11708                 break;
11709         case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
11710                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
11711                 break;
11712         case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
11713                 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
11714                 break;
11715         case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
11716                 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
11717                 break;
11718         case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
11719                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
11720                 break;
11721         case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
11722                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
11723                 break;
11724         case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
11725                 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
11726                 break;
11727         case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
11728                 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
11729                 break;
11730         case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
11731                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
11732                 break;
11733         case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
11734                 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
11735                 break;
11736         case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
11737                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
11738                 break;
11739         case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
11740                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
11741                 break;
11742         case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
11743                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
11744                 break;
11745         case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
11746                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
11747                 break;
11748         case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
11749                 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
11750                 break;
11751         case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
11752                 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
11753                 break;
11754         case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
11755                 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
11756                 break;
11757         default:
11758                 {
11759                         gst_structure_free(s);
11760                         return MM_ERROR_PLAYER_STREAMING_FAIL;
11761                 }
11762         }
11763
11764         error_string = g_strdup(gst_structure_get_string(s, "error_string"));
11765         if (error_string)
11766                 msg_param.data = (void *) error_string;
11767
11768         if (message->src) {
11769                 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
11770
11771                 LOGE("-Msg src : [%s] Code : [%x] Error : [%s]  \n",
11772                         msg_src_element, msg_param.code, (char*)msg_param.data);
11773         }
11774
11775         /* post error to application */
11776         if (!player->msg_posted) {
11777                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
11778
11779                 /* don't post more if one was sent already */
11780                 player->msg_posted = TRUE;
11781         } else
11782                 LOGD("skip error post because it's sent already.\n");
11783
11784         gst_structure_free(s);
11785         MMPLAYER_FLEAVE();
11786         g_free(error_string);
11787
11788         return TRUE;
11789
11790 }
11791
11792 static void
11793 __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms)
11794 {
11795         MMPLAYER_RETURN_IF_FAIL(player);
11796
11797         /* post now if delay is zero */
11798         if (delay_in_ms == 0 || player->set_mode.pcm_extraction) {
11799                 LOGD("eos delay is zero. posting EOS now\n");
11800                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11801
11802                 if (player->set_mode.pcm_extraction)
11803                         __mmplayer_cancel_eos_timer(player);
11804
11805                 return;
11806         }
11807
11808         /* cancel if existing */
11809         __mmplayer_cancel_eos_timer(player);
11810
11811         /* init new timeout */
11812         /* NOTE : consider give high priority to this timer */
11813         LOGD("posting EOS message after [%d] msec\n", delay_in_ms);
11814
11815         player->eos_timer = g_timeout_add(delay_in_ms,
11816                 __mmplayer_eos_timer_cb, player);
11817
11818         player->context.global_default = g_main_context_default();
11819         LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
11820
11821         /* check timer is valid. if not, send EOS now */
11822         if (player->eos_timer == 0) {
11823                 LOGW("creating timer for delayed EOS has failed. sending EOS now\n");
11824                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11825         }
11826 }
11827
11828 static void
11829 __mmplayer_cancel_eos_timer(mm_player_t* player)
11830 {
11831         MMPLAYER_RETURN_IF_FAIL(player);
11832
11833         if (player->eos_timer) {
11834                 LOGD("cancel eos timer");
11835                 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
11836                 player->eos_timer = 0;
11837         }
11838
11839         return;
11840 }
11841
11842 static gboolean
11843 __mmplayer_eos_timer_cb(gpointer u_data)
11844 {
11845         mm_player_t* player = NULL;
11846         MMHandleType attrs = 0;
11847         int count = 0;
11848
11849         MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
11850
11851         player = (mm_player_t*) u_data;
11852         attrs = MMPLAYER_GET_ATTRS(player);
11853
11854         mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
11855
11856         if (count == -1) {
11857                 gint ret_value = 0;
11858                 ret_value = __gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, 0, TRUE);
11859                 if (ret_value != MM_ERROR_NONE)
11860                         LOGE("seeking to 0 failed in repeat play");
11861         } else {
11862                 /* posting eos */
11863                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11864         }
11865
11866         /* we are returning FALSE as we need only one posting */
11867         return FALSE;
11868 }
11869
11870 /* sending event to one of sinkelements */
11871 static gboolean
11872 __gst_send_event_to_sink(mm_player_t* player, GstEvent* event)
11873 {
11874         GstEvent * event2 = NULL;
11875         GList *sinks = NULL;
11876         gboolean res = FALSE;
11877         MMPLAYER_FENTER();
11878
11879         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11880         MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
11881
11882         /* While adding subtitles in live feeds seek is getting called.
11883            Adding defensive check in framework layer.*/
11884         if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
11885                 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
11886                         LOGE("Should not send seek event during live playback");
11887                         return TRUE;
11888                 }
11889         }
11890
11891         if (player->play_subtitle)
11892                 event2 = gst_event_copy((const GstEvent *)event);
11893
11894         sinks = player->sink_elements;
11895         while (sinks) {
11896                 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
11897
11898                 if (GST_IS_ELEMENT(sink)) {
11899                         /* keep ref to the event */
11900                         gst_event_ref(event);
11901
11902                         if ((res = gst_element_send_event(sink, event))) {
11903                                 LOGD("sending event[%s] to sink element [%s] success!\n",
11904                                         GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
11905
11906                                 /* rtsp case, asyn_done is not called after seek during pause state */
11907                                 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
11908                                         if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
11909                                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
11910                                                         LOGD("RTSP seek completed, after pause state..\n");
11911                                                         player->doing_seek = FALSE;
11912                                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
11913                                                 }
11914
11915                                         }
11916                                 }
11917
11918                                 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
11919                                         sinks = g_list_next(sinks);
11920                                         continue;
11921                                 } else {
11922                                         break;
11923                                 }
11924                         }
11925
11926                         LOGD("sending event[%s] to sink element [%s] failed. try with next one.\n",
11927                                 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
11928                 }
11929
11930                 sinks = g_list_next(sinks);
11931         }
11932
11933         /* Note : Textbin is not linked to the video or audio bin.
11934          * It needs to send the event to the text sink seperatelly.
11935          */
11936          if (player->play_subtitle && player->pipeline) {
11937                 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
11938
11939                 if (GST_IS_ELEMENT(text_sink)) {
11940                         /* keep ref to the event */
11941                         gst_event_ref(event2);
11942
11943                         if ((res = gst_element_send_event(text_sink, event2)))
11944                                 LOGD("sending event[%s] to subtitle sink element [%s] success!\n",
11945                                         GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
11946                         else
11947                                 LOGE("sending event[%s] to subtitle sink element [%s] failed!\n",
11948                                         GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
11949
11950                         gst_event_unref(event2);
11951                 }
11952          }
11953
11954         gst_event_unref(event);
11955
11956         MMPLAYER_FLEAVE();
11957
11958         return res;
11959 }
11960
11961 static void
11962 __mmplayer_add_sink(mm_player_t* player, GstElement* sink)
11963 {
11964         MMPLAYER_FENTER();
11965
11966         MMPLAYER_RETURN_IF_FAIL(player);
11967         MMPLAYER_RETURN_IF_FAIL(sink);
11968
11969         player->sink_elements =
11970                 g_list_append(player->sink_elements, sink);
11971
11972         MMPLAYER_FLEAVE();
11973 }
11974
11975 static void
11976 __mmplayer_del_sink(mm_player_t* player, GstElement* sink)
11977 {
11978         MMPLAYER_FENTER();
11979
11980         MMPLAYER_RETURN_IF_FAIL(player);
11981         MMPLAYER_RETURN_IF_FAIL(sink);
11982
11983         player->sink_elements =
11984                         g_list_remove(player->sink_elements, sink);
11985
11986         MMPLAYER_FLEAVE();
11987 }
11988
11989 static gboolean
11990 __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
11991                         GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
11992                         gint64 cur, GstSeekType stop_type, gint64 stop)
11993 {
11994         GstEvent* event = NULL;
11995         gboolean result = FALSE;
11996
11997         MMPLAYER_FENTER();
11998
11999         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12000
12001         if (player->pipeline && player->pipeline->textbin)
12002                 __mmplayer_drop_subtitle(player, FALSE);
12003
12004         event = gst_event_new_seek(rate, format, flags, cur_type,
12005                 cur, stop_type, stop);
12006
12007         result = __gst_send_event_to_sink(player, event);
12008
12009         MMPLAYER_FLEAVE();
12010
12011         return result;
12012 }
12013
12014 /* NOTE : be careful with calling this api. please refer to below glib comment
12015  * glib comment : Note that there is a bug in GObject that makes this function much
12016  * less useful than it might seem otherwise. Once gobject is disposed, the callback
12017  * will no longer be called, but, the signal handler is not currently disconnected.
12018  * If the instance is itself being freed at the same time than this doesn't matter,
12019  * since the signal will automatically be removed, but if instance persists,
12020  * then the signal handler will leak. You should not remove the signal yourself
12021  * because in a future versions of GObject, the handler will automatically be
12022  * disconnected.
12023  *
12024  * It's possible to work around this problem in a way that will continue to work
12025  * with future versions of GObject by checking that the signal handler is still
12026  * connected before disconnected it:
12027  *
12028  *  if (g_signal_handler_is_connected(instance, id))
12029  *    g_signal_handler_disconnect(instance, id);
12030  */
12031 static void
12032 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
12033 {
12034         GList* sig_list = NULL;
12035         MMPlayerSignalItem* item = NULL;
12036
12037         MMPLAYER_FENTER();
12038
12039         MMPLAYER_RETURN_IF_FAIL(player);
12040
12041         LOGD("release signals type : %d", type);
12042
12043         if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
12044                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
12045                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
12046                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
12047                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
12048                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
12049                 return;
12050         }
12051
12052         sig_list = player->signals[type];
12053
12054         for (; sig_list; sig_list = sig_list->next) {
12055                 item = sig_list->data;
12056
12057                 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
12058                         if (g_signal_handler_is_connected(item->obj, item->sig))
12059                                 g_signal_handler_disconnect(item->obj, item->sig);
12060                 }
12061
12062                 MMPLAYER_FREEIF(item);
12063         }
12064
12065         g_list_free(player->signals[type]);
12066         player->signals[type] = NULL;
12067
12068         MMPLAYER_FLEAVE();
12069
12070         return;
12071 }
12072
12073 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
12074 {
12075         mm_player_t* player = 0;
12076         int prev_display_surface_type = 0;
12077         void *prev_display_overlay = NULL;
12078         const gchar *klass = NULL;
12079         gchar *cur_videosink_name = NULL;
12080         int ret = 0;
12081         int i = 0;
12082         int num_of_dec = 2; /* DEC1, DEC2 */
12083
12084         MMPLAYER_FENTER();
12085
12086         MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
12087         MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
12088
12089         player = MM_PLAYER_CAST(handle);
12090
12091         if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
12092                 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
12093                 MMPLAYER_FLEAVE();
12094                 return MM_ERROR_INVALID_ARGUMENT;
12095         }
12096
12097         /* load previous attributes */
12098         if (player->attrs) {
12099                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
12100                 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
12101                 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
12102                 if (prev_display_surface_type == surface_type) {
12103                         LOGD("incoming display surface type is same as previous one, do nothing..");
12104                         MMPLAYER_FLEAVE();
12105                         return MM_ERROR_NONE;
12106                 }
12107         } else {
12108                 LOGE("failed to load attributes");
12109                 MMPLAYER_FLEAVE();
12110                 return MM_ERROR_PLAYER_INTERNAL;
12111         }
12112
12113         /* check videosink element is created */
12114         if (!player->pipeline || !player->pipeline->videobin ||
12115                 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
12116                 LOGD("videosink element is not yet ready");
12117
12118                 /* videobin is not created yet, so we just set attributes related to display surface */
12119                 LOGD("store display attribute for given surface type(%d)", surface_type);
12120                 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
12121                 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
12122                 if (mmf_attrs_commit(player->attrs)) {
12123                         LOGE("failed to commit attribute");
12124                         MMPLAYER_FLEAVE();
12125                         return MM_ERROR_PLAYER_INTERNAL;
12126                 }
12127                 MMPLAYER_FLEAVE();
12128                 return MM_ERROR_NONE;
12129         } else {
12130                 /* get player command status */
12131                 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME || player->cmd == MMPLAYER_COMMAND_PAUSE)) {
12132                         LOGE("invalid player command status(%d), __mmplayer_do_change_videosink() is only available with START/RESUME/PAUSE command", player->cmd);
12133                         MMPLAYER_FLEAVE();
12134                         return MM_ERROR_PLAYER_INVALID_STATE;
12135                 }
12136
12137                 /* surface change */
12138                 for (i = 0 ; i < num_of_dec ; i++) {
12139                         if (player->pipeline->mainbin &&
12140                                 player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst) {
12141                                 GstElementFactory *decfactory;
12142                                 decfactory = gst_element_get_factory(player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst);
12143
12144                                 klass = gst_element_factory_get_metadata(decfactory, GST_ELEMENT_METADATA_KLASS);
12145                                 if ((g_strrstr(klass, "Codec/Decoder/Video"))) {
12146                                         if ((prev_display_surface_type == MM_DISPLAY_SURFACE_OVERLAY) && (surface_type == MM_DISPLAY_SURFACE_REMOTE)) {
12147                                                 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, "fakesink", surface_type, display_overlay);
12148                                                 if (ret) {
12149                                                         goto ERROR_CASE;
12150                                                 } else {
12151                                                         LOGW("success to changing display surface(%d)", surface_type);
12152                                                         MMPLAYER_FLEAVE();
12153                                                         return MM_ERROR_NONE;
12154                                                 }
12155                                         } else if ((prev_display_surface_type == MM_DISPLAY_SURFACE_REMOTE) && (surface_type == MM_DISPLAY_SURFACE_OVERLAY)) {
12156                                                 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, player->ini.videosink_element_overlay, surface_type, display_overlay);
12157                                                 if (ret) {
12158                                                         goto ERROR_CASE;
12159                                                 } else {
12160                                                         LOGW("success to changing display surface(%d)", surface_type);
12161                                                         MMPLAYER_FLEAVE();
12162                                                         return MM_ERROR_NONE;
12163                                                 }
12164                                         } else {
12165                                                 LOGE("invalid incoming surface type(%d) and current videosink_name(%s) for changing display surface", surface_type, cur_videosink_name);
12166                                                 ret = MM_ERROR_PLAYER_INTERNAL;
12167                                                 goto ERROR_CASE;
12168                                         }
12169                                 }
12170                         }
12171                 }
12172         }
12173
12174 ERROR_CASE:
12175         /* rollback to previous attributes */
12176         mm_attrs_set_int_by_name(player->attrs, "display_surface_type", prev_display_surface_type);
12177         mm_attrs_set_data_by_name(player->attrs, "display_overlay", prev_display_overlay, sizeof(void*));
12178         if (mmf_attrs_commit(player->attrs)) {
12179                 LOGE("failed to commit attributes to rollback");
12180                 MMPLAYER_FLEAVE();
12181                 return MM_ERROR_PLAYER_INTERNAL;
12182         }
12183         MMPLAYER_FLEAVE();
12184         return ret;
12185 }
12186
12187 /* NOTE : It does not support some use cases, eg using colorspace converter */
12188 int
12189 __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay)
12190 {
12191         GstPad *src_pad_dec = NULL;
12192         GstPad *sink_pad_videosink = NULL;
12193         GstPad *sink_pad_videobin = NULL;
12194         GstClock *clock = NULL;
12195         MMPlayerStateType previous_state = MM_PLAYER_STATE_NUM;
12196         int ret = MM_ERROR_NONE;
12197         gboolean is_audiobin_created = TRUE;
12198
12199         MMPLAYER_FENTER();
12200
12201         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_COMMON_INVALID_ARGUMENT);
12202         MMPLAYER_RETURN_VAL_IF_FAIL(videosink_element, MM_ERROR_COMMON_INVALID_ARGUMENT);
12203         MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
12204
12205         LOGD("video dec is found(idx:%d), we are going to change videosink to %s", dec_index, videosink_element);
12206         LOGD("surface type(%d), display overlay(%x)", surface_type, display_overlay);
12207
12208         /* get information whether if audiobin is created */
12209         if (!player->pipeline->audiobin ||
12210                      !player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
12211                 LOGW("audiobin is null, this video content may not have audio data");
12212                 is_audiobin_created = FALSE;
12213         }
12214
12215         /* get current state of player */
12216         previous_state = MMPLAYER_CURRENT_STATE(player);
12217         LOGD("previous state(%d)", previous_state);
12218
12219
12220         /* get src pad of decoder and block it */
12221         src_pad_dec = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), "src");
12222         if (!src_pad_dec) {
12223                 LOGE("failed to get src pad from decode in mainbin");
12224                 return MM_ERROR_PLAYER_INTERNAL;
12225         }
12226
12227         if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
12228                 LOGW("trying to block pad(video)");
12229 //              if (!gst_pad_set_blocked(src_pad_dec, TRUE))
12230                 gst_pad_add_probe(src_pad_dec, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
12231                         NULL, NULL, NULL);
12232                 {
12233                         LOGE("failed to set block pad(video)");
12234                         return MM_ERROR_PLAYER_INTERNAL;
12235                 }
12236                 LOGW("pad is blocked(video)");
12237         } else {
12238                 /* no data flows, so no need to do pad_block */
12239                 if (player->doing_seek)
12240                         LOGW("not completed seek(%d), do nothing", player->doing_seek);
12241
12242                 LOGD("MM_PLAYER_STATE is not PLAYING now, skip pad-block(TRUE)");
12243         }
12244
12245         /* remove pad */
12246         if (!gst_element_remove_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst,
12247                 GST_PAD_CAST(GST_GHOST_PAD(player->ghost_pad_for_videobin)))) {
12248                 LOGE("failed to remove previous ghost_pad for videobin");
12249                 return MM_ERROR_PLAYER_INTERNAL;
12250         }
12251
12252         /* change state of videobin to NULL */
12253         LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_NULL);
12254         ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_NULL);
12255         if (ret != GST_STATE_CHANGE_SUCCESS) {
12256                 LOGE("failed to change state of videobin to NULL");
12257                 return MM_ERROR_PLAYER_INTERNAL;
12258         }
12259
12260         /* unlink between decoder and videobin and remove previous videosink from videobin */
12261         gst_element_unlink(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst));
12262         if (!gst_bin_remove(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst))) {
12263                 LOGE("failed to remove former videosink from videobin");
12264                 return MM_ERROR_PLAYER_INTERNAL;
12265         }
12266
12267         __mmplayer_del_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12268
12269         /* create a new videosink and add it to videobin */
12270         player->pipeline->videobin[MMPLAYER_V_SINK].gst = gst_element_factory_make(videosink_element, "videosink");
12271         if (!player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
12272                 LOGE("failed to create videosink element\n");
12273                 MMPLAYER_FLEAVE();
12274                 return MM_ERROR_PLAYER_INTERNAL;
12275         }
12276         gst_bin_add(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst));
12277         __mmplayer_add_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12278         g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "qos", TRUE, NULL);
12279
12280         /* save attributes */
12281         if (player->attrs) {
12282                 /* set a new display surface type */
12283                 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
12284                 /* set a new diplay overlay */
12285                 switch (surface_type) {
12286                 case MM_DISPLAY_SURFACE_OVERLAY:
12287                         LOGD("save attributes related to video display surface : id = %d", *(int*)display_overlay);
12288                         mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
12289                         break;
12290                 default:
12291                         LOGE("invalid type(%d) for changing display surface", surface_type);
12292                         MMPLAYER_FLEAVE();
12293                         return MM_ERROR_INVALID_ARGUMENT;
12294                 }
12295                 if (mmf_attrs_commit(player->attrs)) {
12296                         LOGE("failed to commit");
12297                         MMPLAYER_FLEAVE();
12298                         return MM_ERROR_PLAYER_INTERNAL;
12299                 }
12300         } else {
12301                 LOGE("player->attrs is null, failed to save attributes");
12302                 MMPLAYER_FLEAVE();
12303                 return MM_ERROR_PLAYER_INTERNAL;
12304         }
12305
12306         /* update video param */
12307         if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "update_all_param")) {
12308                 LOGE("failed to update video param");
12309                 return MM_ERROR_PLAYER_INTERNAL;
12310         }
12311
12312         /* change state of videobin to READY */
12313         LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_READY);
12314         ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_READY);
12315         if (ret != GST_STATE_CHANGE_SUCCESS) {
12316                 LOGE("failed to change state of videobin to READY");
12317                 return MM_ERROR_PLAYER_INTERNAL;
12318         }
12319
12320         /* change ghostpad */
12321         sink_pad_videosink = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "sink");
12322         if (!sink_pad_videosink) {
12323                 LOGE("failed to get sink pad from videosink element");
12324                 return MM_ERROR_PLAYER_INTERNAL;
12325         }
12326         player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", sink_pad_videosink);
12327         if (!gst_pad_set_active(player->ghost_pad_for_videobin, TRUE)) {
12328                 LOGE("failed to set active to ghost_pad");
12329                 return MM_ERROR_PLAYER_INTERNAL;
12330         }
12331         if (FALSE == gst_element_add_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
12332                 LOGE("failed to change ghostpad for videobin");
12333                 return MM_ERROR_PLAYER_INTERNAL;
12334         }
12335         gst_object_unref(sink_pad_videosink);
12336
12337         /* link decoder with videobin */
12338         sink_pad_videobin = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst), "sink");
12339         if (!sink_pad_videobin) {
12340                 LOGE("failed to get sink pad from videobin");
12341                 return MM_ERROR_PLAYER_INTERNAL;
12342         }
12343         if (GST_PAD_LINK_OK != gst_pad_link(src_pad_dec, sink_pad_videobin)) {
12344                 LOGE("failed to link");
12345                 return MM_ERROR_PLAYER_INTERNAL;
12346         }
12347         gst_object_unref(sink_pad_videobin);
12348
12349         /* clock setting for a new videosink plugin */
12350         /* NOTE : Below operation is needed, because a new videosink plugin doesn't have clock for basesink,
12351                         so we set it from audiosink plugin or pipeline(system clock) */
12352         if (!is_audiobin_created) {
12353                 LOGW("audiobin is not created, get clock from pipeline..");
12354                 clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
12355         } else {
12356                 clock = GST_ELEMENT_CLOCK(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
12357         }
12358         if (clock) {
12359                 GstClockTime now;
12360                 GstClockTime base_time;
12361                 LOGD("set the clock to videosink");
12362                 gst_element_set_clock(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), clock);
12363                 clock = GST_ELEMENT_CLOCK(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12364                 if (clock) {
12365                         LOGD("got clock of videosink");
12366                         now = gst_clock_get_time(clock);
12367                         base_time = GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst)->base_time;
12368                         LOGD("at time %" GST_TIME_FORMAT ", base %"
12369                                         GST_TIME_FORMAT, GST_TIME_ARGS(now), GST_TIME_ARGS(base_time));
12370                 } else {
12371                         LOGE("failed to get clock of videosink after setting clock");
12372                         return MM_ERROR_PLAYER_INTERNAL;
12373                 }
12374         } else
12375                 LOGW("failed to get clock, maybe it is the time before first playing");
12376
12377         if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
12378                 /* change state of videobin to PAUSED */
12379                 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PLAYING);
12380                 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PLAYING);
12381                 if (ret != GST_STATE_CHANGE_FAILURE) {
12382                         LOGW("change state of videobin to PLAYING, ret(%d)", ret);
12383                 } else {
12384                         LOGE("failed to change state of videobin to PLAYING");
12385                         return MM_ERROR_PLAYER_INTERNAL;
12386                 }
12387
12388                 /* release blocked and unref src pad of video decoder */
12389                 #if 0
12390                 if (!gst_pad_set_blocked(src_pad_dec, FALSE)) {
12391                         LOGE("failed to set pad blocked FALSE(video)");
12392                         return MM_ERROR_PLAYER_INTERNAL;
12393                 }
12394                 #endif
12395                 LOGW("pad is unblocked(video)");
12396         } else {
12397                 if (player->doing_seek)
12398                         LOGW("not completed seek(%d)", player->doing_seek);
12399                 /* change state of videobin to PAUSED */
12400                 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PAUSED);
12401                 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PAUSED);
12402                 if (ret != GST_STATE_CHANGE_FAILURE) {
12403                         LOGW("change state of videobin to PAUSED, ret(%d)", ret);
12404                 } else {
12405                         LOGE("failed to change state of videobin to PLAYING");
12406                         return MM_ERROR_PLAYER_INTERNAL;
12407                 }
12408
12409                 /* already skipped pad block */
12410                 LOGD("previous MM_PLAYER_STATE is not PLAYING, skip pad-block(FALSE)");
12411         }
12412
12413         /* do get/set position for new videosink plugin */
12414         {
12415                 unsigned long position = 0;
12416                 gint64 pos_msec = 0;
12417
12418                 LOGD("do get/set position for new videosink plugin");
12419                 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position)) {
12420                         LOGE("failed to get position");
12421                         return MM_ERROR_PLAYER_INTERNAL;
12422                 }
12423 #ifdef SINKCHANGE_WITH_ACCURATE_SEEK
12424                 /* accurate seek */
12425                 if (__gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, position, TRUE)) {
12426                         LOGE("failed to set position");
12427                         return MM_ERROR_PLAYER_INTERNAL;
12428                 }
12429 #else
12430                 /* key unit seek */
12431                 pos_msec = position * G_GINT64_CONSTANT(1000000);
12432                 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
12433                                 GST_FORMAT_TIME, (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT),
12434                                                         GST_SEEK_TYPE_SET, pos_msec,
12435                                                         GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
12436                 if (!ret) {
12437                         LOGE("failed to set position");
12438                         return MM_ERROR_PLAYER_INTERNAL;
12439                 }
12440 #endif
12441         }
12442
12443         if (src_pad_dec)
12444                 gst_object_unref(src_pad_dec);
12445         LOGD("success to change sink");
12446
12447         MMPLAYER_FLEAVE();
12448
12449         return MM_ERROR_NONE;
12450 }
12451
12452
12453 /* Note : if silent is true, then subtitle would not be displayed. :*/
12454 int _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
12455 {
12456         mm_player_t* player = (mm_player_t*) hplayer;
12457
12458         MMPLAYER_FENTER();
12459
12460         /* check player handle */
12461         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12462
12463         player->set_mode.subtitle_off = silent;
12464
12465         LOGD("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
12466
12467         MMPLAYER_FLEAVE();
12468
12469         return MM_ERROR_NONE;
12470 }
12471
12472 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
12473 {
12474         MMPlayerGstElement* mainbin = NULL;
12475         MMPlayerGstElement* textbin = NULL;
12476         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
12477         GstState current_state = GST_STATE_VOID_PENDING;
12478         GstState element_state = GST_STATE_VOID_PENDING;
12479         GstState element_pending_state = GST_STATE_VOID_PENDING;
12480         gint64 time = 0;
12481         GstEvent *event = NULL;
12482         int result = MM_ERROR_NONE;
12483
12484         GstClock *curr_clock = NULL;
12485         GstClockTime base_time, start_time, curr_time;
12486
12487
12488         MMPLAYER_FENTER();
12489
12490         /* check player handle */
12491         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12492                                                                 player->pipeline &&
12493                                                                 player->pipeline->mainbin &&
12494                                                                 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12495
12496         mainbin = player->pipeline->mainbin;
12497         textbin = player->pipeline->textbin;
12498
12499         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12500
12501         // sync clock with current pipeline
12502         curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
12503         curr_time = gst_clock_get_time(curr_clock);
12504
12505         base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
12506         start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
12507
12508         LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
12509                 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
12510
12511         if (current_state > GST_STATE_READY) {
12512                 // sync state with current pipeline
12513                 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
12514                 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
12515                 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
12516
12517                 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
12518                 if (GST_STATE_CHANGE_FAILURE == ret) {
12519                         LOGE("fail to state change.\n");
12520                         result = MM_ERROR_PLAYER_INTERNAL;
12521                         goto ERROR;
12522                 }
12523         }
12524
12525         gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
12526         gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
12527
12528         if (curr_clock) {
12529                 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
12530                 gst_object_unref(curr_clock);
12531         }
12532
12533         // seek to current position
12534         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
12535                 result = MM_ERROR_PLAYER_INVALID_STATE;
12536                 LOGE("gst_element_query_position failed, invalid state\n");
12537                 goto ERROR;
12538         }
12539
12540         LOGD("seek time = %lld, rate = %f\n", time, player->playback_rate);
12541         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);
12542         if (event) {
12543                 __gst_send_event_to_sink(player, event);
12544         } else {
12545                 result = MM_ERROR_PLAYER_INTERNAL;
12546                 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
12547                 goto ERROR;
12548         }
12549
12550         /* sync state with current pipeline */
12551         gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
12552         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
12553         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
12554
12555         return MM_ERROR_NONE;
12556
12557 ERROR:
12558         /* release text pipeline resource */
12559         player->textsink_linked = 0;
12560
12561         /* release signal */
12562         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
12563
12564         /* release textbin with it's childs */
12565         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
12566         MMPLAYER_FREEIF(player->pipeline->textbin);
12567         player->pipeline->textbin = NULL;
12568
12569         /* release subtitle elem */
12570         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
12571         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
12572
12573         return result;
12574 }
12575
12576 static int
12577 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
12578 {
12579         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
12580         GstState current_state = GST_STATE_VOID_PENDING;
12581
12582         MMHandleType attrs = 0;
12583         MMPlayerGstElement* mainbin = NULL;
12584         MMPlayerGstElement* textbin = NULL;
12585
12586         gchar* subtitle_uri = NULL;
12587         int result = MM_ERROR_NONE;
12588         const gchar *charset = NULL;
12589
12590         MMPLAYER_FENTER();
12591
12592         /* check player handle */
12593         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12594                                                                 player->pipeline &&
12595                                                                 player->pipeline->mainbin &&
12596                                                                 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12597         MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
12598
12599         mainbin = player->pipeline->mainbin;
12600         textbin = player->pipeline->textbin;
12601
12602         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12603         if (current_state < GST_STATE_READY) {
12604                 result = MM_ERROR_PLAYER_INVALID_STATE;
12605                 LOGE("Pipeline is not in proper state\n");
12606                 goto EXIT;
12607         }
12608
12609         attrs = MMPLAYER_GET_ATTRS(player);
12610         if (!attrs) {
12611                 LOGE("cannot get content attribute\n");
12612                 result = MM_ERROR_PLAYER_INTERNAL;
12613                 goto EXIT;
12614         }
12615
12616         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
12617         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
12618                 LOGE("subtitle uri is not proper filepath\n");
12619                 result = MM_ERROR_PLAYER_INVALID_URI;
12620                 goto EXIT;
12621         }
12622
12623         if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
12624                 LOGE("failed to get storage info of subtitle path");
12625                 result = MM_ERROR_PLAYER_INVALID_URI;
12626                 goto EXIT;
12627         }
12628
12629         LOGD("old subtitle file path is [%s]\n", subtitle_uri);
12630         LOGD("new subtitle file path is [%s]\n", filepath);
12631
12632         if (!strcmp(filepath, subtitle_uri)) {
12633                 LOGD("No need to swtich subtitle, as input filepath is same as current filepath\n");
12634                 goto EXIT;
12635         } else {
12636                 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12637                 if (mmf_attrs_commit(player->attrs)) {
12638                         LOGE("failed to commit.\n");
12639                         goto EXIT;
12640                 }
12641         }
12642
12643         //gst_pad_set_blocked_async(src-srcpad, TRUE)
12644         MMPLAYER_SUBTITLE_INFO_LOCK(player);
12645         player->subtitle_language_list = NULL;
12646         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
12647
12648         ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
12649         if (ret != GST_STATE_CHANGE_SUCCESS) {
12650                 LOGE("failed to change state of textbin to READY");
12651                 result = MM_ERROR_PLAYER_INTERNAL;
12652                 goto EXIT;
12653         }
12654
12655         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
12656         if (ret != GST_STATE_CHANGE_SUCCESS) {
12657                 LOGE("failed to change state of subparse to READY");
12658                 result = MM_ERROR_PLAYER_INTERNAL;
12659                 goto EXIT;
12660         }
12661
12662         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
12663         if (ret != GST_STATE_CHANGE_SUCCESS) {
12664                 LOGE("failed to change state of filesrc to READY");
12665                 result = MM_ERROR_PLAYER_INTERNAL;
12666                 goto EXIT;
12667         }
12668
12669         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
12670
12671         g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
12672
12673         charset = util_get_charset(filepath);
12674         if (charset) {
12675                 LOGD("detected charset is %s\n", charset);
12676                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
12677         }
12678
12679         result = _mmplayer_sync_subtitle_pipeline(player);
12680
12681 EXIT:
12682         MMPLAYER_FLEAVE();
12683         return result;
12684 }
12685
12686 /* API to switch between external subtitles */
12687 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
12688 {
12689         int result = MM_ERROR_NONE;
12690         mm_player_t* player = (mm_player_t*)hplayer;
12691         char *path = NULL;
12692
12693         MMPLAYER_FENTER();
12694
12695         /* check player handle */
12696         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12697
12698         /* filepath can be null in idle state */
12699         if (filepath) {
12700                 /* check file path */
12701                 if ((path = strstr(filepath, "file://")))
12702                         result = util_exist_file_path(path + 7);
12703                 else
12704                         result = util_exist_file_path(filepath);
12705
12706                 if (result != MM_ERROR_NONE) {
12707                         LOGE("invalid subtitle path 0x%X", result);
12708                         return result; /* file not found or permission denied */
12709                 }
12710         }
12711
12712         if (!player->pipeline) {
12713                 /* IDLE state */
12714                 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12715                 if (mmf_attrs_commit(player->attrs)) {
12716                         LOGE("failed to commit");       /* subtitle path will not be created */
12717                         return MM_ERROR_PLAYER_INTERNAL;
12718                 }
12719         } else {
12720                 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
12721                 /* check filepath */
12722                 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
12723
12724                 if (!__mmplayer_check_subtitle(player)) {
12725                         mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12726                         if (mmf_attrs_commit(player->attrs)) {
12727                                 LOGE("failed to commit");
12728                                 return MM_ERROR_PLAYER_INTERNAL;
12729                         }
12730
12731                         if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
12732                                 LOGE("fail to create text pipeline");
12733                                 return MM_ERROR_PLAYER_INTERNAL;
12734                         }
12735
12736                         result = _mmplayer_sync_subtitle_pipeline(player);
12737                 } else {
12738                         result = __mmplayer_change_external_subtitle_language(player, filepath);
12739                 }
12740
12741                 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
12742                 player->is_external_subtitle_added_now = TRUE;
12743
12744                 MMPLAYER_SUBTITLE_INFO_LOCK(player);
12745                 if (!player->subtitle_language_list) {
12746                         gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
12747                         if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
12748                                 LOGW("subtitle language list is not updated yet");
12749                 }
12750                 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
12751         }
12752
12753         MMPLAYER_FLEAVE();
12754         return result;
12755 }
12756
12757 static int
12758 __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index)
12759 {
12760         int result = MM_ERROR_NONE;
12761         gchar* change_pad_name = NULL;
12762         GstPad* sinkpad = NULL;
12763         MMPlayerGstElement* mainbin = NULL;
12764         enum MainElementID elemId = MMPLAYER_M_NUM;
12765         GstCaps* caps = NULL;
12766         gint total_track_num = 0;
12767
12768         MMPLAYER_FENTER();
12769
12770         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
12771                                                                                                         MM_ERROR_PLAYER_NOT_INITIALIZED);
12772
12773         LOGD("Change Track(%d) to %d\n", type, index);
12774
12775         mainbin = player->pipeline->mainbin;
12776
12777         if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
12778                 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
12779         } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
12780                 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
12781         } else {
12782                 /* Changing Video Track is not supported. */
12783                 LOGE("Track Type Error\n");
12784                 goto EXIT;
12785         }
12786
12787         if (mainbin[elemId].gst == NULL) {
12788                 result = MM_ERROR_PLAYER_NO_OP;
12789                 LOGD("Req track doesn't exist\n");
12790                 goto EXIT;
12791         }
12792
12793         total_track_num = player->selector[type].total_track_num;
12794         if (total_track_num <= 0) {
12795                 result = MM_ERROR_PLAYER_NO_OP;
12796                 LOGD("Language list is not available \n");
12797                 goto EXIT;
12798         }
12799
12800         if ((index < 0) || (index >= total_track_num)) {
12801                 result = MM_ERROR_INVALID_ARGUMENT;
12802                 LOGD("Not a proper index : %d \n", index);
12803                 goto EXIT;
12804         }
12805
12806         /*To get the new pad from the selector*/
12807         change_pad_name = g_strdup_printf("sink_%u", index);
12808         if (change_pad_name == NULL) {
12809                 result = MM_ERROR_PLAYER_INTERNAL;
12810                 LOGD("Pad does not exists\n");
12811                 goto EXIT;
12812         }
12813
12814         LOGD("new active pad name: %s\n", change_pad_name);
12815
12816         sinkpad = gst_element_get_static_pad(mainbin[elemId].gst, change_pad_name);
12817         if (sinkpad == NULL) {
12818                 LOGD("sinkpad is NULL");
12819                 result = MM_ERROR_PLAYER_INTERNAL;
12820                 goto EXIT;
12821         }
12822
12823         LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
12824         g_object_set(mainbin[elemId].gst, "active-pad", sinkpad, NULL);
12825
12826         caps = gst_pad_get_current_caps(sinkpad);
12827         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
12828
12829         if (sinkpad)
12830                 gst_object_unref(sinkpad);
12831
12832         if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
12833                 __mmplayer_set_audio_attrs(player, caps);
12834
12835 EXIT:
12836
12837         MMPLAYER_FREEIF(change_pad_name);
12838         return result;
12839 }
12840
12841 int _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
12842 {
12843         int result = MM_ERROR_NONE;
12844         mm_player_t* player = NULL;
12845         MMPlayerGstElement* mainbin = NULL;
12846
12847         gint current_active_index = 0;
12848
12849         GstState current_state = GST_STATE_VOID_PENDING;
12850         GstEvent* event = NULL;
12851         gint64 time = 0;
12852
12853         MMPLAYER_FENTER();
12854
12855         player = (mm_player_t*)hplayer;
12856         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12857
12858         if (!player->pipeline) {
12859                 LOGE("Track %d pre setting -> %d\n", type, index);
12860
12861                 player->selector[type].active_pad_index = index;
12862                 goto EXIT;
12863         }
12864
12865         mainbin = player->pipeline->mainbin;
12866
12867         current_active_index = player->selector[type].active_pad_index;
12868
12869         /*If index is same as running index no need to change the pad*/
12870         if (current_active_index == index)
12871                 goto EXIT;
12872
12873         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
12874                 result = MM_ERROR_PLAYER_INVALID_STATE;
12875                 goto EXIT;
12876         }
12877
12878         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12879         if (current_state < GST_STATE_PAUSED) {
12880                 result = MM_ERROR_PLAYER_INVALID_STATE;
12881                 LOGW("Pipeline not in porper state\n");
12882                 goto EXIT;
12883         }
12884
12885         result = __mmplayer_change_selector_pad(player, type, index);
12886         if (result != MM_ERROR_NONE) {
12887                 LOGE("change selector pad error\n");
12888                 goto EXIT;
12889         }
12890
12891         player->selector[type].active_pad_index = index;
12892
12893         if (current_state == GST_STATE_PLAYING) {
12894                 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);
12895                 if (event) {
12896                         __gst_send_event_to_sink(player, event);
12897                 } else {
12898                         result = MM_ERROR_PLAYER_INTERNAL;
12899                         goto EXIT;
12900                 }
12901         }
12902
12903 EXIT:
12904         return result;
12905 }
12906
12907 int _mmplayer_get_subtitle_silent(MMHandleType hplayer, int* silent)
12908 {
12909         mm_player_t* player = (mm_player_t*) hplayer;
12910
12911         MMPLAYER_FENTER();
12912
12913         /* check player handle */
12914         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12915
12916         *silent = player->set_mode.subtitle_off;
12917
12918         LOGD("subtitle is %s.\n", silent ? "ON" : "OFF");
12919
12920         MMPLAYER_FLEAVE();
12921
12922         return MM_ERROR_NONE;
12923 }
12924
12925 gboolean
12926 __is_ms_buff_src(mm_player_t* player)
12927 {
12928         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12929
12930         return (player->profile.uri_type == MM_PLAYER_URI_TYPE_MS_BUFF) ? TRUE : FALSE;
12931 }
12932
12933 gboolean
12934 __has_suffix(mm_player_t* player, const gchar* suffix)
12935 {
12936         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12937         MMPLAYER_RETURN_VAL_IF_FAIL(suffix, FALSE);
12938
12939         gboolean ret = FALSE;
12940         gchar* t_url = g_ascii_strdown(player->profile.uri, -1);
12941         gchar* t_suffix = g_ascii_strdown(suffix, -1);
12942
12943         if (g_str_has_suffix(player->profile.uri, suffix))
12944                 ret = TRUE;
12945
12946         MMPLAYER_FREEIF(t_url);
12947         MMPLAYER_FREEIF(t_suffix);
12948
12949         return ret;
12950 }
12951
12952 int
12953 _mmplayer_set_video_hub_download_mode(MMHandleType hplayer, bool mode)
12954 {
12955         mm_player_t* player = (mm_player_t*) hplayer;
12956
12957         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12958
12959         if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL) {
12960                 MMPLAYER_PRINT_STATE(player);
12961                 LOGE("wrong-state : can't set the download mode to parse");
12962                 return MM_ERROR_PLAYER_INVALID_STATE;
12963         }
12964
12965         LOGD("set video hub download mode to %s", (mode) ? "ON" : "OFF");
12966         player->video_hub_download_mode = mode;
12967
12968         return MM_ERROR_NONE;
12969 }
12970
12971 int
12972 _mmplayer_enable_sync_handler(MMHandleType hplayer, bool enable)
12973 {
12974         mm_player_t* player = (mm_player_t*) hplayer;
12975
12976         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12977
12978         LOGD("enable sync handler : %s", (enable) ? "ON" : "OFF");
12979         player->sync_handler = enable;
12980
12981         return MM_ERROR_NONE;
12982 }
12983
12984 int
12985 _mmplayer_set_video_share_master_clock(MMHandleType hplayer,
12986                                         long long clock,
12987                                         long long clock_delta,
12988                                         long long video_time,
12989                                         long long media_clock,
12990                                         long long audio_time)
12991 {
12992         mm_player_t* player = (mm_player_t*) hplayer;
12993         MMPlayerGstElement* mainbin = NULL;
12994         GstClockTime start_time_audio = 0, start_time_video = 0;
12995         GstClockTimeDiff base_time = 0, new_base_time = 0;
12996         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
12997         gint64 api_delta = 0;
12998         gint64 position = 0, position_delta = 0;
12999         gint64 adj_base_time = 0;
13000         GstClock *curr_clock = NULL;
13001         GstClockTime curr_time = 0;
13002         gboolean query_ret = TRUE;
13003         int result = MM_ERROR_NONE;
13004
13005         MMPLAYER_FENTER();
13006
13007         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
13008         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
13009         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
13010
13011         // LOGD("in(us) : %lld, %lld, %lld, %lld, %lld", clock, clock_delta, video_time, media_clock, audio_time);
13012
13013         if ((video_time < 0) || (player->doing_seek)) {
13014                 LOGD("skip setting master clock.  %lld", video_time);
13015                 goto EXIT;
13016         }
13017
13018         mainbin = player->pipeline->mainbin;
13019
13020         curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
13021         curr_time = gst_clock_get_time(curr_clock);
13022
13023         current_state = MMPLAYER_CURRENT_STATE(player);
13024
13025         if (current_state == MM_PLAYER_STATE_PLAYING)
13026                 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
13027
13028         if ((current_state != MM_PLAYER_STATE_PLAYING) ||
13029                 (!query_ret)) {
13030                 position = player->last_position;
13031                 LOGD("query fail. %lld", position);
13032         }
13033
13034         clock *= GST_USECOND;
13035         clock_delta *= GST_USECOND;
13036
13037         api_delta = clock - curr_time;
13038         if ((player->video_share_api_delta == 0) || (player->video_share_api_delta > api_delta))
13039                 player->video_share_api_delta = api_delta;
13040         else
13041                 clock_delta += (api_delta - player->video_share_api_delta);
13042
13043         if ((player->video_share_clock_delta == 0) || (player->video_share_clock_delta > clock_delta)) {
13044                 player->video_share_clock_delta = (gint64)clock_delta;
13045
13046                 position_delta = (position/GST_USECOND) - video_time;
13047                 position_delta *= GST_USECOND;
13048
13049                 adj_base_time = position_delta;
13050                 LOGD("video_share_clock_delta = %lld, adj = %lld", player->video_share_clock_delta, adj_base_time);
13051
13052         } else {
13053                 gint64 new_play_time = 0;
13054                 gint64 network_delay = 0;
13055
13056                 video_time *= GST_USECOND;
13057
13058                 network_delay = clock_delta - player->video_share_clock_delta;
13059                 new_play_time = video_time + network_delay;
13060
13061                 adj_base_time = position - new_play_time;
13062
13063                 LOGD("%lld(delay) = %lld - %lld / %lld(adj) = %lld(slave_pos) - %lld(master_pos) - %lld(delay)",
13064                         network_delay, clock_delta, player->video_share_clock_delta, adj_base_time, position, video_time, network_delay);
13065         }
13066
13067         /* Adjust Current Stream Time with base_time of sink
13068          * 1. Set Start time to CLOCK NONE, to control the base time by MSL
13069          * 2. Set new base time
13070          *    if adj_base_time is positive value, the stream time will be decreased.
13071          * 3. If seek event is occurred, the start time will be reset. */
13072         if ((player->pipeline->audiobin) &&
13073                 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst)) {
13074                 start_time_audio = gst_element_get_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13075
13076                 if (start_time_audio != GST_CLOCK_TIME_NONE) {
13077                         LOGD("audio sink : gst_element_set_start_time -> NONE");
13078                         gst_element_set_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, GST_CLOCK_TIME_NONE);
13079                 }
13080
13081                 base_time = gst_element_get_base_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13082         }
13083
13084         if ((player->pipeline->videobin) &&
13085                 (player->pipeline->videobin[MMPLAYER_V_SINK].gst)) {
13086                 start_time_video = gst_element_get_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13087
13088                 if (start_time_video != GST_CLOCK_TIME_NONE) {
13089                         LOGD("video sink : gst_element_set_start_time -> NONE");
13090                         gst_element_set_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst, GST_CLOCK_TIME_NONE);
13091                 }
13092
13093                 // if videobin exist, get base_time from videobin.
13094                 base_time = gst_element_get_base_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13095         }
13096
13097         new_base_time = base_time + adj_base_time;
13098
13099         if ((player->pipeline->audiobin) &&
13100                 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst))
13101                 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), (GstClockTime)new_base_time);
13102
13103         if ((player->pipeline->videobin) &&
13104                 (player->pipeline->videobin[MMPLAYER_V_SINK].gst))
13105                 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), (GstClockTime)new_base_time);
13106
13107 EXIT:
13108         MMPLAYER_FLEAVE();
13109
13110         return result;
13111 }
13112
13113 int
13114 _mmplayer_get_video_share_master_clock(MMHandleType hplayer,
13115                                         long long *video_time,
13116                                         long long *media_clock,
13117                                         long long *audio_time)
13118 {
13119         mm_player_t* player = (mm_player_t*) hplayer;
13120         MMPlayerGstElement* mainbin = NULL;
13121         GstClock *curr_clock = NULL;
13122         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
13123         gint64 position = 0;
13124         gboolean query_ret = TRUE;
13125
13126         MMPLAYER_FENTER();
13127
13128         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
13129         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
13130         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
13131
13132         MMPLAYER_RETURN_VAL_IF_FAIL(video_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
13133         MMPLAYER_RETURN_VAL_IF_FAIL(media_clock, MM_ERROR_COMMON_INVALID_ARGUMENT);
13134         MMPLAYER_RETURN_VAL_IF_FAIL(audio_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
13135
13136         mainbin = player->pipeline->mainbin;
13137
13138         curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
13139
13140         current_state = MMPLAYER_CURRENT_STATE(player);
13141
13142         if (current_state != MM_PLAYER_STATE_PAUSED)
13143                 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
13144
13145         if ((current_state == MM_PLAYER_STATE_PAUSED) ||
13146                 (!query_ret))
13147                 position = player->last_position;
13148
13149         *media_clock = *video_time = *audio_time = (position/GST_USECOND);
13150
13151         LOGD("media_clock: %lld, video_time: %lld(us)", *media_clock, *video_time);
13152
13153         if (curr_clock)
13154                 gst_object_unref(curr_clock);
13155
13156         MMPLAYER_FLEAVE();
13157
13158         return MM_ERROR_NONE;
13159 }
13160
13161 static gboolean
13162 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
13163 {
13164         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13165         MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
13166
13167         gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
13168         gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
13169
13170         int idx = 0;
13171
13172         for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
13173                 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
13174                         LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
13175                         mm_player_dump_t *dump_s;
13176                         dump_s = g_malloc(sizeof(mm_player_dump_t));
13177
13178                         if (dump_s == NULL) {
13179                                 LOGE("malloc fail");
13180                                 return FALSE;
13181                         }
13182
13183                         dump_s->dump_element_file = NULL;
13184                         dump_s->dump_pad = NULL;
13185                         dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
13186
13187                         if (dump_s->dump_pad) {
13188                                 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
13189                                 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]);
13190                                 dump_s->dump_element_file = fopen(dump_file_name, "w+");
13191                                 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);
13192                                 /* add list for removed buffer probe and close FILE */
13193                                 player->dump_list = g_list_append(player->dump_list, dump_s);
13194                                 LOGD("%s sink pad added buffer probe for dump", factory_name);
13195                                 return TRUE;
13196                         } else {
13197                                 g_free(dump_s);
13198                                 dump_s = NULL;
13199                                 LOGE("failed to get %s sink pad added", factory_name);
13200                         }
13201
13202
13203                 }
13204         }
13205         return FALSE;
13206 }
13207
13208 static GstPadProbeReturn
13209 __mmplayer_dump_buffer_probe_cb(GstPad *pad,  GstPadProbeInfo *info, gpointer u_data)
13210 {
13211         FILE *dump_data = (FILE *) u_data;
13212 //      int written = 0;
13213         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
13214         GstMapInfo probe_info = GST_MAP_INFO_INIT;
13215
13216         MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, FALSE);
13217
13218         gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
13219
13220 //      LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
13221
13222         fwrite(probe_info.data, 1, probe_info.size , dump_data);
13223
13224         return GST_PAD_PROBE_OK;
13225 }
13226
13227 static void
13228 __mmplayer_release_dump_list(GList *dump_list)
13229 {
13230         if (dump_list) {
13231                 GList *d_list = dump_list;
13232                 for (; d_list; d_list = g_list_next(d_list)) {
13233                         mm_player_dump_t *dump_s = d_list->data;
13234                         if (dump_s->dump_pad) {
13235                                 if (dump_s->probe_handle_id)
13236                                         gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
13237                         }
13238                         if (dump_s->dump_element_file) {
13239                                 fclose(dump_s->dump_element_file);
13240                                 dump_s->dump_element_file = NULL;
13241                         }
13242                         MMPLAYER_FREEIF(dump_s);
13243                 }
13244                 g_list_free(dump_list);
13245                 dump_list = NULL;
13246         }
13247 }
13248
13249 int
13250 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
13251 {
13252         mm_player_t* player = (mm_player_t*) hplayer;
13253
13254         MMPLAYER_FENTER();
13255
13256         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13257         MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
13258
13259         *exist = player->has_closed_caption;
13260
13261         MMPLAYER_FLEAVE();
13262
13263         return MM_ERROR_NONE;
13264 }
13265
13266 void _mm_player_video_stream_internal_buffer_unref(void *buffer)
13267 {
13268         MMPLAYER_FENTER();
13269         if (buffer) {
13270                 // LOGD("unref internal gst buffer %p", buffer);
13271                 gst_buffer_unref((GstBuffer *)buffer);
13272                 buffer = NULL;
13273         }
13274         MMPLAYER_FLEAVE();
13275 }
13276
13277 void
13278 __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data)
13279 {
13280         mm_player_t *player  = (mm_player_t*)user_data;
13281         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13282         guint64 current_level_bytes = 0;
13283
13284         MMPLAYER_RETURN_IF_FAIL(player);
13285
13286         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
13287
13288         LOGI("app-src: feed audio(%llu)\n", current_level_bytes);
13289         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13290
13291         if (player->media_stream_buffer_status_cb[type])
13292                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13293         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13294
13295 }
13296
13297 void
13298 __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data)
13299 {
13300         mm_player_t *player  = (mm_player_t*)user_data;
13301         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13302         guint64 current_level_bytes = 0;
13303
13304         MMPLAYER_RETURN_IF_FAIL(player);
13305
13306         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
13307
13308         LOGI("app-src: feed video(%llu)\n", current_level_bytes);
13309
13310         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13311         if (player->media_stream_buffer_status_cb[type])
13312                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13313         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13314 }
13315
13316 void
13317 __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data)
13318 {
13319         mm_player_t *player  = (mm_player_t*)user_data;
13320         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
13321         guint64 current_level_bytes = 0;
13322
13323         MMPLAYER_RETURN_IF_FAIL(player);
13324
13325         LOGI("app-src: feed subtitle\n");
13326
13327         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
13328
13329         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13330         if (player->media_stream_buffer_status_cb[type])
13331                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13332
13333         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13334 }
13335
13336 void
13337 __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data)
13338 {
13339         mm_player_t *player  = (mm_player_t*)user_data;
13340         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13341         guint64 current_level_bytes = 0;
13342
13343         MMPLAYER_RETURN_IF_FAIL(player);
13344
13345         LOGI("app-src: audio buffer is full.\n");
13346
13347         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
13348
13349         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13350
13351         if (player->media_stream_buffer_status_cb[type])
13352                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
13353
13354         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13355 }
13356
13357 void
13358 __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data)
13359 {
13360         mm_player_t *player  = (mm_player_t*)user_data;
13361         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13362         guint64 current_level_bytes = 0;
13363
13364         MMPLAYER_RETURN_IF_FAIL(player);
13365
13366         LOGI("app-src: video buffer is full.\n");
13367
13368         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
13369
13370         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13371         if (player->media_stream_buffer_status_cb[type])
13372                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
13373
13374         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13375 }
13376
13377 gboolean
13378 __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data)
13379 {
13380         mm_player_t *player  = (mm_player_t*)user_data;
13381         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13382
13383         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13384
13385         LOGD("app-src: seek audio data %llu\n", position);
13386         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13387
13388         if (player->media_stream_seek_data_cb[type])
13389                 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13390         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13391
13392         return TRUE;
13393 }
13394
13395 gboolean
13396 __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data)
13397 {
13398         mm_player_t *player  = (mm_player_t*)user_data;
13399         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13400
13401         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13402
13403         LOGD("app-src: seek video data %llu\n", position);
13404         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13405         if (player->media_stream_seek_data_cb[type])
13406                 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13407         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13408
13409         return TRUE;
13410 }
13411
13412 gboolean
13413 __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data)
13414 {
13415         mm_player_t *player  = (mm_player_t*)user_data;
13416         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
13417
13418         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13419
13420         LOGD("app-src: seek subtitle data\n");
13421         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13422
13423         if (player->media_stream_seek_data_cb[type])
13424                 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13425         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13426
13427         return TRUE;
13428 }
13429
13430 int
13431 _mmplayer_set_pcm_spec(MMHandleType hplayer, int samplerate, int channel)
13432 {
13433         mm_player_t* player = (mm_player_t*) hplayer;
13434
13435         MMPLAYER_FENTER();
13436
13437         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13438
13439         player->pcm_samplerate = samplerate;
13440         player->pcm_channel = channel;
13441
13442         MMPLAYER_FLEAVE();
13443         return MM_ERROR_NONE;
13444 }
13445
13446 int _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
13447 {
13448         mm_player_t* player = (mm_player_t*) hplayer;
13449
13450         MMPLAYER_FENTER();
13451
13452         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13453         MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
13454
13455         if (MMPLAYER_IS_STREAMING(player))
13456                 *timeout = player->ini.live_state_change_timeout;
13457         else
13458                 *timeout = player->ini.localplayback_state_change_timeout;
13459
13460         LOGD("timeout = %d\n", *timeout);
13461
13462         MMPLAYER_FLEAVE();
13463         return MM_ERROR_NONE;
13464 }
13465
13466 int _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
13467 {
13468         mm_player_t* player = (mm_player_t*) hplayer;
13469
13470         MMPLAYER_FENTER();
13471
13472         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13473         MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
13474
13475         *num = player->video_num_buffers;
13476         *extra_num = player->video_extra_num_buffers;
13477
13478         LOGD("state %d, num %d(%d)\n", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
13479
13480         MMPLAYER_FLEAVE();
13481         return MM_ERROR_NONE;
13482 }
13483
13484 static void
13485 __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type)
13486 {
13487         int i = 0;
13488         MMPLAYER_FENTER();
13489         MMPLAYER_RETURN_IF_FAIL(player);
13490
13491         for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
13492
13493                 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
13494                         player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
13495                         player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
13496                         player->storage_info[i].id = -1;
13497                         memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
13498
13499                         if (path_type != MMPLAYER_PATH_MAX)
13500                                 break;
13501                 }
13502         }
13503
13504         MMPLAYER_FLEAVE();
13505 }
13506
13507 int _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
13508 {
13509         int ret = MM_ERROR_NONE;
13510         mm_player_t* player = (mm_player_t*)hplayer;
13511         MMMessageParamType msg_param = {0, };
13512
13513         MMPLAYER_FENTER();
13514         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13515
13516         LOGW("state changed storage %d:%d", id, state);
13517
13518         if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
13519                 return MM_ERROR_NONE;
13520
13521         /* FIXME: text path should be handled seperately. */
13522         if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
13523                 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
13524                 LOGW("external storage is removed");
13525
13526                 if (player->msg_posted == FALSE) {
13527                         memset(&msg_param, 0, sizeof(MMMessageParamType));
13528                         msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
13529                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
13530                         player->msg_posted = TRUE;
13531                 }
13532
13533                 /* unrealize the player */
13534                 ret = _mmplayer_unrealize(hplayer);
13535                 if (ret != MM_ERROR_NONE)
13536                         LOGE("failed to unrealize");
13537         }
13538
13539         MMPLAYER_FLEAVE();
13540         return ret;
13541 }
13542
13543 int _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
13544 {
13545         int ret = MM_ERROR_NONE;
13546         mm_player_t* player = (mm_player_t*) hplayer;
13547         int idx = 0, total = 0;
13548         gchar *result = NULL, *tmp = NULL;
13549
13550         MMPLAYER_FENTER();
13551         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13552         MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
13553
13554         total = *num = g_list_length(player->adaptive_info.var_list);
13555         if (total <= 0) {
13556                 LOGW("There is no stream variant info.");
13557                 return ret;
13558         }
13559
13560         result = g_strdup("");
13561         for (idx = 0 ; idx < total ; idx++) {
13562                 VariantData *v_data = NULL;
13563                 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
13564
13565                 if (v_data) {
13566                         gchar data[64] = {0};
13567                         snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
13568
13569                         tmp = g_strconcat(result, data, NULL);
13570                         g_free(result);
13571                         result = tmp;
13572                 } else {
13573                         LOGW("There is no variant data in %d", idx);
13574                         (*num)--;
13575                 }
13576         }
13577
13578         *var_info = (char *)result;
13579
13580         LOGD("variant info %d:%s", *num, *var_info);
13581         MMPLAYER_FLEAVE();
13582         return ret;
13583 }
13584
13585 int _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
13586 {
13587         int ret = MM_ERROR_NONE;
13588         mm_player_t* player = (mm_player_t*) hplayer;
13589
13590         MMPLAYER_FENTER();
13591         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13592
13593         LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
13594
13595         player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13596         player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13597         player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13598
13599         if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
13600                 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
13601                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
13602                                                 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
13603
13604                 /* FIXME: seek to current position for applying new variant limitation */
13605         }
13606
13607         MMPLAYER_FLEAVE();
13608         return ret;
13609
13610 }
13611
13612 int _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
13613 {
13614         int ret = MM_ERROR_NONE;
13615         mm_player_t* player = (mm_player_t*) hplayer;
13616
13617         MMPLAYER_FENTER();
13618         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13619         MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
13620
13621         *bandwidth = player->adaptive_info.limit.bandwidth;
13622         *width = player->adaptive_info.limit.width;
13623         *height = player->adaptive_info.limit.height;
13624
13625         LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
13626
13627         MMPLAYER_FLEAVE();
13628         return ret;
13629 }
13630
13631 int _mmplayer_set_streaming_buffering_time(MMHandleType hplayer, int buffer_ms, int rebuffer_ms)
13632 {
13633         int ret = MM_ERROR_NONE;
13634         mm_player_t* player = (mm_player_t*) hplayer;
13635
13636         MMPLAYER_FENTER();
13637         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13638
13639         if (MMPLAYER_CURRENT_STATE(player) !=  MM_PLAYER_STATE_NULL)
13640                 LOGW("buffer_ms will not be applied.");
13641
13642
13643         LOGD("set buffering time %d ms / %d ms", buffer_ms, rebuffer_ms);
13644
13645         if (player->streamer == NULL) {
13646                 player->streamer = __mm_player_streaming_create();
13647                 __mm_player_streaming_initialize(player->streamer);
13648         }
13649
13650         if (buffer_ms >= 0)
13651                 player->streamer->buffering_req.prebuffer_time = buffer_ms;
13652
13653         if (rebuffer_ms >= 0)
13654                 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
13655
13656         MMPLAYER_FLEAVE();
13657         return ret;
13658
13659 }
13660
13661 int _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *buffer_ms, int *rebuffer_ms)
13662 {
13663         int ret = MM_ERROR_NONE;
13664         mm_player_t* player = (mm_player_t*) hplayer;
13665
13666         MMPLAYER_FENTER();
13667         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13668         MMPLAYER_RETURN_VAL_IF_FAIL(buffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
13669
13670         if (player->streamer == NULL) {
13671                 player->streamer = __mm_player_streaming_create();
13672                 __mm_player_streaming_initialize(player->streamer);
13673         }
13674
13675         *buffer_ms = player->streamer->buffering_req.prebuffer_time;
13676         *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
13677
13678         LOGD("buffering time %d ms / %d ms", *buffer_ms, *rebuffer_ms);
13679
13680         MMPLAYER_FLEAVE();
13681         return ret;
13682 }
13683
13684 int _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
13685 {
13686 #define IDX_FIRST_SW_CODEC 0
13687         mm_player_t* player = (mm_player_t*) hplayer;
13688         const char* attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
13689         MMHandleType attrs = 0;
13690
13691         MMPLAYER_FENTER();
13692         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13693
13694         LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
13695                 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
13696                 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
13697
13698         switch (stream_type) {
13699         case MM_PLAYER_STREAM_TYPE_AUDIO:
13700                 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
13701                          (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
13702                         ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
13703                          (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
13704                         LOGE("There is no a codec for codec_type %d", codec_type);
13705                         return MM_ERROR_PLAYER_NO_OP;
13706                 }
13707         break;
13708         case MM_PLAYER_STREAM_TYPE_VIDEO:
13709                 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
13710                          (!strcmp(player->ini.videocodec_element_hw, ""))) ||
13711                         ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
13712                          (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
13713                         LOGE("There is no v codec for codec_type %d", codec_type);
13714                         return MM_ERROR_PLAYER_NO_OP;
13715                 }
13716
13717         break;
13718         default:
13719                 LOGE("Invalid stream type %d", stream_type);
13720                 return MM_ERROR_COMMON_INVALID_ARGUMENT;
13721         break;
13722         }
13723
13724         LOGD("update %s codec_type to %d", attr_name, codec_type);
13725
13726         attrs = MMPLAYER_GET_ATTRS(player);
13727         mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
13728
13729         if (mmf_attrs_commit(player->attrs)) {
13730                 LOGE("failed to commit codec_type attributes");
13731                 return MM_ERROR_PLAYER_INTERNAL;
13732         }
13733
13734         MMPLAYER_FLEAVE();
13735         return MM_ERROR_NONE;
13736 }
13737
13738 int
13739 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
13740 {
13741         mm_player_t* player = (mm_player_t*) hplayer;
13742         GstElement* rg_vol_element = NULL;
13743
13744         MMPLAYER_FENTER();
13745
13746         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13747
13748         player->sound.rg_enable = enabled;
13749
13750         /* just hold rgvolume enable value if pipeline is not ready */
13751         if (!player->pipeline || !player->pipeline->audiobin) {
13752                 LOGD("pipeline is not ready. holding rgvolume enable value\n");
13753                 return MM_ERROR_NONE;
13754         }
13755
13756         rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
13757
13758         if (!rg_vol_element) {
13759                 LOGD("rgvolume element is not created");
13760                 return MM_ERROR_PLAYER_INTERNAL;
13761         }
13762
13763         if (enabled)
13764                 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
13765         else
13766                 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
13767
13768         MMPLAYER_FLEAVE();
13769
13770         return MM_ERROR_NONE;
13771 }
13772
13773 int
13774 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
13775 {
13776         mm_player_t* player = (mm_player_t*) hplayer;
13777         GstElement* rg_vol_element = NULL;
13778         gboolean enable = FALSE;
13779
13780         MMPLAYER_FENTER();
13781
13782         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13783         MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
13784
13785         /* just hold enable_rg value if pipeline is not ready */
13786         if (!player->pipeline || !player->pipeline->audiobin) {
13787                 LOGD("pipeline is not ready. holding rgvolume value (%d)\n", player->sound.rg_enable);
13788                 *enabled = player->sound.rg_enable;
13789                 return MM_ERROR_NONE;
13790         }
13791
13792         rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
13793
13794         if (!rg_vol_element) {
13795                 LOGD("rgvolume element is not created");
13796                 return MM_ERROR_PLAYER_INTERNAL;
13797         }
13798
13799         g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
13800         *enabled = enable;
13801
13802         MMPLAYER_FLEAVE();
13803
13804         return MM_ERROR_NONE;
13805 }